Skip to content

Commit 0499eb8

Browse files
authored
[CIR] Upstream Re-Throw with no return (llvm#154994)
This change adds support for the throw op without sub expression and with noreturn Issue llvm#154992
1 parent ea3a3a8 commit 0499eb8

File tree

15 files changed

+404
-6
lines changed

15 files changed

+404
-6
lines changed

clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
#include "mlir/IR/Builders.h"
2121
#include "mlir/IR/BuiltinAttributes.h"
22-
#include "mlir/IR/BuiltinTypes.h"
2322
#include "mlir/IR/Location.h"
2423
#include "mlir/IR/Types.h"
2524

@@ -313,6 +312,25 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
313312
resOperands, attrs);
314313
}
315314

315+
cir::CallOp createTryCallOp(
316+
mlir::Location loc, mlir::SymbolRefAttr callee = mlir::SymbolRefAttr(),
317+
mlir::Type returnType = cir::VoidType(),
318+
mlir::ValueRange operands = mlir::ValueRange(),
319+
[[maybe_unused]] cir::SideEffect sideEffect = cir::SideEffect::All) {
320+
assert(!cir::MissingFeatures::opCallCallConv());
321+
assert(!cir::MissingFeatures::opCallSideEffect());
322+
return createCallOp(loc, callee, returnType, operands);
323+
}
324+
325+
cir::CallOp createTryCallOp(
326+
mlir::Location loc, cir::FuncOp callee, mlir::ValueRange operands,
327+
[[maybe_unused]] cir::SideEffect sideEffect = cir::SideEffect::All) {
328+
assert(!cir::MissingFeatures::opCallCallConv());
329+
assert(!cir::MissingFeatures::opCallSideEffect());
330+
return createTryCallOp(loc, mlir::SymbolRefAttr::get(callee),
331+
callee.getFunctionType().getReturnType(), operands);
332+
}
333+
316334
//===--------------------------------------------------------------------===//
317335
// Cast/Conversion Operators
318336
//===--------------------------------------------------------------------===//

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3864,4 +3864,63 @@ def CIR_VAArgOp : CIR_Op<"va_arg"> {
38643864
}];
38653865
}
38663866

3867+
//===----------------------------------------------------------------------===//
3868+
// ThrowOp
3869+
//===----------------------------------------------------------------------===//
3870+
3871+
def CIR_ThrowOp : CIR_Op<"throw"> {
3872+
let summary = "(Re)Throws an exception";
3873+
let description = [{
3874+
This operation is equivalent to either __cxa_throw or __cxa_rethrow,
3875+
depending on the arguments.
3876+
3877+
The absense of arguments for `cir.throw` means it rethrows.
3878+
3879+
For the no-rethrow version, it must have at least two operands, the RTTI
3880+
information, a pointer to the exception object (likely allocated via
3881+
`cir.alloc_exception`) and finally an optional dtor, which might run as
3882+
part of this operation.
3883+
3884+
Example:
3885+
3886+
```mlir
3887+
// re-throw;
3888+
cir.throw
3889+
3890+
// if (b == 0)
3891+
// throw "Division by zero condition!";
3892+
3893+
// Type info for char const*
3894+
cir.global "private" constant external @_ZTIPKc : !cir.ptr<!u8i>
3895+
cir.if %cond {
3896+
%exception_addr = cir.alloc_exception 8 -> !cir.ptr<!void>
3897+
...
3898+
// Store string addr for "Division by zero condition!"
3899+
cir.store %string_addr, %exception_addr : !cir.ptr<!s8i>,
3900+
!cir.ptr<!cir.ptr<!s8i>>
3901+
cir.throw %exception_addr : !cir.ptr<!cir.ptr<!u8i>>,
3902+
@_ZTIPKc
3903+
```
3904+
}];
3905+
3906+
let arguments = (ins
3907+
Optional<CIR_PointerType>:$exception_ptr,
3908+
OptionalAttr<FlatSymbolRefAttr>:$type_info,
3909+
OptionalAttr<FlatSymbolRefAttr>:$dtor
3910+
);
3911+
3912+
let assemblyFormat = [{
3913+
($exception_ptr^ `:` type($exception_ptr))?
3914+
(`,` $type_info^)?
3915+
(`,` $dtor^)?
3916+
attr-dict
3917+
}];
3918+
3919+
let extraClassDeclaration = [{
3920+
bool rethrows() { return getNumOperands() == 0; }
3921+
}];
3922+
3923+
let hasVerifier = 1;
3924+
}
3925+
38673926
#endif // CLANG_CIR_DIALECT_IR_CIROPS_TD

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ struct MissingFeatures {
9393
static bool opCallReturn() { return false; }
9494
static bool opCallArgEvaluationOrder() { return false; }
9595
static bool opCallCallConv() { return false; }
96+
static bool opCallSideEffect() { return false; }
9697
static bool opCallMustTail() { return false; }
9798
static bool opCallInAlloca() { return false; }
9899
static bool opCallAttrs() { return false; }

clang/lib/CIR/CodeGen/CIRGenCXXABI.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,11 @@ class CIRGenCXXABI {
5353
}
5454

5555
/// Emit the ABI-specific prolog for the function
56-
virtual void emitInstanceFunctionProlog(SourceLocation Loc,
56+
virtual void emitInstanceFunctionProlog(SourceLocation loc,
5757
CIRGenFunction &cgf) = 0;
5858

59+
virtual void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) = 0;
60+
5961
/// Get the type of the implicit "this" parameter used by a method. May return
6062
/// zero if no specific type is applicable, e.g. if the ABI expects the "this"
6163
/// parameter to point to some artificial offset in a complete object due to
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//===--- CIRGenException.cpp - Emit CIR Code for C++ exceptions -*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This contains code dealing with C++ exception related code generation.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "CIRGenCXXABI.h"
14+
#include "CIRGenFunction.h"
15+
16+
#include "clang/AST/StmtVisitor.h"
17+
18+
using namespace clang;
19+
using namespace clang::CIRGen;
20+
21+
void CIRGenFunction::emitCXXThrowExpr(const CXXThrowExpr *e) {
22+
const llvm::Triple &triple = getTarget().getTriple();
23+
if (cgm.getLangOpts().OpenMPIsTargetDevice &&
24+
(triple.isNVPTX() || triple.isAMDGCN())) {
25+
cgm.errorNYI("emitCXXThrowExpr OpenMP with NVPTX or AMDGCN Triples");
26+
return;
27+
}
28+
29+
if (const Expr *subExpr = e->getSubExpr()) {
30+
QualType throwType = subExpr->getType();
31+
if (throwType->isObjCObjectPointerType()) {
32+
cgm.errorNYI("emitCXXThrowExpr ObjCObjectPointerType");
33+
return;
34+
} else {
35+
cgm.errorNYI("emitCXXThrowExpr with subExpr");
36+
return;
37+
}
38+
} else {
39+
cgm.getCXXABI().emitRethrow(*this, /*isNoReturn=*/true);
40+
}
41+
}

clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,11 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
668668
return cgf.emitCXXNewExpr(e);
669669
}
670670

671+
mlir::Value VisitCXXThrowExpr(const CXXThrowExpr *e) {
672+
cgf.emitCXXThrowExpr(e);
673+
return {};
674+
}
675+
671676
/// Emit a conversion from the specified type to the specified destination
672677
/// type, both of which are CIR scalar types.
673678
/// TODO: do we need ScalarConversionOpts here? Should be done in another

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,6 +1143,8 @@ class CIRGenFunction : public CIRGenTypeCache {
11431143

11441144
RValue emitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *expr);
11451145

1146+
void emitCXXThrowExpr(const CXXThrowExpr *e);
1147+
11461148
void emitCtorPrologue(const clang::CXXConstructorDecl *ctor,
11471149
clang::CXXCtorType ctorType, FunctionArgList &args);
11481150

clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
5656
bool delegating, Address thisAddr,
5757
QualType thisTy) override;
5858

59+
void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override;
60+
5961
bool useThunkForDtorVariant(const CXXDestructorDecl *dtor,
6062
CXXDtorType dt) const override {
6163
// Itanium does not emit any destructor variant as an inline thunk.
@@ -352,6 +354,44 @@ void CIRGenItaniumCXXABI::emitDestructorCall(
352354
vttTy, nullptr);
353355
}
354356

357+
// The idea here is creating a separate block for the throw with an
358+
// `UnreachableOp` as the terminator. So, we branch from the current block
359+
// to the throw block and create a block for the remaining operations.
360+
static void insertThrowAndSplit(mlir::OpBuilder &builder, mlir::Location loc,
361+
mlir::Value exceptionPtr = {},
362+
mlir::FlatSymbolRefAttr typeInfo = {},
363+
mlir::FlatSymbolRefAttr dtor = {}) {
364+
mlir::Block *currentBlock = builder.getInsertionBlock();
365+
mlir::Region *region = currentBlock->getParent();
366+
367+
if (currentBlock->empty()) {
368+
cir::ThrowOp::create(builder, loc, exceptionPtr, typeInfo, dtor);
369+
cir::UnreachableOp::create(builder, loc);
370+
} else {
371+
mlir::Block *throwBlock = builder.createBlock(region);
372+
373+
cir::ThrowOp::create(builder, loc, exceptionPtr, typeInfo, dtor);
374+
cir::UnreachableOp::create(builder, loc);
375+
376+
builder.setInsertionPointToEnd(currentBlock);
377+
cir::BrOp::create(builder, loc, throwBlock);
378+
}
379+
380+
(void)builder.createBlock(region);
381+
}
382+
383+
void CIRGenItaniumCXXABI::emitRethrow(CIRGenFunction &cgf, bool isNoReturn) {
384+
// void __cxa_rethrow();
385+
if (isNoReturn) {
386+
CIRGenBuilderTy &builder = cgf.getBuilder();
387+
assert(cgf.currSrcLoc && "expected source location");
388+
mlir::Location loc = *cgf.currSrcLoc;
389+
insertThrowAndSplit(builder, loc);
390+
} else {
391+
cgm.errorNYI("emitRethrow with isNoReturn false");
392+
}
393+
}
394+
355395
CIRGenCXXABI *clang::CIRGen::CreateCIRGenItaniumCXXABI(CIRGenModule &cgm) {
356396
switch (cgm.getASTContext().getCXXABIKind()) {
357397
case TargetCXXABI::GenericItanium:

clang/lib/CIR/CodeGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ add_clang_library(clangCIR
2020
CIRGenBuiltin.cpp
2121
CIRGenDecl.cpp
2222
CIRGenDeclOpenACC.cpp
23+
CIRGenException.cpp
2324
CIRGenExpr.cpp
2425
CIRGenExprAggregate.cpp
2526
CIRGenExprComplex.cpp

clang/lib/CIR/Dialect/IR/CIRDialect.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2697,6 +2697,24 @@ ParseResult cir::InlineAsmOp::parse(OpAsmParser &parser,
26972697
return mlir::success();
26982698
}
26992699

2700+
//===----------------------------------------------------------------------===//
2701+
// ThrowOp
2702+
//===----------------------------------------------------------------------===//
2703+
2704+
mlir::LogicalResult cir::ThrowOp::verify() {
2705+
// For the no-rethrow version, it must have at least the exception pointer.
2706+
if (rethrows())
2707+
return success();
2708+
2709+
if (getNumOperands() != 0) {
2710+
if (getTypeInfo())
2711+
return success();
2712+
return emitOpError() << "'type_info' symbol attribute missing";
2713+
}
2714+
2715+
return failure();
2716+
}
2717+
27002718
//===----------------------------------------------------------------------===//
27012719
// TableGen'd op method definitions
27022720
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)