// cannot alias any other memory objects.
bool isSpillSlot;
- // MayNeedSP - If true the stack object triggered the creation of the stack
- // protector. We should allocate this object right after the stack
- // protector.
- bool MayNeedSP;
-
/// Alloca - If this stack object is originated from an Alloca instruction
/// this value saves the original IR allocation. Can be NULL.
const AllocaInst *Alloca;
bool PreAllocated;
StackObject(uint64_t Sz, unsigned Al, int64_t SP, bool IM,
- bool isSS, bool NSP, const AllocaInst *Val)
+ bool isSS, const AllocaInst *Val)
: SPOffset(SP), Size(Sz), Alignment(Al), isImmutable(IM),
- isSpillSlot(isSS), MayNeedSP(NSP), Alloca(Val), PreAllocated(false) {}
+ isSpillSlot(isSS), Alloca(Val), PreAllocated(false) {}
};
const TargetMachine &TM;
return Objects[ObjectIdx+NumFixedObjects].Alloca;
}
- /// NeedsStackProtector - Returns true if the object may need stack
- /// protectors.
- bool MayNeedStackProtector(int ObjectIdx) const {
- assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
- "Invalid Object Idx!");
- return Objects[ObjectIdx+NumFixedObjects].MayNeedSP;
- }
-
/// getObjectOffset - Return the assigned stack offset of the specified object
/// from the incoming stack pointer.
///
/// a nonnegative identifier to represent it.
///
int CreateStackObject(uint64_t Size, unsigned Alignment, bool isSS,
- bool MayNeedSP = false, const AllocaInst *Alloca = 0);
+ const AllocaInst *Alloca = 0);
/// CreateSpillStackObject - Create a new statically sized stack object that
/// represents a spill slot, returning a nonnegative identifier to represent
/// variable sized object is created, whether or not the index returned is
/// actually used.
///
- int CreateVariableSizedObject(unsigned Alignment);
+ int CreateVariableSizedObject(unsigned Alignment, const AllocaInst *Alloca);
/// getCalleeSavedInfo - Returns a reference to call saved info vector for the
/// current function.
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/ValueMap.h"
+#include "llvm/Analysis/Dominators.h"
#include "llvm/Pass.h"
#include "llvm/Target/TargetLowering.h"
namespace llvm {
-class DominatorTree;
class Function;
class Module;
class PHINode;
#define DEBUG_TYPE "localstackalloc"
#include "llvm/CodeGen/Passes.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/StackProtector.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Instructions.h"
class LocalStackSlotPass: public MachineFunctionPass {
SmallVector<int64_t,16> LocalOffsets;
+ /// StackObjSet - A set of stack object indexes
+ typedef SmallSetVector<int, 8> StackObjSet;
void AdjustStackOffset(MachineFrameInfo *MFI, int FrameIdx, int64_t &Offset,
bool StackGrowsDown, unsigned &MaxAlign);
+ void AssignProtectedObjSet(const StackObjSet &UnassignedObjs,
+ SmallSet<int, 16> &ProtectedObjs,
+ MachineFrameInfo *MFI, bool StackGrowsDown,
+ int64_t &Offset, unsigned &MaxAlign);
void calculateFrameObjectOffsets(MachineFunction &Fn);
bool insertFrameReferenceRegisters(MachineFunction &Fn);
public:
static char ID; // Pass identification, replacement for typeid
- explicit LocalStackSlotPass() : MachineFunctionPass(ID) { }
+ explicit LocalStackSlotPass() : MachineFunctionPass(ID) {
+ initializeLocalStackSlotPassPass(*PassRegistry::getPassRegistry());
+ }
bool runOnMachineFunction(MachineFunction &MF);
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesCFG();
+ AU.addRequired<StackProtector>();
MachineFunctionPass::getAnalysisUsage(AU);
}
char LocalStackSlotPass::ID = 0;
char &llvm::LocalStackSlotAllocationID = LocalStackSlotPass::ID;
-INITIALIZE_PASS(LocalStackSlotPass, "localstackalloc",
- "Local Stack Slot Allocation", false, false)
+INITIALIZE_PASS_BEGIN(LocalStackSlotPass, "localstackalloc",
+ "Local Stack Slot Allocation", false, false)
+INITIALIZE_PASS_DEPENDENCY(StackProtector)
+INITIALIZE_PASS_END(LocalStackSlotPass, "localstackalloc",
+ "Local Stack Slot Allocation", false, false)
+
bool LocalStackSlotPass::runOnMachineFunction(MachineFunction &MF) {
MachineFrameInfo *MFI = MF.getFrameInfo();
++NumAllocations;
}
+/// AssignProtectedObjSet - Helper function to assign large stack objects (i.e.,
+/// those required to be close to the Stack Protector) to stack offsets.
+void LocalStackSlotPass::AssignProtectedObjSet(const StackObjSet &UnassignedObjs,
+ SmallSet<int, 16> &ProtectedObjs,
+ MachineFrameInfo *MFI,
+ bool StackGrowsDown, int64_t &Offset,
+ unsigned &MaxAlign) {
+
+ for (StackObjSet::const_iterator I = UnassignedObjs.begin(),
+ E = UnassignedObjs.end(); I != E; ++I) {
+ int i = *I;
+ AdjustStackOffset(MFI, i, Offset, StackGrowsDown, MaxAlign);
+ ProtectedObjs.insert(i);
+ }
+}
+
/// calculateFrameObjectOffsets - Calculate actual frame offsets for all of the
/// abstract stack objects.
///
TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsDown;
int64_t Offset = 0;
unsigned MaxAlign = 0;
+ StackProtector *SP = &getAnalysis<StackProtector>();
// Make sure that the stack protector comes before the local variables on the
// stack.
- SmallSet<int, 16> LargeStackObjs;
+ SmallSet<int, 16> ProtectedObjs;
if (MFI->getStackProtectorIndex() >= 0) {
+ StackObjSet LargeArrayObjs;
AdjustStackOffset(MFI, MFI->getStackProtectorIndex(), Offset,
StackGrowsDown, MaxAlign);
continue;
if (MFI->getStackProtectorIndex() == (int)i)
continue;
- if (!MFI->MayNeedStackProtector(i))
- continue;
- AdjustStackOffset(MFI, i, Offset, StackGrowsDown, MaxAlign);
- LargeStackObjs.insert(i);
+ switch (SP->getSSPLayout(MFI->getObjectAllocation(i))) {
+ case StackProtector::SSPLK_None:
+ case StackProtector::SSPLK_SmallArray:
+ case StackProtector::SSPLK_AddrOf:
+ continue;
+ case StackProtector::SSPLK_LargeArray:
+ LargeArrayObjs.insert(i);
+ continue;
+ }
+ llvm_unreachable("Unexpected SSPLayoutKind.");
}
+
+ AssignProtectedObjSet(LargeArrayObjs, ProtectedObjs, MFI, StackGrowsDown,
+ Offset, MaxAlign);
}
// Then assign frame offsets to stack objects that are not used to spill
continue;
if (MFI->getStackProtectorIndex() == (int)i)
continue;
- if (LargeStackObjs.count(i))
+ if (ProtectedObjs.count(i))
continue;
AdjustStackOffset(MFI, i, Offset, StackGrowsDown, MaxAlign);
/// a nonnegative identifier to represent it.
///
int MachineFrameInfo::CreateStackObject(uint64_t Size, unsigned Alignment,
- bool isSS, bool MayNeedSP, const AllocaInst *Alloca) {
+ bool isSS, const AllocaInst *Alloca) {
assert(Size != 0 && "Cannot allocate zero size stack objects!");
Alignment =
clampStackAlignment(!getFrameLowering()->isStackRealignable() ||
!RealignOption,
Alignment, getFrameLowering()->getStackAlignment());
- Objects.push_back(StackObject(Size, Alignment, 0, false, isSS, MayNeedSP,
- Alloca));
+ Objects.push_back(StackObject(Size, Alignment, 0, false, isSS, Alloca));
int Index = (int)Objects.size() - NumFixedObjects - 1;
assert(Index >= 0 && "Bad frame index!");
ensureMaxAlignment(Alignment);
clampStackAlignment(!getFrameLowering()->isStackRealignable() ||
!RealignOption,
Alignment, getFrameLowering()->getStackAlignment());
- CreateStackObject(Size, Alignment, true, false);
+ CreateStackObject(Size, Alignment, true);
int Index = (int)Objects.size() - NumFixedObjects - 1;
ensureMaxAlignment(Alignment);
return Index;
/// variable sized object is created, whether or not the index returned is
/// actually used.
///
-int MachineFrameInfo::CreateVariableSizedObject(unsigned Alignment) {
+int MachineFrameInfo::CreateVariableSizedObject(unsigned Alignment,
+ const AllocaInst *Alloca) {
HasVarSizedObjects = true;
Alignment =
clampStackAlignment(!getFrameLowering()->isStackRealignable() ||
!RealignOption,
Alignment, getFrameLowering()->getStackAlignment());
- Objects.push_back(StackObject(0, Alignment, 0, false, false, true, 0));
+ Objects.push_back(StackObject(0, Alignment, 0, false, false, Alloca));
ensureMaxAlignment(Alignment);
return (int)Objects.size()-NumFixedObjects-1;
}
Align, getFrameLowering()->getStackAlignment());
Objects.insert(Objects.begin(), StackObject(Size, Align, SPOffset, Immutable,
/*isSS*/ false,
- /*NeedSP*/ false,
/*Alloca*/ 0));
return -++NumFixedObjects;
}
AU.addPreserved("domfrontier");
AU.addPreserved("loops");
AU.addPreserved("lda");
+ AU.addPreserved("stack-protector");
FunctionPass::getAnalysisUsage(AU);
}
/// Add common passes that perform LLVM IR to IR transforms in preparation for
/// instruction selection.
void TargetPassConfig::addISelPrepare() {
- addPass(createStackProtectorPass(TM));
-
addPreISel();
+ addPass(createStackProtectorPass(TM));
+
if (PrintISelInput)
addPass(createPrintFunctionPass("\n\n"
"*** Final LLVM Code input to ISel ***\n",
#include "PrologEpilogInserter.h"
#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/CodeGen/StackProtector.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/CommandLine.h"
"Prologue/Epilogue Insertion", false, false)
INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
+INITIALIZE_PASS_DEPENDENCY(StackProtector)
INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
INITIALIZE_PASS_END(PEI, "prologepilog",
"Prologue/Epilogue Insertion & Frame Finalization",
AU.setPreservesCFG();
AU.addPreserved<MachineLoopInfo>();
AU.addPreserved<MachineDominatorTree>();
+ AU.addRequired<StackProtector>();
AU.addRequired<TargetPassConfig>();
MachineFunctionPass::getAnalysisUsage(AU);
}
return;
}
+/// StackObjSet - A set of stack object indexes
+typedef SmallSetVector<int, 8> StackObjSet;
+
/// runOnMachineFunction - Insert prolog/epilog code and replace abstract
/// frame indexes with appropriate references.
///
}
}
+/// AssignProtectedObjSet - Helper function to assign large stack objects (i.e.,
+/// those required to be close to the Stack Protector) to stack offsets.
+static void
+AssignProtectedObjSet(const StackObjSet &UnassignedObjs,
+ SmallSet<int, 16> &ProtectedObjs,
+ MachineFrameInfo *MFI, bool StackGrowsDown,
+ int64_t &Offset, unsigned &MaxAlign) {
+
+ for (StackObjSet::const_iterator I = UnassignedObjs.begin(),
+ E = UnassignedObjs.end(); I != E; ++I) {
+ int i = *I;
+ AdjustStackOffset(MFI, i, StackGrowsDown, Offset, MaxAlign);
+ ProtectedObjs.insert(i);
+ }
+}
+
/// calculateFrameObjectOffsets - Calculate actual frame offsets for all of the
/// abstract stack objects.
///
void PEI::calculateFrameObjectOffsets(MachineFunction &Fn) {
const TargetFrameLowering &TFI = *Fn.getTarget().getFrameLowering();
+ StackProtector *SP = &getAnalysis<StackProtector>();
bool StackGrowsDown =
TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsDown;
// Make sure that the stack protector comes before the local variables on the
// stack.
- SmallSet<int, 16> LargeStackObjs;
+ SmallSet<int, 16> ProtectedObjs;
if (MFI->getStackProtectorIndex() >= 0) {
+ StackObjSet LargeArrayObjs;
AdjustStackOffset(MFI, MFI->getStackProtectorIndex(), StackGrowsDown,
Offset, MaxAlign);
continue;
if (MFI->getStackProtectorIndex() == (int)i)
continue;
- if (!MFI->MayNeedStackProtector(i))
- continue;
- AdjustStackOffset(MFI, i, StackGrowsDown, Offset, MaxAlign);
- LargeStackObjs.insert(i);
+ switch (SP->getSSPLayout(MFI->getObjectAllocation(i))) {
+ case StackProtector::SSPLK_None:
+ case StackProtector::SSPLK_SmallArray:
+ case StackProtector::SSPLK_AddrOf:
+ continue;
+ case StackProtector::SSPLK_LargeArray:
+ LargeArrayObjs.insert(i);
+ continue;
+ }
+ llvm_unreachable("Unexpected SSPLayoutKind.");
}
+
+ AssignProtectedObjSet(LargeArrayObjs, ProtectedObjs, MFI, StackGrowsDown,
+ Offset, MaxAlign);
}
// Then assign frame offsets to stack objects that are not used to spill
continue;
if (MFI->getStackProtectorIndex() == (int)i)
continue;
- if (LargeStackObjs.count(i))
+ if (ProtectedObjs.count(i))
continue;
AdjustStackOffset(MFI, i, StackGrowsDown, Offset, MaxAlign);
TySize *= CUI->getZExtValue(); // Get total allocated size.
if (TySize == 0) TySize = 1; // Don't create zero-sized stack objects.
- // The object may need to be placed onto the stack near the stack
- // protector if one exists. Determine here if this object is a suitable
- // candidate. I.e., it would trigger the creation of a stack protector.
- bool MayNeedSP =
- (AI->isArrayAllocation() ||
- (TySize >= 8 && isa<ArrayType>(Ty) &&
- cast<ArrayType>(Ty)->getElementType()->isIntegerTy(8)));
StaticAllocaMap[AI] =
- MF->getFrameInfo()->CreateStackObject(TySize, Align, false,
- MayNeedSP, AI);
+ MF->getFrameInfo()->CreateStackObject(TySize, Align, false, AI);
}
for (; BB != EB; ++BB)
// Inform the Frame Information that we have just allocated a variable-sized
// object.
- FuncInfo.MF->getFrameInfo()->CreateVariableSizedObject(Align ? Align : 1);
+ FuncInfo.MF->getFrameInfo()->CreateVariableSizedObject(Align ? Align : 1, &I);
}
void SelectionDAGBuilder::visitLoad(const LoadInst &I) {
#include "llvm/CodeGen/Passes.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
-#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/Constants.h"
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<MachineFunctionAnalysis>();
AU.addPreserved<MachineFunctionAnalysis>();
+ AU.addPreserved("stack-protector");
FunctionPass::getAnalysisUsage(AU);
}
};
void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<DataLayout>();
+ AU.addPreserved("stack-protector");
AU.addPreserved<MachineFunctionAnalysis>();
}
void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<DataLayout>();
+ AU.addPreserved("stack-protector");
AU.addPreserved<MachineFunctionAnalysis>();
}
NVPTXSplitBBatBar() : FunctionPass(ID) {}
void getAnalysisUsage(AnalysisUsage &AU) const {
+ AU.addPreserved("stack-protector");
AU.addPreserved<MachineFunctionAnalysis>();
}
virtual bool runOnFunction(Function &F);
const Value *Op1 = I.getArgOperand(0); // The guard's value.
const AllocaInst *Slot = cast<AllocaInst>(I.getArgOperand(1));
+ MFI.setStackProtectorIndex(FuncInfo.StaticAllocaMap[Slot]);
+
// Grab the frame index.
X86AddressMode AM;
if (!X86SelectAddress(Slot, AM)) return false;
unsigned Size = ArgDI->Flags.getByValSize();
unsigned Align = std::max(StackSlotSize, ArgDI->Flags.getByValAlign());
// Create a new object on the stack and copy the pointee into it.
- int FI = MFI->CreateStackObject(Size, Align, false, false);
+ int FI = MFI->CreateStackObject(Size, Align, false);
SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
InVals.push_back(FIN);
MemOps.push_back(DAG.getMemcpy(Chain, dl, FIN, ArgDI->SDV,
--- /dev/null
+; RUN: llc < %s -disable-fp-elim -march=arm -o - | FileCheck %s
+; This test is fairly fragile. The goal is to ensure that "large" stack
+; objects are allocated closest to the stack protector (i.e., farthest away
+; from the Stack Pointer.) In standard SSP mode this means that large (>=
+; ssp-buffer-size) arrays and structures containing such arrays are
+; closet to the protector. With sspstrong and sspreq this means large
+; arrays/structures-with-arrays are closest, followed by small (< ssp-buffer-size)
+; arrays/structures-with-arrays, and then addr-taken variables.
+;
+; Ideally, we only want verify that the objects appear in the correct groups
+; and that the groups have the correct relative stack offset. The ordering
+; within a group is not relevant to this test. Unfortunately, there is not
+; an elegant way to do this, so just match the offset for each object.
+
+%struct.struct_large_char = type { [8 x i8] }
+%struct.struct_large_char2 = type { [2 x i8], [8 x i8] }
+%struct.struct_small_char = type { [2 x i8] }
+%struct.struct_large_nonchar = type { [8 x i32] }
+%struct.struct_small_nonchar = type { [2 x i16] }
+
+define void @layout_ssp() ssp {
+entry:
+; Expected stack layout for ssp is
+; 180 large_char . Group 1, nested arrays, arrays >= ssp-buffer-size
+; 172 struct_large_char .
+; 168 scalar1 | Everything else
+; 164 scalar2
+; 160 scalar3
+; 156 addr-of
+; 152 small_nonchar (84+68)
+; 112 large_nonchar
+; 110 small_char
+; 108 struct_small_char
+; 72 struct_large_nonchar
+; 68 struct_small_nonchar
+
+; CHECK: layout_ssp:
+; r[[SP]] is used as an offset into the stack later
+; CHECK: add r[[SP:[0-9]+]], sp, #68
+
+; CHECK: bl get_scalar1
+; CHECK: str r0, [sp, #168]
+; CHECK: bl end_scalar1
+
+; CHECK: bl get_scalar2
+; CHECK: str r0, [sp, #164]
+; CHECK: bl end_scalar2
+
+; CHECK: bl get_scalar3
+; CHECK: str r0, [sp, #160]
+; CHECK: bl end_scalar3
+
+; CHECK: bl get_addrof
+; CHECK: str r0, [sp, #156]
+; CHECK: bl end_addrof
+
+; CHECK: get_small_nonchar
+; CHECK: strh r0, [r[[SP]], #84]
+; CHECK: bl end_small_nonchar
+
+; CHECK: bl get_large_nonchar
+; CHECK: str r0, [sp, #112]
+; CHECK: bl end_large_nonchar
+
+; CHECK: bl get_small_char
+; CHECK: strb r0, [sp, #110]
+; CHECK: bl end_small_char
+
+; CHECK: bl get_large_char
+; CHECK: strb r0, [sp, #180]
+; CHECK: bl end_large_char
+
+; CHECK: bl get_struct_large_char
+; CHECK: strb r0, [sp, #172]
+; CHECK: bl end_struct_large_char
+
+; CHECK: bl get_struct_small_char
+; CHECK: strb r0, [sp, #108]
+; CHECK: bl end_struct_small_char
+
+; CHECK: bl get_struct_large_nonchar
+; CHECK:str r0, [sp, #72]
+; CHECK: bl end_struct_large_nonchar
+
+; CHECK: bl get_struct_small_nonchar
+; CHECK: strh r0, [r[[SP]]]
+; CHECK: bl end_struct_small_nonchar
+ %x = alloca i32, align 4
+ %y = alloca i32, align 4
+ %z = alloca i32, align 4
+ %ptr = alloca i32, align 4
+ %small2 = alloca [2 x i16], align 2
+ %large2 = alloca [8 x i32], align 16
+ %small = alloca [2 x i8], align 1
+ %large = alloca [8 x i8], align 1
+ %a = alloca %struct.struct_large_char, align 1
+ %b = alloca %struct.struct_small_char, align 1
+ %c = alloca %struct.struct_large_nonchar, align 8
+ %d = alloca %struct.struct_small_nonchar, align 2
+ %call = call i32 @get_scalar1()
+ store i32 %call, i32* %x, align 4
+ call void @end_scalar1()
+ %call1 = call i32 @get_scalar2()
+ store i32 %call1, i32* %y, align 4
+ call void @end_scalar2()
+ %call2 = call i32 @get_scalar3()
+ store i32 %call2, i32* %z, align 4
+ call void @end_scalar3()
+ %call3 = call i32 @get_addrof()
+ store i32 %call3, i32* %ptr, align 4
+ call void @end_addrof()
+ %call4 = call signext i16 @get_small_nonchar()
+ %arrayidx = getelementptr inbounds [2 x i16]* %small2, i32 0, i64 0
+ store i16 %call4, i16* %arrayidx, align 2
+ call void @end_small_nonchar()
+ %call5 = call i32 @get_large_nonchar()
+ %arrayidx6 = getelementptr inbounds [8 x i32]* %large2, i32 0, i64 0
+ store i32 %call5, i32* %arrayidx6, align 4
+ call void @end_large_nonchar()
+ %call7 = call signext i8 @get_small_char()
+ %arrayidx8 = getelementptr inbounds [2 x i8]* %small, i32 0, i64 0
+ store i8 %call7, i8* %arrayidx8, align 1
+ call void @end_small_char()
+ %call9 = call signext i8 @get_large_char()
+ %arrayidx10 = getelementptr inbounds [8 x i8]* %large, i32 0, i64 0
+ store i8 %call9, i8* %arrayidx10, align 1
+ call void @end_large_char()
+ %call11 = call signext i8 @get_struct_large_char()
+ %foo = getelementptr inbounds %struct.struct_large_char* %a, i32 0, i32 0
+ %arrayidx12 = getelementptr inbounds [8 x i8]* %foo, i32 0, i64 0
+ store i8 %call11, i8* %arrayidx12, align 1
+ call void @end_struct_large_char()
+ %call13 = call signext i8 @get_struct_small_char()
+ %foo14 = getelementptr inbounds %struct.struct_small_char* %b, i32 0, i32 0
+ %arrayidx15 = getelementptr inbounds [2 x i8]* %foo14, i32 0, i64 0
+ store i8 %call13, i8* %arrayidx15, align 1
+ call void @end_struct_small_char()
+ %call16 = call i32 @get_struct_large_nonchar()
+ %foo17 = getelementptr inbounds %struct.struct_large_nonchar* %c, i32 0, i32 0
+ %arrayidx18 = getelementptr inbounds [8 x i32]* %foo17, i32 0, i64 0
+ store i32 %call16, i32* %arrayidx18, align 4
+ call void @end_struct_large_nonchar()
+ %call19 = call signext i16 @get_struct_small_nonchar()
+ %foo20 = getelementptr inbounds %struct.struct_small_nonchar* %d, i32 0, i32 0
+ %arrayidx21 = getelementptr inbounds [2 x i16]* %foo20, i32 0, i64 0
+ store i16 %call19, i16* %arrayidx21, align 2
+ call void @end_struct_small_nonchar()
+ %arraydecay = getelementptr inbounds [8 x i8]* %large, i32 0, i32 0
+ %arraydecay22 = getelementptr inbounds [2 x i8]* %small, i32 0, i32 0
+ %arraydecay23 = getelementptr inbounds [8 x i32]* %large2, i32 0, i32 0
+ %arraydecay24 = getelementptr inbounds [2 x i16]* %small2, i32 0, i32 0
+ %0 = load i32* %x, align 4
+ %1 = load i32* %y, align 4
+ %2 = load i32* %z, align 4
+ %coerce.dive = getelementptr %struct.struct_large_char* %a, i32 0, i32 0
+ %3 = bitcast [8 x i8]* %coerce.dive to i64*
+ %4 = load i64* %3, align 1
+ %coerce.dive25 = getelementptr %struct.struct_small_char* %b, i32 0, i32 0
+ %5 = bitcast [2 x i8]* %coerce.dive25 to i16*
+ %6 = load i16* %5, align 1
+ %coerce.dive26 = getelementptr %struct.struct_small_nonchar* %d, i32 0, i32 0
+ %7 = bitcast [2 x i16]* %coerce.dive26 to i32*
+ %8 = load i32* %7, align 1
+ call void @takes_all(i64 %4, i16 %6, %struct.struct_large_nonchar* byval align 8 %c, i32 %8, i8* %arraydecay, i8* %arraydecay22, i32* %arraydecay23, i16* %arraydecay24, i32* %ptr, i32 %0, i32 %1, i32 %2)
+ ret void
+}
+
+declare i32 @get_scalar1()
+declare void @end_scalar1()
+
+declare i32 @get_scalar2()
+declare void @end_scalar2()
+
+declare i32 @get_scalar3()
+declare void @end_scalar3()
+
+declare i32 @get_addrof()
+declare void @end_addrof()
+
+declare signext i16 @get_small_nonchar()
+declare void @end_small_nonchar()
+
+declare i32 @get_large_nonchar()
+declare void @end_large_nonchar()
+
+declare signext i8 @get_small_char()
+declare void @end_small_char()
+
+declare signext i8 @get_large_char()
+declare void @end_large_char()
+
+declare signext i8 @get_struct_large_char()
+declare void @end_struct_large_char()
+
+declare signext i8 @get_struct_large_char2()
+declare void @end_struct_large_char2()
+
+declare signext i8 @get_struct_small_char()
+declare void @end_struct_small_char()
+
+declare i32 @get_struct_large_nonchar()
+declare void @end_struct_large_nonchar()
+
+declare signext i16 @get_struct_small_nonchar()
+declare void @end_struct_small_nonchar()
+
+declare void @takes_all(i64, i16, %struct.struct_large_nonchar* byval align 8, i32, i8*, i8*, i32*, i16*, i32*, i32, i32, i32)
--- /dev/null
+; RUN: llc < %s -disable-fp-elim -mtriple=x86_64-pc-linux-gnu -mcpu=corei7 -o - | FileCheck %s
+; This test is fairly fragile. The goal is to ensure that "large" stack
+; objects are allocated closest to the stack protector (i.e., farthest away
+; from the Stack Pointer.) In standard SSP mode this means that large (>=
+; ssp-buffer-size) arrays and structures containing such arrays are
+; closet to the protector. With sspstrong and sspreq this means large
+; arrays/structures-with-arrays are closest, followed by small (< ssp-buffer-size)
+; arrays/structures-with-arrays, and then addr-taken variables.
+;
+; Ideally, we only want verify that the objects appear in the correct groups
+; and that the groups have the correct relative stack offset. The ordering
+; within a group is not relevant to this test. Unfortunately, there is not
+; an elegant way to do this, so just match the offset for each object.
+; RUN: llc < %s -disable-fp-elim -mtriple=x86_64-unknown-unknown -O0 -mcpu=corei7 -o - \
+; RUN: | FileCheck --check-prefix=FAST-NON-LIN %s
+; FastISel was not setting the StackProtectorIndex when lowering
+; Intrinsic::stackprotector and as a result the stack re-arrangement code was
+; never applied. This problem only shows up on non-Linux platforms because on
+; Linux the stack protector cookie is loaded from a special address space which
+; always triggers standard ISel. Run a basic test to ensure that at -O0
+; on a non-linux target the data layout rules are triggered.
+
+%struct.struct_large_char = type { [8 x i8] }
+%struct.struct_large_char2 = type { [2 x i8], [8 x i8] }
+%struct.struct_small_char = type { [2 x i8] }
+%struct.struct_large_nonchar = type { [8 x i32] }
+%struct.struct_small_nonchar = type { [2 x i16] }
+
+define void @layout_ssp() ssp {
+entry:
+; Expected stack layout for ssp is
+; -16 large_char . Group 1, nested arrays, arrays >= ssp-buffer-size
+; -24 struct_large_char .
+; -28 scalar1 | Everything else
+; -32 scalar2
+; -36 scalar3
+; -40 addr-of
+; -44 small_nonchar
+; -80 large_nonchar
+; -82 small_char
+; -88 struct_small_char
+; -120 struct_large_nonchar
+; -128 struct_small_nonchar
+
+; CHECK: layout_ssp:
+; CHECK: call{{l|q}} get_scalar1
+; CHECK: movl %eax, -28(
+; CHECK: call{{l|q}} end_scalar1
+
+; CHECK: call{{l|q}} get_scalar2
+; CHECK: movl %eax, -32(
+; CHECK: call{{l|q}} end_scalar2
+
+; CHECK: call{{l|q}} get_scalar3
+; CHECK: movl %eax, -36(
+; CHECK: call{{l|q}} end_scalar3
+
+; CHECK: call{{l|q}} get_addrof
+; CHECK: movl %eax, -40(
+; CHECK: call{{l|q}} end_addrof
+
+; CHECK: get_small_nonchar
+; CHECK: movw %ax, -44(
+; CHECK: call{{l|q}} end_small_nonchar
+
+; CHECK: call{{l|q}} get_large_nonchar
+; CHECK: movl %eax, -80(
+; CHECK: call{{l|q}} end_large_nonchar
+
+; CHECK: call{{l|q}} get_small_char
+; CHECK: movb %al, -82(
+; CHECK: call{{l|q}} end_small_char
+
+; CHECK: call{{l|q}} get_large_char
+; CHECK: movb %al, -16(
+; CHECK: call{{l|q}} end_large_char
+
+; CHECK: call{{l|q}} get_struct_large_char
+; CHECK: movb %al, -24(
+; CHECK: call{{l|q}} end_struct_large_char
+
+; CHECK: call{{l|q}} get_struct_small_char
+; CHECK: movb %al, -88(
+; CHECK: call{{l|q}} end_struct_small_char
+
+; CHECK: call{{l|q}} get_struct_large_nonchar
+; CHECK: movl %eax, -120(
+; CHECK: call{{l|q}} end_struct_large_nonchar
+
+; CHECK: call{{l|q}} get_struct_small_nonchar
+; CHECK: movw %ax, -128(
+; CHECK: call{{l|q}} end_struct_small_nonchar
+ %x = alloca i32, align 4
+ %y = alloca i32, align 4
+ %z = alloca i32, align 4
+ %ptr = alloca i32, align 4
+ %small2 = alloca [2 x i16], align 2
+ %large2 = alloca [8 x i32], align 16
+ %small = alloca [2 x i8], align 1
+ %large = alloca [8 x i8], align 1
+ %a = alloca %struct.struct_large_char, align 1
+ %b = alloca %struct.struct_small_char, align 1
+ %c = alloca %struct.struct_large_nonchar, align 8
+ %d = alloca %struct.struct_small_nonchar, align 2
+ %call = call i32 @get_scalar1()
+ store i32 %call, i32* %x, align 4
+ call void @end_scalar1()
+ %call1 = call i32 @get_scalar2()
+ store i32 %call1, i32* %y, align 4
+ call void @end_scalar2()
+ %call2 = call i32 @get_scalar3()
+ store i32 %call2, i32* %z, align 4
+ call void @end_scalar3()
+ %call3 = call i32 @get_addrof()
+ store i32 %call3, i32* %ptr, align 4
+ call void @end_addrof()
+ %call4 = call signext i16 @get_small_nonchar()
+ %arrayidx = getelementptr inbounds [2 x i16]* %small2, i32 0, i64 0
+ store i16 %call4, i16* %arrayidx, align 2
+ call void @end_small_nonchar()
+ %call5 = call i32 @get_large_nonchar()
+ %arrayidx6 = getelementptr inbounds [8 x i32]* %large2, i32 0, i64 0
+ store i32 %call5, i32* %arrayidx6, align 4
+ call void @end_large_nonchar()
+ %call7 = call signext i8 @get_small_char()
+ %arrayidx8 = getelementptr inbounds [2 x i8]* %small, i32 0, i64 0
+ store i8 %call7, i8* %arrayidx8, align 1
+ call void @end_small_char()
+ %call9 = call signext i8 @get_large_char()
+ %arrayidx10 = getelementptr inbounds [8 x i8]* %large, i32 0, i64 0
+ store i8 %call9, i8* %arrayidx10, align 1
+ call void @end_large_char()
+ %call11 = call signext i8 @get_struct_large_char()
+ %foo = getelementptr inbounds %struct.struct_large_char* %a, i32 0, i32 0
+ %arrayidx12 = getelementptr inbounds [8 x i8]* %foo, i32 0, i64 0
+ store i8 %call11, i8* %arrayidx12, align 1
+ call void @end_struct_large_char()
+ %call13 = call signext i8 @get_struct_small_char()
+ %foo14 = getelementptr inbounds %struct.struct_small_char* %b, i32 0, i32 0
+ %arrayidx15 = getelementptr inbounds [2 x i8]* %foo14, i32 0, i64 0
+ store i8 %call13, i8* %arrayidx15, align 1
+ call void @end_struct_small_char()
+ %call16 = call i32 @get_struct_large_nonchar()
+ %foo17 = getelementptr inbounds %struct.struct_large_nonchar* %c, i32 0, i32 0
+ %arrayidx18 = getelementptr inbounds [8 x i32]* %foo17, i32 0, i64 0
+ store i32 %call16, i32* %arrayidx18, align 4
+ call void @end_struct_large_nonchar()
+ %call19 = call signext i16 @get_struct_small_nonchar()
+ %foo20 = getelementptr inbounds %struct.struct_small_nonchar* %d, i32 0, i32 0
+ %arrayidx21 = getelementptr inbounds [2 x i16]* %foo20, i32 0, i64 0
+ store i16 %call19, i16* %arrayidx21, align 2
+ call void @end_struct_small_nonchar()
+ %arraydecay = getelementptr inbounds [8 x i8]* %large, i32 0, i32 0
+ %arraydecay22 = getelementptr inbounds [2 x i8]* %small, i32 0, i32 0
+ %arraydecay23 = getelementptr inbounds [8 x i32]* %large2, i32 0, i32 0
+ %arraydecay24 = getelementptr inbounds [2 x i16]* %small2, i32 0, i32 0
+ %0 = load i32* %x, align 4
+ %1 = load i32* %y, align 4
+ %2 = load i32* %z, align 4
+ %coerce.dive = getelementptr %struct.struct_large_char* %a, i32 0, i32 0
+ %3 = bitcast [8 x i8]* %coerce.dive to i64*
+ %4 = load i64* %3, align 1
+ %coerce.dive25 = getelementptr %struct.struct_small_char* %b, i32 0, i32 0
+ %5 = bitcast [2 x i8]* %coerce.dive25 to i16*
+ %6 = load i16* %5, align 1
+ %coerce.dive26 = getelementptr %struct.struct_small_nonchar* %d, i32 0, i32 0
+ %7 = bitcast [2 x i16]* %coerce.dive26 to i32*
+ %8 = load i32* %7, align 1
+ call void @takes_all(i64 %4, i16 %6, %struct.struct_large_nonchar* byval align 8 %c, i32 %8, i8* %arraydecay, i8* %arraydecay22, i32* %arraydecay23, i16* %arraydecay24, i32* %ptr, i32 %0, i32 %1, i32 %2)
+ ret void
+}
+
+define void @fast_non_linux() ssp {
+entry:
+; FAST-NON-LIN: fast_non_linux:
+; FAST-NON-LIN: call{{l|q}} get_scalar1
+; FAST-NON-LIN: movl %eax, -20(
+; FAST-NON-LIN: call{{l|q}} end_scalar1
+
+; FAST-NON-LIN: call{{l|q}} get_large_char
+; FAST-NON-LIN: movb %al, -16(
+; FAST-NON-LIN: call{{l|q}} end_large_char
+ %x = alloca i32, align 4
+ %large = alloca [8 x i8], align 1
+ %call = call i32 @get_scalar1()
+ store i32 %call, i32* %x, align 4
+ call void @end_scalar1()
+ %call1 = call signext i8 @get_large_char()
+ %arrayidx = getelementptr inbounds [8 x i8]* %large, i32 0, i64 0
+ store i8 %call1, i8* %arrayidx, align 1
+ call void @end_large_char()
+ %0 = load i32* %x, align 4
+ %arraydecay = getelementptr inbounds [8 x i8]* %large, i32 0, i32 0
+ call void @takes_two(i32 %0, i8* %arraydecay)
+ ret void
+}
+
+declare i32 @get_scalar1()
+declare void @end_scalar1()
+
+declare i32 @get_scalar2()
+declare void @end_scalar2()
+
+declare i32 @get_scalar3()
+declare void @end_scalar3()
+
+declare i32 @get_addrof()
+declare void @end_addrof()
+
+declare signext i16 @get_small_nonchar()
+declare void @end_small_nonchar()
+
+declare i32 @get_large_nonchar()
+declare void @end_large_nonchar()
+
+declare signext i8 @get_small_char()
+declare void @end_small_char()
+
+declare signext i8 @get_large_char()
+declare void @end_large_char()
+
+declare signext i8 @get_struct_large_char()
+declare void @end_struct_large_char()
+
+declare signext i8 @get_struct_large_char2()
+declare void @end_struct_large_char2()
+
+declare signext i8 @get_struct_small_char()
+declare void @end_struct_small_char()
+
+declare i32 @get_struct_large_nonchar()
+declare void @end_struct_large_nonchar()
+
+declare signext i16 @get_struct_small_nonchar()
+declare void @end_struct_small_nonchar()
+
+declare void @takes_all(i64, i16, %struct.struct_large_nonchar* byval align 8, i32, i8*, i8*, i32*, i16*, i32*, i32, i32, i32)
+declare void @takes_two(i32, i8*)