169d411351856a509659907ba83499f7b0b0a762
[nit.git] / src / compiling / compiling_icode.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2009 Jean Privat <jean@pryen.org>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Generate C code from intermediate code representation
18 package compiling_icode
19
20 import icode
21 private import analysis
22 import primitive_info
23 import compiling_base
24
25 # Compiler context from ICode to C
26 class I2CCompilerVisitor
27 # Associate things
28 var _ids: HashMap[Object, String] = new HashMap[Object, String]
29 # Associate other things
30 var _ids2: HashMap[Object, String] = new HashMap[Object, String]
31
32 # Return the string associated with a register
33 fun register(e: IRegister): String
34 do
35 if e.stype isa MMTypeNone then return "NIT_NULL"
36 var ids = _ids
37 if closure and not e.is_local then ids = _ids2
38 if ids.has_key(e) then
39 return ids[e]
40 else
41 var i = e.slot_index
42 if i == null then
43 # The register is dead
44 var s = "NIT_NULL"
45 ids[e] = s
46 return s
47 else
48 var s: String
49 var strs: HashMap[Int, String]
50 if e.in_tag_slots then
51 strs = once new HashMap[Int, String]
52 if not strs.has_key(i) then strs[i] = "REGB{i}"
53 else if closure and not e.is_local then
54 strs = once new HashMap[Int, String]
55 if not strs.has_key(i) then strs[i] = "closctx->REG[{i}]"
56 else
57 strs = once new HashMap[Int, String]
58 if not strs.has_key(i) then strs[i] = "fra.me.REG[{i}]"
59 end
60 s = strs[i]
61 ids[e] = s
62 return s
63 end
64 end
65 end
66
67 # Return the strings associated with registers
68 fun registers(a: Collection[IRegister]): Array[String]
69 do
70 var r = new Array[String].with_capacity(a.length)
71 for e in a do
72 r.add(register(e))
73 end
74 return r
75 end
76
77 var _last_number: Int = 0
78 # Give a new unique number (unique for the visitor)
79 fun new_number: Int
80 do
81 _last_number += 1
82 return _last_number
83 end
84
85 # Return the string associated with a escape label
86 fun lab(e: ISeq): String
87 do
88 if _ids.has_key(e) then
89 return _ids[e]
90 else
91 var s = "label{new_number}"
92 _ids[e] = s
93 return s
94 end
95 end
96
97 # The rank (number) of each closure
98 readable var _closures: HashMap[IClosureDecl, String] = new HashMap[IClosureDecl, String]
99
100 # The functionnal type of each closure
101 readable var _clostypes: HashMap[IClosureDecl, String] = new HashMap[IClosureDecl, String]
102
103 # label locally accessibles
104 readable writable var _local_labels: HashSet[ISeq] = new HashSet[ISeq]
105
106 # Not local escaped labels
107 # The integer value is an index identifying the label
108 readable writable var _escaped_labels: HashMap[ISeq, Int] = new HashMap[ISeq, Int]
109
110 # Register a escape to a non local label and return an index identifying the label
111 fun register_escape_label(e: ISeq): Int
112 do
113 if _escaped_labels.has_key(e) then
114 return _escaped_labels[e]
115 else
116 var res = _escaped_labels.length + 1
117 _escaped_labels[e] = res
118 return res
119 end
120 end
121
122 # Add a C label mark (if needed)
123 fun add_label(e: ISeq)
124 do
125 if _ids.has_key(e) then
126 add_instr("{_ids[e]}: while(0);")
127 end
128 end
129
130 # Add a goto to a label (even outside a closure)
131 fun add_goto(seq: ISeq)
132 do
133 if local_labels.has(seq) then
134 add_instr("goto {lab(seq)};")
135 else
136 assert closure
137 var ind = register_escape_label(seq)
138 add_instr("closctx->has_broke = {ind};")
139 add_instr("goto {lab(return_label.as(not null))};")
140 end
141 end
142
143 # Association between IEscapeMarks and visited ISeq
144 readable var _marks_to_seq: Map[IEscapeMark, ISeq] = new HashMap[IEscapeMark, ISeq]
145
146 # Are we in a closure ?
147 readable writable var _closure: Bool = false
148
149 # The current compiler visitor
150 readable var _visitor: CompilerVisitor
151
152 # The current compiled iroutine
153 readable var _iroutine: IRoutine
154
155 # The return label of the current compiling C function
156 readable writable var _return_label: nullable ISeq = null
157
158 fun add_decl(s: String)
159 do
160 visitor.add_decl(s)
161 end
162
163 # Prepare a new instuction (indent, comment)
164 # Caller must ensure to add a new line to finish its instr
165 fun new_instr: Writer
166 do
167 var w = visitor.writer
168 var l = _next_location
169 if l != null then
170 visitor.add_indent(w)
171 w.add("/* ")
172 w.add(l.file.filename)
173 w.add(":")
174 w.add(l.line_start.to_s)
175 w.add(" */\n")
176 _next_location = null
177 end
178 visitor.add_indent(w)
179 return w
180 end
181
182 fun add_instr(s: String)
183 do
184 new_instr.add(s).add("\n")
185 end
186
187 fun indent
188 do
189 visitor.indent
190 end
191
192 fun unindent
193 do
194 visitor.unindent
195 end
196
197 fun add_assignment(to, from: String)
198 do
199 visitor.add_assignment(to, from)
200 end
201
202 var _last_location: nullable Location = null
203 var _next_location: nullable Location = null
204
205 # Add location information in a comment
206 # Do nothing if the last location added is the same
207 fun add_location(l: nullable Location)
208 do
209 var last = _last_location
210 if last == l or l == null then return
211 _last_location = l
212 if last != null and last.file == l.file and last.line_start == l.line_start then
213 return
214 else
215 _next_location = l
216 end
217 end
218
219 # The C fonction name of the iroutine
220 readable var _basecname: String
221
222 init(v: CompilerVisitor, ir: IRoutine, cname: String)
223 do
224 _visitor = v
225 _iroutine = ir
226 _basecname = cname
227 end
228 end
229
230 redef class IRoutine
231 # Declare and start a C function that match the routine
232 # Return what must be given to compile_inside_to_c or to compile_to_c
233 # After the method, an openinig { and and indent is added.
234 # So, do not forget to add a sub_context, to unintent and to add a closing }
235 fun compile_signature_to_c(v: CompilerVisitor, cname: String, human_name: nullable String, before_params, after_params: nullable String): Array[String]
236 do
237 var cargs = new Array[String]
238 var cparams = new Array[String]
239 if before_params != null then cparams.add(before_params)
240 for i in [0..params.length[ do
241 cargs.add("p{i}")
242 cparams.add("val_t p{i}")
243 end
244 if closure_decls != null then
245 cparams.add("struct stack_frame_t *closctx_param")
246 for i in [0..closure_decls.length[ do
247 var closcn = "CLOS_{cname}_{i}"
248 var cs = closure_decls[i].closure.signature
249 var subparams = new Array[String] # Parameters of the closure
250 subparams.add("struct stack_frame_t *")
251 for j in [0..cs.arity[ do
252 subparams.add("val_t")
253 end
254 var rr = "void"
255 if cs.return_type != null then rr = "val_t"
256 v.add_decl("typedef {rr} (*{closcn})({subparams.join(", ")});")
257 cargs.add("clos_fun{i}")
258 cparams.add("fun_t clos_fun{i}")
259 end
260 end
261 if after_params != null then cparams.add(after_params)
262 var r = "void"
263 if result != null then r = "val_t"
264 var p: String
265 if cparams.is_empty then
266 p = "void"
267 else
268 p = cparams.join(", ")
269 end
270 if human_name != null then v.add_decl("static const char * const LOCATE_{cname} = \"{human_name}\";")
271 v.add_decl("{r} {cname}({p});")
272 v.add_decl("typedef {r} (*{cname}_t)({p});")
273 v.add_instr("{r} {cname}({p})\{")
274 v.indent
275 return cargs
276 end
277
278 # Compile the body of the routine, return the result value is any
279 fun compile_inside_to_c(v: I2CCompilerVisitor, args: Array[String]): nullable String
280 do
281 # Create and push the stack frame
282 var ll = 0
283 if location != null then
284 ll = location.line_start
285 end
286 # Encapsulate the frame ('me') in a larger structure ('fra') that has enough space to store the local variables (REG)
287 if std_slots_nb > 1 then
288 v.add_decl("struct \{struct stack_frame_t me; val_t MORE_REG[{std_slots_nb-1}];\} fra;")
289 else
290 v.add_decl("struct \{struct stack_frame_t me;\} fra;")
291 end
292 v.add_instr("fra.me.prev = stack_frame_head; stack_frame_head = &fra.me;")
293 v.add_instr("fra.me.file = LOCATE_{v.visitor.mmmodule.cname};")
294 v.add_instr("fra.me.line = {ll};")
295 v.add_instr("fra.me.meth = LOCATE_{v.basecname};")
296 v.add_instr("fra.me.has_broke = 0;")
297 v.add_instr("fra.me.REG_size = {std_slots_nb};")
298
299 # Declare/initialize local variables
300 for i in [0..std_slots_nb[ do
301 v.add_instr("fra.me.REG[{i}] = NIT_NULL;")
302 end
303 for i in [0..tag_slots_nb[ do
304 v.add_decl("val_t REGB{i};")
305 end
306 var iclosdecls = closure_decls
307 if iclosdecls != null then
308 v.add_decl("fun_t CREG[{iclosdecls.length}];")
309 v.add_instr("fra.me.closure_ctx = closctx_param;")
310 v.add_instr("fra.me.closure_funs = CREG;")
311 end
312 var k = 0
313 for r in params do
314 if r.slot_index != null then v.add_assignment(v.register(r), args[k])
315 k += 1
316 end
317 if iclosdecls != null then
318 for i in [0..iclosdecls.length[ do
319 var iclosdecl = iclosdecls[i]
320 v.add_instr("CREG[{i}] = {args[params.length+i]};")
321 v.closures[iclosdecl] = i.to_s
322 var cs = iclosdecl.closure.signature # Closure signature
323 var subparams = new Array[String] # Parameters of the closure
324 subparams.add("struct stack_frame_t *")
325 for j in [0..cs.arity[ do
326 var p = "val_t"
327 subparams.add(p)
328 end
329 var r = "void"
330 if cs.return_type != null then r = "val_t"
331 v.clostypes[iclosdecl] = "{r} (*)({subparams.join(", ")})"
332 end
333 end
334 v.add_decl("val_t tmp;")
335
336 # Prepare return
337 var old_rl = v.return_label
338 v.return_label = body
339
340 # Compile body
341 body.compile_to_c(v)
342
343 v.add_instr("stack_frame_head = fra.me.prev;")
344 v.return_label = old_rl
345 var r = result
346 if r != null then
347 return v.register(r)
348 else
349 return null
350 end
351 end
352
353 # Full compilation of the routine
354 # cv must be in the correct function
355 fun compile_to_c(cv: CompilerVisitor, cname: String, args: Array[String]): nullable String
356 do
357 var v = new I2CCompilerVisitor(cv, self, cname)
358 return compile_inside_to_c(v, args)
359 end
360 end
361
362 redef class ICode
363 # Full compilation of the icode
364 fun compile_to_c(v: I2CCompilerVisitor) is abstract
365
366 # Is a result really needed
367 private fun need_result: Bool
368 do
369 var r = result
370 return r != null and r.slot_index != null
371 end
372
373 # Store s in the result value of self
374 private fun store_result(v: I2CCompilerVisitor, w: nullable Writer)
375 do
376 var r = result
377 if r != null and r.slot_index != null then
378 assert w != null
379 var w2 = v.new_instr
380 w2.add(v.register(r))
381 w2.add(" = ")
382 w2.append(w)
383 w2.add(";\n")
384 else if w != null and not is_pure then
385 # ICode with side effects must be evaluated
386 # even if the result is not wanted
387 var w2 = v.new_instr
388 w2.append(w)
389 w2.add(";\n")
390 end
391 end
392
393 # Prepare a writer if the expression icode need to be compiled
394 # * Result assigment is automatic if needed
395 private fun new_result(v: I2CCompilerVisitor): Writer
396 do
397 assert need_result or not is_pure
398 var w2 = v.new_instr
399 var r = result
400 if r != null and r.slot_index != null then
401 w2.add(v.register(r))
402 w2.add(" = ")
403 end
404 var w = w2.sub
405 w2.add(";\n")
406 return w
407 end
408 end
409
410 redef class ISeq
411 redef fun compile_to_c(v)
412 do
413 v.add_location(location)
414 v.local_labels.add(self)
415 var mark = iescape_mark
416 if mark != null then v.marks_to_seq[mark] = self
417 for ic in icodes do
418 ic.compile_to_c(v)
419 end
420 v.add_label(self)
421 end
422 end
423
424 redef class IIf
425 redef fun compile_to_c(v)
426 do
427 v.add_location(location)
428 var w = v.new_instr
429 w.add("if (UNTAG_Bool(")
430 w.add(v.register(expr))
431 w.add(")) \{\n")
432 if not then_seq.icodes.is_empty then
433 v.indent
434 then_seq.compile_to_c(v)
435 v.unindent
436 end
437 if not else_seq.icodes.is_empty then
438 v.add_instr("\} else \{")
439 v.indent
440 else_seq.compile_to_c(v)
441 v.unindent
442 end
443 v.add_instr("\}")
444 end
445 end
446
447 redef class ILoop
448 redef fun compile_to_c(v)
449 do
450 v.add_location(location)
451 v.local_labels.add(self)
452 var mark = iescape_mark
453 if mark != null then v.marks_to_seq[mark] = self
454 v.add_instr("while(1) \{")
455 v.indent
456 for ic in icodes do
457 ic.compile_to_c(v)
458 end
459 v.unindent
460 v.add_instr("\}")
461 v.add_label(self)
462 end
463 end
464
465 redef class IEscape
466 redef fun compile_to_c(v)
467 do
468 v.add_location(location)
469 v.add_goto(v.marks_to_seq[iescape_mark])
470 end
471 end
472
473 redef class IAbsCall
474 redef fun compile_to_c(v)
475 do
476 v.add_location(location)
477 var args = v.registers(exprs)
478
479 # Compile closure definitions
480 var old_el = v.escaped_labels
481 var closdefs = closure_defs
482 var closctx: nullable String = null # The closure context of closdefs
483 if closdefs != null then
484 # Get the closure context
485 if v.closure then
486 closctx = "closctx"
487 else
488 closctx = "(&(fra.me))"
489 end
490
491 # First aditionnal arguments is the closure context
492 args.add(closctx)
493
494 # We are in a new escape boundary
495 v.escaped_labels = new HashMap[ISeq, Int]
496
497 # Compile each closures and add each sub-function as an other additionnal parameter
498 for cd in closdefs do
499 if cd != null then
500 var cn = cd.compile_closure(v)
501 args.add(cn)
502 else
503 args.add("NULL")
504 end
505 end
506 end
507
508 # Compile the real call
509 var call = compile_call_to_c(v, args)
510 var res: nullable Writer = call
511
512 # Intercept escapes
513 if closctx != null then
514 var els = v.escaped_labels
515 v.escaped_labels = old_el
516 # Is there possible escapes?
517 if not els.is_empty then
518 # Call in a tmp variable to avoid 'break' overwrite
519 var w = v.new_instr
520 if need_result then
521 w.add("tmp")
522 w.add(" = ")
523 w.append(call)
524 w.add(";\n")
525 res = new Writer
526 res.add("tmp")
527 else
528 res = null
529 w.append(call)
530 w.add(";\n")
531 end
532 # What are the expected escape indexes
533 v.new_instr.add("switch (").add(closctx).add("->has_broke) \{\n")
534 v.indent
535 # No escape occured, continue as usual
536 v.add_instr("case 0: break;")
537 var lls = v.local_labels
538 var iels = els.iterator
539 var forward_escape = false
540 while iels.is_ok do
541 var seq = iels.key
542 if lls.has(seq) then
543 # Local escape occured
544 # Clear the has_broke information and go to the target
545 v.new_instr.add("case ").add(iels.item.to_s).add(": ").add(closctx).add("->has_broke = 0; goto ").add(v.lab(seq)).add(";\n")
546 else
547 # Forward escape occured: register the escape label
548 assert v.closure
549 v.register_escape_label(seq)
550 forward_escape = true
551 end
552 iels.next
553 end
554 # If forward escape occured, just pass to the next one
555 if forward_escape then
556 # Do not need to copy 'has_broke' value since it is shared by the next one.
557 # So just exit the C function.
558 v.new_instr.add("default: goto ").add(v.lab(v.return_label.as(not null))).add(";\n")
559 end
560 v.unindent
561 v.add_instr("\}")
562 end
563 end
564
565 if res != null then
566 var w = new_result(v)
567 w.append(res)
568 end
569 end
570
571 # The single invocation witout fancy stuffs
572 private fun compile_call_to_c(v: I2CCompilerVisitor, args: Array[String]): Writer is abstract
573 end
574
575 redef class ICall
576 redef fun compile_call_to_c(v, args)
577 do
578 var w = new Writer
579
580 # do not compile explicit calls from native methods
581 # theses are really manually called in the native implementation
582 if is_explicit_from_extern then return w
583
584 var prop = property
585 if prop.global.is_init then args.add("init_table")
586 w.add(prop.global.meth_call)
587 w.add("(")
588 w.add(args.first)
589 w.add(")(")
590 w.add_all(args, ", ")
591 w.add(")")
592 return w
593 end
594 end
595
596 redef class ISuper
597 redef fun compile_call_to_c(v, args)
598 do
599 # do not compile explicit calls from native methods
600 # theses are really manually called in the native implementation
601 if is_explicit_from_extern then return new Writer
602
603 var prop = property
604 if prop.global.is_init then args.add("init_table")
605 var w = new Writer
606 w.add(prop.super_meth_call)
607 w.add("(")
608 w.add(args.first)
609 w.add(")(")
610 w.add_all(args, ", ")
611 w.add(")")
612 return w
613 end
614 end
615
616 redef class INew
617 redef fun compile_call_to_c(v, args)
618 do
619 var w = new Writer
620
621 # do not compile explicit calls from native methods
622 # theses are really manually called in the native implementation
623 if is_explicit_from_extern then return w
624
625 w.add("NEW_")
626 w.add(stype.local_class.to_s)
627 w.add("_")
628 w.add(property.global.intro.cname)
629 w.add("(")
630 w.add_all(args, ", ")
631 w.add(")")
632 return w
633 end
634 end
635
636 redef class IAllocateInstance
637 redef fun compile_to_c(v)
638 do
639 v.add_location(location)
640 var w = new_result(v)
641 w.add("NEW_")
642 w.add(stype.local_class.cname)
643 w.add("()")
644 end
645 end
646
647 redef class ICheckInstance
648 redef fun compile_to_c(v)
649 do
650 v.add_location(location)
651 var w = new_result(v)
652 w.add("CHECKNEW_")
653 w.add(stype.local_class.cname)
654 w.add("(")
655 w.add(v.register(expr))
656 w.add(")")
657 end
658 end
659
660 redef class IInitAttributes
661 redef fun compile_to_c(v)
662 do
663 v.add_location(location)
664 var w = v.new_instr
665 w.add("INIT_ATTRIBUTES__")
666 w.add(stype.local_class.cname)
667 w.add("(")
668 w.add(v.register(expr))
669 w.add(");\n")
670 end
671 end
672
673 redef class IStaticCall
674 redef fun compile_call_to_c(v, args)
675 do
676 var prop = property
677 if prop.global.is_init then args.add("init_table")
678 var w = new Writer
679 w.add(property.cname)
680 w.add("(")
681 w.add_all(args, ", ")
682 w.add(")")
683 return w
684 end
685 end
686
687 redef class INative
688 redef fun compile_to_c(v)
689 do
690 v.add_location(location)
691 if method.is_intern then
692 compile_intern_method_to_c(v)
693 else if not method.global.is_init then
694 compile_extern_method_to_c(v)
695 end
696 end
697
698 fun compile_extern_method_to_c(v: I2CCompilerVisitor)
699 do
700 var ename = "{method.friendly_extern_name(method.local_class)}___out"
701
702 var sig = method.signature
703 assert exprs.length == sig.arity + 1
704
705 var regs = v.registers(exprs)
706
707 var args = new Array[String]
708 args.add(regs[0])
709 for i in [0..sig.arity[ do
710 args.add(regs[i+1])
711 end
712 var s = "{ename}({args.join(", ")})"
713
714 if need_result then s = s # sig.return_type.boxtype(s)
715 var w = new_result(v)
716 w.add(s)
717 end
718
719 fun compile_intern_method_to_c(v: I2CCompilerVisitor)
720 do
721 var sig = method.signature
722 assert exprs.length == sig.arity + 1
723 var c = method.local_class.name
724 var n = method.name
725 var regs = v.registers(exprs)
726 var s: nullable String = null
727 if c == once "Int".to_symbol then
728 if n == once "object_id".to_symbol then
729 s = regs[0]
730 else if n == once "unary -".to_symbol then
731 s = "TAG_Int(-UNTAG_Int({regs[0]}))"
732 else if n == once "output".to_symbol then
733 s = "printf(\"%ld\\n\", UNTAG_Int({regs[0]}));"
734 else if n == once "ascii".to_symbol then
735 s = "TAG_Char(UNTAG_Int({regs[0]}))"
736 else if n == once "succ".to_symbol then
737 s = "TAG_Int(UNTAG_Int({regs[0]})+1)"
738 else if n == once "prec".to_symbol then
739 s = "TAG_Int(UNTAG_Int({regs[0]})-1)"
740 else if n == once "to_f".to_symbol then
741 s = "BOX_Float((float)UNTAG_Int({regs[0]}))"
742 else if n == once "+".to_symbol then
743 s = "TAG_Int(UNTAG_Int({regs[0]})+UNTAG_Int({regs[1]}))"
744 else if n == once "-".to_symbol then
745 s = "TAG_Int(UNTAG_Int({regs[0]})-UNTAG_Int({regs[1]}))"
746 else if n == once "*".to_symbol then
747 s = "TAG_Int(UNTAG_Int({regs[0]})*UNTAG_Int({regs[1]}))"
748 else if n == once "/".to_symbol then
749 s = "TAG_Int(UNTAG_Int({regs[0]})/UNTAG_Int({regs[1]}))"
750 else if n == once "%".to_symbol then
751 s = "TAG_Int(UNTAG_Int({regs[0]})%UNTAG_Int({regs[1]}))"
752 else if n == once "<".to_symbol then
753 s = "TAG_Bool(UNTAG_Int({regs[0]})<UNTAG_Int({regs[1]}))"
754 else if n == once ">".to_symbol then
755 s = "TAG_Bool(UNTAG_Int({regs[0]})>UNTAG_Int({regs[1]}))"
756 else if n == once "<=".to_symbol then
757 s = "TAG_Bool(UNTAG_Int({regs[0]})<=UNTAG_Int({regs[1]}))"
758 else if n == once ">=".to_symbol then
759 s = "TAG_Bool(UNTAG_Int({regs[0]})>=UNTAG_Int({regs[1]}))"
760 else if n == once "lshift".to_symbol then
761 s = "TAG_Int(UNTAG_Int({regs[0]})<<UNTAG_Int({regs[1]}))"
762 else if n == once "rshift".to_symbol then
763 s = "TAG_Int(UNTAG_Int({regs[0]})>>UNTAG_Int({regs[1]}))"
764 else if n == once "==".to_symbol then
765 s = "TAG_Bool(({regs[0]})==({regs[1]}))"
766 else if n == once "!=".to_symbol then
767 s = "TAG_Bool(({regs[0]})!=({regs[1]}))"
768 end
769 else if c == once "Float".to_symbol then
770 if n == once "object_id".to_symbol then
771 s = "TAG_Int((bigint)UNBOX_Float({regs[0]}))"
772 else if n == once "unary -".to_symbol then
773 s = "BOX_Float(-UNBOX_Float({regs[0]}))"
774 else if n == once "output".to_symbol then
775 s = "printf(\"%f\\n\", UNBOX_Float({regs[0]}));"
776 else if n == once "to_i".to_symbol then
777 s = "TAG_Int((bigint)UNBOX_Float({regs[0]}))"
778 else if n == once "+".to_symbol then
779 s = "BOX_Float(UNBOX_Float({regs[0]})+UNBOX_Float({regs[1]}))"
780 else if n == once "-".to_symbol then
781 s = "BOX_Float(UNBOX_Float({regs[0]})-UNBOX_Float({regs[1]}))"
782 else if n == once "*".to_symbol then
783 s = "BOX_Float(UNBOX_Float({regs[0]})*UNBOX_Float({regs[1]}))"
784 else if n == once "/".to_symbol then
785 s = "BOX_Float(UNBOX_Float({regs[0]})/UNBOX_Float({regs[1]}))"
786 else if n == once "<".to_symbol then
787 s = "TAG_Bool(UNBOX_Float({regs[0]})<UNBOX_Float({regs[1]}))"
788 else if n == once ">".to_symbol then
789 s = "TAG_Bool(UNBOX_Float({regs[0]})>UNBOX_Float({regs[1]}))"
790 else if n == once "<=".to_symbol then
791 s = "TAG_Bool(UNBOX_Float({regs[0]})<=UNBOX_Float({regs[1]}))"
792 else if n == once ">=".to_symbol then
793 s = "TAG_Bool(UNBOX_Float({regs[0]})>=UNBOX_Float({regs[1]}))"
794 end
795 else if c == once "Char".to_symbol then
796 if n == once "object_id".to_symbol then
797 s = "TAG_Int(UNTAG_Char({regs[0]}))"
798 else if n == once "unary -".to_symbol then
799 s = "TAG_Char(-UNTAG_Char({regs[0]}))"
800 else if n == once "output".to_symbol then
801 s = "printf(\"%c\", (unsigned char)UNTAG_Char({regs[0]}));"
802 else if n == once "ascii".to_symbol then
803 s = "TAG_Int((unsigned char)UNTAG_Char({regs[0]}))"
804 else if n == once "succ".to_symbol then
805 s = "TAG_Char(UNTAG_Char({regs[0]})+1)"
806 else if n == once "prec".to_symbol then
807 s = "TAG_Char(UNTAG_Char({regs[0]})-1)"
808 else if n == once "to_i".to_symbol then
809 s = "TAG_Int(UNTAG_Char({regs[0]})-'0')"
810 else if n == once "+".to_symbol then
811 s = "TAG_Char(UNTAG_Char({regs[0]})+UNTAG_Char({regs[1]}))"
812 else if n == once "-".to_symbol then
813 s = "TAG_Char(UNTAG_Char({regs[0]})-UNTAG_Char({regs[1]}))"
814 else if n == once "*".to_symbol then
815 s = "TAG_Char(UNTAG_Char({regs[0]})*UNTAG_Char({regs[1]}))"
816 else if n == once "/".to_symbol then
817 s = "TAG_Char(UNTAG_Char({regs[0]})/UNTAG_Char({regs[1]}))"
818 else if n == once "%".to_symbol then
819 s = "TAG_Char(UNTAG_Char({regs[0]})%UNTAG_Char({regs[1]}))"
820 else if n == once "<".to_symbol then
821 s = "TAG_Bool(UNTAG_Char({regs[0]})<UNTAG_Char({regs[1]}))"
822 else if n == once ">".to_symbol then
823 s = "TAG_Bool(UNTAG_Char({regs[0]})>UNTAG_Char({regs[1]}))"
824 else if n == once "<=".to_symbol then
825 s = "TAG_Bool(UNTAG_Char({regs[0]})<=UNTAG_Char({regs[1]}))"
826 else if n == once ">=".to_symbol then
827 s = "TAG_Bool(UNTAG_Char({regs[0]})>=UNTAG_Char({regs[1]}))"
828 else if n == once "==".to_symbol then
829 s = "TAG_Bool(({regs[0]})==({regs[1]}))"
830 else if n == once "!=".to_symbol then
831 s = "TAG_Bool(({regs[0]})!=({regs[1]}))"
832 end
833 else if c == once "Bool".to_symbol then
834 if n == once "object_id".to_symbol then
835 s = "TAG_Int(UNTAG_Bool({regs[0]}))"
836 else if n == once "unary -".to_symbol then
837 s = "TAG_Bool(-UNTAG_Bool({regs[0]}))"
838 else if n == once "output".to_symbol then
839 s = "(void)printf(UNTAG_Bool({regs[0]})?\"true\\n\":\"false\\n\");"
840 else if n == once "ascii".to_symbol then
841 s = "TAG_Bool(UNTAG_Bool({regs[0]}))"
842 else if n == once "to_i".to_symbol then
843 s = "TAG_Int(UNTAG_Bool({regs[0]}))"
844 else if n == once "==".to_symbol then
845 s = "TAG_Bool(({regs[0]})==({regs[1]}))"
846 else if n == once "!=".to_symbol then
847 s = "TAG_Bool(({regs[0]})!=({regs[1]}))"
848 end
849 else if c == once "NativeArray".to_symbol then
850 if n == once "object_id".to_symbol then
851 s = "TAG_Int(((Nit_NativeArray){regs[0]})->object_id)"
852 else if n == once "[]".to_symbol then
853 s = "((Nit_NativeArray){regs[0]})->val[UNTAG_Int({regs[1]})]"
854 else if n == once "[]=".to_symbol then
855 s = "((Nit_NativeArray){regs[0]})->val[UNTAG_Int({regs[1]})]={regs[2]}"
856 else if n == once "copy_to".to_symbol then
857 s = "(void)memcpy(((Nit_NativeArray ){regs[1]})->val, ((Nit_NativeArray){regs[0]})->val, UNTAG_Int({regs[2]})*sizeof(val_t))"
858 end
859 else if c == once "NativeString".to_symbol then
860 if n == once "object_id".to_symbol then
861 s = "TAG_Int(UNBOX_NativeString({regs[0]}))"
862 else if n == once "atoi".to_symbol then
863 s = "TAG_Int(atoi(UNBOX_NativeString({regs[0]})))"
864 else if n == once "[]".to_symbol then
865 s = "TAG_Char(UNBOX_NativeString({regs[0]})[UNTAG_Int({regs[1]})])"
866 else if n == once "[]=".to_symbol then
867 s = "UNBOX_NativeString({regs[0]})[UNTAG_Int({regs[1]})]=UNTAG_Char({regs[2]});"
868 else if n == once "copy_to".to_symbol then
869 s = "(void)memcpy(UNBOX_NativeString({regs[1]})+UNTAG_Int({regs[4]}), UNBOX_NativeString({regs[0]})+UNTAG_Int({regs[3]}), UNTAG_Int({regs[2]}));"
870 end
871 else if c == once "Sys".to_symbol then
872 if n == once "force_garbage_collection".to_symbol then
873 s = "Nit_gc_force_garbage_collection()"
874 end
875 else if n == once "object_id".to_symbol then
876 s = "TAG_Int((bigint)((obj_t){regs[0]})[1].object_id)"
877 else if n == once "sys".to_symbol then
878 s = "(G_sys)"
879 else if n == once "is_same_type".to_symbol then
880 s = "TAG_Bool((VAL2VFT({regs[0]})==VAL2VFT({regs[1]})))"
881 else if n == once "exit".to_symbol then
882 s = "exit(UNTAG_Int({regs[1]}));"
883 else if n == once "calloc_array".to_symbol then
884 s = "NEW_NativeArray(UNTAG_Int({regs[1]}), sizeof(val_t))"
885 else if n == once "calloc_string".to_symbol then
886 s = "BOX_NativeString((char*)raw_alloc((UNTAG_Int({regs[1]}) * sizeof(char))))"
887 # Add output_class_name native implementation
888 else if n == once "output_class_name".to_symbol then
889 s = "printf(\"%s\\n\", VAL2VFT({regs[0]})[2].cname);"
890 # Add class_name implementation
891 else if n == once "native_class_name".to_symbol then
892 s = "BOX_NativeString(VAL2VFT({regs[0]})[2].cname);"
893 end
894
895 if s == null then
896 var ll = location
897 if ll != null then v.add_instr("fprintf(stderr, \"{ll.to_s}: \");")
898 v.add_instr("fprintf(stderr, \"Fatal error: unknown intern method {method.full_name}.\\n\");")
899 v.add_instr("nit_exit(1);")
900 s = "NIT_NULL"
901 end
902 if result == null then
903 v.new_instr.add(s).add(";\n")
904 else if need_result then
905 var w = new_result(v)
906 w.add(s)
907 end
908 end
909 end
910
911 redef class IIntValue
912 redef fun compile_to_c(v)
913 do
914 v.add_location(location)
915 var w = new_result(v)
916 w.add("TAG_Int(").add(value.to_s).add(")")
917 end
918 end
919
920 redef class IBoolValue
921 redef fun compile_to_c(v)
922 do
923 v.add_location(location)
924 var w = new_result(v)
925 w.add("TAG_Bool(")
926 if value then w.add("true") else w.add("false")
927 w.add(")")
928 end
929 end
930
931 redef class ICharValue
932 redef fun compile_to_c(v)
933 do
934 v.add_location(location)
935 var w = new_result(v)
936 w.add("TAG_Char(").add(value).add(")")
937 end
938 end
939
940 redef class IFloatValue
941 redef fun compile_to_c(v)
942 do
943 v.add_location(location)
944 var w = new_result(v)
945 w.add("BOX_Float(").add(value).add(")")
946 end
947 end
948
949 redef class IStringValue
950 redef fun compile_to_c(v)
951 do
952 v.add_location(location)
953 var w = new_result(v)
954 w.add("BOX_NativeString(\"").add(value).add("\")")
955 end
956 end
957
958 redef class IAbort
959 redef fun compile_to_c(v)
960 do
961 v.add_location(location)
962 var w = v.new_instr
963 w.add("nit_abort(\"")
964 w.add(texts[0])
965 if texts.length > 1 then
966 w.add("\", \"")
967 w.add(texts[1])
968 w.add("\"")
969 else
970 w.add("\", NULL")
971 end
972 w.add(", LOCATE_")
973 w.add(module_location.cname)
974 var ll = location
975 if ll != null then
976 w.add(", ")
977 w.add(ll.line_start.to_s)
978 else
979 w.add(", 0")
980 end
981 w.add(");\n")
982 end
983 end
984
985 redef class IMove
986 redef fun compile_to_c(v)
987 do
988 if not need_result then return
989 var e = v.register(expr)
990 var r = v.register(result.as(not null))
991 if e == r then return
992 v.add_location(location)
993 var w = v.new_instr
994 w.add(r)
995 w.add(" = ")
996 w.add(e)
997 w.add(";\n")
998 end
999 end
1000
1001 redef class IAttrRead
1002 redef fun compile_to_c(v)
1003 do
1004 if not need_result then return
1005 v.add_location(location)
1006 var w = new_result(v)
1007 w.add(property.global.attr_access)
1008 w.add("(")
1009 w.add(v.register(expr))
1010 w.add(")")
1011 end
1012 end
1013
1014 redef class IAttrIsset
1015 redef fun compile_to_c(v)
1016 do
1017 if not need_result then return
1018 v.add_location(location)
1019 var w = new_result(v)
1020 w.add("TAG_Bool(")
1021 w.add(property.global.attr_access)
1022 w.add("(")
1023 w.add(v.register(expr))
1024 w.add(")!=NIT_NULL)")
1025 end
1026 end
1027
1028 redef class IAttrWrite
1029 redef fun compile_to_c(v)
1030 do
1031 v.add_location(location)
1032 var w = v.new_instr
1033 w.add(property.global.attr_access)
1034 w.add("(")
1035 w.add(v.register(expr1))
1036 w.add(") = ")
1037 w.add(v.register(expr2))
1038 w.add(";\n")
1039 end
1040 end
1041
1042 redef class ITypeCheck
1043 redef fun compile_to_c(v)
1044 do
1045 if not need_result then return
1046 v.add_location(location)
1047 var recv = v.register(expr2)
1048 var w = new_result(v)
1049 w.add("TAG_Bool(")
1050 if expr2.stype.is_nullable then
1051 if stype.is_nullable then
1052 w.add("(")
1053 w.add(recv)
1054 w.add("==NIT_NULL) || ")
1055 else if stype.as_nullable == expr2.stype then
1056 w.add(recv)
1057 w.add("!=NIT_NULL)")
1058 return
1059 else
1060 w.add("(")
1061 w.add(recv)
1062 w.add("!=NIT_NULL) && ")
1063 end
1064 end
1065 # FIXME handle formaltypes
1066 var t = stype
1067 if t isa MMVirtualType then
1068 var slf = v.register(expr1)
1069 var g = t.property.global
1070 w.add("VAL_ISA(")
1071 w.add(recv)
1072 w.add(", ")
1073 w.add(g.vt_class_color)
1074 w.add("(")
1075 w.add(slf)
1076 w.add(")")
1077 w.add(", ")
1078 w.add(g.vt_class_id)
1079 w.add("(")
1080 w.add(slf)
1081 w.add(")")
1082 w.add(")) /*cast ")
1083 w.add(t.to_s)
1084 w.add("*/")
1085 else
1086 var g = t.local_class.global
1087 w.add("VAL_ISA(")
1088 w.add(recv)
1089 w.add(", ")
1090 w.add(g.color_id)
1091 w.add(", ")
1092 w.add(g.id_id)
1093 w.add(")) /*cast ")
1094 w.add(t.to_s)
1095 w.add("*/")
1096 end
1097 end
1098 end
1099
1100 redef class IIs
1101 redef fun compile_to_c(v)
1102 do
1103 if not need_result then return
1104 v.add_location(location)
1105 var w = new_result(v)
1106 w.add("TAG_Bool(")
1107 var t1 = expr1.stype
1108 var t2 = expr2.stype
1109 if t1 isa MMTypeNone then
1110 if t2 isa MMTypeNone then
1111 w.add("1)")
1112 return
1113 else if t2.is_nullable then
1114 w.add(v.register(expr2))
1115 w.add("==NIT_NULL)")
1116 return
1117 else
1118 w.add("0)")
1119 return
1120 end
1121 else if t1.is_nullable then
1122 if t2 isa MMTypeNone then
1123 w.add(v.register(expr1))
1124 w.add("==NIT_NULL)")
1125 return
1126 else if t2.is_nullable then
1127 w.add("IS_EQUAL_NN(")
1128 else
1129 w.add("IS_EQUAL_ON(")
1130 w.add(v.register(expr2))
1131 w.add(",")
1132 w.add(v.register(expr1))
1133 w.add("))")
1134 return
1135 end
1136 else
1137 if t2 isa MMTypeNone then
1138 w.add("0)")
1139 return
1140 else if t2.is_nullable then
1141 w.add("IS_EQUAL_ON(")
1142 else
1143 w.add("IS_EQUAL_OO(")
1144 end
1145 end
1146 w.add(v.register(expr1))
1147 w.add(",")
1148 w.add(v.register(expr2))
1149 w.add("))")
1150 end
1151 end
1152
1153 redef class INot
1154 redef fun compile_to_c(v)
1155 do
1156 if not need_result then return
1157 v.add_location(location)
1158 var w = new_result(v)
1159 w.add("TAG_Bool(!UNTAG_Bool(")
1160 w.add(v.register(expr))
1161 w.add("))")
1162 end
1163 end
1164
1165 redef class IOnce
1166 redef fun compile_to_c(v)
1167 do
1168 v.add_location(location)
1169 var i = v.new_number
1170 var res = result.as(not null)
1171 if res.stype.is_nullable then
1172 v.add_decl("static val_t once_value_{i}; static int once_bool_{i}; /* Once value */")
1173 v.add_instr("if (!once_bool_{i}) \{")
1174 else
1175 # Since the value is not nullable, we use the null value to represent the boolean
1176 v.add_decl("static val_t once_value_{i}; /* Once value */")
1177 v.add_instr("if (!once_value_{i}) \{")
1178 end
1179 v.indent
1180 body.compile_to_c(v)
1181 var e = v.register(res)
1182 v.add_instr("once_value_{i} = {e};")
1183 v.add_instr("register_static_object(&once_value_{i});")
1184 if res.stype.is_nullable then v.add_instr("once_bool_{i} = true;")
1185 v.unindent
1186 v.add_instr("\} else {e} = once_value_{i};")
1187 var w = new_result(v)
1188 w.add(e)
1189 end
1190 end
1191
1192 redef class IClosCall
1193 redef fun compile_to_c(v: I2CCompilerVisitor)
1194 do
1195 v.add_location(location)
1196 var ivar: String
1197 var args: Array[String]
1198 if v.closure then
1199 ivar = "closctx->closure_funs[{v.closures[closure_decl]}]"
1200 args = ["closctx->closure_ctx"]
1201 else
1202 ivar = "CREG[{v.closures[closure_decl]}]"
1203 args = ["closctx_param"]
1204 end
1205 args.append(v.registers(exprs))
1206
1207 var s = "(({v.clostypes[closure_decl]})({ivar}))({args.join(", ")})"
1208 var w = new Writer
1209 w.add(s)
1210 store_result(v, w)
1211
1212 # Intercept escape
1213 v.add_instr("if ({args.first}->has_broke) \{")
1214 v.indent
1215 var bs = break_seq
1216 if bs != null then
1217 bs.compile_to_c(v)
1218 end
1219 v.add_goto(v.iroutine.body)
1220 v.unindent
1221 v.add_instr("\}")
1222 end
1223 end
1224
1225 redef class IHasClos
1226 redef fun compile_to_c(v)
1227 do
1228 if not need_result then return
1229 v.add_location(location)
1230 var w = new_result(v)
1231 w.add("TAG_Bool(")
1232 if v.closure then
1233 w.add("closctx->closure_funs[")
1234 w.add(v.closures[closure_decl])
1235 w.add("]")
1236 else
1237 w.add("CREG[")
1238 w.add(v.closures[closure_decl])
1239 w.add("]")
1240 end
1241 w.add(" != NULL)")
1242 end
1243 end
1244
1245 redef class IClosureDef
1246 # Compile the closure as a separate C function in the visitor out_contexts.
1247 # Return a fun_t pointer to the function.
1248 fun compile_closure(v: I2CCompilerVisitor): String
1249 do
1250 var cv = v.visitor
1251
1252 # We are now in a closure
1253 var cfc_old = v.closure
1254 v.closure = true
1255
1256 # We are now in a escape boundary
1257 var lls_old = v.local_labels
1258 v.local_labels = new HashSet[ISeq]
1259
1260 # We are now in a new C context
1261 var decl_writer_old = cv.decl_writer
1262 var writer_old = cv.writer
1263 cv.writer = cv.top_writer.sub
1264 cv.decl_writer = cv.header_writer.sub
1265
1266 # Generate the C function
1267 var cname = "OC_{v.basecname}_{v.new_number}"
1268 var args = compile_signature_to_c(v.visitor, cname, null, "struct stack_frame_t *closctx", null)
1269 cv.decl_writer = cv.writer.sub
1270
1271 var s = compile_inside_to_c(v, args)
1272 if s == null then
1273 v.add_instr("return;")
1274 else
1275 v.add_instr("return {s};")
1276 end
1277 v.unindent
1278 v.add_instr("\}")
1279
1280 # Restore things
1281 cv.writer = writer_old
1282 cv.decl_writer = decl_writer_old
1283 v.closure = cfc_old
1284 v.local_labels = lls_old
1285 return "((fun_t){cname})"
1286 end
1287 end