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
43 changes: 40 additions & 3 deletions clang/lib/CIR/CodeGen/CIRGenCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -465,12 +465,48 @@ static cir::CIRCallOpInterface
emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
cir::FuncType indirectFuncTy, mlir::Value indirectFuncVal,
cir::FuncOp directFuncOp,
const SmallVectorImpl<mlir::Value> &cirCallArgs,
const SmallVectorImpl<mlir::Value> &cirCallArgs, bool isInvoke,
const mlir::NamedAttrList &attrs) {
CIRGenBuilderTy &builder = cgf.getBuilder();

assert(!cir::MissingFeatures::opCallSurroundingTry());
assert(!cir::MissingFeatures::invokeOp());

if (isInvoke) {
// This call can throw, few options:
// - If this call does not have an associated cir.try, use the
// one provided by InvokeDest,
// - User written try/catch clauses require calls to handle
// exceptions under cir.try.

// In OG, we build the landing pad for this scope. In CIR, we emit a
// synthetic cir.try because this didn't come from code generating from a
// try/catch in C++.
assert(cgf.curLexScope && "expected scope");
cir::TryOp tryOp = cgf.curLexScope->getClosestTryParent();
if (!tryOp) {
cgf.cgm.errorNYI(
"emitCallLikeOp: call does not have an associated cir.try");
return {};
}

if (tryOp.getSynthetic()) {
cgf.cgm.errorNYI("emitCallLikeOp: tryOp synthetic");
return {};
}

cir::CallOp callOpWithExceptions;
if (indirectFuncTy) {
cgf.cgm.errorNYI("emitCallLikeOp: indirect function type");
return {};
}

callOpWithExceptions =
builder.createTryCallOp(callLoc, directFuncOp, cirCallArgs);

(void)cgf.getInvokeDest(tryOp);

return callOpWithExceptions;
}

assert(builder.getInsertionBlock() && "expected valid basic block");

Expand Down Expand Up @@ -628,10 +664,11 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
indirectFuncVal = calleePtr->getResult(0);
}

bool isInvoke = isInvokeDest();
mlir::Location callLoc = loc;
cir::CIRCallOpInterface theCall =
emitCallLikeOp(*this, loc, indirectFuncTy, indirectFuncVal, directFuncOp,
cirCallArgs, attrs);
cirCallArgs, isInvoke, attrs);

if (callOp)
*callOp = theCall;
Expand Down
18 changes: 14 additions & 4 deletions clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ void *EHScopeStack::pushCleanup(CleanupKind kind, size_t size) {

assert(!cir::MissingFeatures::innermostEHScope());

EHCleanupScope *scope = new (buffer)
EHCleanupScope(size, branchFixups.size(), innermostNormalCleanup);
EHCleanupScope *scope = new (buffer) EHCleanupScope(
size, branchFixups.size(), innermostNormalCleanup, innermostEHScope);

if (isNormalCleanup)
innermostNormalCleanup = stable_begin();
Expand Down Expand Up @@ -188,10 +188,20 @@ void EHScopeStack::popCleanup() {
}
}

bool EHScopeStack::requiresLandingPad() const {
for (stable_iterator si = getInnermostEHScope(); si != stable_end();) {
// TODO(cir): Skip lifetime markers.
assert(!cir::MissingFeatures::emitLifetimeMarkers());
return true;
}
return false;
}

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

Expand Down
78 changes: 70 additions & 8 deletions clang/lib/CIR/CodeGen/CIRGenCleanup.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,16 @@ struct CatchTypeInfo {

/// A protected scope for zero-cost EH handling.
class EHScope {
EHScopeStack::stable_iterator enclosingEHScope;

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

bool isScopeMayThrow;

protected:
class CatchBitFields {
friend class EHCatchScope;
Expand Down Expand Up @@ -79,16 +83,24 @@ class EHScope {
public:
enum Kind { Cleanup, Catch, Terminate, Filter };

EHScope(Kind kind) { commonBits.kind = kind; }
EHScope(Kind kind, EHScopeStack::stable_iterator enclosingEHScope)
: enclosingEHScope(enclosingEHScope) {
commonBits.kind = kind;
}

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

bool mayThrow() 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;
return isScopeMayThrow;
}

void setMayThrow(bool mayThrow) { isScopeMayThrow = mayThrow; }

EHScopeStack::stable_iterator getEnclosingEHScope() const {
return enclosingEHScope;
}
};

Expand All @@ -111,19 +123,27 @@ class EHCatchScope : public EHScope {

/// The catch handler for this type.
mlir::Region *region;

bool isCatchAll() const { return type.rtti == nullptr; }
};

private:
friend class EHScopeStack;

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

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

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

EHCatchScope(unsigned numHandlers) : EHScope(Catch) {
EHCatchScope(unsigned numHandlers,
EHScopeStack::stable_iterator enclosingEHScope)
: EHScope(Catch, enclosingEHScope) {
catchBits.numHandlers = numHandlers;
assert(catchBits.numHandlers == numHandlers && "NumHandlers overflow?");
}
Expand All @@ -136,6 +156,11 @@ class EHCatchScope : public EHScope {
getHandlers()[i].region = region;
}

const Handler &getHandler(unsigned i) const {
assert(i < getNumHandlers());
return getHandlers()[i];
}

// 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
Expand All @@ -144,6 +169,10 @@ class EHCatchScope : public EHScope {
// The blocks are owned by TryOp, nothing to delete.
}

using iterator = const Handler *;
iterator begin() const { return getHandlers(); }
iterator end() const { return getHandlers() + getNumHandlers(); }

static bool classof(const EHScope *scope) {
return scope->getKind() == Catch;
}
Expand Down Expand Up @@ -176,9 +205,10 @@ class alignas(EHScopeStack::ScopeStackAlignment) EHCleanupScope
}

EHCleanupScope(unsigned cleanupSize, unsigned fixupDepth,
EHScopeStack::stable_iterator enclosingNormal)
: EHScope(EHScope::Cleanup), enclosingNormal(enclosingNormal),
fixupDepth(fixupDepth) {
EHScopeStack::stable_iterator enclosingNormal,
EHScopeStack::stable_iterator enclosingEH)
: EHScope(EHScope::Cleanup, enclosingEH),
enclosingNormal(enclosingNormal), fixupDepth(fixupDepth) {
// TODO(cir): When exception handling is upstreamed, isNormalCleanup and
// isEHCleanup will be arguments to the constructor.
cleanupBits.isNormalCleanup = true;
Expand Down Expand Up @@ -235,13 +265,45 @@ class EHScopeStack::iterator {

EHScope *get() const { return reinterpret_cast<EHScope *>(ptr); }

EHScope *operator->() const { return get(); }
EHScope &operator*() const { return *get(); }

iterator &operator++() {
size_t size;
switch (get()->getKind()) {
case EHScope::Catch:
size = EHCatchScope::getSizeForNumHandlers(
static_cast<const EHCatchScope *>(get())->getNumHandlers());
break;

case EHScope::Filter:
llvm_unreachable("EHScopeStack::iterator Filter");
break;

case EHScope::Cleanup:
llvm_unreachable("EHScopeStack::iterator Cleanup");
break;

case EHScope::Terminate:
llvm_unreachable("EHScopeStack::iterator Terminate");
break;
}
ptr += llvm::alignTo(size, ScopeStackAlignment);
return *this;
}

bool operator==(iterator other) const { return ptr == other.ptr; }
bool operator!=(iterator other) const { return ptr != other.ptr; }
};

inline EHScopeStack::iterator EHScopeStack::begin() const {
return iterator(startOfData);
}

inline EHScopeStack::iterator EHScopeStack::end() const {
return iterator(endOfBuffer);
}

inline EHScopeStack::iterator
EHScopeStack::find(stable_iterator savePoint) const {
assert(savePoint.isValid() && "finding invalid savepoint");
Expand All @@ -254,7 +316,7 @@ inline void EHScopeStack::popCatch() {
assert(!empty() && "popping exception stack when not empty");

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

Expand Down
Loading