From 2f7228b80c6a129fa1d8eef8c3075085003d5b87 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Sat, 11 Dec 2010 10:49:22 +0000 Subject: [PATCH] Generalize the and-icmp-select instcombine further by allowing selects of the form (x & 2^n) ? 2^m+C : C we can offset both arms by C to get the "(x & 2^n) ? 2^m : 0" form, optimize the select to a shift and apply the offset afterwards. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@121609 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/README.txt | 12 ----- .../InstCombine/InstCombineSelect.cpp | 26 ++++++++-- test/Transforms/InstCombine/select.ll | 50 +++++++++++++++++++ 3 files changed, 72 insertions(+), 16 deletions(-) diff --git a/lib/Target/README.txt b/lib/Target/README.txt index 38f5af642d7..35273344d78 100644 --- a/lib/Target/README.txt +++ b/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/lib/Transforms/InstCombine/InstCombineSelect.cpp b/lib/Transforms/InstCombine/InstCombineSelect.cpp index 6f0da3eb64a..82ce31128c8 100644 --- a/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/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/test/Transforms/InstCombine/select.ll b/test/Transforms/InstCombine/select.ll index e9efa74e1a2..fecc9d1c3fa 100644 --- a/test/Transforms/InstCombine/select.ll +++ b/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 -- 2.34.1