Skip to content
Draft
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
20 changes: 20 additions & 0 deletions include/circt/Dialect/Moore/MooreTypes.td
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,26 @@ def AnyUnionType : MooreType<
"packed or unpacked union type",
"moore::UnpackedType">;

/// An aggregate type (any struct/union/queue/array form).
def AggregateType : MooreType<
Or<[
AnyStructType.predicate,
AnyUnionType.predicate,
AnyStaticArrayType.predicate,
OpenArrayType.predicate,
OpenUnpackedArrayType.predicate,
AssocArrayType.predicate,
QueueType.predicate
]>,
"aggregate type",
"mlir::Type">;

/// A non-aggregate (singular) type.
def SingularType : MooreType<
Neg<AggregateType.predicate>,
"singular type",
"mlir::Type">;

/// A nullable handle or NullType type
def NullableType : MooreType<
Or<[ChandleType.predicate, ClassHandleType.predicate, NullType.predicate]>,
Expand Down
64 changes: 52 additions & 12 deletions lib/Conversion/ImportVerilog/Expressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2619,7 +2619,7 @@ Value Context::convertToSimpleBitVector(Value value) {
/// corresponding simple bit vector `IntType`. This will apply special handling
/// to time values, which requires scaling by the local timescale.
static Value materializePackedToSBVConversion(Context &context, Value value,
Location loc) {
Location loc, bool fallible) {
if (isa<moore::IntType>(value.getType()))
return value;

Expand All @@ -2642,9 +2642,10 @@ static Value materializePackedToSBVConversion(Context &context, Value value,
// `TimeType` fields. These require special conversion to ensure that the
// local timescale is in effect.
if (packedType.containsTimeType()) {
mlir::emitError(loc) << "unsupported conversion: " << packedType
<< " cannot be converted to " << intType
<< "; contains a time type";
if (!fallible)
mlir::emitError(loc) << "unsupported conversion: " << packedType
<< " cannot be converted to " << intType
<< "; contains a time type";
return {};
}

Expand All @@ -2657,7 +2658,8 @@ static Value materializePackedToSBVConversion(Context &context, Value value,
/// time values, which requires scaling by the local timescale.
static Value materializeSBVToPackedConversion(Context &context,
moore::PackedType packedType,
Value value, Location loc) {
Value value, Location loc,
bool fallible) {
if (value.getType() == packedType)
return value;

Expand All @@ -2679,9 +2681,10 @@ static Value materializeSBVToPackedConversion(Context &context,
// `TimeType` fields. These require special conversion to ensure that the
// local timescale is in effect.
if (packedType.containsTimeType()) {
mlir::emitError(loc) << "unsupported conversion: " << intType
<< " cannot be converted to " << packedType
<< "; contains a time type";
if (!fallible)
mlir::emitError(loc) << "unsupported conversion: " << intType
<< " cannot be converted to " << packedType
<< "; contains a time type";
return {};
}

Expand Down Expand Up @@ -2723,7 +2726,7 @@ static mlir::Value maybeUpcastHandle(Context &context, mlir::Value actualHandle,
}

Value Context::materializeConversion(Type type, Value value, bool isSigned,
Location loc) {
Location loc, bool fallible) {
// Nothing to do if the types are already equal.
if (type == value.getType())
return value;
Expand All @@ -2737,7 +2740,7 @@ Value Context::materializeConversion(Type type, Value value, bool isSigned,

if (dstInt && srcInt) {
// Convert the value to a simple bit vector if it isn't one already.
value = materializePackedToSBVConversion(*this, value, loc);
value = materializePackedToSBVConversion(*this, value, loc, fallible);
if (!value)
return {};

Expand All @@ -2763,7 +2766,8 @@ Value Context::materializeConversion(Type type, Value value, bool isSigned,
}

// Convert the value from a simple bit vector back to the packed type.
value = materializeSBVToPackedConversion(*this, dstPacked, value, loc);
value = materializeSBVToPackedConversion(*this, dstPacked, value, loc,
fallible);
if (!value)
return {};

Expand Down Expand Up @@ -2809,7 +2813,7 @@ Value Context::materializeConversion(Type type, Value value, bool isSigned,
loc, dyn_cast<moore::IntType>(type).getTwoValued(), value);

if (dyn_cast<moore::IntType>(type).getDomain() == moore::Domain::FourValued)
return materializePackedToSBVConversion(*this, twoValInt, loc);
return materializePackedToSBVConversion(*this, twoValInt, loc, fallible);
return twoValInt;
}

Expand Down Expand Up @@ -2903,6 +2907,8 @@ Value Context::materializeConversion(Type type, Value value, bool isSigned,
return maybeUpcastHandle(*this, value, cast<moore::ClassHandleType>(type));

// TODO: Handle other conversions with dedicated ops.
if (fallible && value.getType() != type)
return {};
if (value.getType() != type)
value = moore::ConversionOp::create(builder, loc, type, value);
return value;
Expand Down Expand Up @@ -3054,6 +3060,40 @@ Value Context::convertSystemCall(
return convertRealMathBI<moore::BitstoshortrealBIOp>(*this, loc, name,
args);

if (nameId == ksn::Cast) {
assert(numArgs == 2 && "`cast` takes 2 arguments");
auto *dstExpr = args[0];
auto dstType = convertType(*dstExpr->type);
if (!dstType)
return {};

if (auto *assign = dstExpr->as_if<slang::ast::AssignmentExpression>())
dstExpr = &assign->left();
auto dst = convertLvalueExpression(*dstExpr);
if (!dst)
return {};

auto src = convertRvalueExpression(*args[1]);
if (!src)
return {};
// Class-typed $cast (upcast/downcast) is intentionally left for follow-up.
if (isa<moore::ClassHandleType>(dstType) ||
isa<moore::ClassHandleType>(src.getType())) {
auto i1Ty = moore::IntType::getInt(builder.getContext(), 1);
return moore::ConstantOp::create(builder, loc, i1Ty, 0,
/*isSigned=*/false);
}
auto converted = materializeConversion(
dstType, src, args[1]->type->isSigned(), loc, /*fallible=*/true);
auto i1Ty = moore::IntType::getInt(builder.getContext(), 1);
if (!converted)
return moore::ConstantOp::create(builder, loc, i1Ty, 0,
/*isSigned=*/false);
moore::BlockingAssignOp::create(builder, loc, dst, converted);
return moore::ConstantOp::create(builder, loc, i1Ty, 1,
/*isSigned=*/false);
}

//===--------------------------------------------------------------------===//
// String Methods
//===--------------------------------------------------------------------===//
Expand Down
5 changes: 3 additions & 2 deletions lib/Conversion/ImportVerilog/ImportVerilogInternals.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,9 +294,10 @@ struct Context {
Value convertToSimpleBitVector(Value value);

/// Helper function to insert the necessary operations to cast a value from
/// one type to another.
/// one type to another. If `fallible` is true, conversion failures are
/// reported by returning a null value without emitting diagnostics.
Value materializeConversion(Type type, Value value, bool isSigned,
Location loc);
Location loc, bool fallible = false);

/// Helper function to materialize an `SVInt` as an SSA value.
Value materializeSVInt(const slang::SVInt &svint,
Expand Down
28 changes: 28 additions & 0 deletions test/Conversion/ImportVerilog/basic.sv
Original file line number Diff line number Diff line change
Expand Up @@ -5167,3 +5167,31 @@ module DisplayWithStringArg;
initial $display(i, s);
endmodule

// CHECK-LABEL: func.func private @DynCastRealToInt(
// CHECK-SAME: %arg0: !moore.i32
// CHECK-SAME: ) -> !moore.i32 {
// CHECK: [[A:%.+]] = moore.variable %arg0 : <i32>
// CHECK: [[V1:%.+]] = moore.variable : <i32>
// CHECK: [[CR:%.+]] = moore.constant_real 2.300000e+00 : f64
// CHECK: [[REAL_TO_INT:%.+]] = moore.real_to_int [[CR]] : f64 -> i32
// CHECK: moore.blocking_assign [[A]], [[REAL_TO_INT]] : i32
// CHECK: [[SUCC:%.+]] = moore.constant 1 : i1
// CHECK: [[READ:%.+]] = moore.read [[V1]] : <i32>
// CHECK: return [[READ]] : !moore.i32
// CHECK: }

function int DynCastRealToInt(int a);
$cast(a, 2.3);
endfunction

// CHECK-LABEL: moore.coroutine private @DynCastRealToString() {
// CHECK: [[S:%.+]] = moore.variable : <string>
// CHECK: [[CR:%.+]] = moore.constant_real 2.300000e+00 : f64
// CHECK: [[FAIL:%.+]] = moore.constant 0 : i1
// CHECK: moore.return
// CHECK: }

task DynCastRealToString;
string s;
$cast(s, 2.3);
endtask
Comment on lines +5170 to +5197
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Really cool! 🥳 You could try to use inout a and return $cast(...); to make the pass/fail of the cast show up in the return IR op, and to treat a as a reference that can be directly assigned to (that might remove a few helper variables in the IR and make it easier to write CHECK lines.)

Loading