Skip to content

Commit c1f1871

Browse files
authored
[CIR][CIRGen][Builtin] Support __builtin_frame_address (#1137)
1 parent 0ace889 commit c1f1871

File tree

6 files changed

+80
-13
lines changed

6 files changed

+80
-13
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4218,13 +4218,21 @@ def MemChrOp : CIR_Op<"libc.memchr"> {
42184218
}
42194219

42204220
//===----------------------------------------------------------------------===//
4221-
// ReturnAddrOp
4221+
// ReturnAddrOp and FrameAddrOp
42224222
//===----------------------------------------------------------------------===//
42234223

4224-
def ReturnAddrOp : CIR_Op<"return_address"> {
4224+
class FuncAddrBuiltinOp<string mnemonic> : CIR_Op<mnemonic, []> {
42254225
let arguments = (ins UInt32:$level);
4226-
let summary = "The return address of the current function, or of one of its callers";
42274226
let results = (outs Res<VoidPtr, "">:$result);
4227+
let assemblyFormat = [{
4228+
`(` $level `)` attr-dict
4229+
}];
4230+
let hasVerifier = 0;
4231+
}
4232+
4233+
def ReturnAddrOp : FuncAddrBuiltinOp<"return_address"> {
4234+
let summary =
4235+
"The return address of the current function, or of one of its callers";
42284236

42294237
let description = [{
42304238
Represents call to builtin function ` __builtin_return_address` in CIR.
@@ -4241,11 +4249,34 @@ def ReturnAddrOp : CIR_Op<"return_address"> {
42414249
%p = return_address(%level) -> !cir.ptr<!void>
42424250
```
42434251
}];
4252+
}
42444253

4245-
let assemblyFormat = [{
4246-
`(` $level `)` attr-dict
4254+
def FrameAddrOp : FuncAddrBuiltinOp<"frame_address"> {
4255+
let summary =
4256+
"The frame address of the current function, or of one of its callers";
4257+
4258+
let description = [{
4259+
Represents call to builtin function ` __builtin_frame_address` in CIR.
4260+
This builtin function returns the frame address of the current function,
4261+
or of one of its callers. The frame is the area on the stack that holds
4262+
local variables and saved registers. The frame address is normally the
4263+
address of the first word pushed on to the stack by the function.
4264+
However, the exact definition depends upon the processor and the calling
4265+
convention. If the processor has a dedicated frame pointer register, and
4266+
the function has a frame, then __builtin_frame_address returns the value of
4267+
the frame pointer register.
4268+
4269+
The `level` argument is number of frames to scan up the call stack.
4270+
For instance, value of 0 yields the frame address of the current function,
4271+
value of 1 yields the frame address of the caller of the current function,
4272+
and so forth.
4273+
4274+
Examples:
4275+
4276+
```mlir
4277+
%p = frame_address(%level) -> !cir.ptr<!void>
4278+
```
42474279
}];
4248-
let hasVerifier = 0;
42494280
}
42504281

42514282
//===----------------------------------------------------------------------===//

clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1592,18 +1592,21 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
15921592
llvm_unreachable("BI__builtin_wmemcmp NYI");
15931593
case Builtin::BI__builtin_dwarf_cfa:
15941594
llvm_unreachable("BI__builtin_dwarf_cfa NYI");
1595-
case Builtin::BI__builtin_return_address: {
1595+
case Builtin::BI__builtin_return_address:
1596+
case Builtin::BI__builtin_frame_address: {
15961597
mlir::Location loc = getLoc(E->getExprLoc());
15971598
mlir::Attribute levelAttr = ConstantEmitter(*this).emitAbstract(
15981599
E->getArg(0), E->getArg(0)->getType());
1599-
int64_t level = mlir::cast<cir::IntAttr>(levelAttr).getSInt();
1600+
uint64_t level = mlir::cast<cir::IntAttr>(levelAttr).getUInt();
1601+
if (BuiltinID == Builtin::BI__builtin_return_address) {
1602+
return RValue::get(builder.create<cir::ReturnAddrOp>(
1603+
loc, builder.getUInt32(level, loc)));
1604+
}
16001605
return RValue::get(
1601-
builder.create<cir::ReturnAddrOp>(loc, builder.getUInt32(level, loc)));
1606+
builder.create<cir::FrameAddrOp>(loc, builder.getUInt32(level, loc)));
16021607
}
16031608
case Builtin::BI_ReturnAddress:
16041609
llvm_unreachable("BI_ReturnAddress NYI");
1605-
case Builtin::BI__builtin_frame_address:
1606-
llvm_unreachable("BI__builtin_frame_address NYI");
16071610
case Builtin::BI__builtin_extract_return_addr:
16081611
llvm_unreachable("BI__builtin_extract_return_addr NYI");
16091612
case Builtin::BI__builtin_frob_return_addr:

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3612,6 +3612,15 @@ mlir::LogicalResult CIRToLLVMReturnAddrOpLowering::matchAndRewrite(
36123612
return mlir::success();
36133613
}
36143614

3615+
mlir::LogicalResult CIRToLLVMFrameAddrOpLowering::matchAndRewrite(
3616+
cir::FrameAddrOp op, OpAdaptor adaptor,
3617+
mlir::ConversionPatternRewriter &rewriter) const {
3618+
auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());
3619+
replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm.frameaddress", llvmPtrTy,
3620+
adaptor.getOperands());
3621+
return mlir::success();
3622+
}
3623+
36153624
mlir::LogicalResult CIRToLLVMClearCacheOpLowering::matchAndRewrite(
36163625
cir::ClearCacheOp op, OpAdaptor adaptor,
36173626
mlir::ConversionPatternRewriter &rewriter) const {
@@ -3888,6 +3897,7 @@ void populateCIRToLLVMConversionPatterns(
38883897
CIRToLLVMEhInflightOpLowering,
38893898
CIRToLLVMEhTypeIdOpLowering,
38903899
CIRToLLVMExpectOpLowering,
3900+
CIRToLLVMFrameAddrOpLowering,
38913901
CIRToLLVMFreeExceptionOpLowering,
38923902
CIRToLLVMFuncOpLowering,
38933903
CIRToLLVMGetBitfieldOpLowering,

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,16 @@ class CIRToLLVMReturnAddrOpLowering
936936
mlir::ConversionPatternRewriter &) const override;
937937
};
938938

939+
class CIRToLLVMFrameAddrOpLowering
940+
: public mlir::OpConversionPattern<cir::FrameAddrOp> {
941+
public:
942+
using mlir::OpConversionPattern<cir::FrameAddrOp>::OpConversionPattern;
943+
944+
mlir::LogicalResult
945+
matchAndRewrite(cir::FrameAddrOp op, OpAdaptor,
946+
mlir::ConversionPatternRewriter &) const override;
947+
};
948+
939949
class CIRToLLVMClearCacheOpLowering
940950
: public mlir::OpConversionPattern<cir::ClearCacheOp> {
941951
public:

clang/test/CIR/CodeGen/builtins.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,20 @@ extern "C" void *test_return_address(void) {
9999
return __builtin_return_address(1);
100100

101101
// CIR-LABEL: test_return_address
102-
// [[ARG:%.*]] = cir.const #cir.int<1> : !u32i
103-
// {{%.*}} = cir.return_address([[ARG]])
102+
// CIR: [[ARG:%.*]] = cir.const #cir.int<1> : !u32i
103+
// CIR: {{%.*}} = cir.return_address([[ARG]])
104104

105105
// LLVM-LABEL: @test_return_address
106106
// LLVM: {{%.*}} = call ptr @llvm.returnaddress(i32 1)
107107
}
108+
109+
extern "C" void *test_frame_address(void) {
110+
return __builtin_frame_address(1);
111+
112+
// CIR-LABEL: test_frame_address
113+
// CIR: [[ARG:%.*]] = cir.const #cir.int<1> : !u32i
114+
// CIR: {{%.*}} = cir.frame_address([[ARG]])
115+
116+
// LLVM-LABEL: @test_frame_address
117+
// LLVM: {{%.*}} = call ptr @llvm.frameaddress.p0(i32 1)
118+
}

clang/test/CIR/IR/builtins.cir

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ module {
55
cir.func @test1() {
66
%0 = cir.const #cir.int<1> : !u32i
77
%1 = cir.return_address(%0)
8+
%2 = cir.frame_address(%0)
89
cir.return
910
}
1011
// CHECK: cir.func @test1()
1112
// CHECK: %0 = cir.const #cir.int<1> : !u32i
1213
// CHECK: %1 = cir.return_address(%0)
14+
// CHECK: %2 = cir.frame_address(%0)
1315
// CHECK: cir.return
1416
}

0 commit comments

Comments
 (0)