diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 1e0ec41fdc9b..8f64f166d3a1 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -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) -> !s32i + + // Specify setjmp is not builtin. + %0 = cir.eh.setjmp %arg0 : (!cir.ptr) -> !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 //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 0820b5f9b54f..38b8cf3817c9 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -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"); @@ -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. diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 9b31ee09d562..ce8d1f3735bb 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -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(op, returnType, fnName, + adaptor.getEnv()); + return mlir::success(); +} + mlir::LogicalResult CIRToLLVMCatchParamOpLowering::matchAndRewrite( cir::CatchParamOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { @@ -4530,6 +4552,7 @@ void populateCIRToLLVMConversionPatterns( CIRToLLVMDerivedClassAddrOpLowering, CIRToLLVMEhInflightOpLowering, CIRToLLVMEhTypeIdOpLowering, + CIRToLLVMEhSetjmpOpLowering, CIRToLLVMExpectOpLowering, CIRToLLVMExtractMemberOpLowering, CIRToLLVMFrameAddrOpLowering, diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index 01bc7c12be6e..1f668894625f 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -1220,6 +1220,16 @@ class CIRToLLVMEhTypeIdOpLowering mlir::ConversionPatternRewriter &) const override; }; +class CIRToLLVMEhSetjmpOpLowering + : public mlir::OpConversionPattern { +public: + using mlir::OpConversionPattern::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::EhSetjmpOp 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 88aef46d2ecf..a0ff6792ef58 100644 --- a/clang/test/CIR/CodeGen/builtin-setjmp-longjmp.c +++ b/clang/test/CIR/CodeGen/builtin-setjmp-longjmp.c @@ -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, !cir.ptr>, @@ -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>, !s32i) -> !cir.ptr> // CIR-NEXT: cir.store [[SS]], [[GEP]] : !cir.ptr, !cir.ptr> - // CIR-NEXT: [[SJ:%[0-9]+]] = cir.llvm.intrinsic "eh.sjlj.setjmp" [[CAST]] + // CIR-NEXT: [[SJ:%[0-9]+]] = cir.eh.setjmp builtin [[CAST]] : (!cir.ptr>) -> !s32i // LLVM-LABEL: test_setjmp @@ -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 - // 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>) -> !s32i + // LLVM-LABEL: test_setjmp2 // LLVM-SAME: (ptr{{.*}}[[ENV:%.*]]) diff --git a/clang/test/CIR/Lowering/setjmp-longjmp.cir b/clang/test/CIR/Lowering/setjmp-longjmp.cir new file mode 100644 index 000000000000..627a573e5051 --- /dev/null +++ b/clang/test/CIR/Lowering/setjmp-longjmp.cir @@ -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 +!p32 = !cir.ptr + +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: } +} + diff --git a/clang/test/CIR/Transforms/setjmp-longjmp-lower.c b/clang/test/CIR/Transforms/setjmp-longjmp-lower.c new file mode 100644 index 000000000000..b76b3251cfae --- /dev/null +++ b/clang/test/CIR/Transforms/setjmp-longjmp-lower.c @@ -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, !cir.ptr>, + // BEFORE-LOWERING-PREPARE-NEXT: cir.store [[ENV]], [[ENV_ALLOCA]] : !cir.ptr, !cir.ptr> + // 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), !cir.ptr> + // 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, !cir.ptr> + // 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>, !s32i) -> !cir.ptr> + // BEFORE-LOWERING-PREPARE-NEXT: cir.store [[SS]], [[GEP]] : !cir.ptr, !cir.ptr> + // BEFORE-LOWERING-PREPARE-NEXT: [[SJ:%[0-9]+]] = cir.eh.setjmp builtin [[CAST]] : (!cir.ptr>) -> !s32i + + // AFTER-LOWERING-PREPARE-LABEL: test_setjmp + // AFTER-LOWERING-PREPARE-SAME: [[ENV:%.*]]: + // AFTER-LOWERING-PREPARE-NEXT: [[ENV_ALLOCA:%[0-9]+]] = cir.alloca !cir.ptr, !cir.ptr>, + // AFTER-LOWERING-PREPARE-NEXT: cir.store [[ENV]], [[ENV_ALLOCA]] : !cir.ptr, !cir.ptr> + // 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), !cir.ptr> + // 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, !cir.ptr> + // 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>, !s32i) -> !cir.ptr> + // AFTER-LOWERING-PREPARE-NEXT: cir.store [[SS]], [[GEP]] : !cir.ptr, !cir.ptr> + // AFTER-LOWERING-PREPARE-NEXT: [[SJ:%[0-9]+]] = cir.eh.setjmp builtin [[CAST]] : (!cir.ptr>) -> !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>) -> !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>) -> !s32i + _setjmp (env); +}