// 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).
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;
}
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);
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()
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.
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;
}
//===----------------------------------------------------------------------===//
--- /dev/null
+; 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 }