Skip to content

Commit 41e68f7

Browse files
committed
[EarlyCSE] Fix and recommit the revised c982682
In addition to calculate hash consistently by swapping SELECT's operands, we also need to inverse the select pattern favor to match the original logic. [EarlyCSE] Equivalent SELECTs should hash equally DenseMap<SimpleValue> assumes that, if its isEqual method returns true for two elements, then its getHashValue method must return the same value for them. This invariant is broken when one SELECT node is a min/max operation, and the other can be transformed into an equivalent min/max by inverting its predicate and swapping its operands. This patch fixes an assertion failure that would occur intermittently while compiling the following IR: define i32 @t(i32 %i) { %cmp = icmp sle i32 0, %i %twin1 = select i1 %cmp, i32 %i, i32 0 %cmpinv = icmp sgt i32 0, %i %twin2 = select i1 %cmpinv, i32 0, i32 %i %sink = add i32 %twin1, %twin2 ret i32 %sink } Differential Revision: https://reviews.llvm.org/D86843
1 parent 3f7c3e8 commit 41e68f7

File tree

2 files changed

+39
-4
lines changed

2 files changed

+39
-4
lines changed

llvm/lib/Transforms/Scalar/EarlyCSE.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,26 @@ static bool matchSelectWithOptionalNotCond(Value *V, Value *&Cond, Value *&A,
191191
Pred = ICmpInst::getSwappedPredicate(Pred);
192192
}
193193

194+
// Check for inverted variants of min/max by swapping operands.
195+
bool Inversed = false;
194196
switch (Pred) {
195-
case CmpInst::ICMP_UGT: Flavor = SPF_UMAX; break;
196-
case CmpInst::ICMP_ULT: Flavor = SPF_UMIN; break;
197-
case CmpInst::ICMP_SGT: Flavor = SPF_SMAX; break;
198-
case CmpInst::ICMP_SLT: Flavor = SPF_SMIN; break;
197+
case CmpInst::ICMP_ULE:
198+
case CmpInst::ICMP_UGE:
199+
case CmpInst::ICMP_SLE:
200+
case CmpInst::ICMP_SGE:
201+
Pred = CmpInst::getInversePredicate(Pred);
202+
std::swap(A, B);
203+
Inversed = true;
204+
break;
205+
default:
206+
break;
207+
}
208+
209+
switch (Pred) {
210+
case CmpInst::ICMP_UGT: Flavor = Inversed ? SPF_UMIN : SPF_UMAX; break;
211+
case CmpInst::ICMP_ULT: Flavor = Inversed ? SPF_UMAX : SPF_UMIN; break;
212+
case CmpInst::ICMP_SGT: Flavor = Inversed ? SPF_SMIN : SPF_SMAX; break;
213+
case CmpInst::ICMP_SLT: Flavor = Inversed ? SPF_SMAX : SPF_SMIN; break;
199214
default: break;
200215
}
201216

llvm/test/Transforms/EarlyCSE/commute.ll

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,26 @@ define i32 @select_not_invert_pred_cond_wrong_select_op(i8 %x, i8 %y, i32 %t, i3
684684
ret i32 %r
685685
}
686686

687+
; This test is a reproducer for a bug involving inverted min/max selects
688+
; hashing differently but comparing as equal. It exhibits such a pair of
689+
; values, and we run this test with -earlycse-debug-hash which would catch
690+
; the disagreement and fail if it regressed.
691+
; EarlyCSE should be able to detect the 2nd redundant `select` and eliminate
692+
; it.
693+
define i32 @inverted_max(i32 %i) {
694+
; CHECK-LABEL: @inverted_max(
695+
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 0, [[I:%.*]]
696+
; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP]], i32 [[I]], i32 0
697+
; CHECK-NEXT: [[CMPINV:%.*]] = icmp sgt i32 0, [[I:%.*]]
698+
; CHECK-NEXT: [[R:%.*]] = add i32 [[M1]], [[M1]]
699+
; CHECK-NEXT: ret i32 [[R]]
700+
%cmp = icmp sle i32 0, %i
701+
%m1 = select i1 %cmp, i32 %i, i32 0
702+
%cmpinv = icmp sgt i32 0, %i
703+
%m2 = select i1 %cmpinv, i32 0, i32 %i
704+
%r = add i32 %m1, %m2
705+
ret i32 %r
706+
}
687707

688708
; This test is a reproducer for a bug involving inverted min/max selects
689709
; hashing differently but comparing as equal. It exhibits such a pair of

0 commit comments

Comments
 (0)