[clang] [CIR] Emit the frame-pointer function attribute and module flag (PR #230697)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 9 15:50:07 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clangir
Author: Adam Smith (adams381)
<details>
<summary>Changes</summary>
CIR now honors -mframe-pointer= the way classic CodeGen does. Functions and the module carry a new #cir.frame_pointer attribute, which lowers to the "frame-pointer" function attribute and module flag.
Assisted-by: Cursor / claude-opus-5.5
---
Patch is 29.72 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/230697.diff
14 Files Affected:
- (modified) clang/include/clang/CIR/Dialect/IR/CIRAttrs.td (+45)
- (modified) clang/include/clang/CIR/Dialect/IR/CIRDialect.td (+2)
- (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+2-1)
- (modified) clang/lib/CIR/CodeGen/CIRGenCall.cpp (+22-1)
- (modified) clang/lib/CIR/CodeGen/CIRGenModule.cpp (+6)
- (modified) clang/lib/CIR/CodeGen/CIRGenModule.h (+6)
- (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+30-9)
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+25)
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp (+22)
- (added) clang/test/CIR/CodeGen/frame-pointer.cpp (+93)
- (modified) clang/test/CIR/IR/func-attrs.cir (+31)
- (modified) clang/test/CIR/IR/invalid-func-attr.cir (+19)
- (added) clang/test/CIR/IR/invalid-module-frame-pointer.cir (+19)
- (added) clang/test/CIR/Lowering/frame-pointer.cir (+96)
``````````diff
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index eb4cf65b919c4..e9eac89b34ec5 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -1454,6 +1454,51 @@ def CIR_UnwindTableKindAttr : CIR_EnumAttr<CIR_UnwindTableKind, "uwtable"> {
}];
}
+//===----------------------------------------------------------------------===//
+// FramePointerKind
+//===----------------------------------------------------------------------===//
+def CIR_FramePointerKind : CIR_I32Enum<"FramePointerKind",
+ "Frame Pointer Kind", [
+ I32EnumCase<"None", 0, "none">,
+ I32EnumCase<"NonLeaf", 1, "non_leaf">,
+ I32EnumCase<"All", 2, "all">,
+ I32EnumCase<"Reserved", 3, "reserved">,
+ I32EnumCase<"NonLeafNoReserve", 4, "non_leaf_no_reserve">
+]>;
+
+def CIR_FramePointerKindAttr
+ : CIR_EnumAttr<CIR_FramePointerKind, "frame_pointer"> {
+ let summary = "Encodes the frame pointer kind for a function or a module.";
+
+ let description = [{
+ This mirrors the FramePointerKind enum of the LLVM dialect. On a
+ `cir.func` it is the `frame_pointer` attribute and lowers to the
+ `frame-pointer` function attribute in LLVM IR. As the value of the
+ module attribute `cir.frame_pointer` it lowers to the `frame-pointer`
+ module flag, which LLVM gives to the functions it synthesizes. A
+ function or module without the attribute behaves as `none`.
+
+ `none` lets the frame pointer be eliminated. `all` keeps the frame
+ pointer, and `non_leaf` keeps it if the function calls other functions.
+ `reserved` lets the frame pointer be eliminated but keeps its register
+ from being used for anything else, so the register either points to a
+ valid frame record for the current function or is left unmodified.
+ `non_leaf_no_reserve` is `non_leaf`, except that a leaf function may use
+ the frame pointer register as a general-purpose register.
+
+ Example:
+
+ ```
+ module attributes {cir.frame_pointer = #cir.frame_pointer<all>} {
+ cir.func private @f() attributes {frame_pointer = #cir.frame_pointer<all>}
+ cir.func private @g() attributes {
+ frame_pointer = #cir.frame_pointer<non_leaf>
+ }
+ }
+ ```
+ }];
+}
+
//===----------------------------------------------------------------------===//
// GloblCtorAttr
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
index 2086646949a11..c8cf2870a7eb5 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
@@ -52,6 +52,7 @@ def CIR_Dialect : Dialect {
static llvm::StringRef getNoReturnAttrName() { return "noreturn"; }
static llvm::StringRef getMemoryEffectsAttrName() { return "memory_effects"; }
static llvm::StringRef getUwtableAttrName() { return "uwtable"; }
+ static llvm::StringRef getFramePointerAttrName() { return "frame_pointer"; }
static llvm::StringRef getReturnsTwiceAttrName() { return "returns_twice"; }
static llvm::StringRef getColdAttrName() { return "cold"; }
static llvm::StringRef getHotAttrName() { return "hot"; }
@@ -67,6 +68,7 @@ def CIR_Dialect : Dialect {
static llvm::StringRef getNoUnwindAttrName() { return "nounwind"; }
static llvm::StringRef getWillReturnAttrName() { return "willreturn"; }
static llvm::StringRef getModuleLevelAsmAttrName() { return "cir.module_asm"; }
+ static llvm::StringRef getModuleFramePointerAttrName() { return "cir.frame_pointer"; }
static llvm::StringRef getGlobalCtorsAttrName() { return "cir.global_ctors"; }
static llvm::StringRef getGlobalDtorsAttrName() { return "cir.global_dtors"; }
static llvm::StringRef getOffloadContainerAttrName() { return "cir.offload.container"; }
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 53f693a7863ee..4c26dcf630ecc 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4362,7 +4362,8 @@ def CIR_FuncOp : CIR_Op<"func", [
CIR_OptionalPriorityAttr:$global_dtor_priority,
OptionalAttr<CIR_FuncInfoAttr>:$func_info,
OptionalAttr<CIR_AnnotationArrayAttr>:$annotations,
- OptionalAttr<CIR_UnwindTableKindAttr>:$uwtable
+ OptionalAttr<CIR_UnwindTableKindAttr>:$uwtable,
+ OptionalAttr<CIR_FramePointerKindAttr>:$frame_pointer
);
let regions = (region AnyRegion:$body);
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index ec4dde920a270..6499f3dcceab5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -204,6 +204,23 @@ getZeroCallUsedRegsKindStr(llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind k) {
llvm_unreachable("Unknown kind?");
}
+std::optional<cir::FramePointerKind>
+CIRGenModule::getFramePointerKind(CodeGenOptions::FramePointerKind kind) {
+ switch (kind) {
+ case CodeGenOptions::FramePointerKind::None:
+ return std::nullopt;
+ case CodeGenOptions::FramePointerKind::Reserved:
+ return cir::FramePointerKind::Reserved;
+ case CodeGenOptions::FramePointerKind::NonLeafNoReserve:
+ return cir::FramePointerKind::NonLeafNoReserve;
+ case CodeGenOptions::FramePointerKind::NonLeaf:
+ return cir::FramePointerKind::NonLeaf;
+ case CodeGenOptions::FramePointerKind::All:
+ return cir::FramePointerKind::All;
+ }
+ llvm_unreachable("Unknown frame pointer kind");
+}
+
/// Add default attributes to a function, which have merge semantics under
/// -mlink-builtin-bitcode and should not simply overwrite any existing
/// attributes in the linked library.
@@ -235,7 +252,11 @@ static void addTrivialDefaultFunctionAttributes(
attrs.set(cir::CIRDialect::getTrapFuncNameAttrName(),
mlir::StringAttr::get(mlirCtx, codeGenOpts.TrapFuncName));
} else {
- // TODO(cir): Set frame pointer attribute here.
+ if (std::optional<cir::FramePointerKind> kind =
+ CIRGenModule::getFramePointerKind(codeGenOpts.getFramePointer()))
+ attrs.set(cir::CIRDialect::getFramePointerAttrName(),
+ cir::FramePointerKindAttr::get(mlirCtx, *kind));
+
// TODO(cir): a number of other attribute 1-offs based on codegen/lang opts
// should be done here: less-recise-fpmad null-pointer-is-valid
// no-trapping-math
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 1f80f4e0ebf08..f4074aecb051c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -3923,6 +3923,12 @@ void CIRGenModule::release() {
emitGlobalAnnotations();
+ if (std::optional<cir::FramePointerKind> kind =
+ getFramePointerKind(codeGenOpts.getFramePointer()))
+ theModule->setAttr(
+ cir::CIRDialect::getModuleFramePointerAttrName(),
+ cir::FramePointerKindAttr::get(&getMLIRContext(), *kind));
+
if (!recordLayoutEntries.empty())
theModule->setAttr(
cir::CIRDialect::getRecordLayoutsAttrName(),
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 05ba8b5ee212e..ed5b7409eaa12 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -385,6 +385,12 @@ class CIRGenModule : public CIRGenTypeCache {
bool attrOnCallSite,
mlir::NamedAttrList &attrs);
+ /// Returns the frame pointer kind to record on functions and on the module,
+ /// or std::nullopt when \p kind is CodeGenOptions::FramePointerKind::None,
+ /// the default, which is left implicit.
+ static std::optional<cir::FramePointerKind>
+ getFramePointerKind(CodeGenOptions::FramePointerKind kind);
+
/// Will return a global variable of the given type. If a variable with a
/// different type already exists then a new variable with the right type
/// will be created and all uses of the old variable will be replaced with a
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 8a62ae541b4b6..96c6c05e0a11a 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -272,6 +272,16 @@ cir::CIRDialect::verifyOperationAttribute(mlir::Operation *op,
<< "' attribute to be attached to '"
<< mlir::ModuleOp::getOperationName() << "'";
+ if (attrName == getModuleFramePointerAttrName()) {
+ if (!mlir::isa<mlir::ModuleOp>(op))
+ return op->emitOpError() << "expects '" << getModuleFramePointerAttrName()
+ << "' attribute to be attached to '"
+ << mlir::ModuleOp::getOperationName() << "'";
+ if (!mlir::isa<cir::FramePointerKindAttr>(attr.getValue()))
+ return op->emitOpError() << "expects '" << getModuleFramePointerAttrName()
+ << "' to be a #cir.frame_pointer attribute";
+ }
+
// LoweringPrepare uses this attribute directly as the fatbin global's
// initializer, so it must be a valid #cir.const_array payload for its type.
if (attrName == getCUDADeviceBinaryAttrName()) {
@@ -1371,9 +1381,10 @@ parseTryCallDestinations(mlir::OpAsmParser &parser,
return mlir::success();
}
-/// Reject an effect attribute of the wrong kind in an explicit attribute
-/// dictionary. Where these are declared they are stored as properties, so a
-/// value of the wrong kind would be dropped without a diagnostic.
+/// Reject an attribute in an explicit attribute dictionary whose value is not
+/// the attribute class expected for its name. Where an op declares the
+/// attribute it is stored as a property, so a value of the wrong class would
+/// be dropped without a diagnostic.
static ParseResult checkEffectAttrKinds(mlir::OpAsmParser &parser,
llvm::SMLoc loc,
const mlir::NamedAttrList &attrs) {
@@ -1390,6 +1401,13 @@ static ParseResult checkEffectAttrKinds(mlir::OpAsmParser &parser,
<< CIRDialect::getUwtableAttrName()
<< "' must be a #cir.uwtable attribute";
+ if (mlir::Attribute framePointer =
+ attrs.get(CIRDialect::getFramePointerAttrName()))
+ if (!mlir::isa<cir::FramePointerKindAttr>(framePointer))
+ return parser.emitError(loc, "attribute '")
+ << CIRDialect::getFramePointerAttrName()
+ << "' must be a #cir.frame_pointer attribute";
+
for (llvm::StringRef name :
{CIRDialect::getNoUnwindAttrName(), CIRDialect::getWillReturnAttrName(),
CIRDialect::getMustProgressAttrName()})
@@ -3098,11 +3116,13 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
return failure();
// Every other declared attribute has dedicated syntax above, so
- // memory_effects and uwtable is the only one the explicit list may carry.
- // Without the exception cir.func could not parse back what it prints.
+ // memory_effects, uwtable and frame_pointer are the only ones the explicit
+ // list may carry. Without these exceptions cir.func could not parse back
+ // what it prints.
for (StringRef disallowed : cir::FuncOp::getAttributeNames()) {
if (disallowed == CIRDialect::getMemoryEffectsAttrName() ||
- disallowed == CIRDialect::getUwtableAttrName())
+ disallowed == CIRDialect::getUwtableAttrName() ||
+ disallowed == CIRDialect::getFramePointerAttrName())
continue;
if (parsedAttrs.get(disallowed))
return parser.emitError(loc, "attribute '")
@@ -3295,12 +3315,13 @@ void cir::FuncOp::print(OpAsmPrinter &p) {
}
// Every declared attribute is printed by the syntax above, except
- // memory_effects and uwtable, which have none and so must reach the
- // dictionary.
+ // memory_effects, uwtable and frame_pointer, which have none and so must
+ // reach the dictionary.
llvm::SmallVector<llvm::StringRef> elidedAttrs;
for (llvm::StringRef name : cir::FuncOp::getAttributeNames())
if (name != CIRDialect::getMemoryEffectsAttrName() &&
- name != CIRDialect::getUwtableAttrName())
+ name != CIRDialect::getUwtableAttrName() &&
+ name != CIRDialect::getFramePointerAttrName())
elidedAttrs.push_back(name);
function_interface_impl::printFunctionAttributes(p, *this, elidedAttrs);
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index d919ed2e98a5b..11679fbe53091 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -305,6 +305,26 @@ convertUWTableKind(cir::UnwindTableKind kind) {
llvm_unreachable("Unknown CIR unwind table kind");
}
+static mlir::LLVM::framePointerKind::FramePointerKind
+convertFramePointerKind(cir::FramePointerKind kind) {
+ using CIR = cir::FramePointerKind;
+ using LLVM = mlir::LLVM::framePointerKind::FramePointerKind;
+
+ switch (kind) {
+ case CIR::None:
+ return LLVM::None;
+ case CIR::NonLeaf:
+ return LLVM::NonLeaf;
+ case CIR::All:
+ return LLVM::All;
+ case CIR::Reserved:
+ return LLVM::Reserved;
+ case CIR::NonLeafNoReserve:
+ return LLVM::NonLeafNoReserve;
+ }
+ llvm_unreachable("Unknown CIR frame pointer kind");
+}
+
mlir::LogicalResult CIRToLLVMCopyOpLowering::matchAndRewrite(
cir::CopyOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -2933,6 +2953,11 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
fn.setUwtableKindAttr(mlir::LLVM::UWTableKindAttr::get(
fn.getContext(), convertUWTableKind(*uwtableKind)));
+ if (std::optional<cir::FramePointerKind> framePointerKind =
+ op.getFramePointer())
+ fn.setFramePointerAttr(mlir::LLVM::FramePointerKindAttr::get(
+ fn.getContext(), convertFramePointerKind(*framePointerKind)));
+
// Function attributes with no dedicated field on the LLVM dialect's
// LLVMFuncOp are routed through the `passthrough` array. The MLIR LLVM IR
// translator forwards `passthrough` entries to LLVM IR as function
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp
index 213f80f0defb0..71f59bafdb7c9 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp
@@ -27,6 +27,23 @@ using namespace llvm;
namespace cir {
namespace direct {
+static llvm::FramePointerKind
+convertFramePointerKind(cir::FramePointerKind kind) {
+ switch (kind) {
+ case cir::FramePointerKind::None:
+ return llvm::FramePointerKind::None;
+ case cir::FramePointerKind::NonLeaf:
+ return llvm::FramePointerKind::NonLeaf;
+ case cir::FramePointerKind::All:
+ return llvm::FramePointerKind::All;
+ case cir::FramePointerKind::Reserved:
+ return llvm::FramePointerKind::Reserved;
+ case cir::FramePointerKind::NonLeafNoReserve:
+ return llvm::FramePointerKind::NonLeafNoReserve;
+ }
+ llvm_unreachable("Unknown CIR frame pointer kind");
+}
+
/// Implementation of the dialect interface that converts CIR attributes to LLVM
/// IR metadata.
class CIRDialectLLVMIRTranslationInterface
@@ -135,6 +152,11 @@ class CIRDialectLLVMIRTranslationInterface
llvm::Module *llvmModule = moduleTranslation.getLLVMModule();
llvm::LLVMContext &llvmContext = llvmModule->getContext();
+ if (attribute.getName() == cir::CIRDialect::getModuleFramePointerAttrName())
+ llvmModule->setFramePointer(convertFramePointerKind(
+ mlir::cast<cir::FramePointerKindAttr>(attribute.getValue())
+ .getValue()));
+
if (attribute.getName() == "cir.amdhsa_code_object_version") {
if (auto intAttr =
mlir::dyn_cast<mlir::IntegerAttr>(attribute.getValue())) {
diff --git a/clang/test/CIR/CodeGen/frame-pointer.cpp b/clang/test/CIR/CodeGen/frame-pointer.cpp
new file mode 100644
index 0000000000000..a99ac0c20e309
--- /dev/null
+++ b/clang/test/CIR/CodeGen/frame-pointer.cpp
@@ -0,0 +1,93 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t-default.cir
+// RUN: FileCheck --input-file=%t-default.cir %s --check-prefix=CIR-NONE
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-default-cir.ll
+// RUN: FileCheck --input-file=%t-default-cir.ll %s --check-prefix=LLVM-NONE
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t-default.ll
+// RUN: FileCheck --input-file=%t-default.ll %s --check-prefix=LLVM-NONE
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mframe-pointer=none -fclangir -emit-cir %s -o %t-none.cir
+// RUN: FileCheck --input-file=%t-none.cir %s --check-prefix=CIR-NONE
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mframe-pointer=none -fclangir -emit-llvm %s -o %t-none-cir.ll
+// RUN: FileCheck --input-file=%t-none-cir.ll %s --check-prefix=LLVM-NONE
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mframe-pointer=none -emit-llvm %s -o %t-none.ll
+// RUN: FileCheck --input-file=%t-none.ll %s --check-prefix=LLVM-NONE
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mframe-pointer=non-leaf -fclangir -emit-cir %s -o %t-non-leaf.cir
+// RUN: FileCheck --input-file=%t-non-leaf.cir %s --check-prefix=CIR-NON-LEAF
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mframe-pointer=non-leaf -fclangir -emit-llvm %s -o %t-non-leaf-cir.ll
+// RUN: FileCheck --input-file=%t-non-leaf-cir.ll %s --check-prefix=LLVM-NON-LEAF
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mframe-pointer=non-leaf -emit-llvm %s -o %t-non-leaf.ll
+// RUN: FileCheck --input-file=%t-non-leaf.ll %s --check-prefix=LLVM-NON-LEAF
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mframe-pointer=all -fclangir -emit-cir %s -o %t-all.cir
+// RUN: FileCheck --input-file=%t-all.cir %s --check-prefix=CIR-ALL
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mframe-pointer=all -fclangir -emit-llvm %s -o %t-all-cir.ll
+// RUN: FileCheck --input-file=%t-all-cir.ll %s --check-prefix=LLVM-ALL
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mframe-pointer=all -emit-llvm %s -o %t-all.ll
+// RUN: FileCheck --input-file=%t-all.ll %s --check-prefix=LLVM-ALL
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mframe-pointer=reserved -fclangir -emit-cir %s -o %t-reserved.cir
+// RUN: FileCheck --input-file=%t-reserved.cir %s --check-prefix=CIR-RESERVED
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mframe-pointer=reserved -fclangir -emit-llvm %s -o %t-reserved-cir.ll
+// RUN: FileCheck --input-file=%t-reserved-cir.ll %s --check-prefix=LLVM-RESERVED
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mframe-pointer=reserved -emit-llvm %s -o %t-reserved.ll
+// RUN: FileCheck --input-file=%t-reserved.ll %s --check-prefix=LLVM-RESERVED
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mframe-pointer=non-leaf-no-reserve -fclangir -emit-cir %s -o %t-nlnr.cir
+// RUN: FileCheck --input-file=%t-nlnr.cir %s --check-prefix=CIR-NLNR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mframe-pointer=non-leaf-no-reserve -fclangir -emit-llvm %s -o %t-nlnr-cir.ll
+// RUN: FileCheck --input-file=%t-nlnr-cir.ll %s --check-prefix=LLVM-NLNR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mframe-pointer=non-leaf-no-reserve -emit-llvm %s -o %t-nlnr.ll
+// RUN: FileCheck --input-file=%t-nlnr.ll %s --check-prefix=LLVM-NLNR
+
+void declaration();
+void definition() { declaration(); }
+
+// CIR-NONE-NOT: frame_pointer
+// CIR-NONE: cir.func {{.*}}@_Z10definitionv()
+// CIR-NONE-NOT: frame_pointer
+
+// CIR-NON-LEAF: module {{.*}}attributes {{.*}}cir.frame_pointer = #cir.frame_pointer<non_leaf>
+// CIR-NON-LEAF: cir.func {{.*}}@_Z10definitionv() attributes {{.*}}frame_pointer = #cir.frame_pointer<non_leaf>
+// CIR-NON-LEAF: cir.func private @_Z11declarationv() attributes {{.*}}frame_pointer = #cir.frame_pointer<non_leaf>
+
+// CIR-ALL: module {{.*}}attributes {{.*}}cir.frame_pointer = #cir.frame_pointer<all>
+// CIR-ALL: cir.func {{.*}}@_Z10definitionv() attributes {{.*}}frame_pointer = #cir.frame_point...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/230697
More information about the cfe-commits
mailing list