15016
|
1 /* |
|
2 |
16768
|
3 Copyright (C) 2012 Max Brister |
15016
|
4 |
|
5 This file is part of Octave. |
|
6 |
|
7 Octave is free software; you can redistribute it and/or modify it |
|
8 under the terms of the GNU General Public License as published by the |
|
9 Free Software Foundation; either version 3 of the License, or (at your |
|
10 option) any later version. |
|
11 |
|
12 Octave is distributed in the hope that it will be useful, but WITHOUT |
|
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
15 for more details. |
|
16 |
|
17 You should have received a copy of the GNU General Public License |
|
18 along with Octave; see the file COPYING. If not, see |
|
19 <http://www.gnu.org/licenses/>. |
|
20 |
|
21 */ |
|
22 |
16768
|
23 // Author: Max Brister <max@2bass.com> |
|
24 |
15016
|
25 // Some utility classes and functions used throughout jit |
|
26 |
|
27 #if !defined (octave_jit_util_h) |
|
28 #define octave_jit_util_h 1 |
|
29 |
|
30 #ifdef HAVE_LLVM |
|
31 |
|
32 #include <stdexcept> |
|
33 |
17172
|
34 #if defined(HAVE_LLVM_IR_DATALAYOUT_H) || defined(HAVE_LLVM_DATALAYOUT_H) |
|
35 #define HAVE_LLVM_DATALAYOUT |
|
36 #endif |
|
37 |
15016
|
38 // we don't want to include llvm headers here, as they require |
|
39 // __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS be defined in the entire |
|
40 // compilation unit |
|
41 namespace llvm |
|
42 { |
|
43 class Value; |
|
44 class Module; |
|
45 class FunctionPassManager; |
|
46 class PassManager; |
|
47 class ExecutionEngine; |
|
48 class Function; |
|
49 class BasicBlock; |
|
50 class LLVMContext; |
|
51 class Type; |
|
52 class StructType; |
|
53 class Twine; |
|
54 class GlobalVariable; |
|
55 class TerminatorInst; |
|
56 class PHINode; |
|
57 |
|
58 class ConstantFolder; |
|
59 |
|
60 template <bool preserveNames> |
|
61 class IRBuilderDefaultInserter; |
|
62 |
|
63 template <bool preserveNames, typename T, typename Inserter> |
|
64 class IRBuilder; |
|
65 |
|
66 typedef IRBuilder<true, ConstantFolder, IRBuilderDefaultInserter<true> > |
|
67 IRBuilderD; |
|
68 } |
|
69 |
|
70 class octave_base_value; |
|
71 class octave_builtin; |
|
72 class octave_value; |
|
73 class tree; |
|
74 class tree_expression; |
|
75 |
|
76 // thrown when we should give up on JIT and interpret |
|
77 class jit_fail_exception : public std::runtime_error |
|
78 { |
|
79 public: |
|
80 jit_fail_exception (void) : std::runtime_error ("unknown"), mknown (false) {} |
|
81 jit_fail_exception (const std::string& reason) : std::runtime_error (reason), |
|
82 mknown (true) |
|
83 {} |
|
84 |
|
85 bool known (void) const { return mknown; } |
|
86 private: |
|
87 bool mknown; |
|
88 }; |
|
89 |
|
90 // llvm doesn't provide this, and it's really useful for debugging |
|
91 std::ostream& operator<< (std::ostream& os, const llvm::Value& v); |
|
92 |
|
93 template <typename HOLDER_T, typename SUB_T> |
|
94 class jit_internal_node; |
|
95 |
|
96 // jit_internal_list and jit_internal_node implement generic embedded doubly |
|
97 // linked lists. List items extend from jit_internal_list, and can be placed |
|
98 // in nodes of type jit_internal_node. We use CRTP twice. |
|
99 template <typename LIST_T, typename NODE_T> |
|
100 class |
|
101 jit_internal_list |
|
102 { |
|
103 friend class jit_internal_node<LIST_T, NODE_T>; |
|
104 public: |
|
105 jit_internal_list (void) : use_head (0), use_tail (0), muse_count (0) {} |
|
106 |
|
107 virtual ~jit_internal_list (void) |
|
108 { |
|
109 while (use_head) |
|
110 use_head->stash_value (0); |
|
111 } |
|
112 |
|
113 NODE_T *first_use (void) const { return use_head; } |
|
114 |
|
115 size_t use_count (void) const { return muse_count; } |
|
116 private: |
|
117 NODE_T *use_head; |
|
118 NODE_T *use_tail; |
|
119 size_t muse_count; |
|
120 }; |
|
121 |
|
122 // a node for internal linked lists |
|
123 template <typename LIST_T, typename NODE_T> |
|
124 class |
|
125 jit_internal_node |
|
126 { |
|
127 public: |
|
128 typedef jit_internal_list<LIST_T, NODE_T> jit_ilist; |
|
129 |
|
130 jit_internal_node (void) : mvalue (0), mnext (0), mprev (0) {} |
|
131 |
|
132 ~jit_internal_node (void) { remove (); } |
|
133 |
|
134 LIST_T *value (void) const { return mvalue; } |
|
135 |
|
136 void stash_value (LIST_T *avalue) |
|
137 { |
|
138 remove (); |
|
139 |
|
140 mvalue = avalue; |
|
141 |
|
142 if (mvalue) |
|
143 { |
|
144 jit_ilist *ilist = mvalue; |
|
145 NODE_T *sthis = static_cast<NODE_T *> (this); |
|
146 if (ilist->use_head) |
|
147 { |
|
148 ilist->use_tail->mnext = sthis; |
|
149 mprev = ilist->use_tail; |
|
150 } |
|
151 else |
|
152 ilist->use_head = sthis; |
|
153 |
|
154 ilist->use_tail = sthis; |
|
155 ++ilist->muse_count; |
|
156 } |
|
157 } |
|
158 |
|
159 NODE_T *next (void) const { return mnext; } |
|
160 |
|
161 NODE_T *prev (void) const { return mprev; } |
|
162 private: |
|
163 void remove () |
|
164 { |
|
165 if (mvalue) |
|
166 { |
|
167 jit_ilist *ilist = mvalue; |
|
168 if (mprev) |
|
169 mprev->mnext = mnext; |
|
170 else |
|
171 // we are the use_head |
|
172 ilist->use_head = mnext; |
|
173 |
|
174 if (mnext) |
|
175 mnext->mprev = mprev; |
|
176 else |
|
177 // we are the use tail |
|
178 ilist->use_tail = mprev; |
|
179 |
|
180 mnext = mprev = 0; |
|
181 --ilist->muse_count; |
|
182 mvalue = 0; |
|
183 } |
|
184 } |
|
185 |
|
186 LIST_T *mvalue; |
|
187 NODE_T *mnext; |
|
188 NODE_T *mprev; |
|
189 }; |
|
190 |
|
191 // Use like: isa<jit_phi> (value) |
|
192 // basically just a short cut type typing dyanmic_cast. |
|
193 template <typename T, typename U> |
|
194 bool isa (U *value) |
|
195 { |
|
196 return dynamic_cast<T *> (value); |
|
197 } |
|
198 |
|
199 #define JIT_ASSIGN_ARG(i) the_args[i] = arg ## i; |
|
200 #define JIT_EXPAND(ret, fname, type, isconst, N) \ |
|
201 ret fname (JIT_PARAM_ARGS OCT_MAKE_DECL_LIST (type, arg, N)) isconst \ |
|
202 { \ |
|
203 std::vector<type> the_args (N); \ |
|
204 OCT_ITERATE_MACRO (JIT_ASSIGN_ARG, N); \ |
|
205 return fname (JIT_PARAMS the_args); \ |
|
206 } |
|
207 |
|
208 #endif |
|
209 #endif |