Skip to content

Don't generate code for transparent functions. #3035

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 16, 2016
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
25 changes: 24 additions & 1 deletion lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1216,7 +1216,8 @@ bool LinkEntity::isFragile(IRGenModule &IGM) const {
static std::pair<llvm::GlobalValue::LinkageTypes,
llvm::GlobalValue::VisibilityTypes>
getIRLinkage(IRGenModule &IGM,
SILLinkage linkage, bool isFragile, ForDefinition_t isDefinition,
SILLinkage linkage, bool isFragile, bool isSILOnly,
ForDefinition_t isDefinition,
bool isWeakImported) {

#define RESULT(LINKAGE, VISIBILITY) \
Expand Down Expand Up @@ -1260,6 +1261,22 @@ llvm::GlobalValue::VISIBILITY##Visibility }

switch (linkage) {
case SILLinkage::Public:
// Don't code-gen transparent functions. Internal linkage
// will enable llvm to delete transparent functions except
// they are referenced from somewhere (i.e. the function pointer
// is taken).
if (isSILOnly &&
// In case we are generating multiple LLVM modules, we still have to
// use ExternalLinkage so that modules can cross-reference transparent
// functions.
!IGM.IRGen.hasMultipleIGMs() &&

// TODO: In non-whole-module-opt the generated swiftmodules are "linked"
// and this strips all serialized transparent functions. So we have to
// code-gen transparent functions in non-whole-module-opt.
IGM.getSILModule().isWholeModule()) {
return RESULT(Internal, Default);
}
return {llvm::GlobalValue::ExternalLinkage, PublicDefinitionVisibility};
case SILLinkage::Shared:
case SILLinkage::SharedExternal: return RESULT(LinkOnceODR, Hidden);
Expand All @@ -1273,6 +1290,10 @@ llvm::GlobalValue::VISIBILITY##Visibility }
return RESULT(Internal, Default);
case SILLinkage::PublicExternal:
if (isDefinition) {
if (isSILOnly) {
// Transparent function are not available externally.
return RESULT(LinkOnceODR, Hidden);
}
return RESULT(AvailableExternally, Default);
}

Expand Down Expand Up @@ -1303,6 +1324,7 @@ static void updateLinkageForDefinition(IRGenModule &IGM,
IGM,
entity.getLinkage(IGM, ForDefinition),
entity.isFragile(IGM),
entity.isSILOnly(),
ForDefinition,
entity.isWeakImported(IGM.getSwiftModule()));
global->setLinkage(linkage.first);
Expand All @@ -1329,6 +1351,7 @@ LinkInfo LinkInfo::get(IRGenModule &IGM, const LinkEntity &entity,
std::tie(result.Linkage, result.Visibility) =
getIRLinkage(IGM, entity.getLinkage(IGM, isDefinition),
entity.isFragile(IGM),
entity.isSILOnly(),
isDefinition,
entity.isWeakImported(IGM.getSwiftModule()));

Expand Down
12 changes: 11 additions & 1 deletion lib/IRGen/Linking.h
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,17 @@ class LinkEntity {
assert(getKind() == Kind::SILFunction);
return reinterpret_cast<SILFunction*>(Pointer);
}


/// Returns true if this function is only serialized, but not necessarily
/// code-gen'd. These are fragile transparent functions.
bool isSILOnly() const {
if (getKind() != Kind::SILFunction)
return false;

SILFunction *F = getSILFunction();
return F->isTransparent() && F->isDefinition() && F->isFragile();
}

SILGlobalVariable *getSILGlobalVariable() const {
assert(getKind() == Kind::SILGlobalVariable);
return reinterpret_cast<SILGlobalVariable*>(Pointer);
Expand Down
2 changes: 1 addition & 1 deletion lib/SILOptimizer/IPO/ExternalDefsToDecls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class ExternalDefsToDecls : public SILModuleTransform {
for (auto &F : *getModule()) {
SILLinkage linkage = F.getLinkage();
if (isAvailableExternally(linkage) && F.isDefinition() &&
!hasSharedVisibility(linkage)) {
!hasSharedVisibility(linkage) && !F.isTransparent()) {
F.convertToDeclaration();
invalidateAnalysis(&F, SILAnalysis::InvalidationKind::FunctionBody);
}
Expand Down
9 changes: 9 additions & 0 deletions lib/SILOptimizer/Mandatory/MandatoryInlining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,15 @@ class MandatoryInlining : public SILModuleTransform {
SetFactory, SetFactory.getEmptySet(), CHA);
}

// Make sure that we de-serialize all transparent functions,
// even if we didn't inline them for some reason.
// Transparent functions are not available externally, so we
// have to generate code for them.
for (auto &F : *M) {
if (F.isTransparent())
M->linkFunction(&F, Mode);
}

if (!ShouldCleanup)
return;

Expand Down
4 changes: 4 additions & 0 deletions test/IRGen/Inputs/multithread_module/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ private struct MyStruct : MyProto {
}
}

@_transparent public func transparentfunc(_ x: Int) -> Int {
return x + 3
}

public var g1 = 234

let i = testit(27)
Expand Down
3 changes: 3 additions & 0 deletions test/IRGen/multithread_module.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ func callPrivInc(_ x: Int) -> Int {
return privateInc(x)
}

// Check if we use the correct linkage for a transparent function
public var transparentfuncptr = transparentfunc

protocol MyProto {
func protofunc() -> Int
}
Expand Down
14 changes: 14 additions & 0 deletions test/IRGen/sil_linkage.sil
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
sil_stage canonical

// CHECK: define{{( protected)?}} void @public_fragile_function_test() {{.*}} {
// CHECK: define{{( protected)?}} internal void @public_transparent_fragile_function_test() {{.*}} {
// CHECK: define{{( protected)?}} void @public_transparent_function_test() {{.*}} {
// CHECK: define{{( protected)?}} void @hidden_fragile_function_test() {{.*}} {
// CHECK: define linkonce_odr hidden void @shared_fragile_function_test() {{.*}} {
// CHECK: define{{( protected)?}} void @private_fragile_function_test() {{.*}} {
Expand All @@ -23,6 +25,16 @@ sil public [fragile] @public_fragile_function_test : $@convention(thin) () -> ()
return %0 : $()
}

sil public [transparent] [fragile] @public_transparent_fragile_function_test : $@convention(thin) () -> () {
%0 = tuple()
return %0 : $()
}

sil public [transparent] @public_transparent_function_test : $@convention(thin) () -> () {
%0 = tuple()
return %0 : $()
}

sil hidden [fragile] @hidden_fragile_function_test : $@convention(thin) () -> () {
%0 = tuple()
return %0 : $()
Expand Down Expand Up @@ -122,6 +134,8 @@ sil hidden_external @hidden_external_resilient_function_decl_test : $@convention

sil public @use_all_symbols : $@convention(thin) () -> () {
%0 = function_ref @public_fragile_function_test : $@convention(thin) () -> ()
%t0 = function_ref @public_transparent_fragile_function_test : $@convention(thin) () -> ()
%t1 = function_ref @public_transparent_function_test : $@convention(thin) () -> ()
%1 = function_ref @hidden_fragile_function_test : $@convention(thin) () -> ()
%2 = function_ref @shared_fragile_function_test : $@convention(thin) () -> ()
%3 = function_ref @private_fragile_function_test : $@convention(thin) () -> ()
Expand Down