diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index e6159d1474be..9c7e2b14ac5a 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -4218,13 +4218,21 @@ def MemChrOp : CIR_Op<"libc.memchr"> { } //===----------------------------------------------------------------------===// -// ReturnAddrOp +// ReturnAddrOp and FrameAddrOp //===----------------------------------------------------------------------===// -def ReturnAddrOp : CIR_Op<"return_address"> { +class FuncAddrBuiltinOp : CIR_Op { let arguments = (ins UInt32:$level); - let summary = "The return address of the current function, or of one of its callers"; let results = (outs Res:$result); + let assemblyFormat = [{ + `(` $level `)` attr-dict + }]; + let hasVerifier = 0; +} + +def ReturnAddrOp : FuncAddrBuiltinOp<"return_address"> { + let summary = + "The return address of the current function, or of one of its callers"; let description = [{ Represents call to builtin function ` __builtin_return_address` in CIR. @@ -4241,11 +4249,34 @@ def ReturnAddrOp : CIR_Op<"return_address"> { %p = return_address(%level) -> !cir.ptr ``` }]; +} - let assemblyFormat = [{ - `(` $level `)` attr-dict +def FrameAddrOp : FuncAddrBuiltinOp<"frame_address"> { + let summary = + "The frame address of the current function, or of one of its callers"; + + let description = [{ + Represents call to builtin function ` __builtin_frame_address` in CIR. + This builtin function returns the frame address of the current function, + or of one of its callers. The frame is the area on the stack that holds + local variables and saved registers. The frame address is normally the + address of the first word pushed on to the stack by the function. + However, the exact definition depends upon the processor and the calling + convention. If the processor has a dedicated frame pointer register, and + the function has a frame, then __builtin_frame_address returns the value of + the frame pointer register. + + The `level` argument is number of frames to scan up the call stack. + For instance, value of 0 yields the frame address of the current function, + value of 1 yields the frame address of the caller of the current function, + and so forth. + + Examples: + + ```mlir + %p = frame_address(%level) -> !cir.ptr + ``` }]; - let hasVerifier = 0; } //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index e7a07f1523c3..058fca2f8de7 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -1592,18 +1592,21 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, llvm_unreachable("BI__builtin_wmemcmp NYI"); case Builtin::BI__builtin_dwarf_cfa: llvm_unreachable("BI__builtin_dwarf_cfa NYI"); - case Builtin::BI__builtin_return_address: { + case Builtin::BI__builtin_return_address: + case Builtin::BI__builtin_frame_address: { mlir::Location loc = getLoc(E->getExprLoc()); mlir::Attribute levelAttr = ConstantEmitter(*this).emitAbstract( E->getArg(0), E->getArg(0)->getType()); - int64_t level = mlir::cast(levelAttr).getSInt(); + uint64_t level = mlir::cast(levelAttr).getUInt(); + if (BuiltinID == Builtin::BI__builtin_return_address) { + return RValue::get(builder.create( + loc, builder.getUInt32(level, loc))); + } return RValue::get( - builder.create(loc, builder.getUInt32(level, loc))); + builder.create(loc, builder.getUInt32(level, loc))); } case Builtin::BI_ReturnAddress: llvm_unreachable("BI_ReturnAddress NYI"); - case Builtin::BI__builtin_frame_address: - llvm_unreachable("BI__builtin_frame_address NYI"); case Builtin::BI__builtin_extract_return_addr: llvm_unreachable("BI__builtin_extract_return_addr NYI"); case Builtin::BI__builtin_frob_return_addr: diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 040f72562cac..00d658f61ec8 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -3623,6 +3623,15 @@ mlir::LogicalResult CIRToLLVMReturnAddrOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMFrameAddrOpLowering::matchAndRewrite( + cir::FrameAddrOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext()); + replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm.frameaddress", llvmPtrTy, + adaptor.getOperands()); + return mlir::success(); +} + mlir::LogicalResult CIRToLLVMClearCacheOpLowering::matchAndRewrite( cir::ClearCacheOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { @@ -3897,6 +3906,7 @@ void populateCIRToLLVMConversionPatterns( CIRToLLVMEhInflightOpLowering, CIRToLLVMEhTypeIdOpLowering, CIRToLLVMExpectOpLowering, + CIRToLLVMFrameAddrOpLowering, CIRToLLVMFreeExceptionOpLowering, CIRToLLVMFuncOpLowering, CIRToLLVMGetBitfieldOpLowering, diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index a88c30d3dd15..b965b859d556 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -917,6 +917,16 @@ class CIRToLLVMReturnAddrOpLowering mlir::ConversionPatternRewriter &) const override; }; +class CIRToLLVMFrameAddrOpLowering + : public mlir::OpConversionPattern { +public: + using mlir::OpConversionPattern::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::FrameAddrOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + class CIRToLLVMClearCacheOpLowering : public mlir::OpConversionPattern { public: diff --git a/clang/test/CIR/CodeGen/builtins.cpp b/clang/test/CIR/CodeGen/builtins.cpp index f103abb8db64..c5f1ed5e0aff 100644 --- a/clang/test/CIR/CodeGen/builtins.cpp +++ b/clang/test/CIR/CodeGen/builtins.cpp @@ -99,9 +99,20 @@ extern "C" void *test_return_address(void) { return __builtin_return_address(1); // CIR-LABEL: test_return_address - // [[ARG:%.*]] = cir.const #cir.int<1> : !u32i - // {{%.*}} = cir.return_address([[ARG]]) + // CIR: [[ARG:%.*]] = cir.const #cir.int<1> : !u32i + // CIR: {{%.*}} = cir.return_address([[ARG]]) // LLVM-LABEL: @test_return_address // LLVM: {{%.*}} = call ptr @llvm.returnaddress(i32 1) } + +extern "C" void *test_frame_address(void) { + return __builtin_frame_address(1); + + // CIR-LABEL: test_frame_address + // CIR: [[ARG:%.*]] = cir.const #cir.int<1> : !u32i + // CIR: {{%.*}} = cir.frame_address([[ARG]]) + + // LLVM-LABEL: @test_frame_address + // LLVM: {{%.*}} = call ptr @llvm.frameaddress.p0(i32 1) +} diff --git a/clang/test/CIR/IR/builtins.cir b/clang/test/CIR/IR/builtins.cir index 86c0c57825de..413119420be6 100644 --- a/clang/test/CIR/IR/builtins.cir +++ b/clang/test/CIR/IR/builtins.cir @@ -5,10 +5,12 @@ module { cir.func @test1() { %0 = cir.const #cir.int<1> : !u32i %1 = cir.return_address(%0) + %2 = cir.frame_address(%0) cir.return } // CHECK: cir.func @test1() // CHECK: %0 = cir.const #cir.int<1> : !u32i // CHECK: %1 = cir.return_address(%0) + // CHECK: %2 = cir.frame_address(%0) // CHECK: cir.return }