compiler: some Env parts

This commit is contained in:
ProgramSnail 2025-01-22 22:35:01 +03:00
parent 02e22ff99b
commit 28f4dc191b

View file

@ -120,6 +120,10 @@ enum class OS { // TODO: other oses
DARWIN, DARWIN,
}; };
struct Options {
std::string filename;
};
struct CompilationMode { struct CompilationMode {
bool is_debug; bool is_debug;
OS os; OS os;
@ -804,8 +808,11 @@ struct Mode {
OS target_os; OS target_os;
}; };
// FIXME: TODO: find out what is Prg
using Prg = std::string;
// TODO: rebuild in c++ way // TODO: rebuild in c++ way
template <typename Prg, Mode mode> struct Env : public Indexer<Prg> { struct Env : public Indexer<Prg> {
private: private:
const std::string chars = const std::string chars =
"_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'"; "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'";
@ -820,7 +827,8 @@ private:
size_t stack_slots = 0; /* maximal number of stack positions */ size_t stack_slots = 0; /* maximal number of stack positions */
size_t static_size = 0; /* static data size */ size_t static_size = 0; /* static data size */
SymbolicStack::T stack = SymbolicStack::empty(0); /* symbolic stack */ SymbolicStack::T stack = SymbolicStack::empty(0); /* symbolic stack */
std::vector<std::string> locals; /* function local variables */ std::vector<std::vector<std::string>> locals;
/* function local variables */ // TODO: never used (?)
MapS<SymbolicStack::T> stackmap; /* labels to stack map */ MapS<SymbolicStack::T> stackmap; /* labels to stack map */
bool barrier = false; /* barrier condition */ bool barrier = false; /* barrier condition */
@ -838,7 +846,11 @@ public:
size_t nargs = 0; /* number of function arguments */ size_t nargs = 0; /* number of function arguments */
Mode mode;
public: public:
Env(Mode mode) : mode(std::move(mode)) {}
void register_public(std::string name) { publics.insert(std::move(name)); } void register_public(std::string name) { publics.insert(std::move(name)); }
void register_extern(std::string name) { externs.insert(std::move(name)); } void register_extern(std::string name) { externs.insert(std::move(name)); }
@ -848,30 +860,38 @@ public:
} }
} }
// TODO: add SymbolicStack functions to opimize
std::string print_stack() const { std::string print_stack() const {
std::stringstream result; std::stringstream result;
// TODO SymbolicStack::T stack_copy = stack;
// let rec show stack acc =
// if SymbolicStack.is_empty stack then acc std::vector<std::string> elements;
// else while (!SymbolicStack::is_empty(stack_copy)) {
// let stack, loc = SymbolicStack.pop stack in auto result = SymbolicStack::pop(std::move(stack_copy));
// show stack (show_opnd loc ^ " " ^ acc) stack_copy = std::move(result.first);
// in elements.push_back(to_string(result.second));
// show stack "" }
std::reverse(elements.begin(), elements.end());
for (const auto &element : elements) {
result << element << " ";
}
return result.str(); return result.str();
} }
std::string print_locals() const { std::string print_locals() const {
std::stringstream result; std::stringstream result;
// TODO // TODO
// Printf.printf "LOCALS: size = %d\n" static_size; result << std::format("LOCALS: size = {}\n", static_size);
// List.iter for (const auto &l : locals) {
// (fun l -> result << "(";
// Printf.printf "("; // NOTE: same to List.iter (fun (a, i) -> Printf.printf "%s=%d " a i) l;
// List.iter (fun (a, i) -> Printf.printf "%s=%d " a i) l; for (size_t i = 0; i < l.size(); ++i) {
// Printf.printf ")\n") result << std::format("{}={} ", l[i],
// locals; i); // TODO: exact format of locals
// Printf.printf "END LOCALS\n" }
result << ")\n";
}
result << "END LOCALS\n";
return result.str(); return result.str();
} }
@ -882,10 +902,10 @@ public:
bool is_barrier() { return barrier; } bool is_barrier() { return barrier; }
/* set barrier */ /* set barrier */
bool set_barrier() { barrier = true; } void set_barrier() { barrier = true; }
/* drop barrier */ /* drop barrier */
bool drop_barrier() { barrier = false; } void drop_barrier() { barrier = false; }
/* drop stack */ /* drop stack */
void drop_stack() { stack = SymbolicStack::empty(static_size); } void drop_stack() { stack = SymbolicStack::empty(static_size); }
@ -911,20 +931,30 @@ public:
/* gets a location for a variable */ /* gets a location for a variable */
Opnd loc(const ValT &x) { Opnd loc(const ValT &x) {
// TODO return std::visit(
// match x with utils::multifunc{
// | Value.Global name -> [this](const ValT::Global &x) -> Opnd {
// let loc_name = labeled_global name in auto loc_name = utils::labeled_global(x.s);
// let ext = if self#is_external name then E else I in const auto ext =
// M (D, ext, V, loc_name) is_external(x.s) ? Externality::E : Externality::I;
// | Value.Fun name -> return M{DataKind::D, ext, Addressed::V, std::move(loc_name)};
// let ext = if self#is_external name then E else I in },
// M (F, ext, A, name) [this](const ValT::Fun &x) -> Opnd {
// | Value.Local i -> S i const auto ext =
// | Value.Arg i when i < argument_registers_size -> is_external(x.s) ? Externality::E : Externality::I;
// argument_registers.(i) | Value.Arg i -> S (-(i - return M{DataKind::F, ext, Addressed::A, x.s};
// argument_registers_size) - 1) | Value.Access i -> I (word_size * (i + },
// 1), r15); [](const ValT::Local &x) -> Opnd { return S{x.n}; },
[this](const ValT::Arg &x) -> Opnd {
return x.n < argument_registers_size
? Opnd{argument_registers[x.n]}
: S{-(x.n - argument_registers_size) - 1};
},
[](const ValT::Access &x) -> Opnd {
return I{static_cast<int>(word_size * (x.n + 1)), r15};
},
},
*x);
} }
/* allocates a fresh position on a symbolic stack */ /* allocates a fresh position on a symbolic stack */
@ -949,15 +979,31 @@ public:
std::pair<std::vector<SymbolicStack::SymbolicLocation>, size_t> std::pair<std::vector<SymbolicStack::SymbolicLocation>, size_t>
arguments_locations(size_t n) { arguments_locations(size_t n) {
// TODO // TODO
// if n < argument_registers_size then
// ( Array.to_list (Array.sub argument_registers 0 n) using SymbolicLocation = SymbolicStack::SymbolicLocation;
// |> List.map (fun r -> Register r), using Register = SymbolicStack::Register;
// 0 ) using Stack = SymbolicStack::Stack;
// else
// ( (Array.to_list argument_registers |> List.map (fun r -> Register if (n < argument_registers_size) {
// r)) std::vector<::Register::T> result;
// @ List.init (n - argument_registers_size) (fun _ -> Stack), result.insert(result.end(), argument_registers.begin(),
// n - argument_registers_size ) argument_registers.begin() + n);
return {
utils::transform<::Register::T, SymbolicLocation>(
std::move(result),
[](const auto &r) -> SymbolicLocation { return {Register{r}}; }),
0};
} else {
return {utils::concat( //
utils::transform<::Register::T, SymbolicLocation>(
std::move(argument_registers),
[](const auto &r) -> SymbolicLocation {
return {Register{r}};
}),
std::vector<SymbolicLocation>(n - argument_registers_size,
{Stack{}})),
n - argument_registers_size};
}
} }
/* peeks the top of the stack (the stack does not change) */ /* peeks the top of the stack (the stack does not change) */
@ -1033,9 +1079,6 @@ public:
// (M (D, I, A, name), {<scount = scount + 1; stringm = m>}) // (M (D, I, A, name), {<scount = scount + 1; stringm = m>})
} }
/* gets number of arguments in the current function */
// method nargs = nargs
/* gets all global variables */ /* gets all global variables */
std::vector<std::string> get_globals() const { std::vector<std::string> get_globals() const {
std::vector<std::string> result; std::vector<std::string> result;
@ -1049,7 +1092,15 @@ public:
} }
/* gets all string definitions */ /* gets all string definitions */
SetS get_strings() const { /*M.bindings stringm*/ } SetS get_strings() const {
SetS result;
result.reserve(stringm.size());
for (const auto &str : stringm) {
result.insert(
str.first); // TODO: M.bindings -> take first elem argument (?)
}
return result;
}
/* gets a number of stack positions allocated */ /* gets a number of stack positions allocated */
size_t get_allocated() const { return stack_slots; } size_t get_allocated() const { return stack_slots; }
@ -1129,11 +1180,7 @@ public:
int stack_offset(int i) { return (i >= 0 ? (i + 1) : (-i + 1)) * word_size; } int stack_offset(int i) { return (i >= 0 ? (i + 1) : (-i + 1)) * word_size; }
// template <typename Prg, Mode mode> std::string to_code(const Env &env, const Opnd &opnd) {
// FIXME: testing
using Prg = int;
constexpr Mode mode_ = {};
std::string to_code(const Env<Prg, mode_> &env, const Opnd &opnd) {
return std::visit( return std::visit(
utils::multifunc{ utils::multifunc{
[](const Opnd::R &x) { return to_string(x.reg); }, [](const Opnd::R &x) { return to_string(x.reg); },
@ -1170,7 +1217,7 @@ std::string to_code(const Env<Prg, mode_> &env, const Opnd &opnd) {
// template <typename Prg, Mode mode> // template <typename Prg, Mode mode>
// FIXME: testing // FIXME: testing
std::string to_code(const Env<Prg, mode_> &env, const Instr &instr) { std::string to_code(const Env &env, const Instr &instr) {
const auto opnd_to_code = [&env](const Opnd &opnd) -> std::string { const auto opnd_to_code = [&env](const Opnd &opnd) -> std::string {
return to_code(env, opnd); return to_code(env, opnd);
}; };
@ -1298,7 +1345,7 @@ int box(int n) { return (n << 1) | 1; }
compile_binop : env -> string -> env * instr list compile_binop : env -> string -> env * instr list
*/ */
// template <typename Prg, Mode mode> // template <typename Prg, Mode mode>
std::vector<Instr> compile_binop(Env<Prg, mode_> &env, Opr op) { std::vector<Instr> compile_binop(Env &env, Opr op) {
const auto suffix = [](Opr op) { const auto suffix = [](Opr op) {
const static std::unordered_map<Opr, std::string> ops = { const static std::unordered_map<Opr, std::string> ops = {
{Opr::LT, "l"}, {Opr::LEQ, "le"}, {Opr::EQ, "e"}, {Opr::LT, "l"}, {Opr::LEQ, "le"}, {Opr::EQ, "e"},
@ -1465,9 +1512,9 @@ std::vector<Instr> compile_binop(Env<Prg, mode_> &env, Opr op) {
} }
/* For pointers to be marked by GC as alive they have to be located on the /* For pointers to be marked by GC as alive they have to be located on the
stack. As we do not have control where does the C compiler locate them in the stack. As we do not have control where does the C compiler locate them in
moment of GC, we have to explicitly locate them on the stack. And to the the moment of GC, we have to explicitly locate them on the stack. And to
runtime function we are passing a reference to their location. */ the runtime function we are passing a reference to their location. */
const std::unordered_set<std::string> safepoint_functions = { const std::unordered_set<std::string> safepoint_functions = {
utils::labeled("s__Infix_58"), utils::labeled("substring"), utils::labeled("s__Infix_58"), utils::labeled("substring"),
utils::labeled("clone"), utils::labeled_builtin("string"), utils::labeled("clone"), utils::labeled_builtin("string"),
@ -1491,8 +1538,7 @@ const std::unordered_map<std::string, size_t> vararg_functions = {
namespace utils::call_compilation::tail { namespace utils::call_compilation::tail {
// NOTE: all comands in result are in inversed order // NOTE: all comands in result are in inversed order
void push_args_rec_inv(Env<Prg, mode_> &env, std::vector<Instr> &acc, void push_args_rec_inv(Env &env, std::vector<Instr> &acc, size_t n) {
size_t n) {
if (n == 0) { if (n == 0) {
return; return;
} }
@ -1500,7 +1546,7 @@ void push_args_rec_inv(Env<Prg, mode_> &env, std::vector<Instr> &acc,
utils::insert(acc, utils::reverse(mov(x, env.loc(ValT::Arg{n - 1})))); utils::insert(acc, utils::reverse(mov(x, env.loc(ValT::Arg{n - 1}))));
push_args_rec_inv(env, acc, n - 1); push_args_rec_inv(env, acc, n - 1);
} }
std::vector<Instr> push_args(Env<Prg, mode_> &env, size_t n) { std::vector<Instr> push_args(Env &env, size_t n) {
std::vector<Instr> acc; std::vector<Instr> acc;
push_args_rec_inv(env, acc, n); push_args_rec_inv(env, acc, n);
std::reverse(acc.begin(), acc.end()); std::reverse(acc.begin(), acc.end());
@ -1508,7 +1554,7 @@ std::vector<Instr> push_args(Env<Prg, mode_> &env, size_t n) {
} }
} // namespace utils::call_compilation::tail } // namespace utils::call_compilation::tail
std::vector<Instr> compile_tail_call(Env<Prg, mode_> &env, std::vector<Instr> compile_tail_call(Env &env,
const std::optional<std::string> &fname, const std::optional<std::string> &fname,
size_t nargs) { size_t nargs) {
using namespace utils::call_compilation::tail; using namespace utils::call_compilation::tail;
@ -1532,7 +1578,7 @@ std::vector<Instr> compile_tail_call(Env<Prg, mode_> &env,
namespace utils::call_compilation { namespace utils::call_compilation {
std::vector<Opnd> pop_arguments(Env<Prg, mode_> &env, size_t n) { std::vector<Opnd> pop_arguments(Env &env, size_t n) {
std::vector<Opnd> result; std::vector<Opnd> result;
result.reserve(n); result.reserve(n);
for (size_t i = 0; i < n; ++i) { for (size_t i = 0; i < n; ++i) {
@ -1545,8 +1591,7 @@ std::vector<Opnd> pop_arguments(Env<Prg, mode_> &env, size_t n) {
namespace common { namespace common {
std::pair<size_t, std::vector<Instr>> setup_arguments(Env<Prg, mode_> &env, std::pair<size_t, std::vector<Instr>> setup_arguments(Env &env, size_t nargs) {
size_t nargs) {
const auto move_arguments = const auto move_arguments =
[](std::vector<Opnd> &&args, [](std::vector<Opnd> &&args,
std::vector<SymbolicStack::SymbolicLocation> &&arg_locs) { std::vector<SymbolicStack::SymbolicLocation> &&arg_locs) {
@ -1573,7 +1618,7 @@ std::pair<size_t, std::vector<Instr>> setup_arguments(Env<Prg, mode_> &env,
return {stack_slots, std::move(setup_args_code)}; return {stack_slots, std::move(setup_args_code)};
} }
std::optional<Instr> setup_closure(Env<Prg, mode_> &env, std::optional<Instr> setup_closure(Env &env,
const std::optional<std::string> &fname) { const std::optional<std::string> &fname) {
if (!fname) { if (!fname) {
return {}; return {};
@ -1595,8 +1640,7 @@ Instr add_argc_counter(const std::optional<std::string> &fname, size_t nargs) {
} // namespace common } // namespace common
std::pair<std::vector<Instr>, std::vector<Instr>> std::pair<std::vector<Instr>, std::vector<Instr>> protect_registers(Env &env) {
protect_registers(Env<Prg, mode_> &env) {
std::vector<Instr> pushr; std::vector<Instr> pushr;
std::vector<Instr> popr; std::vector<Instr> popr;
if (env.has_closure) { if (env.has_closure) {
@ -1633,13 +1677,13 @@ align_stack(size_t saved_registers, size_t stack_arguments) {
L{static_cast<int>(word_size * (1 + stack_arguments))}, rsp}}}; L{static_cast<int>(word_size * (1 + stack_arguments))}, rsp}}};
} }
Instr move_result(Env<Prg, mode_> &env) { Instr move_result(Env &env) {
const auto y = env.allocate(); const auto y = env.allocate();
return Mov{rax, y}; return Mov{rax, y};
} }
} // namespace utils::call_compilation } // namespace utils::call_compilation
std::vector<Instr> compile_common_call(Env<Prg, mode_> &env, std::vector<Instr> compile_common_call(Env &env,
const std::optional<std::string> &fname, const std::optional<std::string> &fname,
size_t nargs) { size_t nargs) {
using namespace utils::call_compilation::common; using namespace utils::call_compilation::common;
@ -1666,7 +1710,7 @@ std::vector<Instr> compile_common_call(Env<Prg, mode_> &env,
namespace utils::call_compilation::safepoint { namespace utils::call_compilation::safepoint {
std::pair<size_t, std::vector<Instr>> std::pair<size_t, std::vector<Instr>>
setup_arguments(Env<Prg, mode_> &env, const std::optional<std::string> &fname, setup_arguments(Env &env, const std::optional<std::string> &fname,
size_t nargs) { size_t nargs) {
auto args = pop_arguments(env, nargs); auto args = pop_arguments(env, nargs);
auto [arg_locs, stack_slots] = env.arguments_locations(args.size()); auto [arg_locs, stack_slots] = env.arguments_locations(args.size());
@ -1687,8 +1731,8 @@ Instr call(const std::optional<std::string> &fname) { return Call{*fname}; }
} // namespace utils::call_compilation::safepoint } // namespace utils::call_compilation::safepoint
std::vector<Instr> std::vector<Instr>
compile_safepoint_call(Env<Prg, mode_> &env, compile_safepoint_call(Env &env, const std::optional<std::string> &fname,
const std::optional<std::string> &fname, size_t nargs) { size_t nargs) {
using namespace utils::call_compilation::safepoint; using namespace utils::call_compilation::safepoint;
using namespace utils::call_compilation; using namespace utils::call_compilation;
@ -1706,7 +1750,7 @@ compile_safepoint_call(Env<Prg, mode_> &env,
std::move(move_result_code)); std::move(move_result_code));
} }
std::vector<Instr> compile_call(Env<Prg, mode_> &env, std::vector<Instr> compile_call(Env &env,
std::optional<std::string_view> fname_in, std::optional<std::string_view> fname_in,
size_t nargs, bool tail) { size_t nargs, bool tail) {
std::optional<std::string> fname; std::optional<std::string> fname;
@ -1909,10 +1953,10 @@ struct SMInstr {
Take an environment, a stack machine program, and returns a pair --- Take an environment, a stack machine program, and returns a pair ---
the updated environment and the list of x86 instructions the updated environment and the list of x86 instructions
*/ */
std::vector<Instr> compile(cmd, Env<Prg, mode_> &env, std::vector<Instr> compile(const Options &cmd, Env &env,
const std::vector<std::string> &imports, const std::vector<std::string> &imports,
const SMInstr &instr) { const SMInstr &instr) {
const std::string stack_state = mode_.is_debug ? env.print_stack() : ""; const std::string stack_state = env.mode.is_debug ? env.print_stack() : "";
if (env.is_barrier()) { if (env.is_barrier()) {
return std::visit( // return std::visit( //
utils::multifunc{ utils::multifunc{
@ -2123,9 +2167,9 @@ std::vector<Instr> compile(cmd, Env<Prg, mode_> &env,
[&env](const SMInstr::LINE &x) -> std::vector<Instr> { [&env](const SMInstr::LINE &x) -> std::vector<Instr> {
return env.gen_line(x.n); return env.gen_line(x.n);
}, },
[&env](const SMInstr::FAIL &x) -> std::vector<Instr> { [&env, &cmd](const SMInstr::FAIL &x) -> std::vector<Instr> {
const auto v = x.val ? env.peek() : env.pop(); const auto v = x.val ? env.peek() : env.pop();
const auto msg_addr = env.register_string(cmd.get_infile()); const auto msg_addr = env.register_string(cmd.filename);
const auto vr = env.allocate(); const auto vr = env.allocate();
const auto sr = env.allocate(); const auto sr = env.allocate();
const auto liner = env.allocate(); const auto liner = env.allocate();
@ -2150,7 +2194,7 @@ std::vector<Instr> compile(cmd, Env<Prg, mode_> &env,
} }
} }
std::vector<Instr> compile(cmd, Env<Prg, mode_> &env, std::vector<Instr> compile(const Options &cmd, Env &env,
const std::vector<std::string> &imports, const std::vector<std::string> &imports,
const std::vector<SMInstr> &code) { const std::vector<SMInstr> &code) {
std::vector<Instr> result; std::vector<Instr> result;