diff --git a/frontends/PyRTG/test/basic.py b/frontends/PyRTG/test/basic.py index 047f4b404a5d..a7fced953740 100644 --- a/frontends/PyRTG/test/basic.py +++ b/frontends/PyRTG/test/basic.py @@ -20,10 +20,10 @@ def entry0(): return Set.create(Integer(0), Integer(1)) -# MLIR-LABEL: rtg.target @Tgt1 : !rtg.dict +# MLIR-LABEL: rtg.target @Tgt1 : !rtg.dict # MLIR-NEXT: [[C0:%.+]] = index.constant 0 # MLIR-NEXT: [[LBL:%.+]] = rtg.label_decl "l0" -# MLIR-NEXT: rtg.yield [[C0]], [[LBL]] : index, !rtg.label +# MLIR-NEXT: rtg.yield [[C0]], [[LBL]] : index, !rtg.isa.label # MLIR-NEXT: } @@ -40,7 +40,7 @@ def entry1(): # MLIR-LABEL: rtg.sequence @seq0 -# MLIR-SAME: ([[SET:%.+]]: !rtg.set) +# MLIR-SAME: ([[SET:%.+]]: !rtg.set) # MLIR-NEXT: [[LABEL:%.+]] = rtg.set_select_random [[SET]] # MLIR-NEXT: rtg.label local [[LABEL]] # MLIR-NEXT: } @@ -114,15 +114,15 @@ def test_args(set: Set): # MLIR-NEXT: rtg.label external [[L1]] # MLIR-NEXT: rtg.label local [[L2]] -# MLIR-NEXT: [[SET0:%.+]] = rtg.set_create [[L0]], [[L1]] : !rtg.label -# MLIR-NEXT: [[SET1:%.+]] = rtg.set_create [[L2]] : !rtg.label -# MLIR-NEXT: [[EMPTY_SET:%.+]] = rtg.set_create : !rtg.label -# MLIR-NEXT: [[SET2_1:%.+]] = rtg.set_union [[SET0]], [[SET1]] : !rtg.set -# MLIR-NEXT: [[SET2:%.+]] = rtg.set_union [[SET2_1]], [[EMPTY_SET]] : !rtg.set -# MLIR-NEXT: [[RL0:%.+]] = rtg.set_select_random [[SET2]] : !rtg.set +# MLIR-NEXT: [[SET0:%.+]] = rtg.set_create [[L0]], [[L1]] : !rtg.isa.label +# MLIR-NEXT: [[SET1:%.+]] = rtg.set_create [[L2]] : !rtg.isa.label +# MLIR-NEXT: [[EMPTY_SET:%.+]] = rtg.set_create : !rtg.isa.label +# MLIR-NEXT: [[SET2_1:%.+]] = rtg.set_union [[SET0]], [[SET1]] : !rtg.set +# MLIR-NEXT: [[SET2:%.+]] = rtg.set_union [[SET2_1]], [[EMPTY_SET]] : !rtg.set +# MLIR-NEXT: [[RL0:%.+]] = rtg.set_select_random [[SET2]] : !rtg.set # MLIR-NEXT: rtg.label local [[RL0]] -# MLIR-NEXT: [[SET2_MINUS_SET0:%.+]] = rtg.set_difference [[SET2]], [[SET0]] : !rtg.set -# MLIR-NEXT: [[RL1:%.+]] = rtg.set_select_random [[SET2_MINUS_SET0]] : !rtg.set +# MLIR-NEXT: [[SET2_MINUS_SET0:%.+]] = rtg.set_difference [[SET2]], [[SET0]] : !rtg.set +# MLIR-NEXT: [[RL1:%.+]] = rtg.set_select_random [[SET2_MINUS_SET0]] : !rtg.set # MLIR-NEXT: rtg.label local [[RL1]] # MLIR-NEXT: rtg.label_decl "L_{{[{][{]0[}][}]}}", %idx5 @@ -130,21 +130,21 @@ def test_args(set: Set): # MLIR-NEXT: rtg.label_decl "L_{{[{][{]0[}][}]}}", %idx3 # MLIR-NEXT: rtg.label local -# MLIR-NEXT: [[BAG0:%.+]] = rtg.bag_create (%idx2 x [[L0:%.+]], %idx1 x [[L1:%.+]]) : !rtg.label -# MLIR-NEXT: [[BAG1:%.+]] = rtg.bag_create (%idx1 x [[L2:%.+]]) : !rtg.label -# MLIR-NEXT: [[EMPTY_BAG:%.+]] = rtg.bag_create : !rtg.label -# MLIR-NEXT: [[BAG2_1:%.+]] = rtg.bag_union [[BAG0]], [[BAG1]] : !rtg.bag -# MLIR-NEXT: [[BAG2:%.+]] = rtg.bag_union [[BAG2_1]], [[EMPTY_BAG]] : !rtg.bag -# MLIR-NEXT: [[RL2:%.+]] = rtg.bag_select_random [[BAG2]] : !rtg.bag -# MLIR-NEXT: [[SUB:%.+]] = rtg.bag_create (%idx1 x [[RL2]]) : !rtg.label -# MLIR-NEXT: [[BAG3:%.+]] = rtg.bag_difference [[BAG2]], [[SUB]] inf : !rtg.bag +# MLIR-NEXT: [[BAG0:%.+]] = rtg.bag_create (%idx2 x [[L0:%.+]], %idx1 x [[L1:%.+]]) : !rtg.isa.label +# MLIR-NEXT: [[BAG1:%.+]] = rtg.bag_create (%idx1 x [[L2:%.+]]) : !rtg.isa.label +# MLIR-NEXT: [[EMPTY_BAG:%.+]] = rtg.bag_create : !rtg.isa.label +# MLIR-NEXT: [[BAG2_1:%.+]] = rtg.bag_union [[BAG0]], [[BAG1]] : !rtg.bag +# MLIR-NEXT: [[BAG2:%.+]] = rtg.bag_union [[BAG2_1]], [[EMPTY_BAG]] : !rtg.bag +# MLIR-NEXT: [[RL2:%.+]] = rtg.bag_select_random [[BAG2]] : !rtg.bag +# MLIR-NEXT: [[SUB:%.+]] = rtg.bag_create (%idx1 x [[RL2]]) : !rtg.isa.label +# MLIR-NEXT: [[BAG3:%.+]] = rtg.bag_difference [[BAG2]], [[SUB]] inf : !rtg.bag # MLIR-NEXT: rtg.label local [[RL2]] -# MLIR-NEXT: [[BAG4:%.+]] = rtg.bag_difference [[BAG3]], [[BAG1]] : !rtg.bag -# MLIR-NEXT: [[RL3:%.+]] = rtg.bag_select_random [[BAG4]] : !rtg.bag +# MLIR-NEXT: [[BAG4:%.+]] = rtg.bag_difference [[BAG3]], [[BAG1]] : !rtg.bag +# MLIR-NEXT: [[RL3:%.+]] = rtg.bag_select_random [[BAG4]] : !rtg.bag # MLIR-NEXT: rtg.label local [[RL3]] -# MLIR-NEXT: [[SEQ:%.+]] = rtg.get_sequence @seq0 : !rtg.sequence> -# MLIR-NEXT: [[SUBST:%.+]] = rtg.substitute_sequence [[SEQ]]([[SET0]]) : !rtg.sequence> +# MLIR-NEXT: [[SEQ:%.+]] = rtg.get_sequence @seq0 : !rtg.sequence> +# MLIR-NEXT: [[SUBST:%.+]] = rtg.substitute_sequence [[SEQ]]([[SET0]]) : !rtg.sequence> # MLIR-NEXT: [[RAND1:%.+]] = rtg.randomize_sequence [[SUBST]] # MLIR-NEXT: rtg.embed_sequence [[RAND1]] # MLIR-NEXT: [[RAND2:%.+]] = rtg.randomize_sequence [[SUBST]] diff --git a/include/circt-c/Dialect/RTG.h b/include/circt-c/Dialect/RTG.h index 9b0913daf079..0460659fcdba 100644 --- a/include/circt-c/Dialect/RTG.h +++ b/include/circt-c/Dialect/RTG.h @@ -79,6 +79,16 @@ MLIR_CAPI_EXPORTED MlirType rtgDictTypeGet(MlirContext ctxt, MlirAttribute const *entryNames, MlirType const *entryTypes); +/// If the type is an RTG immediate. +MLIR_CAPI_EXPORTED bool rtgTypeIsAImmediate(MlirType type); + +/// Creates an RTG immediate type in the context. +MLIR_CAPI_EXPORTED MlirType rtgImmediateTypeGet(MlirContext ctx, + uint32_t width); + +/// Returns the width of the RTG immediate type. +MLIR_CAPI_EXPORTED uint32_t rtgImmediateTypeGetWidth(MlirType type); + //===----------------------------------------------------------------------===// // Attribute API. //===----------------------------------------------------------------------===// @@ -108,6 +118,21 @@ MLIR_CAPI_EXPORTED bool rtgAttrIsADefaultContextAttr(MlirAttribute attr); MLIR_CAPI_EXPORTED MlirAttribute rtgDefaultContextAttrGet(MlirContext ctxt, MlirType type); +/// Checks if the attribute is an RTG immediate attribute. +MLIR_CAPI_EXPORTED bool rtgAttrIsAImmediate(MlirAttribute attr); + +/// Creates an RTG immediate attribute in the context with the given width and +/// value. +MLIR_CAPI_EXPORTED MlirAttribute rtgImmediateAttrGet(MlirContext ctx, + uint32_t width, + uint64_t value); + +/// Returns the width of the RTG immediate attribute. +MLIR_CAPI_EXPORTED uint32_t rtgImmediateAttrGetWidth(MlirAttribute attr); + +/// Returns the value of the RTG immediate attribute. +MLIR_CAPI_EXPORTED uint64_t rtgImmediateAttrGetValue(MlirAttribute attr); + #ifdef __cplusplus } #endif diff --git a/include/circt/Dialect/RTG/IR/RTGAttributes.h b/include/circt/Dialect/RTG/IR/RTGAttributes.h index 9a1c581360e9..f3cb1e1ce3f0 100644 --- a/include/circt/Dialect/RTG/IR/RTGAttributes.h +++ b/include/circt/Dialect/RTG/IR/RTGAttributes.h @@ -10,6 +10,7 @@ #define CIRCT_DIALECT_RTG_IR_RTGATTRIBUTES_H #include "circt/Dialect/RTG/IR/RTGAttrInterfaces.h" +#include "circt/Dialect/RTG/IR/RTGTypes.h" #include "mlir/IR/Attributes.h" #include "mlir/IR/BuiltinAttributes.h" diff --git a/include/circt/Dialect/RTG/IR/RTGAttributes.td b/include/circt/Dialect/RTG/IR/RTGAttributes.td index 6debe9c2b652..896716682a7e 100644 --- a/include/circt/Dialect/RTG/IR/RTGAttributes.td +++ b/include/circt/Dialect/RTG/IR/RTGAttributes.td @@ -75,4 +75,25 @@ def DefaultContextAttr : RTGAttrDef<"DefaultContext", [ let assemblyFormat = ""; } +//===----------------------------------------------------------------------===// +// Attributes for ISA targets +//===----------------------------------------------------------------------===// + +class RTGISAAttrDef traits = []> + : RTGAttrDef { let mnemonic = "isa." # !tolower(name); } + +def ImmediateAttr : RTGISAAttrDef<"Immediate", [ + DeclareAttrInterfaceMethods, +]> { + let summary = "an ISA immediate value"; + let description = [{ + This represents an ISA immediate of arbitrary but fixed bit-width. The type + of this attribute must always be an `ImmediateType` of matching bit-width. + }]; + + let parameters = (ins "llvm::APInt":$value); + + let hasCustomAssemblyFormat = true; +} + #endif // CIRCT_DIALECT_RTG_IR_RTGATTRIBUTES_TD diff --git a/include/circt/Dialect/RTG/IR/RTGDialect.td b/include/circt/Dialect/RTG/IR/RTGDialect.td index e86d46de999e..17f695000551 100644 --- a/include/circt/Dialect/RTG/IR/RTGDialect.td +++ b/include/circt/Dialect/RTG/IR/RTGDialect.td @@ -29,6 +29,8 @@ def RTGDialect : Dialect { let useDefaultTypePrinterParser = 1; let cppNamespace = "::circt::rtg"; + let hasConstantMaterializer = 1; + let extraClassDeclaration = [{ void registerAttributes(); void registerTypes(); diff --git a/include/circt/Dialect/RTG/IR/RTGOps.td b/include/circt/Dialect/RTG/IR/RTGOps.td index e120d2b8e615..28d946ae155c 100644 --- a/include/circt/Dialect/RTG/IR/RTGOps.td +++ b/include/circt/Dialect/RTG/IR/RTGOps.td @@ -25,6 +25,21 @@ include "circt/Dialect/RTG/IR/RTGISAAssemblyInterfaces.td" class RTGOp traits = []> : Op; + +def ConstantOp : RTGOp<"constant", [ + Pure, + ConstantLike, + DeclareOpInterfaceMethods +]> { + let summary = "create an SSA value from an attribute"; + + let arguments = (ins TypedAttrInterface:$value); + let results = (outs AnyType:$result); + + let assemblyFormat = "$value attr-dict"; + let hasFolder = 1; +} + //===- Sequence Handling Operations ---------------------------------------===// def SequenceOp : RTGOp<"sequence", [ diff --git a/include/circt/Dialect/RTG/IR/RTGTypes.td b/include/circt/Dialect/RTG/IR/RTGTypes.td index 7f991db42f13..6c7f5102bf5f 100644 --- a/include/circt/Dialect/RTG/IR/RTGTypes.td +++ b/include/circt/Dialect/RTG/IR/RTGTypes.td @@ -16,7 +16,12 @@ include "circt/Dialect/RTG/IR/RTGDialect.td" include "mlir/IR/AttrTypeBase.td" -class RTGTypeDef : TypeDef; +class RTGTypeDef traits = []> + : TypeDef; + +//===----------------------------------------------------------------------===// +// Sequence Types +//===----------------------------------------------------------------------===// def SequenceType : RTGTypeDef<"Sequence"> { let summary = "handle to a sequence or sequence family"; @@ -51,17 +56,9 @@ def FullySubstitutedSequenceType : DialectType{})">; -def LabelType : RTGTypeDef<"Label"> { - let summary = "a reference to a label"; - let description = [{ - This type represents a label. Payload dialects can add operations to cast - from this type to an immediate type they can use as an operand to an - instruction. - }]; - - let mnemonic = "label"; - let assemblyFormat = ""; -} +//===----------------------------------------------------------------------===// +// Types for common datastructures +//===----------------------------------------------------------------------===// def SetType : RTGTypeDef<"Set"> { let summary = "a set of values"; @@ -123,6 +120,43 @@ def DictType : RTGTypeDef<"Dict"> { let genVerifyDecl = 1; } +//===----------------------------------------------------------------------===// +// Types for ISA targets +//===----------------------------------------------------------------------===// + +class RTGISATypeDef traits = []> + : RTGTypeDef { let mnemonic = "isa." # !tolower(name); } + + +def LabelType : RTGISATypeDef<"Label"> { + let summary = "a reference to a label"; + let description = [{ + This type represents a label. Payload dialects can add operations to cast + from this type to an immediate type they can use as an operand to an + instruction or allow an operand of this type directly. + }]; + + let assemblyFormat = ""; +} + +def ImmediateType : RTGISATypeDef<"Immediate"> { + let summary = "an ISA immediate"; + let description = [{ + This type represents immediates of arbitrary but fixed bit-width. + The RTG dialect provides this type to avoid duplication in ISA payload + dialects. + }]; + + let parameters = (ins "uint32_t":$width); + let assemblyFormat = "`<` $width `>`"; +} + +class ImmediateOfWidth : Type< + And<[CPred<"llvm::isa<::circt::rtg::ImmediateType>($_self)">, + CPred<"llvm::cast<::circt::rtg::ImmediateType>($_self).getWidth() == " # width>]>, + "a " # width # "-bit immediate">, + BuildableType<"::circt::rtg::ImmediateType::get($_builder.getContext(), " # width # ")">; + class ImmTypeBase : TypeDef { let summary = "represents a " # width # "-bit immediate"; let mnemonic = "imm" # width; diff --git a/include/circt/Dialect/RTG/IR/RTGVisitors.h b/include/circt/Dialect/RTG/IR/RTGVisitors.h index 01c1cc68a1d0..1cdba41667d7 100644 --- a/include/circt/Dialect/RTG/IR/RTGVisitors.h +++ b/include/circt/Dialect/RTG/IR/RTGVisitors.h @@ -32,6 +32,8 @@ class RTGOpVisitor { auto *thisCast = static_cast(this); return TypeSwitch(op) .template Case< + // Constants + ConstantOp, // Bags BagCreateOp, BagSelectRandomOp, BagDifferenceOp, BagUnionOp, BagUniqueSizeOp, @@ -82,6 +84,7 @@ class RTGOpVisitor { return static_cast(this)->visit##OPKIND##Op(op, args...); \ } + HANDLE(ConstantOp, Unhandled); HANDLE(SequenceOp, Unhandled); HANDLE(GetSequenceOp, Unhandled); HANDLE(SubstituteSequenceOp, Unhandled); @@ -120,10 +123,11 @@ class RTGTypeVisitor { ResultType dispatchTypeVisitor(Type type, ExtraArgs... args) { auto *thisCast = static_cast(this); return TypeSwitch(type) - .template Case([&](auto expr) -> ResultType { - return thisCast->visitType(expr, args...); - }) + .template Case( + [&](auto expr) -> ResultType { + return thisCast->visitType(expr, args...); + }) .template Case( [&](auto expr) -> ResultType { return thisCast->visitContextResourceType(expr, args...); @@ -163,6 +167,7 @@ class RTGTypeVisitor { args...); \ } + HANDLE(ImmediateType, Unhandled); HANDLE(SequenceType, Unhandled); HANDLE(SetType, Unhandled); HANDLE(BagType, Unhandled); diff --git a/integration_test/Bindings/Python/dialects/rtg.py b/integration_test/Bindings/Python/dialects/rtg.py index 2d238fe0d067..6a5f64852945 100644 --- a/integration_test/Bindings/Python/dialects/rtg.py +++ b/integration_test/Bindings/Python/dialects/rtg.py @@ -106,7 +106,7 @@ # CHECK: index{{$}} print(bagTy.element_type) - # CHECK: rtg.sequence @seq(%{{.*}}: !rtg.sequence, %{{.*}}: !rtg.label, %{{.*}}: !rtg.set, %{{.*}}: !rtg.bag, %{{.*}}: !rtgtest.ireg, %{{.*}}: !rtg.randomized_sequence) + # CHECK: rtg.sequence @seq(%{{.*}}: !rtg.sequence, %{{.*}}: !rtg.isa.label, %{{.*}}: !rtg.set, %{{.*}}: !rtg.bag, %{{.*}}: !rtgtest.ireg, %{{.*}}: !rtg.randomized_sequence) print(m) with Context() as ctx, Location.unknown(): @@ -221,3 +221,17 @@ print(attr.type) # CHECK: #rtg.default : !rtgtest.cpu print(attr) + + immediate_type = rtg.ImmediateType.get(32) + # CHECK: width=32 + print(f"width={immediate_type.width}") + # CHECK: !rtg.isa.immediate<32> + print(immediate_type) + + immediate_attr = rtg.ImmediateAttr.get(32, 42) + # CHECK: width=32 + print(f"width={immediate_attr.width}") + # CHECK: value=42 + print(f"value={immediate_attr.value}") + # CHECK: #rtg.isa.immediate<32, 42> + print(immediate_attr) diff --git a/lib/Bindings/Python/RTGModule.cpp b/lib/Bindings/Python/RTGModule.cpp index df0c6aa48438..d97848b28706 100644 --- a/lib/Bindings/Python/RTGModule.cpp +++ b/lib/Bindings/Python/RTGModule.cpp @@ -23,6 +23,13 @@ using namespace mlir::python::nanobind_adaptors; void circt::python::populateDialectRTGSubmodule(nb::module_ &m) { m.doc() = "RTG dialect Python native extension"; + //===--------------------------------------------------------------------===// + // Types + //===--------------------------------------------------------------------===// + + // Sequence Types + //===--------------------------------------------------------------------===// + mlir_type_subclass(m, "SequenceType", rtgTypeIsASequence) .def_classmethod( "get", @@ -48,13 +55,8 @@ void circt::python::populateDialectRTGSubmodule(nb::module_ &m) { }, nb::arg("self"), nb::arg("ctxt") = nullptr); - mlir_type_subclass(m, "LabelType", rtgTypeIsALabel) - .def_classmethod( - "get", - [](nb::object cls, MlirContext ctxt) { - return cls(rtgLabelTypeGet(ctxt)); - }, - nb::arg("self"), nb::arg("ctxt") = nullptr); + // Common Datastructure Types + //===--------------------------------------------------------------------===// mlir_type_subclass(m, "SetType", rtgTypeIsASet) .def_classmethod( @@ -98,6 +100,43 @@ void circt::python::populateDialectRTGSubmodule(nb::module_ &m) { std::vector>(), nb::arg("ctxt") = nullptr); + // Types for ISA targets + //===--------------------------------------------------------------------===// + + mlir_type_subclass(m, "LabelType", rtgTypeIsALabel) + .def_classmethod( + "get", + [](nb::object cls, MlirContext ctxt) { + return cls(rtgLabelTypeGet(ctxt)); + }, + nb::arg("self"), nb::arg("ctxt") = nullptr); + + mlir_type_subclass(m, "ImmediateType", rtgTypeIsAImmediate) + .def_classmethod( + "get", + [](nb::object cls, uint32_t width, MlirContext ctx) { + return cls(rtgImmediateTypeGet(ctx, width)); + }, + nb::arg("self"), nb::arg("width"), nb::arg("ctx") = nullptr) + .def_property_readonly("width", [](MlirType self) { + return rtgImmediateTypeGetWidth(self); + }); + + //===--------------------------------------------------------------------===// + // Attributes + //===--------------------------------------------------------------------===// + + mlir_attribute_subclass(m, "DefaultContextAttr", rtgAttrIsADefaultContextAttr) + .def_classmethod( + "get", + [](nb::object cls, MlirType type, MlirContext ctxt) { + return cls(rtgDefaultContextAttrGet(ctxt, type)); + }, + nb::arg("self"), nb::arg("type"), nb::arg("ctxt") = nullptr); + + // Attributes for ISA targets + //===--------------------------------------------------------------------===// + nb::enum_(m, "LabelVisibility") .value("LOCAL", RTG_LABEL_VISIBILITY_LOCAL) .value("GLOBAL", RTG_LABEL_VISIBILITY_GLOBAL) @@ -116,11 +155,18 @@ void circt::python::populateDialectRTGSubmodule(nb::module_ &m) { return rtgLabelVisibilityAttrGetValue(self); }); - mlir_attribute_subclass(m, "DefaultContextAttr", rtgAttrIsADefaultContextAttr) + mlir_attribute_subclass(m, "ImmediateAttr", rtgAttrIsAImmediate) .def_classmethod( "get", - [](nb::object cls, MlirType type, MlirContext ctxt) { - return cls(rtgDefaultContextAttrGet(ctxt, type)); + [](nb::object cls, uint32_t width, uint64_t value, MlirContext ctx) { + return cls(rtgImmediateAttrGet(ctx, width, value)); }, - nb::arg("self"), nb::arg("type"), nb::arg("ctxt") = nullptr); + nb::arg("self"), nb::arg("width"), nb::arg("value"), + nb::arg("ctx") = nullptr) + .def_property_readonly( + "width", + [](MlirAttribute self) { return rtgImmediateAttrGetWidth(self); }) + .def_property_readonly("value", [](MlirAttribute self) { + return rtgImmediateAttrGetValue(self); + }); } diff --git a/lib/CAPI/Dialect/RTG.cpp b/lib/CAPI/Dialect/RTG.cpp index 625e4491f6fb..7ac8f1666fc6 100644 --- a/lib/CAPI/Dialect/RTG.cpp +++ b/lib/CAPI/Dialect/RTG.cpp @@ -115,10 +115,39 @@ MlirType rtgDictTypeGet(MlirContext ctxt, intptr_t numEntries, return wrap(DictType::get(unwrap(ctxt), entries)); } +// ImmediateType +//===----------------------------------------------------------------------===// + +bool rtgTypeIsAImmediate(MlirType type) { + return isa(unwrap(type)); +} + +MlirType rtgImmediateTypeGet(MlirContext ctx, uint32_t width) { + return wrap(ImmediateType::get(unwrap(ctx), width)); +} + +uint32_t rtgImmediateTypeGetWidth(MlirType type) { + return cast(unwrap(type)).getWidth(); +} + //===----------------------------------------------------------------------===// // Attribute API. //===----------------------------------------------------------------------===// +// DefaultContext +//===----------------------------------------------------------------------===// + +bool rtgAttrIsADefaultContextAttr(MlirAttribute attr) { + return isa(unwrap(attr)); +} + +MlirAttribute rtgDefaultContextAttrGet(MlirContext ctxt, MlirType type) { + return wrap(DefaultContextAttr::get(unwrap(ctxt), unwrap(type))); +} + +// Label Visibility +//===----------------------------------------------------------------------===// + bool rtgAttrIsALabelVisibilityAttr(MlirAttribute attr) { return isa(unwrap(attr)); } @@ -152,10 +181,22 @@ MlirAttribute rtgLabelVisibilityAttrGet(MlirContext ctxt, return wrap(LabelVisibilityAttr::get(unwrap(ctxt), convert(visibility))); } -bool rtgAttrIsADefaultContextAttr(MlirAttribute attr) { - return isa(unwrap(attr)); +// ImmediateAttr +//===----------------------------------------------------------------------===// + +bool rtgAttrIsAImmediate(MlirAttribute attr) { + return isa(unwrap(attr)); } -MlirAttribute rtgDefaultContextAttrGet(MlirContext ctxt, MlirType type) { - return wrap(DefaultContextAttr::get(unwrap(ctxt), unwrap(type))); +MlirAttribute rtgImmediateAttrGet(MlirContext ctx, uint32_t width, + uint64_t value) { + return wrap(rtg::ImmediateAttr::get(unwrap(ctx), APInt(width, value))); +} + +uint32_t rtgImmediateAttrGetWidth(MlirAttribute attr) { + return cast(unwrap(attr)).getValue().getBitWidth(); +} + +uint64_t rtgImmediateAttrGetValue(MlirAttribute attr) { + return cast(unwrap(attr)).getValue().getZExtValue(); } diff --git a/lib/Dialect/RTG/IR/RTGAttributes.cpp b/lib/Dialect/RTG/IR/RTGAttributes.cpp index 8d660ac078f2..d834cc218d9e 100644 --- a/lib/Dialect/RTG/IR/RTGAttributes.cpp +++ b/lib/Dialect/RTG/IR/RTGAttributes.cpp @@ -15,6 +15,60 @@ using namespace circt; using namespace rtg; +//===----------------------------------------------------------------------===// +// ImmediateAttr +//===----------------------------------------------------------------------===// + +Type ImmediateAttr::getType() const { + return ImmediateType::get(getContext(), getValue().getBitWidth()); +} + +Attribute ImmediateAttr::parse(AsmParser &odsParser, Type odsType) { + llvm::SMLoc loc = odsParser.getCurrentLocation(); + + APInt val; + uint32_t width; // NOTE: this integer type should match the 'width' parameter + // type in immediate type. + if (odsParser.parseLess() || odsParser.parseInteger(width) || + odsParser.parseComma() || odsParser.parseInteger(val) || + odsParser.parseGreater()) + return {}; + + // If the attribute type is explicitly given, check that the bit-widths match. + if (auto immTy = llvm::dyn_cast_or_null(odsType)) { + if (immTy.getWidth() != width) { + odsParser.emitError(loc) << "explicit immediate type bit-width does not " + "match attribute bit-width, " + << immTy.getWidth() << " vs " << width; + return {}; + } + } + + if (width > val.getBitWidth()) { + // sext is always safe here, even for unsigned values, because the + // parseOptionalInteger method will return something with a zero in the + // top bits if it is a positive number. + val = val.sext(width); + } else if (width < val.getBitWidth()) { + // The parser can return an unnecessarily wide result. + // This isn't a problem, but truncating off bits is bad. + unsigned neededBits = + val.isNegative() ? val.getSignificantBits() : val.getActiveBits(); + if (width < neededBits) { + odsParser.emitError(loc) + << "integer value out-of-range for bit-width " << width; + return {}; + } + val = val.trunc(width); + } + + return ImmediateAttr::get(odsParser.getContext(), val); +} + +void ImmediateAttr::print(AsmPrinter &odsPrinter) const { + odsPrinter << "<" << getValue().getBitWidth() << ", " << getValue() << ">"; +} + //===----------------------------------------------------------------------===// // TableGen generated logic. //===----------------------------------------------------------------------===// diff --git a/lib/Dialect/RTG/IR/RTGDialect.cpp b/lib/Dialect/RTG/IR/RTGDialect.cpp index 17aa7206d6b6..f98c0c6c6d55 100644 --- a/lib/Dialect/RTG/IR/RTGDialect.cpp +++ b/lib/Dialect/RTG/IR/RTGDialect.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "circt/Dialect/RTG/IR/RTGDialect.h" +#include "circt/Dialect/RTG/IR/RTGAttributes.h" #include "circt/Dialect/RTG/IR/RTGOps.h" #include "circt/Dialect/RTG/IR/RTGTypes.h" #include "mlir/IR/Builders.h" @@ -34,6 +35,22 @@ void RTGDialect::initialize() { >(); } +/// Registered hook to materialize a single constant operation from a given +/// attribute value with the desired resultant type. This method should use +/// the provided builder to create the operation without changing the +/// insertion position. The generated operation is expected to be constant +/// like, i.e. single result, zero operands, non side-effecting, etc. On +/// success, this hook should return the value generated to represent the +/// constant value. Otherwise, it should return null on failure. +Operation *RTGDialect::materializeConstant(OpBuilder &builder, Attribute value, + Type type, Location loc) { + if (auto attr = dyn_cast(value)) + if (type == attr.getType()) + return builder.create(loc, attr); + + return nullptr; +} + #include "circt/Dialect/RTG/IR/RTGEnums.cpp.inc" #include "circt/Dialect/RTG/IR/RTGDialect.cpp.inc" diff --git a/lib/Dialect/RTG/IR/RTGOps.cpp b/lib/Dialect/RTG/IR/RTGOps.cpp index 29f84c099bea..7c834478b673 100644 --- a/lib/Dialect/RTG/IR/RTGOps.cpp +++ b/lib/Dialect/RTG/IR/RTGOps.cpp @@ -20,6 +20,22 @@ using namespace mlir; using namespace circt; using namespace rtg; +//===----------------------------------------------------------------------===// +// ConstantOp +//===----------------------------------------------------------------------===// + +LogicalResult +ConstantOp::inferReturnTypes(MLIRContext *context, std::optional loc, + ValueRange operands, DictionaryAttr attributes, + OpaqueProperties properties, RegionRange regions, + SmallVectorImpl &inferredReturnTypes) { + inferredReturnTypes.push_back( + properties.as()->getValue().getType()); + return success(); +} + +OpFoldResult ConstantOp::fold(FoldAdaptor adaptor) { return getValueAttr(); } + //===----------------------------------------------------------------------===// // SequenceOp //===----------------------------------------------------------------------===// diff --git a/lib/Dialect/RTG/Transforms/ElaborationPass.cpp b/lib/Dialect/RTG/Transforms/ElaborationPass.cpp index d569eaa8e926..821837287c28 100644 --- a/lib/Dialect/RTG/Transforms/ElaborationPass.cpp +++ b/lib/Dialect/RTG/Transforms/ElaborationPass.cpp @@ -874,6 +874,10 @@ class Elaborator : public RTGOpVisitor> { return visitUnhandledOp(op); } + FailureOr visitOp(ConstantOp op) { + return visitConstantLike(op); + } + FailureOr visitOp(GetSequenceOp op) { SmallVector replacements; state[op.getResult()] = diff --git a/test/CAPI/rtg.c b/test/CAPI/rtg.c index 0e816bf6ea65..aa51afdcf2c2 100644 --- a/test/CAPI/rtg.c +++ b/test/CAPI/rtg.c @@ -52,7 +52,7 @@ static void testLabelType(MlirContext ctx) { // CHECK: is_label fprintf(stderr, rtgTypeIsALabel(labelTy) ? "is_label\n" : "isnot_label\n"); - // CHECK: !rtg.label + // CHECK: !rtg.isa.label mlirTypeDump(labelTy); } @@ -138,6 +138,29 @@ static void testDefaultContextAttr(MlirContext ctx) { mlirTypeDump(mlirAttributeGetType(defaultCtxtAttr)); } +static void testImmediate(MlirContext ctx) { + MlirType immediateTy = rtgImmediateTypeGet(ctx, 32); + // CHECK: is_immediate + fprintf(stderr, rtgTypeIsAImmediate(immediateTy) ? "is_immediate\n" + : "isnot_immediate\n"); + // CHECK: !rtg.isa.immediate<32> + mlirTypeDump(immediateTy); + // CHECK: width=32 + fprintf(stderr, "width=%u\n", rtgImmediateTypeGetWidth(immediateTy)); + + MlirAttribute immediateAttr = rtgImmediateAttrGet(ctx, 32, 42); + // CHECK: is_immediate_attr + fprintf(stderr, rtgAttrIsAImmediate(immediateAttr) + ? "is_immediate_attr\n" + : "isnot_immediate_attr\n"); + // CHECK: #rtg.isa.immediate<32, 42> + mlirAttributeDump(immediateAttr); + // CHECK: width=32 + fprintf(stderr, "width=%u\n", rtgImmediateAttrGetWidth(immediateAttr)); + // CHECK: value=42 + fprintf(stderr, "value=%llu\n", rtgImmediateAttrGetValue(immediateAttr)); +} + int main(int argc, char **argv) { MlirContext ctx = mlirContextCreate(); mlirDialectHandleLoadDialect(mlirGetDialectHandle__rtg__(), ctx); @@ -152,6 +175,7 @@ int main(int argc, char **argv) { testLabelVisibilityAttr(ctx); testDefaultContextAttr(ctx); + testImmediate(ctx); mlirContextDestroy(ctx); diff --git a/test/Dialect/RTG/IR/basic.mlir b/test/Dialect/RTG/IR/basic.mlir index 2ef9f68837da..a22a67e37e85 100644 --- a/test/Dialect/RTG/IR/basic.mlir +++ b/test/Dialect/RTG/IR/basic.mlir @@ -1,5 +1,11 @@ // RUN: circt-opt %s --verify-roundtrip | FileCheck %s +// CHECK-LABEL: @constants +rtg.test @constants() { + // CHECK-NEXT: rtg.constant #rtg.isa.immediate<2, -1> : !rtg.isa.immediate<2> + %0 = rtg.constant #rtg.isa.immediate<2, -1> +} + // CHECK-LABEL: rtg.sequence @ranomizedSequenceType // CHECK-SAME: (%{{.*}}: !rtg.randomized_sequence) rtg.sequence @ranomizedSequenceType(%seq: !rtg.randomized_sequence) {} @@ -20,8 +26,8 @@ rtg.sequence @seq0() { } // CHECK-LABEL: rtg.sequence @seqAttrsAndTypeElements -// CHECK-SAME: (%arg0: !rtg.sequence>>) attributes {rtg.some_attr} { -rtg.sequence @seqAttrsAndTypeElements(%arg0: !rtg.sequence>>) attributes {rtg.some_attr} {} +// CHECK-SAME: (%arg0: !rtg.sequence>>) attributes {rtg.some_attr} { +rtg.sequence @seqAttrsAndTypeElements(%arg0: !rtg.sequence>>) attributes {rtg.some_attr} {} // CHECK-LABEL: rtg.sequence @seq1 // CHECK-SAME: (%arg0: i32, %arg1: !rtg.sequence) diff --git a/test/Dialect/RTG/IR/errors.mlir b/test/Dialect/RTG/IR/errors.mlir index ac53e2d1361d..09dbdc7312d0 100644 --- a/test/Dialect/RTG/IR/errors.mlir +++ b/test/Dialect/RTG/IR/errors.mlir @@ -1,5 +1,18 @@ // RUN: circt-opt %s --split-input-file --verify-diagnostics +rtg.test @constantTooBig() { + // expected-error @below {{integer value out-of-range for bit-width 2}} + rtg.constant #rtg.isa.immediate<2, 4> +} + +// ----- + +rtg.test @immediateWidthMismatch() { + // expected-error @below {{explicit immediate type bit-width does not match attribute bit-width, 1 vs 2}} + rtg.constant #rtg.isa.immediate<2, 1> : !rtg.isa.immediate<1> +} + +// ----- func.func @seq0() { return diff --git a/test/Dialect/RTG/Transform/elaboration.mlir b/test/Dialect/RTG/Transform/elaboration.mlir index e17ba07588a3..2afe3c3dced6 100644 --- a/test/Dialect/RTG/Transform/elaboration.mlir +++ b/test/Dialect/RTG/Transform/elaboration.mlir @@ -5,6 +5,15 @@ func.func @dummy2(%arg0: index) -> () {return} func.func @dummy3(%arg0: !rtg.sequence) -> () {return} func.func @dummy4(%arg0: index, %arg1: index, %arg2: !rtg.bag, %arg3: !rtg.bag) -> () {return} func.func @dummy5(%arg0: i1) -> () {return} +func.func @dummy6(%arg0: !rtg.isa.immediate<2>) -> () {return} + +// CHECK-LABEL: @constantImmediate +rtg.test @constantImmediate() { + // CHECK-NEXT: [[V0:%.+]] = rtg.constant #rtg.isa.immediate<2, -1> + // CHECK-NEXT: func.call @dummy6([[V0]]) : (!rtg.isa.immediate<2>) -> () + %0 = rtg.constant #rtg.isa.immediate<2, -1> + func.call @dummy6(%0) : (!rtg.isa.immediate<2>) -> () +} // Test the set operations and passing a sequence to another one via argument // CHECK-LABEL: rtg.test @setOperations @@ -574,17 +583,17 @@ rtg.test @contextSwitchNotAvailable(cpu = %cpu: !rtgtest.cpu) { // ----- rtg.test @emptySetSelect() { - %0 = rtg.set_create : !rtg.label + %0 = rtg.set_create : !rtg.isa.label // expected-error @below {{cannot select from an empty set}} - %1 = rtg.set_select_random %0 : !rtg.set + %1 = rtg.set_select_random %0 : !rtg.set rtg.label local %1 } // ----- rtg.test @emptyBagSelect() { - %0 = rtg.bag_create : !rtg.label + %0 = rtg.bag_create : !rtg.isa.label // expected-error @below {{cannot select from an empty bag}} - %1 = rtg.bag_select_random %0 : !rtg.bag + %1 = rtg.bag_select_random %0 : !rtg.bag rtg.label local %1 } diff --git a/test/Dialect/RTG/Transform/emit-rtg-isa-assembly-errors.mlir b/test/Dialect/RTG/Transform/emit-rtg-isa-assembly-errors.mlir index 959e437fbd9b..c9966cf940f4 100644 --- a/test/Dialect/RTG/Transform/emit-rtg-isa-assembly-errors.mlir +++ b/test/Dialect/RTG/Transform/emit-rtg-isa-assembly-errors.mlir @@ -6,7 +6,7 @@ rtg.test @test0() { %label = rtg.label_decl "label_name" // expected-error @below {{labels cannot be emitted as binary}} - rtgtest.rv32i.beq %rd, %rs, %label : !rtg.label + rtgtest.rv32i.beq %rd, %rs, %label : !rtg.isa.label } // ----- diff --git a/test/Dialect/RTG/Transform/emit-rtg-isa-assembly-labels.mlir b/test/Dialect/RTG/Transform/emit-rtg-isa-assembly-labels.mlir index c3f8165119ac..2e72c3177e00 100644 --- a/test/Dialect/RTG/Transform/emit-rtg-isa-assembly-labels.mlir +++ b/test/Dialect/RTG/Transform/emit-rtg-isa-assembly-labels.mlir @@ -9,7 +9,7 @@ rtg.test @test0() { %label = rtg.label_decl "label_name" // CHECK-NEXT: beq ra, s0, label_name - rtgtest.rv32i.beq %rd, %rs, %label : !rtg.label + rtgtest.rv32i.beq %rd, %rs, %label : !rtg.isa.label // CHECK-NEXT:label_name: rtg.label local %label // CHECK-NEXT:.extern label_name @@ -18,21 +18,21 @@ rtg.test @test0() { // CHECK-NEXT:label_name: rtg.label global %label // CHECK-NEXT: bne ra, s0, label_name - rtgtest.rv32i.bne %rd, %rs, %label : !rtg.label + rtgtest.rv32i.bne %rd, %rs, %label : !rtg.isa.label // CHECK-NEXT: blt ra, s0, label_name - rtgtest.rv32i.blt %rd, %rs, %label : !rtg.label + rtgtest.rv32i.blt %rd, %rs, %label : !rtg.isa.label // CHECK-NEXT: bge ra, s0, label_name - rtgtest.rv32i.bge %rd, %rs, %label : !rtg.label + rtgtest.rv32i.bge %rd, %rs, %label : !rtg.isa.label // CHECK-NEXT: bltu ra, s0, label_name - rtgtest.rv32i.bltu %rd, %rs, %label : !rtg.label + rtgtest.rv32i.bltu %rd, %rs, %label : !rtg.isa.label // CHECK-NEXT: bgeu ra, s0, label_name - rtgtest.rv32i.bgeu %rd, %rs, %label : !rtg.label + rtgtest.rv32i.bgeu %rd, %rs, %label : !rtg.isa.label // CHECK-NEXT: lui ra, label_name - rtgtest.rv32i.lui %rd, %label : !rtg.label + rtgtest.rv32i.lui %rd, %label : !rtg.isa.label // CHECK-NEXT: auipc ra, label_name - rtgtest.rv32i.auipc %rd, %label : !rtg.label + rtgtest.rv32i.auipc %rd, %label : !rtg.isa.label // CHECK-NEXT: jal ra, label_name - rtgtest.rv32i.jal %rd, %label : !rtg.label + rtgtest.rv32i.jal %rd, %label : !rtg.isa.label } // CHECK-EMPTY: diff --git a/test/Dialect/RTGTest/IR/basic.mlir b/test/Dialect/RTGTest/IR/basic.mlir index 678bc17587c2..a5b94c24650c 100644 --- a/test/Dialect/RTGTest/IR/basic.mlir +++ b/test/Dialect/RTGTest/IR/basic.mlir @@ -100,8 +100,8 @@ rtg.test @immediates() { } // CHECK-LABEL: @instructions -// CHECK-SAME: (imm = [[IMM:%.+]]: !rtgtest.imm12, imm13 = [[IMM13:%.+]]: !rtgtest.imm13, imm21 = [[IMM21:%.+]]: !rtgtest.imm21, imm32 = [[IMM32:%.+]]: !rtgtest.imm32, imm5 = [[IMM5:%.+]]: !rtgtest.imm5, label = [[LABEL:%.+]]: !rtg.label, rd = [[RD:%.+]]: !rtgtest.ireg, rs = [[RS:%.+]]: !rtgtest.ireg) -rtg.test @instructions(imm = %imm: !rtgtest.imm12, imm13 = %imm13: !rtgtest.imm13, imm21 = %imm21: !rtgtest.imm21, imm32 = %imm32: !rtgtest.imm32, imm5 = %imm5: !rtgtest.imm5, label = %label: !rtg.label, rd = %rd: !rtgtest.ireg, rs = %rs: !rtgtest.ireg) { +// CHECK-SAME: (imm = [[IMM:%.+]]: !rtgtest.imm12, imm13 = [[IMM13:%.+]]: !rtgtest.imm13, imm21 = [[IMM21:%.+]]: !rtgtest.imm21, imm32 = [[IMM32:%.+]]: !rtgtest.imm32, imm5 = [[IMM5:%.+]]: !rtgtest.imm5, label = [[LABEL:%.+]]: !rtg.isa.label, rd = [[RD:%.+]]: !rtgtest.ireg, rs = [[RS:%.+]]: !rtgtest.ireg) +rtg.test @instructions(imm = %imm: !rtgtest.imm12, imm13 = %imm13: !rtgtest.imm13, imm21 = %imm21: !rtgtest.imm21, imm32 = %imm32: !rtgtest.imm32, imm5 = %imm5: !rtgtest.imm5, label = %label: !rtg.isa.label, rd = %rd: !rtgtest.ireg, rs = %rs: !rtgtest.ireg) { // CHECK: rtgtest.rv32i.jalr [[RD]], [[RS]], [[IMM]] rtgtest.rv32i.jalr %rd, %rs, %imm // CHECK: rtgtest.rv32i.lb [[RD]], [[RS]], [[IMM]] @@ -130,18 +130,18 @@ rtg.test @instructions(imm = %imm: !rtgtest.imm12, imm13 = %imm13: !rtgtest.imm1 rtgtest.rv32i.bltu %rd, %rs, %imm13 : !rtgtest.imm13 // CHECK: rtgtest.rv32i.bgeu [[RD]], [[RS]], [[IMM13]] : !rtgtest.imm13 rtgtest.rv32i.bgeu %rd, %rs, %imm13 : !rtgtest.imm13 - // CHECK: rtgtest.rv32i.beq [[RD]], [[RS]], [[LABEL]] : !rtg.label - rtgtest.rv32i.beq %rd, %rs, %label : !rtg.label - // CHECK: rtgtest.rv32i.bne [[RD]], [[RS]], [[LABEL]] : !rtg.label - rtgtest.rv32i.bne %rd, %rs, %label : !rtg.label - // CHECK: rtgtest.rv32i.blt [[RD]], [[RS]], [[LABEL]] : !rtg.label - rtgtest.rv32i.blt %rd, %rs, %label : !rtg.label - // CHECK: rtgtest.rv32i.bge [[RD]], [[RS]], [[LABEL]] : !rtg.label - rtgtest.rv32i.bge %rd, %rs, %label : !rtg.label - // CHECK: rtgtest.rv32i.bltu [[RD]], [[RS]], [[LABEL]] : !rtg.label - rtgtest.rv32i.bltu %rd, %rs, %label : !rtg.label - // CHECK: rtgtest.rv32i.bgeu [[RD]], [[RS]], [[LABEL]] : !rtg.label - rtgtest.rv32i.bgeu %rd, %rs, %label : !rtg.label + // CHECK: rtgtest.rv32i.beq [[RD]], [[RS]], [[LABEL]] : !rtg.isa.label + rtgtest.rv32i.beq %rd, %rs, %label : !rtg.isa.label + // CHECK: rtgtest.rv32i.bne [[RD]], [[RS]], [[LABEL]] : !rtg.isa.label + rtgtest.rv32i.bne %rd, %rs, %label : !rtg.isa.label + // CHECK: rtgtest.rv32i.blt [[RD]], [[RS]], [[LABEL]] : !rtg.isa.label + rtgtest.rv32i.blt %rd, %rs, %label : !rtg.isa.label + // CHECK: rtgtest.rv32i.bge [[RD]], [[RS]], [[LABEL]] : !rtg.isa.label + rtgtest.rv32i.bge %rd, %rs, %label : !rtg.isa.label + // CHECK: rtgtest.rv32i.bltu [[RD]], [[RS]], [[LABEL]] : !rtg.isa.label + rtgtest.rv32i.bltu %rd, %rs, %label : !rtg.isa.label + // CHECK: rtgtest.rv32i.bgeu [[RD]], [[RS]], [[LABEL]] : !rtg.isa.label + rtgtest.rv32i.bgeu %rd, %rs, %label : !rtg.isa.label // CHECK: rtgtest.rv32i.add [[RD]], [[RS]], [[RS]] {rtg.some_attr} rtgtest.rv32i.add %rd, %rs, %rs {rtg.some_attr} @@ -178,12 +178,12 @@ rtg.test @instructions(imm = %imm: !rtgtest.imm12, imm13 = %imm13: !rtgtest.imm1 // CHECK: rtgtest.rv32i.jal [[RD]], [[IMM21]] : !rtgtest.imm21 {rtg.some_attr} rtgtest.rv32i.jal %rd, %imm21 : !rtgtest.imm21 {rtg.some_attr} - // CHECK: rtgtest.rv32i.lui [[RD]], [[LABEL]] : !rtg.label {rtg.some_attr} - rtgtest.rv32i.lui %rd, %label : !rtg.label {rtg.some_attr} - // CHECK: rtgtest.rv32i.auipc [[RD]], [[LABEL]] : !rtg.label {rtg.some_attr} - rtgtest.rv32i.auipc %rd, %label : !rtg.label {rtg.some_attr} - // CHECK: rtgtest.rv32i.jal [[RD]], [[LABEL]] : !rtg.label {rtg.some_attr} - rtgtest.rv32i.jal %rd, %label : !rtg.label {rtg.some_attr} + // CHECK: rtgtest.rv32i.lui [[RD]], [[LABEL]] : !rtg.isa.label {rtg.some_attr} + rtgtest.rv32i.lui %rd, %label : !rtg.isa.label {rtg.some_attr} + // CHECK: rtgtest.rv32i.auipc [[RD]], [[LABEL]] : !rtg.isa.label {rtg.some_attr} + rtgtest.rv32i.auipc %rd, %label : !rtg.isa.label {rtg.some_attr} + // CHECK: rtgtest.rv32i.jal [[RD]], [[LABEL]] : !rtg.isa.label {rtg.some_attr} + rtgtest.rv32i.jal %rd, %label : !rtg.isa.label {rtg.some_attr} // CHECK: rtgtest.rv32i.addi [[RD]], [[RS]], [[IMM]] {rtg.some_attr} rtgtest.rv32i.addi %rd, %rs, %imm {rtg.some_attr} diff --git a/unittests/Dialect/CMakeLists.txt b/unittests/Dialect/CMakeLists.txt index 932d4bf03010..cfc2573a09a6 100644 --- a/unittests/Dialect/CMakeLists.txt +++ b/unittests/Dialect/CMakeLists.txt @@ -3,5 +3,6 @@ add_subdirectory(FIRRTL) add_subdirectory(ESI) add_subdirectory(HW) add_subdirectory(OM) +add_subdirectory(RTG) add_subdirectory(RTGTest) add_subdirectory(SMT) diff --git a/unittests/Dialect/RTG/CMakeLists.txt b/unittests/Dialect/RTG/CMakeLists.txt new file mode 100644 index 000000000000..36686e5c427a --- /dev/null +++ b/unittests/Dialect/RTG/CMakeLists.txt @@ -0,0 +1,9 @@ +add_circt_unittest(CIRCTRTGTests + MaterializerTest.cpp +) + +target_link_libraries(CIRCTRTGTests + PRIVATE + CIRCTRTGDialect + MLIRIR +) diff --git a/unittests/Dialect/RTG/MaterializerTest.cpp b/unittests/Dialect/RTG/MaterializerTest.cpp new file mode 100644 index 000000000000..b134576bc8e4 --- /dev/null +++ b/unittests/Dialect/RTG/MaterializerTest.cpp @@ -0,0 +1,39 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "circt/Dialect/RTG/IR/RTGAttributes.h" +#include "circt/Dialect/RTG/IR/RTGDialect.h" +#include "circt/Dialect/RTG/IR/RTGOps.h" +#include "mlir/IR/Builders.h" +#include "mlir/IR/BuiltinOps.h" +#include "gtest/gtest.h" + +using namespace mlir; +using namespace circt; +using namespace rtg; + +namespace { + +TEST(MaterializerTest, ImmediateAttr) { + MLIRContext context; + context.loadDialect(); + Location loc(UnknownLoc::get(&context)); + auto moduleOp = ModuleOp::create(loc); + OpBuilder builder = OpBuilder::atBlockBegin(moduleOp.getBody()); + + auto attr = ImmediateAttr::get(&context, APInt(12, 0)); + auto *op0 = context.getLoadedDialect()->materializeConstant( + builder, attr, attr.getType(), loc); + auto *op1 = context.getLoadedDialect()->materializeConstant( + builder, attr, ImmediateType::get(&context, 2), loc); + + ASSERT_TRUE(op0 && isa(op0)); + ASSERT_EQ(op1, nullptr); +} + +} // namespace