--- /dev/null
+#include "rust-bir-dump.h"
+
+namespace Rust {
+namespace BIR {
+
+constexpr auto indentation = " ";
+
+uint32_t
+get_place_name (PlaceId place_id)
+{
+ rust_assert (place_id >= FIRST_VARIABLE_PLACE);
+ return place_id - FIRST_VARIABLE_PLACE;
+}
+
+uint32_t
+get_lifetime_name (Lifetime lifetime_id)
+{
+ rust_assert (lifetime_id.id >= FIRST_NORMAL_LIFETIME_ID);
+ // Start from 1 as rustc does.
+ return lifetime_id.id - FIRST_NORMAL_LIFETIME_ID + 1;
+}
+
+std::string
+get_tyty_name (TyTy::BaseType *tyty)
+{
+ if (tyty)
+ return tyty->get_name ();
+ return "unknown";
+}
+
+void
+Dump::go ()
+{
+ stream << "fn " << name << "(";
+ for (PlaceId arg : func.arguments)
+ {
+ stream << "_" << get_place_name (arg) << ": "
+ << get_tyty_name (place_db[arg].tyty) << ", ";
+ }
+ stream << ") -> " << get_tyty_name (place_db[RETURN_VALUE_PLACE].tyty)
+ << " {\n";
+
+ for (PlaceId id = FIRST_VARIABLE_PLACE; id < place_db.size (); ++id)
+ {
+ const Place &place = place_db[id];
+ if (place.kind == Place::VARIABLE || place.kind == Place::TEMPORARY)
+ {
+ if (std::find (func.arguments.begin (), func.arguments.end (), id)
+ != func.arguments.end ())
+ continue;
+ stream << indentation << "let _" << get_place_name (id) << ": "
+ << get_tyty_name (place_db[id].tyty) << ";\n";
+ }
+ }
+
+ for (BasicBlockId id = 0; id < func.basic_blocks.size (); ++id)
+ {
+ if (func.basic_blocks[id].statements.empty ()
+ && func.basic_blocks[id].successors.empty ())
+ continue;
+
+ BasicBlock &bb = func.basic_blocks[id];
+ stream << "\n";
+ stream << indentation << "bb" << id << ": {\n";
+ for (auto &stmt : bb.statements)
+ {
+ stream << indentation << indentation;
+ visit (stmt);
+ stream << ";\n";
+ }
+ stream << indentation << "} -> [";
+ for (auto succ : bb.successors)
+ stream << "bb" << succ << ", ";
+ stream << "]\n";
+ }
+
+ stream << "}\n\n";
+}
+void
+Dump::visit (Node &node)
+{
+ node_place = node.get_place ();
+ switch (node.get_kind ())
+ {
+ case Node::Kind::ASSIGNMENT: {
+ stream << "_" << get_place_name (node.get_place ()) << " = ";
+ node.get_expr ().accept_vis (*this);
+ break;
+ }
+ case Node::Kind::SWITCH:
+ stream << "switch ";
+ visit_move_place (node.get_place ());
+ break;
+ case Node::Kind::RETURN:
+ stream << "return";
+ break;
+ case Node::Kind::GOTO:
+ stream << "goto";
+ break;
+ case Node::Kind::STORAGE_DEAD:
+ stream << "StorageDead(";
+ visit_move_place (node.get_place ());
+ stream << ")";
+ break;
+ case Node::Kind::STORAGE_LIVE:
+ stream << "StorageLive(";
+ visit_move_place (node.get_place ());
+ stream << ")";
+ break;
+ }
+ node_place = INVALID_PLACE;
+}
+
+void
+Dump::visit_place (PlaceId place_id)
+{
+ const Place &place = place_db[place_id];
+ switch (place.kind)
+ {
+ case Place::TEMPORARY:
+ case Place::VARIABLE:
+ stream << "_" << get_place_name (place_id);
+ break;
+ case Place::DEREF:
+ stream << "(";
+ stream << "*";
+ visit_place (place.path.parent);
+ stream << ")";
+ break;
+ case Place::FIELD:
+ stream << "(";
+ visit_place (place.path.parent);
+ stream << ".";
+ stream << place.variable_or_field_index;
+ stream << ": " << get_tyty_name (place.tyty) << ")";
+ break;
+ case Place::INDEX:
+ stream << "(";
+ visit_place (place.path.parent);
+ stream << "[]";
+ stream << ": " << get_tyty_name (place.tyty) << ")";
+ break;
+ case Place::CONSTANT:
+ stream << "const " << get_tyty_name (place.tyty);
+ break;
+ case Place::INVALID:
+ stream << "_INVALID";
+ }
+}
+
+void
+Dump::visit_move_place (PlaceId place_id)
+{
+ const Place &place = place_db[place_id];
+ if (!place.is_copy)
+ stream << "move ";
+ visit_place (place_id);
+}
+
+void
+Dump::visit (BorrowExpr &expr)
+{
+ stream << "&";
+ visit_lifetime (node_place);
+ visit_place (expr.get_place ());
+}
+
+void
+Dump::visit_lifetime (PlaceId place_id)
+{
+ const Place &place = place_db[place_id];
+ if (place.lifetime.has_lifetime ())
+ {
+ if (place.lifetime.id == STATIC_LIFETIME_ID)
+ stream << "'static ";
+ else
+ stream << "'#" << get_lifetime_name (place.lifetime) << " ";
+ }
+}
+
+void
+Dump::visit (InitializerExpr &expr)
+{
+ stream << "{";
+ for (auto &place : expr.get_values ())
+ {
+ visit_move_place (place);
+ stream << ", ";
+ }
+ stream << "}";
+}
+
+void
+Dump::visit (CallExpr &expr)
+{
+ stream << "Call(";
+ if (auto fn_type
+ = place_db[expr.get_callable ()].tyty->try_as<TyTy::FnType> ())
+ {
+ stream << fn_type->get_identifier ();
+ }
+ else
+ {
+ visit_move_place (expr.get_callable ());
+ }
+ stream << ")(";
+ for (auto &place : expr.get_arguments ())
+ {
+ visit_move_place (place);
+ stream << ", ";
+ }
+ stream << ")";
+}
+
+void
+Dump::visit (Operator<1> &expr)
+{
+ stream << "Operator(";
+ visit_move_place (expr.get_operand<0> ());
+ stream << ")";
+}
+
+void
+Dump::visit (Operator<2> &expr)
+{
+ stream << "Operator(";
+ visit_move_place (expr.get_operand<0> ());
+ stream << ", ";
+ visit_move_place (expr.get_operand<1> ());
+ stream << ")";
+}
+void
+Dump::visit (Assignment &expr)
+{
+ visit_move_place (expr.get_rhs ());
+}
+
+} // namespace BIR
+} // namespace Rust
--- /dev/null
+// Copyright (C) 2020-2023 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_BIR_DUMP_H
+#define RUST_BIR_DUMP_H
+
+#include <ostream>
+#include <utility>
+#include "rust-bir-place.h"
+#include "rust-bir-visitor.h"
+#include "rust-bir.h"
+
+namespace Rust {
+namespace BIR {
+
+class Dump : public Visitor
+{
+ std::ostream &stream;
+ const PlaceDB &place_db;
+ Function &func;
+ const std::string &name;
+
+ PlaceId node_place = INVALID_PLACE;
+
+public:
+ Dump (std::ostream &os, Function &func, const std::string &name)
+ : stream (os), place_db (func.place_db), func (func), name (name)
+ {}
+ void go ();
+
+protected:
+ void visit (Node &node) override;
+ void visit_place (PlaceId place_id);
+ void visit_move_place (PlaceId place_id);
+ void visit (BorrowExpr &expr) override;
+ void visit_lifetime (PlaceId place_id);
+ void visit (InitializerExpr &expr) override;
+ void visit (CallExpr &expr) override;
+ void visit (Operator<1> &expr) override;
+ void visit (Operator<2> &expr) override;
+ void visit (Assignment &expr) override;
+};
+
+} // namespace BIR
+} // namespace Rust
+
+#endif // RUST_BIR_DUMP_H
#include "rust-borrow-checker.h"
#include "rust-function-collector.h"
#include "rust-bir-builder.h"
+#include "rust-bir-dump.h"
namespace Rust {
namespace HIR {
+void
+mkdir_wrapped (const std::string &dirname)
+{
+ int ret;
+#ifdef _WIN32
+ ret = _mkdir (dirname.c_str ());
+#elif unix
+ ret = mkdir (dirname.c_str (), 0775);
+#elif __APPLE__
+ ret = mkdir (dirname.c_str (), 0775);
+#endif
+ (void) ret;
+}
+
+void
+dump_function_bir (const std::string &filename, BIR::Function &func,
+ const std::string &name)
+{
+ std::ofstream file;
+ file.open (filename);
+ if (file.fail ())
+ {
+ rust_error_at (UNKNOWN_LOCATION, "Failed to open file %s",
+ filename.c_str ());
+ return;
+ }
+ BIR::Dump (file, func, name).go ();
+ file.close ();
+}
+
void
BorrowChecker::go (HIR::Crate &crate)
{
+ std::string crate_name;
+
+ if (enable_dump_bir)
+ {
+ mkdir_wrapped ("bir_dump");
+ auto mappings = Analysis::Mappings::get ();
+ bool ok
+ = mappings->get_crate_name (crate.get_mappings ().get_crate_num (),
+ crate_name);
+ rust_assert (ok);
+ }
+
FunctionCollector collector;
collector.go (crate);
{
BIR::BuilderContext ctx;
BIR::Builder builder (ctx);
- builder.build (*func);
+ auto bir = builder.build (*func);
+
+ if (enable_dump_bir)
+ {
+ std::string filename = "bir_dump/" + crate_name + "."
+ + func->get_function_name ().as_string ()
+ + ".bir.dump";
+ dump_function_bir (filename, bir,
+ func->get_function_name ().as_string ());
+ }
}
for (auto closure ATTRIBUTE_UNUSED : collector.get_closures ())
{
+ rust_sorry_at (closure->get_locus (),
+ "Closure borrow checking is not implemented yet.");
}
}