[Moore][ImportVerilog] Implement static $cast via materializeConversion#10156
[Moore][ImportVerilog] Implement static $cast via materializeConversion#10156sunhailong2001 wants to merge 1 commit intollvm:mainfrom
Conversation
|
Hey, @fabianschuiki. 😃 If my thought is accepted, I will add more tests. |
|
Hey @sunhailong2001! I love your idea of doing casting and assignment in separate operations, that's very elegant. The dynamic casting is an interesting challenge. I see a few different groups that a
Groups 1-4 are all static casts: we know at compile time whether they succeed or not. To implement these, we could directly call
Group 5 is the truly dynamic one. When we see that a WDYT? Does it make sense to separate |
|
+1 for the idea of trying to implement dynamic casts statically at compile time! Imo this could also be left for a follow-up. With regards to class-typed cast I think this work could be orthogonalised. We would likely just have to exclude |
|
That sounds like we could do almost all casting statically with the existing |
Upcasts generally go through I agree with the suggestion. I'm sure we'll get vtables materialised one of these days 🚀 |
177d38b to
f97682a
Compare
| // 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 |
There was a problem hiding this comment.
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.)
|
Your fallible conversion changes look fantastic @sunhailong2001! 🥳 |
f97682a to
2314c67
Compare
I checked the LLVM IR for C++ |
7b8b3b0 to
c3551b1
Compare
|
|
||
| if (dyn_cast<moore::IntType>(type).getDomain() == moore::Domain::FourValued) | ||
| return materializePackedToSBVConversion(*this, twoValInt, loc); | ||
| return builder.createOrFold<moore::IntToLogicOp>(loc, twoValInt); |
There was a problem hiding this comment.
Please check function int DynCastRealToLogic(inout a) in the test, materializePackedToSBVConversion will directly return twoValInt without conversion. Therefore, there is not moore.int_to_logic when translate $cast(a, 2.3), and then it will report an error: 'moore.blocking_assign' op failed to verify that src and dst types match
There was a problem hiding this comment.
This is an interesting find! You might be able to materializeConversion here to do the domain casting and any potential simple-bit-vector unpacking automatically. Something like this:
if (dstInt && isa<moore::RealType>(value.getType())) {
auto twoValInt = builder.createOrFold<moore::RealToIntOp>(
loc, dstInt.getTwoValued(), value);
return materializeConversion(type, twoValInt, true, loc, fallible);
}This would check if the destination type is an int, or something like a packed struct or packed array that has a simple-bit-vector equivalent type. If it does, it would use RealToIntOp to convert to the two-valued simple-bit-vector, and then use materializeConversion to go from that to the actual type, which also handles int-to-logic and struct/array unpacking for you. WDYT?
This could allow for tests like these:
struct packed { shortint a; shortint b; } x;
logic [3:0][7:0] y;
$cast(x, 2.3);
$cast(y, 2.3);
fabianschuiki
left a comment
There was a problem hiding this comment.
LGTM! Thanks a lot for implementing this 🥳 Just a minor nit, but this looks excellent!
|
|
||
| if (dyn_cast<moore::IntType>(type).getDomain() == moore::Domain::FourValued) | ||
| return materializePackedToSBVConversion(*this, twoValInt, loc); | ||
| return builder.createOrFold<moore::IntToLogicOp>(loc, twoValInt); |
There was a problem hiding this comment.
This is an interesting find! You might be able to materializeConversion here to do the domain casting and any potential simple-bit-vector unpacking automatically. Something like this:
if (dstInt && isa<moore::RealType>(value.getType())) {
auto twoValInt = builder.createOrFold<moore::RealToIntOp>(
loc, dstInt.getTwoValued(), value);
return materializeConversion(type, twoValInt, true, loc, fallible);
}This would check if the destination type is an int, or something like a packed struct or packed array that has a simple-bit-vector equivalent type. If it does, it would use RealToIntOp to convert to the two-valued simple-bit-vector, and then use materializeConversion to go from that to the actual type, which also handles int-to-logic and struct/array unpacking for you. WDYT?
This could allow for tests like these:
struct packed { shortint a; shortint b; } x;
logic [3:0][7:0] y;
$cast(x, 2.3);
$cast(y, 2.3);| // CHECK: return [[MAX]] : !moore.i32 | ||
| // CHECK: } | ||
|
|
||
| function int DynCastRealToLogic(inout a); |
There was a problem hiding this comment.
Nit-picking:
| function int DynCastRealToLogic(inout a); | |
| function int DynCastRealToLogic(inout integer a); |
There was a problem hiding this comment.
Your suggestion is absolutely wonderful. 🥳
c3551b1 to
bce5921
Compare
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.
bce5921 to
3bd9061
Compare
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.