From d10a54f07fac76add4be5f3756a6121d38484938 Mon Sep 17 00:00:00 2001 From: Dinesh Dwivedi Date: Thu, 15 May 2014 06:01:33 +0000 Subject: [PATCH] Added inst combine transforms for single bit tests from Chris's note if ((x & C) == 0) x |= C becomes x |= C if ((x & C) != 0) x ^= C becomes x &= ~C if ((x & C) == 0) x ^= C becomes x |= C if ((x & C) != 0) x &= ~C becomes x &= ~C if ((x & C) == 0) x &= ~C becomes nothing Z3 Verifications code for above transform http://rise4fun.com/Z3/Pmsh Differential Revision: http://reviews.llvm.org/D3717 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208848 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../InstCombine/InstCombineSelect.cpp | 42 +++++++++++++-- test/Transforms/InstCombine/select.ll | 54 +++++++++++++++++++ 2 files changed, 91 insertions(+), 5 deletions(-) diff --git a/lib/Transforms/InstCombine/InstCombineSelect.cpp b/lib/Transforms/InstCombine/InstCombineSelect.cpp index 795e645840c..50b5b3740f1 100644 --- a/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -365,7 +365,15 @@ static Value *SimplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp, /// 1. The icmp predicate is inverted /// 2. The select operands are reversed /// 3. The magnitude of C2 and C1 are flipped -static Value *foldSelectICmpAndOr(const SelectInst &SI, Value *TrueVal, +/// +/// This also tries to turn +/// --- Single bit tests: +/// if ((x & C) == 0) x |= C to x |= C +/// if ((x & C) != 0) x ^= C to x &= ~C +/// if ((x & C) == 0) x ^= C to x |= C +/// if ((x & C) != 0) x &= ~C to x &= ~C +/// if ((x & C) == 0) x &= ~C to nothing +static Value *foldSelectICmpAndOr(SelectInst &SI, Value *TrueVal, Value *FalseVal, InstCombiner::BuilderTy *Builder) { const ICmpInst *IC = dyn_cast(SI.getCondition()); @@ -384,10 +392,34 @@ static Value *foldSelectICmpAndOr(const SelectInst &SI, Value *TrueVal, return nullptr; const APInt *C2; - bool OrOnTrueVal = false; - bool OrOnFalseVal = match(FalseVal, m_Or(m_Specific(TrueVal), m_Power2(C2))); - if (!OrOnFalseVal) - OrOnTrueVal = match(TrueVal, m_Or(m_Specific(FalseVal), m_Power2(C2))); + + // if ((x & C) != 0) x ^= C becomes x &= ~C + if (match(FalseVal, m_Xor(m_Specific(TrueVal), m_APInt(C2))) && C1 == C2) { + return Builder->CreateAnd(TrueVal, ~(*C1)); + } + + // if ((x & C) == 0) x ^= C becomes x |= C + if (match(TrueVal, m_Xor(m_Specific(FalseVal), m_APInt(C2))) && C1 == C2) { + return Builder->CreateOr(FalseVal, *C1); + } + + // if ((x & C) != 0) x &= ~C becomes x &= ~C + // if ((x & C) == 0) x &= ~C becomes nothing + if ((match(FalseVal, m_And(m_Specific(TrueVal), m_APInt(C2))) || + match(TrueVal, m_And(m_Specific(FalseVal), m_APInt(C2)))) && + *C1 == ~(*C2)) { + return FalseVal; + } + + bool OrOnFalseVal = false; + bool OrOnTrueVal = match(TrueVal, m_Or(m_Specific(FalseVal), m_Power2(C2))); + + // if ((x & C) == 0) x |= C becomes x |= C + if (OrOnTrueVal && C1 == C2) + return TrueVal; + + if (!OrOnTrueVal) + OrOnFalseVal = match(FalseVal, m_Or(m_Specific(TrueVal), m_Power2(C2))); if (!OrOnFalseVal && !OrOnTrueVal) return nullptr; diff --git a/test/Transforms/InstCombine/select.ll b/test/Transforms/InstCombine/select.ll index 1458bde8212..1f8b38f5642 100644 --- a/test/Transforms/InstCombine/select.ll +++ b/test/Transforms/InstCombine/select.ll @@ -996,6 +996,60 @@ define <2 x i32> @select_icmp_eq_and_1_0_or_vector_of_2s(i32 %x, <2 x i32> %y) { ret <2 x i32> %select } +; CHECK-LABEL: @select_icmp_and_8_eq_0_or_8( +; CHECK-NEXT: [[OR:%[a-z0-9]+]] = or i32 %x, 8 +; CHECK-NEXT: ret i32 [[OR]] +define i32 @select_icmp_and_8_eq_0_or_8(i32 %x) { + %and = and i32 %x, 8 + %cmp = icmp eq i32 %and, 0 + %or = or i32 %x, 8 + %or.x = select i1 %cmp, i32 %or, i32 %x + ret i32 %or.x +} + +; CHECK-LABEL: @select_icmp_and_8_ne_0_xor_8( +; CHECK-NEXT: [[AND:%[a-z0-9]+]] = and i32 %x, -9 +; CHECK-NEXT: ret i32 [[AND]] +define i32 @select_icmp_and_8_ne_0_xor_8(i32 %x) { + %and = and i32 %x, 8 + %cmp = icmp eq i32 %and, 0 + %xor = xor i32 %x, 8 + %x.xor = select i1 %cmp, i32 %x, i32 %xor + ret i32 %x.xor +} + +; CHECK-LABEL: @select_icmp_and_8_eq_0_xor_8( +; CHECK-NEXT: [[OR:%[a-z0-9]+]] = or i32 %x, 8 +; CHECK-NEXT: ret i32 [[OR]] +define i32 @select_icmp_and_8_eq_0_xor_8(i32 %x) { + %and = and i32 %x, 8 + %cmp = icmp eq i32 %and, 0 + %xor = xor i32 %x, 8 + %xor.x = select i1 %cmp, i32 %xor, i32 %x + ret i32 %xor.x +} + +; CHECK-LABEL: @select_icmp_and_8_ne_0_and_not_8( +; CHECK-NEXT: [[AND:%[a-z0-9]+]] = and i32 %x, -9 +; CHECK-NEXT: ret i32 [[AND]] +define i32 @select_icmp_and_8_ne_0_and_not_8(i32 %x) { + %and = and i32 %x, 8 + %cmp = icmp eq i32 %and, 0 + %and1 = and i32 %x, -9 + %x.and1 = select i1 %cmp, i32 %x, i32 %and1 + ret i32 %x.and1 +} + +; CHECK-LABEL: @select_icmp_and_8_eq_0_and_not_8( +; CHECK-NEXT: ret i32 %x +define i32 @select_icmp_and_8_eq_0_and_not_8(i32 %x) { + %and = and i32 %x, 8 + %cmp = icmp eq i32 %and, 0 + %and1 = and i32 %x, -9 + %and1.x = select i1 %cmp, i32 %and1, i32 %x + ret i32 %and1.x +} + define i32 @test65(i64 %x) { %1 = and i64 %x, 16 %2 = icmp ne i64 %1, 0 -- 2.34.1