mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-13 23:18:58 +00:00
[PowerPC] Better lowering for add/or of a FrameIndex
If we have an add (or an or that is really an add), where one operand is a FrameIndex and the other operand is a small constant, we can combine the lowering of the FrameIndex (which is lowered as an add of the FI and a zero offset) with the constant operand. Amusingly, this is an old potential improvement entry from lib/Target/PowerPC/README.txt which had never been resolved. In short, we used to lower: %X = alloca { i32, i32 } %Y = getelementptr {i32,i32}* %X, i32 0, i32 1 ret i32* %Y as: addi 3, 1, -8 ori 3, 3, 4 blr and now we produce: addi 3, 1, -4 blr which is much more sensible. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@224071 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
934da0fc3f
commit
f329765d23
@ -112,6 +112,8 @@ namespace {
|
||||
/// base register. Return the virtual register that holds this value.
|
||||
SDNode *getGlobalBaseReg();
|
||||
|
||||
SDNode *getFrameIndex(SDNode *SN, SDNode *N, unsigned Offset = 0);
|
||||
|
||||
// Select - Convert the specified operand from a target-independent to a
|
||||
// target-specific node if it hasn't already been changed.
|
||||
SDNode *Select(SDNode *N) override;
|
||||
@ -373,6 +375,18 @@ static bool isOpcWithIntImmediate(SDNode *N, unsigned Opc, unsigned& Imm) {
|
||||
&& isInt32Immediate(N->getOperand(1).getNode(), Imm);
|
||||
}
|
||||
|
||||
SDNode *PPCDAGToDAGISel::getFrameIndex(SDNode *SN, SDNode *N, unsigned Offset) {
|
||||
SDLoc dl(SN);
|
||||
int FI = cast<FrameIndexSDNode>(N)->getIndex();
|
||||
SDValue TFI = CurDAG->getTargetFrameIndex(FI, N->getValueType(0));
|
||||
unsigned Opc = N->getValueType(0) == MVT::i32 ? PPC::ADDI : PPC::ADDI8;
|
||||
if (SN->hasOneUse())
|
||||
return CurDAG->SelectNodeTo(SN, Opc, N->getValueType(0), TFI,
|
||||
getSmallIPtrImm(Offset));
|
||||
return CurDAG->getMachineNode(Opc, dl, N->getValueType(0), TFI,
|
||||
getSmallIPtrImm(Offset));
|
||||
}
|
||||
|
||||
bool PPCDAGToDAGISel::isRunOfOnes(unsigned Val, unsigned &MB, unsigned &ME) {
|
||||
if (!Val)
|
||||
return false;
|
||||
@ -1019,16 +1033,8 @@ SDNode *PPCDAGToDAGISel::Select(SDNode *N) {
|
||||
case PPCISD::GlobalBaseReg:
|
||||
return getGlobalBaseReg();
|
||||
|
||||
case ISD::FrameIndex: {
|
||||
int FI = cast<FrameIndexSDNode>(N)->getIndex();
|
||||
SDValue TFI = CurDAG->getTargetFrameIndex(FI, N->getValueType(0));
|
||||
unsigned Opc = N->getValueType(0) == MVT::i32 ? PPC::ADDI : PPC::ADDI8;
|
||||
if (N->hasOneUse())
|
||||
return CurDAG->SelectNodeTo(N, Opc, N->getValueType(0), TFI,
|
||||
getSmallIPtrImm(0));
|
||||
return CurDAG->getMachineNode(Opc, dl, N->getValueType(0), TFI,
|
||||
getSmallIPtrImm(0));
|
||||
}
|
||||
case ISD::FrameIndex:
|
||||
return getFrameIndex(N, N);
|
||||
|
||||
case PPCISD::MFOCRF: {
|
||||
SDValue InFlag = N->getOperand(1);
|
||||
@ -1213,13 +1219,34 @@ SDNode *PPCDAGToDAGISel::Select(SDNode *N) {
|
||||
// Other cases are autogenerated.
|
||||
break;
|
||||
}
|
||||
case ISD::OR:
|
||||
case ISD::OR: {
|
||||
if (N->getValueType(0) == MVT::i32)
|
||||
if (SDNode *I = SelectBitfieldInsert(N))
|
||||
return I;
|
||||
|
||||
short Imm;
|
||||
if (N->getOperand(0)->getOpcode() == ISD::FrameIndex &&
|
||||
isIntS16Immediate(N->getOperand(1), Imm)) {
|
||||
APInt LHSKnownZero, LHSKnownOne;
|
||||
CurDAG->computeKnownBits(N->getOperand(0), LHSKnownZero, LHSKnownOne);
|
||||
|
||||
// If this is equivalent to an add, then we can fold it with the
|
||||
// FrameIndex calculation.
|
||||
if ((LHSKnownZero.getZExtValue()|~(uint64_t)Imm) == ~0ULL)
|
||||
return getFrameIndex(N, N->getOperand(0).getNode(), (int)Imm);
|
||||
}
|
||||
|
||||
// Other cases are autogenerated.
|
||||
break;
|
||||
}
|
||||
case ISD::ADD: {
|
||||
short Imm;
|
||||
if (N->getOperand(0)->getOpcode() == ISD::FrameIndex &&
|
||||
isIntS16Immediate(N->getOperand(1), Imm))
|
||||
return getFrameIndex(N, N->getOperand(0).getNode(), (int)Imm);
|
||||
|
||||
break;
|
||||
}
|
||||
case ISD::SHL: {
|
||||
unsigned Imm, SH, MB, ME;
|
||||
if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::AND, Imm) &&
|
||||
|
@ -184,25 +184,6 @@ http://gcc.gnu.org/ml/gcc-patches/2006-02/msg00133.html
|
||||
|
||||
===-------------------------------------------------------------------------===
|
||||
|
||||
Compile offsets from allocas:
|
||||
|
||||
int *%test() {
|
||||
%X = alloca { int, int }
|
||||
%Y = getelementptr {int,int}* %X, int 0, uint 1
|
||||
ret int* %Y
|
||||
}
|
||||
|
||||
into a single add, not two:
|
||||
|
||||
_test:
|
||||
addi r2, r1, -8
|
||||
addi r3, r2, 4
|
||||
blr
|
||||
|
||||
--> important for C++.
|
||||
|
||||
===-------------------------------------------------------------------------===
|
||||
|
||||
No loads or stores of the constants should be needed:
|
||||
|
||||
struct foo { double X, Y; };
|
||||
|
24
test/CodeGen/PowerPC/add-fi.ll
Normal file
24
test/CodeGen/PowerPC/add-fi.ll
Normal file
@ -0,0 +1,24 @@
|
||||
; RUN: llc -mcpu=ppc64 < %s | FileCheck %s
|
||||
target datalayout = "E-m:e-i64:64-n32:64"
|
||||
target triple = "powerpc64-unknown-linux-gnu"
|
||||
|
||||
define i32* @test1() {
|
||||
%X = alloca { i32, i32 }
|
||||
%Y = getelementptr {i32,i32}* %X, i32 0, i32 1
|
||||
ret i32* %Y
|
||||
|
||||
; CHECK-LABEL: @test1
|
||||
; CHECK: addi 3, 1, -4
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i32* @test2() {
|
||||
%X = alloca { i32, i32, i32, i32 }
|
||||
%Y = getelementptr {i32,i32,i32,i32}* %X, i32 0, i32 3
|
||||
ret i32* %Y
|
||||
|
||||
; CHECK-LABEL: @test2
|
||||
; CHECK: addi 3, 1, -4
|
||||
; CHECK: blr
|
||||
}
|
||||
|
@ -16,5 +16,5 @@ declare void @llvm.va_start(i8*) nounwind
|
||||
|
||||
; CHECK: @intvaarg
|
||||
; Make sure that the va pointer is incremented by 8 (not 4).
|
||||
; CHECK: addi{{.*}}, 8
|
||||
; CHECK: addi{{.*}}, 1, 64
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user