mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
[Hexagon] Add support for run-time stack overflow checking
Patch by Sundeep Kushwaha. llvm-svn: 264328
This commit is contained in:
parent
ea65bef4df
commit
80d0666040
@ -137,6 +137,10 @@ static cl::opt<int> SpillFuncThresholdOs("spill-func-threshold-Os",
|
||||
cl::Hidden, cl::desc("Specify Os spill func threshold"),
|
||||
cl::init(1), cl::ZeroOrMore);
|
||||
|
||||
static cl::opt<bool> EnableStackOVFSanitizer("enable-stackovf-sanitizer",
|
||||
cl::Hidden, cl::desc("Enable runtime checks for stack overflow."),
|
||||
cl::init(false), cl::ZeroOrMore);
|
||||
|
||||
static cl::opt<bool> EnableShrinkWrapping("hexagon-shrink-frame",
|
||||
cl::init(true), cl::Hidden, cl::ZeroOrMore,
|
||||
cl::desc("Enable stack frame shrink wrapping"));
|
||||
@ -387,6 +391,7 @@ void HexagonFrameLowering::findShrunkPrologEpilog(MachineFunction &MF,
|
||||
EpilogB = PDomB;
|
||||
}
|
||||
|
||||
|
||||
/// Perform most of the PEI work here:
|
||||
/// - saving/restoring of the callee-saved registers,
|
||||
/// - stack frame creation and destruction.
|
||||
@ -404,8 +409,9 @@ void HexagonFrameLowering::emitPrologue(MachineFunction &MF,
|
||||
if (EnableShrinkWrapping)
|
||||
findShrunkPrologEpilog(MF, PrologB, EpilogB);
|
||||
|
||||
insertCSRSpillsInBlock(*PrologB, CSI, HRI);
|
||||
insertPrologueInBlock(*PrologB);
|
||||
bool PrologueStubs = false;
|
||||
insertCSRSpillsInBlock(*PrologB, CSI, HRI, PrologueStubs);
|
||||
insertPrologueInBlock(*PrologB, PrologueStubs);
|
||||
|
||||
if (EpilogB) {
|
||||
insertCSRRestoresInBlock(*EpilogB, CSI, HRI);
|
||||
@ -422,7 +428,8 @@ void HexagonFrameLowering::emitPrologue(MachineFunction &MF,
|
||||
}
|
||||
|
||||
|
||||
void HexagonFrameLowering::insertPrologueInBlock(MachineBasicBlock &MBB) const {
|
||||
void HexagonFrameLowering::insertPrologueInBlock(MachineBasicBlock &MBB,
|
||||
bool PrologueStubs) const {
|
||||
MachineFunction &MF = *MBB.getParent();
|
||||
MachineFrameInfo *MFI = MF.getFrameInfo();
|
||||
auto &HST = MF.getSubtarget<HexagonSubtarget>();
|
||||
@ -497,6 +504,13 @@ void HexagonFrameLowering::insertPrologueInBlock(MachineBasicBlock &MBB) const {
|
||||
.addReg(SP)
|
||||
.addImm(-int64_t(MaxAlign));
|
||||
}
|
||||
|
||||
// If the stack-checking is enabled, and we spilled the callee-saved
|
||||
// registers inline (i.e. did not use a spill function), then call
|
||||
// the stack checker directly.
|
||||
if (EnableStackOVFSanitizer && !PrologueStubs)
|
||||
BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::CALLstk))
|
||||
.addExternalSymbol("__runtime_stack_check");
|
||||
}
|
||||
|
||||
void HexagonFrameLowering::insertEpilogueInBlock(MachineBasicBlock &MBB) const {
|
||||
@ -736,7 +750,7 @@ bool HexagonFrameLowering::hasFP(const MachineFunction &MF) const {
|
||||
return true;
|
||||
|
||||
if (MFI.getStackSize() > 0) {
|
||||
if (UseAllocframe)
|
||||
if (EnableStackOVFSanitizer || UseAllocframe)
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -754,8 +768,8 @@ enum SpillKind {
|
||||
SK_FromMemTailcall
|
||||
};
|
||||
|
||||
static const char *
|
||||
getSpillFunctionFor(unsigned MaxReg, SpillKind SpillType) {
|
||||
static const char *getSpillFunctionFor(unsigned MaxReg, SpillKind SpillType,
|
||||
bool Stkchk = false) {
|
||||
const char * V4SpillToMemoryFunctions[] = {
|
||||
"__save_r16_through_r17",
|
||||
"__save_r16_through_r19",
|
||||
@ -764,6 +778,14 @@ getSpillFunctionFor(unsigned MaxReg, SpillKind SpillType) {
|
||||
"__save_r16_through_r25",
|
||||
"__save_r16_through_r27" };
|
||||
|
||||
const char * V4SpillToMemoryStkchkFunctions[] = {
|
||||
"__save_r16_through_r17_stkchk",
|
||||
"__save_r16_through_r19_stkchk",
|
||||
"__save_r16_through_r21_stkchk",
|
||||
"__save_r16_through_r23_stkchk",
|
||||
"__save_r16_through_r25_stkchk",
|
||||
"__save_r16_through_r27_stkchk" };
|
||||
|
||||
const char * V4SpillFromMemoryFunctions[] = {
|
||||
"__restore_r16_through_r17_and_deallocframe",
|
||||
"__restore_r16_through_r19_and_deallocframe",
|
||||
@ -785,7 +807,8 @@ getSpillFunctionFor(unsigned MaxReg, SpillKind SpillType) {
|
||||
|
||||
switch(SpillType) {
|
||||
case SK_ToMem:
|
||||
SpillFunc = V4SpillToMemoryFunctions;
|
||||
SpillFunc = Stkchk ? V4SpillToMemoryStkchkFunctions
|
||||
: V4SpillToMemoryFunctions;
|
||||
break;
|
||||
case SK_FromMem:
|
||||
SpillFunc = V4SpillFromMemoryFunctions;
|
||||
@ -913,24 +936,34 @@ int HexagonFrameLowering::getFrameIndexReference(const MachineFunction &MF,
|
||||
|
||||
|
||||
bool HexagonFrameLowering::insertCSRSpillsInBlock(MachineBasicBlock &MBB,
|
||||
const CSIVect &CSI, const HexagonRegisterInfo &HRI) const {
|
||||
const CSIVect &CSI, const HexagonRegisterInfo &HRI,
|
||||
bool &PrologueStubs) const {
|
||||
if (CSI.empty())
|
||||
return true;
|
||||
|
||||
MachineBasicBlock::iterator MI = MBB.begin();
|
||||
PrologueStubs = false;
|
||||
MachineFunction &MF = *MBB.getParent();
|
||||
auto &HII = *MF.getSubtarget<HexagonSubtarget>().getInstrInfo();
|
||||
|
||||
if (useSpillFunction(MF, CSI)) {
|
||||
PrologueStubs = true;
|
||||
unsigned MaxReg = getMaxCalleeSavedReg(CSI, HRI);
|
||||
const char *SpillFun = getSpillFunctionFor(MaxReg, SK_ToMem);
|
||||
bool StkOvrFlowEnabled = EnableStackOVFSanitizer;
|
||||
const char *SpillFun = getSpillFunctionFor(MaxReg, SK_ToMem,
|
||||
StkOvrFlowEnabled);
|
||||
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;
|
||||
unsigned SpillOpc;
|
||||
if (StkOvrFlowEnabled)
|
||||
SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4STK_PIC
|
||||
: Hexagon::SAVE_REGISTERS_CALL_V4STK;
|
||||
else
|
||||
SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4_PIC
|
||||
: Hexagon::SAVE_REGISTERS_CALL_V4;
|
||||
|
||||
MachineInstr *SaveRegsCall =
|
||||
BuildMI(MBB, MI, DL, HII.get(SpillOpc))
|
||||
@ -1007,6 +1040,7 @@ bool HexagonFrameLowering::insertCSRRestoresInBlock(MachineBasicBlock &MBB,
|
||||
int FI = CSI[i].getFrameIdx();
|
||||
HII.loadRegFromStackSlot(MBB, MI, Reg, FI, RC, &HRI);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -84,10 +84,10 @@ private:
|
||||
|
||||
void expandAlloca(MachineInstr *AI, const HexagonInstrInfo &TII,
|
||||
unsigned SP, unsigned CF) const;
|
||||
void insertPrologueInBlock(MachineBasicBlock &MBB) const;
|
||||
void insertPrologueInBlock(MachineBasicBlock &MBB, bool PrologueStubs) const;
|
||||
void insertEpilogueInBlock(MachineBasicBlock &MBB) const;
|
||||
bool insertCSRSpillsInBlock(MachineBasicBlock &MBB, const CSIVect &CSI,
|
||||
const HexagonRegisterInfo &HRI) const;
|
||||
const HexagonRegisterInfo &HRI, bool &PrologueStubs) const;
|
||||
bool insertCSRRestoresInBlock(MachineBasicBlock &MBB, const CSIVect &CSI,
|
||||
const HexagonRegisterInfo &HRI) const;
|
||||
void insertCFIInstructionsAt(MachineBasicBlock &MBB,
|
||||
|
@ -67,6 +67,9 @@ defm J2_call: T_Calls<"">, PredRel;
|
||||
let isCodeGenOnly = 1, isCall = 1, hasSideEffects = 1, Defs = VolatileV3.Regs in
|
||||
def CALLv3nr : T_Call<"">, PredRel;
|
||||
|
||||
let isCodeGenOnly = 1, isCall = 1, hasSideEffects = 1, Defs = [PC, R31, R6, R7, P0] in
|
||||
def CALLstk : T_Call<"">, PredRel;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// J -
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -3295,6 +3295,7 @@ let isCall = 1, isBarrier = 1, isReturn = 1, isTerminator = 1,
|
||||
// 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;
|
||||
|
||||
@ -3309,14 +3310,27 @@ let isCall = 1, Defs = [R29, R30, R31, PC], isAsmParserOnly = 1 in {
|
||||
// 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;
|
||||
|
||||
let Defs = [P0] in
|
||||
def SAVE_REGISTERS_CALL_V4STK : T_Call<"">, PredRel;
|
||||
|
||||
let Defs = [P0], isExtended = 1, opExtendable = 0 in
|
||||
def SAVE_REGISTERS_CALL_V4STK_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;
|
||||
|
||||
let Defs = [R14, R15, R28, P0] in
|
||||
def SAVE_REGISTERS_CALL_V4STK_PIC : T_Call<"">, PredRel;
|
||||
|
||||
let Defs = [R14, R15, R28, P0], isExtended = 1, opExtendable = 0 in
|
||||
def SAVE_REGISTERS_CALL_V4STK_EXT_PIC : T_Call<"">, PredRel;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
44
test/CodeGen/Hexagon/runtime-stkchk.ll
Normal file
44
test/CodeGen/Hexagon/runtime-stkchk.ll
Normal file
@ -0,0 +1,44 @@
|
||||
; RUN: llc -march=hexagon -mcpu=hexagonv55 -enable-stackovf-sanitizer < %s | FileCheck %s
|
||||
|
||||
; CHECK-LABEL: foo_1
|
||||
; CHECK: __runtime_stack_check
|
||||
define i32 @foo_1(i32 %n) #0 {
|
||||
entry:
|
||||
%local = alloca [1024 x i32], align 8
|
||||
%0 = bitcast [1024 x i32]* %local to i8*
|
||||
call void @llvm.lifetime.start(i64 4096, i8* %0) #1
|
||||
%arraydecay = getelementptr inbounds [1024 x i32], [1024 x i32]* %local, i32 0, i32 0
|
||||
call void @baz_1(i32* %arraydecay) #3
|
||||
%arrayidx = getelementptr inbounds [1024 x i32], [1024 x i32]* %local, i32 0, i32 %n
|
||||
%1 = load i32, i32* %arrayidx, align 4
|
||||
call void @llvm.lifetime.end(i64 4096, i8* %0) #1
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
; CHECK-LABEL: foo_2
|
||||
; CHECK: __save_r16_through_r19_stkchk
|
||||
define i32 @foo_2(i32 %n, i32* %y) #0 {
|
||||
entry:
|
||||
%local = alloca [2048 x i32], align 8
|
||||
%0 = bitcast [2048 x i32]* %local to i8*
|
||||
call void @llvm.lifetime.start(i64 8192, i8* %0) #1
|
||||
%arraydecay = getelementptr inbounds [2048 x i32], [2048 x i32]* %local, i32 0, i32 0
|
||||
call void @baz_2(i32* %y, i32* %arraydecay) #3
|
||||
%1 = load i32, i32* %y, align 4
|
||||
%add = add nsw i32 %n, %1
|
||||
%arrayidx = getelementptr inbounds [2048 x i32], [2048 x i32]* %local, i32 0, i32 %add
|
||||
%2 = load i32, i32* %arrayidx, align 4
|
||||
call void @llvm.lifetime.end(i64 8192, i8* %0) #1
|
||||
ret i32 %2
|
||||
}
|
||||
|
||||
declare void @baz_1(i32*) #2
|
||||
declare void @baz_2(i32*, i32*) #2
|
||||
declare void @llvm.lifetime.start(i64, i8* nocapture) #1
|
||||
declare void @llvm.lifetime.end(i64, i8* nocapture) #1
|
||||
|
||||
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 = { 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 #3 = { optsize }
|
||||
|
Loading…
x
Reference in New Issue
Block a user