When the value of lshr's shift operand is unknown (e.g., the operand is passed through a function parameter), the cmp instruction used to determine the validity of the shift operand cannot be eliminated. Otherwise, undefined behavior may occur.
Details
Diff Detail
Event Timeline
Sorry, but i can not parse the description,
The current transformation is *not* a miscompile:
https://godbolt.org/z/WeTeasK53
https://alive2.llvm.org/ce/z/LVDqSX
@lebedev.ri I think the problem is when %0 is negative, the original code gives a definite result while the transformed IR is UB.
I'm sorry I didn't make my point clear. The purpose of my current modification is to circumvent a false optimization. In, the case, %0 may be negative. If we eliminate %cmp = icmp slt i32 %0, 0, undefined behavior may occur, as lshr performed a negative shift. @lebedev.ri
original version
%cmp = icmp slt i32 %0, 0 %shr = lshr i32 7, %0 %cmp1 = icmp sgt i32 %0, %shr %or.cond = or i1 %cmp, %cmp1 br i1 %or.cond, label %cond.end, label %cond.false
miscompile
%shr = lshr i32 7, %0 %1 = icmp ult i32 %shr, %0 br i1 %1, label %cond.end, label %cond.false
If an input to an or instruction is poison, the output of the or is poison regardless of whether the other operand is true when the poison result occurs.
If an incorrect optimization is occurring it must be where the or is created.
Thanks for your review! @craig.topper. Do you mean that we should prevent this pattern from being generated, rather than remedying it after the pattern is generated? Actually, the issue I met started from D95959. That optimization does not seem to apply to all scenarios, such as those where the shift operand is negative. In the case I present, this optimization results in a miscalculation of the KnownBit, which in turn results in a false transformation.
The transform is correct based on the semantics of llvm's or instruction. The or instruction in llvm does not have short circuit evaluation. It can't block the spread of poison. The IR that has the semantics you want is
define i32 @cmp_lshr_cmp(i32 %0) { entry: %cmp = icmp slt i32 %0, 0 %shr = lshr i32 7, %0 %cmp1 = icmp sgt i32 %0, %shr %or.cond = select i1 %cmp, i1 true, i1 %cmp1 br i1 %or.cond, label %cond.end, label %cond.false cond.false: ; preds = %entry ret i32 1 cond.end: ; preds = %entry, %cond.false ret i32 0 }
Using a select instruction instead of an or prevents the %cmp1 value from being used if %cmp is true. There was previously an incorrect transform that would turn such a select into an or, but it was disabled in https://reviews.llvm.org/D101191
OK, I get it. I'll try to find out why the or is still generated. Thanks very much @craig.topper