Skip to content

Commit bce5921

Browse files
[Moore][ImportVerilog] Implement static $cast via materializeConversion
Implement statically inferable $cast lowering through materializeConversion. Use fallible conversion to produce the $cast success flag: emit blocking assignment only on success, and return i1 true/false accordingly.
1 parent aa97d68 commit bce5921

File tree

3 files changed

+108
-19
lines changed

3 files changed

+108
-19
lines changed

lib/Conversion/ImportVerilog/Expressions.cpp

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2619,7 +2619,7 @@ Value Context::convertToSimpleBitVector(Value value) {
26192619
/// corresponding simple bit vector `IntType`. This will apply special handling
26202620
/// to time values, which requires scaling by the local timescale.
26212621
static Value materializePackedToSBVConversion(Context &context, Value value,
2622-
Location loc) {
2622+
Location loc, bool fallible) {
26232623
if (isa<moore::IntType>(value.getType()))
26242624
return value;
26252625

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

@@ -2657,7 +2658,8 @@ static Value materializePackedToSBVConversion(Context &context, Value value,
26572658
/// time values, which requires scaling by the local timescale.
26582659
static Value materializeSBVToPackedConversion(Context &context,
26592660
moore::PackedType packedType,
2660-
Value value, Location loc) {
2661+
Value value, Location loc,
2662+
bool fallible) {
26612663
if (value.getType() == packedType)
26622664
return value;
26632665

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

@@ -2723,7 +2726,7 @@ static mlir::Value maybeUpcastHandle(Context &context, mlir::Value actualHandle,
27232726
}
27242727

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

27382741
if (dstInt && srcInt) {
27392742
// Convert the value to a simple bit vector if it isn't one already.
2740-
value = materializePackedToSBVConversion(*this, value, loc);
2743+
value = materializePackedToSBVConversion(*this, value, loc, fallible);
27412744
if (!value)
27422745
return {};
27432746

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

27652768
// Convert the value from a simple bit vector back to the packed type.
2766-
value = materializeSBVToPackedConversion(*this, dstPacked, value, loc);
2769+
value = materializeSBVToPackedConversion(*this, dstPacked, value, loc,
2770+
fallible);
27672771
if (!value)
27682772
return {};
27692773

@@ -2804,13 +2808,10 @@ Value Context::materializeConversion(Type type, Value value, bool isSigned,
28042808
}
28052809

28062810
// Handle Real To Int conversion
2807-
if (isa<moore::IntType>(type) && isa<moore::RealType>(value.getType())) {
2811+
if (dstInt && isa<moore::RealType>(value.getType())) {
28082812
auto twoValInt = builder.createOrFold<moore::RealToIntOp>(
2809-
loc, dyn_cast<moore::IntType>(type).getTwoValued(), value);
2810-
2811-
if (dyn_cast<moore::IntType>(type).getDomain() == moore::Domain::FourValued)
2812-
return materializePackedToSBVConversion(*this, twoValInt, loc);
2813-
return twoValInt;
2813+
loc, dstInt.getTwoValued(), value);
2814+
return materializeConversion(type, twoValInt, true, loc, fallible);
28142815
}
28152816

28162817
// Handle Int to Real conversion
@@ -2903,6 +2904,8 @@ Value Context::materializeConversion(Type type, Value value, bool isSigned,
29032904
return maybeUpcastHandle(*this, value, cast<moore::ClassHandleType>(type));
29042905

29052906
// TODO: Handle other conversions with dedicated ops.
2907+
if (fallible && value.getType() != type)
2908+
return {};
29062909
if (value.getType() != type)
29072910
value = moore::ConversionOp::create(builder, loc, type, value);
29082911
return value;
@@ -3054,6 +3057,40 @@ Value Context::convertSystemCall(
30543057
return convertRealMathBI<moore::BitstoshortrealBIOp>(*this, loc, name,
30553058
args);
30563059

3060+
if (nameId == ksn::Cast) {
3061+
assert(numArgs == 2 && "`cast` takes 2 arguments");
3062+
auto *dstExpr = args[0];
3063+
auto dstType = convertType(*dstExpr->type);
3064+
if (!dstType)
3065+
return {};
3066+
3067+
if (auto *assign = dstExpr->as_if<slang::ast::AssignmentExpression>())
3068+
dstExpr = &assign->left();
3069+
auto dst = convertLvalueExpression(*dstExpr);
3070+
if (!dst)
3071+
return {};
3072+
3073+
auto src = convertRvalueExpression(*args[1]);
3074+
if (!src)
3075+
return {};
3076+
// Class-typed $cast (upcast/downcast) is intentionally left for follow-up.
3077+
if (isa<moore::ClassHandleType>(dstType) ||
3078+
isa<moore::ClassHandleType>(src.getType())) {
3079+
auto i1Ty = moore::IntType::getInt(builder.getContext(), 1);
3080+
return moore::ConstantOp::create(builder, loc, i1Ty, 0,
3081+
/*isSigned=*/false);
3082+
}
3083+
auto converted = materializeConversion(
3084+
dstType, src, args[1]->type->isSigned(), loc, /*fallible=*/true);
3085+
auto i1Ty = moore::IntType::getInt(builder.getContext(), 1);
3086+
if (!converted)
3087+
return moore::ConstantOp::create(builder, loc, i1Ty, 0,
3088+
/*isSigned=*/false);
3089+
moore::BlockingAssignOp::create(builder, loc, dst, converted);
3090+
return moore::ConstantOp::create(builder, loc, i1Ty, 1,
3091+
/*isSigned=*/false);
3092+
}
3093+
30573094
//===--------------------------------------------------------------------===//
30583095
// String Methods
30593096
//===--------------------------------------------------------------------===//

lib/Conversion/ImportVerilog/ImportVerilogInternals.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,9 +294,10 @@ struct Context {
294294
Value convertToSimpleBitVector(Value value);
295295

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

301302
/// Helper function to materialize an `SVInt` as an SSA value.
302303
Value materializeSVInt(const slang::SVInt &svint,

test/Conversion/ImportVerilog/basic.sv

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5167,3 +5167,54 @@ module DisplayWithStringArg;
51675167
initial $display(i, s);
51685168
endmodule
51695169

5170+
// CHECK-LABEL: func.func private @BuiltinCastTrue(
5171+
// CHECK-SAME: %arg0: !moore.ref<l32>
5172+
// CHECK-SAME: ) -> !moore.i32 {
5173+
// CHECK: [[X:%.+]] = moore.variable : <struct<{a: i16, b: i16}>>
5174+
// CHECK: [[Y:%.+]] = moore.variable : <array<4 x l8>>
5175+
// CHECK: [[CR1:%.+]] = moore.constant_real 2.300000e+00 : f64
5176+
// CHECK: [[REAL_TO_INT1:%.+]] = moore.real_to_int [[CR1]] : f64 -> i32
5177+
// CHECK: [[SBV_TO_PACK1:%.+]] = moore.sbv_to_packed [[REAL_TO_INT1]] : struct<{a: i16, b: i16}>
5178+
// CHECK: moore.blocking_assign [[X]], [[SBV_TO_PACK1]] : struct<{a: i16, b: i16}>
5179+
// CHECK: [[SUCC1:%.+]] = moore.constant 1 : i1
5180+
// CHECK: [[CR2:%.+]] = moore.constant_real 2.300000e+00 : f64
5181+
// CHECK: [[REAL_TO_INT2:%.+]] = moore.real_to_int [[CR2]] : f64 -> i32
5182+
// CHECK: [[INT_TO_LOGIC2:%.+]] = moore.int_to_logic [[REAL_TO_INT2]] : i32
5183+
// CHECK: [[SBV_TO_PACK2:%.+]] = moore.sbv_to_packed [[INT_TO_LOGIC2]] : array<4 x l8>
5184+
// CHECK: moore.blocking_assign [[Y]], [[SBV_TO_PACK2]] : array<4 x l8>
5185+
// CHECK: [[SUCC2:%.+]] = moore.constant 1 : i1
5186+
// CHECK: [[CR3:%.+]] = moore.constant_real 2.300000e+00 : f64
5187+
// CHECK: [[REAL_TO_INT3:%.+]] = moore.real_to_int [[CR3]] : f64 -> i32
5188+
// CHECK: [[INT_TO_LOGIC3:%.+]] = moore.int_to_logic [[REAL_TO_INT3]] : i32
5189+
// CHECK: moore.blocking_assign %arg0, [[INT_TO_LOGIC3]] : l32
5190+
// CHECK: [[SUCC3:%.+]] = moore.constant 1 : i1
5191+
// CHECK: [[MAX:%.+]] = moore.constant -1 : i32
5192+
// CHECK: return [[MAX]] : !moore.i32
5193+
// CHECK: }
5194+
5195+
function int BuiltinCastTrue(inout integer a);
5196+
struct packed { shortint a; shortint b; } x;
5197+
logic [3:0][7:0] y;
5198+
5199+
$cast(x, 2.3);
5200+
$cast(y, 2.3);
5201+
return $cast(a, 2.3);
5202+
endfunction
5203+
5204+
// CHECK-LABEL: moore.coroutine private @BuiltinCastFalse() {
5205+
// CHECK: [[S:%.+]] = moore.variable : <string>
5206+
// CHECK: [[Q:%.+]] = moore.variable : <queue<l1, 0>>
5207+
// CHECK: [[CR1:%.+]] = moore.constant_real 2.300000e+00 : f64
5208+
// CHECK: [[FAIL1:%.+]] = moore.constant 0 : i1
5209+
// CHECK: [[CR2:%.+]] = moore.constant_real 2.300000e+00 : f64
5210+
// CHECK: [[FAIL2:%.+]] = moore.constant 0 : i1
5211+
// CHECK: moore.return
5212+
// CHECK: }
5213+
5214+
task BuiltinCastFalse;
5215+
string s;
5216+
logic q [$];
5217+
5218+
$cast(s, 2.3);
5219+
$cast(q, 2.3);
5220+
endtask

0 commit comments

Comments
 (0)