diff options
| author | Martial Simon <msimon_fr@hotmail.com> | 2025-09-15 01:07:58 +0200 |
|---|---|---|
| committer | Martial Simon <msimon_fr@hotmail.com> | 2025-09-15 01:07:58 +0200 |
| commit | 967be9e750221ab2ab783f95df79bb26d290a45e (patch) | |
| tree | 6802900a5e975f9f68b169f0f503f040056d6952 /tiger-compiler/src/llvmtranslate/escapes-collector.cc | |
Diffstat (limited to 'tiger-compiler/src/llvmtranslate/escapes-collector.cc')
| -rw-r--r-- | tiger-compiler/src/llvmtranslate/escapes-collector.cc | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/tiger-compiler/src/llvmtranslate/escapes-collector.cc b/tiger-compiler/src/llvmtranslate/escapes-collector.cc new file mode 100644 index 0000000..4984805 --- /dev/null +++ b/tiger-compiler/src/llvmtranslate/escapes-collector.cc @@ -0,0 +1,151 @@ +#include <ast/all.hh> +#include <ast/default-visitor.hh> +#include <ast/non-assert-visitor.hh> +#include <ast/non-object-visitor.hh> +#include <llvmtranslate/escapes-collector.hh> + +namespace llvmtranslate +{ + /// LLVM IR doesn't support static link and nested functions. + /// In order to translate those functions to LLVM IR, we use a technique + /// called Lambda Lifting, which consists in passing a pointer to + /// the escaped variables to the nested function using that variable. + /// + /// In order to do that, we need a visitor to collect these kind of + /// variables and associate them to each function. + + class EscapesCollector + : public ast::DefaultConstVisitor + , public ast::NonObjectConstVisitor + , public ast::NonAssertConstVisitor + { + public: + /// Super class. + using super_type = ast::DefaultConstVisitor; + /// Import overloaded operator() methods. + using super_type::operator(); + + EscapesCollector() + : did_modify_{false} + , escaped_{} + {} + + escaped_map_type& escaped_get() { return escaped_; } + + void operator()(const ast::FunctionChunk& e) override + { + const bool saved_did_modify = did_modify_; + + // Iterate on the chunk in order to iteratively collect all the callee + // functions' escaped variables. + did_modify_ = !e.empty(); + while (did_modify_) + { + did_modify_ = false; + super_type::operator()(e); + } + + did_modify_ = saved_did_modify; + } + + void operator()(const ast::FunctionDec& e) override + { + // Keep track of the current function + // FIXME DONE: Some code was deleted here. + const auto function_type = \ + dynamic_cast<const type::Function*>(&e.type_get()->actual()); + + precondition(function_type != nullptr); + + // Last visited function + const type::Function* previous_scope = current_; + + if (previous_scope == nullptr) + { + // Then we are at the first depth of the program, hence _main + main_function_ = function_type; + } + + current_ = function_type; + + if (!escaped_.contains(current_)) + { + escaped_[current_] = misc::set<const ast::VarDec*>{}; + } + + super_type::operator()(e); + + // Guess we only really need to go back one step before + current_ = previous_scope; + } + + void operator()(const ast::CallExp& e) override + { + super_type::operator()(e); + + // FIXME DONE: Some code was deleted here. + const auto escaped_reference = escaped_.find(current_); + precondition(escaped_reference != escaped_.end()); + const auto escaped_state = escaped_reference->second; + + const size_t before_size = escaped_state.size(); + + super_type::operator()(e.def_get()); + + // Check whether there are any newly collected escaped variables. + // If there are, mark the iteration as modified. + // FIXME DONE: Some code was deleted here. + const size_t after_size = escaped_state.size(); + + did_modify_ = before_size != after_size; + } + + void operator()(const ast::SimpleVar& e) override + { + // Associate escaped variables declared in parent frames with their + // functions + // FIXME DONE: Some code was deleted here. + if (current_ == main_function_ || !e.def_get()->escape_get()) + { + super_type::operator()(e); + return; + } + + // Checking that the variable is escaped because not all variables are + auto attached_to = escaped_.find(current_); + + // We have a function to attach this to + if (attached_to != escaped_.end() + && !attached_to->second.contains(e.def_get())) + { + attached_to->second.insert(e.def_get()); + did_modify_ = true; + } + + super_type::operator()(e); + } + + private: + /// Whether any modification was done during the iteration. + bool did_modify_ = false; + + /// Associate a set of variables with their function. + escaped_map_type escaped_; + + /// Current visiting function. + // FIXME DONE: Some code was deleted here. + const type::Function* current_ = nullptr; + + /// The reference to the main function + const type::Function* main_function_ = nullptr; + }; + + escaped_map_type collect_escapes(const ast::Ast& ast) + { + EscapesCollector collect; + collect(ast); + + return std::move(collect.escaped_get()); + } + +} // namespace llvmtranslate |
