mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-15 07:39:31 +00:00
[x86] X86ISelLowering zext(add_nuw(x, C)) --> add(zext(x), C_zext)
Currently X86ISelLowering has a similar transformation for sexts: sext(add_nsw(x, C)) --> add(sext(x), C_sext) In this change I extend this code to handle zexts as well. Reviewed By: spatel Differential Revision: https://reviews.llvm.org/D23359 llvm-svn: 278520
This commit is contained in:
parent
03643a9b1f
commit
81b9dd6378
@ -30475,19 +30475,32 @@ static SDValue combineSignExtendInReg(SDNode *N, SelectionDAG &DAG,
|
||||
}
|
||||
|
||||
/// sext(add_nsw(x, C)) --> add(sext(x), C_sext)
|
||||
/// Promoting a sign extension ahead of an 'add nsw' exposes opportunities
|
||||
/// to combine math ops, use an LEA, or use a complex addressing mode. This can
|
||||
/// eliminate extend, add, and shift instructions.
|
||||
static SDValue promoteSextBeforeAddNSW(SDNode *Sext, SelectionDAG &DAG,
|
||||
const X86Subtarget &Subtarget) {
|
||||
/// zext(add_nuw(x, C)) --> add(zext(x), C_zext)
|
||||
/// Promoting a sign/zero extension ahead of a no overflow 'add' exposes
|
||||
/// opportunities to combine math ops, use an LEA, or use a complex addressing
|
||||
/// mode. This can eliminate extend, add, and shift instructions.
|
||||
static SDValue promoteExtBeforeAdd(SDNode *Ext, SelectionDAG &DAG,
|
||||
const X86Subtarget &Subtarget) {
|
||||
if (Ext->getOpcode() != ISD::SIGN_EXTEND &&
|
||||
Ext->getOpcode() != ISD::ZERO_EXTEND)
|
||||
return SDValue();
|
||||
|
||||
// TODO: This should be valid for other integer types.
|
||||
EVT VT = Sext->getValueType(0);
|
||||
EVT VT = Ext->getValueType(0);
|
||||
if (VT != MVT::i64)
|
||||
return SDValue();
|
||||
|
||||
// We need an 'add nsw' feeding into the 'sext'.
|
||||
SDValue Add = Sext->getOperand(0);
|
||||
if (Add.getOpcode() != ISD::ADD || !Add->getFlags()->hasNoSignedWrap())
|
||||
SDValue Add = Ext->getOperand(0);
|
||||
if (Add.getOpcode() != ISD::ADD)
|
||||
return SDValue();
|
||||
|
||||
bool Sext = Ext->getOpcode() == ISD::SIGN_EXTEND;
|
||||
bool NSW = Add->getFlags()->hasNoSignedWrap();
|
||||
bool NUW = Add->getFlags()->hasNoUnsignedWrap();
|
||||
|
||||
// We need an 'add nsw' feeding into the 'sext' or 'add nuw' feeding
|
||||
// into the 'zext'
|
||||
if ((Sext && !NSW) || (!Sext && !NUW))
|
||||
return SDValue();
|
||||
|
||||
// Having a constant operand to the 'add' ensures that we are not increasing
|
||||
@ -30503,7 +30516,7 @@ static SDValue promoteSextBeforeAddNSW(SDNode *Sext, SelectionDAG &DAG,
|
||||
// of single 'add' instructions, but the cost model for selecting an LEA
|
||||
// currently has a high threshold.
|
||||
bool HasLEAPotential = false;
|
||||
for (auto *User : Sext->uses()) {
|
||||
for (auto *User : Ext->uses()) {
|
||||
if (User->getOpcode() == ISD::ADD || User->getOpcode() == ISD::SHL) {
|
||||
HasLEAPotential = true;
|
||||
break;
|
||||
@ -30512,17 +30525,18 @@ static SDValue promoteSextBeforeAddNSW(SDNode *Sext, SelectionDAG &DAG,
|
||||
if (!HasLEAPotential)
|
||||
return SDValue();
|
||||
|
||||
// Everything looks good, so pull the 'sext' ahead of the 'add'.
|
||||
int64_t AddConstant = AddOp1->getSExtValue();
|
||||
// Everything looks good, so pull the '{s|z}ext' ahead of the 'add'.
|
||||
int64_t AddConstant = Sext ? AddOp1->getSExtValue() : AddOp1->getZExtValue();
|
||||
SDValue AddOp0 = Add.getOperand(0);
|
||||
SDValue NewSext = DAG.getNode(ISD::SIGN_EXTEND, SDLoc(Sext), VT, AddOp0);
|
||||
SDValue NewExt = DAG.getNode(Ext->getOpcode(), SDLoc(Ext), VT, AddOp0);
|
||||
SDValue NewConstant = DAG.getConstant(AddConstant, SDLoc(Add), VT);
|
||||
|
||||
// The wider add is guaranteed to not wrap because both operands are
|
||||
// sign-extended.
|
||||
SDNodeFlags Flags;
|
||||
Flags.setNoSignedWrap(true);
|
||||
return DAG.getNode(ISD::ADD, SDLoc(Add), VT, NewSext, NewConstant, &Flags);
|
||||
Flags.setNoSignedWrap(NSW);
|
||||
Flags.setNoUnsignedWrap(NUW);
|
||||
return DAG.getNode(ISD::ADD, SDLoc(Add), VT, NewExt, NewConstant, &Flags);
|
||||
}
|
||||
|
||||
/// (i8,i32 {s/z}ext ({s/u}divrem (i8 x, i8 y)) ->
|
||||
@ -30681,7 +30695,7 @@ static SDValue combineSext(SDNode *N, SelectionDAG &DAG,
|
||||
if (SDValue R = WidenMaskArithmetic(N, DAG, DCI, Subtarget))
|
||||
return R;
|
||||
|
||||
if (SDValue NewAdd = promoteSextBeforeAddNSW(N, DAG, Subtarget))
|
||||
if (SDValue NewAdd = promoteExtBeforeAdd(N, DAG, Subtarget))
|
||||
return NewAdd;
|
||||
|
||||
return SDValue();
|
||||
@ -30773,6 +30787,9 @@ static SDValue combineZext(SDNode *N, SelectionDAG &DAG,
|
||||
if (SDValue DivRem8 = getDivRem8(N, DAG))
|
||||
return DivRem8;
|
||||
|
||||
if (SDValue NewAdd = promoteExtBeforeAdd(N, DAG, Subtarget))
|
||||
return NewAdd;
|
||||
|
||||
return SDValue();
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
||||
; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s
|
||||
|
||||
; The fundamental problem: an add separated from other arithmetic by a sext can't
|
||||
; be combined with the later instructions. However, if the first add is 'nsw',
|
||||
; then we can promote the sext ahead of that add to allow optimizations.
|
||||
; The fundamental problem: an add separated from other arithmetic by a sign or
|
||||
; zero extension can't be combined with the later instructions. However, if the
|
||||
; first add is 'nsw' or 'nuw' respectively, then we can promote the extension
|
||||
; ahead of that add to allow optimizations.
|
||||
|
||||
define i64 @add_nsw_consts(i32 %i) {
|
||||
; CHECK-LABEL: add_nsw_consts:
|
||||
@ -166,3 +167,28 @@ define void @PR20134(i32* %a, i32 %i) {
|
||||
ret void
|
||||
}
|
||||
|
||||
; The same as @PR20134 but sign extension is replaced with zero extension
|
||||
define void @PR20134_zext(i32* %a, i32 %i) {
|
||||
; CHECK: # BB#0:
|
||||
; CHECK-NEXT: movl %esi, %eax
|
||||
; CHECK-NEXT: movl 4(%rdi,%rax,4), %ecx
|
||||
; CHECK-NEXT: addl 8(%rdi,%rax,4), %ecx
|
||||
; CHECK-NEXT: movl %ecx, (%rdi,%rax,4)
|
||||
; CHECK-NEXT: retq
|
||||
|
||||
%add1 = add nuw i32 %i, 1
|
||||
%idx1 = zext i32 %add1 to i64
|
||||
%gep1 = getelementptr i32, i32* %a, i64 %idx1
|
||||
%load1 = load i32, i32* %gep1, align 4
|
||||
|
||||
%add2 = add nuw i32 %i, 2
|
||||
%idx2 = zext i32 %add2 to i64
|
||||
%gep2 = getelementptr i32, i32* %a, i64 %idx2
|
||||
%load2 = load i32, i32* %gep2, align 4
|
||||
|
||||
%add3 = add i32 %load1, %load2
|
||||
%idx3 = zext i32 %i to i64
|
||||
%gep3 = getelementptr i32, i32* %a, i64 %idx3
|
||||
store i32 %add3, i32* %gep3, align 4
|
||||
ret void
|
||||
}
|
Loading…
Reference in New Issue
Block a user