[X86] Optimized ADD + ADC to ADC (#173543)
This patch folds an `adc` followed by an `add` into a single `adc` instruction when adding constants. Fixes #173408
This commit is contained in:
parent
33584b6250
commit
3a6aa13f51
@ -58631,6 +58631,28 @@ static SDValue combineX86AddSub(SDNode *N, SelectionDAG &DAG,
|
||||
}
|
||||
}
|
||||
|
||||
// Fold ADD(ADC(Y, C1, CF), C2) -> ADC(Y, C1 + C2, CF) and
|
||||
// ADD(ADC(Y, 0, CF), X) -> ADC(Y, X, CF)
|
||||
if (!IsSub && LHS.getOpcode() == X86ISD::ADC && LHS.hasOneUse() &&
|
||||
!needCarryOrOverflowFlag(SDValue(N, 1))) {
|
||||
|
||||
auto *C1 = dyn_cast<ConstantSDNode>(LHS.getOperand(1));
|
||||
auto *C2 = dyn_cast<ConstantSDNode>(RHS);
|
||||
|
||||
// Both are constants: fold C1 + C2
|
||||
if (C1 && C2) {
|
||||
APInt Sum = C1->getAPIntValue() + C2->getAPIntValue();
|
||||
return DAG.getNode(X86ISD::ADC, DL, N->getVTList(), LHS.getOperand(0),
|
||||
DAG.getConstant(Sum, DL, VT), LHS.getOperand(2));
|
||||
}
|
||||
|
||||
// Case: ADC(Y, 0, CF) + X -> ADC(Y, X, CF)
|
||||
if (C1 && C1->isZero()) {
|
||||
return DAG.getNode(X86ISD::ADC, DL, N->getVTList(), LHS.getOperand(0),
|
||||
RHS, LHS.getOperand(2));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Can we drop the ZeroSecondOpOnly limit? This is to guarantee that the
|
||||
// EFLAGS result doesn't change.
|
||||
return combineAddOrSubToADCOrSBB(IsSub, DL, VT, LHS, RHS, DAG,
|
||||
|
||||
@ -561,3 +561,82 @@ define i64 @add_notx_x(i64 %v0) nounwind {
|
||||
%y = add i64 %x, %v0
|
||||
ret i64 %y
|
||||
}
|
||||
|
||||
; Basic positive test
|
||||
define i32 @add_adc_to_adc(i32 %0, i32 %1, i32 %2) nounwind {
|
||||
; CHECK-LABEL: add_adc_to_adc:
|
||||
; CHECK: # %bb.0:
|
||||
; CHECK-NEXT: movl %edi, %eax
|
||||
; CHECK-NEXT: cmpl %esi, %edi
|
||||
; CHECK-NEXT: adcl $42, %edx
|
||||
; CHECK-NEXT: cmovsl %esi, %eax
|
||||
; CHECK-NEXT: retq
|
||||
%4 = icmp ult i32 %0, %1
|
||||
%5 = zext i1 %4 to i32
|
||||
%6 = add i32 %2, 42
|
||||
%7 = add i32 %6, %5
|
||||
%8 = icmp slt i32 %7, 0
|
||||
%9 = select i1 %8, i32 %1, i32 %0
|
||||
ret i32 %9
|
||||
}
|
||||
|
||||
; positive test: nonconst
|
||||
define i32 @add_adc_to_adc_nonconst(i32 %0, i32 %1, i32 %2, i32 %extra) nounwind {
|
||||
; CHECK-LABEL: add_adc_to_adc_nonconst:
|
||||
; CHECK: # %bb.0:
|
||||
; CHECK-NEXT: movl %edi, %eax
|
||||
; CHECK-NEXT: cmpl %esi, %edi
|
||||
; CHECK-NEXT: adcl %ecx, %edx
|
||||
; CHECK-NEXT: cmovsl %esi, %eax
|
||||
; CHECK-NEXT: retq
|
||||
%c = icmp ult i32 %0, %1
|
||||
%carry = zext i1 %c to i32
|
||||
%adc = add i32 %2, %carry
|
||||
%final = add i32 %adc, %extra
|
||||
%neg = icmp slt i32 %final, 0
|
||||
%sel = select i1 %neg, i32 %1, i32 %0
|
||||
ret i32 %sel
|
||||
}
|
||||
|
||||
; Negative test: Carry or overflow flag is used
|
||||
define i32 @add_adc_wrong_flags(i32 %0, i32 %1, i32 %2) nounwind {
|
||||
; CHECK-LABEL: add_adc_wrong_flags:
|
||||
; CHECK: # %bb.0:
|
||||
; CHECK-NEXT: movl %esi, %eax
|
||||
; CHECK-NEXT: cmpl %esi, %edi
|
||||
; CHECK-NEXT: adcl $10, %edx
|
||||
; CHECK-NEXT: addl $32, %edx
|
||||
; CHECK-NEXT: cmovbl %edi, %eax
|
||||
; CHECK-NEXT: retq
|
||||
%4 = icmp ult i32 %0, %1
|
||||
%5 = zext i1 %4 to i32
|
||||
%6 = add i32 %2, 10
|
||||
%7 = add i32 %6, %5
|
||||
%8 = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %7, i32 32)
|
||||
%9 = extractvalue { i32, i1 } %8, 1
|
||||
%10 = select i1 %9, i32 %0, i32 %1
|
||||
ret i32 %10
|
||||
}
|
||||
|
||||
; Negative test: Multi-use
|
||||
define i32 @add_adc_multi_use(i32 %0, i32 %1, i32 %2) nounwind {
|
||||
; CHECK-LABEL: add_adc_multi_use:
|
||||
; CHECK: # %bb.0:
|
||||
; CHECK-NEXT: # kill: def $edx killed $edx def $rdx
|
||||
; CHECK-NEXT: # kill: def $esi killed $esi def $rsi
|
||||
; CHECK-NEXT: cmpl %esi, %edi
|
||||
; CHECK-NEXT: adcl $0, %edx
|
||||
; CHECK-NEXT: movl %edx, %eax
|
||||
; CHECK-NEXT: addl $42, %eax
|
||||
; CHECK-NEXT: cmovsl %edi, %esi
|
||||
; CHECK-NEXT: leal (%rsi,%rdx), %eax
|
||||
; CHECK-NEXT: retq
|
||||
%4 = icmp ult i32 %0, %1
|
||||
%5 = zext i1 %4 to i32
|
||||
%6 = add i32 %2, %5
|
||||
%7 = add i32 %6, 42
|
||||
%8 = icmp slt i32 %7, 0
|
||||
%9 = select i1 %8, i32 %0, i32 %1
|
||||
%10 = add i32 %9, %6
|
||||
ret i32 %10
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user