2020-09-13 21:32:55 -04:00
|
|
|
#pragma once
|
|
|
|
|
2020-09-06 12:45:31 -04:00
|
|
|
/*!
|
|
|
|
* @file Env.h
|
|
|
|
* The Env tree. The stores all of the nested scopes/contexts during compilation and also
|
|
|
|
* manages the memory for stuff generated during compiling.
|
|
|
|
*/
|
2020-09-05 16:37:37 -04:00
|
|
|
|
|
|
|
#ifndef JAK_ENV_H
|
|
|
|
#define JAK_ENV_H
|
|
|
|
|
2020-09-06 12:45:31 -04:00
|
|
|
#include <string>
|
|
|
|
#include <memory>
|
|
|
|
#include <vector>
|
|
|
|
#include "common/type_system/TypeSpec.h"
|
2020-09-06 16:58:25 -04:00
|
|
|
#include "goalc/regalloc/allocate.h"
|
2020-09-17 21:47:52 -04:00
|
|
|
#include "common/goos/Object.h"
|
2020-09-12 13:11:42 -04:00
|
|
|
#include "StaticObject.h"
|
2020-09-06 12:45:31 -04:00
|
|
|
#include "Label.h"
|
|
|
|
#include "Val.h"
|
|
|
|
|
|
|
|
class FileEnv;
|
|
|
|
class BlockEnv;
|
2020-09-06 16:58:25 -04:00
|
|
|
class IR;
|
2020-09-06 12:45:31 -04:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* Parent class for Env's
|
|
|
|
*/
|
|
|
|
class Env {
|
|
|
|
public:
|
|
|
|
explicit Env(Env* parent) : m_parent(parent) {}
|
|
|
|
virtual std::string print() = 0;
|
|
|
|
virtual void emit(std::unique_ptr<IR> ir);
|
|
|
|
virtual RegVal* make_ireg(TypeSpec ts, emitter::RegKind kind);
|
2020-09-12 13:11:42 -04:00
|
|
|
virtual void constrain_reg(IRegConstraint constraint); // todo, remove!
|
2020-09-13 17:34:02 -04:00
|
|
|
virtual RegVal* lexical_lookup(goos::Object sym);
|
2020-09-06 12:45:31 -04:00
|
|
|
virtual BlockEnv* find_block(const std::string& name);
|
2020-09-07 19:17:48 -04:00
|
|
|
virtual std::unordered_map<std::string, Label>& get_label_map();
|
2020-09-19 16:50:42 -04:00
|
|
|
RegVal* make_gpr(const TypeSpec& ts);
|
|
|
|
RegVal* make_xmm(const TypeSpec& ts);
|
2020-09-06 12:45:31 -04:00
|
|
|
virtual ~Env() = default;
|
|
|
|
|
|
|
|
Env* parent() { return m_parent; }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
Env* m_parent = nullptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* The top-level Env. Holds FileEnvs for all files.
|
|
|
|
*/
|
|
|
|
class GlobalEnv : public Env {
|
|
|
|
public:
|
|
|
|
GlobalEnv();
|
|
|
|
std::string print() override;
|
|
|
|
void emit(std::unique_ptr<IR> ir) override;
|
|
|
|
RegVal* make_ireg(TypeSpec ts, emitter::RegKind kind) override;
|
|
|
|
void constrain_reg(IRegConstraint constraint) override;
|
2020-09-13 17:34:02 -04:00
|
|
|
RegVal* lexical_lookup(goos::Object sym) override;
|
2020-09-06 12:45:31 -04:00
|
|
|
BlockEnv* find_block(const std::string& name) override;
|
|
|
|
~GlobalEnv() = default;
|
|
|
|
|
|
|
|
FileEnv* add_file(std::string name);
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::vector<std::unique_ptr<FileEnv>> m_files;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* An Env that doesn't allow emitting to go past it. Used to make sure source code that shouldn't
|
|
|
|
* generate machine code actually does this.
|
|
|
|
*/
|
|
|
|
class NoEmitEnv : public Env {
|
|
|
|
public:
|
|
|
|
explicit NoEmitEnv(Env* parent) : Env(parent) {}
|
|
|
|
std::string print() override;
|
|
|
|
void emit(std::unique_ptr<IR> ir) override;
|
|
|
|
~NoEmitEnv() = default;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* An Env for an entire file (or input to the REPL)
|
|
|
|
*/
|
|
|
|
class FileEnv : public Env {
|
|
|
|
public:
|
|
|
|
FileEnv(Env* parent, std::string name);
|
|
|
|
std::string print() override;
|
|
|
|
void add_function(std::unique_ptr<FunctionEnv> fe);
|
|
|
|
void add_top_level_function(std::unique_ptr<FunctionEnv> fe);
|
2020-09-12 13:11:42 -04:00
|
|
|
void add_static(std::unique_ptr<StaticObject> s);
|
2020-09-06 12:45:31 -04:00
|
|
|
NoEmitEnv* add_no_emit_env();
|
|
|
|
void debug_print_tl();
|
2020-09-06 16:58:25 -04:00
|
|
|
const std::vector<std::unique_ptr<FunctionEnv>>& functions() { return m_functions; }
|
2020-09-12 13:11:42 -04:00
|
|
|
const std::vector<std::unique_ptr<StaticObject>>& statics() { return m_statics; }
|
2020-09-13 10:40:21 -04:00
|
|
|
const FunctionEnv& top_level_function() {
|
|
|
|
assert(m_top_level_func);
|
|
|
|
return *m_top_level_func;
|
|
|
|
}
|
2020-11-13 22:33:57 -05:00
|
|
|
const std::string& name() { return m_name; }
|
2020-09-06 12:45:31 -04:00
|
|
|
|
2020-09-06 17:42:20 -04:00
|
|
|
bool is_empty();
|
2020-09-06 12:45:31 -04:00
|
|
|
~FileEnv() = default;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
std::string m_name;
|
|
|
|
std::vector<std::unique_ptr<FunctionEnv>> m_functions;
|
2020-09-12 13:11:42 -04:00
|
|
|
std::vector<std::unique_ptr<StaticObject>> m_statics;
|
2020-09-06 12:45:31 -04:00
|
|
|
std::unique_ptr<NoEmitEnv> m_no_emit_env = nullptr;
|
|
|
|
|
|
|
|
// statics
|
|
|
|
FunctionEnv* m_top_level_func = nullptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* An Env which manages the scope for (declare ...) statements.
|
|
|
|
*/
|
|
|
|
class DeclareEnv : public Env {
|
|
|
|
public:
|
|
|
|
explicit DeclareEnv(Env* parent) : Env(parent) {}
|
|
|
|
virtual std::string print() = 0;
|
|
|
|
~DeclareEnv() = default;
|
|
|
|
|
|
|
|
struct Settings {
|
|
|
|
bool is_set = false; // has the user set these with a (declare)?
|
|
|
|
bool inline_by_default = false; // if a function, inline when possible?
|
|
|
|
bool save_code = true; // if a function, should we save the code?
|
|
|
|
bool allow_inline = false; // should we allow the user to use this an inline function
|
2020-09-07 13:28:16 -04:00
|
|
|
} settings;
|
2020-09-06 12:45:31 -04:00
|
|
|
};
|
|
|
|
|
2020-09-07 19:17:48 -04:00
|
|
|
class IR_GotoLabel;
|
|
|
|
|
|
|
|
struct UnresolvedGoto {
|
2020-09-13 17:34:02 -04:00
|
|
|
IR_GotoLabel* ir = nullptr;
|
|
|
|
std::string label;
|
|
|
|
};
|
|
|
|
|
|
|
|
class IR_ConditionalBranch;
|
|
|
|
|
|
|
|
struct UnresolvedConditionalGoto {
|
|
|
|
IR_ConditionalBranch* ir = nullptr;
|
2020-09-07 19:17:48 -04:00
|
|
|
std::string label;
|
|
|
|
};
|
|
|
|
|
2020-09-06 12:45:31 -04:00
|
|
|
class FunctionEnv : public DeclareEnv {
|
|
|
|
public:
|
|
|
|
FunctionEnv(Env* parent, std::string name);
|
|
|
|
std::string print() override;
|
2020-09-07 19:17:48 -04:00
|
|
|
std::unordered_map<std::string, Label>& get_label_map() override;
|
2020-09-06 16:58:25 -04:00
|
|
|
void set_segment(int seg) { segment = seg; }
|
2020-09-06 12:45:31 -04:00
|
|
|
void emit(std::unique_ptr<IR> ir) override;
|
|
|
|
void finish();
|
|
|
|
RegVal* make_ireg(TypeSpec ts, emitter::RegKind kind) override;
|
2020-09-13 10:40:21 -04:00
|
|
|
const std::vector<std::unique_ptr<IR>>& code() const { return m_code; }
|
2020-09-06 16:58:25 -04:00
|
|
|
int max_vars() const { return m_iregs.size(); }
|
|
|
|
const std::vector<IRegConstraint>& constraints() { return m_constraints; }
|
2020-09-12 13:11:42 -04:00
|
|
|
void constrain(const IRegConstraint& c) { m_constraints.push_back(c); }
|
2020-09-06 16:58:25 -04:00
|
|
|
void set_allocations(const AllocationResult& result) { m_regalloc_result = result; }
|
2020-09-13 17:34:02 -04:00
|
|
|
RegVal* lexical_lookup(goos::Object sym) override;
|
2020-09-06 16:58:25 -04:00
|
|
|
const AllocationResult& alloc_result() { return m_regalloc_result; }
|
|
|
|
bool needs_aligned_stack() const { return m_aligned_stack_required; }
|
2020-09-12 13:11:42 -04:00
|
|
|
void require_aligned_stack() { m_aligned_stack_required = true; }
|
2020-09-13 17:34:02 -04:00
|
|
|
Label* alloc_unnamed_label() {
|
|
|
|
m_unnamed_labels.emplace_back(std::make_unique<Label>());
|
|
|
|
return m_unnamed_labels.back().get();
|
|
|
|
}
|
2020-11-13 22:33:57 -05:00
|
|
|
const std::string& name() const { return m_name; }
|
|
|
|
|
2020-11-22 12:22:19 -05:00
|
|
|
StackVarAddrVal* allocate_stack_variable(const TypeSpec& ts, int size_bytes);
|
|
|
|
int stack_slots_used_for_stack_vars() const { return m_stack_var_slots_used; }
|
|
|
|
|
2020-09-12 13:11:42 -04:00
|
|
|
int idx_in_file = -1;
|
2020-09-06 12:45:31 -04:00
|
|
|
|
|
|
|
template <typename T, class... Args>
|
|
|
|
T* alloc_val(Args&&... args) {
|
|
|
|
std::unique_ptr<T> new_obj = std::make_unique<T>(std::forward<Args>(args)...);
|
|
|
|
m_vals.push_back(std::move(new_obj));
|
|
|
|
return (T*)m_vals.back().get();
|
|
|
|
}
|
2020-09-07 19:17:48 -04:00
|
|
|
|
|
|
|
template <typename T, class... Args>
|
|
|
|
T* alloc_env(Args&&... args) {
|
|
|
|
std::unique_ptr<T> new_obj = std::make_unique<T>(std::forward<Args>(args)...);
|
|
|
|
m_envs.push_back(std::move(new_obj));
|
|
|
|
return (T*)m_envs.back().get();
|
|
|
|
}
|
|
|
|
|
2020-09-06 16:58:25 -04:00
|
|
|
int segment = -1;
|
2020-09-06 17:42:20 -04:00
|
|
|
std::string method_of_type_name = "#f";
|
2020-09-13 10:40:21 -04:00
|
|
|
bool is_asm_func = false;
|
2020-09-07 19:17:48 -04:00
|
|
|
std::vector<UnresolvedGoto> unresolved_gotos;
|
2020-09-13 17:34:02 -04:00
|
|
|
std::vector<UnresolvedConditionalGoto> unresolved_cond_gotos;
|
|
|
|
std::unordered_map<std::string, RegVal*> params;
|
2020-09-07 19:17:48 -04:00
|
|
|
|
2020-09-06 12:45:31 -04:00
|
|
|
protected:
|
2020-09-07 19:17:48 -04:00
|
|
|
void resolve_gotos();
|
2020-09-06 12:45:31 -04:00
|
|
|
std::string m_name;
|
|
|
|
std::vector<std::unique_ptr<IR>> m_code;
|
|
|
|
std::vector<std::unique_ptr<RegVal>> m_iregs;
|
|
|
|
std::vector<std::unique_ptr<Val>> m_vals;
|
2020-09-07 19:17:48 -04:00
|
|
|
std::vector<std::unique_ptr<Env>> m_envs;
|
2020-09-06 12:45:31 -04:00
|
|
|
std::vector<IRegConstraint> m_constraints;
|
|
|
|
// todo, unresolved gotos
|
|
|
|
AllocationResult m_regalloc_result;
|
|
|
|
|
|
|
|
bool m_aligned_stack_required = false;
|
2020-11-22 12:22:19 -05:00
|
|
|
int m_stack_var_slots_used = 0;
|
2020-09-07 19:17:48 -04:00
|
|
|
std::unordered_map<std::string, Label> m_labels;
|
2020-09-13 17:34:02 -04:00
|
|
|
std::vector<std::unique_ptr<Label>> m_unnamed_labels;
|
2020-09-06 12:45:31 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
class BlockEnv : public Env {
|
|
|
|
public:
|
|
|
|
BlockEnv(Env* parent, std::string name);
|
|
|
|
std::string print() override;
|
|
|
|
BlockEnv* find_block(const std::string& name) override;
|
2020-09-06 16:58:25 -04:00
|
|
|
|
2020-09-07 19:17:48 -04:00
|
|
|
std::string name;
|
|
|
|
Label end_label = nullptr;
|
|
|
|
RegVal* return_value = nullptr;
|
|
|
|
std::vector<TypeSpec> return_types;
|
2020-09-06 12:45:31 -04:00
|
|
|
};
|
|
|
|
|
2020-09-12 13:11:42 -04:00
|
|
|
class LexicalEnv : public DeclareEnv {
|
2020-09-06 12:45:31 -04:00
|
|
|
public:
|
2020-09-12 13:11:42 -04:00
|
|
|
explicit LexicalEnv(Env* parent) : DeclareEnv(parent) {}
|
2020-09-13 17:34:02 -04:00
|
|
|
RegVal* lexical_lookup(goos::Object sym) override;
|
2020-09-06 12:45:31 -04:00
|
|
|
std::string print() override;
|
2020-09-13 17:34:02 -04:00
|
|
|
std::unordered_map<std::string, RegVal*> vars;
|
2020-09-06 12:45:31 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
class LabelEnv : public Env {
|
|
|
|
public:
|
2020-09-12 13:11:42 -04:00
|
|
|
explicit LabelEnv(Env* parent) : Env(parent) {}
|
|
|
|
std::string print() override { return "labelenv"; }
|
2020-09-07 19:17:48 -04:00
|
|
|
std::unordered_map<std::string, Label>& get_label_map() override;
|
|
|
|
|
2020-09-06 12:45:31 -04:00
|
|
|
protected:
|
|
|
|
std::unordered_map<std::string, Label> m_labels;
|
|
|
|
};
|
|
|
|
|
2020-09-12 13:11:42 -04:00
|
|
|
class WithInlineEnv : public Env {
|
|
|
|
public:
|
|
|
|
WithInlineEnv(Env* parent, bool _inline_preference)
|
|
|
|
: Env(parent), inline_preference(_inline_preference) {}
|
|
|
|
bool inline_preference = false;
|
|
|
|
};
|
2020-09-06 12:45:31 -04:00
|
|
|
|
2020-09-12 13:11:42 -04:00
|
|
|
class SymbolMacroEnv : public Env {
|
|
|
|
public:
|
|
|
|
explicit SymbolMacroEnv(Env* parent) : Env(parent) {}
|
|
|
|
std::unordered_map<std::shared_ptr<goos::SymbolObject>, goos::Object> macros;
|
2020-09-13 17:34:02 -04:00
|
|
|
std::string print() override { return "symbol-macro-env"; }
|
2020-09-12 13:11:42 -04:00
|
|
|
};
|
2020-09-05 16:37:37 -04:00
|
|
|
|
2020-09-06 16:58:25 -04:00
|
|
|
template <typename T>
|
2020-09-06 12:45:31 -04:00
|
|
|
T* get_parent_env_of_type(Env* in) {
|
2020-09-06 16:58:25 -04:00
|
|
|
for (;;) {
|
2020-09-06 12:45:31 -04:00
|
|
|
auto attempt = dynamic_cast<T*>(in);
|
2020-09-06 16:58:25 -04:00
|
|
|
if (attempt)
|
|
|
|
return attempt;
|
|
|
|
if (dynamic_cast<GlobalEnv*>(in)) {
|
2020-09-06 12:45:31 -04:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
in = in->parent();
|
|
|
|
}
|
|
|
|
}
|
2020-09-05 16:37:37 -04:00
|
|
|
// function
|
|
|
|
// block
|
|
|
|
// lexical
|
|
|
|
// label
|
|
|
|
// symbolmacro
|
|
|
|
// get parent env of type.
|
|
|
|
|
|
|
|
#endif // JAK_ENV_H
|