[clang] 7edf569 - [CIR] Upstream support for setjmp & longjmp builtins (#178989)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 17 10:50:45 PST 2026
Author: Ayokunle Amodu
Date: 2026-02-17T10:50:40-08:00
New Revision: 7edf569ce6cbfcd3d3831f34230edeb1c3390a6a
URL: https://github.com/llvm/llvm-project/commit/7edf569ce6cbfcd3d3831f34230edeb1c3390a6a
DIFF: https://github.com/llvm/llvm-project/commit/7edf569ce6cbfcd3d3831f34230edeb1c3390a6a.diff
LOG: [CIR] Upstream support for setjmp & longjmp builtins (#178989)
This adds support in CIR for the setjmp & longjmp builtins.
Added:
clang/test/CIR/CodeGenBuiltins/builtin-setjmp-longjmp.c
Modified:
clang/include/clang/CIR/Dialect/IR/CIROps.td
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 7085580d99718..5da61e68ec40a 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -6372,6 +6372,57 @@ 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.
+
+ Examples:
+ ```mlir
+ %0 = cir.eh.setjmp %arg0 : (!cir.ptr<!cir.void>) -> !s32i
+ ```
+ }];
+ let arguments = (ins CIR_PointerType:$env);
+
+ let results = (outs CIR_SInt32:$res);
+
+ let assemblyFormat = [{
+ $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
+ }];
+}
+
//===----------------------------------------------------------------------===//
// Flattened EH Operations: EhInitiateOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index f1b472d4bedba..87c50585c1afb 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -1563,8 +1563,49 @@ 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 voidPtrTy = builder.getVoidPtrTy();
+ cir::PointerType ppTy = builder.getPointerTo(voidPtrTy);
+ Address castBuf = buf.withElementType(builder, voidPtrTy);
+
+ assert(!cir::MissingFeatures::emitCheckedInBoundsGEP());
+ if (getTarget().getTriple().isSystemZ()) {
+ cgm.errorNYI(e->getExprLoc(), "setjmp on SystemZ");
+ return {};
+ }
+
+ mlir::Value frameAddress =
+ cir::FrameAddrOp::create(builder, loc, voidPtrTy,
+ mlir::ValueRange{builder.getUInt32(0, loc)})
+ .getResult();
+
+ builder.createStore(loc, frameAddress, castBuf);
+
+ mlir::Value stacksave =
+ cir::StackSaveOp::create(builder, loc, voidPtrTy).getResult();
+ cir::PtrStrideOp stackSaveSlot = cir::PtrStrideOp::create(
+ builder, loc, ppTy, castBuf.getPointer(), builder.getSInt32(2, loc));
+ llvm::TypeSize voidPtrTySize =
+ cgm.getDataLayout().getTypeAllocSize(voidPtrTy);
+ CharUnits slotAlign = castBuf.getAlignment().alignmentAtOffset(
+ CharUnits().fromQuantity(2 * voidPtrTySize));
+ Address slotAddr = Address(stackSaveSlot, voidPtrTy, slotAlign);
+ builder.createStore(loc, stacksave, slotAddr);
+ auto op = cir::EhSetjmpOp::create(builder, loc, castBuf.getPointer());
+ 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);
+ cir::UnreachableOp::create(builder, 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 28b3454d20613..6d86688f75b6a 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -3853,6 +3853,25 @@ 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());
+ mlir::LLVM::CallIntrinsicOp newOp =
+ createCallLLVMIntrinsicOp(rewriter, op.getLoc(), "llvm.eh.sjlj.setjmp",
+ returnType, adaptor.getEnv());
+ rewriter.replaceOp(op, newOp);
+ 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
new file mode 100644
index 0000000000000..072d9c6531e47
--- /dev/null
+++ b/clang/test/CIR/CodeGenBuiltins/builtin-setjmp-longjmp.c
@@ -0,0 +1,63 @@
+// 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 align(8) [[FA]], [[CAST]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
+ // CIR-NEXT: [[SS:%[0-9]+]] = cir.stacksave
+ // 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 align(8) [[SS]], [[GEP]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
+ // CIR-NEXT: [[SJ:%[0-9]+]] = cir.eh.setjmp [[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]], align 8
+ // 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]], align 8
+ // 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]], align 8
+ // OGCG-NEXT: [[SS:%.*]] = {{.*}}@llvm.stacksave.p0()
+ // OGCG-NEXT: [[GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[ENV]], i64 16
+ // OGCG-NEXT: store ptr [[SS]], ptr [[GEP]], align 8
+ // OGCG-NEXT: @llvm.eh.sjlj.setjmp(ptr{{.*}}[[ENV]])
+ __builtin_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);
+}
More information about the cfe-commits
mailing list