mirror of https://github.com/llvm/circt.git
[Moore] Tweak Variable and ReadLValue ops. (#7095)
[Moore] Modify the tests related to the RefType.
Add a wrapper type(moore::RefType) to work for VariableOp/NetOp, ReadOp, and AssignOpBase, and it can wrap any SystemVerilog types. We added RefType in order to introduce Mem2Reg into moore to eliminate the local temporary variables. Meanwhile, we added a new op named moore.extract_ref which is the copy of moore.extract that explicitly works on the ref type. And moore.concat_ref is the copy of moore.concat. Later, we will tweak union/struct ops like moore.struct_create in order to support the ref type.
moore.variable/moore.net will return a result with ref<T>, it's similar to memref.alloca.
Change moore::ReadLValueOp to moore::ReadOp, it's similar to memref.load. Initially, we need moore.read_lvalue only to service for assigmen operations(like +=, *=, etc). However, moore. read is not only for assignment operations but also to take a value with RefType(ref) and return the current value with the nested type(T). For example, a = b + c, moore.read will take b and c(both are ref<T>), and then return a value with the nested type(T).
We think the MooreLValueType and VariableDeclOp(52a71a6
) that had been removed eventually found their proper site.
We also divide convertExpression() into convertLvalueExpression() for the LHS of assignments and convertRvalueExpression() for the RHS of assignments. The former will return a value with RefType like ref<i32>, but the latter returns a value without RefType like i32.
Co-authored-by: Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
This commit is contained in:
parent
53abd04cac
commit
69085ea0e5
|
@ -182,14 +182,14 @@ def ProcedureOp : MooreOp<"procedure", [
|
|||
def VariableOp : MooreOp<"variable", [
|
||||
DeclareOpInterfaceMethods<OpAsmOpInterface, ["getAsmResultNames"]>,
|
||||
OptionalTypesMatchWith<"initial value and variable types match",
|
||||
"result", "initial", "$_self">,
|
||||
"result", "initial", "cast<RefType>($_self).getNestedType()">
|
||||
]> {
|
||||
let summary = "A variable declaration";
|
||||
let description = [{
|
||||
See IEEE 1800-2017 § 6.8 "Variable declarations".
|
||||
}];
|
||||
let arguments = (ins StrAttr:$name, Optional<UnpackedType>:$initial);
|
||||
let results = (outs Res<UnpackedType, "", [MemAlloc]>:$result);
|
||||
let results = (outs Res<RefType, "", [MemAlloc]>:$result);
|
||||
let assemblyFormat = [{
|
||||
`` custom<ImplicitSSAName>($name) ($initial^)? attr-dict
|
||||
`:` type($result)
|
||||
|
@ -219,7 +219,7 @@ def NetKindAttr : I32EnumAttr<"NetKind", "Net type kind", [
|
|||
def NetOp : MooreOp<"net", [
|
||||
DeclareOpInterfaceMethods<OpAsmOpInterface, ["getAsmResultNames"]>,
|
||||
OptionalTypesMatchWith<"assigned value and variable types match",
|
||||
"result", "assignment", "$_self">,
|
||||
"result", "assignment", "cast<RefType>($_self).getNestedType()">,
|
||||
]> {
|
||||
let summary = "A net declaration";
|
||||
let description = [{
|
||||
|
@ -243,21 +243,24 @@ def NetOp : MooreOp<"net", [
|
|||
NetKindAttr:$kind,
|
||||
Optional<UnpackedType>:$assignment
|
||||
);
|
||||
let results = (outs UnpackedType:$result);
|
||||
let results = (outs Res<RefType, "", [MemAlloc]>:$result);
|
||||
let assemblyFormat = [{
|
||||
``custom<ImplicitSSAName>($name) $kind ($assignment^)? attr-dict
|
||||
`:` type($result)
|
||||
}];
|
||||
}
|
||||
|
||||
def ReadLValueOp : MooreOp<"read_lvalue", [SameOperandsAndResultType]> {
|
||||
def ReadOp : MooreOp<"read", [
|
||||
TypesMatchWith<"input and result types match",
|
||||
"result", "input", "RefType::get(cast<UnpackedType>($_self))">
|
||||
]> {
|
||||
let summary = "Read the current value of a declaration";
|
||||
let description = [{
|
||||
Samples the current value of a declaration. This is a helper to capture the
|
||||
exact point at which declarations that can be targeted by assignments are
|
||||
read.
|
||||
exact point at which declarations that can be targeted by all possible
|
||||
expressions are read. It's similar to llvm.load.
|
||||
}];
|
||||
let arguments = (ins Arg<UnpackedType, "", [MemRead]>:$input);
|
||||
let arguments = (ins Arg<RefType, "", [MemRead]>:$input);
|
||||
let results = (outs UnpackedType:$result);
|
||||
let assemblyFormat = [{
|
||||
$input attr-dict `:` type($result)
|
||||
|
@ -269,8 +272,9 @@ def ReadLValueOp : MooreOp<"read_lvalue", [SameOperandsAndResultType]> {
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class AssignOpBase<string mnemonic, list<Trait> traits = []> :
|
||||
MooreOp<mnemonic, traits # [SameTypeOperands]> {
|
||||
let arguments = (ins UnpackedType:$dst, UnpackedType:$src);
|
||||
MooreOp<mnemonic, traits # [TypesMatchWith<"src and dst types match",
|
||||
"src", "dst", "RefType::get(cast<UnpackedType>($_self))">]> {
|
||||
let arguments = (ins RefType:$dst, UnpackedType:$src);
|
||||
let assemblyFormat = [{
|
||||
$dst `,` $src attr-dict `:` type($src)
|
||||
}];
|
||||
|
@ -297,7 +301,7 @@ def BlockingAssignOp : AssignOpBase<"blocking_assign"> {
|
|||
See IEEE 1800-2017 § 10.4.1 "Blocking procedural assignments".
|
||||
}];
|
||||
let arguments = (ins
|
||||
Arg<UnpackedType, "", [MemWrite]>:$dst,
|
||||
Arg<RefType, "", [MemWrite]>:$dst,
|
||||
UnpackedType:$src
|
||||
);
|
||||
}
|
||||
|
@ -795,6 +799,17 @@ def ConcatOp : MooreOp<"concat", [
|
|||
}];
|
||||
}
|
||||
|
||||
def ConcatRefOp : MooreOp<"concat_ref", [
|
||||
Pure, DeclareOpInterfaceMethods<InferTypeOpInterface>
|
||||
]> {
|
||||
let summary = "The copy of concat that explicitly works on the ref type.";
|
||||
let arguments = (ins Variadic<RefType>:$values);
|
||||
let results = (outs RefType:$result);
|
||||
let assemblyFormat = [{
|
||||
$values attr-dict `:` `(` type($values) `)` `->` type($result)
|
||||
}];
|
||||
}
|
||||
|
||||
def ReplicateOp : MooreOp<"replicate", [
|
||||
Pure
|
||||
]> {
|
||||
|
@ -856,6 +871,16 @@ def ExtractOp : MooreOp<"extract"> {
|
|||
}];
|
||||
}
|
||||
|
||||
def ExtractRefOp : MooreOp<"extract_ref"> {
|
||||
let summary = "The copy of extract that explicitly works on the ref type.";
|
||||
let arguments = (ins RefType:$input, UnpackedType:$lowBit);
|
||||
let results = (outs RefType:$result);
|
||||
let assemblyFormat = [{
|
||||
$input `from` $lowBit attr-dict `:`
|
||||
type($input) `,` type($lowBit) `->` type($result)
|
||||
}];
|
||||
}
|
||||
|
||||
def StructCreateOp : MooreOp<"struct_create", [SameOperandsAndResultType]> {
|
||||
let summary = "Struct Create operation";
|
||||
let description = [{
|
||||
|
|
|
@ -325,6 +325,29 @@ def UnpackedUnionType : StructLikeType<
|
|||
}];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Reference type wrapper
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def RefType : MooreTypeDef<"Ref", [], "moore::UnpackedType">{
|
||||
let mnemonic = "ref";
|
||||
let description = [{
|
||||
A wrapper is used to wrap any SystemVerilog type. It's aimed to work for
|
||||
'moore.variable', 'moore.blocking_assign', and 'moore.read', which are
|
||||
related to memory, like alloca/write/read.
|
||||
}];
|
||||
let parameters = (ins "UnpackedType":$nestedType);
|
||||
let assemblyFormat = [{
|
||||
`<` $nestedType `>`
|
||||
}];
|
||||
|
||||
let builders = [
|
||||
AttrBuilderWithInferredContext<(ins "UnpackedType":$nestedType), [{
|
||||
return $_get(nestedType.getContext(), nestedType);
|
||||
}]>
|
||||
];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Constraints
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -14,12 +14,12 @@ using namespace ImportVerilog;
|
|||
|
||||
// NOLINTBEGIN(misc-no-recursion)
|
||||
namespace {
|
||||
struct ExprVisitor {
|
||||
struct RvalueExprVisitor {
|
||||
Context &context;
|
||||
Location loc;
|
||||
OpBuilder &builder;
|
||||
|
||||
ExprVisitor(Context &context, Location loc)
|
||||
RvalueExprVisitor(Context &context, Location loc)
|
||||
: context(context), loc(loc), builder(context.builder) {}
|
||||
|
||||
/// Helper function to convert a value to its simple bit vector
|
||||
|
@ -27,7 +27,9 @@ struct ExprVisitor {
|
|||
Value convertToSimpleBitVector(Value value) {
|
||||
if (!value)
|
||||
return {};
|
||||
if (isa<moore::IntType>(value.getType()))
|
||||
if (isa<moore::IntType>(value.getType()) ||
|
||||
isa<moore::IntType>(
|
||||
dyn_cast<moore::RefType>(value.getType()).getNestedType()))
|
||||
return value;
|
||||
mlir::emitError(loc, "expression of type ")
|
||||
<< value.getType() << " cannot be cast to a simple bit vector";
|
||||
|
@ -52,13 +54,19 @@ struct ExprVisitor {
|
|||
Value visit(const slang::ast::LValueReferenceExpression &expr) {
|
||||
assert(!context.lvalueStack.empty() && "parent assignments push lvalue");
|
||||
auto lvalue = context.lvalueStack.back();
|
||||
return builder.create<moore::ReadLValueOp>(loc, lvalue);
|
||||
return builder.create<moore::ReadOp>(
|
||||
loc, cast<moore::RefType>(lvalue.getType()).getNestedType(), lvalue);
|
||||
}
|
||||
|
||||
// Handle named values, such as references to declared variables.
|
||||
Value visit(const slang::ast::NamedValueExpression &expr) {
|
||||
if (auto value = context.valueSymbols.lookup(&expr.symbol))
|
||||
return value;
|
||||
return isa<moore::NamedConstantOp>(value.getDefiningOp())
|
||||
? value
|
||||
: builder.create<moore::ReadOp>(
|
||||
loc,
|
||||
cast<moore::RefType>(value.getType()).getNestedType(),
|
||||
value);
|
||||
auto d = mlir::emitError(loc, "unknown name `") << expr.symbol.name << "`";
|
||||
d.attachNote(context.convertLocation(expr.symbol.location))
|
||||
<< "no value generated for " << slang::ast::toString(expr.symbol.kind);
|
||||
|
@ -70,7 +78,7 @@ struct ExprVisitor {
|
|||
auto type = context.convertType(*expr.type);
|
||||
if (!type)
|
||||
return {};
|
||||
auto operand = context.convertExpression(expr.operand());
|
||||
auto operand = context.convertRvalueExpression(expr.operand());
|
||||
if (!operand)
|
||||
return {};
|
||||
return builder.create<moore::ConversionOp>(loc, type, operand);
|
||||
|
@ -78,16 +86,13 @@ struct ExprVisitor {
|
|||
|
||||
// Handle blocking and non-blocking assignments.
|
||||
Value visit(const slang::ast::AssignmentExpression &expr) {
|
||||
auto lhs = context.convertExpression(expr.left());
|
||||
auto lhs = context.convertLvalueExpression(expr.left());
|
||||
context.lvalueStack.push_back(lhs);
|
||||
auto rhs = context.convertExpression(expr.right());
|
||||
auto rhs = context.convertRvalueExpression(expr.right());
|
||||
context.lvalueStack.pop_back();
|
||||
if (!lhs || !rhs)
|
||||
return {};
|
||||
|
||||
if (lhs.getType() != rhs.getType())
|
||||
rhs = builder.create<moore::ConversionOp>(loc, lhs.getType(), rhs);
|
||||
|
||||
if (expr.timingControl) {
|
||||
auto loc = context.convertLocation(expr.timingControl->sourceRange);
|
||||
mlir::emitError(loc, "delayed assignments not supported");
|
||||
|
@ -119,7 +124,9 @@ struct ExprVisitor {
|
|||
auto preValue = convertToSimpleBitVector(arg);
|
||||
if (!preValue)
|
||||
return {};
|
||||
preValue = builder.create<moore::ReadLValueOp>(loc, preValue);
|
||||
preValue = builder.create<moore::ReadOp>(
|
||||
loc, cast<moore::RefType>(preValue.getType()).getNestedType(),
|
||||
preValue);
|
||||
auto one = builder.create<moore::ConstantOp>(
|
||||
loc, cast<moore::IntType>(preValue.getType()), 1);
|
||||
auto postValue =
|
||||
|
@ -131,11 +138,18 @@ struct ExprVisitor {
|
|||
|
||||
// Handle unary operators.
|
||||
Value visit(const slang::ast::UnaryExpression &expr) {
|
||||
auto arg = context.convertExpression(expr.operand());
|
||||
using slang::ast::UnaryOperator;
|
||||
Value arg;
|
||||
if (expr.op == UnaryOperator::Preincrement ||
|
||||
expr.op == UnaryOperator::Predecrement ||
|
||||
expr.op == UnaryOperator::Postincrement ||
|
||||
expr.op == UnaryOperator::Postdecrement)
|
||||
arg = context.convertLvalueExpression(expr.operand());
|
||||
else
|
||||
arg = context.convertRvalueExpression(expr.operand());
|
||||
if (!arg)
|
||||
return {};
|
||||
|
||||
using slang::ast::UnaryOperator;
|
||||
switch (expr.op) {
|
||||
// `+a` is simply `a`, but converted to a simple bit vector type since
|
||||
// this is technically an arithmetic operation.
|
||||
|
@ -200,8 +214,8 @@ struct ExprVisitor {
|
|||
|
||||
// Handle binary operators.
|
||||
Value visit(const slang::ast::BinaryExpression &expr) {
|
||||
auto lhs = context.convertExpression(expr.left());
|
||||
auto rhs = context.convertExpression(expr.right());
|
||||
auto lhs = context.convertRvalueExpression(expr.left());
|
||||
auto rhs = context.convertRvalueExpression(expr.right());
|
||||
if (!lhs || !rhs)
|
||||
return {};
|
||||
|
||||
|
@ -372,7 +386,7 @@ struct ExprVisitor {
|
|||
Value visit(const slang::ast::ConcatenationExpression &expr) {
|
||||
SmallVector<Value> operands;
|
||||
for (auto *operand : expr.operands()) {
|
||||
auto value = context.convertExpression(*operand);
|
||||
auto value = context.convertRvalueExpression(*operand);
|
||||
if (!value)
|
||||
continue;
|
||||
value = convertToSimpleBitVector(value);
|
||||
|
@ -387,7 +401,7 @@ struct ExprVisitor {
|
|||
if (isa<moore::VoidType>(type))
|
||||
return {};
|
||||
|
||||
auto value = context.convertExpression(expr.concat());
|
||||
auto value = context.convertRvalueExpression(expr.concat());
|
||||
if (!value)
|
||||
return {};
|
||||
return builder.create<moore::ReplicateOp>(loc, type, value);
|
||||
|
@ -396,10 +410,10 @@ struct ExprVisitor {
|
|||
// Handle single bit selections.
|
||||
Value visit(const slang::ast::ElementSelectExpression &expr) {
|
||||
auto type = context.convertType(*expr.type);
|
||||
auto value = context.convertExpression(expr.value());
|
||||
auto lowBit = context.convertExpression(expr.selector());
|
||||
auto value = context.convertRvalueExpression(expr.value());
|
||||
auto lowBit = context.convertRvalueExpression(expr.selector());
|
||||
|
||||
if (!value || !lowBit)
|
||||
if (!type || !value || !lowBit)
|
||||
return {};
|
||||
return builder.create<moore::ExtractOp>(loc, type, value, lowBit);
|
||||
}
|
||||
|
@ -407,23 +421,23 @@ struct ExprVisitor {
|
|||
// Handle range bits selections.
|
||||
Value visit(const slang::ast::RangeSelectExpression &expr) {
|
||||
auto type = context.convertType(*expr.type);
|
||||
auto value = context.convertExpression(expr.value());
|
||||
auto value = context.convertRvalueExpression(expr.value());
|
||||
Value lowBit;
|
||||
if (expr.getSelectionKind() == slang::ast::RangeSelectionKind::Simple) {
|
||||
if (expr.left().constant && expr.right().constant) {
|
||||
auto lhs = expr.left().constant->integer().as<uint64_t>().value();
|
||||
auto rhs = expr.right().constant->integer().as<uint64_t>().value();
|
||||
lowBit = lhs < rhs ? context.convertExpression(expr.left())
|
||||
: context.convertExpression(expr.right());
|
||||
lowBit = lhs < rhs ? context.convertRvalueExpression(expr.left())
|
||||
: context.convertRvalueExpression(expr.right());
|
||||
} else {
|
||||
mlir::emitError(loc, "unsupported a variable as the index in the")
|
||||
<< slang::ast::toString(expr.getSelectionKind()) << "kind";
|
||||
return {};
|
||||
}
|
||||
} else
|
||||
lowBit = context.convertExpression(expr.left());
|
||||
lowBit = context.convertRvalueExpression(expr.left());
|
||||
|
||||
if (!value || !lowBit)
|
||||
if (!type || !value || !lowBit)
|
||||
return {};
|
||||
return builder.create<moore::ExtractOp>(loc, type, value, lowBit);
|
||||
}
|
||||
|
@ -431,7 +445,7 @@ struct ExprVisitor {
|
|||
Value visit(const slang::ast::MemberAccessExpression &expr) {
|
||||
auto type = context.convertType(*expr.type);
|
||||
auto valueType = expr.value().type;
|
||||
auto value = context.convertExpression(expr.value());
|
||||
auto value = context.convertRvalueExpression(expr.value());
|
||||
if (!type || !value)
|
||||
return {};
|
||||
if (valueType->isStruct()) {
|
||||
|
@ -447,7 +461,8 @@ struct ExprVisitor {
|
|||
|
||||
// Handle set membership operator.
|
||||
Value visit(const slang::ast::InsideExpression &expr) {
|
||||
auto lhs = convertToSimpleBitVector(context.convertExpression(expr.left()));
|
||||
auto lhs =
|
||||
convertToSimpleBitVector(context.convertRvalueExpression(expr.left()));
|
||||
if (!lhs)
|
||||
return {};
|
||||
// All conditions for determining whether it is inside.
|
||||
|
@ -462,9 +477,9 @@ struct ExprVisitor {
|
|||
listExpr->as_if<slang::ast::OpenRangeExpression>()) {
|
||||
// Handle ranges.
|
||||
auto lowBound = convertToSimpleBitVector(
|
||||
context.convertExpression(openRange->left()));
|
||||
context.convertRvalueExpression(openRange->left()));
|
||||
auto highBound = convertToSimpleBitVector(
|
||||
context.convertExpression(openRange->right()));
|
||||
context.convertRvalueExpression(openRange->right()));
|
||||
if (!lowBound || !highBound)
|
||||
return {};
|
||||
Value leftValue, rightValue;
|
||||
|
@ -495,8 +510,8 @@ struct ExprVisitor {
|
|||
loc, "only simple bit vectors supported in 'inside' expressions");
|
||||
return {};
|
||||
}
|
||||
auto value =
|
||||
convertToSimpleBitVector(context.convertExpression(*listExpr));
|
||||
auto value = convertToSimpleBitVector(
|
||||
context.convertRvalueExpression(*listExpr));
|
||||
if (!value)
|
||||
return {};
|
||||
cond = builder.create<moore::WildcardEqOp>(loc, lhs, value);
|
||||
|
@ -520,7 +535,7 @@ struct ExprVisitor {
|
|||
|
||||
// Handle condition.
|
||||
Value cond = convertToSimpleBitVector(
|
||||
context.convertExpression(*expr.conditions.begin()->expr));
|
||||
context.convertRvalueExpression(*expr.conditions.begin()->expr));
|
||||
cond = convertToBool(cond);
|
||||
if (!cond)
|
||||
return {};
|
||||
|
@ -534,14 +549,14 @@ struct ExprVisitor {
|
|||
|
||||
// Handle left expression.
|
||||
builder.setInsertionPointToStart(conditionalOp.getBody(0));
|
||||
auto trueValue = context.convertExpression(expr.left());
|
||||
auto trueValue = context.convertRvalueExpression(expr.left());
|
||||
if (!trueValue)
|
||||
return {};
|
||||
builder.create<moore::YieldOp>(loc, trueValue);
|
||||
|
||||
// Handle right expression.
|
||||
builder.setInsertionPointToStart(conditionalOp.getBody(1));
|
||||
auto falseValue = context.convertExpression(expr.right());
|
||||
auto falseValue = context.convertRvalueExpression(expr.right());
|
||||
if (!falseValue)
|
||||
return {};
|
||||
builder.create<moore::YieldOp>(loc, falseValue);
|
||||
|
@ -564,8 +579,110 @@ struct ExprVisitor {
|
|||
};
|
||||
} // namespace
|
||||
|
||||
Value Context::convertExpression(const slang::ast::Expression &expr) {
|
||||
namespace {
|
||||
struct LvalueExprVisitor {
|
||||
Context &context;
|
||||
Location loc;
|
||||
OpBuilder &builder;
|
||||
|
||||
LvalueExprVisitor(Context &context, Location loc)
|
||||
: context(context), loc(loc), builder(context.builder) {}
|
||||
|
||||
/// Helper function to convert a value to its simple bit vector
|
||||
/// representation, if it has one. Otherwise returns null.
|
||||
Value convertToSimpleBitVector(Value value) {
|
||||
if (!value)
|
||||
return {};
|
||||
if (isa<moore::IntType>(
|
||||
cast<moore::RefType>(value.getType()).getNestedType()))
|
||||
return value;
|
||||
mlir::emitError(loc, "expression of type ")
|
||||
<< value.getType() << " cannot be cast to a simple bit vector";
|
||||
return {};
|
||||
}
|
||||
|
||||
// Handle named values, such as references to declared variables.
|
||||
Value visit(const slang::ast::NamedValueExpression &expr) {
|
||||
if (auto value = context.valueSymbols.lookup(&expr.symbol))
|
||||
return value;
|
||||
auto d = mlir::emitError(loc, "unknown name `") << expr.symbol.name << "`";
|
||||
d.attachNote(context.convertLocation(expr.symbol.location))
|
||||
<< "no value generated for " << slang::ast::toString(expr.symbol.kind);
|
||||
return {};
|
||||
}
|
||||
|
||||
// Handle concatenations.
|
||||
Value visit(const slang::ast::ConcatenationExpression &expr) {
|
||||
SmallVector<Value> operands;
|
||||
for (auto *operand : expr.operands()) {
|
||||
auto value = context.convertLvalueExpression(*operand);
|
||||
if (!value)
|
||||
continue;
|
||||
value = convertToSimpleBitVector(value);
|
||||
operands.push_back(value);
|
||||
}
|
||||
return builder.create<moore::ConcatRefOp>(loc, operands);
|
||||
}
|
||||
|
||||
// Handle single bit selections.
|
||||
Value visit(const slang::ast::ElementSelectExpression &expr) {
|
||||
auto type = context.convertType(*expr.type);
|
||||
auto value = context.convertLvalueExpression(expr.value());
|
||||
auto lowBit = context.convertRvalueExpression(expr.selector());
|
||||
|
||||
if (!type || !value || !lowBit)
|
||||
return {};
|
||||
return builder.create<moore::ExtractRefOp>(
|
||||
loc, moore::RefType::get(cast<moore::UnpackedType>(type)), value,
|
||||
lowBit);
|
||||
}
|
||||
|
||||
// Handle range bits selections.
|
||||
Value visit(const slang::ast::RangeSelectExpression &expr) {
|
||||
auto type = context.convertType(*expr.type);
|
||||
auto value = context.convertLvalueExpression(expr.value());
|
||||
Value lowBit;
|
||||
if (expr.getSelectionKind() == slang::ast::RangeSelectionKind::Simple) {
|
||||
if (expr.left().constant && expr.right().constant) {
|
||||
auto lhs = expr.left().constant->integer().as<uint64_t>().value();
|
||||
auto rhs = expr.right().constant->integer().as<uint64_t>().value();
|
||||
lowBit = lhs < rhs ? context.convertRvalueExpression(expr.left())
|
||||
: context.convertRvalueExpression(expr.right());
|
||||
} else {
|
||||
mlir::emitError(loc, "unsupported a variable as the index in the")
|
||||
<< slang::ast::toString(expr.getSelectionKind()) << "kind";
|
||||
return {};
|
||||
}
|
||||
} else
|
||||
lowBit = context.convertRvalueExpression(expr.left());
|
||||
|
||||
if (!type || !value || !lowBit)
|
||||
return {};
|
||||
return builder.create<moore::ExtractRefOp>(
|
||||
loc, moore::RefType::get(cast<moore::UnpackedType>(type)), value,
|
||||
lowBit);
|
||||
}
|
||||
|
||||
/// Emit an error for all other expressions.
|
||||
template <typename T>
|
||||
Value visit(T &&node) {
|
||||
return context.convertRvalueExpression(node);
|
||||
}
|
||||
|
||||
Value visitInvalid(const slang::ast::Expression &expr) {
|
||||
mlir::emitError(loc, "invalid expression");
|
||||
return {};
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
Value Context::convertRvalueExpression(const slang::ast::Expression &expr) {
|
||||
auto loc = convertLocation(expr.sourceRange);
|
||||
return expr.visit(ExprVisitor(*this, loc));
|
||||
return expr.visit(RvalueExprVisitor(*this, loc));
|
||||
}
|
||||
|
||||
Value Context::convertLvalueExpression(const slang::ast::Expression &expr) {
|
||||
auto loc = convertLocation(expr.sourceRange);
|
||||
return expr.visit(LvalueExprVisitor(*this, loc));
|
||||
}
|
||||
// NOLINTEND(misc-no-recursion)
|
||||
|
|
|
@ -76,7 +76,8 @@ struct Context {
|
|||
LogicalResult convertStatement(const slang::ast::Statement &stmt);
|
||||
|
||||
// Convert an expression AST node to MLIR ops.
|
||||
Value convertExpression(const slang::ast::Expression &expr);
|
||||
Value convertRvalueExpression(const slang::ast::Expression &expr);
|
||||
Value convertLvalueExpression(const slang::ast::Expression &expr);
|
||||
|
||||
mlir::ModuleOp intoModuleOp;
|
||||
const slang::SourceManager &sourceManager;
|
||||
|
|
|
@ -46,7 +46,7 @@ struct StmtVisitor {
|
|||
|
||||
// Handle expression statements.
|
||||
LogicalResult visit(const slang::ast::ExpressionStatement &stmt) {
|
||||
return failure(!context.convertExpression(stmt.expr));
|
||||
return failure(!context.convertRvalueExpression(stmt.expr));
|
||||
}
|
||||
|
||||
// Handle variable declarations.
|
||||
|
@ -58,14 +58,15 @@ struct StmtVisitor {
|
|||
|
||||
Value initial;
|
||||
if (const auto *init = var.getInitializer()) {
|
||||
initial = context.convertExpression(*init);
|
||||
initial = context.convertRvalueExpression(*init);
|
||||
if (!initial)
|
||||
return failure();
|
||||
}
|
||||
|
||||
// Collect local temporary variables.
|
||||
auto varOp = builder.create<moore::VariableOp>(
|
||||
loc, type, builder.getStringAttr(var.name), initial);
|
||||
loc, moore::RefType::get(cast<moore::UnpackedType>(type)),
|
||||
builder.getStringAttr(var.name), initial);
|
||||
context.valueSymbols.insertIntoScope(context.valueSymbols.getCurScope(),
|
||||
&var, varOp);
|
||||
return success();
|
||||
|
@ -80,7 +81,7 @@ struct StmtVisitor {
|
|||
if (condition.pattern)
|
||||
return mlir::emitError(loc,
|
||||
"match patterns in if conditions not supported");
|
||||
auto cond = context.convertExpression(*condition.expr);
|
||||
auto cond = context.convertRvalueExpression(*condition.expr);
|
||||
if (!cond)
|
||||
return failure();
|
||||
cond = builder.createOrFold<moore::BoolCastOp>(loc, cond);
|
||||
|
@ -115,7 +116,7 @@ struct StmtVisitor {
|
|||
|
||||
// Handle case statements.
|
||||
LogicalResult visit(const slang::ast::CaseStatement &caseStmt) {
|
||||
auto caseExpr = context.convertExpression(caseStmt.expr);
|
||||
auto caseExpr = context.convertRvalueExpression(caseStmt.expr);
|
||||
auto items = caseStmt.items;
|
||||
// Used to generate the condition of the default case statement.
|
||||
SmallVector<Value> defaultConds;
|
||||
|
@ -125,7 +126,7 @@ struct StmtVisitor {
|
|||
// Like case(cond) 0, 1 : y = x; endcase.
|
||||
SmallVector<Value> allConds;
|
||||
for (const auto *expr : item.expressions) {
|
||||
auto itemExpr = context.convertExpression(*expr);
|
||||
auto itemExpr = context.convertRvalueExpression(*expr);
|
||||
auto newEqOp = builder.create<moore::EqOp>(loc, caseExpr, itemExpr);
|
||||
allConds.push_back(newEqOp);
|
||||
}
|
||||
|
@ -174,7 +175,7 @@ struct StmtVisitor {
|
|||
|
||||
// Generate the initializers.
|
||||
for (auto *initExpr : stmt.initializers)
|
||||
if (!context.convertExpression(*initExpr))
|
||||
if (!context.convertRvalueExpression(*initExpr))
|
||||
return failure();
|
||||
|
||||
// Create the while op.
|
||||
|
@ -183,7 +184,7 @@ struct StmtVisitor {
|
|||
|
||||
// In the "before" region, check that the condition holds.
|
||||
builder.createBlock(&whileOp.getBefore());
|
||||
auto cond = context.convertExpression(*stmt.stopExpr);
|
||||
auto cond = context.convertRvalueExpression(*stmt.stopExpr);
|
||||
if (!cond)
|
||||
return failure();
|
||||
cond = builder.createOrFold<moore::BoolCastOp>(loc, cond);
|
||||
|
@ -195,7 +196,7 @@ struct StmtVisitor {
|
|||
if (failed(context.convertStatement(stmt.body)))
|
||||
return failure();
|
||||
for (auto *stepExpr : stmt.steps)
|
||||
if (!context.convertExpression(*stepExpr))
|
||||
if (!context.convertRvalueExpression(*stepExpr))
|
||||
return failure();
|
||||
builder.create<mlir::scf::YieldOp>(loc);
|
||||
|
||||
|
@ -206,7 +207,7 @@ struct StmtVisitor {
|
|||
LogicalResult visit(const slang::ast::RepeatLoopStatement &stmt) {
|
||||
// Create the while op and feed in the repeat count as the initial counter
|
||||
// value.
|
||||
auto count = context.convertExpression(stmt.count);
|
||||
auto count = context.convertRvalueExpression(stmt.count);
|
||||
if (!count)
|
||||
return failure();
|
||||
auto type = cast<moore::IntType>(count.getType());
|
||||
|
@ -240,7 +241,7 @@ struct StmtVisitor {
|
|||
|
||||
// In the "before" region, check that the condition holds.
|
||||
builder.createBlock(&whileOp.getBefore());
|
||||
auto cond = context.convertExpression(stmt.cond);
|
||||
auto cond = context.convertRvalueExpression(stmt.cond);
|
||||
if (!cond)
|
||||
return failure();
|
||||
cond = builder.createOrFold<moore::BoolCastOp>(loc, cond);
|
||||
|
@ -267,7 +268,7 @@ struct StmtVisitor {
|
|||
builder.createBlock(&whileOp.getBefore());
|
||||
if (failed(context.convertStatement(stmt.body)))
|
||||
return failure();
|
||||
auto cond = context.convertExpression(stmt.cond);
|
||||
auto cond = context.convertRvalueExpression(stmt.cond);
|
||||
if (!cond)
|
||||
return failure();
|
||||
cond = builder.createOrFold<moore::BoolCastOp>(loc, cond);
|
||||
|
|
|
@ -133,8 +133,10 @@ struct MemberVisitor {
|
|||
// either attach it to the instance as an operand (for input, inout, and
|
||||
// ref ports), or assign an instance output to it (for output ports).
|
||||
if (auto *port = con->port.as_if<PortSymbol>()) {
|
||||
// TODO: Convert as rvalue for inputs, lvalue for all others.
|
||||
auto value = context.convertExpression(*expr);
|
||||
// Convert as rvalue for inputs, lvalue for all others.
|
||||
auto value = (port->direction == slang::ast::ArgumentDirection::In)
|
||||
? context.convertRvalueExpression(*expr)
|
||||
: context.convertLvalueExpression(*expr);
|
||||
if (!value)
|
||||
return failure();
|
||||
portValues.insert({port, value});
|
||||
|
@ -145,8 +147,8 @@ struct MemberVisitor {
|
|||
// it up into multiple sub-values, one for each of the ports in the
|
||||
// multi-port.
|
||||
if (const auto *multiPort = con->port.as_if<MultiPortSymbol>()) {
|
||||
// TODO: Convert as lvalue.
|
||||
auto value = context.convertExpression(*expr);
|
||||
// Convert as lvalue.
|
||||
auto value = context.convertLvalueExpression(*expr);
|
||||
if (!value)
|
||||
return failure();
|
||||
unsigned offset = 0;
|
||||
|
@ -157,9 +159,12 @@ struct MemberVisitor {
|
|||
auto sliceType = context.convertType(port->getType());
|
||||
if (!sliceType)
|
||||
return failure();
|
||||
auto slice =
|
||||
builder.create<moore::ExtractOp>(loc, sliceType, value, index);
|
||||
// TODO: Read to map to rvalue for input ports.
|
||||
Value slice = builder.create<moore::ExtractRefOp>(
|
||||
loc, moore::RefType::get(cast<moore::UnpackedType>(sliceType)),
|
||||
value, index);
|
||||
// Read to map to rvalue for input ports.
|
||||
if (port->direction == slang::ast::ArgumentDirection::In)
|
||||
slice = builder.create<moore::ReadOp>(loc, sliceType, slice);
|
||||
portValues.insert({port, slice});
|
||||
offset += width;
|
||||
}
|
||||
|
@ -210,17 +215,14 @@ struct MemberVisitor {
|
|||
|
||||
Value initial;
|
||||
if (const auto *init = varNode.getInitializer()) {
|
||||
initial = context.convertExpression(*init);
|
||||
initial = context.convertRvalueExpression(*init);
|
||||
if (!initial)
|
||||
return failure();
|
||||
|
||||
if (initial.getType() != loweredType)
|
||||
initial =
|
||||
builder.create<moore::ConversionOp>(loc, loweredType, initial);
|
||||
}
|
||||
|
||||
auto varOp = builder.create<moore::VariableOp>(
|
||||
loc, loweredType, builder.getStringAttr(varNode.name), initial);
|
||||
loc, moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
|
||||
builder.getStringAttr(varNode.name), initial);
|
||||
context.valueSymbols.insert(&varNode, varOp);
|
||||
return success();
|
||||
}
|
||||
|
@ -233,7 +235,7 @@ struct MemberVisitor {
|
|||
|
||||
Value assignment;
|
||||
if (netNode.getInitializer()) {
|
||||
assignment = context.convertExpression(*netNode.getInitializer());
|
||||
assignment = context.convertRvalueExpression(*netNode.getInitializer());
|
||||
if (!assignment)
|
||||
return failure();
|
||||
}
|
||||
|
@ -246,8 +248,8 @@ struct MemberVisitor {
|
|||
<< netNode.netType.name << "`";
|
||||
|
||||
auto netOp = builder.create<moore::NetOp>(
|
||||
loc, loweredType, builder.getStringAttr(netNode.name), netkind,
|
||||
assignment);
|
||||
loc, moore::RefType::get(cast<moore::UnpackedType>(loweredType)),
|
||||
builder.getStringAttr(netNode.name), netkind, assignment);
|
||||
context.valueSymbols.insert(&netNode, netOp);
|
||||
return success();
|
||||
}
|
||||
|
@ -263,14 +265,11 @@ struct MemberVisitor {
|
|||
const auto &expr =
|
||||
assignNode.getAssignment().as<slang::ast::AssignmentExpression>();
|
||||
|
||||
auto lhs = context.convertExpression(expr.left());
|
||||
auto rhs = context.convertExpression(expr.right());
|
||||
auto lhs = context.convertLvalueExpression(expr.left());
|
||||
auto rhs = context.convertRvalueExpression(expr.right());
|
||||
if (!lhs || !rhs)
|
||||
return failure();
|
||||
|
||||
if (lhs.getType() != rhs.getType())
|
||||
rhs = builder.create<moore::ConversionOp>(loc, lhs.getType(), rhs);
|
||||
|
||||
builder.create<moore::ContinuousAssignOp>(loc, lhs, rhs);
|
||||
return success();
|
||||
}
|
||||
|
@ -296,7 +295,7 @@ struct MemberVisitor {
|
|||
// skip parameters without value.
|
||||
if (!init)
|
||||
return success();
|
||||
Value initial = context.convertExpression(*init);
|
||||
Value initial = context.convertRvalueExpression(*init);
|
||||
if (!initial)
|
||||
return failure();
|
||||
|
||||
|
@ -322,7 +321,7 @@ struct MemberVisitor {
|
|||
// skip specparam without value.
|
||||
if (!init)
|
||||
return success();
|
||||
Value initial = context.convertExpression(*init);
|
||||
Value initial = context.convertRvalueExpression(*init);
|
||||
if (!initial)
|
||||
return failure();
|
||||
|
||||
|
@ -437,8 +436,10 @@ Context::convertModuleHeader(const slang::ast::InstanceBodySymbol *module) {
|
|||
if (port.direction == ArgumentDirection::Out) {
|
||||
modulePorts.push_back({portName, type, hw::ModulePort::Output});
|
||||
} else {
|
||||
// TODO: Once we have net/ref type wrappers, wrap `inout` and `ref`
|
||||
// ports in the corresponding type wrapper.
|
||||
// Only the ref type wrapper exists for the time being, the net type
|
||||
// wrapper for inout may be introduced later if necessary.
|
||||
if (port.direction != slang::ast::ArgumentDirection::In)
|
||||
type = moore::RefType::get(cast<moore::UnpackedType>(type));
|
||||
modulePorts.push_back({portName, type, hw::ModulePort::Input});
|
||||
arg = block->addArgument(type, portLoc);
|
||||
}
|
||||
|
@ -509,9 +510,7 @@ Context::convertModuleBody(const slang::ast::InstanceBodySymbol *module) {
|
|||
for (auto &port : lowering.ports) {
|
||||
Value value;
|
||||
if (auto *expr = port.ast.getInternalExpr()) {
|
||||
// TODO: Once we have separate lvalue/rvalue lowering, this should use
|
||||
// rvalue lowering for outputs and lvalue lowering for everything else.
|
||||
value = convertExpression(*expr);
|
||||
value = convertLvalueExpression(*expr);
|
||||
} else if (port.ast.internalSymbol) {
|
||||
if (const auto *sym =
|
||||
port.ast.internalSymbol->as_if<slang::ast::ValueSymbol>())
|
||||
|
@ -524,13 +523,22 @@ Context::convertModuleBody(const slang::ast::InstanceBodySymbol *module) {
|
|||
|
||||
// Collect output port values to be returned in the terminator.
|
||||
if (port.ast.direction == slang::ast::ArgumentDirection::Out) {
|
||||
if (isa<moore::RefType>(value.getType()))
|
||||
value = builder.create<moore::ReadOp>(
|
||||
value.getLoc(),
|
||||
cast<moore::RefType>(value.getType()).getNestedType(), value);
|
||||
outputs.push_back(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Assign the value coming in through the port to the internal net or symbol
|
||||
// of that port.
|
||||
builder.create<moore::ContinuousAssignOp>(port.loc, value, port.arg);
|
||||
Value portArg = port.arg;
|
||||
if (port.ast.direction != slang::ast::ArgumentDirection::In)
|
||||
portArg = builder.create<moore::ReadOp>(
|
||||
port.loc, cast<moore::RefType>(value.getType()).getNestedType(),
|
||||
port.arg);
|
||||
builder.create<moore::ContinuousAssignOp>(port.loc, value, portArg);
|
||||
}
|
||||
builder.create<moore::OutputOp>(lowering.op.getLoc(), outputs);
|
||||
|
||||
|
|
|
@ -353,6 +353,26 @@ LogicalResult ConcatOp::inferReturnTypes(
|
|||
return success();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ConcatRefOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
LogicalResult ConcatRefOp::inferReturnTypes(
|
||||
MLIRContext *context, std::optional<Location> loc, ValueRange operands,
|
||||
DictionaryAttr attrs, mlir::OpaqueProperties properties,
|
||||
mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
|
||||
Domain domain = Domain::TwoValued;
|
||||
unsigned width = 0;
|
||||
for (auto operand : operands) {
|
||||
auto type = cast<IntType>(cast<RefType>(operand.getType()).getNestedType());
|
||||
if (type.getDomain() == Domain::FourValued)
|
||||
domain = Domain::FourValued;
|
||||
width += type.getWidth();
|
||||
}
|
||||
results.push_back(RefType::get(IntType::get(context, width, domain)));
|
||||
return success();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// YieldOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,9 +8,9 @@
|
|||
module Enums;
|
||||
typedef enum shortint { MAGIC } myEnum;
|
||||
|
||||
// CHECK-NEXT: %e0 = moore.variable : i32
|
||||
// CHECK-NEXT: %e1 = moore.variable : i8
|
||||
// CHECK-NEXT: %e2 = moore.variable : i16
|
||||
// CHECK-NEXT: %e0 = moore.variable : <i32>
|
||||
// CHECK-NEXT: %e1 = moore.variable : <i8>
|
||||
// CHECK-NEXT: %e2 = moore.variable : <i16>
|
||||
enum { FOO, BAR } e0;
|
||||
enum byte { HELLO = 0, WORLD = 1 } e1;
|
||||
myEnum e2;
|
||||
|
@ -18,15 +18,15 @@ endmodule
|
|||
|
||||
// CHECK-LABEL: moore.module @IntAtoms
|
||||
module IntAtoms;
|
||||
// CHECK-NEXT: %d0 = moore.variable : l1
|
||||
// CHECK-NEXT: %d1 = moore.variable : i1
|
||||
// CHECK-NEXT: %d2 = moore.variable : l1
|
||||
// CHECK-NEXT: %d3 = moore.variable : i32
|
||||
// CHECK-NEXT: %d4 = moore.variable : i16
|
||||
// CHECK-NEXT: %d5 = moore.variable : i64
|
||||
// CHECK-NEXT: %d6 = moore.variable : l32
|
||||
// CHECK-NEXT: %d7 = moore.variable : i8
|
||||
// CHECK-NEXT: %d8 = moore.variable : l64
|
||||
// CHECK-NEXT: %d0 = moore.variable : <l1>
|
||||
// CHECK-NEXT: %d1 = moore.variable : <i1>
|
||||
// CHECK-NEXT: %d2 = moore.variable : <l1>
|
||||
// CHECK-NEXT: %d3 = moore.variable : <i32>
|
||||
// CHECK-NEXT: %d4 = moore.variable : <i16>
|
||||
// CHECK-NEXT: %d5 = moore.variable : <i64>
|
||||
// CHECK-NEXT: %d6 = moore.variable : <l32>
|
||||
// CHECK-NEXT: %d7 = moore.variable : <i8>
|
||||
// CHECK-NEXT: %d8 = moore.variable : <l64>
|
||||
logic d0;
|
||||
bit d1;
|
||||
reg d2;
|
||||
|
@ -37,15 +37,15 @@ module IntAtoms;
|
|||
byte d7;
|
||||
time d8;
|
||||
|
||||
// CHECK-NEXT: %u0 = moore.variable : l1
|
||||
// CHECK-NEXT: %u1 = moore.variable : i1
|
||||
// CHECK-NEXT: %u2 = moore.variable : l1
|
||||
// CHECK-NEXT: %u3 = moore.variable : i32
|
||||
// CHECK-NEXT: %u4 = moore.variable : i16
|
||||
// CHECK-NEXT: %u5 = moore.variable : i64
|
||||
// CHECK-NEXT: %u6 = moore.variable : l32
|
||||
// CHECK-NEXT: %u7 = moore.variable : i8
|
||||
// CHECK-NEXT: %u8 = moore.variable : l64
|
||||
// CHECK-NEXT: %u0 = moore.variable : <l1>
|
||||
// CHECK-NEXT: %u1 = moore.variable : <i1>
|
||||
// CHECK-NEXT: %u2 = moore.variable : <l1>
|
||||
// CHECK-NEXT: %u3 = moore.variable : <i32>
|
||||
// CHECK-NEXT: %u4 = moore.variable : <i16>
|
||||
// CHECK-NEXT: %u5 = moore.variable : <i64>
|
||||
// CHECK-NEXT: %u6 = moore.variable : <l32>
|
||||
// CHECK-NEXT: %u7 = moore.variable : <i8>
|
||||
// CHECK-NEXT: %u8 = moore.variable : <l64>
|
||||
logic unsigned u0;
|
||||
bit unsigned u1;
|
||||
reg unsigned u2;
|
||||
|
@ -56,15 +56,15 @@ module IntAtoms;
|
|||
byte unsigned u7;
|
||||
time unsigned u8;
|
||||
|
||||
// CHECK-NEXT: %s0 = moore.variable : l1
|
||||
// CHECK-NEXT: %s1 = moore.variable : i1
|
||||
// CHECK-NEXT: %s2 = moore.variable : l1
|
||||
// CHECK-NEXT: %s3 = moore.variable : i32
|
||||
// CHECK-NEXT: %s4 = moore.variable : i16
|
||||
// CHECK-NEXT: %s5 = moore.variable : i64
|
||||
// CHECK-NEXT: %s6 = moore.variable : l32
|
||||
// CHECK-NEXT: %s7 = moore.variable : i8
|
||||
// CHECK-NEXT: %s8 = moore.variable : l64
|
||||
// CHECK-NEXT: %s0 = moore.variable : <l1>
|
||||
// CHECK-NEXT: %s1 = moore.variable : <i1>
|
||||
// CHECK-NEXT: %s2 = moore.variable : <l1>
|
||||
// CHECK-NEXT: %s3 = moore.variable : <i32>
|
||||
// CHECK-NEXT: %s4 = moore.variable : <i16>
|
||||
// CHECK-NEXT: %s5 = moore.variable : <i64>
|
||||
// CHECK-NEXT: %s6 = moore.variable : <l32>
|
||||
// CHECK-NEXT: %s7 = moore.variable : <i8>
|
||||
// CHECK-NEXT: %s8 = moore.variable : <l64>
|
||||
logic signed s0;
|
||||
bit signed s1;
|
||||
reg signed s2;
|
||||
|
@ -78,46 +78,46 @@ endmodule
|
|||
|
||||
// CHECK-LABEL: moore.module @Dimensions
|
||||
module Dimensions;
|
||||
// CHECK-NEXT: %p0 = moore.variable : l3
|
||||
// CHECK-NEXT: %p0 = moore.variable : <l3>
|
||||
logic [2:0] p0;
|
||||
// CHECK-NEXT: %p1 = moore.variable : l3
|
||||
// CHECK-NEXT: %p1 = moore.variable : <l3>
|
||||
logic [0:2] p1;
|
||||
// CHECK-NEXT: %p2 = moore.variable : array<6 x l3>
|
||||
// CHECK-NEXT: %p2 = moore.variable : <array<6 x l3>>
|
||||
logic [5:0][2:0] p2;
|
||||
// CHECK-NEXT: %p3 = moore.variable : array<6 x l3>
|
||||
// CHECK-NEXT: %p3 = moore.variable : <array<6 x l3>>
|
||||
logic [0:5][2:0] p3;
|
||||
|
||||
// CHECK-NEXT: %u0 = moore.variable : uarray<3 x l1>
|
||||
// CHECK-NEXT: %u0 = moore.variable : <uarray<3 x l1>>
|
||||
logic u0 [2:0];
|
||||
// CHECK-NEXT: %u1 = moore.variable : uarray<3 x l1>
|
||||
// CHECK-NEXT: %u1 = moore.variable : <uarray<3 x l1>>
|
||||
logic u1 [0:2];
|
||||
// CHECK-NEXT: %u2 = moore.variable : uarray<6 x uarray<3 x l1>>
|
||||
// CHECK-NEXT: %u2 = moore.variable : <uarray<6 x uarray<3 x l1>>>
|
||||
logic u2 [5:0][2:0];
|
||||
// CHECK-NEXT: %u3 = moore.variable : uarray<6 x uarray<3 x l1>>
|
||||
// CHECK-NEXT: %u3 = moore.variable : <uarray<6 x uarray<3 x l1>>>
|
||||
logic u3 [0:5][2:0];
|
||||
// CHECK-NEXT: %u4 = moore.variable : open_uarray<l1>
|
||||
// CHECK-NEXT: %u4 = moore.variable : <open_uarray<l1>>
|
||||
logic u4 [];
|
||||
// CHECK-NEXT: %u5 = moore.variable : open_uarray<open_uarray<l1>>
|
||||
// CHECK-NEXT: %u5 = moore.variable : <open_uarray<open_uarray<l1>>>
|
||||
logic u5 [][];
|
||||
// CHECK-NEXT: %u6 = moore.variable : uarray<42 x l1>
|
||||
// CHECK-NEXT: %u6 = moore.variable : <uarray<42 x l1>>
|
||||
logic u6 [42];
|
||||
// CHECK-NEXT: %u7 = moore.variable : assoc_array<l1, i32>
|
||||
// CHECK-NEXT: %u7 = moore.variable : <assoc_array<l1, i32>>
|
||||
logic u7 [int];
|
||||
// CHECK-NEXT: %u8 = moore.variable : assoc_array<l1, l1>
|
||||
// CHECK-NEXT: %u8 = moore.variable : <assoc_array<l1, l1>>
|
||||
logic u8 [logic];
|
||||
//CHECK-NEXT: %u9 = moore.variable : queue<l1, 0>
|
||||
//CHECK-NEXT: %u9 = moore.variable : <queue<l1, 0>>
|
||||
logic u9 [$];
|
||||
//CHECK-NEXT: %u10 = moore.variable : queue<l1, 2>
|
||||
//CHECK-NEXT: %u10 = moore.variable : <queue<l1, 2>>
|
||||
logic u10 [$:2];
|
||||
endmodule
|
||||
|
||||
// CHECK-LABEL: moore.module @RealType
|
||||
module RealType;
|
||||
// CHECK-NEXT: %d0 = moore.variable : real
|
||||
// CHECK-NEXT: %d0 = moore.variable : <real>
|
||||
real d0;
|
||||
// CHECK-NEXT: %d1 = moore.variable : real
|
||||
// CHECK-NEXT: %d1 = moore.variable : <real>
|
||||
realtime d1;
|
||||
// CHECK-NEXT: %d2 = moore.variable : real
|
||||
// CHECK-NEXT: %d2 = moore.variable : <real>
|
||||
shortreal d2;
|
||||
endmodule
|
||||
|
||||
|
@ -126,10 +126,10 @@ module Structs;
|
|||
typedef struct packed { byte a; int b; } myStructA;
|
||||
typedef struct { byte x; int y; } myStructB;
|
||||
|
||||
// CHECK-NEXT: %s0 = moore.variable : struct<{foo: i1, bar: l1}>
|
||||
// CHECK-NEXT: %s1 = moore.variable : ustruct<{many: assoc_array<i1, i32>}>
|
||||
// CHECK-NEXT: %s2 = moore.variable : struct<{a: i8, b: i32}>
|
||||
// CHECK-NEXT: %s3 = moore.variable : ustruct<{x: i8, y: i32}>
|
||||
// CHECK-NEXT: %s0 = moore.variable : <struct<{foo: i1, bar: l1}>>
|
||||
// CHECK-NEXT: %s1 = moore.variable : <ustruct<{many: assoc_array<i1, i32>}>>
|
||||
// CHECK-NEXT: %s2 = moore.variable : <struct<{a: i8, b: i32}>>
|
||||
// CHECK-NEXT: %s3 = moore.variable : <ustruct<{x: i8, y: i32}>>
|
||||
struct packed { bit foo; logic bar; } s0;
|
||||
struct { bit many[int]; } s1;
|
||||
myStructA s2;
|
||||
|
@ -141,8 +141,8 @@ module Typedefs;
|
|||
typedef logic [2:0] myType1;
|
||||
typedef logic myType2 [2:0];
|
||||
|
||||
// CHECK-NEXT: %v0 = moore.variable : l3
|
||||
// CHECK-NEXT: %v1 = moore.variable : uarray<3 x l1>
|
||||
// CHECK-NEXT: %v0 = moore.variable : <l3>
|
||||
// CHECK-NEXT: %v1 = moore.variable : <uarray<3 x l1>>
|
||||
myType1 v0;
|
||||
myType2 v1;
|
||||
endmodule
|
||||
|
|
|
@ -25,43 +25,51 @@ moore.module @Module() {
|
|||
// CHECK: moore.instance "empty" @Empty() -> ()
|
||||
moore.instance "empty" @Empty() -> ()
|
||||
|
||||
// CHECK: moore.instance "ports" @Ports(a: %i1: !moore.string, c: %i2: !moore.event) -> (b: !moore.string, d: !moore.event)
|
||||
%i1 = moore.variable : !moore.string
|
||||
%i2 = moore.variable : !moore.event
|
||||
%o1, %o2 = moore.instance "ports" @Ports(a: %i1: !moore.string, c: %i2: !moore.event) -> (b: !moore.string, d: !moore.event)
|
||||
// CHECK: %[[I1_READ:.+]] = moore.read %i1
|
||||
// CHECK: %[[I2_READ:.+]] = moore.read %i2
|
||||
// CHECK: moore.instance "ports" @Ports(a: %[[I1_READ]]: !moore.string, c: %[[I2_READ]]: !moore.event) -> (b: !moore.string, d: !moore.event)
|
||||
%i1 = moore.variable : <!moore.string>
|
||||
%i2 = moore.variable : <!moore.event>
|
||||
%5 = moore.read %i1 : !moore.string
|
||||
%6 = moore.read %i2 : !moore.event
|
||||
%o1, %o2 = moore.instance "ports" @Ports(a: %5: !moore.string, c: %6: !moore.event) -> (b: !moore.string, d: !moore.event)
|
||||
|
||||
// CHECK: %v1 = moore.variable : i1
|
||||
%v1 = moore.variable : i1
|
||||
%v2 = moore.variable : i1
|
||||
// CHECK: [[TMP:%.+]] = moore.variable name "v1" %v2 : i1
|
||||
moore.variable name "v1" %v2 : i1
|
||||
// CHECK: %v1 = moore.variable : <i1>
|
||||
%v1 = moore.variable : <i1>
|
||||
%v2 = moore.variable : <i1>
|
||||
// CHECK: %[[TMP1:.+]] = moore.read %v2 : i1
|
||||
// CHECK: %[[TMP2:.+]] = moore.variable name "v1" %[[TMP1]] : <i1>
|
||||
%0 = moore.read %v2 : i1
|
||||
moore.variable name "v1" %0 : <i1>
|
||||
|
||||
// CHECK: %w0 = moore.net wire : l1
|
||||
%w0 = moore.net wire : l1
|
||||
// CHECK: %w1 = moore.net wire %w0 : l1
|
||||
%w1 = moore.net wire %w0 : l1
|
||||
// CHECK: %w2 = moore.net uwire %w0 : l1
|
||||
%w2 = moore.net uwire %w0 : l1
|
||||
// CHECK: %w3 = moore.net tri %w0 : l1
|
||||
%w3 = moore.net tri %w0 : l1
|
||||
// CHECK: %w4 = moore.net triand %w0 : l1
|
||||
%w4 = moore.net triand %w0 : l1
|
||||
// CHECK: %w5 = moore.net trior %w0 : l1
|
||||
%w5 = moore.net trior %w0 : l1
|
||||
// CHECK: %w6 = moore.net wand %w0 : l1
|
||||
%w6 = moore.net wand %w0 : l1
|
||||
// CHECK: %w7 = moore.net wor %w0 : l1
|
||||
%w7 = moore.net wor %w0 : l1
|
||||
// CHECK: %w8 = moore.net trireg %w0 : l1
|
||||
%w8 = moore.net trireg %w0 : l1
|
||||
// CHECK: %w9 = moore.net tri0 %w0 : l1
|
||||
%w9 = moore.net tri0 %w0 : l1
|
||||
// CHECK: %w10 = moore.net tri1 %w0 : l1
|
||||
%w10 = moore.net tri1 %w0 : l1
|
||||
// CHECK: %w11 = moore.net supply0 : l1
|
||||
%w11 = moore.net supply0 : l1
|
||||
// CHECK: %w12 = moore.net supply1 : l1
|
||||
%w12 = moore.net supply1 : l1
|
||||
// CHECK: %w0 = moore.net wire : <l1>
|
||||
%w0 = moore.net wire : <l1>
|
||||
// CHECK: %[[W0:.+]] = moore.read %w0 : l1
|
||||
%1 = moore.read %w0 : l1
|
||||
// CHECK: %w1 = moore.net wire %[[W0]] : <l1>
|
||||
%w1 = moore.net wire %1 : <l1>
|
||||
// CHECK: %w2 = moore.net uwire %[[W0]] : <l1>
|
||||
%w2 = moore.net uwire %1 : <l1>
|
||||
// CHECK: %w3 = moore.net tri %[[W0]] : <l1>
|
||||
%w3 = moore.net tri %1 : <l1>
|
||||
// CHECK: %w4 = moore.net triand %[[W0]] : <l1>
|
||||
%w4 = moore.net triand %1 : <l1>
|
||||
// CHECK: %w5 = moore.net trior %[[W0]] : <l1>
|
||||
%w5 = moore.net trior %1 : <l1>
|
||||
// CHECK: %w6 = moore.net wand %[[W0]] : <l1>
|
||||
%w6 = moore.net wand %1 : <l1>
|
||||
// CHECK: %w7 = moore.net wor %[[W0]] : <l1>
|
||||
%w7 = moore.net wor %1 : <l1>
|
||||
// CHECK: %w8 = moore.net trireg %[[W0]] : <l1>
|
||||
%w8 = moore.net trireg %1 : <l1>
|
||||
// CHECK: %w9 = moore.net tri0 %[[W0]] : <l1>
|
||||
%w9 = moore.net tri0 %1 : <l1>
|
||||
// CHECK: %w10 = moore.net tri1 %[[W0]] : <l1>
|
||||
%w10 = moore.net tri1 %1 : <l1>
|
||||
// CHECK: %w11 = moore.net supply0 : <l1>
|
||||
%w11 = moore.net supply0 : <l1>
|
||||
// CHECK: %w12 = moore.net supply1 : <l1>
|
||||
%w12 = moore.net supply1 : <l1>
|
||||
|
||||
// CHECK: moore.procedure initial {
|
||||
// CHECK: moore.procedure final {
|
||||
|
@ -76,29 +84,52 @@ moore.module @Module() {
|
|||
moore.procedure always_latch {}
|
||||
moore.procedure always_ff {}
|
||||
|
||||
// CHECK: moore.assign %v1, %v2 : i1
|
||||
moore.assign %v1, %v2 : i1
|
||||
// CHECK: %[[TMP1:.+]] = moore.read %v2 : i1
|
||||
// CHECK: moore.assign %v1, %[[TMP1]] : i1
|
||||
%2 = moore.read %v2 : i1
|
||||
moore.assign %v1, %2 : i1
|
||||
|
||||
moore.procedure always {
|
||||
// CHECK: moore.blocking_assign %v1, %v2 : i1
|
||||
moore.blocking_assign %v1, %v2 : i1
|
||||
// CHECK: moore.nonblocking_assign %v1, %v2 : i1
|
||||
moore.nonblocking_assign %v1, %v2 : i1
|
||||
// CHECK: %a = moore.variable : i32
|
||||
%a = moore.variable : i32
|
||||
// CHECK: %[[TMP1:.+]] = moore.read %v2 : i1
|
||||
// CHECK: moore.blocking_assign %v1, %[[TMP1]] : i1
|
||||
%3 = moore.read %v2 : i1
|
||||
moore.blocking_assign %v1, %3 : i1
|
||||
// CHECK: %[[TMP2:.+]] = moore.read %v2 : i1
|
||||
// CHECK: moore.nonblocking_assign %v1, %[[TMP2]] : i1
|
||||
%4 = moore.read %v2 : i1
|
||||
moore.nonblocking_assign %v1, %4 : i1
|
||||
// CHECK: %a = moore.variable : <i32>
|
||||
%a = moore.variable : <i32>
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK-LABEL: moore.module @Expressions
|
||||
moore.module @Expressions() {
|
||||
%b1 = moore.variable : i1
|
||||
%l1 = moore.variable : l1
|
||||
%b5 = moore.variable : i5
|
||||
%int = moore.variable : i32
|
||||
%int2 = moore.variable : i32
|
||||
%integer = moore.variable : l32
|
||||
%integer2 = moore.variable : l32
|
||||
%arr = moore.variable : uarray<2 x uarray<4 x i8>>
|
||||
%b1 = moore.variable : <i1>
|
||||
%l1 = moore.variable : <l1>
|
||||
%b5 = moore.variable : <i5>
|
||||
%int = moore.variable : <i32>
|
||||
%int2 = moore.variable : <i32>
|
||||
%integer = moore.variable : <l32>
|
||||
%integer2 = moore.variable : <l32>
|
||||
%arr = moore.variable : <uarray<2 x uarray<4 x i8>>>
|
||||
|
||||
// CHECK: %[[b1:.+]] = moore.read %b1 : i1
|
||||
// CHECK: %[[l1:.+]] = moore.read %l1 : l1
|
||||
// CHECK: %[[b5:.+]] = moore.read %b5 : i5
|
||||
// CHECK: %[[int:.+]] = moore.read %int : i32
|
||||
// CHECK: %[[int2:.+]] = moore.read %int2 : i32
|
||||
// CHECK: %[[integer:.+]] = moore.read %integer : l32
|
||||
// CHECK: %[[integer2:.+]] = moore.read %integer2 : l32
|
||||
// CHECK: %[[arr:.+]] = moore.read %arr : uarray<2 x uarray<4 x i8>>
|
||||
%0 = moore.read %b1 : i1
|
||||
%1 = moore.read %l1 : l1
|
||||
%2 = moore.read %b5 : i5
|
||||
%3 = moore.read %int : i32
|
||||
%4 = moore.read %int2 : i32
|
||||
%5 = moore.read %integer : l32
|
||||
%6 = moore.read %integer2 : l32
|
||||
%7 = moore.read %arr : uarray<2 x uarray<4 x i8>>
|
||||
|
||||
// CHECK: moore.constant 0 : i32
|
||||
moore.constant 0 : i32
|
||||
|
@ -107,125 +138,152 @@ moore.module @Expressions() {
|
|||
// CHECK: moore.constant -2 : i2
|
||||
moore.constant -2 : i2
|
||||
|
||||
// CHECK: moore.conversion %b5 : !moore.i5 -> !moore.l5
|
||||
moore.conversion %b5 : !moore.i5 -> !moore.l5
|
||||
// CHECK: moore.conversion %[[b5]] : !moore.i5 -> !moore.l5
|
||||
moore.conversion %2 : !moore.i5 -> !moore.l5
|
||||
|
||||
// CHECK: moore.neg %int : i32
|
||||
moore.neg %int : i32
|
||||
// CHECK: moore.not %int : i32
|
||||
moore.not %int : i32
|
||||
// CHECK: moore.neg %[[int]] : i32
|
||||
moore.neg %3 : i32
|
||||
// CHECK: moore.not %[[int]] : i32
|
||||
moore.not %3 : i32
|
||||
|
||||
// CHECK: moore.reduce_and %int : i32 -> i1
|
||||
moore.reduce_and %int : i32 -> i1
|
||||
// CHECK: moore.reduce_or %int : i32 -> i1
|
||||
moore.reduce_or %int : i32 -> i1
|
||||
// CHECK: moore.reduce_xor %int : i32 -> i1
|
||||
moore.reduce_xor %int : i32 -> i1
|
||||
// CHECK: moore.reduce_xor %integer : l32 -> l1
|
||||
moore.reduce_xor %integer : l32 -> l1
|
||||
// CHECK: moore.reduce_and %[[int]] : i32 -> i1
|
||||
moore.reduce_and %3 : i32 -> i1
|
||||
// CHECK: moore.reduce_or %[[int]] : i32 -> i1
|
||||
moore.reduce_or %3 : i32 -> i1
|
||||
// CHECK: moore.reduce_xor %[[int]] : i32 -> i1
|
||||
moore.reduce_xor %3 : i32 -> i1
|
||||
// CHECK: moore.reduce_xor %[[integer]] : l32 -> l1
|
||||
moore.reduce_xor %5 : l32 -> l1
|
||||
|
||||
// CHECK: moore.bool_cast %int : i32 -> i1
|
||||
moore.bool_cast %int : i32 -> i1
|
||||
// CHECK: moore.bool_cast %integer : l32 -> l1
|
||||
moore.bool_cast %integer : l32 -> l1
|
||||
// CHECK: moore.bool_cast %[[int]] : i32 -> i1
|
||||
moore.bool_cast %3 : i32 -> i1
|
||||
// CHECK: moore.bool_cast %[[integer]] : l32 -> l1
|
||||
moore.bool_cast %5 : l32 -> l1
|
||||
|
||||
// CHECK: moore.add %int, %int2 : i32
|
||||
moore.add %int, %int2 : i32
|
||||
// CHECK: moore.sub %int, %int2 : i32
|
||||
moore.sub %int, %int2 : i32
|
||||
// CHECK: moore.mul %int, %int2 : i32
|
||||
moore.mul %int, %int2 : i32
|
||||
// CHECK: moore.divu %int, %int2 : i32
|
||||
moore.divu %int, %int2 : i32
|
||||
// CHECK: moore.divs %int, %int2 : i32
|
||||
moore.divs %int, %int2 : i32
|
||||
// CHECK: moore.modu %int, %int2 : i32
|
||||
moore.modu %int, %int2 : i32
|
||||
// CHECK: moore.mods %int, %int2 : i32
|
||||
moore.mods %int, %int2 : i32
|
||||
// CHECK: moore.add %[[int]], %[[int2]] : i32
|
||||
moore.add %3, %4 : i32
|
||||
// CHECK: moore.sub %[[int]], %[[int2]] : i32
|
||||
moore.sub %3, %4 : i32
|
||||
// CHECK: moore.mul %[[int]], %[[int2]] : i32
|
||||
moore.mul %3, %4 : i32
|
||||
// CHECK: moore.divu %[[int]], %[[int2]] : i32
|
||||
moore.divu %3, %4 : i32
|
||||
// CHECK: moore.divs %[[int]], %[[int2]] : i32
|
||||
moore.divs %3, %4 : i32
|
||||
// CHECK: moore.modu %[[int]], %[[int2]] : i32
|
||||
moore.modu %3, %4 : i32
|
||||
// CHECK: moore.mods %[[int]], %[[int2]] : i32
|
||||
moore.mods %3, %4 : i32
|
||||
|
||||
// CHECK: moore.and %int, %int2 : i32
|
||||
moore.and %int, %int2 : i32
|
||||
// CHECK: moore.or %int, %int2 : i32
|
||||
moore.or %int, %int2 : i32
|
||||
// CHECK: moore.xor %int, %int2 : i32
|
||||
moore.xor %int, %int2 : i32
|
||||
// CHECK: moore.and %[[int]], %[[int2]] : i32
|
||||
moore.and %3, %4 : i32
|
||||
// CHECK: moore.or %[[int]], %[[int2]] : i32
|
||||
moore.or %3, %4 : i32
|
||||
// CHECK: moore.xor %[[int]], %[[int2]] : i32
|
||||
moore.xor %3, %4 : i32
|
||||
|
||||
// CHECK: moore.shl %l1, %b1 : l1, i1
|
||||
moore.shl %l1, %b1 : l1, i1
|
||||
// CHECK: moore.shr %l1, %b1 : l1, i1
|
||||
moore.shr %l1, %b1 : l1, i1
|
||||
// CHECK: moore.ashr %b5, %b1 : i5, i1
|
||||
moore.ashr %b5, %b1 : i5, i1
|
||||
// CHECK: moore.shl %[[l1]], %[[b1]] : l1, i1
|
||||
moore.shl %1, %0 : l1, i1
|
||||
// CHECK: moore.shr %[[l1]], %[[b1]] : l1, i1
|
||||
moore.shr %1, %0 : l1, i1
|
||||
// CHECK: moore.ashr %[[b5]], %[[b1]] : i5, i1
|
||||
moore.ashr %2, %0 : i5, i1
|
||||
|
||||
// CHECK: moore.eq %int, %int2 : i32 -> i1
|
||||
moore.eq %int, %int2 : i32 -> i1
|
||||
// CHECK: moore.ne %int, %int2 : i32 -> i1
|
||||
moore.ne %int, %int2 : i32 -> i1
|
||||
// CHECK: moore.ne %integer, %integer2 : l32 -> l1
|
||||
moore.ne %integer, %integer2 : l32 -> l1
|
||||
// CHECK: moore.case_eq %int, %int2 : i32
|
||||
moore.case_eq %int, %int2 : i32
|
||||
// CHECK: moore.case_ne %int, %int2 : i32
|
||||
moore.case_ne %int, %int2 : i32
|
||||
// CHECK: moore.wildcard_eq %int, %int2 : i32 -> i1
|
||||
moore.wildcard_eq %int, %int2 : i32 -> i1
|
||||
// CHECK: moore.wildcard_ne %int, %int2 : i32 -> i1
|
||||
moore.wildcard_ne %int, %int2 : i32 -> i1
|
||||
// CHECK: moore.wildcard_ne %integer, %integer2 : l32 -> l1
|
||||
moore.wildcard_ne %integer, %integer2 : l32 -> l1
|
||||
// CHECK: moore.eq %[[int]], %[[int2]] : i32 -> i1
|
||||
moore.eq %3, %4 : i32 -> i1
|
||||
// CHECK: moore.ne %[[int]], %[[int2]] : i32 -> i1
|
||||
moore.ne %3, %4 : i32 -> i1
|
||||
// CHECK: moore.ne %[[integer]], %[[integer2]] : l32 -> l1
|
||||
moore.ne %5, %6 : l32 -> l1
|
||||
// CHECK: moore.case_eq %[[int]], %[[int2]] : i32
|
||||
moore.case_eq %3, %4 : i32
|
||||
// CHECK: moore.case_ne %[[int]], %[[int2]] : i32
|
||||
moore.case_ne %3, %4 : i32
|
||||
// CHECK: moore.wildcard_eq %[[int]], %[[int2]] : i32 -> i1
|
||||
moore.wildcard_eq %3, %4 : i32 -> i1
|
||||
// CHECK: moore.wildcard_ne %[[int]], %[[int2]] : i32 -> i1
|
||||
moore.wildcard_ne %3, %4 : i32 -> i1
|
||||
// CHECK: moore.wildcard_ne %[[integer]], %[[integer2]] : l32 -> l1
|
||||
moore.wildcard_ne %5, %6 : l32 -> l1
|
||||
|
||||
// CHECK: moore.ult %int, %int2 : i32 -> i1
|
||||
moore.ult %int, %int2 : i32 -> i1
|
||||
// CHECK: moore.ule %int, %int2 : i32 -> i1
|
||||
moore.ule %int, %int2 : i32 -> i1
|
||||
// CHECK: moore.ugt %int, %int2 : i32 -> i1
|
||||
moore.ugt %int, %int2 : i32 -> i1
|
||||
// CHECK: moore.uge %int, %int2 : i32 -> i1
|
||||
moore.uge %int, %int2 : i32 -> i1
|
||||
// CHECK: moore.slt %int, %int2 : i32 -> i1
|
||||
moore.slt %int, %int2 : i32 -> i1
|
||||
// CHECK: moore.sle %int, %int2 : i32 -> i1
|
||||
moore.sle %int, %int2 : i32 -> i1
|
||||
// CHECK: moore.sgt %int, %int2 : i32 -> i1
|
||||
moore.sgt %int, %int2 : i32 -> i1
|
||||
// CHECK: moore.sge %int, %int2 : i32 -> i1
|
||||
moore.sge %int, %int2 : i32 -> i1
|
||||
// CHECK: moore.uge %integer, %integer2 : l32 -> l1
|
||||
moore.uge %integer, %integer2 : l32 -> l1
|
||||
// CHECK: moore.ult %[[int]], %[[int2]] : i32 -> i1
|
||||
moore.ult %3, %4 : i32 -> i1
|
||||
// CHECK: moore.ule %[[int]], %[[int2]] : i32 -> i1
|
||||
moore.ule %3, %4 : i32 -> i1
|
||||
// CHECK: moore.ugt %[[int]], %[[int2]] : i32 -> i1
|
||||
moore.ugt %3, %4 : i32 -> i1
|
||||
// CHECK: moore.uge %[[int]], %[[int2]] : i32 -> i1
|
||||
moore.uge %3, %4 : i32 -> i1
|
||||
// CHECK: moore.slt %[[int]], %[[int2]] : i32 -> i1
|
||||
moore.slt %3, %4 : i32 -> i1
|
||||
// CHECK: moore.sle %[[int]], %[[int2]] : i32 -> i1
|
||||
moore.sle %3, %4 : i32 -> i1
|
||||
// CHECK: moore.sgt %[[int]], %[[int2]] : i32 -> i1
|
||||
moore.sgt %3, %4 : i32 -> i1
|
||||
// CHECK: moore.sge %[[int]], %[[int2]] : i32 -> i1
|
||||
moore.sge %3, %4 : i32 -> i1
|
||||
// CHECK: moore.uge %[[integer]], %[[integer2]] : l32 -> l1
|
||||
moore.uge %5, %6 : l32 -> l1
|
||||
|
||||
// CHECK: moore.concat %b1 : (!moore.i1) -> i1
|
||||
moore.concat %b1 : (!moore.i1) -> i1
|
||||
// CHECK: moore.concat %b5, %b1 : (!moore.i5, !moore.i1) -> i6
|
||||
moore.concat %b5, %b1 : (!moore.i5, !moore.i1) -> i6
|
||||
// CHECK: moore.concat %l1, %l1, %l1 : (!moore.l1, !moore.l1, !moore.l1) -> l3
|
||||
moore.concat %l1, %l1, %l1 : (!moore.l1, !moore.l1, !moore.l1) -> l3
|
||||
// CHECK: moore.replicate %b1 : i1 -> i4
|
||||
moore.replicate %b1 : i1 -> i4
|
||||
// CHECK: moore.concat %[[b1]] : (!moore.i1) -> i1
|
||||
moore.concat %0 : (!moore.i1) -> i1
|
||||
// CHECK: moore.concat %[[b5]], %[[b1]] : (!moore.i5, !moore.i1) -> i6
|
||||
moore.concat %2, %0 : (!moore.i5, !moore.i1) -> i6
|
||||
// CHECK: moore.concat %[[l1]], %[[l1]], %[[l1]] : (!moore.l1, !moore.l1, !moore.l1) -> l3
|
||||
moore.concat %1, %1, %1 : (!moore.l1, !moore.l1, !moore.l1) -> l3
|
||||
// CHECK: moore.concat_ref %b1 : (!moore.ref<i1>) -> <i1>
|
||||
moore.concat_ref %b1 : (!moore.ref<i1>) -> <i1>
|
||||
// CHECK: moore.concat_ref %b5, %b1 : (!moore.ref<i5>, !moore.ref<i1>) -> <i6>
|
||||
moore.concat_ref %b5, %b1 : (!moore.ref<i5>, !moore.ref<i1>) -> <i6>
|
||||
// CHECK: moore.concat_ref %l1, %l1, %l1 : (!moore.ref<l1>, !moore.ref<l1>, !moore.ref<l1>) -> <l3>
|
||||
moore.concat_ref %l1, %l1, %l1 : (!moore.ref<l1>, !moore.ref<l1>, !moore.ref<l1>) -> <l3>
|
||||
// CHECK: moore.replicate %[[b1]] : i1 -> i4
|
||||
moore.replicate %0 : i1 -> i4
|
||||
|
||||
// CHECK: moore.extract %b5 from %b1 : i5, i1 -> i1
|
||||
moore.extract %b5 from %b1 : i5, i1 -> i1
|
||||
// CHECK: [[VAL1:%.*]] = moore.constant 0 : i32
|
||||
// CHECK: [[VAL2:%.*]] = moore.extract %arr from [[VAL1]] : uarray<2 x uarray<4 x i8>>, i32 -> uarray<4 x i8>
|
||||
%1 = moore.constant 0 : i32
|
||||
%2 = moore.extract %arr from %1 : uarray<2 x uarray<4 x i8>>, i32 -> uarray<4 x i8>
|
||||
// CHECK: [[VAL3:%.*]] = moore.constant 3 : i32
|
||||
// CHECK: [[VAL4:%.*]] = moore.extract [[VAL2]] from [[VAL3]] : uarray<4 x i8>, i32 -> i8
|
||||
%3 = moore.constant 3 : i32
|
||||
%4 = moore.extract %2 from %3 : uarray<4 x i8>, i32 -> i8
|
||||
// CHECK: [[VAL5:%.*]] = moore.constant 2 : i32
|
||||
// CHECK: moore.extract [[VAL4]] from [[VAL5]] : i8, i32 -> i5
|
||||
%5 = moore.constant 2 : i32
|
||||
moore.extract %4 from %5 : i8, i32 -> i5
|
||||
// CHECK: moore.extract %[[b5]] from %[[b1]] : i5, i1 -> i1
|
||||
moore.extract %2 from %0 : i5, i1 -> i1
|
||||
// CHECK: %[[VAL1:.*]] = moore.constant 0 : i32
|
||||
// CHECK: %[[VAL2:.*]] = moore.extract %[[arr]] from %[[VAL1]] : uarray<2 x uarray<4 x i8>>, i32 -> uarray<4 x i8>
|
||||
%11 = moore.constant 0 : i32
|
||||
%12 = moore.extract %7 from %11 : uarray<2 x uarray<4 x i8>>, i32 -> uarray<4 x i8>
|
||||
// CHECK: %[[VAL3:.*]] = moore.constant 3 : i32
|
||||
// CHECK: %[[VAL4:.*]] = moore.extract %[[VAL2]] from %[[VAL3]] : uarray<4 x i8>, i32 -> i8
|
||||
%13 = moore.constant 3 : i32
|
||||
%14 = moore.extract %12 from %13 : uarray<4 x i8>, i32 -> i8
|
||||
// CHECK: %[[VAL5:.*]] = moore.constant 2 : i32
|
||||
// CHECK: moore.extract %[[VAL4]] from %[[VAL5]] : i8, i32 -> i5
|
||||
%15 = moore.constant 2 : i32
|
||||
moore.extract %14 from %15 : i8, i32 -> i5
|
||||
|
||||
// CHECK: moore.conditional %b1 : i1 -> i32 {
|
||||
// CHECK: moore.yield %int : i32
|
||||
// CHECK: moore.extract_ref %b5 from %[[b1]] : <i5>, i1 -> <i1>
|
||||
moore.extract_ref %b5 from %0 : <i5>, i1 -> <i1>
|
||||
// CHECK: %[[TMP1:.+]] = moore.constant 0
|
||||
// CHECK: %[[TMP2:.+]] = moore.extract_ref %arr from %[[TMP1]] : <uarray<2 x uarray<4 x i8>>>, i32 -> <uarray<4 x i8>>
|
||||
%16 = moore.constant 0 : i32
|
||||
%17 = moore.extract_ref %arr from %16 : <uarray<2 x uarray<4 x i8>>>, i32 -> <uarray<4 x i8>>
|
||||
// CHECK: %[[TMP3:.+]] = moore.constant 3
|
||||
// CHECK: %[[TMP4:.+]] = moore.extract_ref %[[TMP2]] from %[[TMP3]] : <uarray<4 x i8>>, i32 -> <i8>
|
||||
%18 = moore.constant 3 : i32
|
||||
%19 = moore.extract_ref %17 from %18 : <uarray<4 x i8>>, i32 -> <i8>
|
||||
// CHECK: %[[TMP5:.+]] = moore.constant 2
|
||||
// CHECK: extract_ref %[[TMP4]] from %[[TMP5]] : <i8>, i32 -> <i4>
|
||||
%20 = moore.constant 2 : i32
|
||||
moore.extract_ref %19 from %20 : <i8>, i32 -> <i4>
|
||||
|
||||
// CHECK: %[[B1_COND:.+]] = moore.read %b1
|
||||
// CHECK: moore.conditional %[[B1_COND]] : i1 -> i32 {
|
||||
// CHECK: %[[INT_READ:.+]] = moore.read %int
|
||||
// CHECK: moore.yield %[[INT_READ]] : i32
|
||||
// CHECK: } {
|
||||
// CHECK: moore.yield %int2 : i32
|
||||
// CHECK: %[[INT2_READ:.+]] = moore.read %int2
|
||||
// CHECK: moore.yield %[[INT2_READ]] : i32
|
||||
// CHECK: }
|
||||
moore.conditional %b1 : i1 -> i32 {
|
||||
moore.yield %int : i32
|
||||
%21 = moore.read %b1 : i1
|
||||
moore.conditional %21 : i1 -> i32 {
|
||||
%22 = moore.read %int : i32
|
||||
moore.yield %22 : i32
|
||||
} {
|
||||
moore.yield %int2 : i32
|
||||
%22 = moore.read %int2 : i32
|
||||
moore.yield %22 : i32
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,22 +68,26 @@ moore.constant -2 : !moore.i1
|
|||
|
||||
// -----
|
||||
|
||||
%y = moore.variable : i8
|
||||
%y = moore.variable : <i8>
|
||||
|
||||
moore.module @Cond() {
|
||||
%0 = moore.read %y : i8
|
||||
// expected-error @below {{'moore.yield' op expects parent op 'moore.conditional'}}
|
||||
moore.yield %y : i8
|
||||
moore.yield %0 : i8
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
%x = moore.variable : i1
|
||||
%t = moore.variable : i8
|
||||
%f = moore.variable : i8
|
||||
%x = moore.variable : <i1>
|
||||
%t = moore.variable : <i8>
|
||||
%f = moore.variable : <i8>
|
||||
|
||||
moore.conditional %x : i1 -> i32 {
|
||||
%1 = moore.read %x : i1
|
||||
moore.conditional %1 : i1 -> i32 {
|
||||
%2 = moore.read %t : i8
|
||||
// expected-error @below {{yield type must match conditional. Expected '!moore.i32', but got '!moore.i8'}}
|
||||
moore.yield %t : i8
|
||||
moore.yield %2 : i8
|
||||
} {
|
||||
moore.yield %f : i8
|
||||
%2 = moore.read %f : i8
|
||||
moore.yield %2 : i8
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue