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:
Joe Groff
2025-09-03 08:38:13 -07:00
parent 96900f9bd0
commit ee2ee0b560
4 changed files with 69 additions and 9 deletions

View File

@@ -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);
}
}

View File

@@ -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) {

View File

@@ -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.

View 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)
}
}
}