Skip to content

Commit 4a74c8f

Browse files
committed
[5.3] IRGen: Always eliminate frame pointers of leaf functions
Explanation: This change makes it such that we don't emit frame pointers in leaf functions leading to decreased code size and improved performance. Scope: Should not visibly affect Swift programs other than making them faster. Risk: Medium. There might be unknown dependencies on having the frame pointer available in leaf functions. Testing: Unit test added Reviewer: Andrew Trick rdar://20933449
1 parent 32b2521 commit 4a74c8f

File tree

8 files changed

+91
-11
lines changed

8 files changed

+91
-11
lines changed

include/swift/AST/IRGenOptions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ class IRGenOptions {
194194
unsigned DisableLLVMSLPVectorizer : 1;
195195

196196
/// Disable frame pointer elimination?
197+
unsigned DisableFPElimLeaf : 1;
197198
unsigned DisableFPElim : 1;
198199

199200
/// Special codegen for playgrounds.
@@ -322,6 +323,7 @@ class IRGenOptions {
322323
DisableClangModuleSkeletonCUs(false), UseJIT(false),
323324
IntegratedREPL(false), DisableLLVMOptzns(false),
324325
DisableSwiftSpecificLLVMOptzns(false), DisableLLVMSLPVectorizer(false),
326+
DisableFPElimLeaf(false),
325327
DisableFPElim(true), Playground(false), EmitStackPromotionChecks(false),
326328
FunctionSections(false), PrintInlineTree(false), EmbedMode(IRGenEmbedMode::None),
327329
HasValueNamesSetting(false), ValueNames(false),

include/swift/Option/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,10 @@ def enable_private_imports : Flag<["-"], "enable-private-imports">,
10121012
Flags<[FrontendOption, NoInteractiveOption, HelpHidden]>,
10131013
HelpText<"Allows this module's internal and private API to be accessed">;
10141014

1015+
def disable_leaf_frame_pointer_elim : Flag<["-"], "no-omit-leaf-frame-pointer">,
1016+
Flags<[FrontendOption, NoInteractiveOption, HelpHidden]>,
1017+
HelpText<"Don't omit the frame pointer for leaf functions">;
1018+
10151019
def sanitize_EQ : CommaJoined<["-"], "sanitize=">,
10161020
Flags<[FrontendOption, NoInteractiveOption]>, MetaVarName<"<check>">,
10171021
HelpText<"Turn on runtime checks for erroneous behavior.">;

lib/Driver/ToolChains.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,8 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
289289
arguments.push_back("-enable-anonymous-context-mangled-names");
290290
}
291291

292+
inputArgs.AddLastArg(arguments, options::OPT_disable_leaf_frame_pointer_elim);
293+
292294
// Pass through any subsystem flags.
293295
inputArgs.AddAllArgs(arguments, options::OPT_Xllvm);
294296
inputArgs.AddAllArgs(arguments, options::OPT_Xcc);

lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1477,6 +1477,9 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
14771477
getRuntimeCompatVersion();
14781478
}
14791479

1480+
if (Args.hasArg(OPT_disable_leaf_frame_pointer_elim))
1481+
Opts.DisableFPElimLeaf = true;
1482+
14801483
return false;
14811484
}
14821485

lib/IRGen/IRGenModule.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,20 @@ static llvm::PointerType *createStructPointerType(IRGenModule &IGM,
8989
return createStructType(IGM, name, types)->getPointerTo(DefaultAS);
9090
};
9191

92+
static clang::CodeGenOptions::FramePointerKind
93+
shouldUseFramePointer(const IRGenOptions &Opts) {
94+
if (Opts.DisableFPElim) {
95+
// General frame pointer elimination is disabled.
96+
// Should we at least eliminate in leaf functions?
97+
return Opts.DisableFPElimLeaf
98+
? clang::CodeGenOptions::FramePointerKind::All
99+
: clang::CodeGenOptions::FramePointerKind::NonLeaf;
100+
}
101+
102+
return clang::CodeGenOptions::FramePointerKind::None;
103+
104+
}
105+
92106
static clang::CodeGenerator *createClangCodeGenerator(ASTContext &Context,
93107
llvm::LLVMContext &LLVMContext,
94108
const IRGenOptions &Opts,
@@ -101,9 +115,7 @@ static clang::CodeGenerator *createClangCodeGenerator(ASTContext &Context,
101115

102116
auto &CGO = Importer->getClangCodeGenOpts();
103117
CGO.OptimizationLevel = Opts.shouldOptimize() ? 3 : 0;
104-
CGO.setFramePointer(Opts.DisableFPElim
105-
? clang::CodeGenOptions::FramePointerKind::All
106-
: clang::CodeGenOptions::FramePointerKind::None);
118+
CGO.setFramePointer(shouldUseFramePointer(Opts));
107119
CGO.DiscardValueNames = !Opts.shouldProvideValueNames();
108120
switch (Opts.DebugInfoLevel) {
109121
case IRGenDebugInfoLevel::None:
@@ -983,7 +995,8 @@ bool swift::irgen::shouldRemoveTargetFeature(StringRef feature) {
983995

984996
void IRGenModule::setHasFramePointer(llvm::AttrBuilder &Attrs,
985997
bool HasFramePointer) {
986-
Attrs.addAttribute("frame-pointer", HasFramePointer ? "all" : "none");
998+
auto UseFramePointer = IRGen.Opts.DisableFPElimLeaf ? "all" : "non-leaf";
999+
Attrs.addAttribute("frame-pointer", HasFramePointer ? UseFramePointer : "none");
9871000
}
9881001

9891002
void IRGenModule::setHasFramePointer(llvm::Function *F,

test/IRGen/c_globals.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,4 @@ public func testCaptureGlobal() {
3232
}
3333

3434
// CHECK-DAG: attributes [[CLANG_FUNC_ATTR]] = { noinline nounwind {{.*}}"frame-pointer"="all"{{.*}}
35-
// CHECK-DAG: attributes [[SWIFT_FUNC_ATTR]] = { "frame-pointer"="all" {{.*}}"target-cpu"
35+
// CHECK-DAG: attributes [[SWIFT_FUNC_ATTR]] = { {{.*}}"frame-pointer"="non-leaf" {{.*}}"target-cpu"

test/IRGen/framepointer.sil

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// RUN: %target-swift-frontend -primary-file %s -emit-ir | %FileCheck %s --check-prefix=CHECK
2+
// RUN: %target-swift-frontend -primary-file %s -emit-ir -no-omit-leaf-frame-pointer| %FileCheck %s --check-prefix=CHECK-ALL
3+
// RUN: %target-swift-frontend -primary-file %s -S | %FileCheck %s --check-prefix=CHECKASM --check-prefix=CHECKASM-%target-os-%target-cpu
4+
5+
sil_stage canonical
6+
7+
import Swift
8+
9+
sil @leaf_function_no_frame_pointer : $@convention(thin) (Int32) -> Int32 {
10+
entry(%i : $Int32):
11+
return %i : $Int32
12+
}
13+
14+
sil @non_leaf_function_with_frame_pointer : $@convention(thin) (Int32) -> Int32 {
15+
entry(%i : $Int32):
16+
%f = function_ref @leaf_function_no_frame_pointer : $@convention(thin) (Int32) -> Int32
17+
%r = apply %f(%i) : $@convention(thin) (Int32) -> Int32
18+
return %r : $Int32
19+
}
20+
21+
// CHECK: define{{.*}} swiftcc i32 @leaf_function_no_frame_pointer(i32 %0) [[ATTR:#.*]] {
22+
// CHECK: entry:
23+
// CHECK: ret i32 %0
24+
// CHECK: }
25+
26+
// CHECK: define{{.*}} swiftcc i32 @non_leaf_function_with_frame_pointer(i32 %0) [[ATTR]] {
27+
// CHECK: entry:
28+
// CHECK: %1 = call swiftcc i32 @leaf_function_no_frame_pointer(i32 %0)
29+
// CHECK: ret i32 %1
30+
// CHECK: }
31+
32+
// CHECK: attributes [[ATTR]] = {{{.*}}"frame-pointer"="non-leaf"
33+
34+
// CHECK-ALL: define{{.*}} swiftcc i32 @leaf_function_no_frame_pointer(i32 %0) [[ATTR:#.*]] {
35+
// CHECK-ALL: entry:
36+
// CHECK-ALL: ret i32 %0
37+
// CHECK-ALL: }
38+
39+
// CHECK-ALL: define{{.*}} swiftcc i32 @non_leaf_function_with_frame_pointer(i32 %0) [[ATTR]] {
40+
// CHECK-ALL: entry:
41+
// CHECK-ALL: %1 = call swiftcc i32 @leaf_function_no_frame_pointer(i32 %0)
42+
// CHECK-ALL: ret i32 %1
43+
// CHECK-ALL: }
44+
45+
// CHECK-ALL: attributes [[ATTR]] = {{{.*}}"frame-pointer"="all"
46+
47+
// Silence other os-archs.
48+
// CHECKASM: {{.*}}
49+
50+
// CHECKASM-macosx-x86_64-LABEL: _leaf_function_no_frame_pointer:
51+
// CHECKASM-macosx-x86_64-NOT: push
52+
// CHECKASM-macosx-x86_64: movl %edi, %eax
53+
// CHECKASM-macosx-x86_64-NOT: pop
54+
// CHECKASM-macosx-x86_64: ret
55+
56+
57+
// CHECKASM-macosx-x86_64-LABEL: _non_leaf_function_with_frame_pointer:
58+
// CHECKASM-macosx-x86_64: pushq %rbp
59+
// CHECKASM-macosx-x86_64: movq %rsp, %rbp
60+
// CHECKASM-macosx-x86_64: callq _leaf_function_no_frame_pointer
61+
// CHECKASM-macosx-x86_64: popq %rbp
62+
// CHECKASM-macosx-x86_64: ret

test/Misc/tbi.sil

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,13 @@
1919

2020
// NO_TBI-LABEL: .globl _testTBI
2121
// NO_TBI: _testTBI
22-
// NO_TBI-NEXT: stp
23-
// NO_TBI-NEXT: mov
2422
// NO_TBI-NEXT: and
2523
// NO_TBI-NEXT: ldr
26-
// NO_TBI-NEXT: ldp
2724
// NO_TBI-NEXT: ret
2825

2926
// TBI-LABEL: .globl _testTBI
3027
// TBI: _testTBI:
31-
// TBI-NEXT: stp
32-
// TBI-NEXT: mov
3328
// TBI-NEXT: ldr
34-
// TBI-NEXT: ldp
3529
// TBI-NEXT: ret
3630

3731
sil_stage canonical

0 commit comments

Comments
 (0)