Skip to content
Closed
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
2 changes: 1 addition & 1 deletion include/circt/Dialect/HW/HWMiscOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def WireOp : HWOp<"wire", [
}];
}

def KnownBitWidthType : Type<CPred<[{getBitWidth($_self) != -1}]>,
def KnownBitWidthType : Type<CPred<[{getBitWidth($_self).has_value()}]>,
"Type wherein the bitwidth in hardware is known">;

def BitcastOp: HWOp<"bitcast", [Pure]> {
Expand Down
4 changes: 2 additions & 2 deletions include/circt/Dialect/HW/HWModuleGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,8 @@ struct llvm::DOTGraphTraits<circt::hw::HWModuleOp>
<< ")\"";
}

int64_t width = circt::hw::getBitWidth(v.getType());
if (width > 1)
auto width = circt::hw::getBitWidth(v.getType());
if (width && *width > 1)
os << " style=bold";

return os.str();
Expand Down
2 changes: 1 addition & 1 deletion include/circt/Dialect/HW/HWTypeInterfaces.td
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def BitWidthTypeInterface : TypeInterface<"BitWidthTypeInterface"> {
statically-sized type. Reflects the number of wires needed to transmit a
value of this type. Returns std::nullopt if the type's bit width cannot
be statically computed.
}], "std::optional<int64_t>", "getBitWidth">,
}], "std::optional<uint64_t>", "getBitWidth">,
];
}

Expand Down
7 changes: 4 additions & 3 deletions include/circt/Dialect/HW/HWTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "circt/Support/LLVM.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Types.h"
#include <optional>

namespace circt {
namespace hw {
Expand Down Expand Up @@ -129,9 +130,9 @@ bool isHWValueType(mlir::Type type);
/// Return the hardware bit width of a type. Does not reflect any encoding,
/// padding, or storage scheme, just the bit (and wire width) of a
/// statically-size type. Reflects the number of wires needed to transmit a
/// value of this type. Returns -1 if the type is not known or cannot be
/// statically computed.
int64_t getBitWidth(mlir::Type type);
/// value of this type. Returns std::nullopt if the type is not known or cannot
/// be statically computed.
std::optional<uint64_t> getBitWidth(mlir::Type type);

/// Return true if the specified type contains known marker types like
/// InOutType. Unlike isHWValueType, this is not conservative, it only returns
Expand Down
6 changes: 4 additions & 2 deletions include/circt/Dialect/SV/SVExpressions.td
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@ def ConstantXOp : SVOp<"constantX", [Pure, HasCustomSSAName]> {
let hasVerifier = 1;
let extraClassDeclaration = [{
int64_t getWidth() {
return hw::getBitWidth(getType());
auto width = hw::getBitWidth(getType());
return width ? static_cast<int64_t>(*width) : -1;
}
}];
}
Expand All @@ -180,7 +181,8 @@ def ConstantZOp : SVOp<"constantZ", [Pure, HasCustomSSAName]> {
let hasVerifier = 1;
let extraClassDeclaration = [{
int64_t getWidth() {
return hw::getBitWidth(getType());
auto width = hw::getBitWidth(getType());
return width ? static_cast<int64_t>(*width) : -1;
}
}];
}
Expand Down
2 changes: 1 addition & 1 deletion include/circt/Dialect/SV/SVTypeDecl.td
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def SignalTypeAttr : TypeAttrBase<"::mlir::Type", "Any SV/HW type"> {
let predicate = And<[
CPred<"llvm::isa<::mlir::TypeAttr>($_self)">,
CPred<"::circt::hw::getBitWidth(" #
"llvm::cast<::mlir::TypeAttr>($_self).getValue()) != -1">
"llvm::cast<::mlir::TypeAttr>($_self).getValue()).has_value()">
]>;
}

Expand Down
26 changes: 17 additions & 9 deletions lib/Conversion/CombToSynth/CombToSynth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,9 @@ static int64_t getNumUnknownBitsAndPopulateValues(
// Consider other operations as unknown bits.
// TODO: We can handle replicate, extract, etc.
values.push_back(value);
return hw::getBitWidth(value.getType());
auto width = hw::getBitWidth(value.getType());
assert(width && "value must have known bitwidth");
return *width;
}

// Return a value that substitutes the unknown bits with the mask.
Expand All @@ -193,8 +195,9 @@ substitueMaskToValues(size_t width,
elemWidth = constant.getValue().getBitWidth();
result.insertBits(constant.getValue(), bitPos);
} else {
elemWidth = hw::getBitWidth(cast<Value>(constantOrValue).getType());
assert(elemWidth >= 0 && "unknown bit width");
auto width = hw::getBitWidth(cast<Value>(constantOrValue).getType());
assert(width && "value must have known bitwidth");
elemWidth = *width;
assert(elemWidth + unknownPos < 32 && "unknown bit width too large");
// Create a mask for the unknown bits.
uint32_t usedBits = (mask >> unknownPos) & ((1 << elemWidth) - 1);
Expand Down Expand Up @@ -326,9 +329,10 @@ struct CombOrToMIGConversion : OpConversionPattern<OrOp> {
if (op.getNumOperands() != 2)
return failure();
SmallVector<Value, 3> inputs(adaptor.getInputs());
auto one = hw::ConstantOp::create(
rewriter, op.getLoc(),
APInt::getAllOnes(hw::getBitWidth(op.getType())));
auto width = hw::getBitWidth(op.getType());
assert(width && "op result must have known bitwidth");
auto one = hw::ConstantOp::create(rewriter, op.getLoc(),
APInt::getAllOnes(*width));
inputs.push_back(one);
std::array<bool, 3> inverts = {false, false, false};
replaceOpWithNewOpAndCopyNamehint<synth::mig::MajorityInverterOp>(
Expand All @@ -352,8 +356,10 @@ struct AndInverterToMIGConversion
return success();
}
SmallVector<Value, 3> inputs(adaptor.getInputs());
auto one = hw::ConstantOp::create(
rewriter, op.getLoc(), APInt::getZero(hw::getBitWidth(op.getType())));
auto width = hw::getBitWidth(op.getType());
assert(width && "op result must have known bitwidth");
auto one =
hw::ConstantOp::create(rewriter, op.getLoc(), APInt::getZero(*width));
inputs.push_back(one);
SmallVector<bool, 3> inverts(adaptor.getInverted());
inverts.push_back(false);
Expand Down Expand Up @@ -442,7 +448,9 @@ struct CombMuxOpConversion : OpConversionPattern<MuxOp> {

if (!op.getType().isInteger()) {
// If the type of the mux is not integer, bitcast the operands first.
auto widthType = rewriter.getIntegerType(hw::getBitWidth(op.getType()));
auto width = hw::getBitWidth(op.getType());
assert(width && "op result must have known bitwidth");
auto widthType = rewriter.getIntegerType(*width);
trueVal =
hw::BitcastOp::create(rewriter, op->getLoc(), widthType, trueVal);
falseVal =
Expand Down
4 changes: 3 additions & 1 deletion lib/Conversion/ExportAIGER/ExportAIGER.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ using namespace circt::aiger;

/// Returns the bit width of a value.
static int64_t getBitWidth(Value value) {
return hw::getBitWidth(value.getType());
auto width = hw::getBitWidth(value.getType());
assert(width && "value must have known bitwidth");
return *width;
}

//===----------------------------------------------------------------------===//
Expand Down
30 changes: 22 additions & 8 deletions lib/Conversion/ExportVerilog/ExportVerilog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,10 @@ bool ExportVerilog::isZeroBitType(Type type) {
[](auto elem) { return isZeroBitType(elem.type); });
if (auto enumType = dyn_cast<hw::EnumType>(type))
return enumType.getFields().empty();
if (auto unionType = dyn_cast<hw::UnionType>(type))
return hw::getBitWidth(unionType) == 0;
if (auto unionType = dyn_cast<hw::UnionType>(type)) {
auto width = hw::getBitWidth(unionType);
return width && *width == 0;
}

// We have an open type system, so assume it is ok.
return false;
Expand Down Expand Up @@ -1794,15 +1796,19 @@ static bool printPackedTypeImpl(Type type, raw_ostream &os, Location loc,
return true;
}

int64_t unionWidth = hw::getBitWidth(unionType);
auto unionWidthOpt = hw::getBitWidth(unionType);
int64_t unionWidth =
unionWidthOpt ? static_cast<int64_t>(*unionWidthOpt) : -1;
os << "union packed {";
for (auto &element : unionType.getElements()) {
if (isZeroBitType(element.type)) {
os << "/*" << emitter.getVerilogStructFieldName(element.name)
<< ": Zero Width;*/ ";
continue;
}
int64_t elementWidth = hw::getBitWidth(element.type);
auto elementWidthOpt = hw::getBitWidth(element.type);
int64_t elementWidth =
elementWidthOpt ? static_cast<int64_t>(*elementWidthOpt) : -1;
bool needsPadding = elementWidth < unionWidth || element.offset > 0;
if (needsPadding) {
os << " struct packed {";
Expand Down Expand Up @@ -3434,9 +3440,13 @@ SubExprInfo ExprEmitter::visitTypeOp(UnionCreateOp op) {

// Check if this union type has been padded.
auto unionType = cast<UnionType>(getCanonicalType(op.getType()));
auto unionWidth = hw::getBitWidth(unionType);
auto unionWidthOpt = hw::getBitWidth(unionType);
assert(unionWidthOpt && "union type must have known bitwidth");
uint64_t unionWidth = *unionWidthOpt;
auto &element = unionType.getElements()[op.getFieldIndex()];
auto elementWidth = hw::getBitWidth(element.type);
auto elementWidthOpt = hw::getBitWidth(element.type);
assert(elementWidthOpt && "element type must have known bitwidth");
uint64_t elementWidth = *elementWidthOpt;

// If the element is 0 width, just fill the union with 0s.
if (!elementWidth) {
Expand Down Expand Up @@ -3477,9 +3487,13 @@ SubExprInfo ExprEmitter::visitTypeOp(UnionExtractOp op) {

// Check if this union type has been padded.
auto unionType = cast<UnionType>(getCanonicalType(op.getInput().getType()));
auto unionWidth = hw::getBitWidth(unionType);
auto unionWidthOpt = hw::getBitWidth(unionType);
assert(unionWidthOpt && "union type must have known bitwidth");
uint64_t unionWidth = *unionWidthOpt;
auto &element = unionType.getElements()[op.getFieldIndex()];
auto elementWidth = hw::getBitWidth(element.type);
auto elementWidthOpt = hw::getBitWidth(element.type);
assert(elementWidthOpt && "element type must have known bitwidth");
uint64_t elementWidth = *elementWidthOpt;
bool needsPadding = elementWidth < unionWidth || element.offset > 0;
auto verilogFieldName = emitter.getVerilogStructFieldName(element.name);

Expand Down
15 changes: 10 additions & 5 deletions lib/Conversion/HWToBTOR2/HWToBTOR2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -557,12 +557,13 @@ struct ConvertHWToBTOR2Pass
// has been generated
int64_t requireSort(mlir::Type type) {
// Start by figuring out what sort needs to be generated
int64_t width = hw::getBitWidth(type);
auto widthOpt = hw::getBitWidth(type);

// Sanity check: getBitWidth can technically return -1 it is a type with
// Sanity check: getBitWidth can return nullopt for types with
// no width (like a clock). This shouldn't be allowed as width is required
// to generate a sort
assert(width != noWidth);
assert(widthOpt && "type must have known bitwidth");
int64_t width = *widthOpt;

// Generate the sort regardles of resulting width (nothing will be added
// if the sort already exists)
Expand All @@ -578,12 +579,16 @@ struct ConvertHWToBTOR2Pass

// Extract the operands depending on the register type
if (auto reg = dyn_cast<seq::CompRegOp>(op)) {
width = hw::getBitWidth(reg.getType());
auto widthOpt = hw::getBitWidth(reg.getType());
assert(widthOpt && "register type must have known bitwidth");
width = *widthOpt;
next = reg.getInput();
reset = reg.getReset();
resetVal = reg.getResetValue();
} else if (auto reg = dyn_cast<seq::FirRegOp>(op)) {
width = hw::getBitWidth(reg.getType());
auto widthOpt = hw::getBitWidth(reg.getType());
assert(widthOpt && "register type must have known bitwidth");
width = *widthOpt;
next = reg.getNext();
reset = reg.getReset();
resetVal = reg.getResetValue();
Expand Down
45 changes: 27 additions & 18 deletions lib/Conversion/MooreToCore/MooreToCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -697,14 +697,14 @@ static Value createZeroValue(Type type, Location loc,
}

// Otherwise try to create a zero integer and bitcast it to the result type.
int64_t width = hw::getBitWidth(type);
if (width == -1)
auto width = hw::getBitWidth(type);
if (!width)
return {};

// TODO: Once the core dialects support four-valued integers, this code
// will additionally need to generate an all-X value for four-valued
// variables.
Value constZero = hw::ConstantOp::create(rewriter, loc, APInt(width, 0));
Value constZero = hw::ConstantOp::create(rewriter, loc, APInt(*width, 0));
return rewriter.createOrFold<hw::BitcastOp>(loc, type, constZero);
}

Expand Down Expand Up @@ -902,10 +902,10 @@ struct NetOpConversion : public OpConversionPattern<NetOp> {
// TODO: Once the core dialects support four-valued integers, this code
// will additionally need to generate an all-X value for four-valued nets.
auto elementType = cast<llhd::RefType>(resultType).getNestedType();
int64_t width = hw::getBitWidth(elementType);
if (width == -1)
auto width = hw::getBitWidth(elementType);
if (!width)
return failure();
auto constZero = hw::ConstantOp::create(rewriter, loc, APInt(width, 0));
auto constZero = hw::ConstantOp::create(rewriter, loc, APInt(*width, 0));
auto init =
rewriter.createOrFold<hw::BitcastOp>(loc, elementType, constZero);

Expand Down Expand Up @@ -1032,7 +1032,10 @@ struct ExtractOpConversion : public OpConversionPattern<ExtractOp> {

if (isa<IntegerType>(inputType)) {
int32_t inputWidth = inputType.getIntOrFloatBitWidth();
int32_t resultWidth = hw::getBitWidth(resultType);
auto resultWidthOpt = hw::getBitWidth(resultType);
if (!resultWidthOpt)
return failure();
int32_t resultWidth = *resultWidthOpt;
int32_t high = low + resultWidth;

SmallVector<Value> toConcat;
Expand Down Expand Up @@ -1069,9 +1072,10 @@ struct ExtractOpConversion : public OpConversionPattern<ExtractOp> {

if (auto resArrTy = dyn_cast<hw::ArrayType>(resultType);
resArrTy && resArrTy != arrTy.getElementType()) {
int32_t elementWidth = hw::getBitWidth(arrTy.getElementType());
if (elementWidth < 0)
auto elementWidthOpt = hw::getBitWidth(arrTy.getElementType());
if (!elementWidthOpt)
return failure();
int32_t elementWidth = *elementWidthOpt;

int32_t high = low + resArrTy.getNumElements();
int32_t resWidth = resArrTy.getNumElements();
Expand Down Expand Up @@ -1119,9 +1123,10 @@ struct ExtractOpConversion : public OpConversionPattern<ExtractOp> {

// Otherwise, it has to be the array's element type
if (low < 0 || low >= inputWidth) {
int32_t bw = hw::getBitWidth(resultType);
if (bw < 0)
auto bwOpt = hw::getBitWidth(resultType);
if (!bwOpt)
return failure();
int32_t bw = *bwOpt;

Value val = hw::ConstantOp::create(rewriter, op.getLoc(), APInt(bw, 0));
Value bitcast =
Expand Down Expand Up @@ -1153,9 +1158,10 @@ struct ExtractRefOpConversion : public OpConversionPattern<ExtractRefOp> {
cast<llhd::RefType>(adaptor.getInput().getType()).getNestedType();

if (auto intType = dyn_cast<IntegerType>(inputType)) {
int64_t width = hw::getBitWidth(inputType);
if (width == -1)
auto widthOpt = hw::getBitWidth(inputType);
if (!widthOpt)
return failure();
int64_t width = *widthOpt;

Value lowBit = hw::ConstantOp::create(
rewriter, op.getLoc(),
Expand Down Expand Up @@ -1242,9 +1248,10 @@ struct DynExtractRefOpConversion : public OpConversionPattern<DynExtractRefOp> {
cast<llhd::RefType>(adaptor.getInput().getType()).getNestedType();

if (auto intType = dyn_cast<IntegerType>(inputType)) {
int64_t width = hw::getBitWidth(inputType);
if (width == -1)
auto widthOpt = hw::getBitWidth(inputType);
if (!widthOpt)
return failure();
int64_t width = *widthOpt;

Value amount =
adjustIntegerWidth(rewriter, adaptor.getLowBit(),
Expand Down Expand Up @@ -1503,10 +1510,12 @@ struct ConversionOpConversion : public OpConversionPattern<ConversionOp> {
op.emitError("conversion result type is not currently supported");
return failure();
}
int64_t inputBw = hw::getBitWidth(adaptor.getInput().getType());
int64_t resultBw = hw::getBitWidth(resultType);
if (inputBw == -1 || resultBw == -1)
auto inputBwOpt = hw::getBitWidth(adaptor.getInput().getType());
auto resultBwOpt = hw::getBitWidth(resultType);
if (!inputBwOpt || !resultBwOpt)
return failure();
int64_t inputBw = *inputBwOpt;
int64_t resultBw = *resultBwOpt;

Value input = rewriter.createOrFold<hw::BitcastOp>(
loc, rewriter.getIntegerType(inputBw), adaptor.getInput());
Expand Down
4 changes: 3 additions & 1 deletion lib/Conversion/SeqToSV/FirRegLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,9 @@ void FirRegLowering::lowerReg(FirRegOp reg) {
RegLowerInfo svReg{nullptr, path, reg.getPresetAttr(), nullptr, nullptr,
-1, 0};
svReg.reg = sv::RegOp::create(builder, loc, regTy, reg.getNameAttr());
svReg.width = hw::getBitWidth(regTy);
auto width = hw::getBitWidth(regTy);
assert(width && "register type must have known bitwidth");
svReg.width = *width;

if (auto attr = reg->getAttrOfType<IntegerAttr>("firrtl.random_init_start"))
svReg.randStart = attr.getUInt();
Expand Down
8 changes: 5 additions & 3 deletions lib/Dialect/Arc/Transforms/LowerState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -611,9 +611,11 @@ LogicalResult OpLowering::lowerStateful(
// Generate the zero value writes.
for (auto state : states) {
auto type = cast<StateType>(state.getType()).getType();
Value value = ConstantOp::create(
module.builder, loweredReset.getLoc(),
module.builder.getIntegerType(hw::getBitWidth(type)), 0);
auto width = hw::getBitWidth(type);
assert(width && "state type must have known bitwidth");
Value value =
ConstantOp::create(module.builder, loweredReset.getLoc(),
module.builder.getIntegerType(*width), 0);
if (value.getType() != type)
value = BitcastOp::create(module.builder, loweredReset.getLoc(), type,
value);
Expand Down
Loading
Loading