diff --git a/llvm/lib/Target/README.txt b/llvm/lib/Target/README.txt index 38f5af642d71..35273344d782 100644 --- a/llvm/lib/Target/README.txt +++ b/llvm/lib/Target/README.txt @@ -1055,18 +1055,6 @@ Should also combine to x | 8. Currently not optimized with "clang //===---------------------------------------------------------------------===// -int a(int x) {return (x & 8) == 0 ? -1 : -9;} -Should combine to (x | -9) ^ 8. Currently not optimized with "clang --emit-llvm-bc | opt -std-compile-opts". - -//===---------------------------------------------------------------------===// - -int a(int x) {return (x & 8) == 0 ? -9 : -1;} -Should combine to x | -9. Currently not optimized with "clang --emit-llvm-bc | opt -std-compile-opts". - -//===---------------------------------------------------------------------===// - int a(int x) {return ((x | -9) ^ 8) & x;} Should combine to x & -9. Currently not optimized with "clang -emit-llvm-bc | opt -std-compile-opts". diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp index 6f0da3eb64a9..82ce31128c8e 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -457,10 +457,6 @@ static Value *foldSelectICmpAnd(const SelectInst &SI, ConstantInt *TrueVal, if (!IC || !IC->isEquality()) return 0; - // One of the select arms must be zero. - if (!TrueVal->isZero() && !FalseVal->isZero()) - return 0; - if (ConstantInt *C = dyn_cast(IC->getOperand(1))) if (!C->isZero()) return 0; @@ -471,6 +467,24 @@ static Value *foldSelectICmpAnd(const SelectInst &SI, ConstantInt *TrueVal, !match(LHS, m_And(m_Value(), m_ConstantInt(AndRHS)))) return 0; + // If both select arms are non-zero see if we have a select of the form + // 'x ? 2^n + C : C'. Then we can offset both arms by C, use the logic + // for 'x ? 2^n : 0' and fix the thing up at the end. + ConstantInt *Offset = 0; + if (!TrueVal->isZero() && !FalseVal->isZero()) { + if ((TrueVal->getValue() - FalseVal->getValue()).isPowerOf2()) + Offset = FalseVal; + else if ((FalseVal->getValue() - TrueVal->getValue()).isPowerOf2()) + Offset = TrueVal; + else + return 0; + + // Adjust TrueVal and FalseVal to the offset. + TrueVal = ConstantInt::get(Builder->getContext(), + TrueVal->getValue() - Offset->getValue()); + FalseVal = ConstantInt::get(Builder->getContext(), + FalseVal->getValue() - Offset->getValue()); + } // Make sure the mask in the 'and' and one of the select arms is a power of 2. if (!AndRHS->getValue().isPowerOf2() || @@ -496,6 +510,10 @@ static Value *foldSelectICmpAnd(const SelectInst &SI, ConstantInt *TrueVal, ShouldNotVal ^= IC->getPredicate() == ICmpInst::ICMP_NE; if (ShouldNotVal) V = Builder->CreateXor(V, ValC); + + // Apply an offset if needed. + if (Offset) + V = Builder->CreateAdd(V, Offset); return V; } diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll index e9efa74e1a29..fecc9d1c3faa 100644 --- a/llvm/test/Transforms/InstCombine/select.ll +++ b/llvm/test/Transforms/InstCombine/select.ll @@ -248,6 +248,56 @@ define i32 @test15f(i32 %X) { ; CHECK: ret i32 } +;; (a & 8) ? -1 : -9 +define i32 @test15g(i32 %X) { + %t1 = and i32 %X, 8 + %t2 = icmp ne i32 %t1, 0 + %t3 = select i1 %t2, i32 -1, i32 -9 + ret i32 %t3 +; CHECK: @test15g +; CHECK-NEXT: %1 = or i32 %X, -9 +; CHECK-NEXT: ret i32 %1 +} + +;; (a & 8) ? -9 : -1 +define i32 @test15h(i32 %X) { + %t1 = and i32 %X, 8 + %t2 = icmp ne i32 %t1, 0 + %t3 = select i1 %t2, i32 -9, i32 -1 + ret i32 %t3 +; CHECK: @test15h +; CHECK-NEXT: %1 = or i32 %X, -9 +; CHECK-NEXT: %2 = xor i32 %1, 8 +; CHECK-NEXT: ret i32 %2 +} + +;; (a & 2) ? 577 : 1089 +define i32 @test15i(i32 %X) { + %t1 = and i32 %X, 2 + %t2 = icmp ne i32 %t1, 0 + %t3 = select i1 %t2, i32 577, i32 1089 + ret i32 %t3 +; CHECK: @test15i +; CHECK-NEXT: %t1 = shl i32 %X, 8 +; CHECK-NEXT: %1 = and i32 %t1, 512 +; CHECK-NEXT: %2 = xor i32 %1, 512 +; CHECK-NEXT: %3 = add i32 %2, 577 +; CHECK-NEXT: ret i32 %3 +} + +;; (a & 2) ? 1089 : 577 +define i32 @test15j(i32 %X) { + %t1 = and i32 %X, 2 + %t2 = icmp ne i32 %t1, 0 + %t3 = select i1 %t2, i32 1089, i32 577 + ret i32 %t3 +; CHECK: @test15j +; CHECK-NEXT: %t1 = shl i32 %X, 8 +; CHECK-NEXT: %1 = and i32 %t1, 512 +; CHECK-NEXT: %2 = add i32 %1, 577 +; CHECK-NEXT: ret i32 %2 +} + define i32 @test16(i1 %C, i32* %P) { %P2 = select i1 %C, i32* %P, i32* null %V = load i32* %P2