[X86] Prevent the creation of redundant ops for sadd and ssub with overflow.

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
This commit is contained in:
Juergen Ributzka 2014-01-24 06:47:57 +00:00
parent c30791627e
commit fe08a38a2c
2 changed files with 51 additions and 2 deletions

View 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");

View File

@ -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()