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
15 changes: 15 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
Original file line number Diff line number Diff line change
Expand Up @@ -858,4 +858,19 @@ def CIR_TypeInfoAttr : CIR_Attr<"TypeInfo", "typeinfo", [TypedAttrInterface]> {
}];
}

//===----------------------------------------------------------------------===//
// CatAllAttr & CatchUnwindAttr
Copy link
Member

Choose a reason for hiding this comment

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

CatAllAttr -> CatchAllAttr

//===----------------------------------------------------------------------===//

// Represents the unwind region where unwind continues or
// the program std::terminate's.
def CIR_CatchUnwindAttr : CIR_UnitAttr<"CatchUnwind", "unwind"> {
Copy link
Member

Choose a reason for hiding this comment

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

Need to add testcase for this one

let storageType = [{ CatchUnwind }];
}

// Represents the catch_all region.
def CIR_CatchAllAttr : CIR_UnitAttr<"CatchAll", "all"> {
let storageType = [{ CatchAllAttr }];
}

#endif // CLANG_CIR_DIALECT_IR_CIRATTRS_TD
73 changes: 65 additions & 8 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -535,10 +535,9 @@ def CIR_StoreOp : CIR_Op<"store", [
// ReturnOp
//===----------------------------------------------------------------------===//

defvar CIR_ReturnableScopes = [
"FuncOp", "ScopeOp", "IfOp", "SwitchOp", "CaseOp",
"DoWhileOp", "WhileOp", "ForOp"
];
defvar CIR_ReturnableScopes = ["FuncOp", "ScopeOp", "IfOp", "SwitchOp",
"CaseOp", "DoWhileOp", "WhileOp", "ForOp",
"TryOp"];

def CIR_ReturnOp : CIR_Op<"return", [
ParentOneOf<CIR_ReturnableScopes>, Terminator
Expand Down Expand Up @@ -682,10 +681,9 @@ def CIR_ConditionOp : CIR_Op<"condition", [
// YieldOp
//===----------------------------------------------------------------------===//

defvar CIR_YieldableScopes = [
"ArrayCtor", "ArrayDtor", "CaseOp", "DoWhileOp", "ForOp", "GlobalOp", "IfOp",
"ScopeOp", "SwitchOp", "TernaryOp", "WhileOp"
];
defvar CIR_YieldableScopes = ["ArrayCtor", "ArrayDtor", "CaseOp", "DoWhileOp",
"ForOp", "GlobalOp", "IfOp", "ScopeOp",
"SwitchOp", "TernaryOp", "WhileOp", "TryOp"];

def CIR_YieldOp : CIR_Op<"yield", [
ReturnLike, Terminator, ParentOneOf<CIR_YieldableScopes>
Expand Down Expand Up @@ -4202,6 +4200,65 @@ def CIR_AllocExceptionOp : CIR_Op<"alloc.exception"> {
}];
}

//===----------------------------------------------------------------------===//
// TryOp
//===----------------------------------------------------------------------===//

def CIR_TryOp : CIR_Op<"try",[
DeclareOpInterfaceMethods<RegionBranchOpInterface>,
RecursivelySpeculatable, AutomaticAllocationScope, NoRegionArguments
]> {
let summary = "C++ try block";
let description = [{
Holds the lexical scope of `try {}`. Note that resources used on catch
clauses are usually allocated in the same parent as `cir.try`.

`synthetic`: use `cir.try` to represent try/catches not originally
present in the source code (e.g. `g = new Class` under `-fexceptions`).

`cleanup`: signal to targets (LLVM for now) that this try/catch, needs
to specially tag their landing pads as needing "cleanup".

Example:

```mlir
%0 = cir.alloc.exception 16 -> !cir.ptr<!some_record>
%1 = cir.get_global @d2 : !cir.ptr<!some_record>
cir.try synthetic cleanup {
cir.call exception @_ZN7test2_DC1ERKS_(%0, %1)
: (!cir.ptr<!some_record>, !cir.ptr<!some_record>) -> () cleanup {
%2 = cir.cast bitcast %0 : !cir.ptr<!some_record> -> !cir.ptr<!void>
cir.free.exception %2
cir.yield
}
...
}
```
}];

let arguments = (ins UnitAttr:$synthetic, UnitAttr:$cleanup,
OptionalAttr<ArrayAttr>:$catch_types);
let regions = (region AnyRegion:$try_region,
VariadicRegion<AnyRegion>:$catch_regions);

let assemblyFormat = [{
(`synthetic` $synthetic^)?
(`cleanup` $cleanup^)?
$try_region
custom<CatchRegions>($catch_regions, $catch_types)
attr-dict
}];

// Everything already covered elsewhere.
let builders = [OpBuilder<(ins
"llvm::function_ref<void(mlir::OpBuilder &, "
"mlir::Location)>":$tryBuilder,
"llvm::function_ref<void(mlir::OpBuilder &, mlir::Location, "
"mlir::OperationState &)>":$catchBuilder)>];

let hasLLVMLowering = false;
}

//===----------------------------------------------------------------------===//
// Atomic operations
//===----------------------------------------------------------------------===//
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ CIRGenCXXABI::AddedStructorArgCounts CIRGenCXXABI::addImplicitConstructorArgs(
addedArgs.suffix.size());
}

CatchTypeInfo CIRGenCXXABI::getCatchAllTypeInfo() {
return CatchTypeInfo{nullptr, 0};
}

void CIRGenCXXABI::buildThisParam(CIRGenFunction &cgf,
FunctionArgList &params) {
const auto *md = cast<CXXMethodDecl>(cgf.curGD.getDecl());
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenCXXABI.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#define LLVM_CLANG_LIB_CIR_CIRGENCXXABI_H

#include "CIRGenCall.h"
#include "CIRGenCleanup.h"
#include "CIRGenFunction.h"
#include "CIRGenModule.h"

Expand Down Expand Up @@ -147,6 +148,8 @@ class CIRGenCXXABI {
/// Loads the incoming C++ this pointer as it was passed by the caller.
mlir::Value loadIncomingCXXThis(CIRGenFunction &cgf);

virtual CatchTypeInfo getCatchAllTypeInfo();

/// Emit constructor variants required by this ABI.
virtual void emitCXXConstructors(const clang::CXXConstructorDecl *d) = 0;

Expand Down
7 changes: 7 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@ void EHScopeStack::popCleanup() {
assert(!cir::MissingFeatures::ehCleanupBranchFixups());
}

EHCatchScope *EHScopeStack::pushCatch(unsigned numHandlers) {
char *buffer = allocate(EHCatchScope::getSizeForNumHandlers(numHandlers));
assert(!cir::MissingFeatures::innermostEHScope());
EHCatchScope *scope = new (buffer) EHCatchScope(numHandlers);
return scope;
}

static void emitCleanup(CIRGenFunction &cgf, EHScopeStack::Cleanup *cleanup) {
// Ask the cleanup to emit itself.
assert(cgf.haveInsertPoint() && "expected insertion point");
Expand Down
94 changes: 92 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenCleanup.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,36 @@
#ifndef CLANG_LIB_CIR_CODEGEN_CIRGENCLEANUP_H
#define CLANG_LIB_CIR_CODEGEN_CIRGENCLEANUP_H

#include "Address.h"
#include "EHScopeStack.h"
#include "mlir/IR/Value.h"
#include "mlir/IR/BuiltinAttributeInterfaces.h"
#include "clang/CIR/MissingFeatures.h"

namespace clang::CIRGen {

/// The MS C++ ABI needs a pointer to RTTI data plus some flags to describe the
/// type of a catch handler, so we use this wrapper.
struct CatchTypeInfo {
mlir::TypedAttr rtti;
unsigned flags;
};

/// A protected scope for zero-cost EH handling.
class EHScope {

class CommonBitFields {
friend class EHScope;
unsigned kind : 3;
};
enum { NumCommonBits = 3 };

protected:
class CatchBitFields {
friend class EHCatchScope;
unsigned : NumCommonBits;

Copy link
Member

Choose a reason for hiding this comment

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

Remove newline

unsigned numHandlers : 32 - NumCommonBits;
};

class CleanupBitFields {
friend class EHCleanupScope;
unsigned : NumCommonBits;
Expand Down Expand Up @@ -58,6 +73,7 @@ class EHScope {

union {
CommonBitFields commonBits;
CatchBitFields catchBits;
CleanupBitFields cleanupBits;
};

Expand All @@ -67,6 +83,72 @@ class EHScope {
EHScope(Kind kind) { commonBits.kind = kind; }

Kind getKind() const { return static_cast<Kind>(commonBits.kind); }

bool hasEHBranches() const {
// Traditional LLVM codegen also checks for `!block->use_empty()`, but
// in CIRGen the block content is not important, just used as a way to
// signal `hasEHBranches`.
assert(!cir::MissingFeatures::ehstackBranches());
return false;
}
};

/// A scope which attempts to handle some, possibly all, types of
/// exceptions.
///
/// Objective C \@finally blocks are represented using a cleanup scope
/// after the catch scope.

class EHCatchScope : public EHScope {
// In effect, we have a flexible array member
// Handler Handlers[0];
// But that's only standard in C99, not C++, so we have to do
// annoying pointer arithmetic instead.

public:
struct Handler {
/// A type info value, or null (C++ null, not an LLVM null pointer)
/// for a catch-all.
CatchTypeInfo type;

/// The catch handler for this type.
mlir::Block *block;
};

private:
friend class EHScopeStack;

Handler *getHandlers() { return reinterpret_cast<Handler *>(this + 1); }

public:
static size_t getSizeForNumHandlers(unsigned n) {
return sizeof(EHCatchScope) + n * sizeof(Handler);
}

EHCatchScope(unsigned numHandlers) : EHScope(Catch) {
catchBits.numHandlers = numHandlers;
assert(catchBits.numHandlers == numHandlers && "NumHandlers overflow?");
}

unsigned getNumHandlers() const { return catchBits.numHandlers; }

void setHandler(unsigned i, CatchTypeInfo type, mlir::Block *block) {
assert(i < getNumHandlers());
getHandlers()[i].type = type;
getHandlers()[i].block = block;
}

// Clear all handler blocks.
// FIXME: it's better to always call clearHandlerBlocks in DTOR and have a
// 'takeHandler' or some such function which removes ownership from the
// EHCatchScope object if the handlers should live longer than EHCatchScope.
void clearHandlerBlocks() {
// The blocks are owned by TryOp, nothing to delete.
}

static bool classof(const EHScope *scope) {
return scope->getKind() == Catch;
}
};

/// A cleanup scope which generates the cleanup blocks lazily.
Expand Down Expand Up @@ -147,5 +229,13 @@ EHScopeStack::find(stable_iterator savePoint) const {
return iterator(endOfBuffer - savePoint.size);
}

inline void EHScopeStack::popCatch() {
assert(!empty() && "popping exception stack when not empty");

EHCatchScope &scope = llvm::cast<EHCatchScope>(*begin());
assert(!cir::MissingFeatures::innermostEHScope());
deallocate(EHCatchScope::getSizeForNumHandlers(scope.getNumHandlers()));
}

} // namespace clang::CIRGen
#endif // CLANG_LIB_CIR_CODEGEN_CIRGENCLEANUP_H
Loading