hobbes
a language, embedded compiler, and runtime for efficient dynamic expression evaluation, data storage and analysis
jitcc.H
Go to the documentation of this file.
1 
2 #ifndef HOBBES_EVAL_JITCC_HPP_INCLUDED
3 #define HOBBES_EVAL_JITCC_HPP_INCLUDED
4 
5 #include <hobbes/lang/expr.H>
6 #include <hobbes/lang/type.H>
7 #include <hobbes/util/region.H>
8 
9 #include <hobbes/util/llvm.H>
10 #include <hobbes/eval/func.H>
11 #include <hobbes/eval/ctype.H>
12 
13 #include <map>
14 #include <string>
15 #include <vector>
16 
17 namespace hobbes {
18 
19 // an operation, which can emit some specialized assembly code
20 class jitcc;
21 struct op {
22  virtual ~op();
23 
24  // type : reports the functional type of this operator (may be polymorphic)
25  virtual PolyTypePtr type(typedb&) const = 0;
26 
27  // apply : produces some assembly code out of a JIT compiler,
28  // assuming the given input/output types and with expressions provided for arguments
29  virtual llvm::Value* apply(jitcc* ev, const MonoTypes& tys, const MonoTypePtr& rty, const Exprs& es) = 0;
30 };
31 
32 // a JIT compiler for monotyped expressions
33 class jitcc {
34 public:
35  jitcc();
36  ~jitcc();
37 
38  llvm::IRBuilder<>* builder() const;
39  llvm::Module* module();
40 
41  // get the address of a bound symbol
42  void* getSymbolAddress(const std::string&);
43 
44  // print all module contents
45  void dump() const;
46 
47  // define a global from a primitive expression
48  void defineGlobal(const std::string& vname, const ExprPtr& unsweetExp);
49 
50  // define a global on some existing memory
51  void bindGlobal(const std::string& vn, const MonoTypePtr& ty, void* v);
52 
53  // is there a definition of the named symbol?
54  bool isDefined(const std::string&) const;
55 
56  // compile a named or anonymous expression (into the current instruction stream)
57  // these assume that expressions have explicit (mono-)type annotations
58  llvm::Value* compile(const ExprPtr& exp);
59  llvm::Value* compile(const std::string& vname, const ExprPtr& exp);
60 
61  // backtrack on local-scope to compile an expression that uses only global data
62  llvm::Value* compileAtGlobalScope(const ExprPtr& exp);
63 
64  // compile a function or a set of mutually-recursive functions
65  llvm::Function* compileFunction(const std::string& name, const str::seq& argns, const MonoTypes& argtys, const ExprPtr& exp);
66  void compileFunctions(const LetRec::Bindings&, std::vector<llvm::Function*>* result);
67  void compileFunctions(const LetRec::Bindings&);
68 
69  // compile an allocation statement (to dynamically allocate some data)
70  llvm::Value* compileAllocStmt(size_t sz, llvm::Type* mty, bool zeroMem = false);
71  llvm::Value* compileAllocStmt(llvm::Value* sz, llvm::Type* mty, bool zeroMem = false);
72 
73  // begin a function with the given name, argument type list, return type
74  llvm::Function* allocFunction(const std::string& fname, const MonoTypes& argl, const MonoTypePtr& rty);
75 
76  // bind within local scopes, and begin/end new nested local scopes
77  void pushScope();
78  void bindScope(const std::string& vn, llvm::Value* v);
79  void popScope();
80 
81  // produce some machine code from a function specification (input names, input types, expression body)
82  void* reifyMachineCodeForFn(const MonoTypePtr& reqTy, const str::seq& names, const MonoTypes& tys, const ExprPtr& exp);
83  void releaseMachineCode(void*);
84 
85  // bind a low-level function definition
86  void bindInstruction(const std::string&, op*);
87 
88  // find a low-level function definition by name
89  op* lookupOp(const std::string&) const;
90 
91  // lookup a variable, either in local scopes, globals, or constants
92  llvm::Value* lookupVar(const std::string&, const MonoTypePtr&);
93 
94  // find a function by name (returns nullptr if not found)
95  llvm::Function* lookupFunction(const std::string&);
96 
97  // maybe get a pointer to global data
98  // this will give a nullptr either if the variable is in local scope, or if there is no global variable with that name
99  llvm::GlobalVariable* lookupVarRef(const std::string&);
100 
101  // produce a constant reference to an interned string
102  llvm::Value* internConstString(const std::string&);
103 
104  // get the machine code produced for a given expression
105  typedef std::vector<uint8_t> bytes;
106  bytes machineCodeForExpr(const ExprPtr&);
107 
108  // inline all global definitions within an expression
109  ExprPtr inlineGlobals(const ExprPtr&);
110 private:
111  // produce some machine code for a compiled function
112  void* getMachineCode(llvm::Function*, llvm::JITEventListener* listener = 0);
113 
114  // the current non-finalized module
115  // (new definitions will be accumulated here)
116  // (may be null, to lazily allocate modules)
117  llvm::Module* currentModule;
118 
119  // the set of allocated modules
120  typedef std::vector<llvm::Module*> Modules;
121  Modules modules;
122 
123 #if LLVM_VERSION_MINOR == 6 || LLVM_VERSION_MINOR == 7 || LLVM_VERSION_MINOR == 8
124  llvm::legacy::PassManager* mpm;
125 
126  // the set of allocated execution engines (each will own a finalized module from the set of modules)
127  typedef std::vector<llvm::ExecutionEngine*> ExecutionEngines;
128  ExecutionEngines eengines;
129 #elif LLVM_VERSION_MINOR == 3
130  llvm::PassManager* mpm;
131  llvm::ExecutionEngine* eengine;
132  llvm::FunctionPassManager* fpm;
133 #elif LLVM_VERSION_MINOR == 5
134  llvm::legacy::PassManager* mpm;
135  llvm::ExecutionEngine* eengine;
136  llvm::legacy::FunctionPassManager* fpm;
137 #else
138 #error "This version of LLVM is not supported"
139 #endif
140 
141  // support incremental construction of LLVM assembly sequences
142  llvm::IRBuilder<>* irbuilder;
143 
144  // the bound root function environment
145  typedef std::map<std::string, op*> FuncEnv;
146  FuncEnv fenv;
147 
148  // keep track of variables and local scopes during compilation
149  typedef std::map<std::string, llvm::Value*> VarBindings;
150  typedef std::vector<VarBindings> VarBindingStack;
151  VarBindingStack vtenv;
153 
154  // compile sets of mutually-recursive functions (as a special case, single-function compilation)
155  struct UCF {
156  const std::string& name;
157  const str::seq& argns;
159  const ExprPtr& exp;
160 
161  llvm::Function* result;
162 
163  inline UCF(const std::string& name, const str::seq& argns, const MonoTypes& argtys, const ExprPtr& exp)
164  : name(name), argns(argns), argtys(argtys), exp(exp) { }
165  };
166  typedef std::vector<UCF> UCFS;
167  void unsafeCompileFunctions(UCFS*);
168 
169  // keep track of global variables
170  struct Global {
172  void* value;
173  union {
174  llvm::GlobalVariable* var;
175  llvm::Function* fn;
176  } ref;
177  };
178  typedef std::map<std::string, Global> Globals;
179  Globals globals;
180 
181  // keep track of global data (in case we need to dynamically allocate global variables of any type)
183  size_t pushGlobalRegion();
184  void popGlobalRegion(size_t x);
185 
186  // keep track of global constants
187  struct Constant {
188  llvm::Constant* value;
189  llvm::Type* type;
191  llvm::GlobalVariable* ref;
192  };
193  typedef std::map<std::string, Constant> Constants;
194  Constants constants;
195  llvm::Value* loadConstant(const std::string&);
196 
197  // keep some interned strings, helpful for global constants and debug info
198  typedef std::unordered_map<std::string, std::string> InternConstVars;
199  InternConstVars internConstVars;
200 
201  // try to load a symbol as a global (may return nullptr if this can't be done)
202  llvm::GlobalVariable* maybeRefGlobal(const std::string&);
203  llvm::GlobalVariable* refGlobal(const std::string&, llvm::GlobalVariable*);
204 
205  // pass through a value if it's not a global or if it's a global in the current module
206  // else wrap it in an extern decl
207  llvm::Value* maybeRefGlobalV(llvm::Value*);
208 
209  // keep track of monotyped definitions as expressions
210  // (in case we want to inline them later)
211  typedef std::map<std::string, ExprPtr> GlobalExprs;
212  GlobalExprs globalExprs;
213 };
214 
215 // shorthand for compilation over a sequence of expressions
216 typedef std::vector<llvm::Value*> Values;
217 
218 Values compile(jitcc*, const Exprs&);
219 Values compileArgs(jitcc*, const Exprs&);
220 
221 }
222 
223 #endif
224 
std::vector< llvm::Value * > Values
Definition: jitcc.H:216
Values compileArgs(jitcc *, const Exprs &)
Definition: jitcc.C:776
std::shared_ptr< PolyType > PolyTypePtr
Definition: type.H:23
void * value
Definition: jitcc.H:172
Definition: jitcc.H:33
llvm::IRBuilder * irbuilder
Definition: jitcc.H:142
Definition: tylift.H:22
UCF(const std::string &name, const str::seq &argns, const MonoTypes &argtys, const ExprPtr &exp)
Definition: jitcc.H:163
Definition: jitcc.H:187
Globals globals
Definition: jitcc.H:179
std::map< std::string, op * > FuncEnv
Definition: jitcc.H:145
GlobalExprs globalExprs
Definition: jitcc.H:212
llvm::Function * result
Definition: jitcc.H:161
llvm::GlobalVariable * var
Definition: jitcc.H:174
Definition: boot.H:7
Definition: jitcc.H:170
const std::string & name
Definition: jitcc.H:156
llvm::Constant * value
Definition: jitcc.H:188
std::vector< ExprPtr > Exprs
Definition: expr.H:59
FuncEnv fenv
Definition: jitcc.H:146
MonoTypePtr type
Definition: jitcc.H:171
MonoType::ptr MonoTypePtr
Definition: type.H:71
std::map< std::string, Global > Globals
Definition: jitcc.H:178
llvm::GlobalVariable * ref
Definition: jitcc.H:191
bool ignoreLocalScope
Definition: jitcc.H:152
std::vector< uint8_t > bytes
Definition: jitcc.H:105
MonoTypes argtys
Definition: jitcc.H:158
llvm::Function * fn
Definition: jitcc.H:175
std::shared_ptr< Expr > ExprPtr
Definition: expr.H:58
Definition: jitcc.H:155
const ExprPtr & exp
Definition: jitcc.H:159
virtual PolyTypePtr type(typedb &) const =0
MonoTypePtr mtype
Definition: jitcc.H:190
std::vector< llvm::Module * > Modules
Definition: jitcc.H:120
std::vector< std::string > seq
Definition: str.H:19
llvm::Module * currentModule
Definition: jitcc.H:117
std::map< std::string, llvm::Value * > VarBindings
Definition: jitcc.H:149
std::vector< UCF > UCFS
Definition: jitcc.H:166
region globalData
Definition: jitcc.H:182
uint32_t result
Definition: regex.C:376
std::unordered_map< std::string, std::string > InternConstVars
Definition: jitcc.H:198
Constants constants
Definition: jitcc.H:194
std::map< std::string, Constant > Constants
Definition: jitcc.H:193
std::vector< VarBindings > VarBindingStack
Definition: jitcc.H:150
virtual llvm::Value * apply(jitcc *ev, const MonoTypes &tys, const MonoTypePtr &rty, const Exprs &es)=0
InternConstVars internConstVars
Definition: jitcc.H:199
virtual ~op()
Definition: jitcc.C:810
std::vector< MonoTypePtr > MonoTypes
Definition: type.H:72
std::vector< Binding > Bindings
Definition: expr.H:327
void compile(cc *, const ModulePtr &m)
Definition: cmodule.C:301
Definition: region.H:16
const str::seq & argns
Definition: jitcc.H:157
Modules modules
Definition: jitcc.H:121
llvm::Type * type
Definition: jitcc.H:189
Definition: jitcc.H:21
VarBindingStack vtenv
Definition: jitcc.H:151
std::map< std::string, ExprPtr > GlobalExprs
Definition: jitcc.H:211