Skip to content

Commit 3d01d6e

Browse files
authored
[CIR] Upstream non-empty Try block with catch all (#165158)
Upstream support for try block and catch all block with a function call that may throw an exception. Issue llvm/llvm-project#154992
1 parent 74c4029 commit 3d01d6e

File tree

10 files changed

+414
-34
lines changed

10 files changed

+414
-34
lines changed

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

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -389,25 +389,6 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
389389
return createCallOp(loc, callee, cir::VoidType(), operands, attrs);
390390
}
391391

392-
cir::CallOp createTryCallOp(
393-
mlir::Location loc, mlir::SymbolRefAttr callee = mlir::SymbolRefAttr(),
394-
mlir::Type returnType = cir::VoidType(),
395-
mlir::ValueRange operands = mlir::ValueRange(),
396-
[[maybe_unused]] cir::SideEffect sideEffect = cir::SideEffect::All) {
397-
assert(!cir::MissingFeatures::opCallCallConv());
398-
assert(!cir::MissingFeatures::opCallSideEffect());
399-
return createCallOp(loc, callee, returnType, operands);
400-
}
401-
402-
cir::CallOp createTryCallOp(
403-
mlir::Location loc, cir::FuncOp callee, mlir::ValueRange operands,
404-
[[maybe_unused]] cir::SideEffect sideEffect = cir::SideEffect::All) {
405-
assert(!cir::MissingFeatures::opCallCallConv());
406-
assert(!cir::MissingFeatures::opCallSideEffect());
407-
return createTryCallOp(loc, mlir::SymbolRefAttr::get(callee),
408-
callee.getFunctionType().getReturnType(), operands);
409-
}
410-
411392
//===--------------------------------------------------------------------===//
412393
// Cast/Conversion Operators
413394
//===--------------------------------------------------------------------===//

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ struct MissingFeatures {
9494
static bool opFuncNoReturn() { return false; }
9595
static bool setFunctionAttributes() { return false; }
9696
static bool setLLVMFunctionFEnvAttributes() { return false; }
97+
static bool setFunctionPersonality() { return false; }
9798

9899
// CallOp handling
99100
static bool opCallAggregateArgs() { return false; }
@@ -334,6 +335,9 @@ struct MissingFeatures {
334335
static bool vtableRelativeLayout() { return false; }
335336
static bool weakRefReference() { return false; }
336337
static bool writebacks() { return false; }
338+
static bool msvcCXXPersonality() { return false; }
339+
static bool functionUsesSEHTry() { return false; }
340+
static bool nothrowAttr() { return false; }
337341

338342
// Missing types
339343
static bool dataMemberType() { return false; }
@@ -349,7 +353,6 @@ struct MissingFeatures {
349353
static bool awaitOp() { return false; }
350354
static bool callOp() { return false; }
351355
static bool ifOp() { return false; }
352-
static bool invokeOp() { return false; }
353356
static bool labelOp() { return false; }
354357
static bool ptrDiffOp() { return false; }
355358
static bool llvmLoweringPtrDiffConsidersPointee() { return false; }
@@ -359,6 +362,7 @@ struct MissingFeatures {
359362
static bool tryOp() { return false; }
360363
static bool vecTernaryOp() { return false; }
361364
static bool zextOp() { return false; }
365+
static bool catchParamOp() { return false; }
362366

363367
// Future CIR attributes
364368
static bool optInfoAttr() { return false; }

clang/lib/CIR/CodeGen/CIRGenCall.cpp

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -465,12 +465,47 @@ 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 may throw and requires catch and/or cleanup handling.
476+
// If this call does not appear within the `try` region of an existing
477+
// TryOp, we must create a synthetic TryOp to contain the call. This
478+
// happens when a call that may throw appears within a cleanup
479+
// scope.
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.createCallOp(callLoc, directFuncOp, cirCallArgs);
505+
506+
cgf.populateCatchHandlersIfRequired(tryOp);
507+
return callOpWithExceptions;
508+
}
474509

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

@@ -601,8 +636,6 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
601636
assert(!cir::MissingFeatures::opCallAttrs());
602637
cgm.constructAttributeList(callee.getAbstractInfo(), attrs);
603638

604-
assert(!cir::MissingFeatures::invokeOp());
605-
606639
cir::FuncType indirectFuncTy;
607640
mlir::Value indirectFuncVal;
608641
cir::FuncOp directFuncOp;
@@ -628,10 +661,17 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
628661
indirectFuncVal = calleePtr->getResult(0);
629662
}
630663

664+
assert(!cir::MissingFeatures::msvcCXXPersonality());
665+
assert(!cir::MissingFeatures::functionUsesSEHTry());
666+
assert(!cir::MissingFeatures::nothrowAttr());
667+
668+
bool cannotThrow = attrs.getNamed("nothrow").has_value();
669+
bool isInvoke = !cannotThrow && isCatchOrCleanupRequired();
670+
631671
mlir::Location callLoc = loc;
632672
cir::CIRCallOpInterface theCall =
633673
emitCallLikeOp(*this, loc, indirectFuncTy, indirectFuncVal, directFuncOp,
634-
cirCallArgs, attrs);
674+
cirCallArgs, isInvoke, attrs);
635675

636676
if (callOp)
637677
*callOp = theCall;

clang/lib/CIR/CodeGen/CIRGenCleanup.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,22 @@ void EHScopeStack::popCleanup() {
188188
}
189189
}
190190

191+
bool EHScopeStack::requiresCatchOrCleanup() const {
192+
for (stable_iterator si = getInnermostEHScope(); si != stable_end();) {
193+
if (auto *cleanup = dyn_cast<EHCleanupScope>(&*find(si))) {
194+
if (cleanup->isLifetimeMarker()) {
195+
// Skip lifetime markers and continue from the enclosing EH scope
196+
assert(!cir::MissingFeatures::emitLifetimeMarkers());
197+
continue;
198+
}
199+
}
200+
return true;
201+
}
202+
return false;
203+
}
204+
191205
EHCatchScope *EHScopeStack::pushCatch(unsigned numHandlers) {
192206
char *buffer = allocate(EHCatchScope::getSizeForNumHandlers(numHandlers));
193-
assert(!cir::MissingFeatures::innermostEHScope());
194207
EHCatchScope *scope =
195208
new (buffer) EHCatchScope(numHandlers, innermostEHScope);
196209
innermostEHScope = stable_begin();

clang/lib/CIR/CodeGen/CIRGenCleanup.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "CIRGenModule.h"
1919
#include "EHScopeStack.h"
2020
#include "mlir/IR/Value.h"
21+
#include "clang/AST/StmtCXX.h"
2122

2223
namespace clang::CIRGen {
2324

@@ -38,6 +39,8 @@ class EHScope {
3839
};
3940
enum { NumCommonBits = 3 };
4041

42+
bool scopeMayThrow;
43+
4144
protected:
4245
class CatchBitFields {
4346
friend class EHCatchScope;
@@ -92,10 +95,11 @@ class EHScope {
9295
// Traditional LLVM codegen also checks for `!block->use_empty()`, but
9396
// in CIRGen the block content is not important, just used as a way to
9497
// signal `hasEHBranches`.
95-
assert(!cir::MissingFeatures::ehstackBranches());
96-
return false;
98+
return scopeMayThrow;
9799
}
98100

101+
void setMayThrow(bool mayThrow) { scopeMayThrow = mayThrow; }
102+
99103
EHScopeStack::stable_iterator getEnclosingEHScope() const {
100104
return enclosingEHScope;
101105
}
@@ -121,6 +125,9 @@ class EHCatchScope : public EHScope {
121125
/// The catch handler for this type.
122126
mlir::Region *region;
123127

128+
/// The catch handler stmt.
129+
const CXXCatchStmt *stmt;
130+
124131
bool isCatchAll() const { return type.rtti == nullptr; }
125132
};
126133

@@ -147,10 +154,13 @@ class EHCatchScope : public EHScope {
147154

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

150-
void setHandler(unsigned i, CatchTypeInfo type, mlir::Region *region) {
157+
void setHandler(unsigned i, CatchTypeInfo type, mlir::Region *region,
158+
const CXXCatchStmt *stmt) {
151159
assert(i < getNumHandlers());
152-
getHandlers()[i].type = type;
153-
getHandlers()[i].region = region;
160+
Handler *handler = &getHandlers()[i];
161+
handler->type = type;
162+
handler->region = region;
163+
handler->stmt = stmt;
154164
}
155165

156166
const Handler &getHandler(unsigned i) const {
@@ -231,6 +241,8 @@ class alignas(EHScopeStack::ScopeStackAlignment) EHCleanupScope
231241
bool isActive() const { return cleanupBits.isActive; }
232242
void setActive(bool isActive) { cleanupBits.isActive = isActive; }
233243

244+
bool isLifetimeMarker() const { return cleanupBits.isLifetimeMarker; }
245+
234246
unsigned getFixupDepth() const { return fixupDepth; }
235247
EHScopeStack::stable_iterator getEnclosingNormalCleanup() const {
236248
return enclosingNormal;

0 commit comments

Comments
 (0)