https://github.com/omern1 updated https://github.com/llvm/llvm-project/pull/163775
>From 2cb9a74fe45202d542891b3f609cf56d80130e07 Mon Sep 17 00:00:00 2001 From: Nabeel Omer <[email protected]> Date: Thu, 16 Oct 2025 10:44:55 +0100 Subject: [PATCH 01/10] Add FramePointerKind::NonLeafNoReserve This patch adds a new FramePointerKind::NonLeafNoReserve and makes it the default for -momit-frame-pointer=leaf. This should fix #154379, the main impact of this patch can be found in clang/lib/Driver/ToolChains/CommonArgs.cpp. --- clang/include/clang/Basic/CodeGenOptions.def | 2 +- clang/include/clang/Basic/CodeGenOptions.h | 5 +- clang/include/clang/Driver/Options.td | 4 +- clang/lib/CodeGen/CGCall.cpp | 1 + clang/lib/CodeGen/CodeGenModule.cpp | 3 + clang/lib/Driver/ToolChains/Clang.cpp | 3 + clang/lib/Driver/ToolChains/CommonArgs.cpp | 42 +- clang/lib/Driver/ToolChains/Flang.cpp | 3 + clang/test/Driver/frame-pointer-elim.c | 8 +- clang/test/Driver/fuchsia.c | 2 +- llvm/include/llvm/Support/CodeGen.h | 2 +- llvm/lib/CodeGen/CommandFlags.cpp | 4 + llvm/lib/CodeGen/TargetOptionsImpl.cpp | 3 +- llvm/lib/IR/Function.cpp | 3 + llvm/lib/IR/Verifier.cpp | 2 +- llvm/test/CodeGen/X86/regalloc-fp.ll | 775 +++++++++++++++++++ 16 files changed, 836 insertions(+), 26 deletions(-) create mode 100644 llvm/test/CodeGen/X86/regalloc-fp.ll diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 90e1f8d1eb5e9..52360b67b306c 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -54,7 +54,7 @@ CODEGENOPT(SeparateNamedSections, 1, 0, Benign) ///< Set for -fseparate-named-se CODEGENOPT(EnableAIXExtendedAltivecABI, 1, 0, Benign) ///< Set for -mabi=vec-extabi. Enables the extended Altivec ABI on AIX. CODEGENOPT(XCOFFReadOnlyPointers, 1, 0, Benign) ///< Set for -mxcoff-roptr. CODEGENOPT(AllTocData, 1, 0, Benign) ///< AIX -mtocdata -ENUM_CODEGENOPT(FramePointer, FramePointerKind, 2, FramePointerKind::None, Benign) /// frame-pointer: all,non-leaf,reserved,none +ENUM_CODEGENOPT(FramePointer, FramePointerKind, 3, FramePointerKind::None, Benign) /// frame-pointer: all,non-leaf,non-leaf-no-reserve,reserved,none ENUM_CODEGENOPT(ExceptionHandling, ExceptionHandlingKind, 3, ExceptionHandlingKind::None, NotCompatible) diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index cae06c3c9495a..3dd0140ea0d9f 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -155,9 +155,10 @@ class CodeGenOptions : public CodeGenOptionsBase { std::string BinutilsVersion; enum class FramePointerKind { + NonLeafNoReserve, // Keep non-leaf frame pointers, allow the FP to be used as a GPR in leaf functions. None, // Omit all frame pointers. Reserved, // Maintain valid frame pointer chain. - NonLeaf, // Keep non-leaf frame pointers. + NonLeaf, // Keep non-leaf frame pointers, don't allow the FP to be used as a GPR in leaf functions. All, // Keep all frame pointers. }; @@ -167,6 +168,8 @@ class CodeGenOptions : public CodeGenOptionsBase { return "none"; case FramePointerKind::Reserved: return "reserved"; + case FramePointerKind::NonLeafNoReserve: + return "non-leaf-no-reserve"; case FramePointerKind::NonLeaf: return "non-leaf"; case FramePointerKind::All: diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 7ae153deb9a55..5f7ef34a36be6 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -8481,8 +8481,8 @@ def pic_is_pie : Flag<["-"], "pic-is-pie">, MarshallingInfoFlag<LangOpts<"PIE">>; def mframe_pointer_EQ : Joined<["-"], "mframe-pointer=">, - HelpText<"Specify which frame pointers to retain.">, Values<"all,non-leaf,reserved,none">, - NormalizedValuesScope<"CodeGenOptions::FramePointerKind">, NormalizedValues<["All", "NonLeaf", "Reserved", "None"]>, + HelpText<"Specify which frame pointers to retain.">, Values<"all,non-leaf,non-leaf-no-reserve,reserved,none">, + NormalizedValuesScope<"CodeGenOptions::FramePointerKind">, NormalizedValues<["All", "NonLeaf", "NonLeafNoReserve", "Reserved", "None"]>, MarshallingInfoEnum<CodeGenOpts<"FramePointer">, "None">; diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 741fa44713ac8..60a7779786ee0 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1990,6 +1990,7 @@ static void getTrivialDefaultFunctionAttributes( // This is the default behavior. break; case CodeGenOptions::FramePointerKind::Reserved: + case CodeGenOptions::FramePointerKind::NonLeafNoReserve: case CodeGenOptions::FramePointerKind::NonLeaf: case CodeGenOptions::FramePointerKind::All: FuncAttrs.addAttribute("frame-pointer", diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index c5eb14e329315..2488b2b1ded70 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1506,6 +1506,9 @@ void CodeGenModule::Release() { case CodeGenOptions::FramePointerKind::Reserved: getModule().setFramePointer(llvm::FramePointerKind::Reserved); break; + case CodeGenOptions::FramePointerKind::NonLeafNoReserve: + getModule().setFramePointer(llvm::FramePointerKind::NonLeafNoReserve); + break; case CodeGenOptions::FramePointerKind::NonLeaf: getModule().setFramePointer(llvm::FramePointerKind::NonLeaf); break; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index a7310ba2da061..7072a41d2507a 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -5748,6 +5748,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, case CodeGenOptions::FramePointerKind::Reserved: FPKeepKindStr = "-mframe-pointer=reserved"; break; + case CodeGenOptions::FramePointerKind::NonLeafNoReserve: + FPKeepKindStr = "-mframe-pointer=non-leaf-no-reserve"; + break; case CodeGenOptions::FramePointerKind::NonLeaf: FPKeepKindStr = "-mframe-pointer=non-leaf"; break; diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 99400ac701fbe..55a57acebfd9a 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -222,26 +222,36 @@ static bool framePointerImpliesLeafFramePointer(const llvm::opt::ArgList &Args, clang::CodeGenOptions::FramePointerKind getFramePointerKind(const llvm::opt::ArgList &Args, const llvm::Triple &Triple) { - // There are three things to consider here: + // There are four things to consider here: // * Should a frame record be created for non-leaf functions? // * Should a frame record be created for leaf functions? - // * Is the frame pointer register reserved, i.e. must it always point to - // either a new, valid frame record or be un-modified? + // * Is the frame pointer register reserved in non-leaf functions? + // i.e. must it always point to either a new, valid frame record or be un-modified? + // * Is the frame pointer register reserved in leaf functions? // // Not all combinations of these are valid: // * It's not useful to have leaf frame records without non-leaf ones. // * It's not useful to have frame records without reserving the frame // pointer. // - // | Non-leaf | Leaf | Reserved | - // | N | N | N | FramePointerKind::None - // | N | N | Y | FramePointerKind::Reserved - // | N | Y | N | Invalid - // | N | Y | Y | Invalid - // | Y | N | N | Invalid - // | Y | N | Y | FramePointerKind::NonLeaf - // | Y | Y | N | Invalid - // | Y | Y | Y | FramePointerKind::All + // | Non-leaf | Leaf | Reserved In Non-Leaf | Reserved In Leaf | + // |----------|------|-----------------------|------------------| + // | N | N | N | N | FramePointerKind::None + // | N | N | N | Y | Invalid + // | N | N | Y | N | Invalid + // | N | N | Y | Y | FramePointerKind::Reserved + // | N | Y | N | N | Invalid + // | N | Y | N | Y | Invalid + // | N | Y | Y | N | Invalid + // | N | Y | Y | Y | Invalid + // | Y | N | N | N | Invalid + // | Y | N | N | Y | Invalid + // | Y | N | Y | N | FramePointerKind::NonLeafNoReserve + // | Y | N | Y | Y | FramePointerKind::NonLeaf + // | Y | Y | N | N | Invalid + // | Y | Y | N | Y | Invalid + // | Y | Y | Y | N | Invalid + // | Y | Y | Y | Y | FramePointerKind::All // // The FramePointerKind::Reserved case is currently only reachable for Arm, // which has the -mframe-chain= option which can (in combination with @@ -261,12 +271,16 @@ getFramePointerKind(const llvm::opt::ArgList &Args, clang::driver::options::OPT_mno_omit_leaf_frame_pointer, clang::driver::options::OPT_momit_leaf_frame_pointer, DefaultLeafFP); - bool FPRegReserved = EnableFP || mustMaintainValidFrameChain(Args, Triple); + bool FPRegReserved = mustMaintainValidFrameChain(Args, Triple); if (EnableFP) { if (EnableLeafFP) return clang::CodeGenOptions::FramePointerKind::All; - return clang::CodeGenOptions::FramePointerKind::NonLeaf; + + if (FPRegReserved) + return clang::CodeGenOptions::FramePointerKind::NonLeaf; + + return clang::CodeGenOptions::FramePointerKind::NonLeafNoReserve; } if (FPRegReserved) return clang::CodeGenOptions::FramePointerKind::Reserved; diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index a56fa41c49d34..9eba3914b1e1e 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -1064,6 +1064,9 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, case CodeGenOptions::FramePointerKind::Reserved: FPKeepKindStr = "-mframe-pointer=reserved"; break; + case CodeGenOptions::FramePointerKind::NonLeafNoReserve: + FPKeepKindStr = "-mframe-pointer=non-leaf-no-reserve"; + break; case CodeGenOptions::FramePointerKind::NonLeaf: FPKeepKindStr = "-mframe-pointer=non-leaf"; break; diff --git a/clang/test/Driver/frame-pointer-elim.c b/clang/test/Driver/frame-pointer-elim.c index 6d719828c6a06..9b0e6fa15b0d4 100644 --- a/clang/test/Driver/frame-pointer-elim.c +++ b/clang/test/Driver/frame-pointer-elim.c @@ -1,7 +1,7 @@ // KEEP-ALL-NOT: warning: argument unused // KEEP-ALL: "-mframe-pointer=all" // KEEP-NON-LEAF-NOT: warning: argument unused -// KEEP-NON-LEAF: "-mframe-pointer=non-leaf" +// KEEP-NON-LEAF: "-mframe-pointer=non-leaf-no-reserve" // KEEP-NONE-NOT: warning: argument unused // KEEP-NONE: "-mframe-pointer=none" // KEEP-RESERVED-NOT: warning: argument unused @@ -73,17 +73,17 @@ // RUN: %clang -### -target armv7s-apple-ios -fomit-frame-pointer %s 2>&1 | \ // RUN: FileCheck --check-prefix=WARN-OMIT-7S %s // WARN-OMIT-7S: warning: optimization flag '-fomit-frame-pointer' is not supported for target 'armv7s' -// WARN-OMIT-7S: "-mframe-pointer=non-leaf" +// WARN-OMIT-7S: "-mframe-pointer=non-leaf-no-reserve" // RUN: %clang -### -target armv7k-apple-watchos -fomit-frame-pointer %s 2>&1 | \ // RUN: FileCheck --check-prefix=WARN-OMIT-7K %s // WARN-OMIT-7K: warning: optimization flag '-fomit-frame-pointer' is not supported for target 'armv7k' -// WARN-OMIT-7K: "-mframe-pointer=non-leaf" +// WARN-OMIT-7K: "-mframe-pointer=non-leaf-no-reserve" // RUN: %clang -### -target armv7s-apple-ios8.0 -momit-leaf-frame-pointer %s 2>&1 | \ // RUN: FileCheck --check-prefix=WARN-OMIT-LEAF-7S %s // WARN-OMIT-LEAF-7S-NOT: warning: optimization flag '-momit-leaf-frame-pointer' is not supported for target 'armv7s' -// WARN-OMIT-LEAF-7S: "-mframe-pointer=non-leaf" +// WARN-OMIT-LEAF-7S: "-mframe-pointer=non-leaf-no-reserve" // On AArch64, PS4, PS5, and VE, default to omitting the frame pointer on leaf // functions diff --git a/clang/test/Driver/fuchsia.c b/clang/test/Driver/fuchsia.c index cf92f85040901..71aabcc9f7fc1 100644 --- a/clang/test/Driver/fuchsia.c +++ b/clang/test/Driver/fuchsia.c @@ -68,7 +68,7 @@ // RUN: %clang -### %s --target=aarch64-unknown-fuchsia -O3 2>&1 \ // RUN: | FileCheck %s -check-prefix=CHECK-FP-NONE // CHECK-FP-ALL: "-mframe-pointer=all" -// CHECK-FP-NONLEAF: "-mframe-pointer=non-leaf" +// CHECK-FP-NONLEAF: "-mframe-pointer=non-leaf-no-reserve" // CHECK-FP-NONE: "-mframe-pointer=none" // RUN: not %clang -### %s --target=x86_64-unknown-fuchsia -rtlib=libgcc 2>&1 \ diff --git a/llvm/include/llvm/Support/CodeGen.h b/llvm/include/llvm/Support/CodeGen.h index cd1f9167b996d..6675f131bc406 100644 --- a/llvm/include/llvm/Support/CodeGen.h +++ b/llvm/include/llvm/Support/CodeGen.h @@ -115,7 +115,7 @@ namespace llvm { }; // Specify what functions should keep the frame pointer. - enum class FramePointerKind { None, NonLeaf, All, Reserved }; + enum class FramePointerKind { None, NonLeaf, All, Reserved, NonLeafNoReserve }; // Specify what type of zeroing callee-used registers. namespace ZeroCallUsedRegs { diff --git a/llvm/lib/CodeGen/CommandFlags.cpp b/llvm/lib/CodeGen/CommandFlags.cpp index 0522698adf183..e3089dd1eb07b 100644 --- a/llvm/lib/CodeGen/CommandFlags.cpp +++ b/llvm/lib/CodeGen/CommandFlags.cpp @@ -211,6 +211,8 @@ codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() { clEnumValN(FramePointerKind::All, "all", "Disable frame pointer elimination"), clEnumValN(FramePointerKind::NonLeaf, "non-leaf", + "Disable frame pointer elimination for non-leaf frame but reserve the register in leaf functions"), + clEnumValN(FramePointerKind::NonLeafNoReserve, "non-leaf-no-reserve", "Disable frame pointer elimination for non-leaf frame"), clEnumValN(FramePointerKind::Reserved, "reserved", "Enable frame pointer elimination, but reserve the frame " @@ -695,6 +697,8 @@ void codegen::setFunctionAttributes(StringRef CPU, StringRef Features, NewAttrs.addAttribute("frame-pointer", "all"); else if (getFramePointerUsage() == FramePointerKind::NonLeaf) NewAttrs.addAttribute("frame-pointer", "non-leaf"); + else if (getFramePointerUsage() == FramePointerKind::NonLeafNoReserve) + NewAttrs.addAttribute("frame-pointer", "non-leaf-no-reserve"); else if (getFramePointerUsage() == FramePointerKind::Reserved) NewAttrs.addAttribute("frame-pointer", "reserved"); else if (getFramePointerUsage() == FramePointerKind::None) diff --git a/llvm/lib/CodeGen/TargetOptionsImpl.cpp b/llvm/lib/CodeGen/TargetOptionsImpl.cpp index 5eb86e740ff7c..90d61f7b359e5 100644 --- a/llvm/lib/CodeGen/TargetOptionsImpl.cpp +++ b/llvm/lib/CodeGen/TargetOptionsImpl.cpp @@ -30,7 +30,7 @@ bool TargetOptions::DisableFramePointerElim(const MachineFunction &MF) const { StringRef FP = FPAttr.getValueAsString(); if (FP == "all") return true; - if (FP == "non-leaf") + if (FP == "non-leaf" || FP == "non-leaf-no-reserve") return MF.getFrameInfo().hasCalls(); if (FP == "none" || FP == "reserved") return false; @@ -45,6 +45,7 @@ bool TargetOptions::FramePointerIsReserved(const MachineFunction &MF) const { return StringSwitch<bool>(FPAttr.getValueAsString()) .Cases("all", "non-leaf", "reserved", true) + .Case(("non-leaf-no-reserve"), MF.getFrameInfo().hasCalls()) .Case("none", false); } diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp index fc067459dcba3..31a294447152e 100644 --- a/llvm/lib/IR/Function.cpp +++ b/llvm/lib/IR/Function.cpp @@ -396,6 +396,9 @@ Function *Function::createWithDefaultAttr(FunctionType *Ty, case FramePointerKind::NonLeaf: B.addAttribute("frame-pointer", "non-leaf"); break; + case FramePointerKind::NonLeafNoReserve: + B.addAttribute("frame-pointer", "non-leaf-no-reserve"); + break; case FramePointerKind::All: B.addAttribute("frame-pointer", "all"); break; diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index c79a95087dbdd..4a5e0b6bdae97 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -2484,7 +2484,7 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs, if (Attribute FPAttr = Attrs.getFnAttr("frame-pointer"); FPAttr.isValid()) { StringRef FP = FPAttr.getValueAsString(); - if (FP != "all" && FP != "non-leaf" && FP != "none" && FP != "reserved") + if (FP != "all" && FP != "non-leaf" && FP != "none" && FP != "reserved" && FP != "non-leaf-no-reserve") CheckFailed("invalid value for 'frame-pointer' attribute: " + FP, V); } diff --git a/llvm/test/CodeGen/X86/regalloc-fp.ll b/llvm/test/CodeGen/X86/regalloc-fp.ll new file mode 100644 index 0000000000000..e89e5ab1d6b59 --- /dev/null +++ b/llvm/test/CodeGen/X86/regalloc-fp.ll @@ -0,0 +1,775 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; Context: +; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s +define i32 @check_none() "frame-pointer"="none" { +; CHECK-LABEL: check_none: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: pushq %rbp +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: pushq %r15 +; CHECK-NEXT: .cfi_def_cfa_offset 24 +; CHECK-NEXT: pushq %r14 +; CHECK-NEXT: .cfi_def_cfa_offset 32 +; CHECK-NEXT: pushq %r13 +; CHECK-NEXT: .cfi_def_cfa_offset 40 +; CHECK-NEXT: pushq %r12 +; CHECK-NEXT: .cfi_def_cfa_offset 48 +; CHECK-NEXT: pushq %rbx +; CHECK-NEXT: .cfi_def_cfa_offset 56 +; CHECK-NEXT: .cfi_offset %rbx, -56 +; CHECK-NEXT: .cfi_offset %r12, -48 +; CHECK-NEXT: .cfi_offset %r13, -40 +; CHECK-NEXT: .cfi_offset %r14, -32 +; CHECK-NEXT: .cfi_offset %r15, -24 +; CHECK-NEXT: .cfi_offset %rbp, -16 +; CHECK-NEXT: movl $0, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $1, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $2, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $3, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $4, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $5, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $6, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $7, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $8, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $9, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $16, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $17, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $18, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $19, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $20, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %ecx +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %edx +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %esi +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %edi +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r8d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r9d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r10d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r11d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %ebx +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %ebp +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r14d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r15d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r12d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r13d +; CHECK-NEXT: #APP +; CHECK-NEXT: nop +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: movl %eax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %ecx, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %edx, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %esi, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %edi, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r8d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r9d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r10d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r11d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %ebx, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %ebp, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r14d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r15d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r12d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r13d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: popq %rbx +; CHECK-NEXT: .cfi_def_cfa_offset 48 +; CHECK-NEXT: popq %r12 +; CHECK-NEXT: .cfi_def_cfa_offset 40 +; CHECK-NEXT: popq %r13 +; CHECK-NEXT: .cfi_def_cfa_offset 32 +; CHECK-NEXT: popq %r14 +; CHECK-NEXT: .cfi_def_cfa_offset 24 +; CHECK-NEXT: popq %r15 +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: popq %rbp +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq +entry: + %reg0 = alloca i32, align 4 + %reg1 = alloca i32, align 4 + %reg2 = alloca i32, align 4 + %reg3 = alloca i32, align 4 + %reg4 = alloca i32, align 4 + %reg5 = alloca i32, align 4 + %reg6 = alloca i32, align 4 + %reg7 = alloca i32, align 4 + %reg8 = alloca i32, align 4 + %reg9 = alloca i32, align 4 + %reg10 = alloca i32, align 4 + %reg11 = alloca i32, align 4 + %reg12 = alloca i32, align 4 + %reg13 = alloca i32, align 4 + %reg14 = alloca i32, align 4 + store volatile i32 0, ptr %reg0, align 4 + store volatile i32 1, ptr %reg1, align 4 + store volatile i32 2, ptr %reg2, align 4 + store volatile i32 3, ptr %reg3, align 4 + store volatile i32 4, ptr %reg4, align 4 + store volatile i32 5, ptr %reg5, align 4 + store volatile i32 6, ptr %reg6, align 4 + store volatile i32 7, ptr %reg7, align 4 + store volatile i32 8, ptr %reg8, align 4 + store volatile i32 9, ptr %reg9, align 4 + store volatile i32 16, ptr %reg10, align 4 + store volatile i32 17, ptr %reg11, align 4 + store volatile i32 18, ptr %reg12, align 4 + store volatile i32 19, ptr %reg13, align 4 + store volatile i32 20, ptr %reg14, align 4 + %0 = load volatile i32, ptr %reg0, align 4 + %1 = load volatile i32, ptr %reg1, align 4 + %2 = load volatile i32, ptr %reg2, align 4 + %3 = load volatile i32, ptr %reg3, align 4 + %4 = load volatile i32, ptr %reg4, align 4 + %5 = load volatile i32, ptr %reg5, align 4 + %6 = load volatile i32, ptr %reg6, align 4 + %7 = load volatile i32, ptr %reg7, align 4 + %8 = load volatile i32, ptr %reg8, align 4 + %9 = load volatile i32, ptr %reg9, align 4 + %10 = load volatile i32, ptr %reg10, align 4 + %11 = load volatile i32, ptr %reg11, align 4 + %12 = load volatile i32, ptr %reg12, align 4 + %13 = load volatile i32, ptr %reg13, align 4 + %14 = load volatile i32, ptr %reg14, align 4 + %15 = call { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } asm "nop", "=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,~{dirflag},~{fpsr},~{flags}"(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7, i32 %8, i32 %9, i32 %10, i32 %11, i32 %12, i32 %13, i32 %14) #1 + %asmresult = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 0 + %asmresult1 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 1 + %asmresult2 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 2 + %asmresult3 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 3 + %asmresult4 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 4 + %asmresult5 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 5 + %asmresult6 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 6 + %asmresult7 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 7 + %asmresult8 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 8 + %asmresult9 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 9 + %asmresult10 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 10 + %asmresult11 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 11 + %asmresult12 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 12 + %asmresult13 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 13 + %asmresult14 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 14 + store volatile i32 %asmresult, ptr %reg0, align 4 + store volatile i32 %asmresult1, ptr %reg1, align 4 + store volatile i32 %asmresult2, ptr %reg2, align 4 + store volatile i32 %asmresult3, ptr %reg3, align 4 + store volatile i32 %asmresult4, ptr %reg4, align 4 + store volatile i32 %asmresult5, ptr %reg5, align 4 + store volatile i32 %asmresult6, ptr %reg6, align 4 + store volatile i32 %asmresult7, ptr %reg7, align 4 + store volatile i32 %asmresult8, ptr %reg8, align 4 + store volatile i32 %asmresult9, ptr %reg9, align 4 + store volatile i32 %asmresult10, ptr %reg10, align 4 + store volatile i32 %asmresult11, ptr %reg11, align 4 + store volatile i32 %asmresult12, ptr %reg12, align 4 + store volatile i32 %asmresult13, ptr %reg13, align 4 + store volatile i32 %asmresult14, ptr %reg14, align 4 + ret i32 0 +} + +define i32 @test_non_leaf_no_reserve() "frame-pointer"="non-leaf-no-reserve" { +; CHECK-LABEL: test_non_leaf_no_reserve: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: pushq %rbp +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: pushq %r15 +; CHECK-NEXT: .cfi_def_cfa_offset 24 +; CHECK-NEXT: pushq %r14 +; CHECK-NEXT: .cfi_def_cfa_offset 32 +; CHECK-NEXT: pushq %r13 +; CHECK-NEXT: .cfi_def_cfa_offset 40 +; CHECK-NEXT: pushq %r12 +; CHECK-NEXT: .cfi_def_cfa_offset 48 +; CHECK-NEXT: pushq %rbx +; CHECK-NEXT: .cfi_def_cfa_offset 56 +; CHECK-NEXT: .cfi_offset %rbx, -56 +; CHECK-NEXT: .cfi_offset %r12, -48 +; CHECK-NEXT: .cfi_offset %r13, -40 +; CHECK-NEXT: .cfi_offset %r14, -32 +; CHECK-NEXT: .cfi_offset %r15, -24 +; CHECK-NEXT: .cfi_offset %rbp, -16 +; CHECK-NEXT: movl $0, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $1, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $2, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $3, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $4, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $5, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $6, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $7, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $8, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $9, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $16, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $17, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $18, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $19, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $20, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %ecx +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %edx +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %esi +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %edi +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r8d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r9d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r10d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r11d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %ebx +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %ebp +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r14d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r15d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r12d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r13d +; CHECK-NEXT: #APP +; CHECK-NEXT: nop +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: movl %eax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %ecx, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %edx, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %esi, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %edi, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r8d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r9d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r10d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r11d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %ebx, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %ebp, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r14d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r15d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r12d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r13d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: popq %rbx +; CHECK-NEXT: .cfi_def_cfa_offset 48 +; CHECK-NEXT: popq %r12 +; CHECK-NEXT: .cfi_def_cfa_offset 40 +; CHECK-NEXT: popq %r13 +; CHECK-NEXT: .cfi_def_cfa_offset 32 +; CHECK-NEXT: popq %r14 +; CHECK-NEXT: .cfi_def_cfa_offset 24 +; CHECK-NEXT: popq %r15 +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: popq %rbp +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq +entry: + %reg0 = alloca i32, align 4 + %reg1 = alloca i32, align 4 + %reg2 = alloca i32, align 4 + %reg3 = alloca i32, align 4 + %reg4 = alloca i32, align 4 + %reg5 = alloca i32, align 4 + %reg6 = alloca i32, align 4 + %reg7 = alloca i32, align 4 + %reg8 = alloca i32, align 4 + %reg9 = alloca i32, align 4 + %reg10 = alloca i32, align 4 + %reg11 = alloca i32, align 4 + %reg12 = alloca i32, align 4 + %reg13 = alloca i32, align 4 + %reg14 = alloca i32, align 4 + store volatile i32 0, ptr %reg0, align 4 + store volatile i32 1, ptr %reg1, align 4 + store volatile i32 2, ptr %reg2, align 4 + store volatile i32 3, ptr %reg3, align 4 + store volatile i32 4, ptr %reg4, align 4 + store volatile i32 5, ptr %reg5, align 4 + store volatile i32 6, ptr %reg6, align 4 + store volatile i32 7, ptr %reg7, align 4 + store volatile i32 8, ptr %reg8, align 4 + store volatile i32 9, ptr %reg9, align 4 + store volatile i32 16, ptr %reg10, align 4 + store volatile i32 17, ptr %reg11, align 4 + store volatile i32 18, ptr %reg12, align 4 + store volatile i32 19, ptr %reg13, align 4 + store volatile i32 20, ptr %reg14, align 4 + %0 = load volatile i32, ptr %reg0, align 4 + %1 = load volatile i32, ptr %reg1, align 4 + %2 = load volatile i32, ptr %reg2, align 4 + %3 = load volatile i32, ptr %reg3, align 4 + %4 = load volatile i32, ptr %reg4, align 4 + %5 = load volatile i32, ptr %reg5, align 4 + %6 = load volatile i32, ptr %reg6, align 4 + %7 = load volatile i32, ptr %reg7, align 4 + %8 = load volatile i32, ptr %reg8, align 4 + %9 = load volatile i32, ptr %reg9, align 4 + %10 = load volatile i32, ptr %reg10, align 4 + %11 = load volatile i32, ptr %reg11, align 4 + %12 = load volatile i32, ptr %reg12, align 4 + %13 = load volatile i32, ptr %reg13, align 4 + %14 = load volatile i32, ptr %reg14, align 4 + %15 = call { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } asm "nop", "=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,~{dirflag},~{fpsr},~{flags}"(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7, i32 %8, i32 %9, i32 %10, i32 %11, i32 %12, i32 %13, i32 %14) #1 + %asmresult = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 0 + %asmresult1 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 1 + %asmresult2 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 2 + %asmresult3 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 3 + %asmresult4 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 4 + %asmresult5 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 5 + %asmresult6 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 6 + %asmresult7 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 7 + %asmresult8 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 8 + %asmresult9 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 9 + %asmresult10 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 10 + %asmresult11 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 11 + %asmresult12 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 12 + %asmresult13 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 13 + %asmresult14 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %15, 14 + store volatile i32 %asmresult, ptr %reg0, align 4 + store volatile i32 %asmresult1, ptr %reg1, align 4 + store volatile i32 %asmresult2, ptr %reg2, align 4 + store volatile i32 %asmresult3, ptr %reg3, align 4 + store volatile i32 %asmresult4, ptr %reg4, align 4 + store volatile i32 %asmresult5, ptr %reg5, align 4 + store volatile i32 %asmresult6, ptr %reg6, align 4 + store volatile i32 %asmresult7, ptr %reg7, align 4 + store volatile i32 %asmresult8, ptr %reg8, align 4 + store volatile i32 %asmresult9, ptr %reg9, align 4 + store volatile i32 %asmresult10, ptr %reg10, align 4 + store volatile i32 %asmresult11, ptr %reg11, align 4 + store volatile i32 %asmresult12, ptr %reg12, align 4 + store volatile i32 %asmresult13, ptr %reg13, align 4 + store volatile i32 %asmresult14, ptr %reg14, align 4 + ret i32 0 +} + +define i32 @test_non_leaf() "frame-pointer"="non-leaf" { +; CHECK-LABEL: test_non_leaf: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: pushq %r15 +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: pushq %r14 +; CHECK-NEXT: .cfi_def_cfa_offset 24 +; CHECK-NEXT: pushq %r13 +; CHECK-NEXT: .cfi_def_cfa_offset 32 +; CHECK-NEXT: pushq %r12 +; CHECK-NEXT: .cfi_def_cfa_offset 40 +; CHECK-NEXT: pushq %rbx +; CHECK-NEXT: .cfi_def_cfa_offset 48 +; CHECK-NEXT: .cfi_offset %rbx, -48 +; CHECK-NEXT: .cfi_offset %r12, -40 +; CHECK-NEXT: .cfi_offset %r13, -32 +; CHECK-NEXT: .cfi_offset %r14, -24 +; CHECK-NEXT: .cfi_offset %r15, -16 +; CHECK-NEXT: movl $0, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $1, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $2, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $3, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $4, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $5, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $6, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $7, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $8, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $9, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $16, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $17, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $18, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $19, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %ecx +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %edx +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %esi +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %edi +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r8d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r9d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r10d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r11d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %ebx +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r14d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r15d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r12d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r13d +; CHECK-NEXT: #APP +; CHECK-NEXT: nop +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: movl %eax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %ecx, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %edx, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %esi, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %edi, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r8d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r9d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r10d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r11d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %ebx, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r14d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r15d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r12d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r13d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: popq %rbx +; CHECK-NEXT: .cfi_def_cfa_offset 40 +; CHECK-NEXT: popq %r12 +; CHECK-NEXT: .cfi_def_cfa_offset 32 +; CHECK-NEXT: popq %r13 +; CHECK-NEXT: .cfi_def_cfa_offset 24 +; CHECK-NEXT: popq %r14 +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: popq %r15 +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq +entry: + %reg0 = alloca i32, align 4 + %reg1 = alloca i32, align 4 + %reg2 = alloca i32, align 4 + %reg3 = alloca i32, align 4 + %reg4 = alloca i32, align 4 + %reg5 = alloca i32, align 4 + %reg6 = alloca i32, align 4 + %reg7 = alloca i32, align 4 + %reg8 = alloca i32, align 4 + %reg9 = alloca i32, align 4 + %reg10 = alloca i32, align 4 + %reg11 = alloca i32, align 4 + %reg12 = alloca i32, align 4 + %reg13 = alloca i32, align 4 + store volatile i32 0, ptr %reg0, align 4 + store volatile i32 1, ptr %reg1, align 4 + store volatile i32 2, ptr %reg2, align 4 + store volatile i32 3, ptr %reg3, align 4 + store volatile i32 4, ptr %reg4, align 4 + store volatile i32 5, ptr %reg5, align 4 + store volatile i32 6, ptr %reg6, align 4 + store volatile i32 7, ptr %reg7, align 4 + store volatile i32 8, ptr %reg8, align 4 + store volatile i32 9, ptr %reg9, align 4 + store volatile i32 16, ptr %reg10, align 4 + store volatile i32 17, ptr %reg11, align 4 + store volatile i32 18, ptr %reg12, align 4 + store volatile i32 19, ptr %reg13, align 4 + %0 = load volatile i32, ptr %reg0, align 4 + %1 = load volatile i32, ptr %reg1, align 4 + %2 = load volatile i32, ptr %reg2, align 4 + %3 = load volatile i32, ptr %reg3, align 4 + %4 = load volatile i32, ptr %reg4, align 4 + %5 = load volatile i32, ptr %reg5, align 4 + %6 = load volatile i32, ptr %reg6, align 4 + %7 = load volatile i32, ptr %reg7, align 4 + %8 = load volatile i32, ptr %reg8, align 4 + %9 = load volatile i32, ptr %reg9, align 4 + %10 = load volatile i32, ptr %reg10, align 4 + %11 = load volatile i32, ptr %reg11, align 4 + %12 = load volatile i32, ptr %reg12, align 4 + %13 = load volatile i32, ptr %reg13, align 4 + %14 = call { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } asm "nop", "=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,0,1,2,3,4,5,6,7,8,9,10,11,12,13,~{dirflag},~{fpsr},~{flags}"(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7, i32 %8, i32 %9, i32 %10, i32 %11, i32 %12, i32 %13) #1 + %asmresult = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 0 + %asmresult1 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 1 + %asmresult2 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 2 + %asmresult3 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 3 + %asmresult4 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 4 + %asmresult5 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 5 + %asmresult6 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 6 + %asmresult7 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 7 + %asmresult8 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 8 + %asmresult9 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 9 + %asmresult10 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 10 + %asmresult11 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 11 + %asmresult12 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 12 + %asmresult13 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 13 + store volatile i32 %asmresult, ptr %reg0, align 4 + store volatile i32 %asmresult1, ptr %reg1, align 4 + store volatile i32 %asmresult2, ptr %reg2, align 4 + store volatile i32 %asmresult3, ptr %reg3, align 4 + store volatile i32 %asmresult4, ptr %reg4, align 4 + store volatile i32 %asmresult5, ptr %reg5, align 4 + store volatile i32 %asmresult6, ptr %reg6, align 4 + store volatile i32 %asmresult7, ptr %reg7, align 4 + store volatile i32 %asmresult8, ptr %reg8, align 4 + store volatile i32 %asmresult9, ptr %reg9, align 4 + store volatile i32 %asmresult10, ptr %reg10, align 4 + store volatile i32 %asmresult11, ptr %reg11, align 4 + store volatile i32 %asmresult12, ptr %reg12, align 4 + store volatile i32 %asmresult13, ptr %reg13, align 4 + ret i32 0 +} + +define i32 @test_reserved() "frame-pointer"="reserved" { +; CHECK-LABEL: test_reserved: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: pushq %r15 +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: pushq %r14 +; CHECK-NEXT: .cfi_def_cfa_offset 24 +; CHECK-NEXT: pushq %r13 +; CHECK-NEXT: .cfi_def_cfa_offset 32 +; CHECK-NEXT: pushq %r12 +; CHECK-NEXT: .cfi_def_cfa_offset 40 +; CHECK-NEXT: pushq %rbx +; CHECK-NEXT: .cfi_def_cfa_offset 48 +; CHECK-NEXT: .cfi_offset %rbx, -48 +; CHECK-NEXT: .cfi_offset %r12, -40 +; CHECK-NEXT: .cfi_offset %r13, -32 +; CHECK-NEXT: .cfi_offset %r14, -24 +; CHECK-NEXT: .cfi_offset %r15, -16 +; CHECK-NEXT: movl $0, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $1, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $2, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $3, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $4, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $5, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $6, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $7, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $8, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $9, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $16, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $17, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $18, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl $19, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %ecx +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %edx +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %esi +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %edi +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r8d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r9d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r10d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r11d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %ebx +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r14d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r15d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r12d +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %r13d +; CHECK-NEXT: #APP +; CHECK-NEXT: nop +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: movl %eax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %ecx, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %edx, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %esi, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %edi, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r8d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r9d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r10d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r11d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %ebx, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r14d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r15d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r12d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movl %r13d, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: popq %rbx +; CHECK-NEXT: .cfi_def_cfa_offset 40 +; CHECK-NEXT: popq %r12 +; CHECK-NEXT: .cfi_def_cfa_offset 32 +; CHECK-NEXT: popq %r13 +; CHECK-NEXT: .cfi_def_cfa_offset 24 +; CHECK-NEXT: popq %r14 +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: popq %r15 +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq +entry: + %reg0 = alloca i32, align 4 + %reg1 = alloca i32, align 4 + %reg2 = alloca i32, align 4 + %reg3 = alloca i32, align 4 + %reg4 = alloca i32, align 4 + %reg5 = alloca i32, align 4 + %reg6 = alloca i32, align 4 + %reg7 = alloca i32, align 4 + %reg8 = alloca i32, align 4 + %reg9 = alloca i32, align 4 + %reg10 = alloca i32, align 4 + %reg11 = alloca i32, align 4 + %reg12 = alloca i32, align 4 + %reg13 = alloca i32, align 4 + store volatile i32 0, ptr %reg0, align 4 + store volatile i32 1, ptr %reg1, align 4 + store volatile i32 2, ptr %reg2, align 4 + store volatile i32 3, ptr %reg3, align 4 + store volatile i32 4, ptr %reg4, align 4 + store volatile i32 5, ptr %reg5, align 4 + store volatile i32 6, ptr %reg6, align 4 + store volatile i32 7, ptr %reg7, align 4 + store volatile i32 8, ptr %reg8, align 4 + store volatile i32 9, ptr %reg9, align 4 + store volatile i32 16, ptr %reg10, align 4 + store volatile i32 17, ptr %reg11, align 4 + store volatile i32 18, ptr %reg12, align 4 + store volatile i32 19, ptr %reg13, align 4 + %0 = load volatile i32, ptr %reg0, align 4 + %1 = load volatile i32, ptr %reg1, align 4 + %2 = load volatile i32, ptr %reg2, align 4 + %3 = load volatile i32, ptr %reg3, align 4 + %4 = load volatile i32, ptr %reg4, align 4 + %5 = load volatile i32, ptr %reg5, align 4 + %6 = load volatile i32, ptr %reg6, align 4 + %7 = load volatile i32, ptr %reg7, align 4 + %8 = load volatile i32, ptr %reg8, align 4 + %9 = load volatile i32, ptr %reg9, align 4 + %10 = load volatile i32, ptr %reg10, align 4 + %11 = load volatile i32, ptr %reg11, align 4 + %12 = load volatile i32, ptr %reg12, align 4 + %13 = load volatile i32, ptr %reg13, align 4 + %14 = call { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } asm "nop", "=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,0,1,2,3,4,5,6,7,8,9,10,11,12,13,~{dirflag},~{fpsr},~{flags}"(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7, i32 %8, i32 %9, i32 %10, i32 %11, i32 %12, i32 %13) #1 + %asmresult = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 0 + %asmresult1 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 1 + %asmresult2 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 2 + %asmresult3 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 3 + %asmresult4 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 4 + %asmresult5 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 5 + %asmresult6 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 6 + %asmresult7 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 7 + %asmresult8 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 8 + %asmresult9 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 9 + %asmresult10 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 10 + %asmresult11 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 11 + %asmresult12 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 12 + %asmresult13 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 13 + store volatile i32 %asmresult, ptr %reg0, align 4 + store volatile i32 %asmresult1, ptr %reg1, align 4 + store volatile i32 %asmresult2, ptr %reg2, align 4 + store volatile i32 %asmresult3, ptr %reg3, align 4 + store volatile i32 %asmresult4, ptr %reg4, align 4 + store volatile i32 %asmresult5, ptr %reg5, align 4 + store volatile i32 %asmresult6, ptr %reg6, align 4 + store volatile i32 %asmresult7, ptr %reg7, align 4 + store volatile i32 %asmresult8, ptr %reg8, align 4 + store volatile i32 %asmresult9, ptr %reg9, align 4 + store volatile i32 %asmresult10, ptr %reg10, align 4 + store volatile i32 %asmresult11, ptr %reg11, align 4 + store volatile i32 %asmresult12, ptr %reg12, align 4 + store volatile i32 %asmresult13, ptr %reg13, align 4 + ret i32 0 +} + +define i32 @test_all() "frame-pointer"="all" { +; CHECK-LABEL: test_all: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: pushq %rbp +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset %rbp, -16 +; CHECK-NEXT: movq %rsp, %rbp +; CHECK-NEXT: .cfi_def_cfa_register %rbp +; CHECK-NEXT: pushq %r15 +; CHECK-NEXT: pushq %r14 +; CHECK-NEXT: pushq %r13 +; CHECK-NEXT: pushq %r12 +; CHECK-NEXT: pushq %rbx +; CHECK-NEXT: .cfi_offset %rbx, -56 +; CHECK-NEXT: .cfi_offset %r12, -48 +; CHECK-NEXT: .cfi_offset %r13, -40 +; CHECK-NEXT: .cfi_offset %r14, -32 +; CHECK-NEXT: .cfi_offset %r15, -24 +; CHECK-NEXT: movl $0, -96(%rbp) +; CHECK-NEXT: movl $1, -92(%rbp) +; CHECK-NEXT: movl $2, -88(%rbp) +; CHECK-NEXT: movl $3, -84(%rbp) +; CHECK-NEXT: movl $4, -80(%rbp) +; CHECK-NEXT: movl $5, -76(%rbp) +; CHECK-NEXT: movl $6, -72(%rbp) +; CHECK-NEXT: movl $7, -68(%rbp) +; CHECK-NEXT: movl $8, -64(%rbp) +; CHECK-NEXT: movl $9, -60(%rbp) +; CHECK-NEXT: movl $16, -56(%rbp) +; CHECK-NEXT: movl $17, -52(%rbp) +; CHECK-NEXT: movl $18, -48(%rbp) +; CHECK-NEXT: movl $19, -44(%rbp) +; CHECK-NEXT: movl -96(%rbp), %eax +; CHECK-NEXT: movl -92(%rbp), %ecx +; CHECK-NEXT: movl -88(%rbp), %edx +; CHECK-NEXT: movl -84(%rbp), %esi +; CHECK-NEXT: movl -80(%rbp), %edi +; CHECK-NEXT: movl -76(%rbp), %r8d +; CHECK-NEXT: movl -72(%rbp), %r9d +; CHECK-NEXT: movl -68(%rbp), %r10d +; CHECK-NEXT: movl -64(%rbp), %r11d +; CHECK-NEXT: movl -60(%rbp), %ebx +; CHECK-NEXT: movl -56(%rbp), %r14d +; CHECK-NEXT: movl -52(%rbp), %r15d +; CHECK-NEXT: movl -48(%rbp), %r12d +; CHECK-NEXT: movl -44(%rbp), %r13d +; CHECK-NEXT: #APP +; CHECK-NEXT: nop +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: movl %eax, -96(%rbp) +; CHECK-NEXT: movl %ecx, -92(%rbp) +; CHECK-NEXT: movl %edx, -88(%rbp) +; CHECK-NEXT: movl %esi, -84(%rbp) +; CHECK-NEXT: movl %edi, -80(%rbp) +; CHECK-NEXT: movl %r8d, -76(%rbp) +; CHECK-NEXT: movl %r9d, -72(%rbp) +; CHECK-NEXT: movl %r10d, -68(%rbp) +; CHECK-NEXT: movl %r11d, -64(%rbp) +; CHECK-NEXT: movl %ebx, -60(%rbp) +; CHECK-NEXT: movl %r14d, -56(%rbp) +; CHECK-NEXT: movl %r15d, -52(%rbp) +; CHECK-NEXT: movl %r12d, -48(%rbp) +; CHECK-NEXT: movl %r13d, -44(%rbp) +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: popq %rbx +; CHECK-NEXT: popq %r12 +; CHECK-NEXT: popq %r13 +; CHECK-NEXT: popq %r14 +; CHECK-NEXT: popq %r15 +; CHECK-NEXT: popq %rbp +; CHECK-NEXT: .cfi_def_cfa %rsp, 8 +; CHECK-NEXT: retq +entry: + %reg0 = alloca i32, align 4 + %reg1 = alloca i32, align 4 + %reg2 = alloca i32, align 4 + %reg3 = alloca i32, align 4 + %reg4 = alloca i32, align 4 + %reg5 = alloca i32, align 4 + %reg6 = alloca i32, align 4 + %reg7 = alloca i32, align 4 + %reg8 = alloca i32, align 4 + %reg9 = alloca i32, align 4 + %reg10 = alloca i32, align 4 + %reg11 = alloca i32, align 4 + %reg12 = alloca i32, align 4 + %reg13 = alloca i32, align 4 + store volatile i32 0, ptr %reg0, align 4 + store volatile i32 1, ptr %reg1, align 4 + store volatile i32 2, ptr %reg2, align 4 + store volatile i32 3, ptr %reg3, align 4 + store volatile i32 4, ptr %reg4, align 4 + store volatile i32 5, ptr %reg5, align 4 + store volatile i32 6, ptr %reg6, align 4 + store volatile i32 7, ptr %reg7, align 4 + store volatile i32 8, ptr %reg8, align 4 + store volatile i32 9, ptr %reg9, align 4 + store volatile i32 16, ptr %reg10, align 4 + store volatile i32 17, ptr %reg11, align 4 + store volatile i32 18, ptr %reg12, align 4 + store volatile i32 19, ptr %reg13, align 4 + %0 = load volatile i32, ptr %reg0, align 4 + %1 = load volatile i32, ptr %reg1, align 4 + %2 = load volatile i32, ptr %reg2, align 4 + %3 = load volatile i32, ptr %reg3, align 4 + %4 = load volatile i32, ptr %reg4, align 4 + %5 = load volatile i32, ptr %reg5, align 4 + %6 = load volatile i32, ptr %reg6, align 4 + %7 = load volatile i32, ptr %reg7, align 4 + %8 = load volatile i32, ptr %reg8, align 4 + %9 = load volatile i32, ptr %reg9, align 4 + %10 = load volatile i32, ptr %reg10, align 4 + %11 = load volatile i32, ptr %reg11, align 4 + %12 = load volatile i32, ptr %reg12, align 4 + %13 = load volatile i32, ptr %reg13, align 4 + %14 = call { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } asm "nop", "=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,0,1,2,3,4,5,6,7,8,9,10,11,12,13,~{dirflag},~{fpsr},~{flags}"(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7, i32 %8, i32 %9, i32 %10, i32 %11, i32 %12, i32 %13) #1 + %asmresult = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 0 + %asmresult1 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 1 + %asmresult2 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 2 + %asmresult3 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 3 + %asmresult4 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 4 + %asmresult5 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 5 + %asmresult6 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 6 + %asmresult7 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 7 + %asmresult8 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 8 + %asmresult9 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 9 + %asmresult10 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 10 + %asmresult11 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 11 + %asmresult12 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 12 + %asmresult13 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %14, 13 + store volatile i32 %asmresult, ptr %reg0, align 4 + store volatile i32 %asmresult1, ptr %reg1, align 4 + store volatile i32 %asmresult2, ptr %reg2, align 4 + store volatile i32 %asmresult3, ptr %reg3, align 4 + store volatile i32 %asmresult4, ptr %reg4, align 4 + store volatile i32 %asmresult5, ptr %reg5, align 4 + store volatile i32 %asmresult6, ptr %reg6, align 4 + store volatile i32 %asmresult7, ptr %reg7, align 4 + store volatile i32 %asmresult8, ptr %reg8, align 4 + store volatile i32 %asmresult9, ptr %reg9, align 4 + store volatile i32 %asmresult10, ptr %reg10, align 4 + store volatile i32 %asmresult11, ptr %reg11, align 4 + store volatile i32 %asmresult12, ptr %reg12, align 4 + store volatile i32 %asmresult13, ptr %reg13, align 4 + ret i32 0 +} >From 20fe190f084347b20969f00021b9577988bd764b Mon Sep 17 00:00:00 2001 From: Nabeel Omer <[email protected]> Date: Thu, 16 Oct 2025 14:21:20 +0100 Subject: [PATCH 02/10] Fix formatting --- clang/include/clang/Basic/CodeGenOptions.h | 12 +++++--- clang/lib/Driver/ToolChains/CommonArgs.cpp | 36 ++++++++++++---------- llvm/include/llvm/Support/CodeGen.h | 8 ++++- llvm/lib/CodeGen/CommandFlags.cpp | 3 +- llvm/lib/IR/Verifier.cpp | 3 +- 5 files changed, 37 insertions(+), 25 deletions(-) diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index 3dd0140ea0d9f..0eb48dc377ae8 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -155,11 +155,13 @@ class CodeGenOptions : public CodeGenOptionsBase { std::string BinutilsVersion; enum class FramePointerKind { - NonLeafNoReserve, // Keep non-leaf frame pointers, allow the FP to be used as a GPR in leaf functions. - None, // Omit all frame pointers. - Reserved, // Maintain valid frame pointer chain. - NonLeaf, // Keep non-leaf frame pointers, don't allow the FP to be used as a GPR in leaf functions. - All, // Keep all frame pointers. + NonLeafNoReserve, // Keep non-leaf frame pointers, allow the FP to be used + // as a GPR in leaf functions. + None, // Omit all frame pointers. + Reserved, // Maintain valid frame pointer chain. + NonLeaf, // Keep non-leaf frame pointers, don't allow the FP to be used as a + // GPR in leaf functions. + All, // Keep all frame pointers. }; static StringRef getFramePointerKindName(FramePointerKind Kind) { diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 55a57acebfd9a..4172f7950a545 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -226,7 +226,8 @@ getFramePointerKind(const llvm::opt::ArgList &Args, // * Should a frame record be created for non-leaf functions? // * Should a frame record be created for leaf functions? // * Is the frame pointer register reserved in non-leaf functions? - // i.e. must it always point to either a new, valid frame record or be un-modified? + // i.e. must it always point to either a new, valid frame record or be + // un-modified? // * Is the frame pointer register reserved in leaf functions? // // Not all combinations of these are valid: @@ -236,22 +237,23 @@ getFramePointerKind(const llvm::opt::ArgList &Args, // // | Non-leaf | Leaf | Reserved In Non-Leaf | Reserved In Leaf | // |----------|------|-----------------------|------------------| - // | N | N | N | N | FramePointerKind::None - // | N | N | N | Y | Invalid - // | N | N | Y | N | Invalid - // | N | N | Y | Y | FramePointerKind::Reserved - // | N | Y | N | N | Invalid - // | N | Y | N | Y | Invalid - // | N | Y | Y | N | Invalid - // | N | Y | Y | Y | Invalid - // | Y | N | N | N | Invalid - // | Y | N | N | Y | Invalid - // | Y | N | Y | N | FramePointerKind::NonLeafNoReserve - // | Y | N | Y | Y | FramePointerKind::NonLeaf - // | Y | Y | N | N | Invalid - // | Y | Y | N | Y | Invalid - // | Y | Y | Y | N | Invalid - // | Y | Y | Y | Y | FramePointerKind::All + // | N | N | N | N | + // FramePointerKind::None | N | N | N | Y | + // Invalid | N | N | Y | N | + // Invalid | N | N | Y | Y | + // FramePointerKind::Reserved | N | Y | N | N | + // Invalid | N | Y | N | Y | + // Invalid | N | Y | Y | N | + // Invalid | N | Y | Y | Y | + // Invalid | Y | N | N | N | + // Invalid | Y | N | N | Y | + // Invalid | Y | N | Y | N | + // FramePointerKind::NonLeafNoReserve | Y | N | Y | Y | + // FramePointerKind::NonLeaf | Y | Y | N | N | + // Invalid | Y | Y | N | Y | + // Invalid | Y | Y | Y | N | + // Invalid | Y | Y | Y | Y | + // FramePointerKind::All // // The FramePointerKind::Reserved case is currently only reachable for Arm, // which has the -mframe-chain= option which can (in combination with diff --git a/llvm/include/llvm/Support/CodeGen.h b/llvm/include/llvm/Support/CodeGen.h index 6675f131bc406..15df265556339 100644 --- a/llvm/include/llvm/Support/CodeGen.h +++ b/llvm/include/llvm/Support/CodeGen.h @@ -115,7 +115,13 @@ namespace llvm { }; // Specify what functions should keep the frame pointer. - enum class FramePointerKind { None, NonLeaf, All, Reserved, NonLeafNoReserve }; + enum class FramePointerKind { + None, + NonLeaf, + All, + Reserved, + NonLeafNoReserve + }; // Specify what type of zeroing callee-used registers. namespace ZeroCallUsedRegs { diff --git a/llvm/lib/CodeGen/CommandFlags.cpp b/llvm/lib/CodeGen/CommandFlags.cpp index e3089dd1eb07b..6169d8e00dc33 100644 --- a/llvm/lib/CodeGen/CommandFlags.cpp +++ b/llvm/lib/CodeGen/CommandFlags.cpp @@ -211,7 +211,8 @@ codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() { clEnumValN(FramePointerKind::All, "all", "Disable frame pointer elimination"), clEnumValN(FramePointerKind::NonLeaf, "non-leaf", - "Disable frame pointer elimination for non-leaf frame but reserve the register in leaf functions"), + "Disable frame pointer elimination for non-leaf frame but " + "reserve the register in leaf functions"), clEnumValN(FramePointerKind::NonLeafNoReserve, "non-leaf-no-reserve", "Disable frame pointer elimination for non-leaf frame"), clEnumValN(FramePointerKind::Reserved, "reserved", diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 4a5e0b6bdae97..7cbc2c5f95a6f 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -2484,7 +2484,8 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs, if (Attribute FPAttr = Attrs.getFnAttr("frame-pointer"); FPAttr.isValid()) { StringRef FP = FPAttr.getValueAsString(); - if (FP != "all" && FP != "non-leaf" && FP != "none" && FP != "reserved" && FP != "non-leaf-no-reserve") + if (FP != "all" && FP != "non-leaf" && FP != "none" && FP != "reserved" && + FP != "non-leaf-no-reserve") CheckFailed("invalid value for 'frame-pointer' attribute: " + FP, V); } >From c6fde3db39e335a9f023c950ffd8fed36601524f Mon Sep 17 00:00:00 2001 From: Nabeel Omer <[email protected]> Date: Mon, 20 Oct 2025 16:47:57 +0100 Subject: [PATCH 03/10] Add `-mreserve-frame-pointer-reg` --- clang/include/clang/Driver/Options.td | 3 + clang/lib/Driver/ToolChains/CommonArgs.cpp | 46 ++++++++------ clang/test/Driver/frame-pointer-elim.c | 72 +++++++++++++--------- 3 files changed, 72 insertions(+), 49 deletions(-) diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 5f7ef34a36be6..9084aadefaaa4 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -5657,6 +5657,9 @@ def mno_warn_nonportable_cfstrings : Flag<["-"], "mno-warn-nonportable-cfstrings def mno_omit_leaf_frame_pointer : Flag<["-"], "mno-omit-leaf-frame-pointer">, Group<m_Group>; def momit_leaf_frame_pointer : Flag<["-"], "momit-leaf-frame-pointer">, Group<m_Group>, HelpText<"Omit frame pointer setup for leaf functions">; +def mno_reserve_frame_pointer_reg : Flag<["-"], "mno-reserve-frame-pointer-reg">, Group<m_Group>; +def mreserve_frame_pointer_reg : Flag<["-"], "mreserve-frame-pointer-reg">, Group<m_Group>, + HelpText<"Reserve the frame pointer register even if the function doesn't have a frame">; def moslib_EQ : Joined<["-"], "moslib=">, Group<m_Group>; def mpascal_strings : Flag<["-"], "mpascal-strings">, Alias<fpascal_strings>; def mred_zone : Flag<["-"], "mred-zone">, Group<m_Group>; diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 4172f7950a545..aa3095d310a56 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -235,25 +235,26 @@ getFramePointerKind(const llvm::opt::ArgList &Args, // * It's not useful to have frame records without reserving the frame // pointer. // - // | Non-leaf | Leaf | Reserved In Non-Leaf | Reserved In Leaf | - // |----------|------|-----------------------|------------------| - // | N | N | N | N | - // FramePointerKind::None | N | N | N | Y | - // Invalid | N | N | Y | N | - // Invalid | N | N | Y | Y | - // FramePointerKind::Reserved | N | Y | N | N | - // Invalid | N | Y | N | Y | - // Invalid | N | Y | Y | N | - // Invalid | N | Y | Y | Y | - // Invalid | Y | N | N | N | - // Invalid | Y | N | N | Y | - // Invalid | Y | N | Y | N | - // FramePointerKind::NonLeafNoReserve | Y | N | Y | Y | - // FramePointerKind::NonLeaf | Y | Y | N | N | - // Invalid | Y | Y | N | Y | - // Invalid | Y | Y | Y | N | - // Invalid | Y | Y | Y | Y | - // FramePointerKind::All + // | Frame Setup | Reg Reserved | + // |-----------------|-----------------| + // | Non-leaf | Leaf | Non-Leaf | Leaf | + // |----------|------|----------|------| + // | N | N | N | N | FramePointerKind::None + // | N | N | N | Y | Invalid + // | N | N | Y | N | Invalid + // | N | N | Y | Y | FramePointerKind::Reserved + // | N | Y | N | N | Invalid + // | N | Y | N | Y | Invalid + // | N | Y | Y | N | Invalid + // | N | Y | Y | Y | Invalid + // | Y | N | N | N | Invalid + // | Y | N | N | Y | Invalid + // | Y | N | Y | N | FramePointerKind::NonLeafNoReserve + // | Y | N | Y | Y | FramePointerKind::NonLeaf + // | Y | Y | N | N | Invalid + // | Y | Y | N | Y | Invalid + // | Y | Y | Y | N | Invalid + // | Y | Y | Y | Y | FramePointerKind::All // // The FramePointerKind::Reserved case is currently only reachable for Arm, // which has the -mframe-chain= option which can (in combination with @@ -273,7 +274,12 @@ getFramePointerKind(const llvm::opt::ArgList &Args, clang::driver::options::OPT_mno_omit_leaf_frame_pointer, clang::driver::options::OPT_momit_leaf_frame_pointer, DefaultLeafFP); - bool FPRegReserved = mustMaintainValidFrameChain(Args, Triple); + bool FPRegReserved = + Args.hasFlag(clang::driver::options::OPT_mreserve_frame_pointer_reg, + clang::driver::options::OPT_mno_reserve_frame_pointer_reg, + false); + + FPRegReserved |= mustMaintainValidFrameChain(Args, Triple); if (EnableFP) { if (EnableLeafFP) diff --git a/clang/test/Driver/frame-pointer-elim.c b/clang/test/Driver/frame-pointer-elim.c index 9b0e6fa15b0d4..d5e093a58599c 100644 --- a/clang/test/Driver/frame-pointer-elim.c +++ b/clang/test/Driver/frame-pointer-elim.c @@ -1,7 +1,9 @@ // KEEP-ALL-NOT: warning: argument unused // KEEP-ALL: "-mframe-pointer=all" // KEEP-NON-LEAF-NOT: warning: argument unused -// KEEP-NON-LEAF: "-mframe-pointer=non-leaf-no-reserve" +// KEEP-NON-LEAF: "-mframe-pointer=non-leaf" +// KEEP-NON-LEAF-NO-RESERVE-NOT: warning: argument unused +// KEEP-NON-LEAF-NO-RESERVE: "-mframe-pointer=non-leaf-no-reserve" // KEEP-NONE-NOT: warning: argument unused // KEEP-NONE: "-mframe-pointer=none" // KEEP-RESERVED-NOT: warning: argument unused @@ -24,19 +26,27 @@ // -momit-leaf-frame-pointer omits leaf frame pointer. // -fno-omit-frame-pointer loses out to -momit-leaf-frame-pointer. // RUN: %clang -### --target=i386 -S -momit-leaf-frame-pointer %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=i386-linux -S -O1 -fno-omit-frame-pointer -momit-leaf-frame-pointer %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=i386-linux -S -O1 -momit-leaf-frame-pointer %s 2>&1 | \ // RUN: FileCheck --check-prefix=KEEP-NONE %s +// -momit-leaf-frame-pointer -mreserve-frame-pointer-reg results in the frame pointer reg being reserved +// RUN: %clang -### --target=i386 -S -momit-leaf-frame-pointer -mreserve-frame-pointer-reg %s 2>&1 | \ +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s + +// -fomit-frame-pointer -mreserve-frame-pointer-reg results in the frame pointer reg being reserved +// RUN: %clang -### --target=i386 -S -fomit-frame-pointer -mreserve-frame-pointer-reg %s 2>&1 | \ +// RUN: FileCheck --check-prefix=KEEP-RESERVED %s + // fno-omit-frame-pointer -momit-leaf-frame-pointer can be overwritten by // fomit-frame-pointer later on the command without warning // RUN: %clang -### --target=i386-linux -S -O1 -fno-omit-frame-pointer -momit-leaf-frame-pointer -fomit-frame-pointer %s 2>&1 | \ // RUN: FileCheck --check-prefix=KEEP-NONE %s // RUN: %clang -### --target=i386-linux -S -O1 -fno-omit-frame-pointer -momit-leaf-frame-pointer %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // Explicit or default -fomit-frame-pointer wins over -mno-omit-leaf-frame-pointer. // RUN: %clang -### --target=i386 -S %s -fomit-frame-pointer -mno-omit-leaf-frame-pointer 2>&1 | \ // RUN: FileCheck --check-prefix=KEEP-NONE %s @@ -68,7 +78,7 @@ // RUN: FileCheck --check-prefix=KEEP-NONE %s // RUN: %clang -### --target=i386-darwin -S -momit-leaf-frame-pointer %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### -target armv7s-apple-ios -fomit-frame-pointer %s 2>&1 | \ // RUN: FileCheck --check-prefix=WARN-OMIT-7S %s @@ -88,25 +98,25 @@ // On AArch64, PS4, PS5, and VE, default to omitting the frame pointer on leaf // functions // RUN: %clang -### --target=aarch64 -S %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=x86_64-scei-ps4 -S %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=x86_64-scei-ps4 -S -O2 %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=x86_64-sie-ps5 -S %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=x86_64-sie-ps5 -S -O2 %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### -target aarch64-apple-darwin -arch arm64_32 -S %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=ve-unknown-linux-gnu -S %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=aarch64-linux-android -S %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=aarch64-linux-android -S -O2 %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=aarch64-linux-android -S -Os %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=powerpc64 -S %s 2>&1 | \ // RUN: FileCheck --check-prefix=KEEP-ALL %s @@ -161,9 +171,9 @@ // RUN: %clang -### --target=armv7a-linux-androideabi- -mthumb -mbig-endian -O1 -S %s 2>&1 | \ // RUN: FileCheck --check-prefix=KEEP-ALL %s // RUN: %clang -### --target=riscv64-linux-android -O1 -S %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=riscv64-linux-android -mbig-endian -O1 -S %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // On ARM backend bare metal targets, frame pointer is omitted // RUN: %clang -### --target=arm-arm-none-eabi -S %s 2>&1 | \ @@ -191,21 +201,21 @@ // Check that for Apple bare metal targets, we're keeping frame pointers by default // RUN: %clang -### --target=armv6m-apple-none-macho -S %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=armv6m-apple-none-macho -S -fno-omit-frame-pointer %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=arm-apple-none-macho -S %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=arm-apple-none-macho -S -fno-omit-frame-pointer %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=armv6m-apple-none-macho -S -O1 %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=armv6m-apple-none-macho -S -O1 -fno-omit-frame-pointer %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=arm-apple-none-macho -S -O1 %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=arm-apple-none-macho -S -O1 -fno-omit-frame-pointer %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang --target=armv7-apple-macho -### -S %s 2>&1 \ // RUN: -fomit-frame-pointer \ @@ -221,17 +231,21 @@ // AArch64 bare metal targets behave like hosted targets // RUN: %clang -### --target=aarch64-none-elf -S %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=aarch64-none-elf -S -O1 %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=aarch64-none-elf -S -fno-omit-frame-pointer %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // RUN: %clang -### --target=aarch64-none-elf -S -O1 -fno-omit-frame-pointer %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=KEEP-NON-LEAF-NO-RESERVE %s // AArch64 Windows requires that the frame pointer be reserved // RUN: %clang -### --target=aarch64-pc-windows-msvc -S -fomit-frame-pointer %s 2>&1 | \ // RUN: FileCheck --check-prefix=KEEP-RESERVED %s +// AArch64 Windows requires that the frame pointer be reserved +// RUN: %clang -### --target=aarch64-pc-windows-msvc -S -fomit-frame-pointer -mno-reserve-frame-pointer-reg %s 2>&1 | \ +// RUN: FileCheck --check-prefix=KEEP-RESERVED %s + void f0() {} void f1() { f0(); } >From 084c704f857caa72f1348d5645b98586a5e9568c Mon Sep 17 00:00:00 2001 From: Nabeel Omer <[email protected]> Date: Mon, 20 Oct 2025 16:54:42 +0100 Subject: [PATCH 04/10] Fix formatting --- clang/lib/Driver/ToolChains/CommonArgs.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index aa3095d310a56..e75edfa803526 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -274,11 +274,10 @@ getFramePointerKind(const llvm::opt::ArgList &Args, clang::driver::options::OPT_mno_omit_leaf_frame_pointer, clang::driver::options::OPT_momit_leaf_frame_pointer, DefaultLeafFP); - bool FPRegReserved = - Args.hasFlag(clang::driver::options::OPT_mreserve_frame_pointer_reg, - clang::driver::options::OPT_mno_reserve_frame_pointer_reg, - false); - + bool FPRegReserved = Args.hasFlag( + clang::driver::options::OPT_mreserve_frame_pointer_reg, + clang::driver::options::OPT_mno_reserve_frame_pointer_reg, false); + FPRegReserved |= mustMaintainValidFrameChain(Args, Triple); if (EnableFP) { >From ff4b02d305aa4394033d8d42974d7adec1326634 Mon Sep 17 00:00:00 2001 From: Nabeel Omer <[email protected]> Date: Fri, 24 Oct 2025 16:43:27 +0100 Subject: [PATCH 05/10] Address review comments --- clang/lib/Driver/ToolChains/CommonArgs.cpp | 5 ++--- clang/test/Driver/frame-pointer-elim.c | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index e75edfa803526..e6f180bc10464 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -276,9 +276,8 @@ getFramePointerKind(const llvm::opt::ArgList &Args, bool FPRegReserved = Args.hasFlag( clang::driver::options::OPT_mreserve_frame_pointer_reg, - clang::driver::options::OPT_mno_reserve_frame_pointer_reg, false); - - FPRegReserved |= mustMaintainValidFrameChain(Args, Triple); + clang::driver::options::OPT_mno_reserve_frame_pointer_reg, + mustMaintainValidFrameChain(Args, Triple)); if (EnableFP) { if (EnableLeafFP) diff --git a/clang/test/Driver/frame-pointer-elim.c b/clang/test/Driver/frame-pointer-elim.c index d5e093a58599c..054d643781d20 100644 --- a/clang/test/Driver/frame-pointer-elim.c +++ b/clang/test/Driver/frame-pointer-elim.c @@ -244,6 +244,7 @@ // RUN: FileCheck --check-prefix=KEEP-RESERVED %s // AArch64 Windows requires that the frame pointer be reserved +// But -mno-reserve-frame-pointer-reg should override the target platform default // RUN: %clang -### --target=aarch64-pc-windows-msvc -S -fomit-frame-pointer -mno-reserve-frame-pointer-reg %s 2>&1 | \ // RUN: FileCheck --check-prefix=KEEP-RESERVED %s >From edd81c63326cc9efce2f62b0eb77f3a64a49bfd8 Mon Sep 17 00:00:00 2001 From: Nabeel Omer <[email protected]> Date: Fri, 24 Oct 2025 17:28:21 +0100 Subject: [PATCH 06/10] Fix formatting --- clang/lib/Driver/ToolChains/CommonArgs.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index e6f180bc10464..a9b24844edc9b 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -274,10 +274,10 @@ getFramePointerKind(const llvm::opt::ArgList &Args, clang::driver::options::OPT_mno_omit_leaf_frame_pointer, clang::driver::options::OPT_momit_leaf_frame_pointer, DefaultLeafFP); - bool FPRegReserved = Args.hasFlag( - clang::driver::options::OPT_mreserve_frame_pointer_reg, - clang::driver::options::OPT_mno_reserve_frame_pointer_reg, - mustMaintainValidFrameChain(Args, Triple)); + bool FPRegReserved = + Args.hasFlag(clang::driver::options::OPT_mreserve_frame_pointer_reg, + clang::driver::options::OPT_mno_reserve_frame_pointer_reg, + mustMaintainValidFrameChain(Args, Triple)); if (EnableFP) { if (EnableLeafFP) >From abe2eb444614f456d93fbdb7321581fe3a471ba4 Mon Sep 17 00:00:00 2001 From: Nabeel Omer <[email protected]> Date: Mon, 27 Oct 2025 09:48:55 +0000 Subject: [PATCH 07/10] Fix test --- clang/test/Driver/frame-pointer-elim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Driver/frame-pointer-elim.c b/clang/test/Driver/frame-pointer-elim.c index 054d643781d20..c7990ced88125 100644 --- a/clang/test/Driver/frame-pointer-elim.c +++ b/clang/test/Driver/frame-pointer-elim.c @@ -243,7 +243,7 @@ // RUN: %clang -### --target=aarch64-pc-windows-msvc -S -fomit-frame-pointer %s 2>&1 | \ // RUN: FileCheck --check-prefix=KEEP-RESERVED %s -// AArch64 Windows requires that the frame pointer be reserved +// -mno-reserve-frame-pointer-reg overrides platform defaults // But -mno-reserve-frame-pointer-reg should override the target platform default // RUN: %clang -### --target=aarch64-pc-windows-msvc -S -fomit-frame-pointer -mno-reserve-frame-pointer-reg %s 2>&1 | \ // RUN: FileCheck --check-prefix=KEEP-RESERVED %s >From 2911c4516e86fdc22472e5a78fe9965a2481ead3 Mon Sep 17 00:00:00 2001 From: Nabeel Omer <[email protected]> Date: Tue, 28 Oct 2025 13:58:48 +0000 Subject: [PATCH 08/10] Fix MLIR --- mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td index e7b44fd94b26d..e2edab44153ca 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td @@ -758,13 +758,16 @@ def FramePointerKindAll : LLVM_EnumAttrCase<"All", "all", "All", 2>; def FramePointerKindReserved : LLVM_EnumAttrCase<"Reserved", "reserved", "Reserved", 3>; +def FramePointerKindNonLeafNoReserve + : LLVM_EnumAttrCase<"NonLeafNoReserve", "non-leaf-no-reserve", "NonLeafNoReserve", 4>; def FramePointerKindEnum : LLVM_EnumAttr< "FramePointerKind", "::llvm::FramePointerKind", "LLVM FramePointerKind", [FramePointerKindNone, FramePointerKindNonLeaf, - FramePointerKindAll, FramePointerKindReserved]> { + FramePointerKindAll, FramePointerKindReserved, + FramePointerKindNonLeafNoReserve]> { let cppNamespace = "::mlir::LLVM::framePointerKind"; } >From 27e7e884298fbdb04a05abd62c86409e77340db2 Mon Sep 17 00:00:00 2001 From: Nabeel Omer <[email protected]> Date: Wed, 29 Oct 2025 17:26:01 +0000 Subject: [PATCH 09/10] Fix flang tests --- clang/test/Driver/frame-pointer-elim.c | 2 +- flang/include/flang/Frontend/CodeGenOptions.def | 2 +- flang/lib/Frontend/CompilerInvocation.cpp | 1 + flang/test/Driver/frame-pointer-forwarding.f90 | 4 ++-- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/clang/test/Driver/frame-pointer-elim.c b/clang/test/Driver/frame-pointer-elim.c index c7990ced88125..e68fbf529643e 100644 --- a/clang/test/Driver/frame-pointer-elim.c +++ b/clang/test/Driver/frame-pointer-elim.c @@ -246,7 +246,7 @@ // -mno-reserve-frame-pointer-reg overrides platform defaults // But -mno-reserve-frame-pointer-reg should override the target platform default // RUN: %clang -### --target=aarch64-pc-windows-msvc -S -fomit-frame-pointer -mno-reserve-frame-pointer-reg %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-RESERVED %s +// RUN: FileCheck --check-prefix=KEEP-NONE %s void f0() {} void f1() { f0(); } diff --git a/flang/include/flang/Frontend/CodeGenOptions.def b/flang/include/flang/Frontend/CodeGenOptions.def index dc3da7ba5c7f3..d5415faf06f47 100644 --- a/flang/include/flang/Frontend/CodeGenOptions.def +++ b/flang/include/flang/Frontend/CodeGenOptions.def @@ -54,7 +54,7 @@ CODEGENOPT(Underscoring, 1, 1) ENUM_CODEGENOPT(RelocationModel, llvm::Reloc::Model, 3, llvm::Reloc::PIC_) ///< Name of the relocation model to use. ENUM_CODEGENOPT(DebugInfo, llvm::codegenoptions::DebugInfoKind, 4, llvm::codegenoptions::NoDebugInfo) ///< Level of debug info to generate ENUM_CODEGENOPT(VecLib, llvm::driver::VectorLibrary, 4, llvm::driver::VectorLibrary::NoLibrary) ///< Vector functions library to use -ENUM_CODEGENOPT(FramePointer, llvm::FramePointerKind, 2, llvm::FramePointerKind::None) ///< Enable the usage of frame pointers +ENUM_CODEGENOPT(FramePointer, llvm::FramePointerKind, 3, llvm::FramePointerKind::None) ///< Enable the usage of frame pointers ENUM_CODEGENOPT(ComplexRange, ComplexRangeKind, 3, ComplexRangeKind::CX_Full) ///< Method for calculating complex number division ENUM_CODEGENOPT(DoConcurrentMapping, DoConcurrentMappingKind, 2, DoConcurrentMappingKind::DCMK_None) ///< Map `do concurrent` to OpenMP diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index 548ca675db5ea..60c636a8d4125 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -311,6 +311,7 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts, llvm::StringSwitch<std::optional<llvm::FramePointerKind>>(a->getValue()) .Case("none", llvm::FramePointerKind::None) .Case("non-leaf", llvm::FramePointerKind::NonLeaf) + .Case("non-leaf-no-reserve", llvm::FramePointerKind::NonLeafNoReserve) .Case("reserved", llvm::FramePointerKind::Reserved) .Case("all", llvm::FramePointerKind::All) .Default(std::nullopt); diff --git a/flang/test/Driver/frame-pointer-forwarding.f90 b/flang/test/Driver/frame-pointer-forwarding.f90 index 9fcbd6e12f98b..7e97c98d899f1 100644 --- a/flang/test/Driver/frame-pointer-forwarding.f90 +++ b/flang/test/Driver/frame-pointer-forwarding.f90 @@ -1,12 +1,12 @@ ! Test that flang forwards -fno-omit-frame-pointer and -fomit-frame-pointer Flang frontend ! RUN: %flang --target=aarch64-none-none -fsyntax-only -### %s -o %t 2>&1 | FileCheck %s --check-prefix=CHECK-NOVALUE -! CHECK-NOVALUE: "-fc1"{{.*}}"-mframe-pointer=non-leaf" +! CHECK-NOVALUE: "-fc1"{{.*}}"-mframe-pointer=non-leaf-no-reserve" ! RUN: %flang -fomit-frame-pointer --target=aarch64-none-none -fsyntax-only -### %s -o %t 2>&1 | FileCheck %s --check-prefix=CHECK-NONEFP ! CHECK-NONEFP: "-fc1"{{.*}}"-mframe-pointer=none" ! RUN: %flang -fno-omit-frame-pointer --target=aarch64-none-none -fsyntax-only -### %s -o %t 2>&1 | FileCheck %s --check-prefix=CHECK-NONLEAFFP -! CHECK-NONLEAFFP: "-fc1"{{.*}}"-mframe-pointer=non-leaf" +! CHECK-NONLEAFFP: "-fc1"{{.*}}"-mframe-pointer=non-leaf-no-reserve" ! RUN: %flang -fno-omit-frame-pointer --target=x86-none-none -fsyntax-only -### %s -o %t 2>&1 | FileCheck %s --check-prefix=CHECK-ALLFP ! CHECK-ALLFP: "-fc1"{{.*}}"-mframe-pointer=all" >From 85f4a60de224a342952082e6b7df86c4d9663a96 Mon Sep 17 00:00:00 2001 From: Nabeel Omer <[email protected]> Date: Wed, 29 Oct 2025 17:28:45 +0000 Subject: [PATCH 10/10] Fix formatting --- flang/lib/Frontend/CompilerInvocation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index 60c636a8d4125..80bcd317c6066 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -311,7 +311,8 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts, llvm::StringSwitch<std::optional<llvm::FramePointerKind>>(a->getValue()) .Case("none", llvm::FramePointerKind::None) .Case("non-leaf", llvm::FramePointerKind::NonLeaf) - .Case("non-leaf-no-reserve", llvm::FramePointerKind::NonLeafNoReserve) + .Case("non-leaf-no-reserve", + llvm::FramePointerKind::NonLeafNoReserve) .Case("reserved", llvm::FramePointerKind::Reserved) .Case("all", llvm::FramePointerKind::All) .Default(std::nullopt); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
