Skip to content

Commit 45810d0

Browse files
Merge pull request #31921 from aschwaighofer/irgen_frame_pointer_non_leaf_only
IRGen: Always eliminate frame pointers of leaf functions
2 parents 65962f1 + a12e0b3 commit 45810d0

File tree

8 files changed

+190
-22
lines changed

8 files changed

+190
-22
lines changed

include/swift/AST/IRGenOptions.h

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

193193
/// Disable frame pointer elimination?
194+
unsigned DisableFPElimLeaf : 1;
194195
unsigned DisableFPElim : 1;
195196

196197
/// Special codegen for playgrounds.
@@ -319,6 +320,7 @@ class IRGenOptions {
319320
DisableClangModuleSkeletonCUs(false), UseJIT(false),
320321
DisableLLVMOptzns(false),
321322
DisableSwiftSpecificLLVMOptzns(false), DisableLLVMSLPVectorizer(false),
323+
DisableFPElimLeaf(false),
322324
DisableFPElim(true), Playground(false), EmitStackPromotionChecks(false),
323325
FunctionSections(false), PrintInlineTree(false), EmbedMode(IRGenEmbedMode::None),
324326
HasValueNamesSetting(false), ValueNames(false),

include/swift/Option/Options.td

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

1013+
def disable_leaf_frame_pointer_elim : Flag<["-"], "no-omit-leaf-frame-pointer">,
1014+
Flags<[FrontendOption, NoInteractiveOption, HelpHidden]>,
1015+
HelpText<"Don't omit the frame pointer for leaf functions">;
1016+
10131017
def sanitize_EQ : CommaJoined<["-"], "sanitize=">,
10141018
Flags<[FrontendOption, NoInteractiveOption]>, MetaVarName<"<check>">,
10151019
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
@@ -288,6 +288,8 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
288288
arguments.push_back("-enable-anonymous-context-mangled-names");
289289
}
290290

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

lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,9 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
15111511
getRuntimeCompatVersion();
15121512
}
15131513

1514+
if (Args.hasArg(OPT_disable_leaf_frame_pointer_elim))
1515+
Opts.DisableFPElimLeaf = true;
1516+
15141517
return false;
15151518
}
15161519

lib/IRGen/IRGenModule.cpp

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -90,21 +90,34 @@ static llvm::PointerType *createStructPointerType(IRGenModule &IGM,
9090
return createStructType(IGM, name, types)->getPointerTo(DefaultAS);
9191
};
9292

93-
static clang::CodeGenerator *createClangCodeGenerator(ASTContext &Context,
94-
llvm::LLVMContext &LLVMContext,
95-
const IRGenOptions &Opts,
96-
StringRef ModuleName,
97-
StringRef PD) {
93+
static clang::CodeGenOptions::FramePointerKind
94+
shouldUseFramePointer(const IRGenOptions &Opts, const llvm::Triple &triple) {
95+
if (Opts.DisableFPElim) {
96+
// General frame pointer elimination is disabled.
97+
// Should we at least eliminate in leaf functions?
98+
// Currently we only do that on arm64 (this matches the behavior of clang).
99+
return Opts.DisableFPElimLeaf
100+
? clang::CodeGenOptions::FramePointerKind::All
101+
: triple.isAArch64()
102+
? clang::CodeGenOptions::FramePointerKind::NonLeaf
103+
: clang::CodeGenOptions::FramePointerKind::All;
104+
}
105+
106+
return clang::CodeGenOptions::FramePointerKind::None;
107+
}
108+
109+
static clang::CodeGenerator *
110+
createClangCodeGenerator(ASTContext &Context, llvm::LLVMContext &LLVMContext,
111+
const IRGenOptions &Opts, StringRef ModuleName,
112+
StringRef PD, const llvm::Triple &triple) {
98113
auto Loader = Context.getClangModuleLoader();
99114
auto *Importer = static_cast<ClangImporter*>(&*Loader);
100115
assert(Importer && "No clang module loader!");
101116
auto &ClangContext = Importer->getClangASTContext();
102117

103118
auto &CGO = Importer->getClangCodeGenOpts();
104119
CGO.OptimizationLevel = Opts.shouldOptimize() ? 3 : 0;
105-
CGO.setFramePointer(Opts.DisableFPElim
106-
? clang::CodeGenOptions::FramePointerKind::All
107-
: clang::CodeGenOptions::FramePointerKind::None);
120+
CGO.setFramePointer(shouldUseFramePointer(Opts, triple));
108121
CGO.DiscardValueNames = !Opts.shouldProvideValueNames();
109122
switch (Opts.DebugInfoLevel) {
110123
case IRGenDebugInfoLevel::None:
@@ -194,17 +207,17 @@ static void sanityCheckStdlib(IRGenModule &IGM) {
194207

195208
IRGenModule::IRGenModule(IRGenerator &irgen,
196209
std::unique_ptr<llvm::TargetMachine> &&target,
197-
SourceFile *SF,
198-
StringRef ModuleName, StringRef OutputFilename,
210+
SourceFile *SF, StringRef ModuleName,
211+
StringRef OutputFilename,
199212
StringRef MainInputFilenameForDebugInfo,
200213
StringRef PrivateDiscriminator)
201-
: LLVMContext(new llvm::LLVMContext()),
202-
IRGen(irgen), Context(irgen.SIL.getASTContext()),
214+
: LLVMContext(new llvm::LLVMContext()), IRGen(irgen),
215+
Context(irgen.SIL.getASTContext()),
203216
// The LLVMContext (and the IGM itself) will get deleted by the IGMDeleter
204217
// as long as the IGM is registered with the IRGenerator.
205-
ClangCodeGen(createClangCodeGenerator(Context, *LLVMContext,
206-
irgen.Opts,
207-
ModuleName, PrivateDiscriminator)),
218+
ClangCodeGen(createClangCodeGenerator(Context, *LLVMContext, irgen.Opts,
219+
ModuleName, PrivateDiscriminator,
220+
irgen.getEffectiveClangTriple())),
208221
Module(*ClangCodeGen->GetModule()),
209222
DataLayout(irgen.getClangDataLayout()),
210223
Triple(irgen.getEffectiveClangTriple()), TargetMachine(std::move(target)),
@@ -988,7 +1001,20 @@ bool swift::irgen::shouldRemoveTargetFeature(StringRef feature) {
9881001

9891002
void IRGenModule::setHasFramePointer(llvm::AttrBuilder &Attrs,
9901003
bool HasFramePointer) {
991-
Attrs.addAttribute("frame-pointer", HasFramePointer ? "all" : "none");
1004+
if (!HasFramePointer) {
1005+
Attrs.addAttribute("frame-pointer", "none");
1006+
return;
1007+
}
1008+
if (IRGen.Opts.DisableFPElimLeaf) {
1009+
Attrs.addAttribute("frame-pointer", "all");
1010+
return;
1011+
}
1012+
1013+
// We omit frame pointers for leaf functions only for arm64 for now (matching
1014+
// clang's behavior).
1015+
auto framePointer =
1016+
IRGen.getEffectiveClangTriple().isAArch64() ? "non-leaf" : "all";
1017+
Attrs.addAttribute("frame-pointer", framePointer);
9921018
}
9931019

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

test/IRGen/framepointer.sil

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

test/IRGen/framepointer_arm64.sil

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// RUN: %target-swift-frontend -target arm64-apple-ios8.0 -primary-file %s -emit-ir | %FileCheck %s --check-prefix=CHECK
2+
// RUN: %target-swift-frontend -target arm64-apple-ios8.0 -primary-file %s -emit-ir -no-omit-leaf-frame-pointer| %FileCheck %s --check-prefix=CHECK-ALL
3+
// RUN: %target-swift-frontend -target arm64-apple-ios8.0 -primary-file %s -S | %FileCheck %s --check-prefix=CHECKASM
4+
// RUN: %target-swift-frontend -target arm64-apple-ios8.0 -primary-file %s -S -no-omit-leaf-frame-pointer | %FileCheck %s --check-prefix=CHECKASM-ALL
5+
6+
// REQUIRES: CODEGENERATOR=AArch64
7+
8+
// UNSUPPORTED: OS=linux-gnu
9+
// UNSUPPORTED: OS=windows
10+
11+
sil_stage canonical
12+
13+
import Swift
14+
15+
sil @leaf_function_no_frame_pointer : $@convention(thin) (Int32) -> Int32 {
16+
entry(%i : $Int32):
17+
return %i : $Int32
18+
}
19+
20+
sil @non_leaf_function_with_frame_pointer : $@convention(thin) (Int32) -> Int32 {
21+
entry(%i : $Int32):
22+
%f = function_ref @leaf_function_no_frame_pointer : $@convention(thin) (Int32) -> Int32
23+
%r = apply %f(%i) : $@convention(thin) (Int32) -> Int32
24+
return %r : $Int32
25+
}
26+
27+
// CHECK: define{{.*}} swiftcc i32 @leaf_function_no_frame_pointer(i32 %0) [[ATTR:#.*]] {
28+
// CHECK: entry:
29+
// CHECK: ret i32 %0
30+
// CHECK: }
31+
32+
// CHECK: define{{.*}} swiftcc i32 @non_leaf_function_with_frame_pointer(i32 %0) [[ATTR]] {
33+
// CHECK: entry:
34+
// CHECK: %1 = call swiftcc i32 @leaf_function_no_frame_pointer(i32 %0)
35+
// CHECK: ret i32 %1
36+
// CHECK: }
37+
38+
// CHECK: attributes [[ATTR]] = {{{.*}}"frame-pointer"="non-leaf"
39+
40+
// CHECK-ALL: define{{.*}} swiftcc i32 @leaf_function_no_frame_pointer(i32 %0) [[ATTR:#.*]] {
41+
// CHECK-ALL: entry:
42+
// CHECK-ALL: ret i32 %0
43+
// CHECK-ALL: }
44+
45+
// CHECK-ALL: define{{.*}} swiftcc i32 @non_leaf_function_with_frame_pointer(i32 %0) [[ATTR]] {
46+
// CHECK-ALL: entry:
47+
// CHECK-ALL: %1 = call swiftcc i32 @leaf_function_no_frame_pointer(i32 %0)
48+
// CHECK-ALL: ret i32 %1
49+
// CHECK-ALL: }
50+
51+
// CHECK-ALL: attributes [[ATTR]] = {{{.*}}"frame-pointer"="all"
52+
53+
// CHECKASM-LABEL: _leaf_function_no_frame_pointer:
54+
// CHECKASM-NOT: stp
55+
// CHECKASM-NOT: ldp
56+
// CHECKASM: ret
57+
58+
// CHECKASM-LABEL: _non_leaf_function_with_frame_pointer:
59+
// CHECKASM: stp
60+
// CHECKASM: _leaf_function_no_frame_pointer
61+
// CHECKASM: ldp
62+
// CHECKASM: ret
63+
64+
// CHECKASM-ALL-LABEL: _leaf_function_no_frame_pointer:
65+
// CHECKASM-ALL: stp
66+
// CHECKASM-ALL: ldp
67+
// CHECKASM-ALL: ret
68+
69+
// CHECKASM-ALL-LABEL: _non_leaf_function_with_frame_pointer:
70+
// CHECKASM-ALL: stp
71+
// CHECKASM-ALL: _leaf_function_no_frame_pointer
72+
// CHECKASM-ALL: ldp
73+
// CHECKASM-ALL: 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)