Skip to content

Commit 7fcfcde

Browse files
authored
Merge pull request #66990 from eeckstein/bare-objects
SIL: add a `bare` attribute to `global_value` and `alloc_ref`
2 parents af3f2de + e77e2bc commit 7fcfcde

35 files changed

+372
-73
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ swift_compiler_sources(Optimizer
1919
ReleaseDevirtualizer.swift
2020
SimplificationPasses.swift
2121
StackPromotion.swift
22+
StripObjectHeaders.swift
2223
)

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ObjectOutliner.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ private func replace(object allocRef: AllocRefInstBase,
310310

311311
// Replace the alloc_ref by global_value + strong_retain instructions.
312312
let builder = Builder(before: allocRef, context)
313-
let globalValue = builder.createGlobalValue(global: global)
313+
let globalValue = builder.createGlobalValue(global: global, isBare: false)
314314
builder.createStrongRetain(operand: globalValue)
315315

316316
endCOW.uses.replaceAll(with: endCOW.instance, context)
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//===--- StripObjectHeaders.swift ------------------------------------------==//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import SIL
14+
15+
/// Sets the `[bare]` attribute for `alloc_ref` and `global_value` instructions
16+
/// if their header (reference count and metatype) is not used throughout the
17+
/// lifetime of the object.
18+
///
19+
let stripObjectHeadersPass = FunctionPass(name: "strip-object-headers") {
20+
(function: Function, context: FunctionPassContext) in
21+
22+
for inst in function.instructions {
23+
switch inst {
24+
case let gv as GlobalValueInst:
25+
if !gv.isBare && !gv.needObjectHeader() {
26+
gv.setIsBare(context)
27+
}
28+
case let ar as AllocRefInst:
29+
if !ar.isBare && !ar.needObjectHeader() {
30+
ar.setIsBare(context)
31+
}
32+
default:
33+
break
34+
}
35+
}
36+
}
37+
38+
private extension Value {
39+
func needObjectHeader() -> Bool {
40+
var walker = IsBareObjectWalker()
41+
return walker.walkDownUses(ofValue: self, path: SmallProjectionPath()) == .abortWalk
42+
}
43+
}
44+
45+
private struct IsBareObjectWalker : ValueDefUseWalker {
46+
var walkDownCache = WalkerCache<SmallProjectionPath>()
47+
48+
mutating func walkDown(value operand: Operand, path: Path) -> WalkResult {
49+
switch operand.instruction {
50+
// White-list all instructions which don't use the object header.
51+
case is StructInst, is TupleInst, is EnumInst,
52+
is StructExtractInst, is TupleExtractInst, is UncheckedEnumDataInst,
53+
is DestructureStructInst, is DestructureTupleInst,
54+
is BeginBorrowInst, is MarkDependenceInst,
55+
is BranchInst, is CondBranchInst, is SwitchEnumInst,
56+
is UpcastInst, is UncheckedRefCastInst,
57+
is EndCOWMutationInst:
58+
return walkDownDefault(value: operand, path: path)
59+
default:
60+
return leafUse(value: operand, path: path)
61+
}
62+
}
63+
64+
mutating func leafUse(value operand: Operand, path: SmallProjectionPath) -> WalkResult {
65+
switch operand.instruction {
66+
// White-list all instructions which don't use the object header.
67+
case is RefElementAddrInst, is RefTailAddrInst,
68+
is DeallocRefInst, is DeallocStackRefInst, is SetDeallocatingInst,
69+
is DebugValueInst, is FixLifetimeInst:
70+
return .continueWalk
71+
default:
72+
return .abortWalk
73+
}
74+
}
75+
}

SwiftCompilerSources/Sources/Optimizer/PassManager/Context.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,22 @@ extension RefCountingInst {
430430
}
431431
}
432432

433+
extension AllocRefInst {
434+
func setIsBare(_ context: some MutatingContext) {
435+
context.notifyInstructionsChanged()
436+
bridged.AllocRefInst_setIsBare()
437+
context.notifyInstructionChanged(self)
438+
}
439+
}
440+
441+
extension GlobalValueInst {
442+
func setIsBare(_ context: some MutatingContext) {
443+
context.notifyInstructionsChanged()
444+
bridged.GlobalValueInst_setIsBare()
445+
context.notifyInstructionChanged(self)
446+
}
447+
}
448+
433449
extension TermInst {
434450
func replaceBranchTarget(from fromBlock: BasicBlock, to toBlock: BasicBlock, _ context: some MutatingContext) {
435451
context.notifyBranchesChanged()

SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ private func registerSwiftPasses() {
8181
registerPass(lateOnoneSimplificationPass, { lateOnoneSimplificationPass.run($0) })
8282
registerPass(cleanupDebugStepsPass, { cleanupDebugStepsPass.run($0) })
8383
registerPass(namedReturnValueOptimization, { namedReturnValueOptimization.run($0) })
84+
registerPass(stripObjectHeadersPass, { stripObjectHeadersPass.run($0) })
8485

8586
// Instruction passes
8687
registerForSILCombine(BeginCOWMutationInst.self, { run(BeginCOWMutationInst.self, $0) })

SwiftCompilerSources/Sources/SIL/Builder.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,8 @@ public struct Builder {
239239
return notifyNew(bridged.createGlobalAddr(global.bridged).getAs(GlobalAddrInst.self))
240240
}
241241

242-
public func createGlobalValue(global: GlobalVariable) -> GlobalValueInst {
243-
return notifyNew(bridged.createGlobalValue(global.bridged).getAs(GlobalValueInst.self))
242+
public func createGlobalValue(global: GlobalVariable, isBare: Bool) -> GlobalValueInst {
243+
return notifyNew(bridged.createGlobalValue(global.bridged, isBare).getAs(GlobalValueInst.self))
244244
}
245245

246246
public func createStruct(type: Type, elements: [Value]) -> StructInst {

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,9 @@ final public class PreviousDynamicFunctionRefInst : FunctionRefBaseInst {
523523

524524
final public class GlobalAddrInst : GlobalAccessInst {}
525525

526-
final public class GlobalValueInst : GlobalAccessInst {}
526+
final public class GlobalValueInst : GlobalAccessInst {
527+
public var isBare: Bool { bridged.GlobalValueInst_isBare() }
528+
}
527529

528530
final public class AllocGlobalInst : Instruction {
529531
public var global: GlobalVariable {
@@ -837,6 +839,7 @@ public class AllocRefInstBase : SingleValueInstruction, Allocation {
837839
}
838840

839841
final public class AllocRefInst : AllocRefInstBase {
842+
public var isBare: Bool { bridged.AllocRefInst_isBare() }
840843
}
841844

842845
final public class AllocRefDynamicInst : AllocRefInstBase {

docs/SIL.rst

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3816,6 +3816,7 @@ alloc_ref
38163816
::
38173817

38183818
sil-instruction ::= 'alloc_ref'
3819+
('[' 'bare' ']')?
38193820
('[' 'objc' ']')?
38203821
('[' 'stack' ']')?
38213822
('[' 'tail_elems' sil-type '*' sil-operand ']')*
@@ -3842,6 +3843,11 @@ possible. The final decision on stack allocation is done during llvm IR
38423843
generation. This is because the decision also depends on the object size,
38433844
which is not necessarily known at SIL level.
38443845

3846+
The ``bare`` attribute indicates that the object header is not used throughout
3847+
the lifetime of the object. This means, no reference counting operations are
3848+
performed on the object and its metadata is not used. The header of bare
3849+
objects doesn't need to be initialized.
3850+
38453851
The optional ``tail_elems`` attributes specifies the amount of space to be
38463852
reserved for tail-allocated arrays of given element types and element counts.
38473853
If there are more than one ``tail_elems`` attributes then the tail arrays are
@@ -5484,7 +5490,7 @@ global_value
54845490
`````````````
54855491
::
54865492

5487-
sil-instruction ::= 'global_value' sil-global-name ':' sil-type
5493+
sil-instruction ::= 'global_value' ('[' 'bare' ']')? sil-global-name ':' sil-type
54885494

54895495
%1 = global_value @v : $T
54905496

@@ -5493,6 +5499,11 @@ by ``alloc_global``. It is undefined behavior to perform this operation on a
54935499
global variable which has not been initialized, except the global variable
54945500
has a static initializer.
54955501

5502+
The ``bare`` attribute indicates that the object header is not used throughout
5503+
the lifetime of the value. This means, no reference counting operations are
5504+
performed on the object and its metadata is not used. The header of bare
5505+
objects doesn't need to be initialized.
5506+
54965507
integer_literal
54975508
```````````````
54985509
::

include/swift/SIL/SILBridging.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,14 @@ struct BridgedInstruction {
760760
getAs<swift::AllocRefInstBase>()->setStackAllocatable();
761761
}
762762

763+
bool AllocRefInst_isBare() const {
764+
return getAs<swift::AllocRefInst>()->isBare();
765+
}
766+
767+
void AllocRefInst_setIsBare() const {
768+
getAs<swift::AllocRefInst>()->setBare(true);
769+
}
770+
763771
inline void TermInst_replaceBranchTarget(BridgedBasicBlock from, BridgedBasicBlock to) const;
764772

765773
SwiftInt KeyPathInst_getNumComponents() const {
@@ -786,6 +794,14 @@ struct BridgedInstruction {
786794
}, [](swift::SILDeclRef) {});
787795
}
788796

797+
bool GlobalValueInst_isBare() const {
798+
return getAs<swift::GlobalValueInst>()->isBare();
799+
}
800+
801+
void GlobalValueInst_setIsBare() const {
802+
getAs<swift::GlobalValueInst>()->setBare(true);
803+
}
804+
789805
SWIFT_IMPORT_UNSAFE
790806
inline BridgedBasicBlock CheckedCastBranch_getSuccessBlock() const;
791807

@@ -1242,8 +1258,8 @@ struct BridgedBuilder{
12421258
}
12431259

12441260
SWIFT_IMPORT_UNSAFE
1245-
BridgedInstruction createGlobalValue(BridgedGlobalVar global) const {
1246-
return {builder().createGlobalValue(regularLoc(), global.getGlobal())};
1261+
BridgedInstruction createGlobalValue(BridgedGlobalVar global, bool isBare) const {
1262+
return {builder().createGlobalValue(regularLoc(), global.getGlobal(), isBare)};
12471263
}
12481264

12491265
SWIFT_IMPORT_UNSAFE

include/swift/SIL/SILBuilder.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -446,14 +446,14 @@ class SILBuilder {
446446
}
447447

448448
AllocRefInst *createAllocRef(SILLocation Loc, SILType ObjectType,
449-
bool objc, bool canAllocOnStack,
449+
bool objc, bool canAllocOnStack, bool isBare,
450450
ArrayRef<SILType> ElementTypes,
451451
ArrayRef<SILValue> ElementCountOperands) {
452452
// AllocRefInsts expand to function calls and can therefore not be
453453
// counted towards the function prologue.
454454
assert(!Loc.isInPrologue());
455455
return insert(AllocRefInst::create(getSILDebugLocation(Loc), getFunction(),
456-
ObjectType, objc, canAllocOnStack,
456+
ObjectType, objc, canAllocOnStack, isBare,
457457
ElementTypes, ElementCountOperands));
458458
}
459459

@@ -682,9 +682,9 @@ class SILBuilder {
682682
return insert(new (F->getModule())
683683
GlobalAddrInst(getSILDebugLocation(Loc), Ty));
684684
}
685-
GlobalValueInst *createGlobalValue(SILLocation Loc, SILGlobalVariable *g) {
685+
GlobalValueInst *createGlobalValue(SILLocation Loc, SILGlobalVariable *g, bool isBare) {
686686
return insert(new (getModule()) GlobalValueInst(getSILDebugLocation(Loc), g,
687-
getTypeExpansionContext()));
687+
getTypeExpansionContext(), isBare));
688688
}
689689
BaseAddrForOffsetInst *createBaseAddrForOffset(SILLocation Loc, SILType Ty) {
690690
return insert(new (F->getModule())

0 commit comments

Comments
 (0)