diff --git a/include/circt/Dialect/Calyx/CalyxPrimitives.td b/include/circt/Dialect/Calyx/CalyxPrimitives.td index 7d4b2019cb5d..d792a587a73e 100644 --- a/include/circt/Dialect/Calyx/CalyxPrimitives.td +++ b/include/circt/Dialect/Calyx/CalyxPrimitives.td @@ -10,6 +10,8 @@ // //===----------------------------------------------------------------------===// +include "mlir/IR/BuiltinAttributeInterfaces.td" + /// Base class for Calyx primitives. class CalyxPrimitive traits = []> : CalyxCell { @@ -18,6 +20,42 @@ class CalyxPrimitive traits = []> : let skipDefaultBuilders = 1; } +def ConstantOp: CalyxOp<"constant", + [Pure, ConstantLike, FirstAttrDerivedResultType, + DeclareOpInterfaceMethods, + AllTypesMatch<["value", "result"]> + ]> { + let summary = "integer or floating point constant"; + let description = [{ + The `constant` operation produces an SSA value equal to some integer or + floating-point constant specified by an attribute. + + Example: + + ``` + // Integer constant + %1 = calyx.constant 42 : i32 + + // Floating point constant + %1 = calyx.constant 42.00+e00 : f32 + ``` + }]; + let arguments = (ins TypedAttrInterface:$value); + + let results = (outs SignlessIntegerOrFloatLike:$result); + + let builders = [ + /// Build a ConstantOp from a prebuilt attribute. + OpBuilder <(ins "IntegerAttr":$attr)>, + + OpBuilder <(ins "FloatAttr":$attr)> + ]; + + let hasFolder = 1; + let assemblyFormat = "attr-dict $value"; + let hasVerifier = 1; +} + /// The n-bit, undef op which only provides the out signal def UndefLibOp: CalyxPrimitive<"undefined", []> { let summary = "An undefined signal"; diff --git a/lib/Conversion/SCFToCalyx/SCFToCalyx.cpp b/lib/Conversion/SCFToCalyx/SCFToCalyx.cpp index e208a502efc9..f3d0479ded16 100644 --- a/lib/Conversion/SCFToCalyx/SCFToCalyx.cpp +++ b/lib/Conversion/SCFToCalyx/SCFToCalyx.cpp @@ -795,12 +795,21 @@ LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter, LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter, arith::ConstantOp constOp) const { - /// Move constant operations to the compOp body as hw::ConstantOp's. - APInt value; - calyx::matchConstantOp(constOp, value); - auto hwConstOp = rewriter.replaceOpWithNewOp(constOp, value); - hwConstOp->moveAfter(getComponent().getBodyBlock(), - getComponent().getBodyBlock()->begin()); + if (isa(constOp.getType())) { + /// Move constant operations to the compOp body as hw::ConstantOp's. + APInt value; + calyx::matchConstantOp(constOp, value); + auto hwConstOp = + rewriter.replaceOpWithNewOp(constOp, value); + hwConstOp->moveAfter(getComponent().getBodyBlock(), + getComponent().getBodyBlock()->begin()); + } else { + auto calyxConstOp = rewriter.replaceOpWithNewOp( + constOp, constOp.getType(), constOp.getValueAttr()); + calyxConstOp->moveAfter(getComponent().getBodyBlock(), + getComponent().getBodyBlock()->begin()); + } + return success(); } diff --git a/lib/Dialect/Calyx/CalyxOps.cpp b/lib/Dialect/Calyx/CalyxOps.cpp index ead67b05b50a..21dfe8d17fd2 100644 --- a/lib/Dialect/Calyx/CalyxOps.cpp +++ b/lib/Dialect/Calyx/CalyxOps.cpp @@ -1944,6 +1944,62 @@ ParseResult GroupDoneOp::parse(OpAsmParser &parser, OperationState &result) { return parseGroupPort(parser, result); } +//===----------------------------------------------------------------------===// +// ConstantOp +//===----------------------------------------------------------------------===// +void ConstantOp::getAsmResultNames( + function_ref setNameFn) { + auto type = getType(); + if (auto intCst = llvm::dyn_cast(getValue())) { + auto intType = llvm::dyn_cast(type); + + // Sugar i1 constants with 'true' and 'false'. + if (intType && intType.getWidth() == 1) + return setNameFn(getResult(), (intCst.getInt() ? "true" : "false")); + + // Otherwise, build a complex name with the value and type. + SmallString<32> specialNameBuffer; + llvm::raw_svector_ostream specialName(specialNameBuffer); + specialName << 'c' << intCst.getValue(); + if (intType) + specialName << '_' << type; + setNameFn(getResult(), specialName.str()); + } else { + setNameFn(getResult(), "cst"); + } +} + +LogicalResult ConstantOp::verify() { + auto type = getType(); + // The value's type must match the return type. + if (getValue().getType() != type) { + return emitOpError() << "value type " << getValue().getType() + << " must match return type: " << type; + } + // Integer values must be signless. + if (llvm::isa(type) && + !llvm::cast(type).isSignless()) + return emitOpError("integer return type must be signless"); + // Any float or elements attribute are acceptable. + if (!llvm::isa(getValue())) { + return emitOpError("value must be an integer or float attribute"); + } + + return success(); +} + +OpFoldResult calyx::ConstantOp::fold(FoldAdaptor adaptor) { + return getValueAttr(); +} + +void calyx::ConstantOp::build(OpBuilder &builder, OperationState &state, + FloatAttr attr) { + state.addAttribute("value", attr); + SmallVector types; + types.push_back(attr.getType()); // Out + state.addTypes(types); +} + //===----------------------------------------------------------------------===// // RegisterOp //===----------------------------------------------------------------------===// diff --git a/lib/Dialect/Calyx/Transforms/CalyxLoweringUtils.cpp b/lib/Dialect/Calyx/Transforms/CalyxLoweringUtils.cpp index 1e701973da87..370de7db7266 100644 --- a/lib/Dialect/Calyx/Transforms/CalyxLoweringUtils.cpp +++ b/lib/Dialect/Calyx/Transforms/CalyxLoweringUtils.cpp @@ -657,10 +657,10 @@ void InlineCombGroups::recurseInlineCombGroups( // LateSSAReplacement) if (isa(src) || isa( - src.getDefiningOp())) + calyx::ConstantOp, hw::ConstantOp, mlir::arith::ConstantOp, + calyx::MultPipeLibOp, calyx::DivUPipeLibOp, calyx::DivSPipeLibOp, + calyx::RemSPipeLibOp, calyx::RemUPipeLibOp, mlir::scf::WhileOp, + calyx::InstanceOp>(src.getDefiningOp())) continue; auto srcCombGroup = dyn_cast( @@ -753,11 +753,11 @@ BuildReturnRegs::partiallyLowerFuncToComp(mlir::func::FuncOp funcOp, for (auto argType : enumerate(funcOp.getResultTypes())) { auto convArgType = calyx::convIndexType(rewriter, argType.value()); - assert(isa(convArgType) && "unsupported return type"); - unsigned width = convArgType.getIntOrFloatBitWidth(); + assert((isa(convArgType) || isa(convArgType)) && + "unsupported return type"); std::string name = "ret_arg" + std::to_string(argType.index()); - auto reg = - createRegister(funcOp.getLoc(), rewriter, getComponent(), width, name); + auto reg = createRegister(funcOp.getLoc(), rewriter, getComponent(), + convArgType, 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 b0324b0caeb3..d12d12b369d5 100644 --- a/test/Conversion/SCFToCalyx/convert_simple.mlir +++ b/test/Conversion/SCFToCalyx/convert_simple.mlir @@ -209,3 +209,27 @@ module { return %0, %1 : i8, i8 } } + +// ----- + +// 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.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.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 +// CHECK-DAG: } + +module { + func.func @main(%arg0 : f32) -> (f32, i32, f32) { + %0 = arith.constant 42 : i32 + %1 = arith.constant 4.2e+1 : f32 + + return %arg0, %0, %1 : f32, i32, f32 + } +}