[PATCH] Turn add, icmp, select into icmp, select with constants.

Matt Arsenault Matthew.Arsenault at amd.com
Mon Sep 9 19:21:25 PDT 2013


This doesn't work when the added constant is negative, since something else is turning that into a bitwise and.


http://llvm-reviews.chandlerc.com/D1633

Files:
  lib/Transforms/InstCombine/InstCombineSelect.cpp
  test/Transforms/InstCombine/select.ll

Index: lib/Transforms/InstCombine/InstCombineSelect.cpp
===================================================================
--- lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -429,6 +429,45 @@
   // here, so make sure the select is the only user.
   if (ICI->hasOneUse())
     if (ConstantInt *CI = dyn_cast<ConstantInt>(CmpRHS)) {
+      if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(CmpLHS)) {
+        if (ConstantInt *AddRHS = dyn_cast<ConstantInt>(BinOp->getOperand(1))) {
+          // Transform this:
+          //   %xc = add i32 %x, C
+          //   %cmp = icmp ult i32 %xc, D
+          //   %sel = select i1 %cmp, i32 %x, i32 %y
+          //
+          // To this:
+          //   %cmp = icmp ult i32 %x, (D - C)
+          //   %sel = select i1 %cmp, i32 %x, i32 %y
+          // where C and D are constants
+
+          // TODO: Would other math operations make sense to do here?
+          // Adding negatives and division turn into bitwise ands, which
+          // thwarts some of these cases.
+          if (BinOp->getOpcode() == Instruction::Add) {
+            Value *AddLHS = BinOp->getOperand(0);
+
+            // Combine the two constants.
+            Value *Subbed = Builder->CreateSub(CI,
+                                               AddRHS,
+                                               "",
+                                               BinOp->hasNoUnsignedWrap(),
+                                               BinOp->hasNoSignedWrap());
+
+            Value *NewCmp = Builder->CreateICmp(Pred,
+                                                AddLHS,
+                                                Subbed);
+            NewCmp->takeName(ICI);
+
+            Instruction *NewSelect = SelectInst::Create(NewCmp,
+                                                        AddRHS,
+                                                        SI.getOperand(2));
+            NewSelect->takeName(&SI);
+            return NewSelect;
+          }
+        }
+      }
+
       // X < MIN ? T : F  -->  F
       if ((Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_ULT)
           && CI->isMinValue(Pred == ICmpInst::ICMP_SLT))
Index: test/Transforms/InstCombine/select.ll
===================================================================
--- test/Transforms/InstCombine/select.ll
+++ test/Transforms/InstCombine/select.ll
@@ -1021,3 +1021,100 @@
 ; CHECK: lshr exact i32 %2, 1
 ; CHECK: xor i32 %3, 42
 }
+
+define i32 @test68a(i32 %x) {
+  %xc = add i32 %x, 4
+  %cmp = icmp ne i32 %xc, 0
+  %sel = select i1 %cmp, i32 %x, i32 42
+  ret i32 %sel
+
+; CHECK-LABEL: @test68a(
+; CHECK: icmp ne i32 %x, -4
+; CHECK: select i1 %cmp, i32 %x, i32 42
+}
+
+define i32 @test68b(i32 %x) {
+  %xc = add i32 %x, -1
+  %cmp = icmp ne i32 %xc, 10
+  %sel = select i1 %cmp, i32 %x, i32 42
+  ret i32 %sel
+
+; CHECK-LABEL: @test68b(
+; CHECK: icmp ne i32 %x, 11
+; CHECK: select i1 %cmp, i32 %x, i32 42
+}
+
+define i32 @test68c(i32 %x, i32 %y) {
+  %xc = add i32 %x, 4
+  %cmp = icmp ne i32 %xc, 0
+  %sel = select i1 %cmp, i32 %x, i32 %y
+  ret i32 %sel
+
+; CHECK-LABEL: @test68c(
+; CHECK: icmp ne i32 %x, -4
+; CHECK: select i1 %cmp, i32 %x, i32 %y
+}
+
+; These don't work because the add -2 turns into an and before
+; define i32 @test68d(i32 %x) {
+;   %xc = add i32 %x, -2
+;   %cmp = icmp ult i32 %xc, 2
+;   %sel = select i1 %cmp, i32 %x, i32 0
+;   ret i32 %sel
+;
+; ; XCHECK-LABEL: @test68d(
+; ; XCHECK: icmp ult i32 %x, 0
+; ; XCHECK: select i1 %cmp, i32 %x, i32 %y
+; }
+;
+; define i32 @test68e(i32 %x) {
+;   %xc = add i32 %x, -3
+;   %cmp = icmp ult i32 %xc, 2
+;   %sel = select i1 %cmp, i32 %x, i32 0
+;   ret i32 %sel
+;
+; ; XCHECK-LABEL: @test68e(
+; ; XCHECK-NEXT: ret i32 0
+; }
+
+define i32 @test68f(i32 %x) {
+  %xc = sub i32 %x, 3
+  %cmp = icmp ult i32 %xc, 2
+  %sel = select i1 %cmp, i32 %x, i32 0
+  ret i32 %sel
+
+; CHECK-LABEL: @test68f(
+; CHECK: %cmp = icmp ult i32 %x, 5
+; CHECK: %1 = select i1 %cmp, i32 -3, i32 0
+}
+
+declare void @i32_user(i32)
+
+; Test with another user of the add
+define i32 @test68g(i32 %x) {
+  %xc = add i32 %x, 4
+  call void @i32_user(i32 %xc)
+  %cmp = icmp ne i32 %xc, 0
+  %sel = select i1 %cmp, i32 %x, i32 42
+  ret i32 %sel
+
+; CHECK-LABEL: @test68g(
+; CHECK: %xc = add i32 %x, 4
+; CHECK: call void @i32_user(i32 %xc)
+; CHECK: %cmp = icmp ne i32 %x, -4
+; CHECK: %1 = select i1 %cmp, i32 4, i32 42
+}
+
+define i32 @test68h(i32 %x) {
+  %xc = add i32 %x, 2
+  call void @i32_user(i32 %xc)
+  %cmp = icmp ne i32 %xc, 3
+  %sel = select i1 %cmp, i32 %x, i32 42
+  ret i32 %sel
+
+; CHECK-LABEL: @test68h(
+; CHECK: %xc = add i32 %x, 2
+; CHECK: call void @i32_user(i32 %xc)
+; CHECK: %cmp = icmp ne i32 %x, 1
+; CHECK: %1 = select i1 %cmp, i32 2, i32 42
+}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D1633.1.patch
Type: text/x-patch
Size: 4823 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20130909/e8ab939f/attachment.bin>


More information about the llvm-commits mailing list