[X86] Prevent the creation of redundant ops for sadd and ssub with overflow.
authorJuergen Ributzka <juergen@apple.com>
Fri, 24 Jan 2014 06:47:57 +0000 (06:47 +0000)
committerJuergen Ributzka <juergen@apple.com>
Fri, 24 Jan 2014 06:47:57 +0000 (06:47 +0000)
This commit teaches the X86 backend to create the same X86 instructions when it
lowers an sadd/ssub with overflow intrinsic and a conditional branch that uses
that overflow result. This allows SelectionDAG to recognize and remove one of
the redundant operations.

This fixes <rdar://problem/15874016> and <rdar://problem/15661073>.

Reviewed by Nadav

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@199976 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/X86/X86ISelLowering.cpp
test/CodeGen/X86/saddo-redundant-add.ll [new file with mode: 0644]

index 4b30ff67c9f85caad583a3ccaf7be0ded4a07b08..03eb57a4084b316ed416fc4a5a59611cf895d7f7 100644 (file)
@@ -10715,11 +10715,26 @@ SDValue X86TargetLowering::LowerBRCOND(SDValue Op, SelectionDAG &DAG) const {
     unsigned X86Opcode;
     unsigned X86Cond;
     SDVTList VTs;
+    // Keep this in sync with LowerXALUO, otherwise we might create redundant
+    // instructions that can't be removed afterwards (i.e. X86ISD::ADD and
+    // X86ISD::INC).
     switch (CondOpcode) {
     case ISD::UADDO: X86Opcode = X86ISD::ADD; X86Cond = X86::COND_B; break;
-    case ISD::SADDO: X86Opcode = X86ISD::ADD; X86Cond = X86::COND_O; break;
+    case ISD::SADDO:
+      if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS))
+        if (C->isOne()) {
+          X86Opcode = X86ISD::INC; X86Cond = X86::COND_O;
+          break;
+        }
+      X86Opcode = X86ISD::ADD; X86Cond = X86::COND_O; break;
     case ISD::USUBO: X86Opcode = X86ISD::SUB; X86Cond = X86::COND_B; break;
-    case ISD::SSUBO: X86Opcode = X86ISD::SUB; X86Cond = X86::COND_O; break;
+    case ISD::SSUBO:
+      if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS))
+        if (C->isOne()) {
+          X86Opcode = X86ISD::DEC; X86Cond = X86::COND_O;
+          break;
+        }
+      X86Opcode = X86ISD::SUB; X86Cond = X86::COND_O; break;
     case ISD::UMULO: X86Opcode = X86ISD::UMUL; X86Cond = X86::COND_O; break;
     case ISD::SMULO: X86Opcode = X86ISD::SMUL; X86Cond = X86::COND_O; break;
     default: llvm_unreachable("unexpected overflowing operator");
diff --git a/test/CodeGen/X86/saddo-redundant-add.ll b/test/CodeGen/X86/saddo-redundant-add.ll
new file mode 100644 (file)
index 0000000..c56c686
--- /dev/null
@@ -0,0 +1,34 @@
+; RUN: llc < %s -mtriple=x86_64-apple-darwin | FileCheck %s
+
+define void @redundant_add(i64 %n) {
+; Check that we don't create two additions for the sadd.with.overflow.
+; CHECK-LABEL: redundant_add
+; CHECK-NOT:  leaq
+; CHECK-NOT:  addq
+; CHECK:      incq
+; CHECK-NEXT: jno
+entry:
+  br label %exit_check
+
+exit_check:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+  %c = icmp slt i64 %i, %n
+  br i1 %c, label %loop, label %exit
+
+loop:
+  %i.o = tail call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %i, i64 1)
+  %i.next = extractvalue { i64, i1 } %i.o, 0
+  %o = extractvalue { i64, i1 } %i.o, 1
+  br i1 %o, label %overflow, label %exit_check
+
+exit:
+  ret void
+
+overflow:
+  tail call void @llvm.trap()
+  unreachable
+}
+
+declare { i64, i1 } @llvm.sadd.with.overflow.i64(i64, i64)
+declare void @llvm.trap()
+