Skip to content

Commit 5f38f8e

Browse files
authored
Merge pull request swiftlang#63676 from eeckstein/improve-stack-protection
SILOptimizer: avoid stack protection in two cases where it's not needed
2 parents 791d780 + abf9900 commit 5f38f8e

File tree

17 files changed

+385
-30
lines changed

17 files changed

+385
-30
lines changed

SwiftCompilerSources/Sources/Optimizer/ModulePasses/StackProtection.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,13 +486,23 @@ private extension Instruction {
486486
if !atp.needsStackProtection {
487487
return nil
488488
}
489+
var hasNoStores = NoStores()
490+
if hasNoStores.walkDownUses(ofValue: atp, path: SmallProjectionPath()) == .continueWalk {
491+
return nil
492+
}
493+
489494
// The result of an `address_to_pointer` may be used in any unsafe way, e.g.
490495
// passed to a C function.
491496
baseAddr = atp.operand
492497
case let ia as IndexAddrInst:
493498
if !ia.needsStackProtection {
494499
return nil
495500
}
501+
var hasNoStores = NoStores()
502+
if hasNoStores.walkDownUses(ofAddress: ia, path: SmallProjectionPath()) == .continueWalk {
503+
return nil
504+
}
505+
496506
// `index_addr` is unsafe if not used for tail-allocated elements (e.g. in Array).
497507
baseAddr = ia.base
498508
default:
@@ -509,6 +519,29 @@ private extension Instruction {
509519
}
510520
}
511521

522+
/// Checks if there are no stores to an address or raw pointer.
523+
private struct NoStores : ValueDefUseWalker, AddressDefUseWalker {
524+
var walkDownCache = WalkerCache<SmallProjectionPath>()
525+
526+
mutating func leafUse(value: Operand, path: SmallProjectionPath) -> WalkResult {
527+
if let ptai = value.instruction as? PointerToAddressInst {
528+
return walkDownUses(ofAddress: ptai, path: path)
529+
}
530+
return .abortWalk
531+
}
532+
533+
mutating func leafUse(address: Operand, path: SmallProjectionPath) -> WalkResult {
534+
switch address.instruction {
535+
case is LoadInst:
536+
return .continueWalk
537+
case let cai as CopyAddrInst:
538+
return address == cai.sourceOperand ? .continueWalk : .abortWalk
539+
default:
540+
return .abortWalk
541+
}
542+
}
543+
}
544+
512545
private extension Function {
513546
func setNeedsStackProtection(_ context: FunctionPassContext) {
514547
if !needsStackProtection {

include/swift/AST/Builtins.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,10 @@ BUILTIN_MISC_OPERATION(DeallocRaw, "deallocRaw", "", Special)
629629
/// is not known at compile time, MaximumAlignment is assumed.
630630
BUILTIN_MISC_OPERATION(StackAlloc, "stackAlloc", "", Special)
631631

632+
/// Like `stackAlloc`, but doesn't set the `[stack_protection]` flag on its
633+
/// containing function.
634+
BUILTIN_MISC_OPERATION(UnprotectedStackAlloc, "unprotectedStackAlloc", "", Special)
635+
632636
/// StackDealloc has type (Builtin.RawPointer) -> ()
633637
///
634638
/// Parameters: address.

include/swift/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ LANGUAGE_FEATURE(BuiltinBuildMainExecutor, 0, "MainActor executor building built
8282
LANGUAGE_FEATURE(BuiltinCreateAsyncTaskInGroup, 0, "MainActor executor building builtin", true)
8383
LANGUAGE_FEATURE(BuiltinCopy, 0, "Builtin.copy()", true)
8484
LANGUAGE_FEATURE(BuiltinStackAlloc, 0, "Builtin.stackAlloc", true)
85+
LANGUAGE_FEATURE(BuiltinUnprotectedStackAlloc, 0, "Builtin.unprotectedStackAlloc", true)
8586
LANGUAGE_FEATURE(BuiltinTaskRunInline, 0, "Builtin.taskRunInline", true)
8687
LANGUAGE_FEATURE(BuiltinUnprotectedAddressOf, 0, "Builtin.unprotectedAddressOf", true)
8788
SUPPRESSIBLE_LANGUAGE_FEATURE(SpecializeAttributeWithAvailability, 0, "@_specialize attribute with availability", true)

lib/AST/ASTPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3020,6 +3020,10 @@ static bool usesFeatureBuiltinStackAlloc(Decl *decl) {
30203020
return false;
30213021
}
30223022

3023+
static bool usesFeatureBuiltinUnprotectedStackAlloc(Decl *decl) {
3024+
return false;
3025+
}
3026+
30233027
static bool usesFeatureBuiltinAssumeAlignment(Decl *decl) {
30243028
return false;
30253029
}

lib/AST/Builtins.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2707,6 +2707,7 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
27072707
return getDeallocOperation(Context, Id);
27082708

27092709
case BuiltinValueKind::StackAlloc:
2710+
case BuiltinValueKind::UnprotectedStackAlloc:
27102711
return getStackAllocOperation(Context, Id);
27112712
case BuiltinValueKind::StackDealloc:
27122713
return getStackDeallocOperation(Context, Id);

lib/IRGen/IRGenSIL.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3237,7 +3237,8 @@ static Alignment getStackAllocationAlignment(IRGenSILFunction &IGF,
32373237
/// some other builtin.)
32383238
static bool emitStackAllocBuiltinCall(IRGenSILFunction &IGF,
32393239
swift::BuiltinInst *i) {
3240-
if (i->getBuiltinKind() == BuiltinValueKind::StackAlloc) {
3240+
if (i->getBuiltinKind() == BuiltinValueKind::StackAlloc ||
3241+
i->getBuiltinKind() == BuiltinValueKind::UnprotectedStackAlloc) {
32413242
// Stack-allocate a buffer with the specified size/alignment.
32423243
auto loc = i->getLoc().getSourceLoc();
32433244
auto size = getStackAllocationSize(

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,7 @@ BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, SRem)
783783
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericSRem)
784784
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, SSubOver)
785785
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, StackAlloc)
786+
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, UnprotectedStackAlloc)
786787
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, StackDealloc)
787788
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, SToSCheckedTrunc)
788789
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, SToUCheckedTrunc)

lib/SIL/IR/SILInstruction.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1243,7 +1243,8 @@ bool SILInstruction::isAllocatingStack() const {
12431243
return PA->isOnStack();
12441244

12451245
if (auto *BI = dyn_cast<BuiltinInst>(this)) {
1246-
if (BI->getBuiltinKind() == BuiltinValueKind::StackAlloc) {
1246+
if (BI->getBuiltinKind() == BuiltinValueKind::StackAlloc ||
1247+
BI->getBuiltinKind() == BuiltinValueKind::UnprotectedStackAlloc) {
12471248
return true;
12481249
}
12491250
}

lib/SIL/IR/ValueOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,7 @@ CONSTANT_OWNERSHIP_BUILTIN(None, AllocRaw)
498498
CONSTANT_OWNERSHIP_BUILTIN(None, AssertConf)
499499
CONSTANT_OWNERSHIP_BUILTIN(None, UToSCheckedTrunc)
500500
CONSTANT_OWNERSHIP_BUILTIN(None, StackAlloc)
501+
CONSTANT_OWNERSHIP_BUILTIN(None, UnprotectedStackAlloc)
501502
CONSTANT_OWNERSHIP_BUILTIN(None, StackDealloc)
502503
CONSTANT_OWNERSHIP_BUILTIN(None, SToSCheckedTrunc)
503504
CONSTANT_OWNERSHIP_BUILTIN(None, SToUCheckedTrunc)

lib/SIL/Utils/MemAccessUtils.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2519,6 +2519,7 @@ static void visitBuiltinAddress(BuiltinInst *builtin,
25192519
case BuiltinValueKind::AllocRaw:
25202520
case BuiltinValueKind::DeallocRaw:
25212521
case BuiltinValueKind::StackAlloc:
2522+
case BuiltinValueKind::UnprotectedStackAlloc:
25222523
case BuiltinValueKind::StackDealloc:
25232524
case BuiltinValueKind::Fence:
25242525
case BuiltinValueKind::StaticReport:

0 commit comments

Comments
 (0)