Skip to content

Commit 94c077a

Browse files
authored
Merge pull request #73957 from Azoy/60-address-of-raw-layout
[6.0] [IRGen] Add Builtin.addressOfRawLayout
2 parents 9746fe7 + 15c5df4 commit 94c077a

File tree

15 files changed

+142
-19
lines changed

15 files changed

+142
-19
lines changed

include/swift/AST/Builtins.def

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,6 +1107,19 @@ BUILTIN_MISC_OPERATION_WITH_SILGEN(InjectEnumTag, "injectEnumTag", "", Special)
11071107
/// `any Actor` existential that refers to the local actor.
11081108
BUILTIN_MISC_OPERATION_WITH_SILGEN(DistributedActorAsAnyActor, "distributedActorAsAnyActor", "n", Special)
11091109

1110+
/// addressOfRawLayout: <T: ~Copyable>(_: borrowing T) -> Builtin.RawPointer
1111+
///
1112+
/// Returns a raw pointer to the address of the raw layout type. This address is
1113+
/// only valid during a borrow access of the raw layout type or until the value
1114+
/// is either moved or consumed.
1115+
///
1116+
/// Note: The purpose of this builtin is to get an opaque pointer to the address
1117+
/// of the raw layout type. We explicitly do not want the optimizer looking into
1118+
/// this pointer or address thereof to start assuming things about mutability or
1119+
/// immutability. This builtin _must_ persist throughout all of SIL and must be
1120+
/// lowered away at IRGen, no sooner.
1121+
BUILTIN_MISC_OPERATION_WITH_SILGEN(AddressOfRawLayout, "addressOfRawLayout", "n", Special)
1122+
11101123
/// Builtins for instrumentation added by sanitizers during SILGen.
11111124
#ifndef BUILTIN_SANITIZER_OPERATION
11121125
#define BUILTIN_SANITIZER_OPERATION(Id, Name, Attrs) BUILTIN(Id, Name, Attrs)

include/swift/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ SUPPRESSIBLE_LANGUAGE_FEATURE(NoncopyableGenerics, 427, "Noncopyable generics")
196196
SUPPRESSIBLE_LANGUAGE_FEATURE(ConformanceSuppression, 426, "Suppressible inferred conformances")
197197
SUPPRESSIBLE_LANGUAGE_FEATURE(BitwiseCopyable2, 426, "BitwiseCopyable feature")
198198
LANGUAGE_FEATURE(BodyMacros, 415, "Function body macros")
199+
LANGUAGE_FEATURE(BuiltinAddressOfRawLayout, 0, "Builtin.addressOfRawLayout")
199200

200201
// Swift 6
201202
UPCOMING_FEATURE(ConciseMagicFile, 274, 6)

include/swift/SIL/AddressWalker.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ TransitiveAddressWalker<Impl>::walk(SILValue projectedAddress) && {
276276
case BuiltinValueKind::ZeroInitializer:
277277
case BuiltinValueKind::GetEnumTag:
278278
case BuiltinValueKind::InjectEnumTag:
279+
case BuiltinValueKind::AddressOfRawLayout:
279280
callVisitUse(op);
280281
continue;
281282
default:

lib/AST/Builtins.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2141,6 +2141,15 @@ static ValueDecl *getInjectEnumTag(ASTContext &ctx, Identifier id) {
21412141
return builder.build(id);
21422142
}
21432143

2144+
static ValueDecl *getAddressOfRawLayout(ASTContext &ctx, Identifier id) {
2145+
BuiltinFunctionBuilder builder(ctx, /* genericParamCount */ 1);
2146+
2147+
builder.addParameter(makeGenericParam(), ParamSpecifier::Borrowing);
2148+
builder.setResult(makeConcrete(ctx.TheRawPointerType));
2149+
2150+
return builder.build(id);
2151+
}
2152+
21442153
/// An array of the overloaded builtin kinds.
21452154
static const OverloadedBuiltinKind OverloadedBuiltinKinds[] = {
21462155
OverloadedBuiltinKind::None,
@@ -3214,6 +3223,9 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
32143223

32153224
case BuiltinValueKind::DistributedActorAsAnyActor:
32163225
return getDistributedActorAsAnyActor(Context, Id);
3226+
3227+
case BuiltinValueKind::AddressOfRawLayout:
3228+
return getAddressOfRawLayout(Context, Id);
32173229
}
32183230

32193231
llvm_unreachable("bad builtin value!");

lib/AST/FeatureSet.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ static bool usesFeatureExpressionMacroDefaultArguments(Decl *decl) {
359359
}
360360

361361
UNINTERESTING_FEATURE(BuiltinStoreRaw)
362+
UNINTERESTING_FEATURE(BuiltinAddressOfRawLayout)
362363

363364
// ----------------------------------------------------------------------------
364365
// MARK: - Upcoming Features

lib/IRGen/GenBuiltin.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1498,5 +1498,15 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
14981498
return;
14991499
}
15001500

1501+
// LLVM must not see the address generated here as 'invariant' or immutable
1502+
// ever. A raw layout's address defies all formal access, so immutable looking
1503+
// uses may actually mutate the underlying value!
1504+
if (Builtin.ID == BuiltinValueKind::AddressOfRawLayout) {
1505+
auto addr = args.claimNext();
1506+
auto value = IGF.Builder.CreateBitCast(addr, IGF.IGM.Int8PtrTy);
1507+
out.add(value);
1508+
return;
1509+
}
1510+
15011511
llvm_unreachable("IRGen unimplemented for this builtin!");
15021512
}

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,6 +892,7 @@ BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, TargetOSVersionAtLeast)
892892
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GetEnumTag)
893893
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, InjectEnumTag)
894894
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, DistributedActorAsAnyActor)
895+
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AddressOfRawLayout)
895896
OperandOwnership OperandOwnershipBuiltinClassifier::visitCopy(BuiltinInst *bi,
896897
StringRef) {
897898
if (bi->getFunction()->getConventions().useLoweredAddresses()) {

lib/SIL/IR/ValueOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,7 @@ CONSTANT_OWNERSHIP_BUILTIN(None, GetEnumTag)
620620
CONSTANT_OWNERSHIP_BUILTIN(None, InjectEnumTag)
621621
CONSTANT_OWNERSHIP_BUILTIN(Owned, DistributedActorAsAnyActor)
622622
CONSTANT_OWNERSHIP_BUILTIN(Guaranteed, ExtractFunctionIsolation) // unreachable
623+
CONSTANT_OWNERSHIP_BUILTIN(None, AddressOfRawLayout)
623624

624625
#undef CONSTANT_OWNERSHIP_BUILTIN
625626

lib/SIL/Utils/MemAccessUtils.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2667,6 +2667,7 @@ static void visitBuiltinAddress(BuiltinInst *builtin,
26672667
// These builtins take a generic 'T' as their operand.
26682668
case BuiltinValueKind::GetEnumTag:
26692669
case BuiltinValueKind::InjectEnumTag:
2670+
case BuiltinValueKind::AddressOfRawLayout:
26702671
visitor(&builtin->getAllOperands()[0]);
26712672
return;
26722673

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,12 @@ struct ImmutableAddressUseVerifier {
611611
if (builtinKind == BuiltinValueKind::GetEnumTag) {
612612
return false;
613613
}
614+
615+
// The optimizer cannot reason about a raw layout type's address due
616+
// to it not respecting formal access scopes.
617+
if (builtinKind == BuiltinValueKind::AddressOfRawLayout) {
618+
return false;
619+
}
614620
}
615621

616622
// Otherwise this is a builtin that we are not expecting to see, so bail

lib/SILGen/SILGenBuiltin.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2006,6 +2006,21 @@ static ManagedValue emitBuiltinDistributedActorAsAnyActor(
20062006
return SGF.emitDistributedActorAsAnyActor(loc, subs, args[0]);
20072007
}
20082008

2009+
static ManagedValue emitBuiltinAddressOfRawLayout(SILGenFunction &SGF,
2010+
SILLocation loc,
2011+
SubstitutionMap subs,
2012+
ArrayRef<ManagedValue> args,
2013+
SGFContext C) {
2014+
auto &ctx = SGF.getASTContext();
2015+
2016+
auto bi = SGF.B.createBuiltin(
2017+
loc, ctx.getIdentifier(getBuiltinName(BuiltinValueKind::AddressOfRawLayout)),
2018+
SILType::getRawPointerType(ctx), subs,
2019+
{ args[0].getValue() });
2020+
2021+
return ManagedValue::forObjectRValueWithoutOwnership(bi);
2022+
}
2023+
20092024
std::optional<SpecializedEmitter>
20102025
SpecializedEmitter::forDecl(SILGenModule &SGM, SILDeclRef function) {
20112026
// Only consider standalone declarations in the Builtin module.

lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ static bool isBarrier(SILInstruction *inst) {
159159
case BuiltinValueKind::GetEnumTag:
160160
case BuiltinValueKind::InjectEnumTag:
161161
case BuiltinValueKind::ExtractFunctionIsolation:
162+
case BuiltinValueKind::AddressOfRawLayout:
162163
return false;
163164

164165
// Handle some rare builtins that may be sensitive to object lifetime

test/IRGen/raw_layout.swift

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// RUN: %{python} %utils/chex.py < %s > %t/raw_layout.sil
33
// RUN: %target-swift-frontend -enable-experimental-feature RawLayout -emit-ir -disable-availability-checking %t/raw_layout.sil | %FileCheck %t/raw_layout.sil --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize
44

5+
import Builtin
56
import Swift
67

78
// CHECK-LABEL: @"$s{{[A-Za-z0-9_]*}}4LockVWV" = {{.*}} %swift.vwtable
@@ -142,6 +143,33 @@ struct BadBuffer: ~Copyable {
142143
let buffer: SmallVectorOf3<Int64?>
143144
}
144145

146+
sil @use_lock : $@convention(thin) (@in_guaranteed Lock) -> () {
147+
entry(%L: $*Lock):
148+
return undef : $()
149+
}
150+
151+
sil @use_keymaster_locks : $@convention(thin) (@in_guaranteed Keymaster) -> () {
152+
entry(%K: $*Keymaster):
153+
%f = function_ref @use_lock : $@convention(thin) (@in_guaranteed Lock) -> ()
154+
%a = struct_element_addr %K : $*Keymaster, #Keymaster.lock1
155+
apply %f(%a) : $@convention(thin) (@in_guaranteed Lock) -> ()
156+
%b = struct_element_addr %K : $*Keymaster, #Keymaster.lock2
157+
apply %f(%b) : $@convention(thin) (@in_guaranteed Lock) -> ()
158+
%c = struct_element_addr %K : $*Keymaster, #Keymaster.lock2
159+
apply %f(%c) : $@convention(thin) (@in_guaranteed Lock) -> ()
160+
return undef : $()
161+
}
162+
163+
// CHECK: define {{.*}}swiftcc ptr @get_cell_addr(ptr %"Cell<T>", ptr {{.*}} swiftself [[SELF:%.*]])
164+
// CHECK-NEXT: entry:
165+
// CHECK-NEXT: ret ptr [[SELF]]
166+
sil @get_cell_addr : $@convention(method) <T> (@in_guaranteed Cell<T>) -> UnsafeMutablePointer<T> {
167+
entry(%0 : $*Cell<T>):
168+
%1 = builtin "addressOfRawLayout"(%0 : $*Cell<T>) : $Builtin.RawPointer
169+
%2 = struct $UnsafeMutablePointer<T> (%1 : $Builtin.RawPointer)
170+
return %2 : $UnsafeMutablePointer<T>
171+
}
172+
145173
// Dependent layout metadata initialization:
146174

147175
// Cell<T>
@@ -165,20 +193,3 @@ struct BadBuffer: ~Copyable {
165193

166194
// CHECK-LABEL: define {{.*}} swiftcc %swift.metadata_response @"$s{{[A-Za-z0-9_]*}}14SmallVectorBufVMr"(ptr %"SmallVectorBuf<T>", ptr {{.*}}, ptr {{.*}})
167195
// CHECK: call void @swift_initRawStructMetadata(ptr %"SmallVectorBuf<T>", {{i64|i32}} 0, ptr {{%.*}}, {{i64|i32}} 8)
168-
169-
sil @use_lock : $@convention(thin) (@in_guaranteed Lock) -> () {
170-
entry(%L: $*Lock):
171-
return undef : $()
172-
}
173-
174-
sil @use_keymaster_locks : $@convention(thin) (@in_guaranteed Keymaster) -> () {
175-
entry(%K: $*Keymaster):
176-
%f = function_ref @use_lock : $@convention(thin) (@in_guaranteed Lock) -> ()
177-
%a = struct_element_addr %K : $*Keymaster, #Keymaster.lock1
178-
apply %f(%a) : $@convention(thin) (@in_guaranteed Lock) -> ()
179-
%b = struct_element_addr %K : $*Keymaster, #Keymaster.lock2
180-
apply %f(%b) : $@convention(thin) (@in_guaranteed Lock) -> ()
181-
%c = struct_element_addr %K : $*Keymaster, #Keymaster.lock2
182-
apply %f(%c) : $@convention(thin) (@in_guaranteed Lock) -> ()
183-
return undef : $()
184-
}

test/SILGen/raw_layout.swift

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
// RUN: %target-swift-emit-silgen -enable-experimental-feature RawLayout %s | %FileCheck %s
1+
// RUN: %target-swift-emit-silgen -enable-experimental-feature RawLayout -enable-builtin-module %s | %FileCheck %s
22

33

44

55
// CHECK: @_rawLayout(size: 4, alignment: 4) struct Lock : ~Copyable
66
// CHECK: @_rawLayout(like: T) struct Cell<T> : ~Copyable
77
// CHECK: @_rawLayout(likeArrayOf: T, count: 8) struct SmallVectorBuf<T> : ~Copyable
88

9+
import Builtin
10+
911
@_rawLayout(size: 4, alignment: 4)
1012
struct Lock: ~Copyable {
1113
// Raw layout type should be lowered as address only
@@ -22,7 +24,18 @@ struct Lock: ~Copyable {
2224
}
2325

2426
@_rawLayout(like: T)
25-
struct Cell<T>: ~Copyable {}
27+
struct Cell<T>: ~Copyable {
28+
// CHECK-LABEL: sil {{.*}} @$s10raw_layout4CellV7addressSpyxGvg : $@convention(method) <T> (@in_guaranteed Cell<T>) -> UnsafeMutablePointer<T> {
29+
// CHECK: {{%.*}} = builtin "addressOfRawLayout"<Cell<T>>({{%.*}} : $*Cell<T>) : $Builtin.RawPointer
30+
// CHECK-LABEL: } // end sil function '$s10raw_layout4CellV7addressSpyxGvg'
31+
var address: UnsafeMutablePointer<T> {
32+
.init(Builtin.addressOfRawLayout(self))
33+
}
34+
35+
init(_ value: consuming T) {
36+
address.initialize(to: value)
37+
}
38+
}
2639

2740
@_rawLayout(likeArrayOf: T, count: 8)
2841
struct SmallVectorBuf<T>: ~Copyable {}

test/SILOptimizer/stdlib/Cell.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %target-swift-frontend -O -emit-sil -disable-availability-checking %s -enable-builtin-module -enable-experimental-feature RawLayout -enable-experimental-feature NoncopyableGenerics | %FileCheck %s
2+
3+
import Builtin
4+
5+
@frozen
6+
@_rawLayout(like: T)
7+
public struct Cell<T: ~Copyable>: ~Copyable {
8+
// CHECK-LABEL: sil {{.*}} @$s4CellAAVAARi_zrlE7addressSpyxGvg : $@convention(method) <T where T : ~Copyable> (@in_guaranteed Cell<T>) -> UnsafeMutablePointer<T> {
9+
// CHECK: bb0([[SELF:%.*]] : $*Cell<T>):
10+
// CHECK: [[RAW_LAYOUT_ADDR:%.*]] = builtin "addressOfRawLayout"<Cell<T>>([[SELF]] : $*Cell<T>) : $Builtin.RawPointer
11+
// CHECK-NEXT: [[POINTER:%.*]] = struct $UnsafeMutablePointer<T> ([[RAW_LAYOUT_ADDR]] : $Builtin.RawPointer)
12+
// CHECK-NEXT: return [[POINTER]] : $UnsafeMutablePointer<T>
13+
// CHECK-LABEL: } // end sil function '$s4CellAAVAARi_zrlE7addressSpyxGvg'
14+
@_transparent
15+
public var address: UnsafeMutablePointer<T> {
16+
.init(Builtin.addressOfRawLayout(self))
17+
}
18+
19+
// CHECK-LABEL: sil {{.*}} @$s4CellAAVAARi_zrlEyAByxGxcfC : $@convention(method) <T where T : ~Copyable> (@in T, @thin Cell<T>.Type) -> @out Cell<T> {
20+
// CHECK: bb0({{%.*}} : $*Cell<T>, [[VALUE:%.*]] : $*T, {{%.*}} : $@thin Cell<T>.Type):
21+
// CHECK: {{%.*}} = builtin "zeroInitializer"<Cell<T>>([[SELF:%.*]] : $*Cell<T>) : $()
22+
// CHECK-NEXT: [[RAW_LAYOUT_ADDR:%.*]] = builtin "addressOfRawLayout"<Cell<T>>([[SELF]] : $*Cell<T>) : $Builtin.RawPointer
23+
// CHECK-NEXT: [[POINTER:%.*]] = struct $UnsafeMutablePointer<T> ([[RAW_LAYOUT_ADDR]] : $Builtin.RawPointer)
24+
// Calling 'UnsafeMutablePointer<T>.initialize(to:)'
25+
// CHECK: {{%.*}} = apply {{%.*}}<T>([[VALUE]], [[POINTER]])
26+
// CHECK-LABEL: } // end sil function '$s4CellAAVAARi_zrlEyAByxGxcfC'
27+
@_transparent
28+
public init(_ value: consuming T) {
29+
address.initialize(to: value)
30+
}
31+
32+
@inlinable
33+
deinit {
34+
address.deinitialize(count: 1)
35+
}
36+
}

0 commit comments

Comments
 (0)