Skip to content

[Wasm][IRGen] Add initial support for unconditional absolute function pointer #42094

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
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
5 changes: 5 additions & 0 deletions include/swift/AST/IRGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,11 @@ class IRGenOptions {
unsigned LazyInitializeProtocolConformances : 1;
unsigned IndirectAsyncFunctionPointer : 1;

/// Use absolute function references instead of relative ones.
/// Mainly used on WebAssembly, that doesn't support relative references
/// to code from data.
unsigned CompactAbsoluteFunctionPointer : 1;

/// Normally if the -read-legacy-type-info flag is not specified, we look for
/// a file named "legacy-<arch>.yaml" in SearchPathOpts.RuntimeLibraryPath.
/// Passing this flag completely disables this behavior.
Expand Down
8 changes: 8 additions & 0 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2153,6 +2153,14 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
// AsyncFunctionPointer access.
Opts.IndirectAsyncFunctionPointer = Triple.isOSBinFormatCOFF();

// On some Harvard architectures that allow sliding code and data address space
// offsets independently, it's impossible to make direct relative reference to
// code from data because the relative offset between them is not representable.
// Use absolute function references instead of relative ones on such targets.
// TODO(katei): This is a short-term solution until the WebAssembly target stabilizes
// PIC and 64-bit specifications and toolchain support.
Opts.CompactAbsoluteFunctionPointer = Triple.isOSBinFormatWasm();

if (Args.hasArg(OPT_disable_legacy_type_info)) {
Opts.DisableLegacyTypeInfo = true;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/IRGen/ConformanceDescription.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class ConformanceDescription {

/// The instantiation function, to be run at the end of witness table
/// instantiation.
llvm::Constant *instantiationFn = nullptr;
llvm::Function *instantiationFn = nullptr;

/// The resilient witnesses, if any.
SmallVector<llvm::Constant *, 4> resilientWitnesses;
Expand Down
23 changes: 23 additions & 0 deletions lib/IRGen/ConstantBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===//

#include "swift/ABI/MetadataValues.h"
#include "swift/AST/IRGenOptions.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/GlobalVariable.h"
Expand Down Expand Up @@ -81,6 +82,26 @@ class ConstantAggregateBuilderBase

void addSize(Size size) { addInt(IGM().SizeTy, size.getValue()); }

void addCompactFunctionReferenceOrNull(llvm::Function *function) {
if (function) {
addCompactFunctionReference(function);
} else {
addInt(IGM().RelativeAddressTy, 0);
}
}

/// Add a 32-bit function reference to the given function. The reference
/// is direct relative pointer whenever possible. Otherwise, it is a
/// absolute pointer assuming the function address is 32-bit.
void addCompactFunctionReference(llvm::Function *function) {
if (IGM().getOptions().CompactAbsoluteFunctionPointer) {
// Assume that the function address is 32-bit.
add(llvm::ConstantExpr::getPtrToInt(function, IGM().RelativeAddressTy));
} else {
addRelativeOffset(IGM().RelativeAddressTy, function);
}
}

void addRelativeAddressOrNull(llvm::Constant *target) {
if (target) {
addRelativeAddress(target);
Expand All @@ -91,6 +112,8 @@ class ConstantAggregateBuilderBase

void addRelativeAddress(llvm::Constant *target) {
assert(!isa<llvm::ConstantPointerNull>(target));
assert((!IGM().getOptions().CompactAbsoluteFunctionPointer ||
!isa<llvm::Function>(target)) && "use addCompactFunctionReference");
addRelativeOffset(IGM().RelativeAddressTy, target);
}

Expand Down
4 changes: 2 additions & 2 deletions lib/IRGen/GenCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2086,7 +2086,7 @@ std::pair<llvm::Value *, llvm::Value *> irgen::getAsyncFunctionAndSize(
llvm::Value *addrPtr = IGF.Builder.CreateStructGEP(
getAFPPtr()->getType()->getScalarType()->getPointerElementType(),
getAFPPtr(), 0);
fn = IGF.emitLoadOfRelativePointer(
fn = IGF.emitLoadOfCompactFunctionPointer(
Address(addrPtr, IGF.IGM.getPointerAlignment()), /*isFar*/ false,
/*expectedType*/ functionPointer.getFunctionType()->getPointerTo());
}
Expand Down Expand Up @@ -4955,7 +4955,7 @@ llvm::Value *FunctionPointer::getPointer(IRGenFunction &IGF) const {
auto *addrPtr = IGF.Builder.CreateStructGEP(
descriptorPtr->getType()->getScalarType()->getPointerElementType(),
descriptorPtr, 0);
auto *result = IGF.emitLoadOfRelativePointer(
auto *result = IGF.emitLoadOfCompactFunctionPointer(
Address(addrPtr, IGF.IGM.getPointerAlignment()), /*isFar*/ false,
/*expectedType*/ getFunctionType()->getPointerTo());
if (auto codeAuthInfo = AuthInfo.getCorrespondingCodeAuthInfo()) {
Expand Down
2 changes: 1 addition & 1 deletion lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2063,7 +2063,7 @@ void IRGenerator::emitEntryPointInfo() {
auto &IGM = *getGenModule(entrypoint);
ConstantInitBuilder builder(IGM);
auto entrypointInfo = builder.beginStruct();
entrypointInfo.addRelativeAddress(
entrypointInfo.addCompactFunctionReference(
IGM.getAddrOfSILFunction(entrypoint, NotForDefinition));
auto var = entrypointInfo.finishAndCreateGlobal(
"\x01l_entry_point", Alignment(4),
Expand Down
12 changes: 6 additions & 6 deletions lib/IRGen/GenKeyPath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ getAccessorForComputedComponent(IRGenModule &IGM,
return accessorThunk;
}

static llvm::Constant *
static llvm::Function *
getLayoutFunctionForComputedComponent(IRGenModule &IGM,
const KeyPathPatternComponent &component,
GenericEnvironment *genericEnv,
Expand Down Expand Up @@ -548,7 +548,7 @@ struct KeyPathIndexOperand {
const KeyPathPatternComponent *LastUser;
};

static llvm::Constant *
static llvm::Function *
getInitializerForComputedComponent(IRGenModule &IGM,
const KeyPathPatternComponent &component,
ArrayRef<KeyPathIndexOperand> operands,
Expand Down Expand Up @@ -1101,12 +1101,12 @@ emitKeyPathComponent(IRGenModule &IGM,
}

// Push the accessors, possibly thunked to marshal generic environment.
fields.addRelativeAddress(
fields.addCompactFunctionReference(
getAccessorForComputedComponent(IGM, component, Getter,
genericEnv, requirements,
hasSubscriptIndices));
if (settable)
fields.addRelativeAddress(
fields.addCompactFunctionReference(
getAccessorForComputedComponent(IGM, component, Setter,
genericEnv, requirements,
hasSubscriptIndices));
Expand All @@ -1116,7 +1116,7 @@ emitKeyPathComponent(IRGenModule &IGM,
// arguments in the component. Thunk the SIL-level accessors to give the
// runtime implementation a polymorphically-callable interface.

fields.addRelativeAddress(
fields.addCompactFunctionReference(
getLayoutFunctionForComputedComponent(IGM, component,
genericEnv, requirements));

Expand All @@ -1136,7 +1136,7 @@ emitKeyPathComponent(IRGenModule &IGM,

// Add an initializer function that copies generic arguments out of the
// pattern argument buffer into the instantiated object.
fields.addRelativeAddress(
fields.addCompactFunctionReference(
getInitializerForComputedComponent(IGM, component, operands,
genericEnv, requirements));
}
Expand Down
66 changes: 37 additions & 29 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,13 +302,13 @@ static void buildMethodDescriptorFields(IRGenModule &IGM,
assert(entry->getKind() == SILVTable::Entry::Kind::Normal);

auto *impl = entry->getImplementation();
llvm::Constant *implFn;
if (impl->isAsync())
implFn = IGM.getAddrOfAsyncFunctionPointer(impl);
else
implFn = IGM.getAddrOfSILFunction(impl, NotForDefinition);

descriptor.addRelativeAddress(implFn);
if (impl->isAsync()) {
llvm::Constant *implFn = IGM.getAddrOfAsyncFunctionPointer(impl);
descriptor.addRelativeAddress(implFn);
} else {
llvm::Function *implFn = IGM.getAddrOfSILFunction(impl, NotForDefinition);
descriptor.addCompactFunctionReference(implFn);
}
} else {
// The method is removed by dead method elimination.
// It should be never called. We add a pointer to an error function.
Expand Down Expand Up @@ -962,7 +962,15 @@ namespace {
reqt.addInt32(info.Flags.getIntValue());

// Default implementation.
reqt.addRelativeAddressOrNull(info.DefaultImpl);
if (info.DefaultImpl) {
if (auto *fn = llvm::dyn_cast<llvm::Function>(info.DefaultImpl)) {
reqt.addCompactFunctionReference(fn);
} else {
reqt.addRelativeAddress(info.DefaultImpl);
}
} else {
reqt.addRelativeAddressOrNull(nullptr);
}

reqt.finishAndAddTo(B);
}
Expand Down Expand Up @@ -1226,7 +1234,7 @@ namespace {
}

void addAccessFunction() {
llvm::Constant *accessor;
llvm::Function *accessor;

// Don't include an access function if we're emitting the context
// descriptor without metadata.
Expand All @@ -1247,7 +1255,7 @@ namespace {
accessor = getOtherwiseDefinedTypeMetadataAccessFunction(IGM, type);
}

B.addRelativeAddressOrNull(accessor);
B.addCompactFunctionReferenceOrNull(accessor);
}

ConstantReference getParent() {
Expand Down Expand Up @@ -1376,12 +1384,12 @@ namespace {

/// Add a ForeignMetadataInitialization structure to the descriptor.
void addForeignMetadataInitialization() {
llvm::Constant *completionFunction = nullptr;
llvm::Function *completionFunction = nullptr;
if (asImpl().needsForeignMetadataCompletionFunction()) {
completionFunction =
IGM.getAddrOfTypeMetadataCompletionFunction(Type, NotForDefinition);
}
B.addRelativeAddressOrNull(completionFunction);
B.addCompactFunctionReferenceOrNull(completionFunction);
}

bool needsForeignMetadataCompletionFunction() {
Expand All @@ -1402,7 +1410,7 @@ namespace {
// Completion function.
auto completionFunction =
IGM.getAddrOfTypeMetadataCompletionFunction(Type, NotForDefinition);
B.addRelativeAddress(completionFunction);
B.addCompactFunctionReference(completionFunction);
}

void addIncompleteMetadata() {
Expand Down Expand Up @@ -1905,13 +1913,13 @@ namespace {
assert(entry->getKind() == SILVTable::Entry::Kind::Override);

auto *impl = entry->getImplementation();
llvm::Constant *implFn;
if (impl->isAsync())
implFn = IGM.getAddrOfAsyncFunctionPointer(impl);
else
implFn = IGM.getAddrOfSILFunction(impl, NotForDefinition);

descriptor.addRelativeAddress(implFn);
if (impl->isAsync()) {
llvm::Constant *implFn = IGM.getAddrOfAsyncFunctionPointer(impl);
descriptor.addRelativeAddress(implFn);
} else {
llvm::Function *implFn = IGM.getAddrOfSILFunction(impl, NotForDefinition);
descriptor.addCompactFunctionReference(implFn);
}
} else {
// The method is removed by dead method elimination.
// It should be never called. We add a pointer to an error function.
Expand Down Expand Up @@ -2005,7 +2013,7 @@ namespace {
}
auto specialization = pair.first;
auto *function = IGM.getAddrOfCanonicalSpecializedGenericTypeMetadataAccessFunction(specialization, NotForDefinition);
B.addRelativeAddress(function);
B.addCompactFunctionReference(function);
}
}
};
Expand Down Expand Up @@ -2723,7 +2731,7 @@ namespace {
void addInstantiationFunction() {
auto function = IGM.getAddrOfTypeMetadataInstantiationFunction(Target,
NotForDefinition);
B.addRelativeAddress(function);
B.addCompactFunctionReference(function);
}

void addCompletionFunction() {
Expand All @@ -2734,7 +2742,7 @@ namespace {

auto function = IGM.getAddrOfTypeMetadataCompletionFunction(Target,
NotForDefinition);
B.addRelativeAddress(function);
B.addCompactFunctionReference(function);
}

void addPatternFlags() {
Expand Down Expand Up @@ -2935,7 +2943,7 @@ static void emitClassMetadataBaseOffset(IRGenModule &IGM,
offsetVar->setConstant(true);
}

static Optional<llvm::Constant *>
static Optional<llvm::Function *>
getAddrOfDestructorFunction(IRGenModule &IGM, ClassDecl *classDecl) {
auto dtorRef = SILDeclRef(classDecl->getDestructor(),
SILDeclRef::Kind::Deallocator);
Expand Down Expand Up @@ -3539,15 +3547,15 @@ namespace {

void addDestructorFunction() {
auto function = getAddrOfDestructorFunction(IGM, Target);
B.addRelativeAddressOrNull(function ? *function : nullptr);
B.addCompactFunctionReferenceOrNull(function ? *function : nullptr);
}

void addIVarDestroyer() {
auto function = IGM.getAddrOfIVarInitDestroy(Target,
/*isDestroyer=*/ true,
/*isForeign=*/ false,
NotForDefinition);
B.addRelativeAddressOrNull(function ? *function : nullptr);
B.addCompactFunctionReferenceOrNull(function ? *function : nullptr);
}

void addClassFlags() {
Expand Down Expand Up @@ -3663,15 +3671,15 @@ namespace {

void addDestructorFunction() {
auto function = getAddrOfDestructorFunction(IGM, Target);
B.addRelativeAddressOrNull(function ? *function : nullptr);
B.addCompactFunctionReferenceOrNull(function ? *function : nullptr);
}

void addIVarDestroyer() {
auto function = IGM.getAddrOfIVarInitDestroy(Target,
/*isDestroyer=*/ true,
/*isForeign=*/ false,
NotForDefinition);
B.addRelativeAddressOrNull(function ? *function : nullptr);
B.addCompactFunctionReferenceOrNull(function ? *function : nullptr);
}

bool hasExtraDataPattern() {
Expand Down Expand Up @@ -5614,7 +5622,7 @@ llvm::GlobalValue *irgen::emitAsyncFunctionPointer(IRGenModule &IGM,
ConstantInitBuilder initBuilder(IGM);
ConstantStructBuilder builder(
initBuilder.beginStruct(IGM.AsyncFunctionPointerTy));
builder.addRelativeAddress(function);
builder.addCompactFunctionReference(function);
builder.addInt32(size.getValue());
return cast<llvm::GlobalValue>(IGM.defineAsyncFunctionPointer(
entity, builder.finishAndCreateFuture()));
Expand Down
15 changes: 10 additions & 5 deletions lib/IRGen/GenProto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1472,7 +1472,7 @@ class AccessorConformanceInfo : public ConformanceInfo {

/// Build the instantiation function that runs at the end of witness
/// table specialization.
llvm::Constant *buildInstantiationFunction();
llvm::Function *buildInstantiationFunction();
};

/// A resilient witness table consists of a list of descriptor/witness pairs,
Expand Down Expand Up @@ -1741,7 +1741,7 @@ void ResilientWitnessTableBuilder::collectResilientWitnesses(
}
}

llvm::Constant *FragileWitnessTableBuilder::buildInstantiationFunction() {
llvm::Function *FragileWitnessTableBuilder::buildInstantiationFunction() {
// We need an instantiation function if any base conformance
// is non-dependent.
if (SpecializedBaseConformances.empty())
Expand Down Expand Up @@ -1962,7 +1962,12 @@ namespace {
}

// Add the witness.
B.addRelativeAddress(witnesses.front());
llvm::Constant *witness = witnesses.front();
if (auto *fn = llvm::dyn_cast<llvm::Function>(witness)) {
B.addCompactFunctionReference(fn);
} else {
B.addRelativeAddress(witness);
}
witnesses = witnesses.drop_front();
}
assert(witnesses.empty() && "Wrong # of resilient witnesses");
Expand All @@ -1979,7 +1984,7 @@ namespace {
(Description.witnessTablePrivateSize << 1) |
Description.requiresSpecialization);
// Instantiation function
B.addRelativeAddressOrNull(Description.instantiationFn);
B.addCompactFunctionReferenceOrNull(Description.instantiationFn);

// Private data
if (IGM.IRGen.Opts.NoPreallocatedInstantiationCaches) {
Expand Down Expand Up @@ -2255,7 +2260,7 @@ void IRGenModule::emitSILWitnessTable(SILWitnessTable *wt) {

unsigned tableSize = 0;
llvm::GlobalVariable *global = nullptr;
llvm::Constant *instantiationFunction = nullptr;
llvm::Function *instantiationFunction = nullptr;
bool isDependent = isDependentConformance(conf);
SmallVector<llvm::Constant *, 4> resilientWitnesses;

Expand Down
Loading