Skip to content

Commit 4e092b2

Browse files
authored
[CIR] Add dedicated CIR op for setjmp (#1853)
Fixes #1849
1 parent 4f3e788 commit 4e092b2

File tree

7 files changed

+161
-14
lines changed

7 files changed

+161
-14
lines changed

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4697,6 +4697,36 @@ def CIR_EhTypeIdOp : CIR_Op<"eh.typeid",
46974697
}];
46984698
}
46994699

4700+
def CIR_EhSetjmp : CIR_Op<"eh.setjmp"> {
4701+
let summary = "CIR setjmp operation";
4702+
let description = [{
4703+
Saves call-site information (e.g., stack pointer, instruction
4704+
pointer, signal mask, and other registers) in memory at `env` for use by longjmp(). In this case,
4705+
setjmp() returns 0. Following a successful longjmp(), execution proceeds
4706+
from cir.eh.setjmp with the operation yielding a non-zero value.
4707+
4708+
The presence of the `builtin` attribute refers to the setjmp() function; the lack of the attribute refers
4709+
to the _setjmp() function.
4710+
4711+
Examples:
4712+
```mlir
4713+
// Specify setjmp is builtin.
4714+
%0 = cir.eh.setjmp builtin %arg0 : (!cir.ptr<!cir.void>) -> !s32i
4715+
4716+
// Specify setjmp is not builtin.
4717+
%0 = cir.eh.setjmp %arg0 : (!cir.ptr<!cir.void>) -> !s32i
4718+
```
4719+
}];
4720+
let arguments = (ins CIR_PointerType:$env, UnitAttr:$is_builtin);
4721+
4722+
let results = (outs CIR_SInt32:$res);
4723+
4724+
let assemblyFormat = [{
4725+
(`builtin` $is_builtin^)?
4726+
$env `:` functional-type($env, results) attr-dict
4727+
}];
4728+
}
4729+
47004730
//===----------------------------------------------------------------------===//
47014731
// CopyOp
47024732
//===----------------------------------------------------------------------===//

clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1916,12 +1916,9 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
19161916
cir::PtrStrideOp stackSaveSlot = cir::PtrStrideOp::create(
19171917
builder, loc, ppTy, castBuf, builder.getSInt32(2, loc));
19181918
cir::StoreOp::create(builder, loc, stacksave, stackSaveSlot);
1919-
mlir::Value setjmpCall =
1920-
cir::LLVMIntrinsicCallOp::create(
1921-
builder, loc, builder.getStringAttr("eh.sjlj.setjmp"),
1922-
builder.getSInt32Ty(), mlir::ValueRange{castBuf})
1923-
.getResult();
1924-
return RValue::get(setjmpCall);
1919+
cir::EhSetjmp op =
1920+
cir::EhSetjmp::create(builder, loc, castBuf, /*is_builtin=*/true);
1921+
return RValue::get(op);
19251922
}
19261923
case Builtin::BI__builtin_longjmp:
19271924
llvm_unreachable("BI__builtin_longjmp NYI");
@@ -2423,7 +2420,13 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
24232420
llvm_unreachable("NYI setjmp on aarch64");
24242421
llvm_unreachable("NYI setjmp on generic MSVCRT");
24252422
}
2426-
break;
2423+
Address buf = emitPointerWithAlignment(E->getArg(0));
2424+
mlir::Location loc = getLoc(E->getExprLoc());
2425+
cir::PointerType ppTy = builder.getPointerTo(builder.getVoidPtrTy());
2426+
mlir::Value castBuf = builder.createBitcast(buf.getPointer(), ppTy);
2427+
cir::EhSetjmp op =
2428+
cir::EhSetjmp::create(builder, loc, castBuf, /*builtin = */ false);
2429+
return RValue::get(op);
24272430
}
24282431

24292432
// C++ std:: builtins.

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4287,6 +4287,28 @@ mlir::LogicalResult CIRToLLVMEhTypeIdOpLowering::matchAndRewrite(
42874287
return mlir::success();
42884288
}
42894289

4290+
mlir::LogicalResult CIRToLLVMEhSetjmpOpLowering::matchAndRewrite(
4291+
cir::EhSetjmp op, OpAdaptor adaptor,
4292+
mlir::ConversionPatternRewriter &rewriter) const {
4293+
mlir::Type returnType = typeConverter->convertType(op.getType());
4294+
if (op.getIsBuiltin()) {
4295+
mlir::LLVM::CallIntrinsicOp newOp =
4296+
createCallLLVMIntrinsicOp(rewriter, op.getLoc(), "llvm.eh.sjlj.setjmp",
4297+
returnType, adaptor.getEnv());
4298+
rewriter.replaceOp(op, newOp);
4299+
return mlir::success();
4300+
}
4301+
4302+
StringRef fnName = "_setjmp";
4303+
auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());
4304+
auto fnType = mlir::LLVM::LLVMFunctionType::get(returnType, llvmPtrTy,
4305+
/*isVarArg=*/false);
4306+
getOrCreateLLVMFuncOp(rewriter, op, fnName, fnType);
4307+
rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(op, returnType, fnName,
4308+
adaptor.getEnv());
4309+
return mlir::success();
4310+
}
4311+
42904312
mlir::LogicalResult CIRToLLVMCatchParamOpLowering::matchAndRewrite(
42914313
cir::CatchParamOp op, OpAdaptor adaptor,
42924314
mlir::ConversionPatternRewriter &rewriter) const {
@@ -4530,6 +4552,7 @@ void populateCIRToLLVMConversionPatterns(
45304552
CIRToLLVMDerivedClassAddrOpLowering,
45314553
CIRToLLVMEhInflightOpLowering,
45324554
CIRToLLVMEhTypeIdOpLowering,
4555+
CIRToLLVMEhSetjmpOpLowering,
45334556
CIRToLLVMExpectOpLowering,
45344557
CIRToLLVMExtractMemberOpLowering,
45354558
CIRToLLVMFrameAddrOpLowering,

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,6 +1220,16 @@ class CIRToLLVMEhTypeIdOpLowering
12201220
mlir::ConversionPatternRewriter &) const override;
12211221
};
12221222

1223+
class CIRToLLVMEhSetjmpOpLowering
1224+
: public mlir::OpConversionPattern<cir::EhSetjmp> {
1225+
public:
1226+
using mlir::OpConversionPattern<cir::EhSetjmp>::OpConversionPattern;
1227+
1228+
mlir::LogicalResult
1229+
matchAndRewrite(cir::EhSetjmp op, OpAdaptor,
1230+
mlir::ConversionPatternRewriter &) const override;
1231+
};
1232+
12231233
class CIRToLLVMCatchParamOpLowering
12241234
: public mlir::OpConversionPattern<cir::CatchParamOp> {
12251235
public:

clang/test/CIR/CodeGen/builtin-setjmp-longjmp.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
// RUN: %clang_cc1 -triple x86_64-unknown-linux -O2 -emit-llvm %s -o %t.ll
66
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
77
void test_setjmp(void *env) {
8-
98
// CIR-LABEL: test_setjmp
109
// CIR-SAME: [[ENV:%.*]]:
1110
// CIR-NEXT: [[ENV_ALLOCA:%[0-9]+]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>,
@@ -19,7 +18,7 @@ void test_setjmp(void *env) {
1918
// CIR-NEXT: [[TWO:%[0-9]+]] = cir.const #cir.int<2>
2019
// CIR-NEXT: [[GEP:%[0-9]+]] = cir.ptr_stride([[CAST]] : !cir.ptr<!cir.ptr<!void>>, [[TWO]] : !s32i),
2120
// CIR-NEXT: cir.store [[SS]], [[GEP]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
22-
// CIR-NEXT: [[SJ:%[0-9]+]] = cir.llvm.intrinsic "eh.sjlj.setjmp" [[CAST]]
21+
// CIR-NEXT: [[SJ:%[0-9]+]] = cir.eh.setjmp builtin [[CAST]] : (!cir.ptr<!cir.ptr<!void>>) -> !s32i
2322

2423

2524
// LLVM-LABEL: test_setjmp
@@ -44,14 +43,14 @@ void test_setjmp(void *env) {
4443

4544
extern int _setjmp(void *env);
4645
void test_setjmp2(void *env) {
47-
4846
// CIR-LABEL: test_setjmp2
49-
// CIR-SAME: [[ENV:%.*]]: !cir.ptr<!void>
50-
// CIR-NEXT: [[ENV_ALLOCA:%.*]] = cir.alloca
47+
// CIR-SAME: [[ENV:%.*]]:
48+
// CIR-NEXT: [[ENV_ALLOCA]] = cir.alloca
5149
// CIR-NEXT: cir.store [[ENV]], [[ENV_ALLOCA]]
52-
// CIR-NEXT: [[DEAD_GET_GLOBAL:%.*]] = cir.get_global @_setjmp
5350
// CIR-NEXT: [[ENV_LOAD:%.*]] = cir.load align(8) [[ENV_ALLOCA]]
54-
// CIR-NEXT: cir.call @_setjmp([[ENV_LOAD]])
51+
// CIR-NEXT: [[CAST:%.*]] = cir.cast(bitcast, [[ENV_LOAD]]
52+
// CIR-NEXT: cir.eh.setjmp [[CAST]] : (!cir.ptr<!cir.ptr<!void>>) -> !s32i
53+
5554

5655
// LLVM-LABEL: test_setjmp2
5756
// LLVM-SAME: (ptr{{.*}}[[ENV:%.*]])
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: cir-opt %s -cir-to-llvm -o %t.ll
2+
// RUN: FileCheck %s --input-file=%t.ll -check-prefix=MLIR
3+
!s32i = !cir.int<s, 32>
4+
!p32 = !cir.ptr<!s32i>
5+
6+
module {
7+
// MLIR: module {
8+
cir.func @test_setjmp(%arg0 : !p32) -> !s32i {
9+
10+
// MLIR: llvm.func @test_setjmp([[ARG0:%.*]]: !llvm.ptr) -> i32
11+
// MLIR-NEXT: [[RET:%.*]] = llvm.call_intrinsic "llvm.eh.sjlj.setjmp"([[ARG0]]) : (!llvm.ptr) -> i32
12+
// MLIR-NEXT: llvm.return [[RET:%.*]] : i32
13+
// MLIR-NEXT: }
14+
%0 = cir.eh.setjmp builtin %arg0 : (!p32) -> !s32i
15+
cir.return %0 : !s32i
16+
}
17+
cir.func @test_setjmp_2(%arg0 : !p32) -> !s32i {
18+
19+
// MLIR: llvm.func @test_setjmp_2([[ARG0:%.*]]: !llvm.ptr) -> i32
20+
// MLIR-NEXT: [[RET:%.*]] = llvm.call @_setjmp([[ARG0]]) : (!llvm.ptr) -> i32
21+
// MLIR-NEXT: llvm.return [[RET:%.*]] : i32
22+
// MLIR-NEXT: }
23+
%0 = cir.eh.setjmp %arg0 : (!p32) -> !s32i
24+
cir.return %0 : !s32i
25+
}
26+
// MLIR: }
27+
}
28+
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o - 2>&1 | FileCheck %s -check-prefix=BEFORE-LOWERING-PREPARE
2+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-lowering-prepare %s -o - 2>&1 | FileCheck %s -check-prefix=AFTER-LOWERING-PREPARE
3+
void test_setjmp(void *env) {
4+
// BEFORE-LOWERING-PREPARE-LABEL: test_setjmp
5+
// BEFORE-LOWERING-PREPARE-SAME: [[ENV:%.*]]:
6+
// BEFORE-LOWERING-PREPARE-NEXT: [[ENV_ALLOCA:%[0-9]+]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>,
7+
// BEFORE-LOWERING-PREPARE-NEXT: cir.store [[ENV]], [[ENV_ALLOCA]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
8+
// BEFORE-LOWERING-PREPARE-NEXT: [[ENV_LOAD:%[0-9]+]] = cir.load align(8) [[ENV_ALLOCA]]
9+
// BEFORE-LOWERING-PREPARE-NEXT: [[CAST:%[0-9]+]] = cir.cast(bitcast, [[ENV_LOAD]] : !cir.ptr<!void>), !cir.ptr<!cir.ptr<!void>>
10+
// BEFORE-LOWERING-PREPARE-NEXT: [[ZERO:%[0-9]+]] = cir.const #cir.int<0>
11+
// BEFORE-LOWERING-PREPARE-NEXT: [[FA:%[0-9]+]] = cir.frame_address([[ZERO]])
12+
// BEFORE-LOWERING-PREPARE-NEXT: cir.store [[FA]], [[CAST]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
13+
// BEFORE-LOWERING-PREPARE-NEXT: [[SS:%[0-9]+]] = cir.stack_save
14+
// BEFORE-LOWERING-PREPARE-NEXT: [[TWO:%[0-9]+]] = cir.const #cir.int<2>
15+
// BEFORE-LOWERING-PREPARE-NEXT: [[GEP:%[0-9]+]] = cir.ptr_stride([[CAST]] : !cir.ptr<!cir.ptr<!void>>, [[TWO]] : !s32i),
16+
// BEFORE-LOWERING-PREPARE-NEXT: cir.store [[SS]], [[GEP]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
17+
// BEFORE-LOWERING-PREPARE-NEXT: [[SJ:%[0-9]+]] = cir.eh.setjmp builtin [[CAST]] : (!cir.ptr<!cir.ptr<!void>>) -> !s32i
18+
19+
// AFTER-LOWERING-PREPARE-LABEL: test_setjmp
20+
// AFTER-LOWERING-PREPARE-SAME: [[ENV:%.*]]:
21+
// AFTER-LOWERING-PREPARE-NEXT: [[ENV_ALLOCA:%[0-9]+]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>,
22+
// AFTER-LOWERING-PREPARE-NEXT: cir.store [[ENV]], [[ENV_ALLOCA]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
23+
// AFTER-LOWERING-PREPARE-NEXT: [[ENV_LOAD:%[0-9]+]] = cir.load align(8) [[ENV_ALLOCA]]
24+
// AFTER-LOWERING-PREPARE-NEXT: [[CAST:%[0-9]+]] = cir.cast(bitcast, [[ENV_LOAD]] : !cir.ptr<!void>), !cir.ptr<!cir.ptr<!void>>
25+
// AFTER-LOWERING-PREPARE-NEXT: [[ZERO:%[0-9]+]] = cir.const #cir.int<0>
26+
// AFTER-LOWERING-PREPARE-NEXT: [[FA:%[0-9]+]] = cir.frame_address([[ZERO]])
27+
// AFTER-LOWERING-PREPARE-NEXT: cir.store [[FA]], [[CAST]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
28+
// AFTER-LOWERING-PREPARE-NEXT: [[SS:%[0-9]+]] = cir.stack_save
29+
// AFTER-LOWERING-PREPARE-NEXT: [[TWO:%[0-9]+]] = cir.const #cir.int<2>
30+
// AFTER-LOWERING-PREPARE-NEXT: [[GEP:%[0-9]+]] = cir.ptr_stride([[CAST]] : !cir.ptr<!cir.ptr<!void>>, [[TWO]] : !s32i),
31+
// AFTER-LOWERING-PREPARE-NEXT: cir.store [[SS]], [[GEP]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
32+
// AFTER-LOWERING-PREPARE-NEXT: [[SJ:%[0-9]+]] = cir.eh.setjmp builtin [[CAST]] : (!cir.ptr<!cir.ptr<!void>>) -> !s32i
33+
__builtin_setjmp(env);
34+
}
35+
36+
extern int _setjmp(void *env);
37+
void test_setjmp2(void *env) {
38+
// BEFORE-LOWERING-PREPARE-LABEL: test_setjmp2
39+
// BEFORE-LOWERING-PREPARE-SAME: [[ENV:%.*]]:
40+
// BEFORE-LOWERING-PREPARE-NEXT: [[ENV_ALLOCA:%.*]] = cir.alloca
41+
// BEFORE-LOWERING-PREPARE-NEXT: cir.store [[ENV]], [[ENV_ALLOCA]]
42+
// BEFORE-LOWERING-PREPARE-NEXT: [[ENV_LOAD:%.*]] = cir.load align(8) [[ENV_ALLOCA]]
43+
// BEFORE-LOWERING-PREPARE-NEXT: [[CAST:%.*]] = cir.cast(bitcast, [[ENV_LOAD]]
44+
// BEFORE-LOWERING-PREPARE-NEXT: cir.eh.setjmp [[CAST]] : (!cir.ptr<!cir.ptr<!void>>) -> !s32i
45+
46+
// AFTER-LOWERING-PREPARE-LABEL: test_setjmp2
47+
// AFTER-LOWERING-PREPARE-SAME: [[ENV:%.*]]:
48+
// AFTER-LOWERING-PREPARE-NEXT: [[ENV_ALLOCA:%.*]] = cir.alloca
49+
// AFTER-LOWERING-PREPARE-NEXT: cir.store [[ENV]], [[ENV_ALLOCA]]
50+
// AFTER-LOWERING-PREPARE-NEXT: [[ENV_LOAD:%.*]] = cir.load align(8) [[ENV_ALLOCA]]
51+
// AFTER-LOWERING-PREPARE-NEXT: [[CAST:%.*]] = cir.cast(bitcast, [[ENV_LOAD]]
52+
// AFTER-LOWERING-PREPARE-NEXT: cir.eh.setjmp [[CAST]] : (!cir.ptr<!cir.ptr<!void>>) -> !s32i
53+
_setjmp (env);
54+
}

0 commit comments

Comments
 (0)