[clang] Upstream support for setjmp & longjmp builtins (PR #178989)
Ayokunle Amodu via cfe-commits
cfe-commits at lists.llvm.org
Sat Jan 31 06:36:13 PST 2026
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 <ayokunle321 at gmail.com>
Date: Thu, 29 Jan 2026 09:55:50 -0700
Subject: [PATCH 1/6] 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 <ayokunle321 at gmail.com>
Date: Fri, 30 Jan 2026 15:31:55 -0700
Subject: [PATCH 2/6] 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 <ayokunle321 at gmail.com>
Date: Fri, 30 Jan 2026 16:28:31 -0700
Subject: [PATCH 3/6] 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 <ayokunle321 at gmail.com>
Date: Fri, 30 Jan 2026 16:42:10 -0700
Subject: [PATCH 4/6] 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 <ayokunle321 at gmail.com>
Date: Fri, 30 Jan 2026 19:04:20 -0700
Subject: [PATCH 5/6] 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
>From a264c437ad322901fb8fdcc16371e829a68f0c47 Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Sat, 31 Jan 2026 07:35:46 -0700
Subject: [PATCH 6/6] replace builder create method with op's create method
---
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 91b79c704b3bf..d5ea7820a2054 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -1370,7 +1370,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
mlir::Location loc = getLoc(e->getExprLoc());
cir::EhLongjmpOp::create(builder, loc, buf);
- builder.create<cir::UnreachableOp>(loc);
+ cir::UnreachableOp::create(builder, loc);
return RValue::get(nullptr);
}
case Builtin::BI__builtin_launder:
More information about the cfe-commits
mailing list