Internal error: Inline flag remains in instruction
The following gives an internal error
export
fn main(reg u64 x) -> reg u64 {
reg u64 z;
z = 0;
inline bool b;
b = x > 0;
while (b) {
x = z if x > 0;
}
x = x;
return x;
}
which probably should be a user error indicating that b is invalid after the body. Same happens with two conditionals instead of a loop.
Edit: this is the example with two conditionals
export
fn main(reg u64 x) -> reg u64 {
reg u64 z;
z = 0;
inline bool b;
b = x > 0;
if (b) {
x = z if x > 0;
}
if (b) {
x = 1;
}
x = x;
return x;
}
Please give the example without loop. This would be helpful.
It doesn't happen if we kill the flags with an intrinsic, e.g. #CMP. The difference is that it's propagate inline that inserts the CMPs in the examples.
What kind of error message do you want ? My point, is that it may be tricky to explain, dectecting the problem implies a chain of compilation. I think for example, that if you replace the x = z if x > 0; by x = z if b which is equivalent, then you have no error.
What is strange to me is that when we use #CMP register allocation generates a good error message, but when propagate inline introduces it it then register allocation can't see that there's a problem. I agree that this should be an error, and perhaps the solution is to make this a user error instead of an internal one.
Can you provide the code with #CMP, to be able to understand ?
Sorry, maybe these are clearer: This is good
export
fn main(reg u64 x) -> reg u64 {
reg u64 z;
z = 0;
inline bool b;
b = x == 0; // b = ZF
?{} = #CMP(x, 1); // kills b
x = z if b;
x = x;
return x;
}
because it prints line 9 (4-21): compilation error: register allocation: variable _zf_.214 must be allocated to conflicting register ZF { __zf__.209 }
but the error from this
export
fn main(reg u64 x) -> reg u64 {
reg u64 z;
z = 0;
inline bool b;
b = x == 0; // b = ZF
x = z if x == 1; // kills b, since we introduce CMP
x = z if b;
x = x;
return x;
}
is internal, and it would be nice if it were the one above.
Thank, I think I understood the problem, in the second version the lowering introduce 2 CMP instructions. The first for x == 0 the second for x == 1.
export
fn main (reg u64 x.163) -> (reg u64) {
reg u64 z.172;
inline bool b.173;
reg u64 x.174;
reg u64 x.175;
reg u64 x.176;
reg bool __zf__.177;
reg bool __sf__.178;
reg bool __cf__.179;
reg bool __of__.180;
z.172 = #MOV_64(((64u) 0)); /* */
(__of__.180, __cf__.179, __sf__.178, _ /* bool */, __zf__.177) =
#CMP_64(x.163, ((64u) 0)); /* */
b.173 = __zf__.177; /* bool:i */
(__of__.180, __cf__.179, __sf__.178, _ /* bool */, __zf__.177) =
#CMP_64(x.163, ((64u) 1)); /* */
x.174 = #CMOVcc_64(__zf__.177, z.172, x.163); /* */
x.175 = #CMOVcc_64(b.173, z.172, x.174); /* */
x.176 = #MOV_64(x.175); /* */
return (x.176);
}
The problem is that both instructions use the same variable names for the flags. So the propagate inline is not able to propagate the "value" (zf.177 is modified by the second CMP). In the first version the first and the second CMP use a different variable for flag, so the problem is detected during reg alloc that should merge the variable. A solution can be to use different variable name each time we introduce a CMP in lowering but this will make the code more complex. Another can be to check is some inline variable remains after propagate inline, and then to fail (but how can we provide a good error message).