[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