Skip to content

IRGen: Outlined value functions of types that might expand differently in different TUs must use private linkage #77564

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
15 changes: 11 additions & 4 deletions lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6192,13 +6192,18 @@ IRGenModule::getAddrOfContinuationPrototype(CanSILFunctionType fnType) {
/// Should we be defining the given helper function?
static llvm::Function *shouldDefineHelper(IRGenModule &IGM,
llvm::Constant *fn,
bool setIsNoInline) {
bool setIsNoInline,
IRLinkage *linkage) {
auto *def = dyn_cast<llvm::Function>(fn);
if (!def) return nullptr;
if (!def->empty()) return nullptr;

def->setAttributes(IGM.constructInitialAttributes());
ApplyIRLinkage(IRLinkage::InternalLinkOnceODR).to(def);
if (!linkage)
ApplyIRLinkage(IRLinkage::InternalLinkOnceODR).to(def);
else
ApplyIRLinkage(*linkage).to(def);

def->setDoesNotThrow();
def->setCallingConv(IGM.DefaultCC);
if (setIsNoInline)
Expand All @@ -6220,15 +6225,17 @@ IRGenModule::getOrCreateHelperFunction(StringRef fnName, llvm::Type *resultTy,
llvm::function_ref<void(IRGenFunction &IGF)> generate,
bool setIsNoInline,
bool forPrologue,
bool isPerformanceConstraint) {
bool isPerformanceConstraint,
IRLinkage *optionalLinkageOverride) {
llvm::FunctionType *fnTy =
llvm::FunctionType::get(resultTy, paramTys, false);

llvm::Constant *fn =
cast<llvm::Constant>(
Module.getOrInsertFunction(fnName, fnTy).getCallee());

if (llvm::Function *def = shouldDefineHelper(*this, fn, setIsNoInline)) {
if (llvm::Function *def = shouldDefineHelper(*this, fn, setIsNoInline,
optionalLinkageOverride)) {
IRGenFunction IGF(*this, def, isPerformanceConstraint);
if (DebugInfo && !forPrologue)
DebugInfo->emitArtificialFunction(IGF, def);
Expand Down
4 changes: 3 additions & 1 deletion lib/IRGen/IRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ namespace irgen {
class StructLayout;
class IRGenDebugInfo;
class IRGenFunction;
struct IRLinkage;
class LinkEntity;
class LoadableTypeInfo;
class MetadataLayout;
Expand Down Expand Up @@ -1221,7 +1222,8 @@ class IRGenModule {
llvm::function_ref<void(IRGenFunction &IGF)> generate,
bool setIsNoInline = false,
bool forPrologue = false,
bool isPerformanceConstraint = false);
bool isPerformanceConstraint = false,
IRLinkage *optionalLinkage = nullptr);

llvm::Constant *getOrCreateRetainFunction(const TypeInfo &objectTI, SILType t,
llvm::Type *llvmType, Atomicity atomicity);
Expand Down
39 changes: 37 additions & 2 deletions lib/IRGen/Outlining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "swift/AST/IRGenOptions.h"
#include "swift/Basic/Assertions.h"
#include "swift/IRGen/GenericRequirement.h"
#include "swift/IRGen/Linking.h"
#include "swift/SIL/SILModule.h"

using namespace swift;
Expand Down Expand Up @@ -489,6 +490,22 @@ llvm::Constant *IRGenModule::getOrCreateOutlinedCopyAddrHelperFunction(
paramTys.push_back(ptrTy);
collector.addPolymorphicParameterTypes(paramTys);

IRLinkage *linkage = nullptr;
IRLinkage privateLinkage = {
llvm::GlobalValue::PrivateLinkage,
llvm::GlobalValue::DefaultVisibility,
llvm::GlobalValue::DefaultStorageClass,
};
auto &TL =
getSILModule().Types.getTypeLowering(T, TypeExpansionContext::minimal());
// Opaque result types might lead to different expansions in different files.
// The default hidden linkonce_odr might lead to linking an implementation
// from another file that head a different expansion/different
// signature/different implementation.
if (TL.getRecursiveProperties().isTypeExpansionSensitive()) {
linkage = &privateLinkage;
}

return getOrCreateHelperFunction(funcName, ptrTy, paramTys,
[&](IRGenFunction &IGF) {
auto params = IGF.collectParameters();
Expand All @@ -500,7 +517,8 @@ llvm::Constant *IRGenModule::getOrCreateOutlinedCopyAddrHelperFunction(
},
true /*setIsNoInline*/,
false /*forPrologue*/,
collector.IGF.isPerformanceConstraint);
collector.IGF.isPerformanceConstraint,
linkage);
}

void TypeInfo::callOutlinedDestroy(IRGenFunction &IGF,
Expand Down Expand Up @@ -544,6 +562,22 @@ llvm::Constant *IRGenModule::getOrCreateOutlinedDestroyFunction(
auto funcName = mangler.mangleOutlinedDestroyFunction(manglingBits.first,
manglingBits.second, collector.IGF.isPerformanceConstraint);

IRLinkage *linkage = nullptr;
IRLinkage privateLinkage = {
llvm::GlobalValue::PrivateLinkage,
llvm::GlobalValue::DefaultVisibility,
llvm::GlobalValue::DefaultStorageClass,
};
auto &TL =
getSILModule().Types.getTypeLowering(T, TypeExpansionContext::minimal());
// Opaque result types might lead to different expansions in different files.
// The default hidden linkonce_odr might lead to linking an implementation
// from another file that head a different expansion/different
// signature/different implementation.
if (TL.getRecursiveProperties().isTypeExpansionSensitive()) {
linkage = &privateLinkage;
}

auto ptrTy = ti.getStorageType()->getPointerTo();
llvm::SmallVector<llvm::Type *, 4> paramTys;
paramTys.push_back(ptrTy);
Expand All @@ -565,7 +599,8 @@ llvm::Constant *IRGenModule::getOrCreateOutlinedDestroyFunction(
},
true /*setIsNoInline*/,
false /*forPrologue*/,
collector.IGF.isPerformanceConstraint);
collector.IGF.isPerformanceConstraint,
linkage);
}

llvm::Constant *IRGenModule::getOrCreateRetainFunction(const TypeInfo &ti,
Expand Down
4 changes: 4 additions & 0 deletions test/IRGen/Inputs/opaque_result_type_linkage_2.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
public func f<T>(_: T) {
var g = G<T>()
print(g.lazyVar)
}
22 changes: 22 additions & 0 deletions test/IRGen/opaque_result_type_linkage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// RUN: %target-swift-frontend -Xllvm -type-lowering-disable-verification -emit-ir -primary-file %s %S/Inputs/opaque_result_type_linkage_2.swift -module-name lib | %FileCheck %s
// RUN: %target-swift-frontend -Xllvm -type-lowering-disable-verification -emit-ir %s -primary-file %S/Inputs/opaque_result_type_linkage_2.swift -module-name lib | %FileCheck %s --check-prefix=OTHER

protocol P {
associatedtype A
var a: A { get }
}

struct G<T>: P {
lazy var lazyVar: A = a

var a: some Any {
"hello"
}
}

// We lower the two outlined destroy functions differently depending on the type
// expansion context (there is an opaque result type).
// We therefore must not use hidden linkonce_odr linkage.

// CHECK: define{{.*}} private ptr @"$s3lib1GVyxGlWOh"(ptr %0)
// OTHER: define{{.*}} private ptr @"$s3lib1GVyxGlWOh"(ptr %0, ptr %"some Any", ptr %"Optional<some Any>", ptr %"G<T>")