Skip to content

Commit

Permalink
Don't generate code for transparent functions.
Browse files Browse the repository at this point in the history
They are mandatory inlined anyway. Therefore the binary code of transparent functions is not used in most cases.
In case the address of a transparent function is taken, the main program (which deserialized the transparent function) generates code for it and treats it as shared function.

This reduces the stdlib code size by 2.8%.
  • Loading branch information
eeckstein committed Jun 16, 2016
1 parent e69195b commit d23551a
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 3 deletions.
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

0 comments on commit d23551a

Please sign in to comment.