Files
swift-mirror/lib/SIL/IR/SILGlobalVariable.cpp
T
Doug Gregor 92dcbd17c6 [SIL] Explicitly keep the code generation model in SILGlobalVariable
Just like we do with SILFunction, allow a code generation model to be
specified on a SILGlobalVariable and maintain that through the printed
and serialized forms.
2026-05-20 08:35:22 -07:00

366 lines
11 KiB
C++

//===--- SILGlobalVariable.cpp - Defines SILGlobalVariable structure ------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/Basic/Assertions.h"
#include "swift/SIL/SILBridging.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILGlobalVariable.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILLinkage.h"
#include "swift/SIL/SILModule.h"
using namespace swift;
SwiftMetatype SILGlobalVariable::registeredMetatype;
SILGlobalVariable *SILGlobalVariable::create(SILModule &M, SILLinkage linkage,
SerializedKind_t serializedKind,
StringRef name,
SILType loweredType,
std::optional<SILLocation> loc,
VarDecl *Decl) {
// Get a StringMapEntry for the variable.
llvm::StringMapEntry<SILGlobalVariable*> *entry = nullptr;
assert(!name.empty() && "Name required");
entry = &*M.GlobalVariableMap.insert(std::make_pair(name, nullptr)).first;
assert(!entry->getValue() && "global variable already exists");
name = entry->getKey();
auto var = new (M) SILGlobalVariable(M, linkage, serializedKind, name,
loweredType, loc, Decl);
if (entry) entry->setValue(var);
return var;
}
ModuleDecl *SILGlobalVariable::getParentModule() const {
if (auto parentModule = DeclCtxOrParentModule.dyn_cast<ModuleDecl *>())
return parentModule;
if (auto declContext = DeclCtxOrParentModule.dyn_cast<DeclContext *>())
return declContext->getParentModule();
return getModule().getSwiftModule();
}
DeclContext *SILGlobalVariable::getDeclContext() const {
if (auto var = getDecl())
return var->getDeclContext();
if (auto declContext = DeclCtxOrParentModule.dyn_cast<DeclContext *>())
return declContext;
return nullptr;
}
static bool isGlobalLet(SILModule &mod, VarDecl *decl, SILType type) {
if (!decl)
return false;
if (!decl->isLet())
return false;
// Raw-layout storage may be mutated even for let-variables. Therefore don't
// treat such variables as `let` in SIL.
auto teCtxt = TypeExpansionContext::maximal(mod.getSwiftModule(),
mod.isWholeModule());
auto typeProps = mod.Types.getTypeProperties(type, teCtxt);
if (typeProps.isOrContainsRawLayout())
return false;
return true;
}
SILGlobalVariable::SILGlobalVariable(SILModule &Module, SILLinkage Linkage,
SerializedKind_t serializedKind,
StringRef Name, SILType LoweredType,
std::optional<SILLocation> Loc,
VarDecl *Decl)
: SwiftObjectHeader(registeredMetatype), Module(Module), Name(Name),
LoweredType(LoweredType), Location(Loc.value_or(SILLocation::invalid())),
Linkage(unsigned(Linkage)), HasLocation(Loc.has_value()), CodeGenModel(0),
VDecl(Decl) {
setSerializedKind(serializedKind);
IsDeclaration = isAvailableExternally(Linkage);
setLet(isGlobalLet(Module, Decl, LoweredType));
setMarkedAsUsed(Decl && Decl->getAttrs().hasAttribute<UsedAttr>());
if (Decl) {
auto cgModel = Decl->getExplicitCodeGenerationModel();
if (!cgModel && Module.getOptions().EmbeddedSwift)
cgModel = Decl->getEffectiveCodeGenerationModel();
if (cgModel) {
switch (*cgModel) {
case CodeGenerationModel::Interface:
case CodeGenerationModel::Implementation:
setCodeGenerationModel(*cgModel);
break;
case CodeGenerationModel::Inlinable:
break;
}
}
}
Module.silGlobals.push_back(this);
}
SILGlobalVariable::~SILGlobalVariable() {
clear();
}
void SILGlobalVariable::setAsmName(StringRef value) {
ASSERT((AsmName.empty() || value == AsmName) && "Cannot change asmname");
AsmName = value;
if (!value.empty()) {
// Update the variable-by-asm-name-table.
getModule().GlobalVariableByAsmNameMap.insert({AsmName, this});
}
}
std::optional<CodeGenerationModel>
SILGlobalVariable::codeGenerationModel() const {
if (CodeGenModel == 0)
return std::nullopt;
return static_cast<CodeGenerationModel>(CodeGenModel - 1);
}
void SILGlobalVariable::setCodeGenerationModel(
std::optional<CodeGenerationModel> value) {
if (value)
CodeGenModel = static_cast<unsigned>(*value) + 1;
else
CodeGenModel = 0;
}
bool SILGlobalVariable::isPossiblyUsedExternally() const {
if (shouldBePreservedForDebugger())
return true;
if (markedAsUsed())
return true;
if (!section().empty())
return true;
SILLinkage linkage = getLinkage();
return swift::isPossiblyUsedExternally(linkage, getModule().isWholeModule());
}
bool SILGlobalVariable::hasNonUniqueDefinition() const {
// Non-uniqueness is a property of the Embedded linkage model.
auto &ctx = getModule().getASTContext();
if (!ctx.LangOpts.hasFeature(Feature::Embedded))
return false;
// If a code generation model was recorded on this SIL global (either set at
// SIL construction time or recovered from serialization), use it directly so
// the answer matches across module boundaries.
if (auto cgModel = codeGenerationModel()) {
switch (*cgModel) {
case CodeGenerationModel::Implementation:
return true;
case CodeGenerationModel::Interface:
return false;
case CodeGenerationModel::Inlinable:
break;
}
}
// If this is for a declaration, ask it.
if (auto decl = getDecl()) {
return SILDeclRef::declHasNonUniqueDefinition(decl);
}
// If this variable is from a different module than the one we are emitting
// code for, then it must have a non-unique definition.
if (getParentModule() != getModule().getSwiftModule())
return true;
return false;
}
bool SILGlobalVariable::shouldBePreservedForDebugger() const {
if (getModule().getOptions().OptMode != OptimizationMode::NoOptimization)
return false;
// Keep any language-level global variables for the debugger.
return VDecl != nullptr;
}
bool SILGlobalVariable::isSerialized() const {
return SerializedKind_t(Serialized) == IsSerialized;
}
bool SILGlobalVariable::isAnySerialized() const {
return SerializedKind_t(Serialized) == IsSerialized ||
SerializedKind_t(Serialized) == IsSerializedForPackage;
}
/// Get this global variable's fragile attribute.
SerializedKind_t SILGlobalVariable::getSerializedKind() const {
return SerializedKind_t(Serialized);
}
void SILGlobalVariable::setSerializedKind(SerializedKind_t serializedKind) {
Serialized = unsigned(serializedKind);
}
/// Return the value that is written into the global variable.
SILInstruction *SILGlobalVariable::getStaticInitializerValue() {
if (StaticInitializerBlock.empty())
return nullptr;
return &StaticInitializerBlock.back();
}
bool SILGlobalVariable::mustBeInitializedStatically() const {
if (!section().empty())
return true;
auto *decl = getDecl();
if (decl && isDefinition() && decl->getAttrs().hasAttribute<SILGenNameAttr>())
return true;
if (decl && isDefinition() && decl->getAttrs().hasAttribute<ConstValAttr>())
return true;
if (decl && isDefinition() && decl->getAttrs().hasAttribute<ConstInitializedAttr>())
return true;
return false;
}
/// Return whether this variable corresponds to a Clang node.
bool SILGlobalVariable::hasClangNode() const {
return (VDecl ? VDecl->hasClangNode() : false);
}
/// Return the Clang node associated with this variable if it has one.
ClangNode SILGlobalVariable::getClangNode() const {
return (VDecl ? VDecl->getClangNode() : ClangNode());
}
const clang::Decl *SILGlobalVariable::getClangDecl() const {
return (VDecl ? VDecl->getClangDecl() : nullptr);
}
//===----------------------------------------------------------------------===//
// Utilities for verification and optimization.
//===----------------------------------------------------------------------===//
static SILGlobalVariable *getStaticallyInitializedVariable(SILFunction *AddrF) {
if (AddrF->isExternalDeclaration())
return nullptr;
auto ReturnBB = AddrF->findReturnBB();
if (ReturnBB == AddrF->end())
return nullptr;
auto *RetInst = cast<ReturnInst>(ReturnBB->getTerminator());
auto *API = dyn_cast<AddressToPointerInst>(RetInst->getOperand());
if (!API)
return nullptr;
auto *GAI = dyn_cast<GlobalAddrInst>(API->getOperand());
if (!GAI)
return nullptr;
return GAI->getReferencedGlobal();
}
SILGlobalVariable *swift::getVariableOfGlobalInit(SILFunction *AddrF) {
if (!AddrF->isGlobalInit())
return nullptr;
if (auto *SILG = getStaticallyInitializedVariable(AddrF))
return SILG;
// If the addressor contains a single "once" call, it calls globalinit_func,
// and the globalinit_func is called by "once" from a single location,
// continue; otherwise bail.
BuiltinInst *CallToOnce;
auto *InitF = findInitializer(AddrF, CallToOnce);
if (!InitF)
return nullptr;
return getVariableOfStaticInitializer(InitF);
}
SILFunction *swift::getCalleeOfOnceCall(BuiltinInst *BI) {
assert(BI->getNumOperands() == 2 && "once call should have 2 operands.");
auto Callee = BI->getOperand(1);
assert(Callee->getType().castTo<SILFunctionType>()->getRepresentation()
== SILFunctionTypeRepresentation::CFunctionPointer &&
"Expected C function representation!");
if (auto *FR = dyn_cast<FunctionRefInst>(Callee))
return FR->getReferencedFunction();
return nullptr;
}
// Find the globalinit_func by analyzing the body of the addressor.
SILFunction *swift::findInitializer(SILFunction *AddrF,
BuiltinInst *&CallToOnce) {
// We only handle a single SILBasicBlock for now.
if (AddrF->size() != 1)
return nullptr;
CallToOnce = nullptr;
SILBasicBlock *BB = &AddrF->front();
for (auto &I : *BB) {
// Find the builtin "once" call.
if (auto *BI = dyn_cast<BuiltinInst>(&I)) {
const BuiltinInfo &Builtin =
BI->getModule().getBuiltinInfo(BI->getName());
if (Builtin.ID != BuiltinValueKind::Once)
continue;
// Bail if we have multiple "once" calls in the addressor.
if (CallToOnce)
return nullptr;
CallToOnce = BI;
}
}
if (!CallToOnce)
return nullptr;
SILFunction *callee = getCalleeOfOnceCall(CallToOnce);
if (!callee->isGlobalInitOnceFunction())
return nullptr;
return callee;
}
SILGlobalVariable *swift::getVariableOfStaticInitializer(SILFunction *InitFunc) {
// We only handle a single SILBasicBlock for now.
if (InitFunc->size() != 1)
return nullptr;
for (auto &inst : InitFunc->front()) {
if (auto *agi = dyn_cast<AllocGlobalInst>(&inst)) {
return agi->getReferencedGlobal();
}
}
return nullptr;
}
SILType
SILGlobalVariable::getLoweredTypeInContext(TypeExpansionContext context) const {
auto ty = getLoweredType();
if (!ty.getASTType()->hasOpaqueArchetype() ||
!context.shouldLookThroughOpaqueTypeArchetypes())
return ty;
auto resultTy =
getModule().Types.getTypeLowering(ty, context).getLoweredType();
return resultTy.getCategoryType(ty.getCategory());
}