mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-27 13:40:30 +00:00
[Hexagon] Generate PIC-specific versions of save/restore routines
In PIC mode, the registers R14, R15 and R28 are reserved for use by the PLT handling code. This causes all functions to clobber these registers. While this is not new for regular function calls, it does also apply to save/restore functions, which do not follow the standard ABI conventions with respect to the volatile/non-volatile registers. Patch by Jyotsna Verma. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@264324 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
e4010bf95b
commit
deffc78c77
@ -536,7 +536,8 @@ void HexagonFrameLowering::insertEpilogueInBlock(MachineBasicBlock &MBB) const {
|
||||
|
||||
// Check for RESTORE_DEALLOC_RET* tail call. Don't emit an extra dealloc-
|
||||
// frame instruction if we encounter it.
|
||||
if (RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4) {
|
||||
if (RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4 ||
|
||||
RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC) {
|
||||
MachineBasicBlock::iterator It = RetI;
|
||||
++It;
|
||||
// Delete all instructions after the RESTORE (except labels).
|
||||
@ -556,7 +557,8 @@ void HexagonFrameLowering::insertEpilogueInBlock(MachineBasicBlock &MBB) const {
|
||||
if (!MBB.empty() && InsertPt != MBB.begin()) {
|
||||
MachineBasicBlock::iterator PrevIt = std::prev(InsertPt);
|
||||
unsigned COpc = PrevIt->getOpcode();
|
||||
if (COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4)
|
||||
if (COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4 ||
|
||||
COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC)
|
||||
NeedsDeallocframe = false;
|
||||
}
|
||||
|
||||
@ -922,10 +924,16 @@ bool HexagonFrameLowering::insertCSRSpillsInBlock(MachineBasicBlock &MBB,
|
||||
if (useSpillFunction(MF, CSI)) {
|
||||
unsigned MaxReg = getMaxCalleeSavedReg(CSI, HRI);
|
||||
const char *SpillFun = getSpillFunctionFor(MaxReg, SK_ToMem);
|
||||
auto &HTM = static_cast<const HexagonTargetMachine&>(MF.getTarget());
|
||||
bool IsPIC = HTM.getRelocationModel() == Reloc::PIC_;
|
||||
|
||||
// Call spill function.
|
||||
DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc() : DebugLoc();
|
||||
unsigned SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4_PIC
|
||||
: Hexagon::SAVE_REGISTERS_CALL_V4;
|
||||
|
||||
MachineInstr *SaveRegsCall =
|
||||
BuildMI(MBB, MI, DL, HII.get(Hexagon::SAVE_REGISTERS_CALL_V4))
|
||||
BuildMI(MBB, MI, DL, HII.get(SpillOpc))
|
||||
.addExternalSymbol(SpillFun);
|
||||
// Add callee-saved registers as use.
|
||||
addCalleeSaveRegistersAsImpOperand(SaveRegsCall, MaxReg, false);
|
||||
@ -965,6 +973,8 @@ bool HexagonFrameLowering::insertCSRRestoresInBlock(MachineBasicBlock &MBB,
|
||||
unsigned MaxR = getMaxCalleeSavedReg(CSI, HRI);
|
||||
SpillKind Kind = HasTC ? SK_FromMemTailcall : SK_FromMem;
|
||||
const char *RestoreFn = getSpillFunctionFor(MaxR, Kind);
|
||||
auto &HTM = static_cast<const HexagonTargetMachine&>(MF.getTarget());
|
||||
bool IsPIC = HTM.getRelocationModel() == Reloc::PIC_;
|
||||
|
||||
// Call spill function.
|
||||
DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc()
|
||||
@ -972,14 +982,16 @@ bool HexagonFrameLowering::insertCSRRestoresInBlock(MachineBasicBlock &MBB,
|
||||
MachineInstr *DeallocCall = nullptr;
|
||||
|
||||
if (HasTC) {
|
||||
unsigned ROpc = Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4;
|
||||
unsigned ROpc = IsPIC ? Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC
|
||||
: Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4;
|
||||
DeallocCall = BuildMI(MBB, MI, DL, HII.get(ROpc))
|
||||
.addExternalSymbol(RestoreFn);
|
||||
} else {
|
||||
// The block has a return.
|
||||
MachineBasicBlock::iterator It = MBB.getFirstTerminator();
|
||||
assert(It->isReturn() && std::next(It) == MBB.end());
|
||||
unsigned ROpc = Hexagon::RESTORE_DEALLOC_RET_JMP_V4;
|
||||
unsigned ROpc = IsPIC ? Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC
|
||||
: Hexagon::RESTORE_DEALLOC_RET_JMP_V4;
|
||||
DeallocCall = BuildMI(MBB, It, DL, HII.get(ROpc))
|
||||
.addExternalSymbol(RestoreFn);
|
||||
// Transfer the function live-out registers.
|
||||
|
@ -2354,7 +2354,9 @@ bool HexagonInstrInfo::isPredictedTaken(unsigned Opcode) const {
|
||||
|
||||
bool HexagonInstrInfo::isSaveCalleeSavedRegsCall(const MachineInstr *MI) const {
|
||||
return MI->getOpcode() == Hexagon::SAVE_REGISTERS_CALL_V4 ||
|
||||
MI->getOpcode() == Hexagon::SAVE_REGISTERS_CALL_V4_EXT;
|
||||
MI->getOpcode() == Hexagon::SAVE_REGISTERS_CALL_V4_EXT ||
|
||||
MI->getOpcode() == Hexagon::SAVE_REGISTERS_CALL_V4_PIC ||
|
||||
MI->getOpcode() == Hexagon::SAVE_REGISTERS_CALL_V4_EXT_PIC;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3282,21 +3282,41 @@ let isCall = 1, isBarrier = 1, isReturn = 1, isTerminator = 1,
|
||||
Defs = [R29, R30, R31, PC], isPredicable = 0, isAsmParserOnly = 1 in {
|
||||
def RESTORE_DEALLOC_RET_JMP_V4 : T_JMP<"">;
|
||||
let isExtended = 1, opExtendable = 0 in
|
||||
def RESTORE_DEALLOC_RET_JMP_V4_EXT : T_JMP<"">;
|
||||
def RESTORE_DEALLOC_RET_JMP_V4_EXT : T_JMP<"">;
|
||||
|
||||
let Defs = [R14, R15, R28, R29, R30, R31, PC] in {
|
||||
def RESTORE_DEALLOC_RET_JMP_V4_PIC : T_JMP<"">;
|
||||
|
||||
let isExtended = 1, opExtendable = 0 in
|
||||
def RESTORE_DEALLOC_RET_JMP_V4_EXT_PIC : T_JMP<"">;
|
||||
}
|
||||
}
|
||||
|
||||
// Restore registers and dealloc frame before a tail call.
|
||||
let isCall = 1, Defs = [R29, R30, R31, PC], isAsmParserOnly = 1 in {
|
||||
def RESTORE_DEALLOC_BEFORE_TAILCALL_V4 : T_Call<"">, PredRel;
|
||||
let isExtended = 1, opExtendable = 0 in
|
||||
def RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT : T_Call<"">, PredRel;
|
||||
def RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT : T_Call<"">, PredRel;
|
||||
|
||||
let Defs = [R14, R15, R28, R29, R30, R31, PC] in {
|
||||
def RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC : T_Call<"">, PredRel;
|
||||
|
||||
let isExtended = 1, opExtendable = 0 in
|
||||
def RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT_PIC : T_Call<"">, PredRel;
|
||||
}
|
||||
}
|
||||
|
||||
// Save registers function call.
|
||||
let isCall = 1, Uses = [R29, R31], isAsmParserOnly = 1 in {
|
||||
def SAVE_REGISTERS_CALL_V4 : T_Call<"">, PredRel;
|
||||
let isExtended = 1, opExtendable = 0 in
|
||||
def SAVE_REGISTERS_CALL_V4_EXT : T_Call<"">, PredRel;
|
||||
def SAVE_REGISTERS_CALL_V4_EXT : T_Call<"">, PredRel;
|
||||
|
||||
let Defs = [R14, R15, R28] in
|
||||
def SAVE_REGISTERS_CALL_V4_PIC : T_Call<"">, PredRel;
|
||||
|
||||
let Defs = [R14, R15, R28], isExtended = 1, opExtendable = 0 in
|
||||
def SAVE_REGISTERS_CALL_V4_EXT_PIC : T_Call<"">, PredRel;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
69
test/CodeGen/Hexagon/pic-regusage.ll
Normal file
69
test/CodeGen/Hexagon/pic-regusage.ll
Normal file
@ -0,0 +1,69 @@
|
||||
; RUN: llc -march=hexagon -relocation-model=pic < %s | FileCheck %s
|
||||
|
||||
; Force the use of R14 (by clobbering everything else in the inline asm).
|
||||
; Make sure that R14 is not set before the __save call (which will clobber
|
||||
; R14, R15 and R28).
|
||||
; CHECK: call __save_r16_through_r27
|
||||
; CHECK: }
|
||||
; CHECK: r14{{ *}}=
|
||||
|
||||
@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
|
||||
|
||||
; Function Attrs: nounwind optsize
|
||||
define i32 @_Z7testR14Pi(i32* nocapture %res) #0 {
|
||||
entry:
|
||||
%0 = load i32, i32* %res, align 4
|
||||
%1 = tail call { i32, i32 } asm "r0=$2\0A\09$1=add(r0,#$3)\0A\09$0=add(r0,#$4)\0A\09", "=r,=r,r,i,i,~{r0},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r15},~{r16},~{r17},~{r18},~{r19},~{r20},~{r21},~{r22},~{r23},~{r24},~{r25},~{r26},~{r27}"(i32 %0, i32 40, i32 50) #1
|
||||
%asmresult = extractvalue { i32, i32 } %1, 0
|
||||
%asmresult1 = extractvalue { i32, i32 } %1, 1
|
||||
store i32 %asmresult, i32* %res, align 4
|
||||
%call = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %asmresult1) #2
|
||||
%2 = load i32, i32* %res, align 4
|
||||
%call2 = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %2) #2
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind optsize
|
||||
declare i32 @printf(i8*, ...) #0
|
||||
|
||||
; Same as above for R15.
|
||||
; CHECK: call __save_r16_through_r27
|
||||
; CHECK: }
|
||||
; CHECK: r15{{ *}}=
|
||||
|
||||
; Function Attrs: nounwind optsize
|
||||
define i32 @_Z7testR15Pi(i32* nocapture %res) #0 {
|
||||
entry:
|
||||
%0 = load i32, i32* %res, align 4
|
||||
%1 = tail call { i32, i32 } asm "r0=$2\0A\09$1=add(r0,#$3)\0A\09$0=add(r0,#$4)\0A\09", "=r,=r,r,i,i,~{r0},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r16},~{r17},~{r18},~{r19},~{r20},~{r21},~{r22},~{r23},~{r24},~{r25},~{r26},~{r27}"(i32 %0, i32 40, i32 50) #1
|
||||
%asmresult = extractvalue { i32, i32 } %1, 0
|
||||
%asmresult1 = extractvalue { i32, i32 } %1, 1
|
||||
store i32 %asmresult, i32* %res, align 4
|
||||
%call = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %asmresult1) #2
|
||||
%2 = load i32, i32* %res, align 4
|
||||
%call2 = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %2) #2
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; Same as above for R28.
|
||||
; CHECK: call __save_r16_through_r27
|
||||
; CHECK: }
|
||||
; CHECK: r28{{ *}}=
|
||||
|
||||
; Function Attrs: nounwind optsize
|
||||
define i32 @_Z7testR28Pi(i32* nocapture %res) #0 {
|
||||
entry:
|
||||
%0 = load i32, i32* %res, align 4
|
||||
%1 = tail call { i32, i32 } asm "r0=$2\0A\09$1=add(r0,#$3)\0A\09$0=add(r0,#$4)\0A\09", "=r,=r,r,i,i,~{r0},~{r1},~{r2},~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15},~{r16},~{r17},~{r18},~{r19},~{r20},~{r21},~{r22},~{r23},~{r24},~{r25},~{r26}"(i32 %0, i32 40, i32 50) #1
|
||||
%asmresult = extractvalue { i32, i32 } %1, 0
|
||||
%asmresult1 = extractvalue { i32, i32 } %1, 1
|
||||
store i32 %asmresult, i32* %res, align 4
|
||||
%call = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %asmresult1) #2
|
||||
%2 = load i32, i32* %res, align 4
|
||||
%call2 = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %2) #2
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
attributes #0 = { nounwind optsize "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
|
||||
attributes #1 = { nounwind }
|
||||
attributes #2 = { nounwind optsize }
|
Loading…
Reference in New Issue
Block a user