From ac7c99be71dbfd10dd577b82773bd796f66a8e56 Mon Sep 17 00:00:00 2001 From: Jiahan Xie Date: Mon, 4 Nov 2024 14:42:58 -0500 Subject: [PATCH 1/3] calyx constant op value only specified via attributes (experimental) --- include/circt/Dialect/Calyx/CalyxPrimitives.td | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/include/circt/Dialect/Calyx/CalyxPrimitives.td b/include/circt/Dialect/Calyx/CalyxPrimitives.td index 1a9012b5796d..c0edfcfe5875 100644 --- a/include/circt/Dialect/Calyx/CalyxPrimitives.td +++ b/include/circt/Dialect/Calyx/CalyxPrimitives.td @@ -22,27 +22,26 @@ class CalyxPrimitive traits = []> : def ConstantOp: CalyxPrimitive<"constant", [ConstantLike, FirstAttrDerivedResultType, - DeclareOpInterfaceMethods, - AllTypesMatch<["value", "out"]> + DeclareOpInterfaceMethods ]> { - let summary = "integer or floating point constant"; + let summary = "constant capable of representing an integer or floating point value"; let description = [{ - The `constant` operation produces an SSA value equal to some integer or - floating-point constant specified by an attribute. + The `constant` operation is a wrapper around bit vectors with fixed-size number of bits. + Specific value and intended type should be specified via attribute only. Example: ``` // Integer constant - %1 = calyx.constant 42 : i32 + %1 = calyx.constant {value = 42 : i32} : i32 // Floating point constant - %1 = calyx.constant 42.00+e00 : f32 + %1 = calyx.constant {value = 4.2 : f32} : i32 ``` }]; let arguments = (ins TypedAttrInterface:$value); - let results = (outs SignlessIntegerOrFloatLike:$out); + let results = (outs AnySignlessInteger:$out); let builders = [ /// Build a ConstantOp from a prebuilt attribute. @@ -50,7 +49,7 @@ def ConstantOp: CalyxPrimitive<"constant", ]; let hasFolder = 1; - let assemblyFormat = "attr-dict $value"; + let assemblyFormat = "attr-dict $value type($out)"; let hasVerifier = 1; } From b58ad6944dcdb2560a9e5c5e99fa3d27257a3c10 Mon Sep 17 00:00:00 2001 From: Jiahan Xie Date: Mon, 4 Nov 2024 18:11:00 -0500 Subject: [PATCH 2/3] some changes --- include/circt/Dialect/Calyx/CalyxPrimitives.td | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/include/circt/Dialect/Calyx/CalyxPrimitives.td b/include/circt/Dialect/Calyx/CalyxPrimitives.td index c0edfcfe5875..27fed643f221 100644 --- a/include/circt/Dialect/Calyx/CalyxPrimitives.td +++ b/include/circt/Dialect/Calyx/CalyxPrimitives.td @@ -21,8 +21,7 @@ class CalyxPrimitive traits = []> : } def ConstantOp: CalyxPrimitive<"constant", - [ConstantLike, FirstAttrDerivedResultType, - DeclareOpInterfaceMethods + [ConstantLike, DeclareOpInterfaceMethods ]> { let summary = "constant capable of representing an integer or floating point value"; let description = [{ @@ -33,23 +32,22 @@ def ConstantOp: CalyxPrimitive<"constant", ``` // Integer constant - %1 = calyx.constant {value = 42 : i32} : i32 + %1 = calyx.constant : i32 // Floating point constant - %1 = calyx.constant {value = 4.2 : f32} : i32 + %1 = calyx.constant : i32 ``` }]; - let arguments = (ins TypedAttrInterface:$value); + let arguments = (ins SymbolNameAttr:$sym_name, TypedAttrInterface:$value); let results = (outs AnySignlessInteger:$out); let builders = [ - /// Build a ConstantOp from a prebuilt attribute. OpBuilder <(ins "StringRef":$sym_name, "TypedAttr":$attr)>, ]; let hasFolder = 1; - let assemblyFormat = "attr-dict $value type($out)"; + let assemblyFormat = "$sym_name ` ` `<` $value `>` attr-dict `:` qualified(type($out))"; let hasVerifier = 1; } From 14c7086393f07597f92b3d6ab90aa61fd881ddf1 Mon Sep 17 00:00:00 2001 From: Jiahan Xie Date: Tue, 5 Nov 2024 18:46:55 -0500 Subject: [PATCH 3/3] Change calyx constant op so that the actual value is wrapped in the attribute, while the type is always unsigned integer. Make the corresponding change for addf operator so that they also take integer inputs and produce integer results; make the corresponding change for function argument passing to convert floating point args to integer. Finally make the corresponding change for the test code. --- include/circt/Dialect/Calyx/CalyxHelpers.h | 4 --- .../circt/Dialect/Calyx/CalyxPrimitives.td | 12 ++++---- lib/Conversion/SCFToCalyx/SCFToCalyx.cpp | 13 +++++--- lib/Dialect/Calyx/CalyxOps.cpp | 15 ++++++---- lib/Dialect/Calyx/Transforms/CalyxHelpers.cpp | 8 ----- .../Calyx/Transforms/CalyxLoweringUtils.cpp | 4 ++- .../Conversion/SCFToCalyx/convert_simple.mlir | 10 +++---- test/Dialect/Calyx/emit.mlir | 30 +++++++++---------- 8 files changed, 47 insertions(+), 49 deletions(-) diff --git a/include/circt/Dialect/Calyx/CalyxHelpers.h b/include/circt/Dialect/Calyx/CalyxHelpers.h index f6b48fb85398..0e4661853968 100644 --- a/include/circt/Dialect/Calyx/CalyxHelpers.h +++ b/include/circt/Dialect/Calyx/CalyxHelpers.h @@ -30,10 +30,6 @@ calyx::RegisterOp createRegister(Location loc, OpBuilder &builder, ComponentOp component, size_t width, Twine prefix); -calyx::RegisterOp createRegister(Location loc, OpBuilder &builder, - ComponentOp component, Type type, - Twine prefix); - /// A helper function to create constants in the HW dialect. hw::ConstantOp createConstant(Location loc, OpBuilder &builder, ComponentOp component, size_t width, diff --git a/include/circt/Dialect/Calyx/CalyxPrimitives.td b/include/circt/Dialect/Calyx/CalyxPrimitives.td index 27fed643f221..59c2c0c9560c 100644 --- a/include/circt/Dialect/Calyx/CalyxPrimitives.td +++ b/include/circt/Dialect/Calyx/CalyxPrimitives.td @@ -32,10 +32,10 @@ def ConstantOp: CalyxPrimitive<"constant", ``` // Integer constant - %1 = calyx.constant : i32 + %1 = calyx.constant <42 : i32> : i32 // Floating point constant - %1 = calyx.constant : i32 + %1 = calyx.constant <4.2 : f32> : i32 ``` }]; let arguments = (ins SymbolNameAttr:$sym_name, TypedAttrInterface:$value); @@ -43,7 +43,7 @@ def ConstantOp: CalyxPrimitive<"constant", let results = (outs AnySignlessInteger:$out); let builders = [ - OpBuilder <(ins "StringRef":$sym_name, "TypedAttr":$attr)>, + OpBuilder <(ins "StringRef":$sym_name, "Attribute":$attr, "Type":$type)>, ]; let hasFolder = 1; @@ -337,7 +337,7 @@ class ArithBinaryFloatingPointLibraryOp : ArithBinaryLibraryOp< def AddFNOp : ArithBinaryFloatingPointLibraryOp<"addFN"> { let results = (outs I1:$clk, I1:$reset, I1:$go, I1:$control, I1:$subOp, - AnyFloat:$left, AnyFloat:$right, AnySignlessInteger:$roundingMode, AnyFloat:$out, + AnySignlessInteger:$left, AnySignlessInteger:$right, AnySignlessInteger:$roundingMode, AnySignlessInteger:$out, AnySignlessInteger:$exceptionalFlags, I1:$done); let extraClassDefinition = [{ @@ -349,11 +349,11 @@ def AddFNOp : ArithBinaryFloatingPointLibraryOp<"addFN"> { SmallVector $cppClass::portDirections() { return {Input, Input, Input, Input, Input, Input, Input, Input, Output, Output, Output}; - } + } void $cppClass::getAsmResultNames(OpAsmSetValueNameFn setNameFn) { getCellAsmResultNames(setNameFn, *this, this->portNames()); - } + } bool $cppClass::isCombinational() { return false; } diff --git a/lib/Conversion/SCFToCalyx/SCFToCalyx.cpp b/lib/Conversion/SCFToCalyx/SCFToCalyx.cpp index 6a351d6f97b6..530b4e5f921a 100644 --- a/lib/Conversion/SCFToCalyx/SCFToCalyx.cpp +++ b/lib/Conversion/SCFToCalyx/SCFToCalyx.cpp @@ -414,7 +414,7 @@ class BuildOpGroups : public calyx::FuncOpPartialLoweringPattern { // Pass the result from the Operation to the Calyx primitive. op.getResult().replaceAllUsesWith(out); auto reg = createRegister( - op.getLoc(), rewriter, getComponent(), width, + op.getLoc(), rewriter, getComponent(), width.getIntOrFloatBitWidth(), getState().getUniqueName(opName)); // Operation pipelines are not combinational, so a GroupOp is required. auto group = createGroupForOp(rewriter, op); @@ -687,9 +687,10 @@ LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter, LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter, AddFOp addf) const { Location loc = addf.getLoc(); - Type width = addf.getResult().getType(); IntegerType one = rewriter.getI1Type(), three = rewriter.getIntegerType(3), - five = rewriter.getIntegerType(5); + five = rewriter.getIntegerType(5), + width = rewriter.getIntegerType( + addf.getType().getIntOrFloatBitWidth()); auto addFN = getState() .getNewLibraryOpInstance( @@ -935,8 +936,11 @@ LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter, getComponent().getBodyBlock()->begin()); } else { std::string name = getState().getUniqueName("cst"); + auto floatAttr = cast(constOp.getValueAttr()); + auto intType = + rewriter.getIntegerType(floatAttr.getType().getIntOrFloatBitWidth()); auto calyxConstOp = rewriter.create( - constOp.getLoc(), name, constOp.getValueAttr()); + constOp.getLoc(), name, floatAttr, intType); calyxConstOp->moveAfter(getComponent().getBodyBlock(), getComponent().getBodyBlock()->begin()); rewriter.replaceAllUsesWith(constOp, calyxConstOp.getOut()); @@ -1215,6 +1219,7 @@ struct FuncOpConversion : public calyx::FuncOpPartialLoweringPattern { else resName = "out" + std::to_string(res.index()); funcOpResultMapping[res.index()] = outPorts.size(); + outPorts.push_back(calyx::PortInfo{ rewriter.getStringAttr(resName), calyx::convIndexType(rewriter, res.value()), calyx::Direction::Output, diff --git a/lib/Dialect/Calyx/CalyxOps.cpp b/lib/Dialect/Calyx/CalyxOps.cpp index 3442d76953ec..fb258934e969 100644 --- a/lib/Dialect/Calyx/CalyxOps.cpp +++ b/lib/Dialect/Calyx/CalyxOps.cpp @@ -1980,10 +1980,13 @@ void ConstantOp::getAsmResultNames( LogicalResult ConstantOp::verify() { auto type = getType(); - // The value's type must match the return type. - if (auto valType = getValue().getType(); valType != type) { - return emitOpError() << "value type " << valType - << " must match return type: " << type; + assert(isa(type) && "must be an IntegerType"); + // The value's bit width must match the return type bitwidth. + if (auto valTyBitWidth = getValue().getType().getIntOrFloatBitWidth(); + valTyBitWidth != type.getIntOrFloatBitWidth()) { + return emitOpError() << "value type bit width" << valTyBitWidth + << " must match return type: " + << type.getIntOrFloatBitWidth(); } // Integer values must be signless. if (llvm::isa(type) && @@ -2002,12 +2005,12 @@ OpFoldResult calyx::ConstantOp::fold(FoldAdaptor adaptor) { } void calyx::ConstantOp::build(OpBuilder &builder, OperationState &state, - StringRef symName, TypedAttr attr) { + StringRef symName, Attribute attr, Type type) { state.addAttribute(SymbolTable::getSymbolAttrName(), builder.getStringAttr(symName)); state.addAttribute("value", attr); SmallVector types; - types.push_back(attr.getType()); // Out + types.push_back(type); // Out state.addTypes(types); } diff --git a/lib/Dialect/Calyx/Transforms/CalyxHelpers.cpp b/lib/Dialect/Calyx/Transforms/CalyxHelpers.cpp index 1306ff0ec5dd..1bd5b593958f 100644 --- a/lib/Dialect/Calyx/Transforms/CalyxHelpers.cpp +++ b/lib/Dialect/Calyx/Transforms/CalyxHelpers.cpp @@ -27,14 +27,6 @@ calyx::RegisterOp createRegister(Location loc, OpBuilder &builder, return builder.create(loc, (prefix + "_reg").str(), width); } -calyx::RegisterOp createRegister(Location loc, OpBuilder &builder, - ComponentOp component, Type type, - Twine prefix) { - OpBuilder::InsertionGuard guard(builder); - builder.setInsertionPointToStart(component.getBodyBlock()); - return builder.create(loc, (prefix + "_reg").str(), type); -} - hw::ConstantOp createConstant(Location loc, OpBuilder &builder, ComponentOp component, size_t width, size_t value) { diff --git a/lib/Dialect/Calyx/Transforms/CalyxLoweringUtils.cpp b/lib/Dialect/Calyx/Transforms/CalyxLoweringUtils.cpp index b27188abc4dc..f4cc4ab91cad 100644 --- a/lib/Dialect/Calyx/Transforms/CalyxLoweringUtils.cpp +++ b/lib/Dialect/Calyx/Transforms/CalyxLoweringUtils.cpp @@ -139,6 +139,8 @@ Value getComponentOutput(calyx::ComponentOp compOp, unsigned outPortIdx) { Type convIndexType(OpBuilder &builder, Type type) { if (type.isIndex()) return builder.getI32Type(); + if (type.isIntOrFloat() && !type.isInteger()) + return builder.getIntegerType(type.getIntOrFloatBitWidth()); return type; } @@ -768,7 +770,7 @@ BuildReturnRegs::partiallyLowerFuncToComp(mlir::func::FuncOp funcOp, "unsupported return type"); std::string name = "ret_arg" + std::to_string(argType.index()); auto reg = createRegister(funcOp.getLoc(), rewriter, getComponent(), - convArgType, name); + convArgType.getIntOrFloatBitWidth(), name); getState().addReturnReg(reg, argType.index()); rewriter.setInsertionPointToStart( diff --git a/test/Conversion/SCFToCalyx/convert_simple.mlir b/test/Conversion/SCFToCalyx/convert_simple.mlir index 6c603fc95f3c..f67425507896 100644 --- a/test/Conversion/SCFToCalyx/convert_simple.mlir +++ b/test/Conversion/SCFToCalyx/convert_simple.mlir @@ -215,11 +215,11 @@ module { // Test integer and floating point constant // CHECK: calyx.group @ret_assign_0 { -// CHECK-DAG: calyx.assign %ret_arg0_reg.in = %in0 : f32 +// CHECK-DAG: calyx.assign %ret_arg0_reg.in = %in0 : i32 // CHECK-DAG: calyx.assign %ret_arg0_reg.write_en = %true : i1 // CHECK-DAG: calyx.assign %ret_arg1_reg.in = %c42_i32 : i32 // CHECK-DAG: calyx.assign %ret_arg1_reg.write_en = %true : i1 -// CHECK-DAG: calyx.assign %ret_arg2_reg.in = %cst : f32 +// CHECK-DAG: calyx.assign %ret_arg2_reg.in = %cst : i32 // CHECK-DAG: calyx.assign %ret_arg2_reg.write_en = %true : i1 // CHECK-DAG: %0 = comb.and %ret_arg2_reg.done, %ret_arg1_reg.done, %ret_arg0_reg.done : i1 // CHECK-DAG: calyx.group_done %0 ? %true : i1 @@ -239,9 +239,9 @@ module { // Test floating point add // CHECK: calyx.group @bb0_0 { -// CHECK-DAG: calyx.assign %std_addFN_0.left = %in0 : f32 -// CHECK-DAG: calyx.assign %std_addFN_0.right = %cst : f32 -// CHECK-DAG: calyx.assign %addf_0_reg.in = %std_addFN_0.out : f32 +// CHECK-DAG: calyx.assign %std_addFN_0.left = %in0 : i32 +// CHECK-DAG: calyx.assign %std_addFN_0.right = %cst : i32 +// CHECK-DAG: calyx.assign %addf_0_reg.in = %std_addFN_0.out : i32 // CHECK-DAG: calyx.assign %addf_0_reg.write_en = %std_addFN_0.done : i1 // CHECK-DAG: %0 = comb.xor %std_addFN_0.done, %true : i1 // CHECK-DAG: calyx.assign %std_addFN_0.go = %0 ? %true : i1 diff --git a/test/Dialect/Calyx/emit.mlir b/test/Dialect/Calyx/emit.mlir index 13925b0b9033..fa4f07306ea8 100644 --- a/test/Dialect/Calyx/emit.mlir +++ b/test/Dialect/Calyx/emit.mlir @@ -245,15 +245,15 @@ module attributes {calyx.entrypoint = "main"} { // ----- module attributes {calyx.entrypoint = "main"} { - calyx.component @main(%clk: i1 {clk}, %reset: i1 {reset}, %go: i1 {go}) -> (%out0: i32, %out1: f32, %done: i1 {done}) { + calyx.component @main(%clk: i1 {clk}, %reset: i1 {reset}, %go: i1 {go}) -> (%out0: i32, %out1: i32, %done: i1 {done}) { // CHECK: cst_0 = std_float_const(0, 32, 4.200000); %c42_i32 = hw.constant 42 : i32 - %cst = calyx.constant {sym_name = "cst_0"} 4.200000e+00 : f32 + %cst = calyx.constant @cst_0 <4.200000e+00 : f32> : i32 %true = hw.constant true - %ret_arg1_reg.in, %ret_arg1_reg.write_en, %ret_arg1_reg.clk, %ret_arg1_reg.reset, %ret_arg1_reg.out, %ret_arg1_reg.done = calyx.register @ret_arg1_reg : f32, i1, i1, i1, f32, i1 + %ret_arg1_reg.in, %ret_arg1_reg.write_en, %ret_arg1_reg.clk, %ret_arg1_reg.reset, %ret_arg1_reg.out, %ret_arg1_reg.done = calyx.register @ret_arg1_reg : i32, i1, i1, i1, i32, i1 %ret_arg0_reg.in, %ret_arg0_reg.write_en, %ret_arg0_reg.clk, %ret_arg0_reg.reset, %ret_arg0_reg.out, %ret_arg0_reg.done = calyx.register @ret_arg0_reg : i32, i1, i1, i1, i32, i1 calyx.wires { - calyx.assign %out1 = %ret_arg1_reg.out : f32 + calyx.assign %out1 = %ret_arg1_reg.out : i32 calyx.assign %out0 = %ret_arg0_reg.out : i32 // CHECK-LABEL: group ret_assign_0 { @@ -266,7 +266,7 @@ module attributes {calyx.entrypoint = "main"} { calyx.group @ret_assign_0 { calyx.assign %ret_arg0_reg.in = %c42_i32 : i32 calyx.assign %ret_arg0_reg.write_en = %true : i1 - calyx.assign %ret_arg1_reg.in = %cst : f32 + calyx.assign %ret_arg1_reg.in = %cst : i32 calyx.assign %ret_arg1_reg.write_en = %true : i1 %0 = comb.and %ret_arg1_reg.done, %ret_arg0_reg.done : i1 calyx.group_done %0 ? %true : i1 @@ -285,16 +285,16 @@ module attributes {calyx.entrypoint = "main"} { module attributes {calyx.entrypoint = "main"} { // CHECK: import "primitives/float/addFN.futil"; - calyx.component @main(%in0: f32, %clk: i1 {clk}, %reset: i1 {reset}, %go: i1 {go}) -> (%out0: f32, %done: i1 {done}) { + calyx.component @main(%in0: i32, %clk: i1 {clk}, %reset: i1 {reset}, %go: i1 {go}) -> (%out0: i32, %done: i1 {done}) { // CHECK: std_addFN_0 = std_addFN(8, 24, 32); - %cst = calyx.constant {sym_name = "cst_0"} 4.200000e+00 : f32 + %cst = calyx.constant @cst_0 <4.200000e+00 : f32> : i32 %true = hw.constant true %false = hw.constant false - %addf_0_reg.in, %addf_0_reg.write_en, %addf_0_reg.clk, %addf_0_reg.reset, %addf_0_reg.out, %addf_0_reg.done = calyx.register @addf_0_reg : f32, i1, i1, i1, f32, i1 - %std_addFN_0.clk, %std_addFN_0.reset, %std_addFN_0.go, %std_addFN_0.control, %std_addFN_0.subOp, %std_addFN_0.left, %std_addFN_0.right, %std_addFN_0.roundingMode, %std_addFN_0.out, %std_addFN_0.exceptionalFlags, %std_addFN_0.done = calyx.std_addFN @std_addFN_0 : i1, i1, i1, i1, i1, f32, f32, i3, f32, i5, i1 - %ret_arg0_reg.in, %ret_arg0_reg.write_en, %ret_arg0_reg.clk, %ret_arg0_reg.reset, %ret_arg0_reg.out, %ret_arg0_reg.done = calyx.register @ret_arg0_reg : f32, i1, i1, i1, f32, i1 + %addf_0_reg.in, %addf_0_reg.write_en, %addf_0_reg.clk, %addf_0_reg.reset, %addf_0_reg.out, %addf_0_reg.done = calyx.register @addf_0_reg : i32, i1, i1, i1, i32, i1 + %std_addFN_0.clk, %std_addFN_0.reset, %std_addFN_0.go, %std_addFN_0.control, %std_addFN_0.subOp, %std_addFN_0.left, %std_addFN_0.right, %std_addFN_0.roundingMode, %std_addFN_0.out, %std_addFN_0.exceptionalFlags, %std_addFN_0.done = calyx.std_addFN @std_addFN_0 : i1, i1, i1, i1, i1, i32, i32, i3, i32, i5, i1 + %ret_arg0_reg.in, %ret_arg0_reg.write_en, %ret_arg0_reg.clk, %ret_arg0_reg.reset, %ret_arg0_reg.out, %ret_arg0_reg.done = calyx.register @ret_arg0_reg : i32, i1, i1, i1, i32, i1 calyx.wires { - calyx.assign %out0 = %ret_arg0_reg.out : f32 + calyx.assign %out0 = %ret_arg0_reg.out : i32 // CHECK-LABEL: group bb0_0 { // CHECK-NEXT: std_addFN_0.left = in0; @@ -306,9 +306,9 @@ module attributes {calyx.entrypoint = "main"} { // CHECK-NEXT: bb0_0[done] = addf_0_reg.done; // CHECK-NEXT: } calyx.group @bb0_0 { - calyx.assign %std_addFN_0.left = %in0 : f32 - calyx.assign %std_addFN_0.right = %cst : f32 - calyx.assign %addf_0_reg.in = %std_addFN_0.out : f32 + calyx.assign %std_addFN_0.left = %in0 : i32 + calyx.assign %std_addFN_0.right = %cst : i32 + calyx.assign %addf_0_reg.in = %std_addFN_0.out : i32 calyx.assign %addf_0_reg.write_en = %std_addFN_0.done : i1 %0 = comb.xor %std_addFN_0.done, %true : i1 calyx.assign %std_addFN_0.go = %0 ? %true : i1 @@ -316,7 +316,7 @@ module attributes {calyx.entrypoint = "main"} { calyx.group_done %addf_0_reg.done : i1 } calyx.group @ret_assign_0 { - calyx.assign %ret_arg0_reg.in = %std_addFN_0.out : f32 + calyx.assign %ret_arg0_reg.in = %std_addFN_0.out : i32 calyx.assign %ret_arg0_reg.write_en = %true : i1 calyx.group_done %ret_arg0_reg.done : i1 }