Support else block in IR TryCatch node

try-else-support
A. R. Shajii 2025-03-31 10:10:34 -04:00
parent 59f5bbb73b
commit bcb39d0ddd
8 changed files with 48 additions and 10 deletions

View File

@ -279,7 +279,10 @@ void CFVisitor::visit(const ImperativeForFlow *v) {
void CFVisitor::visit(const TryCatchFlow *v) {
auto *routeBlock = graph->newBlock("tcRoute");
auto *end = graph->newBlock("tcEnd");
analyze::dataflow::CFBlock *else_ = nullptr;
analyze::dataflow::CFBlock *finally = nullptr;
if (v->getElse())
else_ = graph->newBlock("tcElse");
if (v->getFinally())
finally = graph->newBlock("tcFinally");
@ -287,7 +290,7 @@ void CFVisitor::visit(const TryCatchFlow *v) {
tryCatchStack.emplace_back(routeBlock, finally);
process(v->getBody());
graph->getCurrentBlock()->successors_insert(dst);
graph->getCurrentBlock()->successors_insert(else_ ? else_ : dst);
for (auto &c : *v) {
auto *cBlock = graph->newBlock("catch", true);
@ -299,6 +302,12 @@ void CFVisitor::visit(const TryCatchFlow *v) {
graph->getCurrentBlock()->successors_insert(dst);
}
if (v->getElse()) {
graph->setCurrentBlock(else_);
process(v->getElse());
graph->getCurrentBlock()->successors_insert(dst);
}
tryCatchStack.pop_back();
if (v->getFinally()) {

View File

@ -208,7 +208,8 @@ struct SideEfectAnalyzer : public util::ConstVisitor {
}
void visit(const TryCatchFlow *v) override {
auto s = max(process(v->getBody()), process(v->getFinally()));
auto s =
max(process(v->getBody()), process(v->getElse()), process(v->getFinally()));
auto callStatus = Status::PURE;
for (auto &x : *v) {

View File

@ -163,6 +163,8 @@ const char TryCatchFlow::NodeId = 0;
std::vector<Value *> TryCatchFlow::doGetUsedValues() const {
std::vector<Value *> ret = {body};
if (else_)
ret.push_back(else_);
if (finally)
ret.push_back(finally);
@ -180,6 +182,12 @@ int TryCatchFlow::doReplaceUsedValue(id_t id, Value *newValue) {
body = f;
++replacements;
}
if (else_ && else_->getId() == id) {
auto *f = cast<Flow>(newValue);
seqassert(f, "{} is not a flow", *newValue);
else_ = f;
++replacements;
}
if (finally && finally->getId() == id) {
auto *f = cast<Flow>(newValue);
seqassert(f, "{} is not a flow", *newValue);

View File

@ -385,6 +385,8 @@ private:
/// the body
Value *body;
/// the else block, may be nullptr
Value *else_;
/// the finally, may be nullptr
Value *finally;
@ -395,23 +397,32 @@ public:
/// @param name the's name
/// @param body the body
/// @param finally the finally
explicit TryCatchFlow(Flow *body, Flow *finally = nullptr, std::string name = "")
: AcceptorExtend(std::move(name)), body(body), finally(finally) {}
explicit TryCatchFlow(Flow *body, Flow *finally = nullptr, Flow *else_ = nullptr,
std::string name = "")
: AcceptorExtend(std::move(name)), body(body), else_(else_), finally(finally) {}
/// @return the body
Flow *getBody() { return cast<Flow>(body); }
/// @return the body
const Flow *getBody() const { return cast<Flow>(body); }
/// Sets the body.
/// @param f the new
/// @param f the new body
void setBody(Flow *f) { body = f; }
/// @return the else block
Flow *getElse() { return cast<Flow>(else_); }
/// @return the else block
const Flow *getElse() const { return cast<Flow>(else_); }
/// Sets the else block.
/// @param f the new else block
void setElse(Flow *f) { else_ = f; }
/// @return the finally
Flow *getFinally() { return cast<Flow>(finally); }
/// @return the finally
const Flow *getFinally() const { return cast<Flow>(finally); }
/// Sets the finally.
/// @param f the new
/// @param f the new finally
void setFinally(Flow *f) { finally = f; }
/// @return an iterator to the first catch

View File

@ -2871,6 +2871,14 @@ void LLVMVisitor::visit(const TryCatchFlow *x) {
process(x->getBody());
exitTryCatch();
// translate else
if (x->getElse()) {
B->SetInsertPoint(block);
auto *elseBlock = llvm::BasicBlock::Create(*context, "trycatch.else", func);
B->CreateBr(elseBlock);
process(x->getElse());
}
// make sure we always get to finally block
B->SetInsertPoint(block);
B->CreateBr(tc.finallyBlock);

View File

@ -233,7 +233,7 @@ void CloneVisitor::visit(const ImperativeForFlow *v) {
}
void CloneVisitor::visit(const TryCatchFlow *v) {
auto *res = Nt(v, clone(v->getBody()), clone(v->getFinally()));
auto *res = Nt(v, clone(v->getBody()), clone(v->getFinally()), clone(v->getElse()));
for (auto &c : *v) {
res->emplace_back(clone(c.getHandler()), c.getType(), clone(c.getVar()));
}

View File

@ -192,10 +192,10 @@ public:
makeFormatter(c.getVar()), makeFormatter(c.getHandler())));
}
fmt::print(os, FMT_STRING("(try {}\n{}\n(finally\n{}\n)\n)"),
fmt::print(os, FMT_STRING("(try {}\n{}\n(else\n{}\n)\n(finally\n{})\n)"),
makeFormatter(v->getBody()),
fmt::join(catches.begin(), catches.end(), "\n"),
makeFormatter(v->getFinally()));
makeFormatter(v->getElse()), makeFormatter(v->getFinally()));
}
void visit(const PipelineFlow *v) override {
std::vector<std::string> stages;

View File

@ -118,7 +118,8 @@ public:
}
VISIT(TryCatchFlow);
void handle(const TryCatchFlow *x, const TryCatchFlow *y) {
result = result && process(x->getFinally(), y->getFinally()) &&
result = result && process(x->getElse(), y->getElse()) &&
process(x->getFinally(), y->getFinally()) &&
process(x->getBody(), y->getBody()) &&
std::equal(x->begin(), x->end(), y->begin(), y->end(),
[this](auto &x, auto &y) {