Skip to content
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
30 changes: 30 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -4703,6 +4703,36 @@ def CIR_EhTypeIdOp : CIR_Op<"eh.typeid",
}];
}

def CIR_EhSetjmpOp : CIR_Op<"eh.setjmp"> {
let summary = "CIR setjmp operation";
let description = [{
Saves call-site information (e.g., stack pointer, instruction
pointer, signal mask, and other registers) in memory at `env` for use by longjmp(). In this case,
setjmp() returns 0. Following a successful longjmp(), execution proceeds
from cir.eh.setjmp with the operation yielding a non-zero value.

The presence of the `builtin` attribute refers to the setjmp() function; the lack of the attribute refers
to the _setjmp() function.

Examples:
```mlir
// Specify setjmp is builtin.
%0 = cir.eh.setjmp builtin %arg0 : (!cir.ptr<!cir.void>) -> !s32i

// Specify setjmp is not builtin.
%0 = cir.eh.setjmp %arg0 : (!cir.ptr<!cir.void>) -> !s32i
```
}];
let arguments = (ins CIR_PointerType:$env, UnitAttr:$is_builtin);

let results = (outs CIR_SInt32:$res);

let assemblyFormat = [{
(`builtin` $is_builtin^)?
$env `:` functional-type($env, results) attr-dict
}];
}

//===----------------------------------------------------------------------===//
// CopyOp
//===----------------------------------------------------------------------===//
Expand Down
17 changes: 10 additions & 7 deletions clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1927,12 +1927,9 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
cir::PtrStrideOp stackSaveSlot = cir::PtrStrideOp::create(
builder, loc, ppTy, castBuf, builder.getSInt32(2, loc));
cir::StoreOp::create(builder, loc, stacksave, stackSaveSlot);
mlir::Value setjmpCall =
cir::LLVMIntrinsicCallOp::create(
builder, loc, builder.getStringAttr("eh.sjlj.setjmp"),
builder.getSInt32Ty(), mlir::ValueRange{castBuf})
.getResult();
return RValue::get(setjmpCall);
auto op =
cir::EhSetjmpOp::create(builder, loc, castBuf, /*is_builtin=*/true);
return RValue::get(op);
}
case Builtin::BI__builtin_longjmp:
llvm_unreachable("BI__builtin_longjmp NYI");
Expand Down Expand Up @@ -2434,7 +2431,13 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
llvm_unreachable("NYI setjmp on aarch64");
llvm_unreachable("NYI setjmp on generic MSVCRT");
}
break;
Address buf = emitPointerWithAlignment(E->getArg(0));
mlir::Location loc = getLoc(E->getExprLoc());
cir::PointerType ppTy = builder.getPointerTo(builder.getVoidPtrTy());
mlir::Value castBuf = builder.createBitcast(buf.getPointer(), ppTy);
auto op =
cir::EhSetjmpOp::create(builder, loc, castBuf, /*is_builtin = */ false);
return RValue::get(op);
}

// C++ std:: builtins.
Expand Down
23 changes: 23 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4287,6 +4287,28 @@ mlir::LogicalResult CIRToLLVMEhTypeIdOpLowering::matchAndRewrite(
return mlir::success();
}

mlir::LogicalResult CIRToLLVMEhSetjmpOpLowering::matchAndRewrite(
cir::EhSetjmpOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
mlir::Type returnType = typeConverter->convertType(op.getType());
if (op.getIsBuiltin()) {
mlir::LLVM::CallIntrinsicOp newOp =
createCallLLVMIntrinsicOp(rewriter, op.getLoc(), "llvm.eh.sjlj.setjmp",
returnType, adaptor.getEnv());
rewriter.replaceOp(op, newOp);
return mlir::success();
}

StringRef fnName = "_setjmp";
auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());
auto fnType = mlir::LLVM::LLVMFunctionType::get(returnType, llvmPtrTy,
/*isVarArg=*/false);
getOrCreateLLVMFuncOp(rewriter, op, fnName, fnType);
rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(op, returnType, fnName,
adaptor.getEnv());
return mlir::success();
}

mlir::LogicalResult CIRToLLVMCatchParamOpLowering::matchAndRewrite(
cir::CatchParamOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
Expand Down Expand Up @@ -4530,6 +4552,7 @@ void populateCIRToLLVMConversionPatterns(
CIRToLLVMDerivedClassAddrOpLowering,
CIRToLLVMEhInflightOpLowering,
CIRToLLVMEhTypeIdOpLowering,
CIRToLLVMEhSetjmpOpLowering,
CIRToLLVMExpectOpLowering,
CIRToLLVMExtractMemberOpLowering,
CIRToLLVMFrameAddrOpLowering,
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 @@ -1220,6 +1220,16 @@ class CIRToLLVMEhTypeIdOpLowering
mlir::ConversionPatternRewriter &) const override;
};

class CIRToLLVMEhSetjmpOpLowering
: public mlir::OpConversionPattern<cir::EhSetjmpOp> {
public:
using mlir::OpConversionPattern<cir::EhSetjmpOp>::OpConversionPattern;

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

class CIRToLLVMCatchParamOpLowering
: public mlir::OpConversionPattern<cir::CatchParamOp> {
public:
Expand Down
13 changes: 6 additions & 7 deletions clang/test/CIR/CodeGen/builtin-setjmp-longjmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux -O2 -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
void test_setjmp(void *env) {

// CIR-LABEL: test_setjmp
// CIR-SAME: [[ENV:%.*]]:
// CIR-NEXT: [[ENV_ALLOCA:%[0-9]+]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>,
Expand All @@ -19,7 +18,7 @@ void test_setjmp(void *env) {
// CIR-NEXT: [[TWO:%[0-9]+]] = cir.const #cir.int<2>
// CIR-NEXT: [[GEP:%[0-9]+]] = cir.ptr_stride [[CAST]], [[TWO]] : (!cir.ptr<!cir.ptr<!void>>, !s32i) -> !cir.ptr<!cir.ptr<!void>>
// CIR-NEXT: cir.store [[SS]], [[GEP]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
// CIR-NEXT: [[SJ:%[0-9]+]] = cir.llvm.intrinsic "eh.sjlj.setjmp" [[CAST]]
// CIR-NEXT: [[SJ:%[0-9]+]] = cir.eh.setjmp builtin [[CAST]] : (!cir.ptr<!cir.ptr<!void>>) -> !s32i


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

extern int _setjmp(void *env);
void test_setjmp2(void *env) {

// CIR-LABEL: test_setjmp2
// CIR-SAME: [[ENV:%.*]]: !cir.ptr<!void>
// CIR-NEXT: [[ENV_ALLOCA:%.*]] = cir.alloca
// CIR-SAME: [[ENV:%.*]]:
// CIR-NEXT: [[ENV_ALLOCA]] = cir.alloca
// CIR-NEXT: cir.store [[ENV]], [[ENV_ALLOCA]]
// CIR-NEXT: [[DEAD_GET_GLOBAL:%.*]] = cir.get_global @_setjmp
// CIR-NEXT: [[ENV_LOAD:%.*]] = cir.load align(8) [[ENV_ALLOCA]]
// CIR-NEXT: cir.call @_setjmp([[ENV_LOAD]])
// CIR-NEXT: [[CAST:%.*]] = cir.cast(bitcast, [[ENV_LOAD]]
// CIR-NEXT: cir.eh.setjmp [[CAST]] : (!cir.ptr<!cir.ptr<!void>>) -> !s32i


// LLVM-LABEL: test_setjmp2
// LLVM-SAME: (ptr{{.*}}[[ENV:%.*]])
Expand Down
28 changes: 28 additions & 0 deletions clang/test/CIR/Lowering/setjmp-longjmp.cir
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// RUN: cir-opt %s -cir-to-llvm -o %t.ll
// RUN: FileCheck %s --input-file=%t.ll -check-prefix=MLIR
!s32i = !cir.int<s, 32>
!p32 = !cir.ptr<!s32i>

module {
// MLIR: module {
cir.func @test_setjmp(%arg0 : !p32) -> !s32i {

// MLIR: llvm.func @test_setjmp([[ARG0:%.*]]: !llvm.ptr) -> i32
// MLIR-NEXT: [[RET:%.*]] = llvm.call_intrinsic "llvm.eh.sjlj.setjmp"([[ARG0]]) : (!llvm.ptr) -> i32
// MLIR-NEXT: llvm.return [[RET:%.*]] : i32
// MLIR-NEXT: }
%0 = cir.eh.setjmp builtin %arg0 : (!p32) -> !s32i
cir.return %0 : !s32i
}
cir.func @test_setjmp_2(%arg0 : !p32) -> !s32i {

// MLIR: llvm.func @test_setjmp_2([[ARG0:%.*]]: !llvm.ptr) -> i32
// MLIR-NEXT: [[RET:%.*]] = llvm.call @_setjmp([[ARG0]]) : (!llvm.ptr) -> i32
// MLIR-NEXT: llvm.return [[RET:%.*]] : i32
// MLIR-NEXT: }
%0 = cir.eh.setjmp %arg0 : (!p32) -> !s32i
cir.return %0 : !s32i
}
// MLIR: }
}

54 changes: 54 additions & 0 deletions clang/test/CIR/Transforms/setjmp-longjmp-lower.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// 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
// 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
void test_setjmp(void *env) {
// BEFORE-LOWERING-PREPARE-LABEL: test_setjmp
// BEFORE-LOWERING-PREPARE-SAME: [[ENV:%.*]]:
// BEFORE-LOWERING-PREPARE-NEXT: [[ENV_ALLOCA:%[0-9]+]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>,
// BEFORE-LOWERING-PREPARE-NEXT: cir.store [[ENV]], [[ENV_ALLOCA]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
// BEFORE-LOWERING-PREPARE-NEXT: [[ENV_LOAD:%[0-9]+]] = cir.load align(8) [[ENV_ALLOCA]]
// BEFORE-LOWERING-PREPARE-NEXT: [[CAST:%[0-9]+]] = cir.cast(bitcast, [[ENV_LOAD]] : !cir.ptr<!void>), !cir.ptr<!cir.ptr<!void>>
// BEFORE-LOWERING-PREPARE-NEXT: [[ZERO:%[0-9]+]] = cir.const #cir.int<0>
// BEFORE-LOWERING-PREPARE-NEXT: [[FA:%[0-9]+]] = cir.frame_address([[ZERO]])
// BEFORE-LOWERING-PREPARE-NEXT: cir.store [[FA]], [[CAST]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
// BEFORE-LOWERING-PREPARE-NEXT: [[SS:%[0-9]+]] = cir.stack_save
// BEFORE-LOWERING-PREPARE-NEXT: [[TWO:%[0-9]+]] = cir.const #cir.int<2>
// BEFORE-LOWERING-PREPARE-NEXT: [[GEP:%[0-9]+]] = cir.ptr_stride [[CAST]], [[TWO]] : (!cir.ptr<!cir.ptr<!void>>, !s32i) -> !cir.ptr<!cir.ptr<!void>>
// BEFORE-LOWERING-PREPARE-NEXT: cir.store [[SS]], [[GEP]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
// BEFORE-LOWERING-PREPARE-NEXT: [[SJ:%[0-9]+]] = cir.eh.setjmp builtin [[CAST]] : (!cir.ptr<!cir.ptr<!void>>) -> !s32i

// AFTER-LOWERING-PREPARE-LABEL: test_setjmp
// AFTER-LOWERING-PREPARE-SAME: [[ENV:%.*]]:
// AFTER-LOWERING-PREPARE-NEXT: [[ENV_ALLOCA:%[0-9]+]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>,
// AFTER-LOWERING-PREPARE-NEXT: cir.store [[ENV]], [[ENV_ALLOCA]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
// AFTER-LOWERING-PREPARE-NEXT: [[ENV_LOAD:%[0-9]+]] = cir.load align(8) [[ENV_ALLOCA]]
// AFTER-LOWERING-PREPARE-NEXT: [[CAST:%[0-9]+]] = cir.cast(bitcast, [[ENV_LOAD]] : !cir.ptr<!void>), !cir.ptr<!cir.ptr<!void>>
// AFTER-LOWERING-PREPARE-NEXT: [[ZERO:%[0-9]+]] = cir.const #cir.int<0>
// AFTER-LOWERING-PREPARE-NEXT: [[FA:%[0-9]+]] = cir.frame_address([[ZERO]])
// AFTER-LOWERING-PREPARE-NEXT: cir.store [[FA]], [[CAST]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
// AFTER-LOWERING-PREPARE-NEXT: [[SS:%[0-9]+]] = cir.stack_save
// AFTER-LOWERING-PREPARE-NEXT: [[TWO:%[0-9]+]] = cir.const #cir.int<2>
// AFTER-LOWERING-PREPARE-NEXT: [[GEP:%[0-9]+]] = cir.ptr_stride [[CAST]], [[TWO]] : (!cir.ptr<!cir.ptr<!void>>, !s32i) -> !cir.ptr<!cir.ptr<!void>>
// AFTER-LOWERING-PREPARE-NEXT: cir.store [[SS]], [[GEP]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
// AFTER-LOWERING-PREPARE-NEXT: [[SJ:%[0-9]+]] = cir.eh.setjmp builtin [[CAST]] : (!cir.ptr<!cir.ptr<!void>>) -> !s32i
__builtin_setjmp(env);
}

extern int _setjmp(void *env);
void test_setjmp2(void *env) {
// BEFORE-LOWERING-PREPARE-LABEL: test_setjmp2
// BEFORE-LOWERING-PREPARE-SAME: [[ENV:%.*]]:
// BEFORE-LOWERING-PREPARE-NEXT: [[ENV_ALLOCA:%.*]] = cir.alloca
// BEFORE-LOWERING-PREPARE-NEXT: cir.store [[ENV]], [[ENV_ALLOCA]]
// BEFORE-LOWERING-PREPARE-NEXT: [[ENV_LOAD:%.*]] = cir.load align(8) [[ENV_ALLOCA]]
// BEFORE-LOWERING-PREPARE-NEXT: [[CAST:%.*]] = cir.cast(bitcast, [[ENV_LOAD]]
// BEFORE-LOWERING-PREPARE-NEXT: cir.eh.setjmp [[CAST]] : (!cir.ptr<!cir.ptr<!void>>) -> !s32i

// AFTER-LOWERING-PREPARE-LABEL: test_setjmp2
// AFTER-LOWERING-PREPARE-SAME: [[ENV:%.*]]:
// AFTER-LOWERING-PREPARE-NEXT: [[ENV_ALLOCA:%.*]] = cir.alloca
// AFTER-LOWERING-PREPARE-NEXT: cir.store [[ENV]], [[ENV_ALLOCA]]
// AFTER-LOWERING-PREPARE-NEXT: [[ENV_LOAD:%.*]] = cir.load align(8) [[ENV_ALLOCA]]
// AFTER-LOWERING-PREPARE-NEXT: [[CAST:%.*]] = cir.cast(bitcast, [[ENV_LOAD]]
// AFTER-LOWERING-PREPARE-NEXT: cir.eh.setjmp [[CAST]] : (!cir.ptr<!cir.ptr<!void>>) -> !s32i
_setjmp (env);
}
Loading