Index: llvm/include/llvm/CodeGen/StackProtector.h =================================================================== --- llvm/include/llvm/CodeGen/StackProtector.h +++ llvm/include/llvm/CodeGen/StackProtector.h @@ -95,7 +95,7 @@ bool InStruct = false) const; /// Check whether a stack allocation has its address taken. - bool HasAddressTaken(const Instruction *AI, uint64_t AllocSize); + bool HasAddressTaken(const Instruction *AI, TypeSize AllocSize); /// RequiresStackProtector - Check whether or not this function needs a /// stack protector based upon the stack protector level. Index: llvm/lib/CodeGen/PrologEpilogInserter.cpp =================================================================== --- llvm/lib/CodeGen/PrologEpilogInserter.cpp +++ llvm/lib/CodeGen/PrologEpilogInserter.cpp @@ -956,12 +956,20 @@ // LocalStackSlotPass didn't already allocate a slot for it. // If we are told to use the LocalStackAllocationBlock, the stack protector // is expected to be already pre-allocated. - if (!MFI.getUseLocalStackAllocationBlock()) - AdjustStackOffset(MFI, StackProtectorFI, StackGrowsDown, Offset, MaxAlign, - Skew); - else if (!MFI.isObjectPreAllocated(MFI.getStackProtectorIndex())) + if (!MFI.getUseLocalStackAllocationBlock()) { + // If the stack protector isn't on the default stack then it's up to the + // target to set the stack offset. + if (MFI.getStackID(StackProtectorFI) == TargetStackID::Default) + AdjustStackOffset(MFI, StackProtectorFI, StackGrowsDown, Offset, + MaxAlign, Skew); + else + assert(MFI.getObjectOffset(StackProtectorFI) != 0 && + "Offset of stack protector on non-default stack expected to be " + "already set."); + } else if (!MFI.isObjectPreAllocated(MFI.getStackProtectorIndex())) { llvm_unreachable( "Stack protector not pre-allocated by LocalStackSlotPass."); + } // Assign large stack objects first. for (unsigned i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) { Index: llvm/lib/CodeGen/StackProtector.cpp =================================================================== --- llvm/lib/CodeGen/StackProtector.cpp +++ llvm/lib/CodeGen/StackProtector.cpp @@ -164,7 +164,7 @@ } bool StackProtector::HasAddressTaken(const Instruction *AI, - uint64_t AllocSize) { + TypeSize AllocSize) { const DataLayout &DL = M->getDataLayout(); for (const User *U : AI->users()) { const auto *I = cast(U); @@ -172,7 +172,7 @@ // the bounds of the allocated object. Optional MemLoc = MemoryLocation::getOrNone(I); if (MemLoc.hasValue() && MemLoc->Size.hasValue() && - MemLoc->Size.getValue() > AllocSize) + MemLoc->Size.getValue() > AllocSize.getKnownMinValue()) return true; switch (I->getOpcode()) { case Instruction::Store: @@ -205,13 +205,14 @@ // would use it could also be out-of-bounds meaning stack protection is // required. const GetElementPtrInst *GEP = cast(I); - unsigned TypeSize = DL.getIndexTypeSizeInBits(I->getType()); - APInt Offset(TypeSize, 0); - APInt MaxOffset(TypeSize, AllocSize); + unsigned IndexSize = DL.getIndexTypeSizeInBits(I->getType()); + APInt Offset(IndexSize, 0); + APInt MaxOffset(IndexSize, AllocSize); if (!GEP->accumulateConstantOffset(DL, Offset) || Offset.ugt(MaxOffset)) return true; // Adjust AllocSize to be the space remaining after this offset. - if (HasAddressTaken(I, AllocSize - Offset.getLimitedValue())) + TypeSize OffsetSize = TypeSize::Fixed(Offset.getLimitedValue()); + if (HasAddressTaken(I, AllocSize - OffsetSize)) return true; break; } @@ -336,7 +337,8 @@ } bool IsLarge = false; - if (ContainsProtectableArray(AI->getAllocatedType(), IsLarge, Strong)) { + Type *AllocType = AI->getAllocatedType(); + if (ContainsProtectableArray(AllocType, IsLarge, Strong)) { Layout.insert(std::make_pair(AI, IsLarge ? MachineFrameInfo::SSPLK_LargeArray : MachineFrameInfo::SSPLK_SmallArray)); @@ -351,8 +353,8 @@ continue; } - if (Strong && HasAddressTaken(AI, M->getDataLayout().getTypeAllocSize( - AI->getAllocatedType()))) { + TypeSize AllocSize = M->getDataLayout().getTypeAllocSize(AllocType); + if (Strong && HasAddressTaken(AI, AllocSize)) { ++NumAddrTaken; Layout.insert(std::make_pair(AI, MachineFrameInfo::SSPLK_AddrOf)); ORE.emit([&]() { Index: llvm/lib/Target/AArch64/AArch64FrameLowering.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64FrameLowering.cpp +++ llvm/lib/Target/AArch64/AArch64FrameLowering.cpp @@ -2950,6 +2950,15 @@ // stack slots for them. MachineFrameInfo &MFI = MF.getFrameInfo(); auto *AFI = MF.getInfo(); + + // When using a stack protector with SVE it needs to be placed at the top of + // the SVE stack area, as the SVE locals are placed above the other locals, so + // we allocate it as if it were a scalable vector. + if (MFI.hasStackProtectorIndex() && estimateSVEStackObjectOffsets(MFI) > 0) { + MFI.setStackID(MFI.getStackProtectorIndex(), TargetStackID::ScalableVector); + MFI.setObjectAlignment(MFI.getStackProtectorIndex(), Align(16)); + } + for (auto &CS : CSI) { Register Reg = CS.getReg(); const TargetRegisterClass *RC = RegInfo->getMinimalPhysRegClass(Reg); Index: llvm/test/CodeGen/AArch64/stack-guard-sve.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/stack-guard-sve.ll @@ -0,0 +1,147 @@ +; RUN: llc -mtriple=aarch64--linux-gnu -mattr=+sve < %s | FileCheck %s + +declare dso_local void @val_fn() +declare dso_local void @ptr_fn(*) + +; An alloca of a scalable vector shouldn't trigger stack protection. + +; CHECK-LABEL: call_value: +; CHECK-NOT: mov x19, sp +; CHECK: addvl sp, sp, #-1 +; CHECK-NOT: __stack_chk_guard +; CHECK: st1w { {{z[0-9]+.s}} }, {{p[0-9]+}}, [x29, #-1, mul vl] +define void @call_value() #0 { +entry: + %x = alloca , align 16 + store shufflevector ( insertelement ( poison, float 0.000000e+00, i32 0), poison, zeroinitializer), * %x, align 16 + %0 = load , * %x, align 16 + call void @val_fn( %0) + ret void +} + +; CHECK-LABEL: call_value_strong: +; CHECK-NOT: mov x19, sp +; CHECK: addvl sp, sp, #-1 +; CHECK-NOT: __stack_chk_guard +; CHECK: st1w { {{z[0-9]+.s}} }, {{p[0-9]+}}, [x29, #-1, mul vl] +define void @call_value_strong() #1 { +entry: + %x = alloca , align 16 + store shufflevector ( insertelement ( poison, float 0.000000e+00, i32 0), poison, zeroinitializer), * %x, align 16 + %0 = load , * %x, align 16 + call void @val_fn( %0) + ret void +} + +; Address-taking of a scalable vector should trigger stack protection only with +; sspstrong, and the scalable vector should be be placed below the stack guard. + +; CHECK-LABEL: call_ptr: +; CHECK-NOT: mov x19, sp +; CHECK: addvl sp, sp, #-1 +; CHECK-NOT: __stack_chk_guard +; CHECK: addvl x0, x29, #-1 +; CHECK: bl ptr_fn +define void @call_ptr() #0 { +entry: + %x = alloca , align 16 + call void @ptr_fn(* %x) + ret void +} + +; CHECK-LABEL: call_ptr_strong: +; CHECK: mov x29, sp +; CHECK: addvl sp, sp, #-2 +; CHECK-DAG: addvl [[ADDR:x[0-9]+]], x29, #-1 +; CHECK-DAG: ldr [[VAL:x[0-9]+]], [{{x[0-9]+}}, :lo12:__stack_chk_guard] +; CHECK-DAG: str [[VAL]], {{\[}}[[ADDR]]] +; CHECK-DAG: addvl x0, x29, #-2 +; CHECK: bl ptr_fn +define void @call_ptr_strong() #1 { +entry: + %x = alloca , align 16 + call void @ptr_fn(* %x) + ret void +} + +; Check that both variables are addressed in the same way + +; CHECK-LABEL: call_both: +; CHECK: mov x29, sp +; CHECK: addvl sp, sp, #-2 +; CHECK-NOT: __stack_chk_guard +; CHECK: st1w { {{z[0-9]+.s}} }, {{p[0-9]+}}, [x29, #-1, mul vl] +; CHECK: bl val_fn +; CHECK: addvl x0, x29, #-2 +; CHECK: bl ptr_fn +define void @call_both() #0 { +entry: + %x = alloca , align 16 + %y = alloca , align 16 + store shufflevector ( insertelement ( poison, float 0.000000e+00, i32 0), poison, zeroinitializer), * %x, align 16 + %0 = load , * %x, align 16 + call void @val_fn( %0) + call void @ptr_fn(* %y) + ret void +} + +; CHECK-LABEL: call_both_strong: +; CHECK: mov x29, sp +; CHECK: addvl sp, sp, #-3 +; CHECK-DAG: addvl [[ADDR:x[0-9]+]], x29, #-1 +; CHECK-DAG: ldr [[VAL:x[0-9]+]], [{{x[0-9]+}}, :lo12:__stack_chk_guard] +; CHECK-DAG: str [[VAL]], {{\[}}[[ADDR]]] +; CHECK-DAG: st1w { {{z[0-9]+.s}} }, {{p[0-9]+}}, [x29, #-2, mul vl] +; CHECK: bl val_fn +; CHECK: addvl x0, x29, #-3 +; CHECK: bl ptr_fn +define void @call_both_strong() #1 { +entry: + %x = alloca , align 16 + %y = alloca , align 16 + store shufflevector ( insertelement ( poison, float 0.000000e+00, i32 0), poison, zeroinitializer), * %x, align 16 + %0 = load , * %x, align 16 + call void @val_fn( %0) + call void @ptr_fn(* %y) + ret void +} + +; Pushed callee-saved regs should be above the stack guard + +; CHECK-LABEL: callee_save: +; CHECK: mov x29, sp +; CHECK: addvl sp, sp, #-18 +; CHECK: str {{z[0-9]+}}, [sp, #{{[0-9]+}}, mul vl] +; CHECK-NOT: mov x29, sp +; CHECK: addvl sp, sp, #-1 +; CHECK-NOT: __stack_chk_guard +; CHECK: addvl [[REG:x[0-9]+]], x29, #-11 +; CHECK: st1w { {{z[0-9]+.s}} }, {{p[0-9]+}}, {{\[}}[[REG]], #-8, mul vl] +define void @callee_save( %x) #0 { +entry: + %x.addr = alloca , align 16 + store %x, * %x.addr, align 16 + call void @ptr_fn(* %x.addr) + ret void +} + +; CHECK-LABEL: callee_save_strong: +; CHECK: mov x29, sp +; CHECK: addvl sp, sp, #-18 +; CHECK: str {{z[0-9]+}}, [sp, #{{[0-9]+}}, mul vl] +; CHECK: addvl sp, sp, #-2 +; CHECK-DAG: addvl [[ADDR:x[0-9]+]], x29, #-19 +; CHECK-DAG: ldr [[VAL:x[0-9]+]], [{{x[0-9]+}}, :lo12:__stack_chk_guard] +; CHECK-DAG: str [[VAL]], {{\[}}[[ADDR]]] +; CHECK-DAG: addvl [[ADDR2:x[0-9]+]], x29, #-12 +; CHECK-DAG: st1w { z0.s }, p0, {{\[}}[[ADDR2]], #-8, mul vl] +define void @callee_save_strong( %x) #1 { +entry: + %x.addr = alloca , align 16 + store %x, * %x.addr, align 16 + call void @ptr_fn(* %x.addr) + ret void +} + +attributes #0 = { ssp "frame-pointer"="non-leaf" } +attributes #1 = { sspstrong "frame-pointer"="non-leaf" }