Skip to content

Commit f8393c7

Browse files
committed
[CIR] Upstream non-empty Try block with catch all
1 parent ff48353 commit f8393c7

File tree

8 files changed

+507
-17
lines changed

8 files changed

+507
-17
lines changed

clang/lib/CIR/CodeGen/CIRGenCall.cpp

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -465,12 +465,48 @@ static cir::CIRCallOpInterface
465465
emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
466466
cir::FuncType indirectFuncTy, mlir::Value indirectFuncVal,
467467
cir::FuncOp directFuncOp,
468-
const SmallVectorImpl<mlir::Value> &cirCallArgs,
468+
const SmallVectorImpl<mlir::Value> &cirCallArgs, bool isInvoke,
469469
const mlir::NamedAttrList &attrs) {
470470
CIRGenBuilderTy &builder = cgf.getBuilder();
471471

472472
assert(!cir::MissingFeatures::opCallSurroundingTry());
473-
assert(!cir::MissingFeatures::invokeOp());
473+
474+
if (isInvoke) {
475+
// This call can throw, few options:
476+
// - If this call does not have an associated cir.try, use the
477+
// one provided by InvokeDest,
478+
// - User written try/catch clauses require calls to handle
479+
// exceptions under cir.try.
480+
481+
// In OG, we build the landing pad for this scope. In CIR, we emit a
482+
// synthetic cir.try because this didn't come from code generating from a
483+
// try/catch in C++.
484+
assert(cgf.curLexScope && "expected scope");
485+
cir::TryOp tryOp = cgf.curLexScope->getClosestTryParent();
486+
if (!tryOp) {
487+
cgf.cgm.errorNYI(
488+
"emitCallLikeOp: call does not have an associated cir.try");
489+
return {};
490+
}
491+
492+
if (tryOp.getSynthetic()) {
493+
cgf.cgm.errorNYI("emitCallLikeOp: tryOp synthetic");
494+
return {};
495+
}
496+
497+
cir::CallOp callOpWithExceptions;
498+
if (indirectFuncTy) {
499+
cgf.cgm.errorNYI("emitCallLikeOp: indirect function type");
500+
return {};
501+
}
502+
503+
callOpWithExceptions =
504+
builder.createTryCallOp(callLoc, directFuncOp, cirCallArgs);
505+
506+
(void)cgf.getInvokeDest(tryOp);
507+
508+
return callOpWithExceptions;
509+
}
474510

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

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

667+
bool isInvoke = isInvokeDest();
631668
mlir::Location callLoc = loc;
632669
cir::CIRCallOpInterface theCall =
633670
emitCallLikeOp(*this, loc, indirectFuncTy, indirectFuncVal, directFuncOp,
634-
cirCallArgs, attrs);
671+
cirCallArgs, isInvoke, attrs);
635672

636673
if (callOp)
637674
*callOp = theCall;

clang/lib/CIR/CodeGen/CIRGenCleanup.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,8 @@ void *EHScopeStack::pushCleanup(CleanupKind kind, size_t size) {
147147

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

150-
EHCleanupScope *scope = new (buffer)
151-
EHCleanupScope(size, branchFixups.size(), innermostNormalCleanup);
150+
EHCleanupScope *scope = new (buffer) EHCleanupScope(
151+
size, branchFixups.size(), innermostNormalCleanup, innermostEHScope);
152152

153153
if (isNormalCleanup)
154154
innermostNormalCleanup = stable_begin();
@@ -188,10 +188,20 @@ void EHScopeStack::popCleanup() {
188188
}
189189
}
190190

191+
bool EHScopeStack::requiresLandingPad() const {
192+
for (stable_iterator si = getInnermostEHScope(); si != stable_end();) {
193+
// TODO(cir): Skip lifetime markers.
194+
assert(!cir::MissingFeatures::emitLifetimeMarkers());
195+
return true;
196+
}
197+
return false;
198+
}
199+
191200
EHCatchScope *EHScopeStack::pushCatch(unsigned numHandlers) {
192201
char *buffer = allocate(EHCatchScope::getSizeForNumHandlers(numHandlers));
193-
assert(!cir::MissingFeatures::innermostEHScope());
194-
EHCatchScope *scope = new (buffer) EHCatchScope(numHandlers);
202+
EHCatchScope *scope =
203+
new (buffer) EHCatchScope(numHandlers, innermostEHScope);
204+
innermostEHScope = stable_begin();
195205
return scope;
196206
}
197207

clang/lib/CIR/CodeGen/CIRGenCleanup.h

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,16 @@ struct CatchTypeInfo {
3030

3131
/// A protected scope for zero-cost EH handling.
3232
class EHScope {
33+
EHScopeStack::stable_iterator enclosingEHScope;
34+
3335
class CommonBitFields {
3436
friend class EHScope;
3537
unsigned kind : 3;
3638
};
3739
enum { NumCommonBits = 3 };
3840

41+
bool isScopeMayThrow;
42+
3943
protected:
4044
class CatchBitFields {
4145
friend class EHCatchScope;
@@ -79,16 +83,24 @@ class EHScope {
7983
public:
8084
enum Kind { Cleanup, Catch, Terminate, Filter };
8185

82-
EHScope(Kind kind) { commonBits.kind = kind; }
86+
EHScope(Kind kind, EHScopeStack::stable_iterator enclosingEHScope)
87+
: enclosingEHScope(enclosingEHScope) {
88+
commonBits.kind = kind;
89+
}
8390

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

8693
bool mayThrow() const {
8794
// Traditional LLVM codegen also checks for `!block->use_empty()`, but
8895
// in CIRGen the block content is not important, just used as a way to
8996
// signal `hasEHBranches`.
90-
assert(!cir::MissingFeatures::ehstackBranches());
91-
return false;
97+
return isScopeMayThrow;
98+
}
99+
100+
void setMayThrow(bool mayThrow) { isScopeMayThrow = mayThrow; }
101+
102+
EHScopeStack::stable_iterator getEnclosingEHScope() const {
103+
return enclosingEHScope;
92104
}
93105
};
94106

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

112124
/// The catch handler for this type.
113125
mlir::Region *region;
126+
127+
bool isCatchAll() const { return type.rtti == nullptr; }
114128
};
115129

116130
private:
117131
friend class EHScopeStack;
118132

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

135+
const Handler *getHandlers() const {
136+
return reinterpret_cast<const Handler *>(this + 1);
137+
}
138+
121139
public:
122140
static size_t getSizeForNumHandlers(unsigned n) {
123141
return sizeof(EHCatchScope) + n * sizeof(Handler);
124142
}
125143

126-
EHCatchScope(unsigned numHandlers) : EHScope(Catch) {
144+
EHCatchScope(unsigned numHandlers,
145+
EHScopeStack::stable_iterator enclosingEHScope)
146+
: EHScope(Catch, enclosingEHScope) {
127147
catchBits.numHandlers = numHandlers;
128148
assert(catchBits.numHandlers == numHandlers && "NumHandlers overflow?");
129149
}
@@ -136,6 +156,11 @@ class EHCatchScope : public EHScope {
136156
getHandlers()[i].region = region;
137157
}
138158

159+
const Handler &getHandler(unsigned i) const {
160+
assert(i < getNumHandlers());
161+
return getHandlers()[i];
162+
}
163+
139164
// Clear all handler blocks.
140165
// FIXME: it's better to always call clearHandlerBlocks in DTOR and have a
141166
// 'takeHandler' or some such function which removes ownership from the
@@ -144,6 +169,10 @@ class EHCatchScope : public EHScope {
144169
// The blocks are owned by TryOp, nothing to delete.
145170
}
146171

172+
using iterator = const Handler *;
173+
iterator begin() const { return getHandlers(); }
174+
iterator end() const { return getHandlers() + getNumHandlers(); }
175+
147176
static bool classof(const EHScope *scope) {
148177
return scope->getKind() == Catch;
149178
}
@@ -176,9 +205,10 @@ class alignas(EHScopeStack::ScopeStackAlignment) EHCleanupScope
176205
}
177206

178207
EHCleanupScope(unsigned cleanupSize, unsigned fixupDepth,
179-
EHScopeStack::stable_iterator enclosingNormal)
180-
: EHScope(EHScope::Cleanup), enclosingNormal(enclosingNormal),
181-
fixupDepth(fixupDepth) {
208+
EHScopeStack::stable_iterator enclosingNormal,
209+
EHScopeStack::stable_iterator enclosingEH)
210+
: EHScope(EHScope::Cleanup, enclosingEH),
211+
enclosingNormal(enclosingNormal), fixupDepth(fixupDepth) {
182212
// TODO(cir): When exception handling is upstreamed, isNormalCleanup and
183213
// isEHCleanup will be arguments to the constructor.
184214
cleanupBits.isNormalCleanup = true;
@@ -235,13 +265,45 @@ class EHScopeStack::iterator {
235265

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

268+
EHScope *operator->() const { return get(); }
238269
EHScope &operator*() const { return *get(); }
270+
271+
iterator &operator++() {
272+
size_t size;
273+
switch (get()->getKind()) {
274+
case EHScope::Catch:
275+
size = EHCatchScope::getSizeForNumHandlers(
276+
static_cast<const EHCatchScope *>(get())->getNumHandlers());
277+
break;
278+
279+
case EHScope::Filter:
280+
llvm_unreachable("EHScopeStack::iterator Filter");
281+
break;
282+
283+
case EHScope::Cleanup:
284+
llvm_unreachable("EHScopeStack::iterator Cleanup");
285+
break;
286+
287+
case EHScope::Terminate:
288+
llvm_unreachable("EHScopeStack::iterator Terminate");
289+
break;
290+
}
291+
ptr += llvm::alignTo(size, ScopeStackAlignment);
292+
return *this;
293+
}
294+
295+
bool operator==(iterator other) const { return ptr == other.ptr; }
296+
bool operator!=(iterator other) const { return ptr != other.ptr; }
239297
};
240298

241299
inline EHScopeStack::iterator EHScopeStack::begin() const {
242300
return iterator(startOfData);
243301
}
244302

303+
inline EHScopeStack::iterator EHScopeStack::end() const {
304+
return iterator(endOfBuffer);
305+
}
306+
245307
inline EHScopeStack::iterator
246308
EHScopeStack::find(stable_iterator savePoint) const {
247309
assert(savePoint.isValid() && "finding invalid savepoint");
@@ -254,7 +316,7 @@ inline void EHScopeStack::popCatch() {
254316
assert(!empty() && "popping exception stack when not empty");
255317

256318
EHCatchScope &scope = llvm::cast<EHCatchScope>(*begin());
257-
assert(!cir::MissingFeatures::innermostEHScope());
319+
innermostEHScope = scope.getEnclosingEHScope();
258320
deallocate(EHCatchScope::getSizeForNumHandlers(scope.getNumHandlers()));
259321
}
260322

0 commit comments

Comments
 (0)