Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit 32995b5

Browse files
committed
[InstSimplify] recognize trunc + icmp sgt/slt variants of select simplifications (PR28466)
rL245171 exposed a hole in InstSimplify that manifested in a strange way in PR28466: https://llvm.org/bugs/show_bug.cgi?id=28466 It's possible to use trunc + icmp sgt/slt in place of an and + icmp eq/ne, so we need to recognize that pattern to eliminate selects that are choosing between some value and some bitmasked version of that value. Note that there is significant room for improvement (refactoring) and enhancement (more patterns, possibly in InstCombine rather than here). Differential Revision: https://reviews.llvm.org/D22537 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@276341 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 4d4b609 commit 32995b5

File tree

2 files changed

+42
-48
lines changed

2 files changed

+42
-48
lines changed

lib/Analysis/InstructionSimplify.cpp

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3406,6 +3406,33 @@ static Value *simplifySelectBitTest(Value *TrueVal, Value *FalseVal, Value *X,
34063406
return nullptr;
34073407
}
34083408

3409+
/// An alternative way to test if a bit is set or not uses sgt/slt instead of
3410+
/// eq/ne.
3411+
static Value *simplifySelectWithFakeICmpEq(Value *CmpLHS, Value *TrueVal,
3412+
Value *FalseVal,
3413+
bool TrueWhenUnset) {
3414+
unsigned BitWidth = TrueVal->getType()->getScalarSizeInBits();
3415+
APInt MinSignedValue;
3416+
Value *X;
3417+
if (match(CmpLHS, m_Trunc(m_Value(X))) && (X == TrueVal || X == FalseVal)) {
3418+
// icmp slt (trunc X), 0 <--> icmp ne (and X, C), 0
3419+
// icmp sgt (trunc X), -1 <--> icmp eq (and X, C), 0
3420+
unsigned DestSize = CmpLHS->getType()->getScalarSizeInBits();
3421+
MinSignedValue = APInt::getSignedMinValue(DestSize).zext(BitWidth);
3422+
} else {
3423+
// icmp slt X, 0 <--> icmp ne (and X, C), 0
3424+
// icmp sgt X, -1 <--> icmp eq (and X, C), 0
3425+
X = CmpLHS;
3426+
MinSignedValue = APInt::getSignedMinValue(BitWidth);
3427+
}
3428+
3429+
if (Value *V = simplifySelectBitTest(TrueVal, FalseVal, X, &MinSignedValue,
3430+
TrueWhenUnset))
3431+
return V;
3432+
3433+
return nullptr;
3434+
}
3435+
34093436
/// Try to simplify a select instruction when its condition operand is an
34103437
/// integer comparison.
34113438
static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
@@ -3418,9 +3445,6 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
34183445

34193446
// FIXME: This code is nearly duplicated in InstCombine. Using/refactoring
34203447
// decomposeBitTestICmp() might help.
3421-
unsigned BitWidth =
3422-
Q.DL.getTypeSizeInBits(TrueVal->getType()->getScalarType());
3423-
APInt MinSignedValue = APInt::getSignBit(BitWidth);
34243448
if (ICmpInst::isEquality(Pred) && match(CmpRHS, m_Zero())) {
34253449
Value *X;
34263450
const APInt *Y;
@@ -3429,12 +3453,14 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
34293453
Pred == ICmpInst::ICMP_EQ))
34303454
return V;
34313455
} else if (Pred == ICmpInst::ICMP_SLT && match(CmpRHS, m_Zero())) {
3432-
if (Value *V = simplifySelectBitTest(TrueVal, FalseVal, CmpLHS,
3433-
&MinSignedValue, false))
3456+
// Comparing signed-less-than 0 checks if the sign bit is set.
3457+
if (Value *V = simplifySelectWithFakeICmpEq(CmpLHS, TrueVal, FalseVal,
3458+
false))
34343459
return V;
34353460
} else if (Pred == ICmpInst::ICMP_SGT && match(CmpRHS, m_AllOnes())) {
3436-
if (Value *V = simplifySelectBitTest(TrueVal, FalseVal, CmpLHS,
3437-
&MinSignedValue, true))
3461+
// Comparing signed-greater-than -1 checks if the sign bit is not set.
3462+
if (Value *V = simplifySelectWithFakeICmpEq(CmpLHS, TrueVal, FalseVal,
3463+
true))
34383464
return V;
34393465
}
34403466

test/Transforms/InstSimplify/select.ll

Lines changed: 9 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,8 @@ define i32 @select_icmp_and_8_ne_0_and_not_8_alt(i32 %x) {
228228

229229
define i32 @select_icmp_trunc_8_ne_0_or_128(i32 %x) {
230230
; CHECK-LABEL: @select_icmp_trunc_8_ne_0_or_128(
231-
; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 %x to i8
232-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[TRUNC]], -1
233231
; CHECK-NEXT: [[OR:%.*]] = or i32 %x, 128
234-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[OR]], i32 %x
235-
; CHECK-NEXT: ret i32 [[SEL]]
232+
; CHECK-NEXT: ret i32 [[OR]]
236233
;
237234
%trunc = trunc i32 %x to i8
238235
%cmp = icmp sgt i8 %trunc, -1
@@ -243,11 +240,8 @@ define i32 @select_icmp_trunc_8_ne_0_or_128(i32 %x) {
243240

244241
define i32 @select_icmp_trunc_8_ne_0_or_128_alt(i32 %x) {
245242
; CHECK-LABEL: @select_icmp_trunc_8_ne_0_or_128_alt(
246-
; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 %x to i8
247-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[TRUNC]], 0
248243
; CHECK-NEXT: [[OR:%.*]] = or i32 %x, 128
249-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 %x, i32 [[OR]]
250-
; CHECK-NEXT: ret i32 [[SEL]]
244+
; CHECK-NEXT: ret i32 [[OR]]
251245
;
252246
%trunc = trunc i32 %x to i8
253247
%cmp = icmp slt i8 %trunc, 0
@@ -258,11 +252,7 @@ define i32 @select_icmp_trunc_8_ne_0_or_128_alt(i32 %x) {
258252

259253
define i32 @select_icmp_trunc_8_eq_0_or_128(i32 %x) {
260254
; CHECK-LABEL: @select_icmp_trunc_8_eq_0_or_128(
261-
; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 %x to i8
262-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[TRUNC]], 0
263-
; CHECK-NEXT: [[OR:%.*]] = or i32 %x, 128
264-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[OR]], i32 %x
265-
; CHECK-NEXT: ret i32 [[SEL]]
255+
; CHECK-NEXT: ret i32 %x
266256
;
267257
%trunc = trunc i32 %x to i8
268258
%cmp = icmp slt i8 %trunc, 0
@@ -273,11 +263,7 @@ define i32 @select_icmp_trunc_8_eq_0_or_128(i32 %x) {
273263

274264
define i32 @select_icmp_trunc_8_eq_0_or_128_alt(i32 %x) {
275265
; CHECK-LABEL: @select_icmp_trunc_8_eq_0_or_128_alt(
276-
; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 %x to i8
277-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[TRUNC]], -1
278-
; CHECK-NEXT: [[OR:%.*]] = or i32 %x, 128
279-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 %x, i32 [[OR]]
280-
; CHECK-NEXT: ret i32 [[SEL]]
266+
; CHECK-NEXT: ret i32 %x
281267
;
282268
%trunc = trunc i32 %x to i8
283269
%cmp = icmp sgt i8 %trunc, -1
@@ -288,11 +274,8 @@ define i32 @select_icmp_trunc_8_eq_0_or_128_alt(i32 %x) {
288274

289275
define i32 @select_icmp_trunc_8_eq_0_and_not_8(i32 %x) {
290276
; CHECK-LABEL: @select_icmp_trunc_8_eq_0_and_not_8(
291-
; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 %x to i4
292-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i4 [[TRUNC]], -1
293277
; CHECK-NEXT: [[AND:%.*]] = and i32 %x, -9
294-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 %x, i32 [[AND]]
295-
; CHECK-NEXT: ret i32 [[SEL]]
278+
; CHECK-NEXT: ret i32 [[AND]]
296279
;
297280
%trunc = trunc i32 %x to i4
298281
%cmp = icmp sgt i4 %trunc, -1
@@ -303,11 +286,8 @@ define i32 @select_icmp_trunc_8_eq_0_and_not_8(i32 %x) {
303286

304287
define i32 @select_icmp_trunc_8_eq_0_and_not_8_alt(i32 %x) {
305288
; CHECK-LABEL: @select_icmp_trunc_8_eq_0_and_not_8_alt(
306-
; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 %x to i4
307-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i4 [[TRUNC]], 0
308289
; CHECK-NEXT: [[AND:%.*]] = and i32 %x, -9
309-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[AND]], i32 %x
310-
; CHECK-NEXT: ret i32 [[SEL]]
290+
; CHECK-NEXT: ret i32 [[AND]]
311291
;
312292
%trunc = trunc i32 %x to i4
313293
%cmp = icmp slt i4 %trunc, 0
@@ -318,11 +298,7 @@ define i32 @select_icmp_trunc_8_eq_0_and_not_8_alt(i32 %x) {
318298

319299
define i32 @select_icmp_trunc_8_ne_0_and_not_8(i32 %x) {
320300
; CHECK-LABEL: @select_icmp_trunc_8_ne_0_and_not_8(
321-
; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 %x to i4
322-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i4 [[TRUNC]], 0
323-
; CHECK-NEXT: [[AND:%.*]] = and i32 %x, -9
324-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 %x, i32 [[AND]]
325-
; CHECK-NEXT: ret i32 [[SEL]]
301+
; CHECK-NEXT: ret i32 %x
326302
;
327303
%trunc = trunc i32 %x to i4
328304
%cmp = icmp slt i4 %trunc, 0
@@ -333,11 +309,7 @@ define i32 @select_icmp_trunc_8_ne_0_and_not_8(i32 %x) {
333309

334310
define i32 @select_icmp_trunc_8_ne_0_and_not_8_alt(i32 %x) {
335311
; CHECK-LABEL: @select_icmp_trunc_8_ne_0_and_not_8_alt(
336-
; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 %x to i4
337-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i4 [[TRUNC]], -1
338-
; CHECK-NEXT: [[AND:%.*]] = and i32 %x, -9
339-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[AND]], i32 %x
340-
; CHECK-NEXT: ret i32 [[SEL]]
312+
; CHECK-NEXT: ret i32 %x
341313
;
342314
%trunc = trunc i32 %x to i4
343315
%cmp = icmp sgt i4 %trunc, -1
@@ -361,11 +333,7 @@ define <2 x i32> @select_icmp_and_8_ne_0_and_not_8_vec(<2 x i32> %x) {
361333

362334
define <2 x i32> @select_icmp_trunc_8_ne_0_and_not_8_alt_vec(<2 x i32> %x) {
363335
; CHECK-LABEL: @select_icmp_trunc_8_ne_0_and_not_8_alt_vec(
364-
; CHECK-NEXT: [[TRUNC:%.*]] = trunc <2 x i32> %x to <2 x i4>
365-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i4> [[TRUNC]], <i4 -1, i4 -1>
366-
; CHECK-NEXT: [[AND:%.*]] = and <2 x i32> %x, <i32 -9, i32 -9>
367-
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i32> [[AND]], <2 x i32> %x
368-
; CHECK-NEXT: ret <2 x i32> [[SEL]]
336+
; CHECK-NEXT: ret <2 x i32> %x
369337
;
370338
%trunc = trunc <2 x i32> %x to <2 x i4>
371339
%cmp = icmp sgt <2 x i4> %trunc, <i4 -1, i4 -1>

0 commit comments

Comments
 (0)