Mercurial > octave-nkf
annotate src/interp-core/jit-ir.h @ 15102:d29f2583cf7b
Support end in multi indexing in JIT
* src/interp-core/jit-ir.cc (jit_magic_end::context::context): New function.
(jit_magic_end::jit_magic_end): Take context vector as argument.
(jit_magic_end::resolve_context): Return a context.
(jit_magic_end::print): Prettify output.
(jit_magic_end::overload): Use context.
* src/interp-core/jit-ir.h (jit_magic_end::context::context,
jit_magic_end::print): Move implementation to src/jit-ir.cc.
(jit_magic_end::short_print): Prettify output.
(jit_magic_end::resolve_context): Return a context.
* src/interp-core/jit-typeinfo.cc (octave_jit_end_matrix): New function.
(jit_typeinfo::jit_typeinfo): Initilaize end_fn and end1_fn.
(jit_typeinfo::do_end): New function.
(jit_typeinfo::new_type): Moved location in file.
* src/interp-core/jit-typeinfo.h (jit_typeinfo::end): Take index and count
arguments.
(jit_typeinfo::do_end): New declaration.
* src/interp-core/pt-jit.cc (jit_convert::resolve): Pass extra argument to
context constructor.
(jit_convert::convert_llvm::visit): New arguments to jit_magic_end overload.
author | Max Brister <max@2bass.com> |
---|---|
date | Sat, 04 Aug 2012 00:19:07 -0500 |
parents | 909a2797935b |
children | a7a56b436de2 |
rev | line source |
---|---|
15016 | 1 /* |
2 | |
3 Copyright (C) 2012 Max Brister <max@2bass.com> | |
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 | |
23 #if !defined (octave_jit_ir_h) | |
24 #define octave_jit_ir_h 1 | |
25 | |
26 #ifdef HAVE_LLVM | |
27 | |
28 #include <list> | |
29 #include <stack> | |
30 #include <set> | |
31 | |
32 #include "jit-typeinfo.h" | |
33 | |
34 // The low level octave jit ir | |
35 // this ir is close to llvm, but contains information for doing type inference. | |
36 // We convert the octave parse tree to this IR directly. | |
37 | |
38 #define JIT_VISIT_IR_NOTEMPLATE \ | |
39 JIT_METH(block); \ | |
40 JIT_METH(branch); \ | |
41 JIT_METH(cond_branch); \ | |
42 JIT_METH(call); \ | |
43 JIT_METH(extract_argument); \ | |
44 JIT_METH(store_argument); \ | |
45 JIT_METH(phi); \ | |
46 JIT_METH(variable); \ | |
47 JIT_METH(error_check); \ | |
48 JIT_METH(assign) \ | |
15056
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
49 JIT_METH(argument) \ |
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
50 JIT_METH(magic_end) |
15016 | 51 |
52 #define JIT_VISIT_IR_CONST \ | |
53 JIT_METH(const_bool); \ | |
54 JIT_METH(const_scalar); \ | |
55 JIT_METH(const_complex); \ | |
56 JIT_METH(const_index); \ | |
57 JIT_METH(const_string); \ | |
58 JIT_METH(const_range) | |
59 | |
60 #define JIT_VISIT_IR_CLASSES \ | |
61 JIT_VISIT_IR_NOTEMPLATE \ | |
62 JIT_VISIT_IR_CONST | |
63 | |
64 // forward declare all ir classes | |
65 #define JIT_METH(cname) \ | |
66 class jit_ ## cname; | |
67 | |
68 JIT_VISIT_IR_NOTEMPLATE | |
69 | |
70 #undef JIT_METH | |
71 | |
72 class jit_convert; | |
73 | |
74 // ABCs which aren't included in JIT_VISIT_IR_ALL | |
75 class jit_instruction; | |
76 class jit_terminator; | |
77 | |
78 template <typename T, jit_type *(*EXTRACT_T)(void), typename PASS_T = T, | |
79 bool QUOTE=false> | |
80 class jit_const; | |
81 | |
82 typedef jit_const<bool, jit_typeinfo::get_bool> jit_const_bool; | |
83 typedef jit_const<double, jit_typeinfo::get_scalar> jit_const_scalar; | |
84 typedef jit_const<Complex, jit_typeinfo::get_complex> jit_const_complex; | |
85 typedef jit_const<octave_idx_type, jit_typeinfo::get_index> jit_const_index; | |
86 | |
87 typedef jit_const<std::string, jit_typeinfo::get_string, const std::string&, | |
88 true> jit_const_string; | |
89 typedef jit_const<jit_range, jit_typeinfo::get_range, const jit_range&> | |
90 jit_const_range; | |
91 | |
92 class jit_ir_walker; | |
93 class jit_use; | |
94 | |
95 class | |
96 jit_value : public jit_internal_list<jit_value, jit_use> | |
97 { | |
98 public: | |
99 jit_value (void) : llvm_value (0), ty (0), mlast_use (0), | |
100 min_worklist (false) {} | |
101 | |
102 virtual ~jit_value (void); | |
103 | |
104 bool in_worklist (void) const | |
105 { | |
106 return min_worklist; | |
107 } | |
108 | |
109 void stash_in_worklist (bool ain_worklist) | |
110 { | |
111 min_worklist = ain_worklist; | |
112 } | |
113 | |
114 // The block of the first use which is not a jit_error_check | |
115 // So this is not necessarily first_use ()->parent (). | |
116 jit_block *first_use_block (void); | |
117 | |
118 // replace all uses with | |
119 virtual void replace_with (jit_value *value); | |
120 | |
121 jit_type *type (void) const { return ty; } | |
122 | |
123 llvm::Type *type_llvm (void) const | |
124 { | |
125 return ty ? ty->to_llvm () : 0; | |
126 } | |
127 | |
128 const std::string& type_name (void) const | |
129 { | |
130 return ty->name (); | |
131 } | |
132 | |
133 void stash_type (jit_type *new_ty) { ty = new_ty; } | |
134 | |
135 std::string print_string (void) | |
136 { | |
137 std::stringstream ss; | |
138 print (ss); | |
139 return ss.str (); | |
140 } | |
141 | |
142 jit_instruction *last_use (void) const { return mlast_use; } | |
143 | |
144 void stash_last_use (jit_instruction *alast_use) | |
145 { | |
146 mlast_use = alast_use; | |
147 } | |
148 | |
149 virtual bool needs_release (void) const { return false; } | |
150 | |
151 virtual std::ostream& print (std::ostream& os, size_t indent = 0) const = 0; | |
152 | |
153 virtual std::ostream& short_print (std::ostream& os) const | |
154 { return print (os); } | |
155 | |
156 virtual void accept (jit_ir_walker& walker) = 0; | |
157 | |
158 bool has_llvm (void) const | |
159 { | |
160 return llvm_value; | |
161 } | |
162 | |
163 llvm::Value *to_llvm (void) const | |
164 { | |
165 assert (llvm_value); | |
166 return llvm_value; | |
167 } | |
168 | |
169 void stash_llvm (llvm::Value *compiled) | |
170 { | |
171 llvm_value = compiled; | |
172 } | |
173 | |
174 protected: | |
175 std::ostream& print_indent (std::ostream& os, size_t indent = 0) const | |
176 { | |
177 for (size_t i = 0; i < indent * 8; ++i) | |
178 os << " "; | |
179 return os; | |
180 } | |
181 | |
182 llvm::Value *llvm_value; | |
183 private: | |
184 jit_type *ty; | |
185 jit_instruction *mlast_use; | |
186 bool min_worklist; | |
187 }; | |
188 | |
189 std::ostream& operator<< (std::ostream& os, const jit_value& value); | |
190 std::ostream& jit_print (std::ostream& os, jit_value *avalue); | |
191 | |
192 class | |
193 jit_use : public jit_internal_node<jit_value, jit_use> | |
194 { | |
195 public: | |
196 jit_use (void) : muser (0), mindex (0) {} | |
197 | |
198 // we should really have a move operator, but not until c++11 :( | |
199 jit_use (const jit_use& use) : muser (0), mindex (0) | |
200 { | |
201 *this = use; | |
202 } | |
203 | |
204 jit_use& operator= (const jit_use& use) | |
205 { | |
206 stash_value (use.value (), use.user (), use.index ()); | |
207 return *this; | |
208 } | |
209 | |
210 size_t index (void) const { return mindex; } | |
211 | |
212 jit_instruction *user (void) const { return muser; } | |
213 | |
214 jit_block *user_parent (void) const; | |
215 | |
216 std::list<jit_block *> user_parent_location (void) const; | |
217 | |
218 void stash_value (jit_value *avalue, jit_instruction *auser = 0, | |
219 size_t aindex = -1) | |
220 { | |
221 jit_internal_node::stash_value (avalue); | |
222 mindex = aindex; | |
223 muser = auser; | |
224 } | |
225 private: | |
226 jit_instruction *muser; | |
227 size_t mindex; | |
228 }; | |
229 | |
230 class | |
231 jit_instruction : public jit_value | |
232 { | |
233 public: | |
234 // FIXME: this code could be so much pretier with varadic templates... | |
235 jit_instruction (void) : mid (next_id ()), mparent (0) | |
236 {} | |
237 | |
238 jit_instruction (size_t nargs) : mid (next_id ()), mparent (0) | |
239 { | |
240 already_infered.reserve (nargs); | |
241 marguments.reserve (nargs); | |
242 } | |
243 | |
244 #define STASH_ARG(i) stash_argument (i, arg ## i); | |
245 #define JIT_INSTRUCTION_CTOR(N) \ | |
246 jit_instruction (OCT_MAKE_DECL_LIST (jit_value *, arg, N)) \ | |
247 : already_infered (N), marguments (N), mid (next_id ()), mparent (0) \ | |
248 { \ | |
249 OCT_ITERATE_MACRO (STASH_ARG, N); \ | |
250 } | |
251 | |
252 JIT_INSTRUCTION_CTOR(1) | |
253 JIT_INSTRUCTION_CTOR(2) | |
254 JIT_INSTRUCTION_CTOR(3) | |
255 JIT_INSTRUCTION_CTOR(4) | |
256 | |
257 #undef STASH_ARG | |
258 #undef JIT_INSTRUCTION_CTOR | |
259 | |
15056
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
260 jit_instruction (const std::vector<jit_value *>& aarguments) |
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
261 : already_infered (aarguments.size ()), marguments (aarguments.size ()), |
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
262 mid (next_id ()), mparent (0) |
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
263 { |
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
264 for (size_t i = 0; i < aarguments.size (); ++i) |
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
265 stash_argument (i, aarguments[i]); |
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
266 } |
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
267 |
15016 | 268 static void reset_ids (void) |
269 { | |
270 next_id (true); | |
271 } | |
272 | |
273 jit_value *argument (size_t i) const | |
274 { | |
275 return marguments[i].value (); | |
276 } | |
277 | |
278 llvm::Value *argument_llvm (size_t i) const | |
279 { | |
280 assert (argument (i)); | |
281 return argument (i)->to_llvm (); | |
282 } | |
283 | |
284 jit_type *argument_type (size_t i) const | |
285 { | |
286 return argument (i)->type (); | |
287 } | |
288 | |
289 llvm::Type *argument_type_llvm (size_t i) const | |
290 { | |
291 assert (argument (i)); | |
292 return argument_type (i)->to_llvm (); | |
293 } | |
294 | |
295 std::ostream& print_argument (std::ostream& os, size_t i) const | |
296 { | |
297 if (argument (i)) | |
298 return argument (i)->short_print (os); | |
299 else | |
300 return os << "NULL"; | |
301 } | |
302 | |
303 void stash_argument (size_t i, jit_value *arg) | |
304 { | |
305 marguments[i].stash_value (arg, this, i); | |
306 } | |
307 | |
308 void push_argument (jit_value *arg) | |
309 { | |
310 marguments.push_back (jit_use ()); | |
311 stash_argument (marguments.size () - 1, arg); | |
312 already_infered.push_back (0); | |
313 } | |
314 | |
315 size_t argument_count (void) const | |
316 { | |
317 return marguments.size (); | |
318 } | |
319 | |
320 void resize_arguments (size_t acount, jit_value *adefault = 0) | |
321 { | |
322 size_t old = marguments.size (); | |
323 marguments.resize (acount); | |
324 already_infered.resize (acount); | |
325 | |
326 if (adefault) | |
327 for (size_t i = old; i < acount; ++i) | |
328 stash_argument (i, adefault); | |
329 } | |
330 | |
331 const std::vector<jit_use>& arguments (void) const { return marguments; } | |
332 | |
333 // argument types which have been infered already | |
334 const std::vector<jit_type *>& argument_types (void) const | |
335 { return already_infered; } | |
336 | |
337 virtual void push_variable (void) {} | |
338 | |
339 virtual void pop_variable (void) {} | |
340 | |
341 virtual void construct_ssa (void) | |
342 { | |
343 do_construct_ssa (0, argument_count ()); | |
344 } | |
345 | |
346 virtual bool infer (void) { return false; } | |
347 | |
348 void remove (void); | |
349 | |
350 virtual std::ostream& short_print (std::ostream& os) const; | |
351 | |
352 jit_block *parent (void) const { return mparent; } | |
353 | |
354 std::list<jit_instruction *>::iterator location (void) const | |
355 { | |
356 return mlocation; | |
357 } | |
358 | |
359 llvm::BasicBlock *parent_llvm (void) const; | |
360 | |
361 void stash_parent (jit_block *aparent, | |
362 std::list<jit_instruction *>::iterator alocation) | |
363 { | |
364 mparent = aparent; | |
365 mlocation = alocation; | |
366 } | |
367 | |
368 size_t id (void) const { return mid; } | |
369 protected: | |
370 | |
371 // Do SSA replacement on arguments in [start, end) | |
372 void do_construct_ssa (size_t start, size_t end); | |
373 | |
374 std::vector<jit_type *> already_infered; | |
375 private: | |
376 static size_t next_id (bool reset = false) | |
377 { | |
378 static size_t ret = 0; | |
379 if (reset) | |
380 return ret = 0; | |
381 | |
382 return ret++; | |
383 } | |
384 | |
385 std::vector<jit_use> marguments; | |
386 | |
387 size_t mid; | |
388 jit_block *mparent; | |
389 std::list<jit_instruction *>::iterator mlocation; | |
390 }; | |
391 | |
392 // defnie accept methods for subclasses | |
393 #define JIT_VALUE_ACCEPT \ | |
394 virtual void accept (jit_ir_walker& walker); | |
395 | |
396 // for use as a dummy argument during conversion to LLVM | |
397 class | |
398 jit_argument : public jit_value | |
399 { | |
400 public: | |
401 jit_argument (jit_type *atype, llvm::Value *avalue) | |
402 { | |
403 stash_type (atype); | |
404 stash_llvm (avalue); | |
405 } | |
406 | |
407 virtual std::ostream& print (std::ostream& os, size_t indent = 0) const | |
408 { | |
409 print_indent (os, indent); | |
410 return jit_print (os, type ()) << ": DUMMY"; | |
411 } | |
412 | |
413 JIT_VALUE_ACCEPT; | |
414 }; | |
415 | |
416 template <typename T, jit_type *(*EXTRACT_T)(void), typename PASS_T, | |
417 bool QUOTE> | |
418 class | |
419 jit_const : public jit_value | |
420 { | |
421 public: | |
422 typedef PASS_T pass_t; | |
423 | |
424 jit_const (PASS_T avalue) : mvalue (avalue) | |
425 { | |
426 stash_type (EXTRACT_T ()); | |
427 } | |
428 | |
429 PASS_T value (void) const { return mvalue; } | |
430 | |
431 virtual std::ostream& print (std::ostream& os, size_t indent = 0) const | |
432 { | |
433 print_indent (os, indent); | |
434 jit_print (os, type ()) << ": "; | |
435 if (QUOTE) | |
436 os << "\""; | |
437 os << mvalue; | |
438 if (QUOTE) | |
439 os << "\""; | |
440 return os; | |
441 } | |
442 | |
443 JIT_VALUE_ACCEPT; | |
444 private: | |
445 T mvalue; | |
446 }; | |
447 | |
448 class jit_phi_incomming; | |
449 | |
450 class | |
451 jit_block : public jit_value, public jit_internal_list<jit_block, | |
452 jit_phi_incomming> | |
453 { | |
454 typedef jit_internal_list<jit_block, jit_phi_incomming> ILIST_T; | |
455 public: | |
456 typedef std::list<jit_instruction *> instruction_list; | |
457 typedef instruction_list::iterator iterator; | |
458 typedef instruction_list::const_iterator const_iterator; | |
459 | |
460 typedef std::set<jit_block *> df_set; | |
461 typedef df_set::const_iterator df_iterator; | |
462 | |
463 static const size_t NO_ID = static_cast<size_t> (-1); | |
464 | |
465 jit_block (const std::string& aname, size_t avisit_count = 0) | |
466 : mvisit_count (avisit_count), mid (NO_ID), idom (0), mname (aname), | |
467 malive (false) | |
468 {} | |
469 | |
470 virtual void replace_with (jit_value *value); | |
471 | |
472 void replace_in_phi (jit_block *ablock, jit_block *with); | |
473 | |
474 // we have a new internal list, but we want to stay compatable with jit_value | |
475 jit_use *first_use (void) const { return jit_value::first_use (); } | |
476 | |
477 size_t use_count (void) const { return jit_value::use_count (); } | |
478 | |
479 // if a block is alive, then it might be visited during execution | |
480 bool alive (void) const { return malive; } | |
481 | |
482 void mark_alive (void) { malive = true; } | |
483 | |
484 // If we can merge with a successor, do so and return the now empty block | |
485 jit_block *maybe_merge (); | |
486 | |
487 // merge another block into this block, leaving the merge block empty | |
488 void merge (jit_block& merge); | |
489 | |
490 const std::string& name (void) const { return mname; } | |
491 | |
492 jit_instruction *prepend (jit_instruction *instr); | |
493 | |
494 jit_instruction *prepend_after_phi (jit_instruction *instr); | |
495 | |
496 template <typename T> | |
497 T *append (T *instr) | |
498 { | |
499 internal_append (instr); | |
500 return instr; | |
501 } | |
502 | |
503 jit_instruction *insert_before (iterator loc, jit_instruction *instr); | |
504 | |
505 jit_instruction *insert_before (jit_instruction *loc, jit_instruction *instr) | |
506 { | |
507 return insert_before (loc->location (), instr); | |
508 } | |
509 | |
510 jit_instruction *insert_after (iterator loc, jit_instruction *instr); | |
511 | |
512 jit_instruction *insert_after (jit_instruction *loc, jit_instruction *instr) | |
513 { | |
514 return insert_after (loc->location (), instr); | |
515 } | |
516 | |
517 iterator remove (iterator iter) | |
518 { | |
519 jit_instruction *instr = *iter; | |
520 iter = instructions.erase (iter); | |
521 instr->stash_parent (0, instructions.end ()); | |
522 return iter; | |
523 } | |
524 | |
525 jit_terminator *terminator (void) const; | |
526 | |
527 // is the jump from pred alive? | |
528 bool branch_alive (jit_block *asucc) const; | |
529 | |
530 jit_block *successor (size_t i) const; | |
531 | |
532 size_t successor_count (void) const; | |
533 | |
534 iterator begin (void) { return instructions.begin (); } | |
535 | |
536 const_iterator begin (void) const { return instructions.begin (); } | |
537 | |
538 iterator end (void) { return instructions.end (); } | |
539 | |
540 const_iterator end (void) const { return instructions.end (); } | |
541 | |
542 iterator phi_begin (void); | |
543 | |
544 iterator phi_end (void); | |
545 | |
546 iterator nonphi_begin (void); | |
547 | |
548 // must label before id is valid | |
549 size_t id (void) const { return mid; } | |
550 | |
551 // dominance frontier | |
552 const df_set& df (void) const { return mdf; } | |
553 | |
554 df_iterator df_begin (void) const { return mdf.begin (); } | |
555 | |
556 df_iterator df_end (void) const { return mdf.end (); } | |
557 | |
558 // label with a RPO walk | |
559 void label (void) | |
560 { | |
561 size_t number = 0; | |
562 label (mvisit_count, number); | |
563 } | |
564 | |
565 void label (size_t avisit_count, size_t& number) | |
566 { | |
567 if (visited (avisit_count)) | |
568 return; | |
569 | |
570 for (jit_use *use = first_use (); use; use = use->next ()) | |
571 { | |
572 jit_block *pred = use->user_parent (); | |
573 pred->label (avisit_count, number); | |
574 } | |
575 | |
576 mid = number++; | |
577 } | |
578 | |
579 // See for idom computation algorithm | |
580 // Cooper, Keith D.; Harvey, Timothy J; and Kennedy, Ken (2001). | |
581 // "A Simple, Fast Dominance Algorithm" | |
582 void compute_idom (jit_block *entry_block) | |
583 { | |
584 bool changed; | |
585 entry_block->idom = entry_block; | |
586 do | |
587 changed = update_idom (mvisit_count); | |
588 while (changed); | |
589 } | |
590 | |
591 // compute dominance frontier | |
592 void compute_df (void) | |
593 { | |
594 compute_df (mvisit_count); | |
595 } | |
596 | |
597 void create_dom_tree (void) | |
598 { | |
599 create_dom_tree (mvisit_count); | |
600 } | |
601 | |
602 jit_block *dom_successor (size_t idx) const | |
603 { | |
604 return dom_succ[idx]; | |
605 } | |
606 | |
607 size_t dom_successor_count (void) const | |
608 { | |
609 return dom_succ.size (); | |
610 } | |
611 | |
612 // call pop_varaible on all instructions | |
613 void pop_all (void); | |
614 | |
615 virtual std::ostream& print (std::ostream& os, size_t indent = 0) const | |
616 { | |
617 print_indent (os, indent); | |
618 short_print (os) << ": %pred = "; | |
619 for (jit_use *use = first_use (); use; use = use->next ()) | |
620 { | |
621 jit_block *pred = use->user_parent (); | |
622 os << *pred; | |
623 if (use->next ()) | |
624 os << ", "; | |
625 } | |
626 os << std::endl; | |
627 | |
628 for (const_iterator iter = begin (); iter != end (); ++iter) | |
629 { | |
630 jit_instruction *instr = *iter; | |
631 instr->print (os, indent + 1) << std::endl; | |
632 } | |
633 return os; | |
634 } | |
635 | |
636 // ... | |
637 jit_block *maybe_split (jit_convert& convert, jit_block *asuccessor); | |
638 | |
639 jit_block *maybe_split (jit_convert& convert, jit_block& asuccessor) | |
640 { | |
641 return maybe_split (convert, &asuccessor); | |
642 } | |
643 | |
644 // print dominator infomration | |
645 std::ostream& print_dom (std::ostream& os) const; | |
646 | |
647 virtual std::ostream& short_print (std::ostream& os) const | |
648 { | |
649 os << mname; | |
650 if (mid != NO_ID) | |
651 os << mid; | |
652 return os; | |
653 } | |
654 | |
655 llvm::BasicBlock *to_llvm (void) const; | |
656 | |
657 std::list<jit_block *>::iterator location (void) const | |
658 { return mlocation; } | |
659 | |
660 void stash_location (std::list<jit_block *>::iterator alocation) | |
661 { mlocation = alocation; } | |
662 | |
663 // used to prevent visiting the same node twice in the graph | |
664 size_t visit_count (void) const { return mvisit_count; } | |
665 | |
666 // check if this node has been visited yet at the given visit count. If we | |
667 // have not been visited yet, mark us as visited. | |
668 bool visited (size_t avisit_count) | |
669 { | |
670 if (mvisit_count <= avisit_count) | |
671 { | |
672 mvisit_count = avisit_count + 1; | |
673 return false; | |
674 } | |
675 | |
676 return true; | |
677 } | |
678 | |
679 JIT_VALUE_ACCEPT; | |
680 private: | |
681 void internal_append (jit_instruction *instr); | |
682 | |
683 void compute_df (size_t avisit_count); | |
684 | |
685 bool update_idom (size_t avisit_count); | |
686 | |
687 void create_dom_tree (size_t avisit_count); | |
688 | |
689 static jit_block *idom_intersect (jit_block *i, jit_block *j); | |
690 | |
691 size_t mvisit_count; | |
692 size_t mid; | |
693 jit_block *idom; | |
694 df_set mdf; | |
695 std::vector<jit_block *> dom_succ; | |
696 std::string mname; | |
697 instruction_list instructions; | |
698 bool malive; | |
699 std::list<jit_block *>::iterator mlocation; | |
700 }; | |
701 | |
702 // keeps track of phi functions that use a block on incomming edges | |
703 class | |
704 jit_phi_incomming : public jit_internal_node<jit_block, jit_phi_incomming> | |
705 { | |
706 public: | |
707 jit_phi_incomming (void) : muser (0) {} | |
708 | |
709 jit_phi_incomming (jit_phi *auser) : muser (auser) {} | |
710 | |
711 jit_phi_incomming (const jit_phi_incomming& use) : jit_internal_node () | |
712 { | |
713 *this = use; | |
714 } | |
715 | |
716 jit_phi_incomming& operator= (const jit_phi_incomming& use) | |
717 { | |
718 stash_value (use.value ()); | |
719 muser = use.muser; | |
720 return *this; | |
721 } | |
722 | |
723 jit_phi *user (void) const { return muser; } | |
724 | |
725 jit_block *user_parent (void) const; | |
726 private: | |
727 jit_phi *muser; | |
728 }; | |
729 | |
730 // A non-ssa variable | |
731 class | |
732 jit_variable : public jit_value | |
733 { | |
734 public: | |
735 jit_variable (const std::string& aname) : mname (aname), mlast_use (0) {} | |
736 | |
737 const std::string &name (void) const { return mname; } | |
738 | |
739 // manipulate the value_stack, for use during SSA construction. The top of the | |
740 // value stack represents the current value for this variable | |
741 bool has_top (void) const | |
742 { | |
743 return ! value_stack.empty (); | |
744 } | |
745 | |
746 jit_value *top (void) const | |
747 { | |
748 return value_stack.top (); | |
749 } | |
750 | |
751 void push (jit_instruction *v) | |
752 { | |
753 value_stack.push (v); | |
754 mlast_use = v; | |
755 } | |
756 | |
757 void pop (void) | |
758 { | |
759 value_stack.pop (); | |
760 } | |
761 | |
762 jit_instruction *last_use (void) const | |
763 { | |
764 return mlast_use; | |
765 } | |
766 | |
767 void stash_last_use (jit_instruction *instr) | |
768 { | |
769 mlast_use = instr; | |
770 } | |
771 | |
772 // blocks in which we are used | |
773 void use_blocks (jit_block::df_set& result) | |
774 { | |
775 jit_use *use = first_use (); | |
776 while (use) | |
777 { | |
778 result.insert (use->user_parent ()); | |
779 use = use->next (); | |
780 } | |
781 } | |
782 | |
783 virtual std::ostream& print (std::ostream& os, size_t indent = 0) const | |
784 { | |
785 return print_indent (os, indent) << mname; | |
786 } | |
787 | |
788 JIT_VALUE_ACCEPT; | |
789 private: | |
790 std::string mname; | |
791 std::stack<jit_value *> value_stack; | |
792 jit_instruction *mlast_use; | |
793 }; | |
794 | |
795 class | |
796 jit_assign_base : public jit_instruction | |
797 { | |
798 public: | |
799 jit_assign_base (jit_variable *adest) : jit_instruction (), mdest (adest) {} | |
800 | |
801 jit_assign_base (jit_variable *adest, size_t npred) : jit_instruction (npred), | |
802 mdest (adest) {} | |
803 | |
804 jit_assign_base (jit_variable *adest, jit_value *arg0, jit_value *arg1) | |
805 : jit_instruction (arg0, arg1), mdest (adest) {} | |
806 | |
807 jit_variable *dest (void) const { return mdest; } | |
808 | |
809 virtual void push_variable (void) | |
810 { | |
811 mdest->push (this); | |
812 } | |
813 | |
814 virtual void pop_variable (void) | |
815 { | |
816 mdest->pop (); | |
817 } | |
818 | |
819 virtual std::ostream& short_print (std::ostream& os) const | |
820 { | |
821 if (type ()) | |
822 jit_print (os, type ()) << ": "; | |
823 | |
824 dest ()->short_print (os); | |
825 return os << "#" << id (); | |
826 } | |
827 private: | |
828 jit_variable *mdest; | |
829 }; | |
830 | |
831 class | |
832 jit_assign : public jit_assign_base | |
833 { | |
834 public: | |
835 jit_assign (jit_variable *adest, jit_value *asrc) | |
836 : jit_assign_base (adest, adest, asrc), martificial (false) {} | |
837 | |
838 jit_value *overwrite (void) const | |
839 { | |
840 return argument (0); | |
841 } | |
842 | |
843 jit_value *src (void) const | |
844 { | |
845 return argument (1); | |
846 } | |
847 | |
848 // variables don't get modified in an SSA, but COW requires we modify | |
849 // variables. An artificial assign is for when a variable gets modified. We | |
850 // need an assign in the SSA, but the reference counts shouldn't be updated. | |
851 bool artificial (void) const { return martificial; } | |
852 | |
853 void mark_artificial (void) { martificial = true; } | |
854 | |
855 virtual bool infer (void) | |
856 { | |
857 jit_type *stype = src ()->type (); | |
858 if (stype != type()) | |
859 { | |
860 stash_type (stype); | |
861 return true; | |
862 } | |
863 | |
864 return false; | |
865 } | |
866 | |
867 virtual std::ostream& print (std::ostream& os, size_t indent = 0) const | |
868 { | |
869 print_indent (os, indent) << *this << " = " << *src (); | |
870 | |
871 if (artificial ()) | |
872 os << " [artificial]"; | |
873 | |
874 return os; | |
875 } | |
876 | |
877 JIT_VALUE_ACCEPT; | |
878 private: | |
879 bool martificial; | |
880 }; | |
881 | |
882 class | |
883 jit_phi : public jit_assign_base | |
884 { | |
885 public: | |
886 jit_phi (jit_variable *adest, size_t npred) | |
887 : jit_assign_base (adest, npred) | |
888 { | |
889 mincomming.reserve (npred); | |
890 } | |
891 | |
892 // removes arguments form dead incomming jumps | |
893 bool prune (void); | |
894 | |
895 void add_incomming (jit_block *from, jit_value *value) | |
896 { | |
897 push_argument (value); | |
898 mincomming.push_back (jit_phi_incomming (this)); | |
899 mincomming[mincomming.size () - 1].stash_value (from); | |
900 } | |
901 | |
902 jit_block *incomming (size_t i) const | |
903 { | |
904 return mincomming[i].value (); | |
905 } | |
906 | |
907 llvm::BasicBlock *incomming_llvm (size_t i) const | |
908 { | |
909 return incomming (i)->to_llvm (); | |
910 } | |
911 | |
912 virtual void construct_ssa (void) {} | |
913 | |
914 virtual bool infer (void); | |
915 | |
916 virtual std::ostream& print (std::ostream& os, size_t indent = 0) const | |
917 { | |
918 std::stringstream ss; | |
919 print_indent (ss, indent); | |
920 short_print (ss) << " phi "; | |
921 std::string ss_str = ss.str (); | |
922 std::string indent_str (ss_str.size (), ' '); | |
923 os << ss_str; | |
924 | |
925 for (size_t i = 0; i < argument_count (); ++i) | |
926 { | |
927 if (i > 0) | |
928 os << indent_str; | |
929 os << "| "; | |
930 | |
931 os << *incomming (i) << " -> "; | |
932 os << *argument (i); | |
933 | |
934 if (i + 1 < argument_count ()) | |
935 os << std::endl; | |
936 } | |
937 | |
938 return os; | |
939 } | |
940 | |
941 llvm::PHINode *to_llvm (void) const; | |
942 | |
943 JIT_VALUE_ACCEPT; | |
944 private: | |
945 std::vector<jit_phi_incomming> mincomming; | |
946 }; | |
947 | |
948 class | |
949 jit_terminator : public jit_instruction | |
950 { | |
951 public: | |
952 #define JIT_TERMINATOR_CONST(N) \ | |
953 jit_terminator (size_t asuccessor_count, \ | |
954 OCT_MAKE_DECL_LIST (jit_value *, arg, N)) \ | |
955 : jit_instruction (OCT_MAKE_ARG_LIST (arg, N)), \ | |
956 malive (asuccessor_count, false) {} | |
957 | |
958 JIT_TERMINATOR_CONST (1) | |
959 JIT_TERMINATOR_CONST (2) | |
960 JIT_TERMINATOR_CONST (3) | |
961 | |
962 #undef JIT_TERMINATOR_CONST | |
963 | |
964 jit_block *successor (size_t idx = 0) const | |
965 { | |
966 return static_cast<jit_block *> (argument (idx)); | |
967 } | |
968 | |
969 llvm::BasicBlock *successor_llvm (size_t idx = 0) const | |
970 { | |
971 return successor (idx)->to_llvm (); | |
972 } | |
973 | |
974 size_t successor_index (const jit_block *asuccessor) const; | |
975 | |
976 std::ostream& print_successor (std::ostream& os, size_t idx = 0) const | |
977 { | |
978 if (alive (idx)) | |
979 os << "[live] "; | |
980 else | |
981 os << "[dead] "; | |
982 | |
983 return successor (idx)->short_print (os); | |
984 } | |
985 | |
986 // Check if the jump to successor is live | |
987 bool alive (const jit_block *asuccessor) const | |
988 { | |
989 return alive (successor_index (asuccessor)); | |
990 } | |
991 | |
992 bool alive (size_t idx) const { return malive[idx]; } | |
993 | |
994 bool alive (int idx) const { return malive[idx]; } | |
995 | |
996 size_t successor_count (void) const { return malive.size (); } | |
997 | |
998 virtual bool infer (void); | |
999 | |
1000 llvm::TerminatorInst *to_llvm (void) const; | |
1001 protected: | |
1002 virtual bool check_alive (size_t) const { return true; } | |
1003 private: | |
1004 std::vector<bool> malive; | |
1005 }; | |
1006 | |
1007 class | |
1008 jit_branch : public jit_terminator | |
1009 { | |
1010 public: | |
1011 jit_branch (jit_block *succ) : jit_terminator (1, succ) {} | |
1012 | |
1013 virtual size_t successor_count (void) const { return 1; } | |
1014 | |
1015 virtual std::ostream& print (std::ostream& os, size_t indent = 0) const | |
1016 { | |
1017 print_indent (os, indent) << "branch: "; | |
1018 return print_successor (os); | |
1019 } | |
1020 | |
1021 JIT_VALUE_ACCEPT; | |
1022 }; | |
1023 | |
1024 class | |
1025 jit_cond_branch : public jit_terminator | |
1026 { | |
1027 public: | |
1028 jit_cond_branch (jit_value *c, jit_block *ctrue, jit_block *cfalse) | |
1029 : jit_terminator (2, ctrue, cfalse, c) {} | |
1030 | |
1031 jit_value *cond (void) const { return argument (2); } | |
1032 | |
1033 std::ostream& print_cond (std::ostream& os) const | |
1034 { | |
1035 return cond ()->short_print (os); | |
1036 } | |
1037 | |
1038 llvm::Value *cond_llvm (void) const | |
1039 { | |
1040 return cond ()->to_llvm (); | |
1041 } | |
1042 | |
1043 virtual size_t successor_count (void) const { return 2; } | |
1044 | |
1045 virtual std::ostream& print (std::ostream& os, size_t indent = 0) const | |
1046 { | |
1047 print_indent (os, indent) << "cond_branch: "; | |
1048 print_cond (os) << ", "; | |
1049 print_successor (os, 0) << ", "; | |
1050 return print_successor (os, 1); | |
1051 } | |
1052 | |
1053 JIT_VALUE_ACCEPT; | |
1054 }; | |
1055 | |
1056 class | |
1057 jit_call : public jit_instruction | |
1058 { | |
1059 public: | |
1060 #define JIT_CALL_CONST(N) \ | |
1061 jit_call (const jit_operation& aoperation, \ | |
1062 OCT_MAKE_DECL_LIST (jit_value *, arg, N)) \ | |
1063 : jit_instruction (OCT_MAKE_ARG_LIST (arg, N)), moperation (aoperation) {} \ | |
1064 \ | |
1065 jit_call (const jit_operation& (*aoperation) (void), \ | |
1066 OCT_MAKE_DECL_LIST (jit_value *, arg, N)) \ | |
1067 : jit_instruction (OCT_MAKE_ARG_LIST (arg, N)), moperation (aoperation ()) \ | |
1068 {} | |
1069 | |
1070 JIT_CALL_CONST (1) | |
1071 JIT_CALL_CONST (2) | |
1072 JIT_CALL_CONST (3) | |
1073 JIT_CALL_CONST (4) | |
1074 | |
1075 #undef JIT_CALL_CONST | |
1076 | |
15067 | 1077 jit_call (const jit_operation& aoperation, |
1078 const std::vector<jit_value *>& args) | |
1079 : jit_instruction (args), moperation (aoperation) | |
1080 {} | |
15016 | 1081 |
1082 const jit_operation& operation (void) const { return moperation; } | |
1083 | |
1084 bool can_error (void) const | |
1085 { | |
1086 return overload ().can_error (); | |
1087 } | |
1088 | |
1089 const jit_function& overload (void) const | |
1090 { | |
1091 return moperation.overload (argument_types ()); | |
1092 } | |
1093 | |
1094 virtual bool needs_release (void) const | |
1095 { | |
1096 return type () && jit_typeinfo::get_release (type ()).valid (); | |
1097 } | |
1098 | |
1099 virtual std::ostream& print (std::ostream& os, size_t indent = 0) const | |
1100 { | |
1101 print_indent (os, indent); | |
1102 | |
1103 if (use_count ()) | |
1104 short_print (os) << " = "; | |
1105 os << "call " << moperation.name () << " ("; | |
1106 | |
1107 for (size_t i = 0; i < argument_count (); ++i) | |
1108 { | |
1109 print_argument (os, i); | |
1110 if (i + 1 < argument_count ()) | |
1111 os << ", "; | |
1112 } | |
1113 return os << ")"; | |
1114 } | |
1115 | |
1116 virtual bool infer (void); | |
1117 | |
1118 JIT_VALUE_ACCEPT; | |
1119 private: | |
1120 const jit_operation& moperation; | |
1121 }; | |
1122 | |
1123 // FIXME: This is just ugly... | |
1124 // checks error_state, if error_state is false then goto the normal branche, | |
1125 // otherwise goto the error branch | |
1126 class | |
1127 jit_error_check : public jit_terminator | |
1128 { | |
1129 public: | |
1130 jit_error_check (jit_call *acheck_for, jit_block *normal, jit_block *error) | |
1131 : jit_terminator (2, error, normal, acheck_for) {} | |
1132 | |
1133 jit_call *check_for (void) const | |
1134 { | |
1135 return static_cast<jit_call *> (argument (2)); | |
1136 } | |
1137 | |
1138 virtual std::ostream& print (std::ostream& os, size_t indent = 0) const | |
1139 { | |
1140 print_indent (os, indent) << "error_check " << *check_for () << ", "; | |
1141 print_successor (os, 1) << ", "; | |
1142 return print_successor (os, 0); | |
1143 } | |
1144 | |
1145 JIT_VALUE_ACCEPT; | |
1146 protected: | |
1147 virtual bool check_alive (size_t idx) const | |
1148 { | |
1149 return idx == 1 ? true : check_for ()->can_error (); | |
1150 } | |
1151 }; | |
1152 | |
15056
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1153 // for now only handles the 1D case |
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1154 class |
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1155 jit_magic_end : public jit_instruction |
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1156 { |
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1157 public: |
15067 | 1158 class |
1159 context | |
1160 { | |
1161 public: | |
1162 context (void) : value (0), index (0), count (0) | |
1163 {} | |
1164 | |
15102
d29f2583cf7b
Support end in multi indexing in JIT
Max Brister <max@2bass.com>
parents:
15096
diff
changeset
|
1165 context (jit_convert& convert, jit_value *avalue, size_t aindex, |
d29f2583cf7b
Support end in multi indexing in JIT
Max Brister <max@2bass.com>
parents:
15096
diff
changeset
|
1166 size_t acount); |
15067 | 1167 |
1168 jit_value *value; | |
15102
d29f2583cf7b
Support end in multi indexing in JIT
Max Brister <max@2bass.com>
parents:
15096
diff
changeset
|
1169 jit_const_index *index; |
d29f2583cf7b
Support end in multi indexing in JIT
Max Brister <max@2bass.com>
parents:
15096
diff
changeset
|
1170 jit_const_index *count; |
15067 | 1171 }; |
1172 | |
1173 jit_magic_end (const std::vector<context>& full_context); | |
15056
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1174 |
15102
d29f2583cf7b
Support end in multi indexing in JIT
Max Brister <max@2bass.com>
parents:
15096
diff
changeset
|
1175 virtual bool infer (void); |
d29f2583cf7b
Support end in multi indexing in JIT
Max Brister <max@2bass.com>
parents:
15096
diff
changeset
|
1176 |
15056
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1177 const jit_function& overload () const; |
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1178 |
15102
d29f2583cf7b
Support end in multi indexing in JIT
Max Brister <max@2bass.com>
parents:
15096
diff
changeset
|
1179 virtual std::ostream& print (std::ostream& os, size_t indent = 0) const; |
15056
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1180 |
15102
d29f2583cf7b
Support end in multi indexing in JIT
Max Brister <max@2bass.com>
parents:
15096
diff
changeset
|
1181 context resolve_context (void) const; |
15056
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1182 |
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1183 virtual std::ostream& short_print (std::ostream& os) const |
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1184 { |
15102
d29f2583cf7b
Support end in multi indexing in JIT
Max Brister <max@2bass.com>
parents:
15096
diff
changeset
|
1185 return os << "magic_end" << "#" << id (); |
15056
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1186 } |
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1187 |
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1188 JIT_VALUE_ACCEPT; |
15102
d29f2583cf7b
Support end in multi indexing in JIT
Max Brister <max@2bass.com>
parents:
15096
diff
changeset
|
1189 private: |
d29f2583cf7b
Support end in multi indexing in JIT
Max Brister <max@2bass.com>
parents:
15096
diff
changeset
|
1190 std::vector<context> contexts; |
15056
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1191 }; |
bc32288f4a42
Support the end keyword for one dimentional indexing in JIT.
Max Brister <max@2bass.com>
parents:
15016
diff
changeset
|
1192 |
15016 | 1193 class |
1194 jit_extract_argument : public jit_assign_base | |
1195 { | |
1196 public: | |
1197 jit_extract_argument (jit_type *atype, jit_variable *adest) | |
1198 : jit_assign_base (adest) | |
1199 { | |
1200 stash_type (atype); | |
1201 } | |
1202 | |
1203 const std::string& name (void) const | |
1204 { | |
1205 return dest ()->name (); | |
1206 } | |
1207 | |
1208 const jit_function& overload (void) const | |
1209 { | |
1210 return jit_typeinfo::cast (type (), jit_typeinfo::get_any ()); | |
1211 } | |
1212 | |
1213 virtual std::ostream& print (std::ostream& os, size_t indent = 0) const | |
1214 { | |
1215 print_indent (os, indent); | |
1216 | |
1217 return short_print (os) << " = extract " << name (); | |
1218 } | |
1219 | |
1220 JIT_VALUE_ACCEPT; | |
1221 }; | |
1222 | |
1223 class | |
1224 jit_store_argument : public jit_instruction | |
1225 { | |
1226 public: | |
1227 jit_store_argument (jit_variable *var) | |
1228 : jit_instruction (var), dest (var) | |
1229 {} | |
1230 | |
1231 const std::string& name (void) const | |
1232 { | |
1233 return dest->name (); | |
1234 } | |
1235 | |
1236 const jit_function& overload (void) const | |
1237 { | |
1238 return jit_typeinfo::cast (jit_typeinfo::get_any (), result_type ()); | |
1239 } | |
1240 | |
1241 jit_value *result (void) const | |
1242 { | |
1243 return argument (0); | |
1244 } | |
1245 | |
1246 jit_type *result_type (void) const | |
1247 { | |
1248 return result ()->type (); | |
1249 } | |
1250 | |
1251 llvm::Value *result_llvm (void) const | |
1252 { | |
1253 return result ()->to_llvm (); | |
1254 } | |
1255 | |
1256 virtual std::ostream& print (std::ostream& os, size_t indent = 0) const | |
1257 { | |
1258 jit_value *res = result (); | |
1259 print_indent (os, indent) << "store "; | |
1260 dest->short_print (os); | |
1261 | |
1262 if (! isa<jit_variable> (res)) | |
1263 { | |
1264 os << " = "; | |
1265 res->short_print (os); | |
1266 } | |
1267 | |
1268 return os; | |
1269 } | |
1270 | |
1271 JIT_VALUE_ACCEPT; | |
1272 private: | |
1273 jit_variable *dest; | |
1274 }; | |
1275 | |
1276 class | |
1277 jit_ir_walker | |
1278 { | |
1279 public: | |
1280 virtual ~jit_ir_walker () {} | |
1281 | |
1282 #define JIT_METH(clname) \ | |
1283 virtual void visit (jit_ ## clname&) = 0; | |
1284 | |
1285 JIT_VISIT_IR_CLASSES; | |
1286 | |
1287 #undef JIT_METH | |
1288 }; | |
1289 | |
1290 template <typename T, jit_type *(*EXTRACT_T)(void), typename PASS_T, bool QUOTE> | |
1291 void | |
1292 jit_const<T, EXTRACT_T, PASS_T, QUOTE>::accept (jit_ir_walker& walker) | |
1293 { | |
1294 walker.visit (*this); | |
1295 } | |
1296 | |
1297 #undef JIT_VALUE_ACCEPT | |
1298 | |
1299 #endif | |
1300 #endif |