aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
diff options
context:
space:
mode:
authorOmair Javaid <omair.javaid@linaro.org>2025-06-12 19:38:42 +0500
committerGitHub <noreply@github.com>2025-06-12 19:38:42 +0500
commite1e1836bbd70e4f30bd0be97b9d81eabfd6b45c8 (patch)
tree161853a2d8cb724fdc46c3fabac05f2c4c2201df /llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
parentcc17f68e566ab7db4ac8e95dc857e49e10d8366c (diff)
downloadllvm-e1e1836bbd70e4f30bd0be97b9d81eabfd6b45c8.zip
llvm-e1e1836bbd70e4f30bd0be97b9d81eabfd6b45c8.tar.gz
llvm-e1e1836bbd70e4f30bd0be97b9d81eabfd6b45c8.tar.bz2
[CodeGen] Inline stack guard check on Windows (#136290)
This patch optimizes the Windows security cookie check mechanism by moving the comparison inline and only calling __security_check_cookie when the check fails. This reduces the overhead of making a DLL call for every function return. Previously, we implemented this optimization through a machine pass (X86WinFixupBufferSecurityCheckPass) in PR #95904 submitted by @mahesh-attarde. We have reverted that pass in favor of this new approach. Also we have abandoned the AArch64 specific implementation of same pass in PR #121938 in favor of this more general solution. The old machine instruction pass approach: - Scanned the generated code to find __security_check_cookie calls - Modified these calls by splitting basic blocks - Added comparison logic and conditional branching - Required complex block management and live register computation The new approach: - Implements the same optimization during instruction selection - Directly emits the comparison and conditional branching - No need for post-processing or basic block manipulation - Disables optimization at -Oz. Thanks @tamaspetz, @efriedma-quic and @arsenm for their help.
Diffstat (limited to 'llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp')
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp95
1 files changed, 78 insertions, 17 deletions
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index e6a1dc9..c63eb7f 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -3037,8 +3037,9 @@ void SelectionDAGBuilder::visitSPDescriptorParent(StackProtectorDescriptor &SPD,
// First create the loads to the guard/stack slot for the comparison.
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
- EVT PtrTy = TLI.getPointerTy(DAG.getDataLayout());
- EVT PtrMemTy = TLI.getPointerMemTy(DAG.getDataLayout());
+ auto &DL = DAG.getDataLayout();
+ EVT PtrTy = TLI.getFrameIndexTy(DL);
+ EVT PtrMemTy = TLI.getPointerMemTy(DL, DL.getAllocaAddrSpace());
MachineFrameInfo &MFI = ParentBB->getParent()->getFrameInfo();
int FI = MFI.getStackProtectorIndex();
@@ -3047,8 +3048,8 @@ void SelectionDAGBuilder::visitSPDescriptorParent(StackProtectorDescriptor &SPD,
SDLoc dl = getCurSDLoc();
SDValue StackSlotPtr = DAG.getFrameIndex(FI, PtrTy);
const Module &M = *ParentBB->getParent()->getFunction().getParent();
- Align Align =
- DAG.getDataLayout().getPrefTypeAlign(PointerType::get(M.getContext(), 0));
+ Align Align = DL.getPrefTypeAlign(
+ PointerType::get(M.getContext(), DL.getAllocaAddrSpace()));
// Generate code to load the content of the guard slot.
SDValue GuardVal = DAG.getLoad(
@@ -3059,8 +3060,14 @@ void SelectionDAGBuilder::visitSPDescriptorParent(StackProtectorDescriptor &SPD,
if (TLI.useStackGuardXorFP())
GuardVal = TLI.emitStackGuardXorFP(DAG, GuardVal, dl);
- // Retrieve guard check function, nullptr if instrumentation is inlined.
- if (const Function *GuardCheckFn = TLI.getSSPStackGuardCheck(M)) {
+ // If we're using function-based instrumentation, call the guard check
+ // function
+ if (SPD.shouldEmitFunctionBasedCheckStackProtector()) {
+ // Get the guard check function from the target and verify it exists since
+ // we're using function-based instrumentation
+ const Function *GuardCheckFn = TLI.getSSPStackGuardCheck(M);
+ assert(GuardCheckFn && "Guard check function is null");
+
// The target provides a guard check function to validate the guard value.
// Generate a call to that function with the content of the guard slot as
// argument.
@@ -3101,10 +3108,9 @@ void SelectionDAGBuilder::visitSPDescriptorParent(StackProtectorDescriptor &SPD,
}
// Perform the comparison via a getsetcc.
- SDValue Cmp = DAG.getSetCC(dl, TLI.getSetCCResultType(DAG.getDataLayout(),
- *DAG.getContext(),
- Guard.getValueType()),
- Guard, GuardVal, ISD::SETNE);
+ SDValue Cmp = DAG.getSetCC(
+ dl, TLI.getSetCCResultType(DL, *DAG.getContext(), Guard.getValueType()),
+ Guard, GuardVal, ISD::SETNE);
// If the guard/stackslot do not equal, branch to failure MBB.
SDValue BrCond = DAG.getNode(ISD::BRCOND, dl,
@@ -3126,14 +3132,69 @@ void SelectionDAGBuilder::visitSPDescriptorParent(StackProtectorDescriptor &SPD,
/// For a high level explanation of how this fits into the stack protector
/// generation see the comment on the declaration of class
/// StackProtectorDescriptor.
-void
-SelectionDAGBuilder::visitSPDescriptorFailure(StackProtectorDescriptor &SPD) {
+void SelectionDAGBuilder::visitSPDescriptorFailure(
+ StackProtectorDescriptor &SPD) {
+
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
- TargetLowering::MakeLibCallOptions CallOptions;
- CallOptions.setDiscardResult(true);
- SDValue Chain = TLI.makeLibCall(DAG, RTLIB::STACKPROTECTOR_CHECK_FAIL,
- MVT::isVoid, {}, CallOptions, getCurSDLoc())
- .second;
+ MachineBasicBlock *ParentBB = SPD.getParentMBB();
+ const Module &M = *ParentBB->getParent()->getFunction().getParent();
+ SDValue Chain;
+
+ // For -Oz builds with a guard check function, we use function-based
+ // instrumentation. Otherwise, if we have a guard check function, we call it
+ // in the failure block.
+ auto *GuardCheckFn = TLI.getSSPStackGuardCheck(M);
+ if (GuardCheckFn && !SPD.shouldEmitFunctionBasedCheckStackProtector()) {
+ // First create the loads to the guard/stack slot for the comparison.
+ auto &DL = DAG.getDataLayout();
+ EVT PtrTy = TLI.getFrameIndexTy(DL);
+ EVT PtrMemTy = TLI.getPointerMemTy(DL, DL.getAllocaAddrSpace());
+
+ MachineFrameInfo &MFI = ParentBB->getParent()->getFrameInfo();
+ int FI = MFI.getStackProtectorIndex();
+
+ SDLoc dl = getCurSDLoc();
+ SDValue StackSlotPtr = DAG.getFrameIndex(FI, PtrTy);
+ Align Align = DL.getPrefTypeAlign(
+ PointerType::get(M.getContext(), DL.getAllocaAddrSpace()));
+
+ // Generate code to load the content of the guard slot.
+ SDValue GuardVal = DAG.getLoad(
+ PtrMemTy, dl, DAG.getEntryNode(), StackSlotPtr,
+ MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), Align,
+ MachineMemOperand::MOVolatile);
+
+ if (TLI.useStackGuardXorFP())
+ GuardVal = TLI.emitStackGuardXorFP(DAG, GuardVal, dl);
+
+ // The target provides a guard check function to validate the guard value.
+ // Generate a call to that function with the content of the guard slot as
+ // argument.
+ FunctionType *FnTy = GuardCheckFn->getFunctionType();
+ assert(FnTy->getNumParams() == 1 && "Invalid function signature");
+
+ TargetLowering::ArgListTy Args;
+ TargetLowering::ArgListEntry Entry;
+ Entry.Node = GuardVal;
+ Entry.Ty = FnTy->getParamType(0);
+ if (GuardCheckFn->hasParamAttribute(0, Attribute::AttrKind::InReg))
+ Entry.IsInReg = true;
+ Args.push_back(Entry);
+
+ TargetLowering::CallLoweringInfo CLI(DAG);
+ CLI.setDebugLoc(getCurSDLoc())
+ .setChain(DAG.getEntryNode())
+ .setCallee(GuardCheckFn->getCallingConv(), FnTy->getReturnType(),
+ getValue(GuardCheckFn), std::move(Args));
+
+ Chain = TLI.LowerCallTo(CLI).second;
+ } else {
+ TargetLowering::MakeLibCallOptions CallOptions;
+ CallOptions.setDiscardResult(true);
+ Chain = TLI.makeLibCall(DAG, RTLIB::STACKPROTECTOR_CHECK_FAIL, MVT::isVoid,
+ {}, CallOptions, getCurSDLoc())
+ .second;
+ }
// Emit a trap instruction if we are required to do so.
const TargetOptions &TargetOpts = DAG.getTarget().Options;