From a7619edaf15490cad8ddfda5fde0fb2aba825d85 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 23 Mar 2022 15:28:20 +0000 Subject: [PATCH] IRGen: Use indirect relative func-ptr for harvard archs Harvard architectures like WebAssembly cannot make direct relative function pointer because the referent function and the metadata are in different address spaces, and the relative offset between them is not representable. So we need to force such relative function pointers to always be indirect for those archs. --- include/swift/AST/IRGenOptions.h | 4 + lib/Frontend/CompilerInvocation.cpp | 6 ++ lib/IRGen/ConformanceDescription.h | 2 +- lib/IRGen/ConstantBuilder.h | 25 ++++++ lib/IRGen/GenCall.cpp | 4 +- lib/IRGen/GenDecl.cpp | 2 +- lib/IRGen/GenKeyPath.cpp | 35 +++++--- lib/IRGen/GenMeta.cpp | 89 +++++++++++++------ lib/IRGen/GenProto.cpp | 15 ++-- lib/IRGen/GenReflection.cpp | 6 +- lib/IRGen/IRGenFunction.cpp | 13 +++ lib/IRGen/IRGenFunction.h | 4 + lib/IRGen/IRGenModule.h | 3 + .../harvard-arch-relative-func-ptr.swift | 13 +++ 14 files changed, 167 insertions(+), 54 deletions(-) create mode 100644 test/IRGen/harvard-arch-relative-func-ptr.swift diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index 0a433d5ab5ff8..f9a544ff642ac 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -320,6 +320,10 @@ class IRGenOptions { unsigned LazyInitializeProtocolConformances : 1; unsigned IndirectAsyncFunctionPointer : 1; + /// Force relative function pointer to be indirect + /// Used on harvard architectures like WebAssembly + unsigned IndirectRelativeFunctionPointer : 1; + /// Normally if the -read-legacy-type-info flag is not specified, we look for /// a file named "legacy-.yaml" in SearchPathOpts.RuntimeLibraryPath. /// Passing this flag completely disables this behavior. diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 0dc7a34f64d00..19178f191f4fb 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -2161,6 +2161,12 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args, // AsyncFunctionPointer access. Opts.IndirectAsyncFunctionPointer = Triple.isOSBinFormatCOFF(); + // Harvard architectures cannot make direct relative function pointer + // because the referent function and the metadata are in different + // address spaces, and the relative offset between them is not representable. + // So we always use indirect relative function pointer for those. + Opts.IndirectRelativeFunctionPointer = Triple.isOSBinFormatWasm(); + if (Args.hasArg(OPT_disable_legacy_type_info)) { Opts.DisableLegacyTypeInfo = true; } diff --git a/lib/IRGen/ConformanceDescription.h b/lib/IRGen/ConformanceDescription.h index 028429d455303..4a0406b09a131 100644 --- a/lib/IRGen/ConformanceDescription.h +++ b/lib/IRGen/ConformanceDescription.h @@ -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 resilientWitnesses; diff --git a/lib/IRGen/ConstantBuilder.h b/lib/IRGen/ConstantBuilder.h index ffca625d8236d..b20861595f5a4 100644 --- a/lib/IRGen/ConstantBuilder.h +++ b/lib/IRGen/ConstantBuilder.h @@ -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" @@ -81,6 +82,27 @@ class ConstantAggregateBuilderBase void addSize(Size size) { addInt(IGM().SizeTy, size.getValue()); } + void addRelativeFunctionAddressOrNull(llvm::Function *function) { + if (function) { + addRelativeFunctionAddress(function); + } else { + addInt(IGM().RelativeAddressTy, 0); + } + } + + /// Add a relative function reference to the given function. The relative + /// address is direct when the address spaces of the code and the building + /// constant are the same. Otherwise, on harvard architectures, the relative + /// offset between the field and the referent function cannot be computed, + /// so the relative address is indirect. + void addRelativeFunctionAddress(llvm::Function *function) { + if (IGM().getOptions().IndirectRelativeFunctionPointer) { + addRelativeAddress(IGM().getAddrOfIndirectFunctionPointer(function)); + } else { + addRelativeOffset(IGM().RelativeAddressTy, function); + } + } + void addRelativeAddressOrNull(llvm::Constant *target) { if (target) { addRelativeAddress(target); @@ -91,6 +113,9 @@ class ConstantAggregateBuilderBase void addRelativeAddress(llvm::Constant *target) { assert(!isa(target)); + assert((!IGM().getOptions().IndirectRelativeFunctionPointer || + !isa(target)) && + "use addRelativeFunctionAddress"); addRelativeOffset(IGM().RelativeAddressTy, target); } diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index f25f5fe2b6299..fa711b1f665f4 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -2086,7 +2086,7 @@ std::pair irgen::getAsyncFunctionAndSize( llvm::Value *addrPtr = IGF.Builder.CreateStructGEP( getAFPPtr()->getType()->getScalarType()->getPointerElementType(), getAFPPtr(), 0); - fn = IGF.emitLoadOfRelativePointer( + fn = IGF.emitLoadOfRelativeFunctionPointer( Address(addrPtr, IGF.IGM.getPointerAlignment()), /*isFar*/ false, /*expectedType*/ functionPointer.getFunctionType()->getPointerTo()); } @@ -4952,7 +4952,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.emitLoadOfRelativeFunctionPointer( Address(addrPtr, IGF.IGM.getPointerAlignment()), /*isFar*/ false, /*expectedType*/ getFunctionType()->getPointerTo()); if (auto codeAuthInfo = AuthInfo.getCorrespondingCodeAuthInfo()) { diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 09db8318c6827..2ab4f9667f7bf 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -2063,7 +2063,7 @@ void IRGenerator::emitEntryPointInfo() { auto &IGM = *getGenModule(entrypoint); ConstantInitBuilder builder(IGM); auto entrypointInfo = builder.beginStruct(); - entrypointInfo.addRelativeAddress( + entrypointInfo.addRelativeFunctionAddress( IGM.getAddrOfSILFunction(entrypoint, NotForDefinition)); auto var = entrypointInfo.finishAndCreateGlobal( "\x01l_entry_point", Alignment(4), diff --git a/lib/IRGen/GenKeyPath.cpp b/lib/IRGen/GenKeyPath.cpp index 03a66fdf7bcb9..d61d7c9f8b89d 100644 --- a/lib/IRGen/GenKeyPath.cpp +++ b/lib/IRGen/GenKeyPath.cpp @@ -268,7 +268,7 @@ getAccessorForComputedComponent(IRGenModule &IGM, return accessorThunk; } -static llvm::Constant * +static llvm::Function * getLayoutFunctionForComputedComponent(IRGenModule &IGM, const KeyPathPatternComponent &component, GenericEnvironment *genericEnv, @@ -548,7 +548,7 @@ struct KeyPathIndexOperand { const KeyPathPatternComponent *LastUser; }; -static llvm::Constant * +static llvm::Function * getInitializerForComputedComponent(IRGenModule &IGM, const KeyPathPatternComponent &component, ArrayRef operands, @@ -948,13 +948,22 @@ emitKeyPathComponent(IRGenModule &IGM, // FIXME: Does this need to be signed? auto idRef = IGM.getAddrOfLLVMVariableOrGOTEquivalent( LinkEntity::forSILFunction(id.getFunction())); - - idValue = idRef.getValue(); - // If we got an indirect reference, we'll need to resolve it at - // instantiation time. - idResolution = idRef.isIndirect() - ? KeyPathComponentHeader::IndirectPointer - : KeyPathComponentHeader::Resolved; + + if (IGM.getOptions().IndirectRelativeFunctionPointer && + !idRef.isIndirect()) { + // Force the function pointer to be indirect for harvard architecture + // even though it can be referenceable directly. + idValue = IGM.getAddrOfIndirectFunctionPointer( + IGM.getAddrOfSILFunction(id.getFunction(), NotForDefinition)); + idResolution = KeyPathComponentHeader::IndirectPointer; + } else { + idValue = idRef.getValue(); + // If we got an indirect reference, we'll need to resolve it at + // instantiation time. + idResolution = idRef.isIndirect() + ? KeyPathComponentHeader::IndirectPointer + : KeyPathComponentHeader::Resolved; + } break; } case KeyPathPatternComponent::ComputedPropertyId::DeclRef: { @@ -1101,12 +1110,12 @@ emitKeyPathComponent(IRGenModule &IGM, } // Push the accessors, possibly thunked to marshal generic environment. - fields.addRelativeAddress( + fields.addRelativeFunctionAddress( getAccessorForComputedComponent(IGM, component, Getter, genericEnv, requirements, hasSubscriptIndices)); if (settable) - fields.addRelativeAddress( + fields.addRelativeFunctionAddress( getAccessorForComputedComponent(IGM, component, Setter, genericEnv, requirements, hasSubscriptIndices)); @@ -1116,7 +1125,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.addRelativeFunctionAddress( getLayoutFunctionForComputedComponent(IGM, component, genericEnv, requirements)); @@ -1136,7 +1145,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.addRelativeFunctionAddress( getInitializerForComputedComponent(IGM, component, operands, genericEnv, requirements)); } diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index bd0769132214d..223c3e15f373e 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -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.addRelativeFunctionAddress(implFn); + } } else { // The method is removed by dead method elimination. // It should be never called. We add a pointer to an error function. @@ -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(info.DefaultImpl)) { + reqt.addRelativeFunctionAddress(fn); + } else { + reqt.addRelativeAddress(info.DefaultImpl); + } + } else { + reqt.addRelativeAddressOrNull(nullptr); + } reqt.finishAndAddTo(B); } @@ -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. @@ -1247,7 +1255,7 @@ namespace { accessor = getOtherwiseDefinedTypeMetadataAccessFunction(IGM, type); } - B.addRelativeAddressOrNull(accessor); + B.addRelativeFunctionAddressOrNull(accessor); } ConstantReference getParent() { @@ -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.addRelativeFunctionAddressOrNull(completionFunction); } bool needsForeignMetadataCompletionFunction() { @@ -1402,7 +1410,7 @@ namespace { // Completion function. auto completionFunction = IGM.getAddrOfTypeMetadataCompletionFunction(Type, NotForDefinition); - B.addRelativeAddress(completionFunction); + B.addRelativeFunctionAddress(completionFunction); } void addIncompleteMetadata() { @@ -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.addRelativeFunctionAddress(implFn); + } } else { // The method is removed by dead method elimination. // It should be never called. We add a pointer to an error function. @@ -2005,7 +2013,7 @@ namespace { } auto specialization = pair.first; auto *function = IGM.getAddrOfCanonicalSpecializedGenericTypeMetadataAccessFunction(specialization, NotForDefinition); - B.addRelativeAddress(function); + B.addRelativeFunctionAddress(function); } } }; @@ -2723,7 +2731,7 @@ namespace { void addInstantiationFunction() { auto function = IGM.getAddrOfTypeMetadataInstantiationFunction(Target, NotForDefinition); - B.addRelativeAddress(function); + B.addRelativeFunctionAddress(function); } void addCompletionFunction() { @@ -2734,7 +2742,7 @@ namespace { auto function = IGM.getAddrOfTypeMetadataCompletionFunction(Target, NotForDefinition); - B.addRelativeAddress(function); + B.addRelativeFunctionAddress(function); } void addPatternFlags() { @@ -2935,7 +2943,7 @@ static void emitClassMetadataBaseOffset(IRGenModule &IGM, offsetVar->setConstant(true); } -static Optional +static Optional getAddrOfDestructorFunction(IRGenModule &IGM, ClassDecl *classDecl) { auto dtorRef = SILDeclRef(classDecl->getDestructor(), SILDeclRef::Kind::Deallocator); @@ -3539,7 +3547,7 @@ namespace { void addDestructorFunction() { auto function = getAddrOfDestructorFunction(IGM, Target); - B.addRelativeAddressOrNull(function ? *function : nullptr); + B.addRelativeFunctionAddressOrNull(function ? *function : nullptr); } void addIVarDestroyer() { @@ -3547,7 +3555,7 @@ namespace { /*isDestroyer=*/ true, /*isForeign=*/ false, NotForDefinition); - B.addRelativeAddressOrNull(function ? *function : nullptr); + B.addRelativeFunctionAddressOrNull(function ? *function : nullptr); } void addClassFlags() { @@ -3663,7 +3671,7 @@ namespace { void addDestructorFunction() { auto function = getAddrOfDestructorFunction(IGM, Target); - B.addRelativeAddressOrNull(function ? *function : nullptr); + B.addRelativeFunctionAddressOrNull(function ? *function : nullptr); } void addIVarDestroyer() { @@ -3671,7 +3679,7 @@ namespace { /*isDestroyer=*/ true, /*isForeign=*/ false, NotForDefinition); - B.addRelativeAddressOrNull(function ? *function : nullptr); + B.addRelativeFunctionAddressOrNull(function ? *function : nullptr); } bool hasExtraDataPattern() { @@ -5614,8 +5622,31 @@ llvm::GlobalValue *irgen::emitAsyncFunctionPointer(IRGenModule &IGM, ConstantInitBuilder initBuilder(IGM); ConstantStructBuilder builder( initBuilder.beginStruct(IGM.AsyncFunctionPointerTy)); - builder.addRelativeAddress(function); + builder.addRelativeFunctionAddress(function); builder.addInt32(size.getValue()); return cast(IGM.defineAsyncFunctionPointer( entity, builder.finishAndCreateFuture())); } + +/// Get or create an indirect function pointer that references the given +/// function. +/// +/// Similar to \ref IRGenModule::getAddrOfLLVMVariableOrGOTEquivalent, but this +/// one always creates a new trampoline constant pointing to the function even +/// though it can be referenced directly. The indirect function pointer is used +/// to create a relative indirect function pointer for harvard architecture +/// targets. +llvm::Constant * +IRGenModule::getAddrOfIndirectFunctionPointer(llvm::Function *fn) { + auto &entry = IndirectRelativeFunctionPointers[fn]; + if (entry) { + return IndirectRelativeFunctionPointers[fn]; + } + auto *pointer = new llvm::GlobalVariable( + Module, fn->getType(), + /*isConstant=*/true, llvm::GlobalValue::PrivateLinkage, fn, + Twine("indirect.") + fn->getName()); + pointer->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); + entry = pointer; + return pointer; +} diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index 7a47eb1df41e0..7d562aba77244 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -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, @@ -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()) @@ -1962,7 +1962,12 @@ namespace { } // Add the witness. - B.addRelativeAddress(witnesses.front()); + llvm::Constant *witness = witnesses.front(); + if (auto *fn = llvm::dyn_cast(witness)) { + B.addRelativeFunctionAddress(fn); + } else { + B.addRelativeAddress(witness); + } witnesses = witnesses.drop_front(); } assert(witnesses.empty() && "Wrong # of resilient witnesses"); @@ -1979,7 +1984,7 @@ namespace { (Description.witnessTablePrivateSize << 1) | Description.requiresSpecialization); // Instantiation function - B.addRelativeAddressOrNull(Description.instantiationFn); + B.addRelativeFunctionAddressOrNull(Description.instantiationFn); // Private data if (IGM.IRGen.Opts.NoPreallocatedInstantiationCaches) { @@ -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 resilientWitnesses; diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp index 7343f75f28bac..b944b8e43d77b 100644 --- a/lib/IRGen/GenReflection.cpp +++ b/lib/IRGen/GenReflection.cpp @@ -281,7 +281,7 @@ getTypeRefByFunction(IRGenModule &IGM, S.setPacked(true); S.add(llvm::ConstantInt::get(IGM.Int8Ty, 255)); S.add(llvm::ConstantInt::get(IGM.Int8Ty, 9)); - S.addRelativeAddress(accessor); + S.addRelativeFunctionAddress(accessor); // And a null terminator! S.addInt(IGM.Int8Ty, 0); @@ -438,7 +438,7 @@ IRGenModule::emitWitnessTableRefString(CanType type, S.setPacked(true); S.add(llvm::ConstantInt::get(Int8Ty, 255)); S.add(llvm::ConstantInt::get(Int8Ty, 9)); - S.addRelativeAddress(accessorThunk); + S.addRelativeFunctionAddress(accessorThunk); // And a null terminator! S.addInt(Int8Ty, 0); @@ -482,7 +482,7 @@ llvm::Constant *IRGenModule::getMangledAssociatedConformance( S.setPacked(true); S.add(llvm::ConstantInt::get(Int8Ty, 255)); S.add(llvm::ConstantInt::get(Int8Ty, kind)); - S.addRelativeAddress(accessor); + S.addRelativeFunctionAddress(accessor); // And a null terminator! S.addInt(Int8Ty, 0); diff --git a/lib/IRGen/IRGenFunction.cpp b/lib/IRGen/IRGenFunction.cpp index 0e5ce215103c0..2e133e645833f 100644 --- a/lib/IRGen/IRGenFunction.cpp +++ b/lib/IRGen/IRGenFunction.cpp @@ -337,6 +337,19 @@ IRGenFunction::emitLoadOfRelativePointer(Address addr, bool isFar, return pointer.getAddress(); } +llvm::Value *IRGenFunction::emitLoadOfRelativeFunctionPointer( + Address addr, bool isFar, llvm::PointerType *expectedType, + const llvm::Twine &name) { + if (IGM.getOptions().IndirectRelativeFunctionPointer) { + llvm::Value *value = emitLoadOfRelativePointer( + Address(addr.getAddress(), IGM.getPointerAlignment()), isFar, + expectedType->getPointerTo(), name); + return Builder.CreateLoad(value, addr.getAlignment()); + } else { + return emitLoadOfRelativePointer(addr, isFar, expectedType, name); + } +} + llvm::Value * IRGenFunction::emitLoadOfRelativeIndirectablePointer(Address addr, bool isFar, diff --git a/lib/IRGen/IRGenFunction.h b/lib/IRGen/IRGenFunction.h index 0cda72ba7c7ed..fa401047d541f 100644 --- a/lib/IRGen/IRGenFunction.h +++ b/lib/IRGen/IRGenFunction.h @@ -266,6 +266,10 @@ class IRGenFunction { llvm::Value *emitLoadOfRelativePointer(Address addr, bool isFar, llvm::PointerType *expectedType, const llvm::Twine &name = ""); + llvm::Value * + emitLoadOfRelativeFunctionPointer(Address addr, bool isFar, + llvm::PointerType *expectedType, + const llvm::Twine &name = ""); llvm::Value *emitAllocObjectCall(llvm::Value *metadata, llvm::Value *size, llvm::Value *alignMask, diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index f0047cc1c050f..36645b2173439 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -1118,6 +1118,7 @@ class IRGenModule { llvm::DenseMap IndirectAsyncFunctionPointers; llvm::DenseMap GlobalGOTEquivalents; llvm::DenseMap GlobalFuncs; + llvm::DenseMap IndirectRelativeFunctionPointers; llvm::DenseSet GlobalClangDecls; llvm::StringMap> GlobalStrings; @@ -1294,6 +1295,8 @@ class IRGenModule { llvm::Constant *getAssociatedTypeWitness(Type type, GenericSignature sig, bool inProtocolContext); + llvm::Constant *getAddrOfIndirectFunctionPointer(llvm::Function *fn); + void emitAssociatedTypeMetadataRecord(const RootProtocolConformance *C); void emitFieldDescriptor(const NominalTypeDecl *Decl); diff --git a/test/IRGen/harvard-arch-relative-func-ptr.swift b/test/IRGen/harvard-arch-relative-func-ptr.swift new file mode 100644 index 0000000000000..11ef2db462a55 --- /dev/null +++ b/test/IRGen/harvard-arch-relative-func-ptr.swift @@ -0,0 +1,13 @@ +// RUN: %swift -target wasm32-unknown-wasi -parse-stdlib -emit-ir -o - %s | %FileCheck %s + +// REQUIRES: CODEGENERATOR=WebAssembly + +// Ensure that relative function pointer in entry_point is indirect on harvard archs +// +// CHECK: @indirect.main = private unnamed_addr constant i32 (i32, i8*)* @main +// CHECK: @"\01l_entry_point" = private constant { i32 } { +// CHECK-SAME: i32 sub ( +// CHECK-SAME: i32 ptrtoint (i32 (i32, i8*)** @indirect.main to i32), +// CHECK-SAME: i32 ptrtoint ({ i32 }* @"\01l_entry_point" to i32) +// CHECK-SAME: ) +// CHECK-SAME: }, section "swift5_entry", align 4