Skip to content

[CIR][CIRGen][Builtin] Support __builtin_frame_address #1137

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 37 additions & 6 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -4218,13 +4218,21 @@ def MemChrOp : CIR_Op<"libc.memchr"> {
}

//===----------------------------------------------------------------------===//
// ReturnAddrOp
// ReturnAddrOp and FrameAddrOp
//===----------------------------------------------------------------------===//

def ReturnAddrOp : CIR_Op<"return_address"> {
class FuncAddrBuiltinOp<string mnemonic> : CIR_Op<mnemonic, []> {
let arguments = (ins UInt32:$level);
let summary = "The return address of the current function, or of one of its callers";
let results = (outs Res<VoidPtr, "">:$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.
Expand All @@ -4241,11 +4249,34 @@ def ReturnAddrOp : CIR_Op<"return_address"> {
%p = return_address(%level) -> !cir.ptr<!void>
```
}];
}

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<!void>
```
}];
let hasVerifier = 0;
}

//===----------------------------------------------------------------------===//
Expand Down
13 changes: 8 additions & 5 deletions clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<cir::IntAttr>(levelAttr).getSInt();
uint64_t level = mlir::cast<cir::IntAttr>(levelAttr).getUInt();
if (BuiltinID == Builtin::BI__builtin_return_address) {
return RValue::get(builder.create<cir::ReturnAddrOp>(
loc, builder.getUInt32(level, loc)));
}
return RValue::get(
builder.create<cir::ReturnAddrOp>(loc, builder.getUInt32(level, loc)));
builder.create<cir::FrameAddrOp>(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:
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -3897,6 +3906,7 @@ void populateCIRToLLVMConversionPatterns(
CIRToLLVMEhInflightOpLowering,
CIRToLLVMEhTypeIdOpLowering,
CIRToLLVMExpectOpLowering,
CIRToLLVMFrameAddrOpLowering,
CIRToLLVMFreeExceptionOpLowering,
CIRToLLVMFuncOpLowering,
CIRToLLVMGetBitfieldOpLowering,
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,16 @@ class CIRToLLVMReturnAddrOpLowering
mlir::ConversionPatternRewriter &) const override;
};

class CIRToLLVMFrameAddrOpLowering
: public mlir::OpConversionPattern<cir::FrameAddrOp> {
public:
using mlir::OpConversionPattern<cir::FrameAddrOp>::OpConversionPattern;

mlir::LogicalResult
matchAndRewrite(cir::FrameAddrOp op, OpAdaptor,
mlir::ConversionPatternRewriter &) const override;
};

class CIRToLLVMClearCacheOpLowering
: public mlir::OpConversionPattern<cir::ClearCacheOp> {
public:
Expand Down
15 changes: 13 additions & 2 deletions clang/test/CIR/CodeGen/builtins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
2 changes: 2 additions & 0 deletions clang/test/CIR/IR/builtins.cir
Original file line number Diff line number Diff line change
Expand Up @@ -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
}