Skip to content

Commit 7320213

Browse files
emgullufsenrotateright
authored andcommitted
[InstCombine] Optimize test for same-sign of values
(icmp slt (X & Y), 0) | (icmp sgt (X | Y), -1) -> (icmp sgt (X ^ Y), -1) (icmp slt (X | Y), 0) & (icmp sgt (X & Y), -1) -> (icmp slt (X ^ Y), 0) [[ https://alive2.llvm.org/ce/z/qXxEFP | alive2 example ]] [[ https://godbolt.org/z/aWf9c6j74 | godbolt ]] [[ https://godbolt.org/z/5Ydn5TehY | godbolt for inverted form ]] [[ https://alive2.llvm.org/ce/z/93AODr | alive2 for inverted form ]] [[ llvm#55988 | issue llvm#55988 ]] Differential Revision: https://reviews.llvm.org/D127903
1 parent 6dd17a2 commit 7320213

File tree

2 files changed

+79
-85
lines changed

2 files changed

+79
-85
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2647,6 +2647,39 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
26472647
}
26482648
}
26492649

2650+
// Match naive pattern (and its inverted form) for checking if two values
2651+
// share same sign. An example of the pattern:
2652+
// (icmp slt (X & Y), 0) | (icmp sgt (X | Y), -1) -> (icmp sgt (X ^ Y), -1)
2653+
// Inverted form (example):
2654+
// (icmp slt (X | Y), 0) & (icmp sgt (X & Y), -1) -> (icmp slt (X ^ Y), 0)
2655+
bool TrueIfSignedL, TrueIfSignedR;
2656+
if (InstCombiner::isSignBitCheck(PredL, *LHSC, TrueIfSignedL) &&
2657+
InstCombiner::isSignBitCheck(PredR, *RHSC, TrueIfSignedR) &&
2658+
(RHS->hasOneUse() || LHS->hasOneUse())) {
2659+
Value *X, *Y;
2660+
if (IsAnd) {
2661+
if ((TrueIfSignedL && !TrueIfSignedR &&
2662+
match(LHS0, m_Or(m_Value(X), m_Value(Y))) &&
2663+
match(RHS0, m_c_And(m_Specific(X), m_Specific(Y)))) ||
2664+
(!TrueIfSignedL && TrueIfSignedR &&
2665+
match(LHS0, m_And(m_Value(X), m_Value(Y))) &&
2666+
match(RHS0, m_c_Or(m_Specific(X), m_Specific(Y))))) {
2667+
Value *NewXor = Builder.CreateXor(X, Y);
2668+
return Builder.CreateIsNeg(NewXor);
2669+
}
2670+
} else {
2671+
if ((TrueIfSignedL && !TrueIfSignedR &&
2672+
match(LHS0, m_And(m_Value(X), m_Value(Y))) &&
2673+
match(RHS0, m_c_Or(m_Specific(X), m_Specific(Y)))) ||
2674+
(!TrueIfSignedL && TrueIfSignedR &&
2675+
match(LHS0, m_Or(m_Value(X), m_Value(Y))) &&
2676+
match(RHS0, m_c_And(m_Specific(X), m_Specific(Y))))) {
2677+
Value *NewXor = Builder.CreateXor(X, Y);
2678+
return Builder.CreateIsNotNeg(NewXor);
2679+
}
2680+
}
2681+
}
2682+
26502683
return foldAndOrOfICmpsUsingRanges(LHS, RHS, IsAnd);
26512684
}
26522685

llvm/test/Transforms/InstCombine/and-or-icmps.ll

Lines changed: 46 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -2102,12 +2102,9 @@ define i1 @bitwise_and_logical_and_masked_icmp_allones_poison2(i1 %c, i32 %x, i3
21022102

21032103
define i1 @samesign(i32 %x, i32 %y) {
21042104
; CHECK-LABEL: @samesign(
2105-
; CHECK-NEXT: [[A:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
2106-
; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[A]], 0
2107-
; CHECK-NEXT: [[O:%.*]] = or i32 [[X]], [[Y]]
2108-
; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[O]], -1
2109-
; CHECK-NEXT: [[R:%.*]] = or i1 [[LT]], [[GT]]
2110-
; CHECK-NEXT: ret i1 [[R]]
2105+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
2106+
; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[TMP1]], -1
2107+
; CHECK-NEXT: ret i1 [[TMP2]]
21112108
;
21122109
%a = and i32 %x, %y
21132110
%lt = icmp slt i32 %a, 0
@@ -2119,12 +2116,9 @@ define i1 @samesign(i32 %x, i32 %y) {
21192116

21202117
define <2 x i1> @samesign_different_sign_bittest1(<2 x i32> %x, <2 x i32> %y) {
21212118
; CHECK-LABEL: @samesign_different_sign_bittest1(
2122-
; CHECK-NEXT: [[A:%.*]] = and <2 x i32> [[X:%.*]], [[Y:%.*]]
2123-
; CHECK-NEXT: [[LT:%.*]] = icmp slt <2 x i32> [[A]], zeroinitializer
2124-
; CHECK-NEXT: [[O:%.*]] = or <2 x i32> [[X]], [[Y]]
2125-
; CHECK-NEXT: [[GT:%.*]] = icmp sgt <2 x i32> [[O]], <i32 -1, i32 -1>
2126-
; CHECK-NEXT: [[R:%.*]] = or <2 x i1> [[LT]], [[GT]]
2127-
; CHECK-NEXT: ret <2 x i1> [[R]]
2119+
; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i32> [[X:%.*]], [[Y:%.*]]
2120+
; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt <2 x i32> [[TMP1]], <i32 -1, i32 -1>
2121+
; CHECK-NEXT: ret <2 x i1> [[TMP2]]
21282122
;
21292123
%a = and <2 x i32> %x, %y
21302124
%lt = icmp sle <2 x i32> %a, <i32 -1, i32 -1>
@@ -2136,12 +2130,9 @@ define <2 x i1> @samesign_different_sign_bittest1(<2 x i32> %x, <2 x i32> %y) {
21362130

21372131
define i1 @samesign_different_sign_bittest2(i32 %x, i32 %y) {
21382132
; CHECK-LABEL: @samesign_different_sign_bittest2(
2139-
; CHECK-NEXT: [[A:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
2140-
; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[A]], 0
2141-
; CHECK-NEXT: [[O:%.*]] = or i32 [[X]], [[Y]]
2142-
; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[O]], -1
2143-
; CHECK-NEXT: [[R:%.*]] = or i1 [[LT]], [[GT]]
2144-
; CHECK-NEXT: ret i1 [[R]]
2133+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
2134+
; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[TMP1]], -1
2135+
; CHECK-NEXT: ret i1 [[TMP2]]
21452136
;
21462137
%a = and i32 %x, %y
21472138
%lt = icmp slt i32 %a, 0
@@ -2153,12 +2144,9 @@ define i1 @samesign_different_sign_bittest2(i32 %x, i32 %y) {
21532144

21542145
define i1 @samesign_commute1(i32 %x, i32 %y) {
21552146
; CHECK-LABEL: @samesign_commute1(
2156-
; CHECK-NEXT: [[A:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
2157-
; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[A]], 0
2158-
; CHECK-NEXT: [[O:%.*]] = or i32 [[X]], [[Y]]
2159-
; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[O]], -1
2160-
; CHECK-NEXT: [[R:%.*]] = or i1 [[GT]], [[LT]]
2161-
; CHECK-NEXT: ret i1 [[R]]
2147+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
2148+
; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[TMP1]], -1
2149+
; CHECK-NEXT: ret i1 [[TMP2]]
21622150
;
21632151
%a = and i32 %x, %y
21642152
%lt = icmp slt i32 %a, 0
@@ -2170,12 +2158,9 @@ define i1 @samesign_commute1(i32 %x, i32 %y) {
21702158

21712159
define i1 @samesign_commute2(i32 %x, i32 %y) {
21722160
; CHECK-LABEL: @samesign_commute2(
2173-
; CHECK-NEXT: [[A:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
2174-
; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[A]], 0
2175-
; CHECK-NEXT: [[O:%.*]] = or i32 [[Y]], [[X]]
2176-
; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[O]], -1
2177-
; CHECK-NEXT: [[R:%.*]] = or i1 [[LT]], [[GT]]
2178-
; CHECK-NEXT: ret i1 [[R]]
2161+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
2162+
; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[TMP1]], -1
2163+
; CHECK-NEXT: ret i1 [[TMP2]]
21792164
;
21802165
%a = and i32 %x, %y
21812166
%lt = icmp slt i32 %a, 0
@@ -2187,12 +2172,9 @@ define i1 @samesign_commute2(i32 %x, i32 %y) {
21872172

21882173
define i1 @samesign_commute3(i32 %x, i32 %y) {
21892174
; CHECK-LABEL: @samesign_commute3(
2190-
; CHECK-NEXT: [[A:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
2191-
; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[A]], 0
2192-
; CHECK-NEXT: [[O:%.*]] = or i32 [[Y]], [[X]]
2193-
; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[O]], -1
2194-
; CHECK-NEXT: [[R:%.*]] = or i1 [[GT]], [[LT]]
2195-
; CHECK-NEXT: ret i1 [[R]]
2175+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
2176+
; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[TMP1]], -1
2177+
; CHECK-NEXT: ret i1 [[TMP2]]
21962178
;
21972179
%a = and i32 %x, %y
21982180
%lt = icmp slt i32 %a, 0
@@ -2240,12 +2222,11 @@ define i1 @samesign_mult_use(i32 %x, i32 %y) {
22402222
; CHECK-LABEL: @samesign_mult_use(
22412223
; CHECK-NEXT: [[A:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
22422224
; CHECK-NEXT: call void @use32(i32 [[A]])
2243-
; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[A]], 0
22442225
; CHECK-NEXT: [[O:%.*]] = or i32 [[X]], [[Y]]
22452226
; CHECK-NEXT: call void @use32(i32 [[O]])
2246-
; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[O]], -1
2247-
; CHECK-NEXT: [[R:%.*]] = or i1 [[LT]], [[GT]]
2248-
; CHECK-NEXT: ret i1 [[R]]
2227+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X]], [[Y]]
2228+
; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[TMP1]], -1
2229+
; CHECK-NEXT: ret i1 [[TMP2]]
22492230
;
22502231
%a = and i32 %x, %y
22512232
call void @use32(i32 %a)
@@ -2259,13 +2240,12 @@ define i1 @samesign_mult_use(i32 %x, i32 %y) {
22592240

22602241
define i1 @samesign_mult_use2(i32 %x, i32 %y) {
22612242
; CHECK-LABEL: @samesign_mult_use2(
2262-
; CHECK-NEXT: [[A:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
2263-
; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[A]], 0
2264-
; CHECK-NEXT: [[O:%.*]] = or i32 [[X]], [[Y]]
2243+
; CHECK-NEXT: [[O:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
22652244
; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[O]], -1
22662245
; CHECK-NEXT: call void @use(i1 [[GT]])
2267-
; CHECK-NEXT: [[R:%.*]] = or i1 [[LT]], [[GT]]
2268-
; CHECK-NEXT: ret i1 [[R]]
2246+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X]], [[Y]]
2247+
; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[TMP1]], -1
2248+
; CHECK-NEXT: ret i1 [[TMP2]]
22692249
;
22702250
%a = and i32 %x, %y
22712251
%lt = icmp slt i32 %a, 0
@@ -2316,12 +2296,9 @@ define i1 @samesign_wrong_cmp(i32 %x, i32 %y) {
23162296

23172297
define i1 @samesign_inverted(i32 %x, i32 %y) {
23182298
; CHECK-LABEL: @samesign_inverted(
2319-
; CHECK-NEXT: [[A:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
2320-
; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[A]], -1
2321-
; CHECK-NEXT: [[O:%.*]] = or i32 [[X]], [[Y]]
2322-
; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[O]], 0
2323-
; CHECK-NEXT: [[R:%.*]] = and i1 [[GT]], [[LT]]
2324-
; CHECK-NEXT: ret i1 [[R]]
2299+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
2300+
; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 0
2301+
; CHECK-NEXT: ret i1 [[TMP2]]
23252302
;
23262303
%a = and i32 %x, %y
23272304
%gt = icmp sgt i32 %a, -1
@@ -2333,12 +2310,9 @@ define i1 @samesign_inverted(i32 %x, i32 %y) {
23332310

23342311
define i1 @samesign_inverted_different_sign_bittest1(i32 %x, i32 %y) {
23352312
; CHECK-LABEL: @samesign_inverted_different_sign_bittest1(
2336-
; CHECK-NEXT: [[A:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
2337-
; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[A]], -1
2338-
; CHECK-NEXT: [[O:%.*]] = or i32 [[X]], [[Y]]
2339-
; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[O]], 0
2340-
; CHECK-NEXT: [[R:%.*]] = and i1 [[GT]], [[LT]]
2341-
; CHECK-NEXT: ret i1 [[R]]
2313+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
2314+
; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 0
2315+
; CHECK-NEXT: ret i1 [[TMP2]]
23422316
;
23432317
%a = and i32 %x, %y
23442318
%gt = icmp sge i32 %a, 0
@@ -2350,12 +2324,9 @@ define i1 @samesign_inverted_different_sign_bittest1(i32 %x, i32 %y) {
23502324

23512325
define i1 @samesign_inverted_different_sign_bittest2(i32 %x, i32 %y) {
23522326
; CHECK-LABEL: @samesign_inverted_different_sign_bittest2(
2353-
; CHECK-NEXT: [[A:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
2354-
; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[A]], -1
2355-
; CHECK-NEXT: [[O:%.*]] = or i32 [[X]], [[Y]]
2356-
; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[O]], 0
2357-
; CHECK-NEXT: [[R:%.*]] = and i1 [[GT]], [[LT]]
2358-
; CHECK-NEXT: ret i1 [[R]]
2327+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
2328+
; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 0
2329+
; CHECK-NEXT: ret i1 [[TMP2]]
23592330
;
23602331
%a = and i32 %x, %y
23612332
%gt = icmp sgt i32 %a, -1
@@ -2367,12 +2338,9 @@ define i1 @samesign_inverted_different_sign_bittest2(i32 %x, i32 %y) {
23672338

23682339
define i1 @samesign_inverted_commute1(i32 %x, i32 %y) {
23692340
; CHECK-LABEL: @samesign_inverted_commute1(
2370-
; CHECK-NEXT: [[A:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
2371-
; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[A]], -1
2372-
; CHECK-NEXT: [[O:%.*]] = or i32 [[X]], [[Y]]
2373-
; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[O]], 0
2374-
; CHECK-NEXT: [[R:%.*]] = and i1 [[LT]], [[GT]]
2375-
; CHECK-NEXT: ret i1 [[R]]
2341+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
2342+
; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 0
2343+
; CHECK-NEXT: ret i1 [[TMP2]]
23762344
;
23772345
%a = and i32 %x, %y
23782346
%gt = icmp sgt i32 %a, -1
@@ -2384,12 +2352,9 @@ define i1 @samesign_inverted_commute1(i32 %x, i32 %y) {
23842352

23852353
define i1 @samesign_inverted_commute2(i32 %x, i32 %y) {
23862354
; CHECK-LABEL: @samesign_inverted_commute2(
2387-
; CHECK-NEXT: [[A:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
2388-
; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[A]], -1
2389-
; CHECK-NEXT: [[O:%.*]] = or i32 [[Y]], [[X]]
2390-
; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[O]], 0
2391-
; CHECK-NEXT: [[R:%.*]] = and i1 [[GT]], [[LT]]
2392-
; CHECK-NEXT: ret i1 [[R]]
2355+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
2356+
; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 0
2357+
; CHECK-NEXT: ret i1 [[TMP2]]
23932358
;
23942359
%a = and i32 %x, %y
23952360
%gt = icmp sgt i32 %a, -1
@@ -2401,12 +2366,9 @@ define i1 @samesign_inverted_commute2(i32 %x, i32 %y) {
24012366

24022367
define i1 @samesign_inverted_commute3(i32 %x, i32 %y) {
24032368
; CHECK-LABEL: @samesign_inverted_commute3(
2404-
; CHECK-NEXT: [[A:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
2405-
; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[A]], -1
2406-
; CHECK-NEXT: [[O:%.*]] = or i32 [[Y]], [[X]]
2407-
; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[O]], 0
2408-
; CHECK-NEXT: [[R:%.*]] = and i1 [[LT]], [[GT]]
2409-
; CHECK-NEXT: ret i1 [[R]]
2369+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
2370+
; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 0
2371+
; CHECK-NEXT: ret i1 [[TMP2]]
24102372
;
24112373
%a = and i32 %x, %y
24122374
%gt = icmp sgt i32 %a, -1
@@ -2453,12 +2415,11 @@ define i1 @samesign_inverted_mult_use(i32 %x, i32 %y) {
24532415
; CHECK-LABEL: @samesign_inverted_mult_use(
24542416
; CHECK-NEXT: [[A:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
24552417
; CHECK-NEXT: call void @use32(i32 [[A]])
2456-
; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[A]], -1
24572418
; CHECK-NEXT: [[O:%.*]] = or i32 [[X]], [[Y]]
24582419
; CHECK-NEXT: call void @use32(i32 [[O]])
2459-
; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[O]], 0
2460-
; CHECK-NEXT: [[R:%.*]] = and i1 [[GT]], [[LT]]
2461-
; CHECK-NEXT: ret i1 [[R]]
2420+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X]], [[Y]]
2421+
; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 0
2422+
; CHECK-NEXT: ret i1 [[TMP2]]
24622423
;
24632424
%a = and i32 %x, %y
24642425
call void @use32(i32 %a)

0 commit comments

Comments
 (0)