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

View File

@ -208,7 +208,8 @@ struct SideEfectAnalyzer : public util::ConstVisitor {
} }
void visit(const TryCatchFlow *v) override { 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; auto callStatus = Status::PURE;
for (auto &x : *v) { for (auto &x : *v) {

View File

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

View File

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

View File

@ -2871,6 +2871,14 @@ void LLVMVisitor::visit(const TryCatchFlow *x) {
process(x->getBody()); process(x->getBody());
exitTryCatch(); 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 // make sure we always get to finally block
B->SetInsertPoint(block); B->SetInsertPoint(block);
B->CreateBr(tc.finallyBlock); B->CreateBr(tc.finallyBlock);

View File

@ -233,7 +233,7 @@ void CloneVisitor::visit(const ImperativeForFlow *v) {
} }
void CloneVisitor::visit(const TryCatchFlow *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) { for (auto &c : *v) {
res->emplace_back(clone(c.getHandler()), c.getType(), clone(c.getVar())); res->emplace_back(clone(c.getHandler()), c.getType(), clone(c.getVar()));
} }

View File

@ -192,10 +192,10 @@ public:
makeFormatter(c.getVar()), makeFormatter(c.getHandler()))); 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()), makeFormatter(v->getBody()),
fmt::join(catches.begin(), catches.end(), "\n"), fmt::join(catches.begin(), catches.end(), "\n"),
makeFormatter(v->getFinally())); makeFormatter(v->getElse()), makeFormatter(v->getFinally()));
} }
void visit(const PipelineFlow *v) override { void visit(const PipelineFlow *v) override {
std::vector<std::string> stages; std::vector<std::string> stages;

View File

@ -118,7 +118,8 @@ public:
} }
VISIT(TryCatchFlow); VISIT(TryCatchFlow);
void handle(const TryCatchFlow *x, const TryCatchFlow *y) { 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()) && process(x->getBody(), y->getBody()) &&
std::equal(x->begin(), x->end(), y->begin(), y->end(), std::equal(x->begin(), x->end(), y->begin(), y->end(),
[this](auto &x, auto &y) { [this](auto &x, auto &y) {