summaryrefslogtreecommitdiff
path: root/tiger-compiler/src/llvmtranslate/translator.hh
blob: 3ddb625fa75c21a946ad5582fab931adecc58157 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/**
 ** \file llvmtranslate/translator.hh
 ** \brief Declaration of llvmtranslate::Translator
 */

#pragma once

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"

#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Value.h>

#pragma GCC diagnostic pop

#include <ast/default-visitor.hh>
#include <ast/non-assert-visitor.hh>
#include <ast/non-object-visitor.hh>
#include <llvmtranslate/fwd.hh>
#include <llvmtranslate/llvm-type-visitor.hh>

namespace llvmtranslate
{
  class Translator
    : 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();

    Translator(llvm::Module& module, escaped_map_type&& escaped);

    /// Run the translation.
    void operator()(const ast::Ast& e) override;

    /// \brief Run this visitor on \a node, and return its translation.
    ///
    /// It is also guaranteed that \a value_ is set to it.
    /// More generally, this routine saves from direct calls to \a accept.
    llvm::Value* translate(const ast::Ast& node);

    /// \name Lvalues
    /// \{
    void operator()(const ast::SimpleVar& e) override;
    void operator()(const ast::FieldVar& e) override;
    void operator()(const ast::SubscriptVar& e) override;
    /// \}

    /// \name Expressions
    /// \{
    void operator()(const ast::NilExp&) override;
    void operator()(const ast::IntExp& e) override;
    void operator()(const ast::StringExp& e) override;
    void operator()(const ast::RecordExp& e) override;
    void operator()(const ast::CallExp& e) override;
    void operator()(const ast::OpExp& e) override;
    void operator()(const ast::SeqExp& e) override;
    void operator()(const ast::AssignExp& e) override;
    void operator()(const ast::IfExp& e) override;
    void operator()(const ast::WhileExp& e) override;
    void operator()(const ast::BreakExp&) override;
    void operator()(const ast::ArrayExp& e) override;
    void operator()(const ast::CastExp& e) override;
    /// \}

    /// \name Declarations
    /// \{
    void operator()(const ast::FunctionChunk& e) override;
    void visit_function_dec_header(const ast::FunctionDec& e);
    void visit_function_dec_body(const ast::FunctionDec& e);
    void operator()(const ast::VarDec& e) override;

    /**
     * Check for the existence of a VarDec node within the current function
     * scoped (locals_[current_function_]).
     *
     * If the node does exist within the scope, its LLVM reference is returned
     * afterward. If not, nullptr is returned instead.
     *
     * @param e The node to look for
     * @return The associated LLVM value if e does exist within the scope.
     * nullptr otherwise
     */
    llvm::Value* declaration_in_current_scope(const ast::VarDec& e) const;

    /// \}

  protected:
    /// The translation of the last visited node.
    llvm::Value* value_ = nullptr;

    /// The current function.
    llvm::Function* current_function_ = nullptr;

    /// The module containing the metadata and this file's AST.
    llvm::Module& module_;

    /// The global context of the translator.
    llvm::LLVMContext& ctx_;

    /// IR builder to simplify building nodes and instructions.
    llvm::IRBuilder<> builder_;

    /// Access for each "variable".
    /// Since the AST doesn't contain the arguments added
    /// for the lambda lifting, we need to identify them by their declaration.
    std::map<const llvm::Function*, std::map<const ast::VarDec*, llvm::Value*>>
      locals_;

    /// For each loop, the basic block immediately after it.
    std::map<const ast::WhileExp*, llvm::BasicBlock*> loop_end_;

    /// Access every escaped variable for each function.
    escaped_map_type escaped_;

    /// The llvm type translator.
    LLVMTypeVisitor type_visitor_;

    /// Get a Tiger void value.
    inline llvm::Value* get_void_value();

    inline llvm::Value* get_dereferenced(llvm::Value* ptr, const type::Type* type);

  private:
    /// Get a LLVM access to a variable, usually to be loaded right after.
    llvm::Value* access_var(const ast::Var& e);

    /// Call the init_array function that allocates and initialize the array.
    llvm::Value* init_array(llvm::Value* count_val, llvm::Value* init_val);

    /// Get a llvm::Type from a type::Type using the type_visitor_.
    llvm::Type* llvm_type(const type::Type& type);

    /// Create a llvm function from a function type.
    llvm::FunctionType* llvm_function_type(const type::Function& function_t);
  };

} // namespace llvmtranslate

#include <llvmtranslate/translator.hxx>