https://github.com/ayokunle321 updated https://github.com/llvm/llvm-project/pull/178989
>From eb74487e33c59bb283717e99f92f04665b17ae08 Mon Sep 17 00:00:00 2001 From: Ayokunle Amodu <[email protected]> Date: Thu, 29 Jan 2026 09:55:50 -0700 Subject: [PATCH 1/5] add support for setjmp and longjmp builtins --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 58 +++++++++++++ clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 40 ++++++++- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 63 ++++++++++++++ .../test/CIR/CodeGen/builtin-setjmp-longjmp.c | 84 +++++++++++++++++++ clang/test/CIR/Lowering/setjmp-longjmp.cir | 36 ++++++++ .../CIR/Transforms/setjmp-longjmp-lower.c | 74 ++++++++++++++++ 6 files changed, 353 insertions(+), 2 deletions(-) create mode 100644 clang/test/CIR/CodeGen/builtin-setjmp-longjmp.c create mode 100644 clang/test/CIR/Lowering/setjmp-longjmp.cir create mode 100644 clang/test/CIR/Transforms/setjmp-longjmp-lower.c diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index ee84df93b4933..d32dcbd5cdf88 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -5895,6 +5895,64 @@ def CIR_EhTypeIdOp : CIR_Op<"eh.typeid", }]; } +//===----------------------------------------------------------------------===// +// Exception related: EhSetjmpOp +//===----------------------------------------------------------------------===// + +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 + }]; +} + +//===----------------------------------------------------------------------===// +// Exception related: EhLongjmpOp +//===----------------------------------------------------------------------===// + +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 + }]; +} + //===----------------------------------------------------------------------===// // Atomic operations //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 88d37d56fcd78..34d9cf5cda9c2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -1335,8 +1335,44 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, case Builtin::BI__builtin_eh_return: case Builtin::BI__builtin_unwind_init: case Builtin::BI__builtin_extend_pointer: - case Builtin::BI__builtin_setjmp: - case Builtin::BI__builtin_longjmp: + return errorBuiltinNYI(*this, e, builtinID); + case Builtin::BI__builtin_setjmp: { + 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); + + assert(!cir::MissingFeatures::emitCheckedInBoundsGEP()); + if (getTarget().getTriple().isSystemZ()) { + llvm_unreachable("SYSTEMZ NYI"); + } + + mlir::Value frameaddress = + cir::FrameAddrOp::create(builder, loc, builder.getVoidPtrTy(), + mlir::ValueRange{builder.getUInt32(0, loc)}) + .getResult(); + + builder.createStore(loc, frameaddress, Address(castBuf, buf.getAlignment())); + + mlir::Value stacksave = + cir::StackSaveOp::create(builder, loc, builder.getVoidPtrTy()) + .getResult(); + cir::PtrStrideOp stackSaveSlot = cir::PtrStrideOp::create( + builder, loc, ppTy, castBuf, builder.getSInt32(2, loc)); + builder.createStore(loc, stacksave, Address(stackSaveSlot, buf.getAlignment())); + auto op = + cir::EhSetjmpOp::create(builder, loc, castBuf, /*is_builtin=*/true); + return RValue::get(op); + } + 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: case Builtin::BI__sync_fetch_and_add: case Builtin::BI__sync_fetch_and_sub: diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 091489c404642..97f045e90c7cd 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -111,6 +111,39 @@ lowerCIRVisibilityToLLVMVisibility(cir::VisibilityKind visibilityKind) { } } +// Make sure the LLVM function we are about to create a call for actually +// exists, if not create one. Returns a function +void getOrCreateLLVMFuncOp(mlir::ConversionPatternRewriter &rewriter, + mlir::Operation *srcOp, llvm::StringRef fnName, + mlir::Type fnTy) { + if (!fnTy) { + srcOp->emitError("failed to materialize LLVM function type for ") << fnName; + return; + } + auto llvmFnTy = mlir::dyn_cast<mlir::LLVM::LLVMFunctionType>(fnTy); + if (!llvmFnTy) { + srcOp->emitError("expected LLVM function type for ") + << fnName << " but got " << fnTy; + return; + } + auto modOp = srcOp->getParentOfType<mlir::ModuleOp>(); + if (!modOp) { + srcOp->emitError("expected parent module when declaring ") << fnName; + return; + } + auto enclosingFnOp = srcOp->getParentOfType<mlir::LLVM::LLVMFuncOp>(); + if (!enclosingFnOp) { + srcOp->emitError("expected parent LLVM function when declaring ") << fnName; + return; + } + auto *sourceSymbol = mlir::SymbolTable::lookupSymbolIn(modOp, fnName); + if (!sourceSymbol) { + mlir::OpBuilder::InsertionGuard guard(rewriter); + rewriter.setInsertionPoint(enclosingFnOp); + mlir::LLVM::LLVMFuncOp::create(rewriter, srcOp->getLoc(), fnName, llvmFnTy); + } +} + /// Emits the value from memory as expected by its users. Should be called when /// the memory represetnation of a CIR type is not equal to its scalar /// representation. @@ -3613,6 +3646,36 @@ 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 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 CIRToLLVMTrapOpLowering::matchAndRewrite( cir::TrapOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { diff --git a/clang/test/CIR/CodeGen/builtin-setjmp-longjmp.c b/clang/test/CIR/CodeGen/builtin-setjmp-longjmp.c new file mode 100644 index 0000000000000..1cd348993463c --- /dev/null +++ b/clang/test/CIR/CodeGen/builtin-setjmp-longjmp.c @@ -0,0 +1,84 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux -O2 -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux -O2 -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM +// 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>>, + // 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: [[ZERO:%[0-9]+]] = cir.const #cir.int<0> + // CIR-NEXT: [[FA:%[0-9]+]] = cir.frame_address([[ZERO]]) + // CIR-NEXT: cir.store [[FA]], [[CAST]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>> + // CIR-NEXT: [[SS:%[0-9]+]] = cir.stack_save + // 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.eh.setjmp builtin [[CAST]] : (!cir.ptr<!cir.ptr<!void>>) -> !s32i + + + // LLVM-LABEL: test_setjmp + // LLVM-SAME: (ptr{{.*}}[[ENV:%.*]]) + // LLVM-NEXT: [[FA:%[0-9]+]] = {{.*}}@llvm.frameaddress.p0(i32 0) + // LLVM-NEXT: store ptr [[FA]], ptr [[ENV]] + // LLVM-NEXT: [[SS:%[0-9]+]] = {{.*}}@llvm.stacksave.p0() + // LLVM-NEXT: [[GEP:%[0-9]+]] = getelementptr i8, ptr [[ENV]], i64 16 + // LLVM-NEXT: store ptr [[SS]], ptr [[GEP]] + // LLVM-NEXT: @llvm.eh.sjlj.setjmp(ptr{{.*}}[[ENV]]) + + // OGCG-LABEL: test_setjmp + // OGCG-SAME: (ptr{{.*}}[[ENV:%.*]]) + // OGCG: [[FA:%.*]] = {{.*}}@llvm.frameaddress.p0(i32 0) + // OGCG-NEXT: store ptr [[FA]], ptr [[ENV]] + // OGCG-NEXT: [[SS:%.*]] = {{.*}}@llvm.stacksave.p0() + // OGCG-NEXT: [[GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[ENV]], i64 16 + // OGCG-NEXT: store ptr [[SS]], ptr [[GEP]] + // OGCG-NEXT: @llvm.eh.sjlj.setjmp(ptr{{.*}}[[ENV]]) + __builtin_setjmp(env); +} + +extern int _setjmp(void *env); +void test_setjmp2(void *env) { + // CIR-LABEL: test_setjmp2 + // CIR-SAME: [[ENV:%.*]]: + // CIR-NEXT: [[ENV_ALLOCA]] = cir.alloca + // CIR-NEXT: cir.store [[ENV]], [[ENV_ALLOCA]] + // CIR-NEXT: [[ENV_LOAD:%.*]] = cir.load align(8) [[ENV_ALLOCA]] + // 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:%.*]]) + // LLVM-NEXT: call i32 @_setjmp(ptr [[ENV]]) + // + // OGCG-LABEL: test_setjmp2 + // OGCG-SAME: (ptr{{.*}}[[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); +} \ No newline at end of file diff --git a/clang/test/CIR/Lowering/setjmp-longjmp.cir b/clang/test/CIR/Lowering/setjmp-longjmp.cir new file mode 100644 index 0000000000000..e7ee21926b533 --- /dev/null +++ b/clang/test/CIR/Lowering/setjmp-longjmp.cir @@ -0,0 +1,36 @@ +// 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 + } + 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 new file mode 100644 index 0000000000000..77dd98a3d6778 --- /dev/null +++ b/clang/test/CIR/Transforms/setjmp-longjmp-lower.c @@ -0,0 +1,74 @@ +// 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); +} +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); +} \ No newline at end of file >From c436f0589a10a3e6f881220c69d56b7be307e677 Mon Sep 17 00:00:00 2001 From: Ayokunle Amodu <[email protected]> Date: Fri, 30 Jan 2026 15:31:55 -0700 Subject: [PATCH 2/5] remove longjmp handling --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 32 +++--------------- clang/lib/CIR/CodeGen/CIRGenBuilder.h | 1 + clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 33 ++++++++++++------- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 8 ----- .../builtin-setjmp-longjmp.c | 21 ------------ clang/test/CIR/Lowering/setjmp-longjmp.cir | 9 ----- .../CIR/Transforms/setjmp-longjmp-lower.c | 20 ----------- 7 files changed, 27 insertions(+), 97 deletions(-) rename clang/test/CIR/{CodeGen => CodeGenBuiltins}/builtin-setjmp-longjmp.c (79%) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index d32dcbd5cdf88..82d733a535444 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3629,7 +3629,7 @@ def CIR_AddrOfReturnAddrOp : CIR_Op<"address_of_return_address"> { // StackSaveOp & StackRestoreOp //===----------------------------------------------------------------------===// -def CIR_StackSaveOp : CIR_Op<"stacksave"> { +def CIR_StackSaveOp : CIR_Op<"stack_save"> { let summary = "remembers the current state of the function stack"; let description = [{ Saves current state of the function stack. Returns a pointer to an opaque object @@ -3639,7 +3639,7 @@ def CIR_StackSaveOp : CIR_Op<"stacksave"> { This operation corresponds to LLVM intrinsic `stacksave`. ```mlir - %0 = cir.stacksave : <!u8i> + %0 = cir.stack_save : <!u8i> ``` }]; @@ -3651,14 +3651,14 @@ def CIR_StackRestoreOp : CIR_Op<"stackrestore"> { let summary = "restores the state of the function stack"; let description = [{ Restore the state of the function stack to the state it was - in when the corresponding cir.stacksave executed. + in when the corresponding cir.stack_save executed. This is used during the lowering of variable length array allocas. This operation corresponds to LLVM intrinsic `stackrestore`. ```mlir %0 = cir.alloca !cir.ptr<!u8i>, !cir.ptr<!cir.ptr<!u8i>>, ["saved_stack"] {alignment = 8 : i64} - %1 = cir.stacksave : <!u8i> + %1 = cir.stack_save : <!u8i> cir.store %1, %0 : !cir.ptr<!u8i>, !cir.ptr<!cir.ptr<!u8i>> %2 = cir.load %0 : !cir.ptr<!cir.ptr<!u8i>>, !cir.ptr<!u8i> cir.stackrestore %2 : !cir.ptr<!u8i> @@ -5929,30 +5929,6 @@ def CIR_EhSetjmpOp : CIR_Op<"eh.setjmp"> { }]; } -//===----------------------------------------------------------------------===// -// Exception related: EhLongjmpOp -//===----------------------------------------------------------------------===// - -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 - }]; -} - //===----------------------------------------------------------------------===// // Atomic operations //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index dedb369bf3f67..ab36b67995261 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -519,6 +519,7 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { return createAlignedLoad(loc, ty, ptr, align.getAsAlign()); } + using CIRBaseBuilderTy::createStore; cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst, bool isVolatile = false, mlir::IntegerAttr align = {}, diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 34d9cf5cda9c2..25b3eef652d96 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -1353,26 +1353,19 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, mlir::ValueRange{builder.getUInt32(0, loc)}) .getResult(); - builder.createStore(loc, frameaddress, Address(castBuf, buf.getAlignment())); + builder.createStore(loc, frameaddress, castBuf); mlir::Value stacksave = cir::StackSaveOp::create(builder, loc, builder.getVoidPtrTy()) .getResult(); cir::PtrStrideOp stackSaveSlot = cir::PtrStrideOp::create( builder, loc, ppTy, castBuf, builder.getSInt32(2, loc)); - builder.createStore(loc, stacksave, Address(stackSaveSlot, buf.getAlignment())); + builder.createStore(loc, stacksave, stackSaveSlot); auto op = cir::EhSetjmpOp::create(builder, loc, castBuf, /*is_builtin=*/true); return RValue::get(op); } - 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_longjmp: case Builtin::BI__builtin_launder: case Builtin::BI__sync_fetch_and_add: case Builtin::BI__sync_fetch_and_sub: @@ -1773,7 +1766,25 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, case Builtin::BI__abnormal_termination: case Builtin::BI_abnormal_termination: case Builtin::BI_setjmpex: - case Builtin::BI_setjmp: + return errorBuiltinNYI(*this, e, builtinID); + case Builtin::BI_setjmp: { + if (getTarget().getTriple().isOSMSVCRT() && e->getNumArgs() == 1 && + e->getArg(0)->getType()->isPointerType()) { + if (getTarget().getTriple().getArch() == llvm::Triple::x86) + llvm_unreachable("NYI setjmp on x86"); + else if (getTarget().getTriple().getArch() == llvm::Triple::aarch64){ + llvm_unreachable("NYI setjmp on aarch64"); + } + llvm_unreachable("NYI setjmp on generic MSVCRT"); + } + 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); + } case Builtin::BImove: case Builtin::BImove_if_noexcept: case Builtin::BIforward: diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 97f045e90c7cd..e8ca27241d245 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -3668,14 +3668,6 @@ 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 CIRToLLVMTrapOpLowering::matchAndRewrite( cir::TrapOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { diff --git a/clang/test/CIR/CodeGen/builtin-setjmp-longjmp.c b/clang/test/CIR/CodeGenBuiltins/builtin-setjmp-longjmp.c similarity index 79% rename from clang/test/CIR/CodeGen/builtin-setjmp-longjmp.c rename to clang/test/CIR/CodeGenBuiltins/builtin-setjmp-longjmp.c index 1cd348993463c..782f68e003774 100644 --- a/clang/test/CIR/CodeGen/builtin-setjmp-longjmp.c +++ b/clang/test/CIR/CodeGenBuiltins/builtin-setjmp-longjmp.c @@ -60,25 +60,4 @@ void test_setjmp2(void *env) { // OGCG-SAME: (ptr{{.*}}[[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); } \ No newline at end of file diff --git a/clang/test/CIR/Lowering/setjmp-longjmp.cir b/clang/test/CIR/Lowering/setjmp-longjmp.cir index e7ee21926b533..ff6551596a6bf 100644 --- a/clang/test/CIR/Lowering/setjmp-longjmp.cir +++ b/clang/test/CIR/Lowering/setjmp-longjmp.cir @@ -23,14 +23,5 @@ 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 77dd98a3d6778..1f7b8a52f4386 100644 --- a/clang/test/CIR/Transforms/setjmp-longjmp-lower.c +++ b/clang/test/CIR/Transforms/setjmp-longjmp-lower.c @@ -51,24 +51,4 @@ void test_setjmp2(void *env) { // 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); -} -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); } \ No newline at end of file >From d9e3c9ab5732e9f093159c9b83ff334184192b75 Mon Sep 17 00:00:00 2001 From: Ayokunle Amodu <[email protected]> Date: Fri, 30 Jan 2026 16:28:31 -0700 Subject: [PATCH 3/5] fix code format --- clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 25b3eef652d96..0b8f109f09ae5 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -1772,7 +1772,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, e->getArg(0)->getType()->isPointerType()) { if (getTarget().getTriple().getArch() == llvm::Triple::x86) llvm_unreachable("NYI setjmp on x86"); - else if (getTarget().getTriple().getArch() == llvm::Triple::aarch64){ + else if (getTarget().getTriple().getArch() == llvm::Triple::aarch64) { llvm_unreachable("NYI setjmp on aarch64"); } llvm_unreachable("NYI setjmp on generic MSVCRT"); >From 0e0494565150e6be81c12225e0f99c56ffbc47c5 Mon Sep 17 00:00:00 2001 From: Ayokunle Amodu <[email protected]> Date: Fri, 30 Jan 2026 16:42:10 -0700 Subject: [PATCH 4/5] fix code format --- clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 0b8f109f09ae5..7fee1a8495fc9 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -1347,7 +1347,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, if (getTarget().getTriple().isSystemZ()) { llvm_unreachable("SYSTEMZ NYI"); } - + mlir::Value frameaddress = cir::FrameAddrOp::create(builder, loc, builder.getVoidPtrTy(), mlir::ValueRange{builder.getUInt32(0, loc)}) >From 6abcae6d14d81aa7198eb580ecffd7b83a65f99b Mon Sep 17 00:00:00 2001 From: Ayokunle Amodu <[email protected]> Date: Fri, 30 Jan 2026 19:04:20 -0700 Subject: [PATCH 5/5] add support for longjmp --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 24 +++++++++++++++++++ clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 9 ++++++- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 8 +++++++ .../CodeGenBuiltins/builtin-setjmp-longjmp.c | 21 ++++++++++++++++ clang/test/CIR/Lowering/setjmp-longjmp.cir | 9 +++++++ .../CIR/Transforms/setjmp-longjmp-lower.c | 21 ++++++++++++++++ 6 files changed, 91 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 82d733a535444..ed7a213dc9624 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -5929,6 +5929,30 @@ def CIR_EhSetjmpOp : CIR_Op<"eh.setjmp"> { }]; } +//===----------------------------------------------------------------------===// +// Exception related: EhLongjmpOp +//===----------------------------------------------------------------------===// + +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 + }]; +} + //===----------------------------------------------------------------------===// // Atomic operations //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 7fee1a8495fc9..91b79c704b3bf 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -1365,7 +1365,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: + 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: case Builtin::BI__sync_fetch_and_add: case Builtin::BI__sync_fetch_and_sub: diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index e8ca27241d245..97f045e90c7cd 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -3668,6 +3668,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 CIRToLLVMTrapOpLowering::matchAndRewrite( cir::TrapOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-setjmp-longjmp.c b/clang/test/CIR/CodeGenBuiltins/builtin-setjmp-longjmp.c index 782f68e003774..1cd348993463c 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtin-setjmp-longjmp.c +++ b/clang/test/CIR/CodeGenBuiltins/builtin-setjmp-longjmp.c @@ -60,4 +60,25 @@ void test_setjmp2(void *env) { // OGCG-SAME: (ptr{{.*}}[[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); } \ No newline at end of file diff --git a/clang/test/CIR/Lowering/setjmp-longjmp.cir b/clang/test/CIR/Lowering/setjmp-longjmp.cir index ff6551596a6bf..e7ee21926b533 100644 --- a/clang/test/CIR/Lowering/setjmp-longjmp.cir +++ b/clang/test/CIR/Lowering/setjmp-longjmp.cir @@ -23,5 +23,14 @@ 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 1f7b8a52f4386..376e3d729b7f5 100644 --- a/clang/test/CIR/Transforms/setjmp-longjmp-lower.c +++ b/clang/test/CIR/Transforms/setjmp-longjmp-lower.c @@ -51,4 +51,25 @@ void test_setjmp2(void *env) { // 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); +} + +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); } \ No newline at end of file _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
