From 7c32ed42e21b7295f512b7a4db0824d496e66873 Mon Sep 17 00:00:00 2001 From: Fabian Schuiki Date: Fri, 9 Aug 2024 14:23:44 -0700 Subject: [PATCH] [Moore] Add constant materialization, fold constant conversions (#7478) Implement the `materializeConstant` function for the Moore dialect and mark the `ConstantOp` as a `ConstantLike` operation. This now allows us to write constant folders for various operations. As a first example, add a constant folder for `ConversionOp` that directly applies domain conversions (e.g., `i42` to `l42` or vice versa) to constants. --- include/circt/Dialect/Moore/MooreDialect.td | 1 + include/circt/Dialect/Moore/MooreOps.td | 2 +- lib/Dialect/Moore/MooreDialect.cpp | 9 ++++++ lib/Dialect/Moore/MooreOps.cpp | 17 +++++++++++ test/Conversion/MooreToCore/basic.mlir | 5 ++-- test/Dialect/Moore/canonicalizers.mlir | 33 +++++++++++++++++---- 6 files changed, 57 insertions(+), 10 deletions(-) diff --git a/include/circt/Dialect/Moore/MooreDialect.td b/include/circt/Dialect/Moore/MooreDialect.td index 97c0fd0ac055..590e59da6068 100644 --- a/include/circt/Dialect/Moore/MooreDialect.td +++ b/include/circt/Dialect/Moore/MooreDialect.td @@ -38,6 +38,7 @@ def MooreDialect : Dialect { }]; let useDefaultAttributePrinterParser = 1; let useDefaultTypePrinterParser = 0; + let hasConstantMaterializer = 1; let dependentDialects = ["hw::HWDialect"]; } diff --git a/include/circt/Dialect/Moore/MooreOps.td b/include/circt/Dialect/Moore/MooreOps.td index 14751b58794b..b9f77bc0d1c2 100644 --- a/include/circt/Dialect/Moore/MooreOps.td +++ b/include/circt/Dialect/Moore/MooreOps.td @@ -417,7 +417,7 @@ def EventOp : MooreOp<"wait_event", [ // Expressions //===----------------------------------------------------------------------===// -def ConstantOp : MooreOp<"constant", [Pure]> { +def ConstantOp : MooreOp<"constant", [Pure, ConstantLike]> { let summary = "A constant integer value"; let arguments = (ins FVIntegerAttr:$value); let results = (outs IntType:$result); diff --git a/lib/Dialect/Moore/MooreDialect.cpp b/lib/Dialect/Moore/MooreDialect.cpp index a9cc2a9c8b4b..64341d36e39a 100644 --- a/lib/Dialect/Moore/MooreDialect.cpp +++ b/lib/Dialect/Moore/MooreDialect.cpp @@ -32,4 +32,13 @@ void MooreDialect::initialize() { >(); } +Operation *MooreDialect::materializeConstant(OpBuilder &builder, + Attribute value, Type type, + Location loc) { + if (auto intType = dyn_cast(type)) + if (auto intValue = dyn_cast(value)) + return builder.create(loc, intType, intValue); + return nullptr; +} + #include "circt/Dialect/Moore/MooreDialect.cpp.inc" diff --git a/lib/Dialect/Moore/MooreOps.cpp b/lib/Dialect/Moore/MooreOps.cpp index 20553e17d720..2572a804a61d 100644 --- a/lib/Dialect/Moore/MooreOps.cpp +++ b/lib/Dialect/Moore/MooreOps.cpp @@ -998,6 +998,23 @@ OpFoldResult ConversionOp::fold(FoldAdaptor adaptor) { // Fold away no-op casts. if (getInput().getType() == getResult().getType()) return getInput(); + + // Convert domains of constant integer inputs. + auto intInput = dyn_cast_or_null(adaptor.getInput()); + auto fromIntType = dyn_cast(getInput().getType()); + auto toIntType = dyn_cast(getResult().getType()); + if (intInput && fromIntType && toIntType && + fromIntType.getWidth() == toIntType.getWidth()) { + // If we are going *to* a four-valued type, simply pass through the + // constant. + if (toIntType.getDomain() == Domain::FourValued) + return intInput; + + // Otherwise map all unknown bits to zero (the default in SystemVerilog) and + // return a new constant. + return FVIntegerAttr::get(getContext(), intInput.getValue().toAPInt(false)); + } + return {}; } diff --git a/test/Conversion/MooreToCore/basic.mlir b/test/Conversion/MooreToCore/basic.mlir index 64c105f1d231..4ec8c84f9515 100644 --- a/test/Conversion/MooreToCore/basic.mlir +++ b/test/Conversion/MooreToCore/basic.mlir @@ -296,10 +296,9 @@ moore.module @Variable() { %b2 = moore.variable %0 : // CHECK: %true = hw.constant true - %1 = moore.constant 1 : i1 - %2 = moore.conversion %1 : !moore.i1 -> !moore.l1 + %1 = moore.constant 1 : l1 // CHECK: llhd.sig "l" %true : i1 - %l = moore.variable %2 : + %l = moore.variable %1 : // CHECK: [[TMP2:%.+]] = hw.constant 10 : i32 %3 = moore.constant 10 : i32 diff --git a/test/Dialect/Moore/canonicalizers.mlir b/test/Dialect/Moore/canonicalizers.mlir index 0104799c0946..7128f0039b72 100644 --- a/test/Dialect/Moore/canonicalizers.mlir +++ b/test/Dialect/Moore/canonicalizers.mlir @@ -142,6 +142,9 @@ func.func private @useRef(%arg0: !moore.ref) // CHECK-LABEL: moore.module @DropRedundantVars moore.module @DropRedundantVars(in %a : !moore.i42, out b : !moore.i42, out c : !moore.i42) { + // CHECK: [[C9001:%.+]] = moore.constant 9001 : i42 + %c9001_i42 = moore.constant 9001 : i42 + // Remove variables that shadow an input port of the same name. // CHECK-NOT: moore.assigned_variable // CHECK: dbg.variable "a", %a @@ -164,13 +167,11 @@ moore.module @DropRedundantVars(in %a : !moore.i42, out b : !moore.i42, out c : // Remove variables that shadow an output port of the same name. Variables // that shadow an output port of a different name should remain. - // CHECK: [[TMP:%.+]] = moore.constant 9001 : i42 // CHECK-NOT: %b = moore.assigned_variable - // CHECK: %w = moore.assigned_variable [[TMP]] - // CHECK: moore.output [[TMP]], %w - %3 = moore.constant 9001 : i42 - %b = moore.assigned_variable %3 : i42 - %w = moore.assigned_variable %3 : i42 + // CHECK: %w = moore.assigned_variable [[C9001]] + // CHECK: moore.output [[C9001]], %w + %b = moore.assigned_variable %c9001_i42 : i42 + %w = moore.assigned_variable %c9001_i42 : i42 moore.output %b, %w : !moore.i42, !moore.i42 } @@ -229,3 +230,23 @@ func.func @StructInjectFold3(%arg0: !moore.struct<{a: i32, b: i32}>) -> (!moore. %3 = moore.struct_inject %2, "a", %1 : struct<{a: i32, b: i32}>, i32 return %3 : !moore.struct<{a: i32, b: i32}> } + +// CHECK-LABEL: func.func @ConvertConstantTwoToFourValued +func.func @ConvertConstantTwoToFourValued() -> (!moore.l42) { + // CHECK: [[TMP:%.+]] = moore.constant 9001 : l42 + // CHECK-NOT: moore.conversion + // CHECK: return [[TMP]] : + %0 = moore.constant 9001 : i42 + %1 = moore.conversion %0 : !moore.i42 -> !moore.l42 + return %1 : !moore.l42 +} + +// CHECK-LABEL: func.func @ConvertConstantFourToTwoValued +func.func @ConvertConstantFourToTwoValued() -> (!moore.i42) { + // CHECK: [[TMP:%.+]] = moore.constant 8 : i42 + // CHECK-NOT: moore.conversion + // CHECK: return [[TMP]] : + %0 = moore.constant b1XZ0 : l42 + %1 = moore.conversion %0 : !moore.l42 -> !moore.i42 + return %1 : !moore.i42 +}