Skip to content

Commit 26ba097

Browse files
Merge pull request #42094 from kateinoigakukun/katei/wasm-uncond-abs-func-ptr
[Wasm][IRGen] Add initial support for unconditional absolute function pointer
2 parents 230c435 + 43a25e8 commit 26ba097

13 files changed

+120
-47
lines changed

include/swift/AST/IRGenOptions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,11 @@ class IRGenOptions {
320320
unsigned LazyInitializeProtocolConformances : 1;
321321
unsigned IndirectAsyncFunctionPointer : 1;
322322

323+
/// Use absolute function references instead of relative ones.
324+
/// Mainly used on WebAssembly, that doesn't support relative references
325+
/// to code from data.
326+
unsigned CompactAbsoluteFunctionPointer : 1;
327+
323328
/// Normally if the -read-legacy-type-info flag is not specified, we look for
324329
/// a file named "legacy-<arch>.yaml" in SearchPathOpts.RuntimeLibraryPath.
325330
/// Passing this flag completely disables this behavior.

lib/Frontend/CompilerInvocation.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2153,6 +2153,14 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
21532153
// AsyncFunctionPointer access.
21542154
Opts.IndirectAsyncFunctionPointer = Triple.isOSBinFormatCOFF();
21552155

2156+
// On some Harvard architectures that allow sliding code and data address space
2157+
// offsets independently, it's impossible to make direct relative reference to
2158+
// code from data because the relative offset between them is not representable.
2159+
// Use absolute function references instead of relative ones on such targets.
2160+
// TODO(katei): This is a short-term solution until the WebAssembly target stabilizes
2161+
// PIC and 64-bit specifications and toolchain support.
2162+
Opts.CompactAbsoluteFunctionPointer = Triple.isOSBinFormatWasm();
2163+
21562164
if (Args.hasArg(OPT_disable_legacy_type_info)) {
21572165
Opts.DisableLegacyTypeInfo = true;
21582166
}

lib/IRGen/ConformanceDescription.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class ConformanceDescription {
5353

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

5858
/// The resilient witnesses, if any.
5959
SmallVector<llvm::Constant *, 4> resilientWitnesses;

lib/IRGen/ConstantBuilder.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
//===----------------------------------------------------------------------===//
1515

1616
#include "swift/ABI/MetadataValues.h"
17+
#include "swift/AST/IRGenOptions.h"
1718
#include "llvm/IR/Constants.h"
1819
#include "llvm/IR/DerivedTypes.h"
1920
#include "llvm/IR/GlobalVariable.h"
@@ -81,6 +82,26 @@ class ConstantAggregateBuilderBase
8182

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

85+
void addCompactFunctionReferenceOrNull(llvm::Function *function) {
86+
if (function) {
87+
addCompactFunctionReference(function);
88+
} else {
89+
addInt(IGM().RelativeAddressTy, 0);
90+
}
91+
}
92+
93+
/// Add a 32-bit function reference to the given function. The reference
94+
/// is direct relative pointer whenever possible. Otherwise, it is a
95+
/// absolute pointer assuming the function address is 32-bit.
96+
void addCompactFunctionReference(llvm::Function *function) {
97+
if (IGM().getOptions().CompactAbsoluteFunctionPointer) {
98+
// Assume that the function address is 32-bit.
99+
add(llvm::ConstantExpr::getPtrToInt(function, IGM().RelativeAddressTy));
100+
} else {
101+
addRelativeOffset(IGM().RelativeAddressTy, function);
102+
}
103+
}
104+
84105
void addRelativeAddressOrNull(llvm::Constant *target) {
85106
if (target) {
86107
addRelativeAddress(target);
@@ -91,6 +112,8 @@ class ConstantAggregateBuilderBase
91112

92113
void addRelativeAddress(llvm::Constant *target) {
93114
assert(!isa<llvm::ConstantPointerNull>(target));
115+
assert((!IGM().getOptions().CompactAbsoluteFunctionPointer ||
116+
!isa<llvm::Function>(target)) && "use addCompactFunctionReference");
94117
addRelativeOffset(IGM().RelativeAddressTy, target);
95118
}
96119

lib/IRGen/GenCall.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2086,7 +2086,7 @@ std::pair<llvm::Value *, llvm::Value *> irgen::getAsyncFunctionAndSize(
20862086
llvm::Value *addrPtr = IGF.Builder.CreateStructGEP(
20872087
getAFPPtr()->getType()->getScalarType()->getPointerElementType(),
20882088
getAFPPtr(), 0);
2089-
fn = IGF.emitLoadOfRelativePointer(
2089+
fn = IGF.emitLoadOfCompactFunctionPointer(
20902090
Address(addrPtr, IGF.IGM.getPointerAlignment()), /*isFar*/ false,
20912091
/*expectedType*/ functionPointer.getFunctionType()->getPointerTo());
20922092
}
@@ -4955,7 +4955,7 @@ llvm::Value *FunctionPointer::getPointer(IRGenFunction &IGF) const {
49554955
auto *addrPtr = IGF.Builder.CreateStructGEP(
49564956
descriptorPtr->getType()->getScalarType()->getPointerElementType(),
49574957
descriptorPtr, 0);
4958-
auto *result = IGF.emitLoadOfRelativePointer(
4958+
auto *result = IGF.emitLoadOfCompactFunctionPointer(
49594959
Address(addrPtr, IGF.IGM.getPointerAlignment()), /*isFar*/ false,
49604960
/*expectedType*/ getFunctionType()->getPointerTo());
49614961
if (auto codeAuthInfo = AuthInfo.getCorrespondingCodeAuthInfo()) {

lib/IRGen/GenDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2063,7 +2063,7 @@ void IRGenerator::emitEntryPointInfo() {
20632063
auto &IGM = *getGenModule(entrypoint);
20642064
ConstantInitBuilder builder(IGM);
20652065
auto entrypointInfo = builder.beginStruct();
2066-
entrypointInfo.addRelativeAddress(
2066+
entrypointInfo.addCompactFunctionReference(
20672067
IGM.getAddrOfSILFunction(entrypoint, NotForDefinition));
20682068
auto var = entrypointInfo.finishAndCreateGlobal(
20692069
"\x01l_entry_point", Alignment(4),

lib/IRGen/GenKeyPath.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ getAccessorForComputedComponent(IRGenModule &IGM,
268268
return accessorThunk;
269269
}
270270

271-
static llvm::Constant *
271+
static llvm::Function *
272272
getLayoutFunctionForComputedComponent(IRGenModule &IGM,
273273
const KeyPathPatternComponent &component,
274274
GenericEnvironment *genericEnv,
@@ -548,7 +548,7 @@ struct KeyPathIndexOperand {
548548
const KeyPathPatternComponent *LastUser;
549549
};
550550

551-
static llvm::Constant *
551+
static llvm::Function *
552552
getInitializerForComputedComponent(IRGenModule &IGM,
553553
const KeyPathPatternComponent &component,
554554
ArrayRef<KeyPathIndexOperand> operands,
@@ -1101,12 +1101,12 @@ emitKeyPathComponent(IRGenModule &IGM,
11011101
}
11021102

11031103
// Push the accessors, possibly thunked to marshal generic environment.
1104-
fields.addRelativeAddress(
1104+
fields.addCompactFunctionReference(
11051105
getAccessorForComputedComponent(IGM, component, Getter,
11061106
genericEnv, requirements,
11071107
hasSubscriptIndices));
11081108
if (settable)
1109-
fields.addRelativeAddress(
1109+
fields.addCompactFunctionReference(
11101110
getAccessorForComputedComponent(IGM, component, Setter,
11111111
genericEnv, requirements,
11121112
hasSubscriptIndices));
@@ -1116,7 +1116,7 @@ emitKeyPathComponent(IRGenModule &IGM,
11161116
// arguments in the component. Thunk the SIL-level accessors to give the
11171117
// runtime implementation a polymorphically-callable interface.
11181118

1119-
fields.addRelativeAddress(
1119+
fields.addCompactFunctionReference(
11201120
getLayoutFunctionForComputedComponent(IGM, component,
11211121
genericEnv, requirements));
11221122

@@ -1136,7 +1136,7 @@ emitKeyPathComponent(IRGenModule &IGM,
11361136

11371137
// Add an initializer function that copies generic arguments out of the
11381138
// pattern argument buffer into the instantiated object.
1139-
fields.addRelativeAddress(
1139+
fields.addCompactFunctionReference(
11401140
getInitializerForComputedComponent(IGM, component, operands,
11411141
genericEnv, requirements));
11421142
}

lib/IRGen/GenMeta.cpp

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -302,13 +302,13 @@ static void buildMethodDescriptorFields(IRGenModule &IGM,
302302
assert(entry->getKind() == SILVTable::Entry::Kind::Normal);
303303

304304
auto *impl = entry->getImplementation();
305-
llvm::Constant *implFn;
306-
if (impl->isAsync())
307-
implFn = IGM.getAddrOfAsyncFunctionPointer(impl);
308-
else
309-
implFn = IGM.getAddrOfSILFunction(impl, NotForDefinition);
310-
311-
descriptor.addRelativeAddress(implFn);
305+
if (impl->isAsync()) {
306+
llvm::Constant *implFn = IGM.getAddrOfAsyncFunctionPointer(impl);
307+
descriptor.addRelativeAddress(implFn);
308+
} else {
309+
llvm::Function *implFn = IGM.getAddrOfSILFunction(impl, NotForDefinition);
310+
descriptor.addCompactFunctionReference(implFn);
311+
}
312312
} else {
313313
// The method is removed by dead method elimination.
314314
// It should be never called. We add a pointer to an error function.
@@ -962,7 +962,15 @@ namespace {
962962
reqt.addInt32(info.Flags.getIntValue());
963963

964964
// Default implementation.
965-
reqt.addRelativeAddressOrNull(info.DefaultImpl);
965+
if (info.DefaultImpl) {
966+
if (auto *fn = llvm::dyn_cast<llvm::Function>(info.DefaultImpl)) {
967+
reqt.addCompactFunctionReference(fn);
968+
} else {
969+
reqt.addRelativeAddress(info.DefaultImpl);
970+
}
971+
} else {
972+
reqt.addRelativeAddressOrNull(nullptr);
973+
}
966974

967975
reqt.finishAndAddTo(B);
968976
}
@@ -1226,7 +1234,7 @@ namespace {
12261234
}
12271235

12281236
void addAccessFunction() {
1229-
llvm::Constant *accessor;
1237+
llvm::Function *accessor;
12301238

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

1250-
B.addRelativeAddressOrNull(accessor);
1258+
B.addCompactFunctionReferenceOrNull(accessor);
12511259
}
12521260

12531261
ConstantReference getParent() {
@@ -1376,12 +1384,12 @@ namespace {
13761384

13771385
/// Add a ForeignMetadataInitialization structure to the descriptor.
13781386
void addForeignMetadataInitialization() {
1379-
llvm::Constant *completionFunction = nullptr;
1387+
llvm::Function *completionFunction = nullptr;
13801388
if (asImpl().needsForeignMetadataCompletionFunction()) {
13811389
completionFunction =
13821390
IGM.getAddrOfTypeMetadataCompletionFunction(Type, NotForDefinition);
13831391
}
1384-
B.addRelativeAddressOrNull(completionFunction);
1392+
B.addCompactFunctionReferenceOrNull(completionFunction);
13851393
}
13861394

13871395
bool needsForeignMetadataCompletionFunction() {
@@ -1402,7 +1410,7 @@ namespace {
14021410
// Completion function.
14031411
auto completionFunction =
14041412
IGM.getAddrOfTypeMetadataCompletionFunction(Type, NotForDefinition);
1405-
B.addRelativeAddress(completionFunction);
1413+
B.addCompactFunctionReference(completionFunction);
14061414
}
14071415

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

19071915
auto *impl = entry->getImplementation();
1908-
llvm::Constant *implFn;
1909-
if (impl->isAsync())
1910-
implFn = IGM.getAddrOfAsyncFunctionPointer(impl);
1911-
else
1912-
implFn = IGM.getAddrOfSILFunction(impl, NotForDefinition);
1913-
1914-
descriptor.addRelativeAddress(implFn);
1916+
if (impl->isAsync()) {
1917+
llvm::Constant *implFn = IGM.getAddrOfAsyncFunctionPointer(impl);
1918+
descriptor.addRelativeAddress(implFn);
1919+
} else {
1920+
llvm::Function *implFn = IGM.getAddrOfSILFunction(impl, NotForDefinition);
1921+
descriptor.addCompactFunctionReference(implFn);
1922+
}
19151923
} else {
19161924
// The method is removed by dead method elimination.
19171925
// It should be never called. We add a pointer to an error function.
@@ -2005,7 +2013,7 @@ namespace {
20052013
}
20062014
auto specialization = pair.first;
20072015
auto *function = IGM.getAddrOfCanonicalSpecializedGenericTypeMetadataAccessFunction(specialization, NotForDefinition);
2008-
B.addRelativeAddress(function);
2016+
B.addCompactFunctionReference(function);
20092017
}
20102018
}
20112019
};
@@ -2723,7 +2731,7 @@ namespace {
27232731
void addInstantiationFunction() {
27242732
auto function = IGM.getAddrOfTypeMetadataInstantiationFunction(Target,
27252733
NotForDefinition);
2726-
B.addRelativeAddress(function);
2734+
B.addCompactFunctionReference(function);
27272735
}
27282736

27292737
void addCompletionFunction() {
@@ -2734,7 +2742,7 @@ namespace {
27342742

27352743
auto function = IGM.getAddrOfTypeMetadataCompletionFunction(Target,
27362744
NotForDefinition);
2737-
B.addRelativeAddress(function);
2745+
B.addCompactFunctionReference(function);
27382746
}
27392747

27402748
void addPatternFlags() {
@@ -2935,7 +2943,7 @@ static void emitClassMetadataBaseOffset(IRGenModule &IGM,
29352943
offsetVar->setConstant(true);
29362944
}
29372945

2938-
static Optional<llvm::Constant *>
2946+
static Optional<llvm::Function *>
29392947
getAddrOfDestructorFunction(IRGenModule &IGM, ClassDecl *classDecl) {
29402948
auto dtorRef = SILDeclRef(classDecl->getDestructor(),
29412949
SILDeclRef::Kind::Deallocator);
@@ -3539,15 +3547,15 @@ namespace {
35393547

35403548
void addDestructorFunction() {
35413549
auto function = getAddrOfDestructorFunction(IGM, Target);
3542-
B.addRelativeAddressOrNull(function ? *function : nullptr);
3550+
B.addCompactFunctionReferenceOrNull(function ? *function : nullptr);
35433551
}
35443552

35453553
void addIVarDestroyer() {
35463554
auto function = IGM.getAddrOfIVarInitDestroy(Target,
35473555
/*isDestroyer=*/ true,
35483556
/*isForeign=*/ false,
35493557
NotForDefinition);
3550-
B.addRelativeAddressOrNull(function ? *function : nullptr);
3558+
B.addCompactFunctionReferenceOrNull(function ? *function : nullptr);
35513559
}
35523560

35533561
void addClassFlags() {
@@ -3663,15 +3671,15 @@ namespace {
36633671

36643672
void addDestructorFunction() {
36653673
auto function = getAddrOfDestructorFunction(IGM, Target);
3666-
B.addRelativeAddressOrNull(function ? *function : nullptr);
3674+
B.addCompactFunctionReferenceOrNull(function ? *function : nullptr);
36673675
}
36683676

36693677
void addIVarDestroyer() {
36703678
auto function = IGM.getAddrOfIVarInitDestroy(Target,
36713679
/*isDestroyer=*/ true,
36723680
/*isForeign=*/ false,
36733681
NotForDefinition);
3674-
B.addRelativeAddressOrNull(function ? *function : nullptr);
3682+
B.addCompactFunctionReferenceOrNull(function ? *function : nullptr);
36753683
}
36763684

36773685
bool hasExtraDataPattern() {
@@ -5614,7 +5622,7 @@ llvm::GlobalValue *irgen::emitAsyncFunctionPointer(IRGenModule &IGM,
56145622
ConstantInitBuilder initBuilder(IGM);
56155623
ConstantStructBuilder builder(
56165624
initBuilder.beginStruct(IGM.AsyncFunctionPointerTy));
5617-
builder.addRelativeAddress(function);
5625+
builder.addCompactFunctionReference(function);
56185626
builder.addInt32(size.getValue());
56195627
return cast<llvm::GlobalValue>(IGM.defineAsyncFunctionPointer(
56205628
entity, builder.finishAndCreateFuture()));

lib/IRGen/GenProto.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,7 +1472,7 @@ class AccessorConformanceInfo : public ConformanceInfo {
14721472

14731473
/// Build the instantiation function that runs at the end of witness
14741474
/// table specialization.
1475-
llvm::Constant *buildInstantiationFunction();
1475+
llvm::Function *buildInstantiationFunction();
14761476
};
14771477

14781478
/// A resilient witness table consists of a list of descriptor/witness pairs,
@@ -1741,7 +1741,7 @@ void ResilientWitnessTableBuilder::collectResilientWitnesses(
17411741
}
17421742
}
17431743

1744-
llvm::Constant *FragileWitnessTableBuilder::buildInstantiationFunction() {
1744+
llvm::Function *FragileWitnessTableBuilder::buildInstantiationFunction() {
17451745
// We need an instantiation function if any base conformance
17461746
// is non-dependent.
17471747
if (SpecializedBaseConformances.empty())
@@ -1962,7 +1962,12 @@ namespace {
19621962
}
19631963

19641964
// Add the witness.
1965-
B.addRelativeAddress(witnesses.front());
1965+
llvm::Constant *witness = witnesses.front();
1966+
if (auto *fn = llvm::dyn_cast<llvm::Function>(witness)) {
1967+
B.addCompactFunctionReference(fn);
1968+
} else {
1969+
B.addRelativeAddress(witness);
1970+
}
19661971
witnesses = witnesses.drop_front();
19671972
}
19681973
assert(witnesses.empty() && "Wrong # of resilient witnesses");
@@ -1979,7 +1984,7 @@ namespace {
19791984
(Description.witnessTablePrivateSize << 1) |
19801985
Description.requiresSpecialization);
19811986
// Instantiation function
1982-
B.addRelativeAddressOrNull(Description.instantiationFn);
1987+
B.addCompactFunctionReferenceOrNull(Description.instantiationFn);
19831988

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

22562261
unsigned tableSize = 0;
22572262
llvm::GlobalVariable *global = nullptr;
2258-
llvm::Constant *instantiationFunction = nullptr;
2263+
llvm::Function *instantiationFunction = nullptr;
22592264
bool isDependent = isDependentConformance(conf);
22602265
SmallVector<llvm::Constant *, 4> resilientWitnesses;
22612266

0 commit comments

Comments
 (0)