Removal of the moore.conversion op in #11024 has uncovered a few places where we try to cast an lvalue to a different type. This doesn't work, since lvalues are ref<T> pointing to a variable or some other memory-like thing, and we can't simply cast that pointer to a ref<U>. This has come up with output, inout, and ref subroutine arguments, and inout module port connections. Instead of trying to cast the lvalue, we need to pass in a temporary of the correct ref<U> value, and then upon write-back cast the U to V and do the actual write to ref<T>. Modules already do this to some degree when dealing with output ports.
module implicitCastsFunctionArguments;
real r, q;
function void fn(output logic [3:0] o, input logic [3:0] val);
o = val;
endfunction
initial fn(q, r);
endmodule
error: unsupported conversion from '!moore.ref<f64>' to '!moore.ref<l4>'
The same shape shows up for module inout ports whose connecting net has a different width than the port (see the virtual-interface-modport.sv XFAIL test for a related but distinct case: modport port renaming, not a width/domain mismatch).
Context::materializeConversion is fundamentally an rvalue-conversion helper; given two ref types it has nothing better to do than reinterpret the pointee in place, which is wrong. A real fix needs to read through the actual's ref, convert the value, and write it back through a temporary (or similar) rather than converting the ref type itself — this is a different code path from ordinary value conversion. The two call sites are the output/inout/ref argument handling in lib/Conversion/ImportVerilog/Expressions.cpp and the module instance port connection handling in lib/Conversion/ImportVerilog/Structure.cpp.
Removal of the
moore.conversionop in #11024 has uncovered a few places where we try to cast an lvalue to a different type. This doesn't work, since lvalues areref<T>pointing to a variable or some other memory-like thing, and we can't simply cast that pointer to aref<U>. This has come up withoutput,inout, andrefsubroutine arguments, andinoutmodule port connections. Instead of trying to cast the lvalue, we need to pass in a temporary of the correctref<U>value, and then upon write-back cast theUtoVand do the actual write toref<T>. Modules already do this to some degree when dealing with output ports.The same shape shows up for module inout ports whose connecting net has a different width than the port (see the
virtual-interface-modport.svXFAIL test for a related but distinct case: modport port renaming, not a width/domain mismatch).Context::materializeConversionis fundamentally an rvalue-conversion helper; given two ref types it has nothing better to do than reinterpret the pointee in place, which is wrong. A real fix needs to read through the actual's ref, convert the value, and write it back through a temporary (or similar) rather than converting the ref type itself — this is a different code path from ordinary value conversion. The two call sites are the output/inout/ref argument handling inlib/Conversion/ImportVerilog/Expressions.cppand the module instance port connection handling inlib/Conversion/ImportVerilog/Structure.cpp.