Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -4490,6 +4490,35 @@ def CIR_TryOp : CIR_Op<"try",[
let hasLLVMLowering = false;
}

//===----------------------------------------------------------------------===//
// Exception related: EhInflightOp
//===----------------------------------------------------------------------===//

def CIR_EhInflightOp : CIR_Op<"eh.inflight_exception"> {
let summary = "Materialize the catch clause formal parameter";
let description = [{
`cir.eh.inflight_exception` returns two values:
- `exception_ptr`: The exception pointer for the inflight exception
- `type_id`: pointer to the exception object
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `type_id`: pointer to the exception object
- `type_id`: the type info index for the exception type

This operation is expected to be the first one basic blocks on the
exception path out of `cir.try_call` operations.
Comment on lines +4503 to +4504
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This operation is expected to be the first one basic blocks on the
exception path out of `cir.try_call` operations.
This operation is expected to be the first operation in the unwind
destination basic blocks of a `cir.try_call` operation.


The `cleanup` attribute indicates that clean up code might run before the
values produced by this operation are used to gather exception information.
Comment on lines +4506 to +4507
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The `cleanup` attribute indicates that clean up code might run before the
values produced by this operation are used to gather exception information.
The `cleanup` attribute indicates that clean up code must be run before the
values produced by this operation are used to dispatch the exception. This
cleanup code must be executed even if the exception is not caught.

This helps CIR to pass down more accurate information for LLVM lowering
to landingpads.
}];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add examples of operation.


let arguments = (ins UnitAttr:$cleanup,
OptionalAttr<FlatSymbolRefArrayAttr>:$sym_type_list);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
OptionalAttr<FlatSymbolRefArrayAttr>:$sym_type_list);
OptionalAttr<FlatSymbolRefArrayAttr>:$catch_type_list);

let results = (outs CIR_VoidPtrType:$exception_ptr, CIR_UInt32:$type_id);
let assemblyFormat = [{
(`cleanup` $cleanup^)?
($sym_type_list^)?
attr-dict
}];
Comment on lines +4515 to +4519
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add tests covering presence of cleanup and sym_type_list

}

//===----------------------------------------------------------------------===//
// Atomic operations
//===----------------------------------------------------------------------===//
Expand Down
82 changes: 82 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3002,6 +3002,88 @@ mlir::LogicalResult CIRToLLVMAllocExceptionOpLowering::matchAndRewrite(
return mlir::success();
}

static mlir::LLVM::LLVMStructType
getLLVMLandingPadStructTy(mlir::ConversionPatternRewriter &rewriter) {
// Create the landing pad type: struct { ptr, i32 }
mlir::MLIRContext *ctx = rewriter.getContext();
auto llvmPtr = mlir::LLVM::LLVMPointerType::get(ctx);
llvm::SmallVector<mlir::Type> structFields = {llvmPtr, rewriter.getI32Type()};
return mlir::LLVM::LLVMStructType::getLiteral(ctx, structFields);
}

mlir::LogicalResult CIRToLLVMEhInflightOpLowering::matchAndRewrite(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, either defer the lowering to a future PR or add a test.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a CIR -> LLVM test here

cir::EhInflightOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
auto llvmFn = op->getParentOfType<mlir::LLVM::LLVMFuncOp>();
assert(llvmFn && "expected LLVM function parent");
mlir::Block *entryBlock = &llvmFn.getRegion().front();
assert(entryBlock->isEntryBlock());

mlir::ArrayAttr symListAttr = op.getSymTypeListAttr();
mlir::SmallVector<mlir::Value, 4> symAddrs;

auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());
mlir::Location loc = op.getLoc();

// %landingpad = landingpad { ptr, i32 }
// Note that since llvm.landingpad has to be the first operation on the
// block, any needed value for its operands has to be added somewhere else.
if (symListAttr) {
// catch ptr @_ZTIi
// catch ptr @_ZTIPKc
for (mlir::Attribute attr : symListAttr) {
auto symAttr = cast<mlir::FlatSymbolRefAttr>(attr);
// Generate `llvm.mlir.addressof` for each symbol, and place those
// operations in the LLVM function entry basic block.
mlir::OpBuilder::InsertionGuard guard(rewriter);
rewriter.setInsertionPointToStart(entryBlock);
mlir::Value addrOp = mlir::LLVM::AddressOfOp::create(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems a bit strange that the LLVM landingpad op doesn't take flat symbol references. Won't this always be a global object?

rewriter, loc, llvmPtrTy, symAttr.getValue());
symAddrs.push_back(addrOp);
}
} else if (!op.getCleanup()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be useful to have a comment here explaining why we will never need to emit the catch-all handler if getCleanup() is true. (I believe it's because cleanup is never set when we have a catch-all handler because there is no case when we would unwind past the handler.)

// catch ptr null
mlir::OpBuilder::InsertionGuard guard(rewriter);
rewriter.setInsertionPointToStart(entryBlock);
mlir::Value nullOp = mlir::LLVM::ZeroOp::create(rewriter, loc, llvmPtrTy);
symAddrs.push_back(nullOp);
}

// %slot = extractvalue { ptr, i32 } %x, 0
// %selector = extractvalue { ptr, i32 } %x, 1
mlir::LLVM::LLVMStructType llvmLandingPadStructTy =
getLLVMLandingPadStructTy(rewriter);
auto landingPadOp = mlir::LLVM::LandingpadOp::create(
rewriter, loc, llvmLandingPadStructTy, symAddrs);

if (op.getCleanup())
landingPadOp.setCleanup(true);

mlir::Value slot =
mlir::LLVM::ExtractValueOp::create(rewriter, loc, landingPadOp, 0);
mlir::Value selector =
mlir::LLVM::ExtractValueOp::create(rewriter, loc, landingPadOp, 1);
rewriter.replaceOp(op, mlir::ValueRange{slot, selector});

// Landing pads are required to be in LLVM functions with personality
// attribute.
// TODO(cir): for now hardcode personality creation in order to start
// adding exception tests, once we annotate CIR with such information,
// change it to be in FuncOp lowering instead.
mlir::OpBuilder::InsertionGuard guard(rewriter);
// Insert personality decl before the current function.
rewriter.setInsertionPoint(llvmFn);
auto personalityFnTy =
mlir::LLVM::LLVMFunctionType::get(rewriter.getI32Type(), {},
/*isVarArg=*/true);
// Get or create `__gxx_personality_v0`
const StringRef fnName = "__gxx_personality_v0";
createLLVMFuncOpIfNotExist(rewriter, op, fnName, personalityFnTy);
llvmFn.setPersonality(fnName);

return mlir::success();
}

mlir::LogicalResult CIRToLLVMTrapOpLowering::matchAndRewrite(
cir::TrapOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
Expand Down
15 changes: 15 additions & 0 deletions clang/test/CIR/IR/eh-inflight.cir
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// RUN: cir-opt %s --verify-roundtrip | FileCheck %s

module {

cir.func dso_local @function_with_inflight_exception() {
%exception_ptr, %type_id = cir.eh.inflight_exception
cir.return
}

// CHECK: cir.func dso_local @function_with_inflight_exception() {
// CHECK: %exception_ptr, %type_id = cir.eh.inflight_exception
// CHECK: cir.return
// CHECK: }

}