diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index cc40bf2fc291..57c6cd9171aa 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -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 + ``` + }]; + + let arguments = (ins CIR_PointerType:$env); + + let assemblyFormat = [{ + $env `:` qualified(type($env)) attr-dict + }]; +} + //===----------------------------------------------------------------------===// // CopyOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 192f2233fcd8..62520ca17107 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -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(loc); + return RValue::get(nullptr); + } case Builtin::BI__builtin_launder: { const clang::Expr *arg = E->getArg(0); clang::QualType argTy = arg->getType()->getPointeeType(); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 21b17142d8fe..7798ee5093bb 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -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 { @@ -4635,6 +4643,7 @@ void populateCIRToLLVMConversionPatterns( CIRToLLVMEhInflightOpLowering, CIRToLLVMEhTypeIdOpLowering, CIRToLLVMEhSetjmpOpLowering, + CIRToLLVMEhLongjmpOpLowering, CIRToLLVMExpectOpLowering, CIRToLLVMExtractMemberOpLowering, CIRToLLVMFrameAddrOpLowering, diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index f13c37106665..445249311996 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -1273,6 +1273,16 @@ class CIRToLLVMEhSetjmpOpLowering mlir::ConversionPatternRewriter &) const override; }; +class CIRToLLVMEhLongjmpOpLowering + : public mlir::OpConversionPattern { +public: + using mlir::OpConversionPattern::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::EhLongjmpOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + class CIRToLLVMCatchParamOpLowering : public mlir::OpConversionPattern { public: diff --git a/clang/test/CIR/CodeGen/builtin-setjmp-longjmp.c b/clang/test/CIR/CodeGen/builtin-setjmp-longjmp.c index b63f3a75da5a..2d96139c347f 100644 --- a/clang/test/CIR/CodeGen/builtin-setjmp-longjmp.c +++ b/clang/test/CIR/CodeGen/builtin-setjmp-longjmp.c @@ -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, !cir.ptr>, + // CIR-NEXT: cir.store [[ENV]], [[ENV_ALLOCA]] : !cir.ptr, !cir.ptr> + // CIR-NEXT: [[ENV_LOAD:%[0-9]+]] = cir.load align(8) [[ENV_ALLOCA]] + // CIR-NEXT: [[CAST:%[0-9]+]] = cir.cast bitcast [[ENV_LOAD]] : !cir.ptr -> !cir.ptr> + // CIR-NEXT: cir.eh.longjmp [[CAST]] : !cir.ptr> + // 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); +} diff --git a/clang/test/CIR/Lowering/setjmp-longjmp.cir b/clang/test/CIR/Lowering/setjmp-longjmp.cir index 627a573e5051..1a441ce494e0 100644 --- a/clang/test/CIR/Lowering/setjmp-longjmp.cir +++ b/clang/test/CIR/Lowering/setjmp-longjmp.cir @@ -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: } } diff --git a/clang/test/CIR/Transforms/setjmp-longjmp-lower.c b/clang/test/CIR/Transforms/setjmp-longjmp-lower.c index 883e3d6a0bf2..33b4643eb081 100644 --- a/clang/test/CIR/Transforms/setjmp-longjmp-lower.c +++ b/clang/test/CIR/Transforms/setjmp-longjmp-lower.c @@ -52,3 +52,23 @@ void test_setjmp2(void *env) { // AFTER-LOWERING-PREPARE-NEXT: cir.eh.setjmp [[CAST]] : (!cir.ptr>) -> !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> + // 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> + // AFTER-LOWERING-PREPARE-NEXT: cir.unreachable + __builtin_longjmp(env, 1); +}