Skip to content
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
10 changes: 6 additions & 4 deletions include/circt/Dialect/Moore/MooreOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -1997,16 +1997,18 @@ def FormatIntOp : MooreOp<"fmt.int", [Pure]> {
let arguments = (ins
IntType:$value,
IntFormatAttr:$format,
I32Attr:$width,
IntAlignAttr:$alignment,
IntPaddingAttr:$padding
IntPaddingAttr:$padding,
OptionalAttr<I32Attr>:$specifierWidth,
UnitAttr:$isSigned
);
let results = (outs FormatStringType:$result);
let assemblyFormat = [{
$format $value `,`
`width` $width `,`
$format $value `,`
`align` $alignment `,`
`pad` $padding
(`width` $specifierWidth^)?
(`signed` $isSigned^)?
attr-dict `:` type($value)
}];
}
Expand Down
55 changes: 47 additions & 8 deletions include/circt/Dialect/Sim/SimOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -181,12 +181,23 @@ def FormatHexOp : SimOp<"fmt.hex", [Pure]> {
}];


let arguments = (ins AnyInteger:$value);
let arguments = (ins AnyInteger:$value,
BoolAttr:$isHexUppercase,
DefaultValuedAttr<BoolAttr,"false">:$isLeftAligned,
DefaultValuedAttr<I8Attr,"48">:$paddingChar,
OptionalAttr<I32Attr>:$specifierWidth);
let results = (outs FormatStringType:$result);

let hasFolder = true;

let assemblyFormat = "$value attr-dict `:` qualified(type($value))";
let assemblyFormat = [{
$value `,`
`isUpper` $isHexUppercase
(`isLeftAligned` $isLeftAligned^)?
(`paddingChar` $paddingChar^)?
(`specifierWidth` $specifierWidth^)?
attr-dict `:` qualified(type($value))
}];
}

def FormatOctOp : SimOp<"fmt.oct", [Pure]> {
Expand All @@ -201,12 +212,22 @@ def FormatOctOp : SimOp<"fmt.oct", [Pure]> {
}];


let arguments = (ins AnyInteger:$value);
let arguments = (ins AnyInteger:$value,
DefaultValuedAttr<BoolAttr,"false">:$isLeftAligned,
DefaultValuedAttr<I8Attr,"48">:$paddingChar,
OptionalAttr<I32Attr>:$specifierWidth);

let results = (outs FormatStringType:$result);

let hasFolder = true;

let assemblyFormat = "$value attr-dict `:` qualified(type($value))";
let assemblyFormat = [{
$value
(`isLeftAligned` $isLeftAligned^)?
(`paddingChar` $paddingChar^)?
(`specifierWidth` $specifierWidth^)?
attr-dict `:` qualified(type($value))
}];
}

def FormatBinOp : SimOp<"fmt.bin", [Pure]> {
Expand All @@ -219,12 +240,21 @@ def FormatBinOp : SimOp<"fmt.bin", [Pure]> {
the empty string. No further prefix will be added.
}];

let arguments = (ins AnyInteger:$value);
let arguments = (ins AnyInteger:$value,
DefaultValuedAttr<BoolAttr,"false">:$isLeftAligned,
DefaultValuedAttr<I8Attr,"48">:$paddingChar,
OptionalAttr<I32Attr>:$specifierWidth);
let results = (outs FormatStringType:$result);

let hasFolder = true;

let assemblyFormat = "$value attr-dict `:` qualified(type($value))";
let assemblyFormat = [{
$value
(`isLeftAligned` $isLeftAligned^)?
(`paddingChar` $paddingChar^)?
(`specifierWidth` $specifierWidth^)?
attr-dict `:` qualified(type($value))
}];
}


Expand Down Expand Up @@ -252,13 +282,22 @@ def FormatDecOp : SimOp<"fmt.dec", [Pure]> {
Backends are recommended to not exceed the required amount of padding.
}];

let arguments = (ins AnyInteger:$value, UnitAttr:$isSigned);
let arguments = (ins AnyInteger:$value,
DefaultValuedAttr<BoolAttr,"false">:$isLeftAligned,
DefaultValuedAttr<I8Attr,"32">:$paddingChar,
OptionalAttr<I32Attr>:$specifierWidth,
UnitAttr:$isSigned);
let results = (outs FormatStringType:$result);

let hasFolder = true;

let assemblyFormat = [{
(`signed` $isSigned^)? $value attr-dict `:` qualified(type($value))
$value
(`isLeftAligned` $isLeftAligned^)?
(`paddingChar` $paddingChar^)?
(`specifierWidth` $specifierWidth^)?
(`signed` $isSigned^)?
attr-dict `:` qualified(type($value))
}];

let extraClassDeclaration = [{
Expand Down
32 changes: 12 additions & 20 deletions lib/Conversion/ImportVerilog/FormatStrings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ struct FormatStringParser {
Type intTy = {};
Value val;
auto rVal = context.convertRvalueExpression(arg);
// To infer whether or not the value is signed while printing as a decimal
// Since it only matters if it's a decimal, we add `format ==
// IntFormat::Decimal`
bool isSigned = arg.type->isSigned() && format == IntFormat::Decimal;
if (!rVal)
return failure();

Expand Down Expand Up @@ -184,30 +188,17 @@ struct FormatStringParser {
if (!value)
return failure();

// Determine the width to which the formatted integer should be padded.
unsigned width;
if (options.width) {
width = *options.width;
} else {
width = cast<moore::IntType>(value.getType()).getWidth();
if (format == IntFormat::Octal)
// 3 bits per octal digit
width = (width + 2) / 3;
else if (format == IntFormat::HexLower || format == IntFormat::HexUpper)
// 4 bits per hex digit
width = (width + 3) / 4;
else if (format == IntFormat::Decimal)
// ca. 3.322 bits per decimal digit (ln(10)/ln(2))
width = std::ceil(width * std::log(2) / std::log(10));
}

// Determine the alignment and padding.
auto alignment = options.leftJustify ? IntAlign::Left : IntAlign::Right;
auto padding =
format == IntFormat::Decimal ? IntPadding::Space : IntPadding::Zero;
IntegerAttr widthAttr = nullptr;
if (options.width) {
widthAttr = builder.getI32IntegerAttr(*options.width);
}

fragments.push_back(moore::FormatIntOp::create(builder, loc, value, format,
width, alignment, padding));
fragments.push_back(moore::FormatIntOp::create(
builder, loc, value, format, alignment, padding, widthAttr, isSigned));
return success();
}

Expand Down Expand Up @@ -250,7 +241,8 @@ struct FormatStringParser {
auto alignment = options.leftJustify ? IntAlign::Left : IntAlign::Right;
auto padding = options.zeroPad ? IntPadding::Zero : IntPadding::Space;
fragments.push_back(moore::FormatIntOp::create(
builder, loc, value, IntFormat::Decimal, width, alignment, padding));
builder, loc, value, IntFormat::Decimal, alignment, padding,
builder.getI32IntegerAttr(width)));
return success();
}

Expand Down
27 changes: 22 additions & 5 deletions lib/Conversion/MooreToCore/MooreToCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2009,20 +2009,37 @@ struct FormatIntOpConversion : public OpConversionPattern<FormatIntOp> {
LogicalResult
matchAndRewrite(FormatIntOp op, OpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const override {
// TODO: These should honor the width, alignment, and padding.

char padChar = adaptor.getPadding() == IntPadding::Space ? 32 : 48;
IntegerAttr padCharAttr = rewriter.getI8IntegerAttr(padChar);
auto widthAttr = adaptor.getSpecifierWidthAttr();

bool isLeftAligned = adaptor.getAlignment() == IntAlign::Left;
BoolAttr isLeftAlignedAttr = rewriter.getBoolAttr(isLeftAligned);

switch (op.getFormat()) {
case IntFormat::Decimal:
rewriter.replaceOpWithNewOp<sim::FormatDecOp>(op, adaptor.getValue());
rewriter.replaceOpWithNewOp<sim::FormatDecOp>(
op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr,
adaptor.getIsSignedAttr());
return success();
case IntFormat::Binary:
rewriter.replaceOpWithNewOp<sim::FormatBinOp>(op, adaptor.getValue());
rewriter.replaceOpWithNewOp<sim::FormatBinOp>(
op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr);
return success();
case IntFormat::Octal:
rewriter.replaceOpWithNewOp<sim::FormatOctOp>(op, adaptor.getValue());
rewriter.replaceOpWithNewOp<sim::FormatOctOp>(
op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr);
return success();
case IntFormat::HexLower:
rewriter.replaceOpWithNewOp<sim::FormatHexOp>(
op, adaptor.getValue(), rewriter.getBoolAttr(false),
isLeftAlignedAttr, padCharAttr, widthAttr);
return success();
case IntFormat::HexUpper:
rewriter.replaceOpWithNewOp<sim::FormatHexOp>(op, adaptor.getValue());
rewriter.replaceOpWithNewOp<sim::FormatHexOp>(
op, adaptor.getValue(), rewriter.getBoolAttr(true), isLeftAlignedAttr,
padCharAttr, widthAttr);
return success();
default:
return rewriter.notifyMatchFailure(op, "unsupported int format");
Expand Down
120 changes: 73 additions & 47 deletions lib/Dialect/Sim/SimOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,57 @@ using namespace mlir;
using namespace circt;
using namespace sim;

static StringAttr formatIntegersByRadix(MLIRContext *ctx, unsigned radix,
const Attribute &value,
bool isUpperCase, bool isLeftAligned,
char paddingChar,
std::optional<int> specifierWidth,
bool isSigned = false) {

if (auto intAttr = llvm::dyn_cast_or_null<IntegerAttr>(value)) {
SmallVector<char, 32> strBuf;
intAttr.getValue().toString(strBuf, radix, isSigned, false, isUpperCase);
unsigned width = intAttr.getType().getIntOrFloatBitWidth();
unsigned padWidth;
switch (radix) {
case 2:
padWidth = width;
break;
case 8:
padWidth = (width + 2) / 3;
break;
case 16:
padWidth = (width + 3) / 4;
break;
default:
padWidth = width;
break;
}

unsigned numSpaces = 0;
if (specifierWidth.has_value() &&
(specifierWidth.value() >
std::max(padWidth, static_cast<unsigned>(strBuf.size())))) {
numSpaces = std::max(
0U, specifierWidth.value() -
std::max(padWidth, static_cast<unsigned>(strBuf.size())));
}

SmallVector<char, 1> spacePadding(numSpaces, ' ');

padWidth = padWidth > strBuf.size() ? padWidth - strBuf.size() : 0;

SmallVector<char, 32> padding(padWidth, paddingChar);
if (isLeftAligned) {
return StringAttr::get(ctx, Twine(padding) + Twine(strBuf) +
Twine(spacePadding));
}
return StringAttr::get(ctx, Twine(spacePadding) + Twine(padding) +
Twine(strBuf));
}
return {};
}

ParseResult DPIFuncOp::parse(OpAsmParser &parser, OperationState &result) {
auto builder = parser.getBuilder();
// Parse visibility.
Expand Down Expand Up @@ -120,13 +171,21 @@ OpFoldResult FormatDecOp::fold(FoldAdaptor adaptor) {

if (auto intAttr = llvm::dyn_cast_or_null<IntegerAttr>(adaptor.getValue())) {
SmallVector<char, 16> strBuf;
intAttr.getValue().toString(strBuf, 10U, getIsSigned());
intAttr.getValue().toString(strBuf, 10U, adaptor.getIsSigned());
unsigned padWidth;
if (adaptor.getSpecifierWidth().has_value()) {
padWidth = adaptor.getSpecifierWidth().value();
} else {
unsigned width = intAttr.getType().getIntOrFloatBitWidth();
padWidth = FormatDecOp::getDecimalWidth(width, adaptor.getIsSigned());
}

unsigned width = intAttr.getType().getIntOrFloatBitWidth();
unsigned padWidth = FormatDecOp::getDecimalWidth(width, getIsSigned());
padWidth = padWidth > strBuf.size() ? padWidth - strBuf.size() : 0;

SmallVector<char, 8> padding(padWidth, ' ');
SmallVector<char, 10> padding(padWidth, adaptor.getPaddingChar());
if (adaptor.getIsLeftAligned()) {
return StringAttr::get(getContext(), Twine(strBuf) + Twine(padding));
}
return StringAttr::get(getContext(), Twine(padding) + Twine(strBuf));
}
return {};
Expand All @@ -136,61 +195,28 @@ OpFoldResult FormatHexOp::fold(FoldAdaptor adaptor) {
if (getValue().getType() == IntegerType::get(getContext(), 0U))
return StringAttr::get(getContext(), "");

if (auto intAttr = llvm::dyn_cast_or_null<IntegerAttr>(adaptor.getValue())) {
SmallVector<char, 8> strBuf;
intAttr.getValue().toString(strBuf, 16U, /*Signed*/ false,
/*formatAsCLiteral*/ false,
/*UpperCase*/ false);

unsigned width = intAttr.getType().getIntOrFloatBitWidth();
unsigned padWidth = width / 4;
if (width % 4 != 0)
padWidth++;
padWidth = padWidth > strBuf.size() ? padWidth - strBuf.size() : 0;

SmallVector<char, 8> padding(padWidth, '0');
return StringAttr::get(getContext(), Twine(padding) + Twine(strBuf));
}
return {};
return formatIntegersByRadix(
getContext(), 16U, adaptor.getValue(), adaptor.getIsHexUppercase(),
adaptor.getIsLeftAligned(), adaptor.getPaddingChar(),
adaptor.getSpecifierWidth());
}

OpFoldResult FormatOctOp::fold(FoldAdaptor adaptor) {
if (getValue().getType() == IntegerType::get(getContext(), 0U))
return StringAttr::get(getContext(), "");

if (auto intAttr = llvm::dyn_cast_or_null<IntegerAttr>(adaptor.getValue())) {
SmallVector<char, 11> strBuf;
intAttr.getValue().toString(strBuf, 8U, /*Signed*/ false,
/*formatAsCLiteral*/ false,
/*UpperCase*/ false);

unsigned width = intAttr.getType().getIntOrFloatBitWidth();
unsigned padWidth = width / 3;
if (width % 3 != 0)
padWidth++;
padWidth = padWidth > strBuf.size() ? padWidth - strBuf.size() : 0;

SmallVector<char, 11> padding(padWidth, '0');
return StringAttr::get(getContext(), Twine(padding) + Twine(strBuf));
}
return {};
return formatIntegersByRadix(
getContext(), 8U, adaptor.getValue(), false, adaptor.getIsLeftAligned(),
adaptor.getPaddingChar(), adaptor.getSpecifierWidth());
}

OpFoldResult FormatBinOp::fold(FoldAdaptor adaptor) {
if (getValue().getType() == IntegerType::get(getContext(), 0U))
return StringAttr::get(getContext(), "");

if (auto intAttr = llvm::dyn_cast_or_null<IntegerAttr>(adaptor.getValue())) {
SmallVector<char, 32> strBuf;
intAttr.getValue().toString(strBuf, 2U, false);

unsigned width = intAttr.getType().getIntOrFloatBitWidth();
unsigned padWidth = width > strBuf.size() ? width - strBuf.size() : 0;

SmallVector<char, 32> padding(padWidth, '0');
return StringAttr::get(getContext(), Twine(padding) + Twine(strBuf));
}
return {};
return formatIntegersByRadix(
getContext(), 2U, adaptor.getValue(), false, adaptor.getIsLeftAligned(),
adaptor.getPaddingChar(), adaptor.getSpecifierWidth());
}

OpFoldResult FormatCharOp::fold(FoldAdaptor adaptor) {
Expand Down
Loading