Skip to content

IRGen: re-enable generate static arrays in read-only data sections. #59612

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -880,6 +880,10 @@ class ASTContext final {
/// for extended existential types.
AvailabilityContext getParameterizedExistentialRuntimeAvailability();

/// Get the runtime availability of immortal ref-count symbols, which are
/// needed to place array buffers into constant data sections.
AvailabilityContext getImmortalRefCountSymbolsAvailability();

/// Get the runtime availability of features introduced in the Swift 5.2
/// compiler for the target platform.
AvailabilityContext getSwift52Availability();
Expand Down
5 changes: 4 additions & 1 deletion include/swift/AST/IRGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,8 @@ class IRGenOptions {
/// and protocol conformance caches.
unsigned NoPreallocatedInstantiationCaches : 1;

unsigned DisableReadonlyStaticObjects : 1;

/// The number of threads for multi-threaded code generation.
unsigned NumThreads = 0;

Expand Down Expand Up @@ -470,7 +472,8 @@ class IRGenOptions {
EnableGlobalISel(false), VirtualFunctionElimination(false),
WitnessMethodElimination(false), ConditionalRuntimeRecords(false),
InternalizeAtLink(false), InternalizeSymbols(false),
NoPreallocatedInstantiationCaches(false), CmdArgs(),
NoPreallocatedInstantiationCaches(false),
DisableReadonlyStaticObjects(false), CmdArgs(),
SanitizeCoverage(llvm::SanitizerCoverageOptions()),
TypeInfoFilter(TypeInfoDumpFilter::All) {
#ifndef NDEBUG
Expand Down
14 changes: 6 additions & 8 deletions include/swift/IRGen/Linking.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,9 @@ class LinkEntity {
/// A SIL global variable. The pointer is a SILGlobalVariable*.
SILGlobalVariable,

/// An outlined read-only global object. The pointer is a SILGlobalVariable*.
ReadOnlyGlobalObject,

// These next few are protocol-conformance kinds.

/// A direct protocol witness table. The secondary pointer is a
Expand Down Expand Up @@ -993,13 +996,7 @@ class LinkEntity {
return entity;
}

static LinkEntity forSILGlobalVariable(SILGlobalVariable *G) {
LinkEntity entity;
entity.Pointer = G;
entity.SecondaryPointer = nullptr;
entity.Data = LINKENTITY_SET_FIELD(Kind, unsigned(Kind::SILGlobalVariable));
return entity;
}
static LinkEntity forSILGlobalVariable(SILGlobalVariable *G, IRGenModule &IGM);

static LinkEntity
forDifferentiabilityWitness(const SILDifferentiabilityWitness *witness) {
Expand Down Expand Up @@ -1420,7 +1417,8 @@ class LinkEntity {
}

SILGlobalVariable *getSILGlobalVariable() const {
assert(getKind() == Kind::SILGlobalVariable);
assert(getKind() == Kind::SILGlobalVariable ||
getKind() == Kind::ReadOnlyGlobalObject);
return reinterpret_cast<SILGlobalVariable*>(Pointer);
}

Expand Down
4 changes: 4 additions & 0 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,10 @@ def disable_preallocated_instantiation_caches : Flag<["-"], "disable-preallocate
Flags<[FrontendOption, NoInteractiveOption, HelpHidden]>,
HelpText<"Avoid preallocating metadata instantiation caches in globals">;

def disable_readonly_static_objects : Flag<["-"], "disable-readonly-static-objects">,
Flags<[FrontendOption, NoInteractiveOption, HelpHidden]>,
HelpText<"Avoid allocating static objects in a read-only data section">;

def trap_function
: Separate<["-"], "trap-function">, MetaVarName<"<name>">,
HelpText<"Lower traps to calls to this function instead of trap instructions">;
Expand Down
7 changes: 7 additions & 0 deletions lib/AST/Availability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,13 @@ ASTContext::getParameterizedExistentialRuntimeAvailability() {
return getSwift57Availability();
}

AvailabilityContext
ASTContext::getImmortalRefCountSymbolsAvailability() {
// TODO: replace this with a concrete swift version once we have it.
// rdar://94185998
return getSwiftFutureAvailability();
}

AvailabilityContext ASTContext::getSwift52Availability() {
auto target = LangOpts.Target;

Expand Down
4 changes: 4 additions & 0 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2329,6 +2329,10 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
Opts.NoPreallocatedInstantiationCaches = true;
}

if (Args.hasArg(OPT_disable_readonly_static_objects)) {
Opts.DisableReadonlyStaticObjects = true;
}

// Default to disabling swift async extended frame info on anything but
// darwin. Other platforms are unlikely to have support for extended frame
// pointer information.
Expand Down
24 changes: 21 additions & 3 deletions lib/IRGen/GenConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,9 +278,27 @@ llvm::Constant *irgen::emitConstantObject(IRGenModule &IGM, ObjectInst *OI,
}
}
// Construct the object header.
llvm::Type *ObjectHeaderTy = sTy->getElementType(0);
assert(ObjectHeaderTy->isStructTy());
elts[0] = llvm::Constant::getNullValue(ObjectHeaderTy);
llvm::StructType *ObjectHeaderTy = cast<llvm::StructType>(sTy->getElementType(0));

if (IGM.canMakeStaticObjectsReadOnly()) {
if (!IGM.swiftImmortalRefCount) {
auto *var = new llvm::GlobalVariable(IGM.Module, IGM.Int8Ty,
/*constant*/ true, llvm::GlobalValue::ExternalLinkage,
/*initializer*/ nullptr, "_swiftImmortalRefCount");
IGM.swiftImmortalRefCount = var;
}
if (!IGM.swiftStaticArrayMetadata) {
auto *var = new llvm::GlobalVariable(IGM.Module, IGM.TypeMetadataStructTy,
/*constant*/ true, llvm::GlobalValue::ExternalLinkage,
/*initializer*/ nullptr, "_swiftStaticArrayMetadata");
IGM.swiftStaticArrayMetadata = var;
}
elts[0] = llvm::ConstantStruct::get(ObjectHeaderTy, {
IGM.swiftStaticArrayMetadata,
llvm::ConstantExpr::getPtrToInt(IGM.swiftImmortalRefCount, IGM.IntPtrTy)});
} else {
elts[0] = llvm::Constant::getNullValue(ObjectHeaderTy);
}
insertPadding(elts, sTy);
return llvm::ConstantStruct::get(sTy, elts);
}
Expand Down
41 changes: 23 additions & 18 deletions lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2482,7 +2482,7 @@ Address IRGenModule::getAddrOfSILGlobalVariable(SILGlobalVariable *var,
return Address(addr, alignment);
}

LinkEntity entity = LinkEntity::forSILGlobalVariable(var);
LinkEntity entity = LinkEntity::forSILGlobalVariable(var, *this);
ResilienceExpansion expansion = getResilienceExpansionForLayout(var);

llvm::Type *storageType;
Expand Down Expand Up @@ -2528,28 +2528,33 @@ Address IRGenModule::getAddrOfSILGlobalVariable(SILGlobalVariable *var,

// Check whether we've created the global variable already.
// FIXME: We should integrate this into the LinkEntity cache more cleanly.
auto gvar = Module.getGlobalVariable(var->getName(), /*allowInternal*/ true);
LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
auto gvar = Module.getGlobalVariable(link.getName(), /*allowInternal*/ true);
if (gvar) {
if (forDefinition)
updateLinkageForDefinition(*this, gvar, entity);
} else {
LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
llvm::Type *storageTypeWithContainer = storageType;
if (var->isInitializedObject()) {
// A statically initialized object must be placed into a container struct
// because the swift_initStaticObject needs a swift_once_t at offset -1:
// struct Container {
// swift_once_t token[fixedAlignment / sizeof(swift_once_t)];
// HeapObject object;
// };
std::string typeName = storageType->getStructName().str() + 'c';
assert(fixedAlignment >= getPointerAlignment());
unsigned numTokens = fixedAlignment.getValue() /
getPointerAlignment().getValue();
storageTypeWithContainer = llvm::StructType::create(getLLVMContext(),
{llvm::ArrayType::get(OnceTy, numTokens), storageType}, typeName);
gvar = createVariable(*this, link, storageTypeWithContainer,
fixedAlignment);
if (canMakeStaticObjectsReadOnly()) {
gvar = createVariable(*this, link, storageType, fixedAlignment);
gvar->setConstant(true);
} else {
// A statically initialized object must be placed into a container struct
// because the swift_initStaticObject needs a swift_once_t at offset -1:
// struct Container {
// swift_once_t token[fixedAlignment / sizeof(swift_once_t)];
// HeapObject object;
// };
std::string typeName = storageType->getStructName().str() + 'c';
assert(fixedAlignment >= getPointerAlignment());
unsigned numTokens = fixedAlignment.getValue() /
getPointerAlignment().getValue();
storageTypeWithContainer = llvm::StructType::create(getLLVMContext(),
{llvm::ArrayType::get(OnceTy, numTokens), storageType}, typeName);
gvar = createVariable(*this, link, storageTypeWithContainer,
fixedAlignment);
}
} else {
StringRef name;
Optional<SILLocation> loc;
Expand All @@ -2574,7 +2579,7 @@ Address IRGenModule::getAddrOfSILGlobalVariable(SILGlobalVariable *var,
gvar->setComdat(nullptr);
}
llvm::Constant *addr = gvar;
if (var->isInitializedObject()) {
if (var->isInitializedObject() && !canMakeStaticObjectsReadOnly()) {
// Project out the object from the container.
llvm::Constant *Indices[2] = {
llvm::ConstantExpr::getIntegerValue(Int32Ty, APInt(32, 0)),
Expand Down
13 changes: 13 additions & 0 deletions lib/IRGen/IRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1785,6 +1785,19 @@ bool IRGenModule::shouldPrespecializeGenericMetadata() {
canPrespecializeTarget;
}

bool IRGenModule::canMakeStaticObjectsReadOnly() {
if (getOptions().DisableReadonlyStaticObjects)
return false;

// TODO: Support constant static arrays on other platforms, too.
// See also the comment in GlobalObjects.cpp.
if (!Triple.isOSDarwin())
return false;

return getAvailabilityContext().isContainedIn(
Context.getImmortalRefCountSymbolsAvailability());
}

void IRGenerator::addGenModule(SourceFile *SF, IRGenModule *IGM) {
assert(GenModules.count(SF) == 0);
GenModules[SF] = IGM;
Expand Down
5 changes: 5 additions & 0 deletions lib/IRGen/IRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,9 @@ class IRGenModule {

llvm::GlobalVariable *TheTrivialPropertyDescriptor = nullptr;

llvm::GlobalVariable *swiftImmortalRefCount = nullptr;
llvm::GlobalVariable *swiftStaticArrayMetadata = nullptr;

/// Used to create unique names for class layout types with tail allocated
/// elements.
unsigned TailElemTypeID = 0;
Expand Down Expand Up @@ -886,6 +889,8 @@ class IRGenModule {

bool shouldPrespecializeGenericMetadata();

bool canMakeStaticObjectsReadOnly();

Size getAtomicBoolSize() const { return AtomicBoolSize; }
Alignment getAtomicBoolAlignment() const { return AtomicBoolAlign; }

Expand Down
19 changes: 13 additions & 6 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2765,7 +2765,7 @@ void IRGenSILFunction::visitGlobalValueInst(GlobalValueInst *i) {
NotForDefinition).getAddress();
// We don't need to initialize the global object if it's never used for
// something which can access the object header.
if (!hasOnlyProjections(i)) {
if (!hasOnlyProjections(i) && !IGM.canMakeStaticObjectsReadOnly()) {
auto ClassType = loweredTy.getASTType();
llvm::Value *Metadata =
emitClassHeapMetadataRef(*this, ClassType, MetadataValueType::TypeMetadata,
Expand Down Expand Up @@ -7099,8 +7099,11 @@ void IRGenModule::emitSILStaticInitializers() {
"cannot emit a static initializer for dynamically-sized global");
#endif

LinkEntity entity = LinkEntity::forSILGlobalVariable(&Global, *this);
std::string name = entity.mangleAsString();

auto *IRGlobal =
Module.getGlobalVariable(Global.getName(), true /* = AllowLocal */);
Module.getGlobalVariable(name, true /* = AllowLocal */);

// A check for multi-threaded compilation: Is this the llvm module where the
// global is defined and not only referenced (or not referenced at all).
Expand All @@ -7110,10 +7113,14 @@ void IRGenModule::emitSILStaticInitializers() {
if (auto *OI = dyn_cast<ObjectInst>(InitValue)) {
StructLayout *Layout = StaticObjectLayouts[&Global].get();
llvm::Constant *InitVal = emitConstantObject(*this, OI, Layout);
auto *ContainerTy = cast<llvm::StructType>(IRGlobal->getValueType());
auto *zero = llvm::ConstantAggregateZero::get(ContainerTy->getElementType(0));
IRGlobal->setInitializer(llvm::ConstantStruct::get(ContainerTy,
{zero , InitVal}));
if (canMakeStaticObjectsReadOnly()) {
IRGlobal->setInitializer(InitVal);
} else {
auto *ContainerTy = cast<llvm::StructType>(IRGlobal->getValueType());
auto *zero = llvm::ConstantAggregateZero::get(ContainerTy->getElementType(0));
IRGlobal->setInitializer(llvm::ConstantStruct::get(ContainerTy,
{zero , InitVal}));
}
continue;
}

Expand Down
19 changes: 19 additions & 0 deletions lib/IRGen/Linking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,18 @@ UniversalLinkageInfo::UniversalLinkageInfo(const llvm::Triple &triple,
UseDLLStorage(useDllStorage(triple)), Internalize(isStaticLibrary),
HasMultipleIGMs(hasMultipleIGMs), ForcePublicDecls(forcePublicDecls) {}

LinkEntity LinkEntity::forSILGlobalVariable(SILGlobalVariable *G,
IRGenModule &IGM) {
LinkEntity entity;
entity.Pointer = G;
entity.SecondaryPointer = nullptr;
auto kind = (G->isInitializedObject() && IGM.canMakeStaticObjectsReadOnly() ?
Kind::ReadOnlyGlobalObject : Kind::SILGlobalVariable);
entity.Data = unsigned(kind) << KindShift;
return entity;
}


/// Mangle this entity into the given buffer.
void LinkEntity::mangle(SmallVectorImpl<char> &buffer) const {
llvm::raw_svector_ostream stream(buffer);
Expand Down Expand Up @@ -454,6 +466,9 @@ std::string LinkEntity::mangleAsString() const {
case Kind::SILGlobalVariable:
return getSILGlobalVariable()->getName().str();

case Kind::ReadOnlyGlobalObject:
return getSILGlobalVariable()->getName().str() + "r";

case Kind::ReflectionBuiltinDescriptor:
return mangler.mangleReflectionBuiltinDescriptor(getType());
case Kind::ReflectionFieldDescriptor:
Expand Down Expand Up @@ -787,6 +802,7 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const {
return getSILLinkage(getDeclLinkage(getDecl()), forDefinition);

case Kind::SILGlobalVariable:
case Kind::ReadOnlyGlobalObject:
return getSILGlobalVariable()->getLinkage();

case Kind::ReflectionBuiltinDescriptor:
Expand Down Expand Up @@ -882,6 +898,7 @@ bool LinkEntity::isContextDescriptor() const {
case Kind::DefaultAssociatedConformanceAccessor:
case Kind::SILFunction:
case Kind::SILGlobalVariable:
case Kind::ReadOnlyGlobalObject:
case Kind::ProtocolWitnessTable:
case Kind::ProtocolWitnessTablePattern:
case Kind::GenericProtocolWitnessTableInstantiationFunction:
Expand Down Expand Up @@ -1129,6 +1146,7 @@ Alignment LinkEntity::getAlignment(IRGenModule &IGM) const {
bool LinkEntity::isWeakImported(ModuleDecl *module) const {
switch (getKind()) {
case Kind::SILGlobalVariable:
case Kind::ReadOnlyGlobalObject:
if (getSILGlobalVariable()->getDecl()) {
return getSILGlobalVariable()->getDecl()->isWeakImported(module);
}
Expand Down Expand Up @@ -1317,6 +1335,7 @@ DeclContext *LinkEntity::getDeclContextForEmission() const {
return getSILFunction()->getDeclContext();

case Kind::SILGlobalVariable:
case Kind::ReadOnlyGlobalObject:
if (auto decl = getSILGlobalVariable()->getDecl())
return decl->getDeclContext();

Expand Down
Loading