[CIR] Upstream support for setjmp & longjmp builtins (#178989)
This adds support in CIR for the setjmp & longjmp builtins.
This commit is contained in:
parent
e09a587440
commit
7edf569ce6
@ -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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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 {
|
||||
|
||||
63
clang/test/CIR/CodeGenBuiltins/builtin-setjmp-longjmp.c
Normal file
63
clang/test/CIR/CodeGenBuiltins/builtin-setjmp-longjmp.c
Normal file
@ -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);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user