diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index edaf0fe839c6..1e2a34dc8452 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -4125,6 +4125,37 @@ def MemChrOp : CIR_Op<"libc.memchr"> { let hasVerifier = 0; } +//===----------------------------------------------------------------------===// +// ReturnAddrOp +//===----------------------------------------------------------------------===// + +def ReturnAddrOp : CIR_Op<"return_address"> { + 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 description = [{ + Represents call to builtin function ` __builtin_return_address` in CIR. + This builtin function returns the return address of the current function, + or of one of its callers. + The `level` argument is number of frames to scan up the call stack. + For instance, value of 0 yields the return address of the current function, + value of 1 yields the return address of the caller of the current function, + and so forth. + + Examples: + + ```mlir + %p = return_address(%level) -> !cir.ptr + ``` + }]; + + let assemblyFormat = [{ + `(` $level `)` attr-dict + }]; + let hasVerifier = 0; +} + //===----------------------------------------------------------------------===// // StdFindOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 8fa4d3b01530..30805b9378a5 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -1510,8 +1510,14 @@ RValue CIRGenFunction::buildBuiltinExpr(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: - llvm_unreachable("BI__builtin_return_address NYI"); + case Builtin::BI__builtin_return_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(); + return RValue::get(builder.create( + loc, builder.getUInt32(level, loc))); + } case Builtin::BI_ReturnAddress: llvm_unreachable("BI_ReturnAddress NYI"); case Builtin::BI__builtin_frame_address: diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 983ed0d8f254..eebf96ffb720 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -4115,6 +4115,21 @@ class CIRCmpThreeWayOpLowering } }; +class CIRReturnAddrOpLowering + : public mlir::OpConversionPattern { +public: + using OpConversionPattern::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(mlir::cir::ReturnAddrOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override { + auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext()); + replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm.returnaddress", + llvmPtrTy, adaptor.getOperands()); + return mlir::success(); + } +}; + class CIRClearCacheOpLowering : public mlir::OpConversionPattern { public: @@ -4370,9 +4385,16 @@ void populateCIRToLLVMConversionPatterns( CIRVectorShuffleVecLowering, CIRStackSaveLowering, CIRUnreachableLowering, CIRTrapLowering, CIRInlineAsmOpLowering, CIRSetBitfieldLowering, CIRGetBitfieldLowering, CIRPrefetchLowering, CIRObjSizeOpLowering, + CIRIsConstantOpLowering, CIRCmpThreeWayOpLowering, CIRMemCpyOpLowering, + CIRFAbsOpLowering, CIRExpectOpLowering, CIRVTableAddrPointOpLowering, + CIRVectorCreateLowering, CIRVectorCmpOpLowering, CIRVectorSplatLowering, + CIRVectorTernaryLowering, CIRVectorShuffleIntsLowering, + CIRVectorShuffleVecLowering, CIRStackSaveLowering, CIRUnreachableLowering, + CIRTrapLowering, CIRInlineAsmOpLowering, CIRSetBitfieldLowering, + CIRGetBitfieldLowering, CIRPrefetchLowering, CIRObjSizeOpLowering, CIRIsConstantOpLowering, CIRCmpThreeWayOpLowering, - CIRClearCacheOpLowering, CIREhTypeIdOpLowering, CIRCatchParamOpLowering, - CIRResumeOpLowering, CIRAllocExceptionOpLowering, + CIRReturnAddrOpLowering, CIRClearCacheOpLowering, CIREhTypeIdOpLowering, + CIRCatchParamOpLowering, CIRResumeOpLowering, CIRAllocExceptionOpLowering, CIRFreeExceptionOpLowering, CIRThrowOpLowering, CIRIntrinsicCallLowering, CIRAssumeLowering, CIRAssumeAlignedLowering, CIRAssumeSepStorageLowering, CIRBaseClassAddrOpLowering, CIRDerivedClassAddrOpLowering, diff --git a/clang/test/CIR/CodeGen/builtins.cpp b/clang/test/CIR/CodeGen/builtins.cpp index 202ae61f0db2..971fc09e07d9 100644 --- a/clang/test/CIR/CodeGen/builtins.cpp +++ b/clang/test/CIR/CodeGen/builtins.cpp @@ -75,3 +75,14 @@ extern "C" char* test_memchr(const char arg[32]) { // LLVM: [[RET:%.*]] = load ptr, ptr [[RET_P]], align 8 // LLVM: ret ptr [[RET]] } + +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]]) + + // LLVM-LABEL: @test_return_address + // LLVM: {{%.*}} = call ptr @llvm.returnaddress(i32 1) +} diff --git a/clang/test/CIR/IR/builtins.cir b/clang/test/CIR/IR/builtins.cir new file mode 100644 index 000000000000..86c0c57825de --- /dev/null +++ b/clang/test/CIR/IR/builtins.cir @@ -0,0 +1,14 @@ +// RUN: cir-opt %s | cir-opt | FileCheck %s +!u32i = !cir.int + +module { + cir.func @test1() { + %0 = cir.const #cir.int<1> : !u32i + %1 = cir.return_address(%0) + cir.return + } + // CHECK: cir.func @test1() + // CHECK: %0 = cir.const #cir.int<1> : !u32i + // CHECK: %1 = cir.return_address(%0) + // CHECK: cir.return +}