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