Index: lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -809,28 +809,28 @@ if (Value *V = foldLogOpOfMaskedICmps(LHS, RHS, true, Builder)) return V; - // This only handles icmp of constants: (icmp1 A, C1) & (icmp2 B, C2). Value *Val = LHS->getOperand(0), *Val2 = RHS->getOperand(0); - ConstantInt *LHSCst = dyn_cast(LHS->getOperand(1)); - ConstantInt *RHSCst = dyn_cast(RHS->getOperand(1)); - if (!LHSCst || !RHSCst) return nullptr; - - if (LHSCst == RHSCst && LHSCC == RHSCC) { - // (icmp ult A, C) & (icmp ult B, C) --> (icmp ult (A|B), C) - // where C is a power of 2 - if (LHSCC == ICmpInst::ICMP_ULT && - LHSCst->getValue().isPowerOf2()) { - Value *NewOr = Builder->CreateOr(Val, Val2); - return Builder->CreateICmp(LHSCC, NewOr, LHSCst); - } - // (icmp eq A, 0) & (icmp eq B, 0) --> (icmp eq (A|B), 0) - if (LHSCC == ICmpInst::ICMP_EQ && LHSCst->isZero()) { - Value *NewOr = Builder->CreateOr(Val, Val2); - return Builder->CreateICmp(LHSCC, NewOr, LHSCst); + // (icmp CC A, C) & (icmp CC B, C) --> (icmp CC (A|B), C) + if (LHS->getOperand(1) == RHS->getOperand(1) && LHSCC == RHSCC) { + const Type *Ty = Val->getType(); + if (Ty->isIntegerTy() || + (Ty->isVectorTy() && + cast(Ty)->getElementType()->isIntegerTy())) { + // We are creating two instructions; make sure we are replacing at least + // that many. + if (LHS->hasOneUse() || RHS->hasOneUse()) { + Value *NewOr = Builder->CreateOr(Val, Val2); + return Builder->CreateICmp(LHSCC, NewOr, LHS->getOperand(1)); + } } } + // This only handles icmp of constants: (icmp1 A, C1) & (icmp2 B, C2). + ConstantInt *LHSCst = dyn_cast(LHS->getOperand(1)); + ConstantInt *RHSCst = dyn_cast(RHS->getOperand(1)); + if (!LHSCst || !RHSCst) return nullptr; + // (trunc x) == C1 & (and x, CA) == C2 -> (and x, CA|CMAX) == C1|C2 // where CMAX is the all ones value for the truncated type, // iff the lower bits of C2 and CA are zero. Index: test/Transforms/InstCombine/2008-08-05-And.ll =================================================================== --- test/Transforms/InstCombine/2008-08-05-And.ll +++ test/Transforms/InstCombine/2008-08-05-And.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -instcombine -S | not grep or +; RUN: opt < %s -instcombine -S | FileCheck %s ; PR2629 define void @f(i8* %x) nounwind { @@ -13,6 +13,11 @@ %s2 = sub i8 %l1, 10 %c2 = icmp ugt i8 %s2, 2 %a1 = and i1 %c1, %c2 +; CHECK: %[[LOAD:.*]] = load i8* %x, align 1 +; CHECK-NEXT: %[[ADD1:.*]] = add i8 %[[LOAD]], -6 +; CHECK-NEXT: %[[ADD2:.*]] = add i8 %[[LOAD]], -10 +; CHECK-NEXT: %[[OR:.*]] = or i8 %[[ADD1]], %[[ADD2]] +; CHECK-NEXT: %[[ICMP:.*]] = icmp ugt i8 %[[OR]], 2 br i1 %a1, label %incompatible, label %okay okay: Index: test/Transforms/InstCombine/and.ll =================================================================== --- test/Transforms/InstCombine/and.ll +++ test/Transforms/InstCombine/and.ll @@ -1,40 +1,50 @@ ; This test makes sure that these instructions are properly eliminated. ; -; RUN: opt < %s -instcombine -S | not grep and +; RUN: opt < %s -instcombine -S | FileCheck %s define i32 @test1(i32 %A) { - ; zero result %B = and i32 %A, 0 ; [#uses=1] ret i32 %B +; CHECK-LABEL: @test1( +; CHECK: ret i32 0 } define i32 @test2(i32 %A) { - ; noop %B = and i32 %A, -1 ; [#uses=1] ret i32 %B +; CHECK-LABEL: @test2( +; CHECK: ret i32 %A } define i1 @test3(i1 %A) { ; always = false %B = and i1 %A, false ; [#uses=1] ret i1 %B +; CHECK-LABEL: @test3( +; CHECK: ret i1 false } define i1 @test4(i1 %A) { ; noop %B = and i1 %A, true ; [#uses=1] ret i1 %B +; CHECK-LABEL: @test4( +; CHECK: ret i1 %A } define i32 @test5(i32 %A) { %B = and i32 %A, %A ; [#uses=1] ret i32 %B +; CHECK-LABEL: @test5( +; CHECK: ret i32 %A } define i1 @test6(i1 %A) { %B = and i1 %A, %A ; [#uses=1] ret i1 %B +; CHECK-LABEL: @test6( +; CHECK: ret i1 %A } ; A & ~A == 0 @@ -42,6 +52,8 @@ %NotA = xor i32 %A, -1 ; [#uses=1] %B = and i32 %A, %NotA ; [#uses=1] ret i32 %B +; CHECK-LABEL: @test7( +; CHECK: ret i32 0 } ; AND associates @@ -49,6 +61,8 @@ %B = and i8 %A, 3 ; [#uses=1] %C = and i8 %B, 4 ; [#uses=1] ret i8 %C +; CHECK-LABEL: @test8( +; CHECK: ret i8 0 } define i1 @test9(i32 %A) { @@ -56,6 +70,9 @@ %B = and i32 %A, -2147483648 ; [#uses=1] %C = icmp ne i32 %B, 0 ; [#uses=1] ret i1 %C +; CHECK-LABEL: @test9( +; CHECK: %[[CMP:.*]] = icmp slt i32 %A, 0 +; CHECK: ret i1 %[[CMP]] } define i1 @test9a(i32 %A) { @@ -63,6 +80,9 @@ %B = and i32 %A, -2147483648 ; [#uses=1] %C = icmp ne i32 %B, 0 ; [#uses=1] ret i1 %C +; CHECK-LABEL: @test9a( +; CHECK: %[[CMP:.*]] = icmp slt i32 %A, 0 +; CHECK: ret i1 %[[CMP]] } define i32 @test10(i32 %A) { @@ -71,6 +91,8 @@ ; (X ^ C1) & C2 --> (X & C2) ^ (C1&C2) %D = and i32 %C, 1 ; [#uses=1] ret i32 %D +; CHECK-LABEL: @test10( +; CHECK: ret i32 1 } define i32 @test11(i32 %A, i32* %P) { @@ -81,6 +103,8 @@ ; %C = and uint %B, 3 --> 3 %D = and i32 %C, 3 ; [#uses=1] ret i32 %D +; CHECK-LABEL: @test11( +; CHECK: ret i32 3 } define i1 @test12(i32 %A, i32 %B) { @@ -89,6 +113,9 @@ ; (A < B) & (A <= B) === (A < B) %D = and i1 %C1, %C2 ; [#uses=1] ret i1 %D +; CHECK-LABEL: @test12( +; CHECK: %[[CMP:.*]] = icmp ult i32 %A, %B +; CHECK: ret i1 %[[CMP]] } define i1 @test13(i32 %A, i32 %B) { @@ -97,12 +124,17 @@ ; (A < B) & (A > B) === false %D = and i1 %C1, %C2 ; [#uses=1] ret i1 %D +; CHECK-LABEL: @test13( +; CHECK: ret i1 false } define i1 @test14(i8 %A) { %B = and i8 %A, -128 ; [#uses=1] %C = icmp ne i8 %B, 0 ; [#uses=1] ret i1 %C +; CHECK-LABEL: @test14( +; CHECK: %[[CMP:.*]] = icmp slt i8 %A, 0 +; CHECK: ret i1 %[[CMP]] } define i8 @test15(i8 %A) { @@ -110,12 +142,16 @@ ; Always equals zero %C = and i8 %B, 2 ; [#uses=1] ret i8 %C +; CHECK-LABEL: @test15( +; CHECK: ret i8 0 } define i8 @test16(i8 %A) { %B = shl i8 %A, 2 ; [#uses=1] %C = and i8 %B, 3 ; [#uses=1] ret i8 %C +; CHECK-LABEL: @test16( +; CHECK: ret i8 0 } ;; ~(~X & Y) --> (X | ~Y) @@ -124,6 +160,10 @@ %C = and i8 %B, %Y ; [#uses=1] %D = xor i8 %C, -1 ; [#uses=1] ret i8 %D +; CHECK-LABEL: @test17( +; CHECK: %[[XOR:.*]] = xor i8 %Y, -1 +; CHECK: %[[OR:.*]] = or i8 %X, %[[XOR]] +; CHECK: ret i8 %[[OR]] } define i1 @test18(i32 %A) { @@ -131,12 +171,18 @@ ;; C >= 128 %C = icmp ne i32 %B, 0 ; [#uses=1] ret i1 %C +; CHECK-LABEL: @test18( +; CHECK: %[[CMP:.*]] = icmp ugt i32 %A, 127 +; CHECK: ret i1 %[[CMP]] } define i1 @test18a(i8 %A) { %B = and i8 %A, -2 ; [#uses=1] %C = icmp eq i8 %B, 0 ; [#uses=1] ret i1 %C +; CHECK-LABEL: @test18a( +; CHECK: %[[CMP:.*]] = icmp ult i8 %A, 2 +; CHECK: ret i1 %[[CMP]] } define i32 @test19(i32 %A) { @@ -144,6 +190,9 @@ ;; Clearing a zero bit %C = and i32 %B, -2 ; [#uses=1] ret i32 %C +; CHECK-LABEL: @test19( +; CHECK: %[[SHL:.*]] = shl i32 %A, 3 +; CHECK: ret i32 %[[SHL]] } define i8 @test20(i8 %A) { @@ -151,6 +200,9 @@ ;; Unneeded %D = and i8 %C, 1 ; [#uses=1] ret i8 %D +; CHECK-LABEL: @test20( +; CHECK: %[[SHL:.*]] = lshr i8 %A, 7 +; CHECK: ret i8 %[[SHL]] } define i1 @test22(i32 %A) { @@ -159,6 +211,8 @@ ;; false %D = and i1 %B, %C ; [#uses=1] ret i1 %D +; CHECK-LABEL: @test22( +; CHECK: ret i1 false } define i1 @test23(i32 %A) { @@ -167,6 +221,9 @@ ;; A == 2 %D = and i1 %B, %C ; [#uses=1] ret i1 %D +; CHECK-LABEL: @test23( +; CHECK: %[[CMP:.*]] = icmp eq i32 %A, 2 +; CHECK: ret i1 %[[CMP]] } define i1 @test24(i32 %A) { @@ -175,6 +232,9 @@ ;; A > 2 %D = and i1 %B, %C ; [#uses=1] ret i1 %D +; CHECK-LABEL: @test24( +; CHECK: %[[CMP:.*]] = icmp sgt i32 %A, 2 +; CHECK: ret i1 %[[CMP]] } define i1 @test25(i32 %A) { @@ -183,6 +243,10 @@ ;; (A-50) [#uses=1] ret i1 %D +; CHECK-LABEL: @test25( +; CHECK: %[[ADD:.*]] = add i32 %A, -50 +; CHECK: %[[CMP:.*]] = icmp ult i32 %[[ADD]], 50 +; CHECK: ret i1 %[[CMP]] } define i1 @test26(i32 %A) { @@ -191,6 +255,10 @@ ;; (A-49) > 1 %D = and i1 %B, %C ; [#uses=1] ret i1 %D +; CHECK-LABEL: @test26( +; CHECK: %[[ADD:.*]] = add i32 %A, -49 +; CHECK: %[[CMP:.*]] = icmp ugt i32 %[[ADD]], 1 +; CHECK: ret i1 %[[CMP]] } define i8 @test27(i8 %A) { @@ -200,6 +268,8 @@ %D = and i8 %C, -16 ; [#uses=1] %E = add i8 %D, 16 ; [#uses=1] ret i8 %E +; CHECK-LABEL: @test27( +; CHECK: ret i8 0 } ;; This is juse a zero extending shr. @@ -209,6 +279,9 @@ ;; Mask out sign bits %Z = and i32 %Y, 255 ; [#uses=1] ret i32 %Z +; CHECK-LABEL: @test28( +; CHECK: %[[SHL:.*]] = lshr i32 %X, 24 +; CHECK: ret i32 %[[SHL]] } define i32 @test29(i8 %X) { @@ -216,12 +289,18 @@ ;; Zero extend makes this unneeded. %Z = and i32 %Y, 255 ; [#uses=1] ret i32 %Z +; CHECK-LABEL: @test29( +; CHECK: %[[ZEXT:.*]] = zext i8 %X to i32 +; CHECK: ret i32 %[[ZEXT]] } define i32 @test30(i1 %X) { %Y = zext i1 %X to i32 ; [#uses=1] %Z = and i32 %Y, 1 ; [#uses=1] ret i32 %Z +; CHECK-LABEL: @test30( +; CHECK: %[[ZEXT:.*]] = zext i1 %X to i32 +; CHECK: ret i32 %[[ZEXT]] } define i32 @test31(i1 %X) { @@ -229,6 +308,10 @@ %Z = shl i32 %Y, 4 ; [#uses=1] %A = and i32 %Z, 16 ; [#uses=1] ret i32 %A +; CHECK-LABEL: @test31( +; CHECK: %[[ZEXT:.*]] = zext i1 %X to i32 +; CHECK: %[[SHL:.*]] = shl nuw nsw i32 %[[ZEXT]], 4 +; CHECK: ret i32 %[[SHL]] } define i32 @test32(i32 %In) { @@ -236,6 +319,8 @@ %Z = lshr i32 %Y, 2 ; [#uses=1] %A = and i32 %Z, 1 ; [#uses=1] ret i32 %A +; CHECK-LABEL: @test32( +; CHECK: ret i32 0 } ;; Code corresponding to one-bit bitfield ^1. @@ -245,11 +330,26 @@ %tmp.12 = and i32 %b, -2 ; [#uses=1] %tmp.13 = or i32 %tmp.12, %tmp.10 ; [#uses=1] ret i32 %tmp.13 +; CHECK-LABEL: @test33( +; CHECK: %[[XOR:.*]] = xor i32 %b, 1 +; CHECK: ret i32 %[[XOR]] } define i32 @test34(i32 %A, i32 %B) { %tmp.2 = or i32 %B, %A ; [#uses=1] %tmp.4 = and i32 %tmp.2, %B ; [#uses=1] ret i32 %tmp.4 +; CHECK-LABEL: @test34( +; CHECK: ret i32 %B } +define i1 @test35(i32 %a, i32 %b) { + %cmp1 = icmp slt i32 %a, 8 + %cmp2 = icmp slt i32 %b, 8 + %ret = and i1 %cmp1, %cmp2 + ret i1 %ret +; CHECK-LABEL: test35( +; CHECK-NEXT: %[[OR:.*]] = or i32 %a, %b +; CHECK-NEXT: %[[CMP:.*]] = icmp slt i32 %[[OR]], 8 +; CHECK-NEXT: ret i1 %[[CMP]] +}