Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MooreToCore] Add support for format strings and display task #7694

Merged
merged 1 commit into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions include/circt/Conversion/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -512,12 +512,18 @@ def HandshakeToHW : Pass<"lower-handshake-to-hw", "mlir::ModuleOp"> {
def ConvertMooreToCore : Pass<"convert-moore-to-core", "mlir::ModuleOp"> {
let summary = "Convert Moore to Core";
let description = [{
This pass translates Moore to the core dialects (Comb/HW/LLHD).
This pass translates Moore to the core dialects.
}];
let constructor = "circt::createConvertMooreToCorePass()";
let dependentDialects = ["comb::CombDialect", "hw::HWDialect",
"llhd::LLHDDialect", "mlir::cf::ControlFlowDialect",
"mlir::scf::SCFDialect", "verif::VerifDialect"];
let dependentDialects = [
"comb::CombDialect",
"hw::HWDialect",
"llhd::LLHDDialect",
"mlir::cf::ControlFlowDialect",
"mlir::scf::SCFDialect",
"sim::SimDialect",
"verif::VerifDialect",
];
}

//===----------------------------------------------------------------------===//
Expand Down
1 change: 1 addition & 0 deletions lib/Conversion/MooreToCore/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ add_circt_conversion_library(CIRCTMooreToCore
CIRCTHW
CIRCTLLHD
CIRCTMoore
CIRCTSim
CIRCTVerif
MLIRControlFlowDialect
MLIRFuncDialect
Expand Down
83 changes: 79 additions & 4 deletions lib/Conversion/MooreToCore/MooreToCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "circt/Dialect/HW/HWOps.h"
#include "circt/Dialect/LLHD/IR/LLHDOps.h"
#include "circt/Dialect/Moore/MooreOps.h"
#include "circt/Dialect/Sim/SimOps.h"
#include "circt/Dialect/Verif/VerifOps.h"
#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
Expand Down Expand Up @@ -1256,6 +1257,69 @@ struct AssertLikeOpConversion : public OpConversionPattern<MooreOpTy> {
}
};

//===----------------------------------------------------------------------===//
// Format String Conversion
//===----------------------------------------------------------------------===//

struct FormatLiteralOpConversion : public OpConversionPattern<FormatLiteralOp> {
using OpConversionPattern::OpConversionPattern;

LogicalResult
matchAndRewrite(FormatLiteralOp op, OpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const override {
rewriter.replaceOpWithNewOp<sim::FormatLitOp>(op, adaptor.getLiteral());
return success();
}
};

struct FormatConcatOpConversion : public OpConversionPattern<FormatConcatOp> {
using OpConversionPattern::OpConversionPattern;

LogicalResult
matchAndRewrite(FormatConcatOp op, OpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const override {
rewriter.replaceOpWithNewOp<sim::FormatStringConcatOp>(op,
adaptor.getInputs());
return success();
}
};

struct FormatIntOpConversion : public OpConversionPattern<FormatIntOp> {
using OpConversionPattern::OpConversionPattern;

LogicalResult
matchAndRewrite(FormatIntOp op, OpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const override {
// TODO: These should honor the width, alignment, and padding.
switch (op.getFormat()) {
case IntFormat::Decimal:
rewriter.replaceOpWithNewOp<sim::FormatDecOp>(op, adaptor.getValue());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a way of handling signedness here? By not setting the signed attribute the value will always get formatted as unsigned. How would we deal with the difference in this example:

module tb;
  byte foo = 8'h80;
  initial $display("Signed:   %d", $signed(foo));
  initial $display("Unsigned: %d", $unsigned(foo));
endmodule

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a great point. Do you know what the standard says how your example would be printed? Does %d check the type's signedness?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any mention of the sign in the LRM. But for once all simulators on edaplayground agree: It depends on the type's signedness. The above example is the same as

module tb;
  logic signed [7:0] fooS = 8'h80;
  logic [7:0] fooU = 8'h80;
  initial $display("Signed:   %d", fooS); // "Signed:   -128"
  initial $display("Unsigned: %d", fooU); // "Unsigned: 128"
endmodule

I wish they'd also agree on the padding...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 Nice! I also love how the %d field expands to the maximum width a decimal number can have, 3, but then adds a random - in front that throws everything off 🤣. I love how SV consistently picks the wrong default for a lot of things.

return success();
case IntFormat::Binary:
rewriter.replaceOpWithNewOp<sim::FormatBinOp>(op, adaptor.getValue());
return success();
case IntFormat::HexLower:
case IntFormat::HexUpper:
rewriter.replaceOpWithNewOp<sim::FormatHexOp>(op, adaptor.getValue());
return success();
default:
return rewriter.notifyMatchFailure(op, "unsupported int format");
}
}
};

struct DisplayBIOpConversion : public OpConversionPattern<DisplayBIOp> {
using OpConversionPattern::OpConversionPattern;

LogicalResult
matchAndRewrite(DisplayBIOp op, OpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const override {
rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(
op, adaptor.getMessage());
return success();
}
};

} // namespace

//===----------------------------------------------------------------------===//
Expand All @@ -1265,10 +1329,11 @@ struct AssertLikeOpConversion : public OpConversionPattern<MooreOpTy> {
static void populateLegality(ConversionTarget &target,
const TypeConverter &converter) {
target.addIllegalDialect<MooreDialect>();
target.addLegalDialect<mlir::BuiltinDialect>();
target.addLegalDialect<comb::CombDialect>();
target.addLegalDialect<hw::HWDialect>();
target.addLegalDialect<llhd::LLHDDialect>();
target.addLegalDialect<comb::CombDialect>();
target.addLegalDialect<mlir::BuiltinDialect>();
target.addLegalDialect<sim::SimDialect>();
target.addLegalDialect<verif::VerifDialect>();

target.addLegalOp<debug::ScopeOp>();
Expand All @@ -1295,6 +1360,10 @@ static void populateTypeConversion(TypeConverter &typeConverter) {
return IntegerType::get(type.getContext(), type.getWidth());
});

typeConverter.addConversion([&](FormatStringType type) {
return sim::FormatStringType::get(type.getContext());
});

typeConverter.addConversion([&](ArrayType type) -> std::optional<Type> {
if (auto elementType = typeConverter.convertType(type.getElementType()))
return hw::ArrayType::get(elementType, type.getSize());
Expand Down Expand Up @@ -1469,12 +1538,18 @@ static void populateOpConversion(RewritePatternSet &patterns,
// Patterns of assert-like operations
AssertLikeOpConversion<AssertOp, verif::AssertOp>,
AssertLikeOpConversion<AssumeOp, verif::AssumeOp>,
AssertLikeOpConversion<CoverOp, verif::CoverOp>
AssertLikeOpConversion<CoverOp, verif::CoverOp>,

// Format strings.
FormatLiteralOpConversion,
FormatConcatOpConversion,
FormatIntOpConversion,
DisplayBIOpConversion
>(typeConverter, context);
// clang-format on

mlir::populateAnyFunctionOpInterfaceTypeConversionPattern(patterns,
typeConverter);

hw::populateHWModuleLikeTypeConversionPattern(
hw::HWModuleOp::getOperationName(), patterns, typeConverter);
}
Expand Down
19 changes: 19 additions & 0 deletions test/Conversion/MooreToCore/basic.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,25 @@ func.func @Statements(%arg0: !moore.i42) {
return
}

// CHECK-LABEL: func @FormatStrings
func.func @FormatStrings(%arg0: !moore.i42) {
// CHECK: [[TMP:%.+]] = sim.fmt.lit "hello"
%0 = moore.fmt.literal "hello"
// CHECK: sim.fmt.concat ([[TMP]], [[TMP]])
%1 = moore.fmt.concat (%0, %0)
// CHECK: sim.fmt.dec %arg0 : i42
moore.fmt.int decimal %arg0, width 42, align right, pad space : i42
// CHECK: sim.fmt.bin %arg0 : i42
moore.fmt.int binary %arg0, width 42, align right, pad space : i42
// CHECK: sim.fmt.hex %arg0 : i42
moore.fmt.int hex_lower %arg0, width 42, align right, pad space : i42
// CHECK: sim.fmt.hex %arg0 : i42
moore.fmt.int hex_upper %arg0, width 42, align right, pad space : i42
// CHECK: sim.proc.print [[TMP]]
moore.builtin.display %0
return
}

// CHECK-LABEL: hw.module @InstanceNull() {
moore.module @InstanceNull() {

Expand Down
Loading