Skip to content
20 changes: 20 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -4768,6 +4768,26 @@ def CIR_EhSetjmpOp : CIR_Op<"eh.setjmp"> {
}];
}

def CIR_EhLongjmpOp : CIR_Op<"eh.longjmp"> {
let summary = "CIR longjmp operation";
let description = [{
Restore the environment (e.g., stack pointer, instruction pointer,
signal mask, and other registers) at the time of setjmp() call, by using
the information saved in `env` by setjmp().

Examples:
```mlir
cir.eh.longjmp %arg0 : !cir.ptr<!cir.void>
```
}];

let arguments = (ins CIR_PointerType:$env);

let assemblyFormat = [{
$env `:` qualified(type($env)) attr-dict
}];
}

//===----------------------------------------------------------------------===//
// CopyOp
//===----------------------------------------------------------------------===//
Expand Down
10 changes: 8 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1963,8 +1963,14 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
cir::EhSetjmpOp::create(builder, loc, castBuf, /*is_builtin=*/true);
return RValue::get(op);
}
case Builtin::BI__builtin_longjmp:
llvm_unreachable("BI__builtin_longjmp NYI");
case Builtin::BI__builtin_longjmp: {
mlir::Value buf = emitScalarExpr(E->getArg(0));
mlir::Location loc = getLoc(E->getExprLoc());

cir::EhLongjmpOp::create(builder, loc, buf);
builder.create<cir::UnreachableOp>(loc);
return RValue::get(nullptr);
}
case Builtin::BI__builtin_launder: {
const clang::Expr *arg = E->getArg(0);
clang::QualType argTy = arg->getType()->getPointeeType();
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4331,6 +4331,14 @@ mlir::LogicalResult CIRToLLVMEhSetjmpOpLowering::matchAndRewrite(
return mlir::success();
}

mlir::LogicalResult CIRToLLVMEhLongjmpOpLowering::matchAndRewrite(
cir::EhLongjmpOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm.eh.sjlj.longjmp",
/*resultTy=*/{}, adaptor.getOperands());
return mlir::success();
}

mlir::LogicalResult CIRToLLVMCatchParamOpLowering::matchAndRewrite(
cir::CatchParamOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
Expand Down Expand Up @@ -4635,6 +4643,7 @@ void populateCIRToLLVMConversionPatterns(
CIRToLLVMEhInflightOpLowering,
CIRToLLVMEhTypeIdOpLowering,
CIRToLLVMEhSetjmpOpLowering,
CIRToLLVMEhLongjmpOpLowering,
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 @@ -1273,6 +1273,16 @@ class CIRToLLVMEhSetjmpOpLowering
mlir::ConversionPatternRewriter &) const override;
};

class CIRToLLVMEhLongjmpOpLowering
: public mlir::OpConversionPattern<cir::EhLongjmpOp> {
public:
using mlir::OpConversionPattern<cir::EhLongjmpOp>::OpConversionPattern;

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

class CIRToLLVMCatchParamOpLowering
: public mlir::OpConversionPattern<cir::CatchParamOp> {
public:
Expand Down
21 changes: 21 additions & 0 deletions clang/test/CIR/CodeGen/builtin-setjmp-longjmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,24 @@ void test_setjmp2(void *env) {
// OGCG: call i32 @_setjmp(ptr noundef [[ENV]])
_setjmp (env);
}

void test_longjmp(void *env) {
// CIR-LABEL: test_longjmp
// CIR-SAME: [[ENV:%.*]]:
// CIR-NEXT: [[ENV_ALLOCA:%[0-9]+]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>,
// CIR-NEXT: cir.store [[ENV]], [[ENV_ALLOCA]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
// CIR-NEXT: [[ENV_LOAD:%[0-9]+]] = cir.load align(8) [[ENV_ALLOCA]]
// CIR-NEXT: [[CAST:%[0-9]+]] = cir.cast bitcast [[ENV_LOAD]] : !cir.ptr<!void> -> !cir.ptr<!cir.ptr<!void>>
// CIR-NEXT: cir.eh.longjmp [[CAST]] : !cir.ptr<!cir.ptr<!void>>
// CIR-NEXT: cir.unreachable


// LLVM-LABEL: test_longjmp
// LLVM: @llvm.eh.sjlj.longjmp
// LLVM-NEXT: unreachable

// OGCG-LABEL: test_longjmp
// OGCG: @llvm.eh.sjlj.longjmp
// OGCG-NEXT: unreachable
__builtin_longjmp(env, 1);
}
9 changes: 9 additions & 0 deletions clang/test/CIR/Lowering/setjmp-longjmp.cir
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ module {
%0 = cir.eh.setjmp %arg0 : (!p32) -> !s32i
cir.return %0 : !s32i
}
cir.func @test_longjmp(%arg0 : !p32) {

// MLIR: llvm.func @test_longjmp([[ARG0:%.*]]: !llvm.ptr)
// MLIR-NEXT: llvm.call_intrinsic "llvm.eh.sjlj.longjmp"([[ARG0]]) : (!llvm.ptr) -> ()
// MLIR-NEXT: llvm.unreachable
// MLIR-NEXT: }
cir.eh.longjmp %arg0 : !p32
cir.unreachable
}
// MLIR: }
}

20 changes: 20 additions & 0 deletions clang/test/CIR/Transforms/setjmp-longjmp-lower.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,23 @@ void test_setjmp2(void *env) {
// AFTER-LOWERING-PREPARE-NEXT: cir.eh.setjmp [[CAST]] : (!cir.ptr<!cir.ptr<!void>>) -> !s32i
_setjmp (env);
}
void test_longjmp(void *env) {
// BEFORE-LOWERING-PREPARE-LABEL: test_longjmp
// 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.longjmp [[CAST]] : !cir.ptr<!cir.ptr<!void>>
// BEFORE-LOWERING-PREPARE-NEXT: cir.unreachable

// AFTER-LOWERING-PREPARE-LABEL: test_longjmp
// 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.longjmp [[CAST]] : !cir.ptr<!cir.ptr<!void>>
// AFTER-LOWERING-PREPARE-NEXT: cir.unreachable
__builtin_longjmp(env, 1);
}