Implement RETURNADDR and FRAMEADDR lowering in SPARC backend.
llvm-svn: 123310
This commit is contained in:
parent
a08cfb1299
commit
d964580fea
|
@ -743,6 +743,8 @@ const char *SparcTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
||||||
case SPISD::ITOF: return "SPISD::ITOF";
|
case SPISD::ITOF: return "SPISD::ITOF";
|
||||||
case SPISD::CALL: return "SPISD::CALL";
|
case SPISD::CALL: return "SPISD::CALL";
|
||||||
case SPISD::RET_FLAG: return "SPISD::RET_FLAG";
|
case SPISD::RET_FLAG: return "SPISD::RET_FLAG";
|
||||||
|
case SPISD::GLOBAL_BASE_REG: return "SPISD::GLOBAL_BASE_REG";
|
||||||
|
case SPISD::FLUSH: return "SPISD::FLUSH";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -990,13 +992,82 @@ static SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static SDValue getFLUSH(SDValue Op, SelectionDAG &DAG) {
|
||||||
|
DebugLoc dl = Op.getDebugLoc();
|
||||||
|
SDValue Chain = DAG.getNode(SPISD::FLUSH,
|
||||||
|
dl, MVT::Other, DAG.getEntryNode());
|
||||||
|
return Chain;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) {
|
||||||
|
MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
|
||||||
|
MFI->setFrameAddressIsTaken(true);
|
||||||
|
|
||||||
|
EVT VT = Op.getValueType();
|
||||||
|
DebugLoc dl = Op.getDebugLoc();
|
||||||
|
unsigned FrameReg = SP::I6;
|
||||||
|
|
||||||
|
uint64_t depth = Op.getConstantOperandVal(0);
|
||||||
|
|
||||||
|
SDValue FrameAddr;
|
||||||
|
if (depth == 0)
|
||||||
|
FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, FrameReg, VT);
|
||||||
|
else {
|
||||||
|
// flush first to make sure the windowed registers' values are in stack
|
||||||
|
SDValue Chain = getFLUSH(Op, DAG);
|
||||||
|
FrameAddr = DAG.getCopyFromReg(Chain, dl, FrameReg, VT);
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i != depth; ++i) {
|
||||||
|
SDValue Ptr = DAG.getNode(ISD::ADD,
|
||||||
|
dl, MVT::i32,
|
||||||
|
FrameAddr, DAG.getIntPtrConstant(56));
|
||||||
|
FrameAddr = DAG.getLoad(MVT::i32, dl,
|
||||||
|
Chain,
|
||||||
|
Ptr,
|
||||||
|
MachinePointerInfo(), false, false, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FrameAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) {
|
||||||
|
MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
|
||||||
|
MFI->setReturnAddressIsTaken(true);
|
||||||
|
|
||||||
|
EVT VT = Op.getValueType();
|
||||||
|
DebugLoc dl = Op.getDebugLoc();
|
||||||
|
unsigned RetReg = SP::I7;
|
||||||
|
|
||||||
|
uint64_t depth = Op.getConstantOperandVal(0);
|
||||||
|
|
||||||
|
SDValue RetAddr;
|
||||||
|
if (depth == 0)
|
||||||
|
RetAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, RetReg, VT);
|
||||||
|
else {
|
||||||
|
// flush first to make sure the windowed registers' values are in stack
|
||||||
|
SDValue Chain = getFLUSH(Op, DAG);
|
||||||
|
RetAddr = DAG.getCopyFromReg(Chain, dl, SP::I6, VT);
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i != depth; ++i) {
|
||||||
|
SDValue Ptr = DAG.getNode(ISD::ADD,
|
||||||
|
dl, MVT::i32,
|
||||||
|
RetAddr,
|
||||||
|
DAG.getIntPtrConstant((i == depth-1)?60:56));
|
||||||
|
RetAddr = DAG.getLoad(MVT::i32, dl,
|
||||||
|
Chain,
|
||||||
|
Ptr,
|
||||||
|
MachinePointerInfo(), false, false, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RetAddr;
|
||||||
|
}
|
||||||
|
|
||||||
SDValue SparcTargetLowering::
|
SDValue SparcTargetLowering::
|
||||||
LowerOperation(SDValue Op, SelectionDAG &DAG) const {
|
LowerOperation(SDValue Op, SelectionDAG &DAG) const {
|
||||||
switch (Op.getOpcode()) {
|
switch (Op.getOpcode()) {
|
||||||
default: llvm_unreachable("Should not custom lower this!");
|
default: llvm_unreachable("Should not custom lower this!");
|
||||||
// Frame & Return address. Currently unimplemented
|
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);
|
||||||
case ISD::RETURNADDR: return SDValue();
|
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
|
||||||
case ISD::FRAMEADDR: return SDValue();
|
|
||||||
case ISD::GlobalTLSAddress:
|
case ISD::GlobalTLSAddress:
|
||||||
llvm_unreachable("TLS not implemented for Sparc.");
|
llvm_unreachable("TLS not implemented for Sparc.");
|
||||||
case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG);
|
case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG);
|
||||||
|
|
|
@ -36,7 +36,8 @@ namespace llvm {
|
||||||
|
|
||||||
CALL, // A call instruction.
|
CALL, // A call instruction.
|
||||||
RET_FLAG, // Return with a flag operand.
|
RET_FLAG, // Return with a flag operand.
|
||||||
GLOBAL_BASE_REG // Global base reg for PIC
|
GLOBAL_BASE_REG, // Global base reg for PIC
|
||||||
|
FLUSH // FLUSH registers to stack
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,6 +127,9 @@ def call : SDNode<"SPISD::CALL", SDT_SPCall,
|
||||||
def retflag : SDNode<"SPISD::RET_FLAG", SDTNone,
|
def retflag : SDNode<"SPISD::RET_FLAG", SDTNone,
|
||||||
[SDNPHasChain, SDNPOptInGlue]>;
|
[SDNPHasChain, SDNPOptInGlue]>;
|
||||||
|
|
||||||
|
def flush : SDNode<"SPISD::FLUSH", SDTNone,
|
||||||
|
[SDNPHasChain]>;
|
||||||
|
|
||||||
def getPCX : Operand<i32> {
|
def getPCX : Operand<i32> {
|
||||||
let PrintMethod = "printGetPCX";
|
let PrintMethod = "printGetPCX";
|
||||||
}
|
}
|
||||||
|
@ -218,6 +221,12 @@ def ADJCALLSTACKUP : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2),
|
||||||
[(callseq_end timm:$amt1, timm:$amt2)]>;
|
[(callseq_end timm:$amt1, timm:$amt2)]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let hasSideEffects = 1, mayStore = 1 in
|
||||||
|
let rs2 = 0 in
|
||||||
|
def FLUSH : F3_1<0b10, 0b101011, (outs), (ins),
|
||||||
|
"flushw",
|
||||||
|
[(flush)]>;
|
||||||
|
|
||||||
// FpMOVD/FpNEGD/FpABSD - These are lowered to single-precision ops by the
|
// FpMOVD/FpNEGD/FpABSD - These are lowered to single-precision ops by the
|
||||||
// fpmover pass.
|
// fpmover pass.
|
||||||
let Predicates = [HasNoV9] in { // Only emit these in V8 mode.
|
let Predicates = [HasNoV9] in { // Only emit these in V8 mode.
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
;RUN: llc -march=sparc < %s | FileCheck %s
|
||||||
|
|
||||||
|
|
||||||
|
define i8* @frameaddr() nounwind readnone {
|
||||||
|
entry:
|
||||||
|
;CHECK: frameaddr
|
||||||
|
;CHECK: or %g0, %fp, {{.+}}
|
||||||
|
%0 = tail call i8* @llvm.frameaddress(i32 0)
|
||||||
|
ret i8* %0
|
||||||
|
}
|
||||||
|
|
||||||
|
define i8* @frameaddr2() nounwind readnone {
|
||||||
|
entry:
|
||||||
|
;CHECK: frameaddr2
|
||||||
|
;CHECK: flushw
|
||||||
|
;CHECK: ld [%fp+56], {{.+}}
|
||||||
|
;CHECK: ld [{{.+}}+56], {{.+}}
|
||||||
|
;CHECK: ld [{{.+}}+56], {{.+}}
|
||||||
|
%0 = tail call i8* @llvm.frameaddress(i32 3)
|
||||||
|
ret i8* %0
|
||||||
|
}
|
||||||
|
|
||||||
|
declare i8* @llvm.frameaddress(i32) nounwind readnone
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
define i8* @retaddr() nounwind readnone {
|
||||||
|
entry:
|
||||||
|
;CHECK: retaddr
|
||||||
|
;CHECK: or %g0, %i7, {{.+}}
|
||||||
|
%0 = tail call i8* @llvm.returnaddress(i32 0)
|
||||||
|
ret i8* %0
|
||||||
|
}
|
||||||
|
|
||||||
|
define i8* @retaddr2() nounwind readnone {
|
||||||
|
entry:
|
||||||
|
;CHECK: retaddr2
|
||||||
|
;CHECK: flushw
|
||||||
|
;CHECK: ld [%fp+56], {{.+}}
|
||||||
|
;CHECK: ld [{{.+}}+56], {{.+}}
|
||||||
|
;CHECK: ld [{{.+}}+60], {{.+}}
|
||||||
|
%0 = tail call i8* @llvm.returnaddress(i32 3)
|
||||||
|
ret i8* %0
|
||||||
|
}
|
||||||
|
|
||||||
|
declare i8* @llvm.returnaddress(i32) nounwind readnone
|
Loading…
Reference in New Issue