mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
SILGen: Global constants are addressable.
A global or static `let` has a stable address, which is addressable when its representation is naturally fully abstracted.
This commit is contained in:
@@ -3568,8 +3568,8 @@ SILGenFunction::tryEmitAddressableParameterAsAddress(ArgumentSource &&arg,
|
||||
}
|
||||
if (auto dre = dyn_cast<DeclRefExpr>(expr)) {
|
||||
if (auto param = dyn_cast<VarDecl>(dre->getDecl())) {
|
||||
if (auto addr = getLocalVariableAddressableBuffer(param, expr,
|
||||
ownership)) {
|
||||
if (auto addr = getVariableAddressableBuffer(param, expr,
|
||||
ownership)) {
|
||||
return ManagedValue::forBorrowedAddressRValue(addr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2263,12 +2263,41 @@ SILGenFunction::enterLocalVariableAddressableBufferScope(VarDecl *decl,
|
||||
Cleanups.pushCleanup<DeallocateLocalVariableAddressableBuffer>(decl, destroyCleanup);
|
||||
}
|
||||
|
||||
static bool isFullyAbstractedLowering(SILGenFunction &SGF,
|
||||
Type formalType, SILType loweredType) {
|
||||
return SGF.getLoweredType(AbstractionPattern::getOpaque(), formalType)
|
||||
.getASTType()
|
||||
== loweredType.getASTType();
|
||||
}
|
||||
|
||||
static bool isNaturallyFullyAbstractedType(SILGenFunction &SGF,
|
||||
Type formalType) {
|
||||
return isFullyAbstractedLowering(SGF, formalType, SGF.getLoweredType(formalType));
|
||||
}
|
||||
|
||||
SILValue
|
||||
SILGenFunction::getLocalVariableAddressableBuffer(VarDecl *decl,
|
||||
SILLocation curLoc,
|
||||
ValueOwnership ownership) {
|
||||
SILGenFunction::getVariableAddressableBuffer(VarDecl *decl,
|
||||
SILLocation curLoc,
|
||||
ValueOwnership ownership) {
|
||||
// For locals, we might be able to retroactively produce a local addressable
|
||||
// representation.
|
||||
auto foundVarLoc = VarLocs.find(decl);
|
||||
if (foundVarLoc == VarLocs.end()) {
|
||||
// If it's not local, is it at least a global stored variable?
|
||||
if (decl->isGlobalStorage()) {
|
||||
// Is the global immutable?
|
||||
if (!decl->isLet()) {
|
||||
return SILValue();
|
||||
}
|
||||
|
||||
// Does the storage naturally have a fully abstracted representation?
|
||||
if (!isNaturallyFullyAbstractedType(*this, decl->getTypeInContext())) {
|
||||
return SILValue();
|
||||
}
|
||||
|
||||
// We can get the stable address via the addressor.
|
||||
return emitGlobalVariableRef(curLoc, decl, std::nullopt).getUnmanagedValue();
|
||||
}
|
||||
return SILValue();
|
||||
}
|
||||
|
||||
@@ -2282,7 +2311,8 @@ SILGenFunction::getLocalVariableAddressableBuffer(VarDecl *decl,
|
||||
// Check whether the bound value is inherently suitable for addressability.
|
||||
// It must already be in memory and fully abstracted.
|
||||
if (value->getType().isAddress()
|
||||
&& fullyAbstractedTy.getASTType() == value->getType().getASTType()) {
|
||||
&& isFullyAbstractedLowering(*this, decl->getTypeInContext()->getRValueType(),
|
||||
value->getType())) {
|
||||
SILValue address = value;
|
||||
// Begin an access if the address is mutable.
|
||||
if (access != SILAccessEnforcement::Unknown) {
|
||||
|
||||
@@ -576,9 +576,9 @@ public:
|
||||
|
||||
/// Get a stable address which is suitable for forming dependent pointers
|
||||
/// if possible.
|
||||
SILValue getLocalVariableAddressableBuffer(VarDecl *decl,
|
||||
SILLocation loc,
|
||||
ValueOwnership ownership);
|
||||
SILValue getVariableAddressableBuffer(VarDecl *decl,
|
||||
SILLocation loc,
|
||||
ValueOwnership ownership);
|
||||
|
||||
/// The local auxiliary declarations for the parameters of this function that
|
||||
/// need to be emitted inside the next brace statement.
|
||||
|
||||
30
test/SILGen/addressable_global.swift
Normal file
30
test/SILGen/addressable_global.swift
Normal file
@@ -0,0 +1,30 @@
|
||||
// RUN: %target-swift-emit-silgen -parse-as-library -disable-availability-checking %s | %FileCheck %s
|
||||
|
||||
enum Color {
|
||||
case R, G, B
|
||||
}
|
||||
|
||||
let colors: InlineArray<_, Color> = [
|
||||
.G, .G, .R, .G, .G, .B,
|
||||
.G, .G, .B, .G, .G, .R,
|
||||
.B, .R, .G, .R, .B, .G,
|
||||
.G, .G, .B, .G, .G, .R,
|
||||
.G, .G, .R, .G, .G, .B,
|
||||
.R, .B, .G, .B, .R, .G,
|
||||
]
|
||||
|
||||
// CHECK-LABEL: sil{{.*}} @$s{{.*}}4main
|
||||
func main() {
|
||||
// CHECK: [[POINTER:%.*]] = apply {{.*}}() : $@convention(thin) () -> Builtin.RawPointer
|
||||
// CHECK: [[ADDRESS:%.*]] = pointer_to_address [[POINTER]]
|
||||
// CHECK: [[GET_SPAN:%.*]] = function_ref @$s{{.*}}11InlineArray{{.*}}4span
|
||||
// CHECK: apply [[GET_SPAN]]<{{.*}}>([[ADDRESS]])
|
||||
let span = colors.span
|
||||
for elem in [3, 9, 8] {
|
||||
switch span[elem] {
|
||||
case .R: print(0)
|
||||
case .G: print(1)
|
||||
case .B: print(2)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user