Skip to content

[DNM] Follow-up leaf frame pointer elimination #31944

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

Closed
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
2 changes: 2 additions & 0 deletions include/swift/AST/IRGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ class IRGenOptions {
unsigned DisableLLVMSLPVectorizer : 1;

/// Disable frame pointer elimination?
unsigned DisableFPElimLeaf : 1;
unsigned DisableFPElim : 1;

/// Special codegen for playgrounds.
Expand Down Expand Up @@ -319,6 +320,7 @@ class IRGenOptions {
DisableClangModuleSkeletonCUs(false), UseJIT(false),
DisableLLVMOptzns(false),
DisableSwiftSpecificLLVMOptzns(false), DisableLLVMSLPVectorizer(false),
DisableFPElimLeaf(false),
DisableFPElim(true), Playground(false), EmitStackPromotionChecks(false),
FunctionSections(false), PrintInlineTree(false), EmbedMode(IRGenEmbedMode::None),
HasValueNamesSetting(false), ValueNames(false),
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Option/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,10 @@ def enable_private_imports : Flag<["-"], "enable-private-imports">,
Flags<[FrontendOption, NoInteractiveOption, HelpHidden]>,
HelpText<"Allows this module's internal and private API to be accessed">;

def disable_leaf_frame_pointer_elim : Flag<["-"], "no-omit-leaf-frame-pointer">,
Flags<[FrontendOption, NoInteractiveOption, HelpHidden]>,
HelpText<"Don't omit the frame pointer for leaf functions">;

def sanitize_EQ : CommaJoined<["-"], "sanitize=">,
Flags<[FrontendOption, NoInteractiveOption]>, MetaVarName<"<check>">,
HelpText<"Turn on runtime checks for erroneous behavior.">;
Expand Down
2 changes: 2 additions & 0 deletions lib/Driver/ToolChains.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
arguments.push_back("-enable-anonymous-context-mangled-names");
}

inputArgs.AddLastArg(arguments, options::OPT_disable_leaf_frame_pointer_elim);

// Pass through any subsystem flags.
inputArgs.AddAllArgs(arguments, options::OPT_Xllvm);
inputArgs.AddAllArgs(arguments, options::OPT_Xcc);
Expand Down
3 changes: 3 additions & 0 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1511,6 +1511,9 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
getRuntimeCompatVersion();
}

if (Args.hasArg(OPT_disable_leaf_frame_pointer_elim))
Opts.DisableFPElimLeaf = true;

return false;
}

Expand Down
4 changes: 2 additions & 2 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ static void emitMetadataCompletionFunction(IRGenModule &IGM,
IGM.getAddrOfTypeMetadataCompletionFunction(typeDecl, ForDefinition);
f->setAttributes(IGM.constructInitialAttributes());
f->setDoesNotThrow();
IGM.setHasFramePointer(f, false);
IGM.setHasNoFramePointer(f);

IRGenFunction IGF(IGM, f);

Expand Down Expand Up @@ -2234,7 +2234,7 @@ namespace {
IGM.getAddrOfTypeMetadataInstantiationFunction(Target, ForDefinition);
f->setAttributes(IGM.constructInitialAttributes());
f->setDoesNotThrow();
IGM.setHasFramePointer(f, false);
IGM.setHasNoFramePointer(f);

IRGenFunction IGF(IGM, f);

Expand Down
32 changes: 19 additions & 13 deletions lib/IRGen/IRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,20 @@ static llvm::PointerType *createStructPointerType(IRGenModule &IGM,
return createStructType(IGM, name, types)->getPointerTo(DefaultAS);
};

static clang::CodeGenOptions::FramePointerKind
shouldUseFramePointer(const IRGenOptions &Opts) {
if (Opts.DisableFPElim) {
// General frame pointer elimination is disabled.
// Should we at least eliminate in leaf functions?
return Opts.DisableFPElimLeaf
? clang::CodeGenOptions::FramePointerKind::All
: clang::CodeGenOptions::FramePointerKind::NonLeaf;
}

return clang::CodeGenOptions::FramePointerKind::None;

}

static clang::CodeGenerator *createClangCodeGenerator(ASTContext &Context,
llvm::LLVMContext &LLVMContext,
const IRGenOptions &Opts,
Expand All @@ -102,9 +116,7 @@ static clang::CodeGenerator *createClangCodeGenerator(ASTContext &Context,

auto &CGO = Importer->getClangCodeGenOpts();
CGO.OptimizationLevel = Opts.shouldOptimize() ? 3 : 0;
CGO.setFramePointer(Opts.DisableFPElim
? clang::CodeGenOptions::FramePointerKind::All
: clang::CodeGenOptions::FramePointerKind::None);
CGO.setFramePointer(shouldUseFramePointer(Opts));
CGO.DiscardValueNames = !Opts.shouldProvideValueNames();
switch (Opts.DebugInfoLevel) {
case IRGenDebugInfoLevel::None:
Expand Down Expand Up @@ -986,15 +998,13 @@ bool swift::irgen::shouldRemoveTargetFeature(StringRef feature) {
return feature == "+thumb-mode";
}

void IRGenModule::setHasFramePointer(llvm::AttrBuilder &Attrs,
bool HasFramePointer) {
Attrs.addAttribute("frame-pointer", HasFramePointer ? "all" : "none");
void IRGenModule::setHasNoFramePointer(llvm::AttrBuilder &Attrs) {
Attrs.addAttribute("frame-pointer", "none");
}

void IRGenModule::setHasFramePointer(llvm::Function *F,
bool HasFramePointer) {
void IRGenModule::setHasNoFramePointer(llvm::Function *F) {
llvm::AttrBuilder b;
setHasFramePointer(b, HasFramePointer);
setHasNoFramePointer(b);
F->addAttributes(llvm::AttributeList::FunctionIndex, b);
}

Expand All @@ -1004,10 +1014,6 @@ void IRGenModule::constructInitialFnAttributes(llvm::AttrBuilder &Attrs,
// Add the default attributes for the Clang configuration.
clang::CodeGen::addDefaultFunctionDefinitionAttributes(getClangCGM(), Attrs);

// Add frame pointer attributes.
// FIXME: why are we doing this?
setHasFramePointer(Attrs, IRGen.Opts.DisableFPElim);

// Add/remove MinSize based on the appropriate setting.
if (FuncOptMode == OptimizationMode::NotSet)
FuncOptMode = IRGen.Opts.OptMode;
Expand Down
4 changes: 2 additions & 2 deletions lib/IRGen/IRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -1305,8 +1305,8 @@ private: \
void constructInitialFnAttributes(llvm::AttrBuilder &Attrs,
OptimizationMode FuncOptMode =
OptimizationMode::NotSet);
void setHasFramePointer(llvm::AttrBuilder &Attrs, bool HasFP);
void setHasFramePointer(llvm::Function *F, bool HasFP);
void setHasNoFramePointer(llvm::AttrBuilder &Attrs);
void setHasNoFramePointer(llvm::Function *F);
llvm::AttributeList constructInitialAttributes();

void emitProtocolDecl(ProtocolDecl *D);
Expand Down
8 changes: 4 additions & 4 deletions lib/IRGen/MetadataRequest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1608,7 +1608,7 @@ void irgen::emitCacheAccessFunction(IRGenModule &IGM,
accessor->addAttribute(llvm::AttributeList::FunctionIndex,
llvm::Attribute::NoInline);
// Accessor functions don't need frame pointers.
IGM.setHasFramePointer(accessor, false);
IGM.setHasNoFramePointer(accessor);

// This function is logically 'readnone': the caller does not need
// to reason about any side effects or stores it might perform.
Expand Down Expand Up @@ -1990,8 +1990,8 @@ MetadataResponse irgen::emitGenericTypeMetadataAccessFunction(
thunkFn->setCallingConv(IGM.SwiftCC);
thunkFn->addAttribute(llvm::AttributeList::FunctionIndex,
llvm::Attribute::NoInline);
IGM.setHasFramePointer(thunkFn, false);
IGM.setHasNoFramePointer(thunkFn);

[&IGM, thunkFn]{
IRGenFunction subIGF(IGM, thunkFn);

Expand Down Expand Up @@ -2462,7 +2462,7 @@ emitMetadataAccessByMangledName(IRGenFunction &IGF, CanType type,
instantiationFn->setDoesNotThrow();
instantiationFn->addAttribute(llvm::AttributeList::FunctionIndex,
llvm::Attribute::NoInline);
IGM.setHasFramePointer(instantiationFn, false);
IGM.setHasNoFramePointer(instantiationFn);

[&IGM, instantiationFn, request]{
IRGenFunction subIGF(IGM, instantiationFn);
Expand Down
4 changes: 2 additions & 2 deletions test/IRGen/c_globals.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ public func testCaptureGlobal() {
}) // CHECK: {{^}$}}
}

// CHECK-DAG: attributes [[CLANG_FUNC_ATTR]] = { noinline nounwind {{.*}}"frame-pointer"="all"{{.*}}
// CHECK-DAG: attributes [[SWIFT_FUNC_ATTR]] = { {{.*}}"frame-pointer"="all" {{.*}}"target-cpu"
// CHECK-DAG: attributes [[CLANG_FUNC_ATTR]] = { noinline nounwind {{.*}}"frame-pointer"="non-leaf"{{.*}}
// CHECK-DAG: attributes [[SWIFT_FUNC_ATTR]] = { {{.*}}"frame-pointer"="non-leaf" {{.*}}"target-cpu"
62 changes: 62 additions & 0 deletions test/IRGen/framepointer.sil
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// RUN: %target-swift-frontend -primary-file %s -emit-ir | %FileCheck %s --check-prefix=CHECK
// RUN: %target-swift-frontend -primary-file %s -emit-ir -no-omit-leaf-frame-pointer| %FileCheck %s --check-prefix=CHECK-ALL
// RUN: %target-swift-frontend -primary-file %s -S | %FileCheck %s --check-prefix=CHECKASM --check-prefix=CHECKASM-%target-os-%target-cpu

sil_stage canonical

import Swift

sil @leaf_function_no_frame_pointer : $@convention(thin) (Int32) -> Int32 {
entry(%i : $Int32):
return %i : $Int32
}

sil @non_leaf_function_with_frame_pointer : $@convention(thin) (Int32) -> Int32 {
entry(%i : $Int32):
%f = function_ref @leaf_function_no_frame_pointer : $@convention(thin) (Int32) -> Int32
%r = apply %f(%i) : $@convention(thin) (Int32) -> Int32
return %r : $Int32
}

// CHECK: define{{.*}} swiftcc i32 @leaf_function_no_frame_pointer(i32 %0) [[ATTR:#.*]] {
// CHECK: entry:
// CHECK: ret i32 %0
// CHECK: }

// CHECK: define{{.*}} swiftcc i32 @non_leaf_function_with_frame_pointer(i32 %0) [[ATTR]] {
// CHECK: entry:
// CHECK: %1 = call swiftcc i32 @leaf_function_no_frame_pointer(i32 %0)
// CHECK: ret i32 %1
// CHECK: }

// CHECK: attributes [[ATTR]] = {{{.*}}"frame-pointer"="non-leaf"

// CHECK-ALL: define{{.*}} swiftcc i32 @leaf_function_no_frame_pointer(i32 %0) [[ATTR:#.*]] {
// CHECK-ALL: entry:
// CHECK-ALL: ret i32 %0
// CHECK-ALL: }

// CHECK-ALL: define{{.*}} swiftcc i32 @non_leaf_function_with_frame_pointer(i32 %0) [[ATTR]] {
// CHECK-ALL: entry:
// CHECK-ALL: %1 = call swiftcc i32 @leaf_function_no_frame_pointer(i32 %0)
// CHECK-ALL: ret i32 %1
// CHECK-ALL: }

// CHECK-ALL: attributes [[ATTR]] = {{{.*}}"frame-pointer"="all"

// Silence other os-archs.
// CHECKASM: {{.*}}

// CHECKASM-macosx-x86_64-LABEL: _leaf_function_no_frame_pointer:
// CHECKASM-macosx-x86_64-NOT: push
// CHECKASM-macosx-x86_64: movl %edi, %eax
// CHECKASM-macosx-x86_64-NOT: pop
// CHECKASM-macosx-x86_64: ret


// CHECKASM-macosx-x86_64-LABEL: _non_leaf_function_with_frame_pointer:
// CHECKASM-macosx-x86_64: pushq %rbp
// CHECKASM-macosx-x86_64: movq %rsp, %rbp
// CHECKASM-macosx-x86_64: callq _leaf_function_no_frame_pointer
// CHECKASM-macosx-x86_64: popq %rbp
// CHECKASM-macosx-x86_64: ret
6 changes: 0 additions & 6 deletions test/Misc/tbi.sil
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,13 @@

// NO_TBI-LABEL: .globl _testTBI
// NO_TBI: _testTBI
// NO_TBI-NEXT: stp
// NO_TBI-NEXT: mov
// NO_TBI-NEXT: and
// NO_TBI-NEXT: ldr
// NO_TBI-NEXT: ldp
// NO_TBI-NEXT: ret

// TBI-LABEL: .globl _testTBI
// TBI: _testTBI:
// TBI-NEXT: stp
// TBI-NEXT: mov
// TBI-NEXT: ldr
// TBI-NEXT: ldp
// TBI-NEXT: ret

sil_stage canonical
Expand Down