1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2009 Jean Privat <jean@pryen.org>
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
17 # Generate C code from intermediate code representation
18 package compiling_icode
21 private import analysis
25 # Compiler context from ICode to C
26 class I2CCompilerVisitor
28 var _ids
: HashMap[Object, String] = new HashMap[Object, String]
29 # Associate other things
30 var _ids2
: HashMap[Object, String] = new HashMap[Object, String]
32 # Return the string associated with a register
33 fun register
(e
: IRegister): String
35 if e
.stype
isa MMTypeNone then return "NIT_NULL"
37 if closure
and not e
.is_local
then ids
= _ids2
38 if ids
.has_key
(e
) then
43 # The register is dead
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}]"
57 strs
= once
new HashMap[Int, String]
58 if not strs
.has_key
(i
) then strs
[i
] = "fra.me.REG[{i}]"
67 # Return the strings associated with registers
68 fun registers
(a
: Collection[IRegister]): Array[String]
70 var r
= new Array[String].with_capacity
(a
.length
)
77 var _last_number
: Int = 0
78 # Give a new unique number (unique for the visitor)
85 # Return the string associated with a escape label
86 fun lab
(e
: ISeq): String
88 if _ids
.has_key
(e
) then
91 var s
= "label{new_number}"
97 # The rank (number) of each closure
98 readable var _closures
: HashMap[IClosureDecl, String] = new HashMap[IClosureDecl, String]
100 # The functionnal type of each closure
101 readable var _clostypes
: HashMap[IClosureDecl, String] = new HashMap[IClosureDecl, String]
103 # label locally accessibles
104 readable writable var _local_labels
: HashSet[ISeq] = new HashSet[ISeq]
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]
110 # Register a escape to a non local label and return an index identifying the label
111 fun register_escape_label
(e
: ISeq): Int
113 if _escaped_labels
.has_key
(e
) then
114 return _escaped_labels
[e
]
116 var res
= _escaped_labels
.length
+ 1
117 _escaped_labels
[e
] = res
122 # Add a C label mark (if needed)
123 fun add_label
(e
: ISeq)
125 if _ids
.has_key
(e
) then
126 add_instr
("{_ids[e]}: while(0);")
130 # Add a goto to a label (even outside a closure)
131 fun add_goto
(seq
: ISeq)
133 if local_labels
.has
(seq
) then
134 add_instr
("goto {lab(seq)};")
137 var ind
= register_escape_label
(seq
)
138 add_instr
("closctx->has_broke = {ind};")
139 add_instr
("goto {lab(return_label.as(not null))};")
143 # Association between IEscapeMarks and visited ISeq
144 readable var _marks_to_seq
: Map[IEscapeMark, ISeq] = new HashMap[IEscapeMark, ISeq]
146 # Are we in a closure ?
147 readable writable var _closure
: Bool = false
149 # The current compiler visitor
150 readable var _visitor
: CompilerVisitor
152 # The current compiled iroutine
153 readable var _iroutine
: IRoutine
155 # The return label of the current compiling C function
156 readable writable var _return_label
: nullable ISeq = null
158 fun add_decl
(s
: String)
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
167 var w
= visitor
.writer
168 var l
= _next_location
170 visitor
.add_indent
(w
)
172 w
.add
(l
.file
.filename
)
174 w
.add
(l
.line_start
.to_s
)
176 _next_location
= null
178 visitor
.add_indent
(w
)
182 fun add_instr
(s
: String)
184 new_instr
.add
(s
).add
("\n")
197 fun add_assignment
(to
, from
: String)
199 visitor
.add_assignment
(to
, from
)
202 var _last_location
: nullable Location = null
203 var _next_location
: nullable Location = null
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)
209 var last
= _last_location
210 if last
== l
or l
== null then return
212 if last
!= null and last
.file
== l
.file
and last
.line_start
== l
.line_start
then
219 # The C fonction name of the iroutine
220 readable var _basecname
: String
222 init(v
: CompilerVisitor, ir
: IRoutine, cname
: String)
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]
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
242 cparams
.add
("val_t p{i}")
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")
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}")
261 if after_params
!= null then cparams
.add
(after_params
)
263 if result
!= null then r
= "val_t"
265 if cparams
.is_empty
then
268 p
= cparams
.join
(", ")
270 if human_name
!= null then
271 v
.add_instr
("static const char LOCATE_{cname}[] = \"{human_name}\
";")
273 v
.add_decl
("{r} {cname}({p});")
274 v
.add_decl
("typedef {r} (*{cname}_t)({p});")
275 v
.add_instr
("{r} {cname}({p})\{")
280 # Compile the body of the routine, return the result value is any
281 fun compile_inside_to_c
(v
: I2CCompilerVisitor, args
: Array[String]): nullable String
283 # Create and push the stack frame
285 if location
!= null then
286 ll
= location
.line_start
288 # Encapsulate the frame ('me') in a larger structure ('fra') that has enough space to store the local variables (REG)
289 if std_slots_nb
> 1 then
290 v
.add_decl
("struct \{struct stack_frame_t me; val_t MORE_REG[{std_slots_nb-1}];\} fra;")
292 v
.add_decl
("struct \{struct stack_frame_t me;\} fra;")
294 v
.add_instr
("fra.me.prev = stack_frame_head; stack_frame_head = &fra.me;")
295 v
.add_instr
("fra.me.file = LOCATE_{v.visitor.mmmodule.cname};")
296 v
.add_instr
("fra.me.line = {ll};")
297 v
.add_instr
("fra.me.meth = LOCATE_{v.basecname};")
298 v
.add_instr
("fra.me.has_broke = 0;")
299 v
.add_instr
("fra.me.REG_size = {std_slots_nb};")
300 v
.add_instr
("fra.me.nitni_local_ref_head = NULL;")
302 # Declare/initialize local variables
303 for i
in [0..std_slots_nb
[ do
304 v
.add_instr
("fra.me.REG[{i}] = NIT_NULL;")
306 for i
in [0..tag_slots_nb
[ do
307 v
.add_decl
("val_t REGB{i};")
309 var iclosdecls
= closure_decls
310 if iclosdecls
!= null then
311 v
.add_decl
("fun_t CREG[{iclosdecls.length}];")
312 v
.add_instr
("fra.me.closure_ctx = closctx_param;")
313 v
.add_instr
("fra.me.closure_funs = CREG;")
317 if r
.slot_index
!= null then v
.add_assignment
(v
.register
(r
), args
[k
])
320 if iclosdecls
!= null then
321 for i
in [0..iclosdecls
.length
[ do
322 var iclosdecl
= iclosdecls
[i
]
323 v
.add_instr
("CREG[{i}] = {args[params.length+i]};")
324 v
.closures
[iclosdecl
] = i
.to_s
325 var cs
= iclosdecl
.closure
.signature
# Closure signature
326 var subparams
= new Array[String] # Parameters of the closure
327 subparams
.add
("struct stack_frame_t *")
328 for j
in [0..cs
.arity
[ do
333 if cs
.return_type
!= null then r
= "val_t"
334 v
.clostypes
[iclosdecl
] = "{r} (*)({subparams.join(", ")})"
337 v
.add_decl
("val_t tmp;")
340 var old_rl
= v
.return_label
341 v
.return_label
= body
346 v
.add_instr
("stack_frame_head = fra.me.prev;")
347 v
.return_label
= old_rl
356 # Full compilation of the routine
357 # cv must be in the correct function
358 fun compile_to_c
(cv
: CompilerVisitor, cname
: String, args
: Array[String]): nullable String
360 var v
= new I2CCompilerVisitor(cv
, self, cname
)
361 return compile_inside_to_c
(v
, args
)
366 # Full compilation of the icode
367 fun compile_to_c
(v
: I2CCompilerVisitor) is abstract
369 # Is a result really needed
370 private fun need_result
: Bool
373 return r
!= null and r
.slot_index
!= null
376 # Store s in the result value of self
377 private fun store_result
(v
: I2CCompilerVisitor, w
: nullable Writer)
380 if r
!= null and r
.slot_index
!= null then
383 w2
.add
(v
.register
(r
))
387 else if w
!= null and not is_pure
then
388 # ICode with side effects must be evaluated
389 # even if the result is not wanted
396 # Prepare a writer if the expression icode need to be compiled
397 # * Result assigment is automatic if needed
398 private fun new_result
(v
: I2CCompilerVisitor): Writer
400 assert need_result
or not is_pure
403 if r
!= null and r
.slot_index
!= null then
404 w2
.add
(v
.register
(r
))
414 redef fun compile_to_c
(v
)
416 v
.add_location
(location
)
417 v
.local_labels
.add
(self)
418 var mark
= iescape_mark
419 if mark
!= null then v
.marks_to_seq
[mark
] = self
428 redef fun compile_to_c
(v
)
430 v
.add_location
(location
)
432 w
.add
("if (UNTAG_Bool(")
433 w
.add
(v
.register
(expr
))
435 if not then_seq
.icodes
.is_empty
then
437 then_seq
.compile_to_c
(v
)
440 if not else_seq
.icodes
.is_empty
then
441 v
.add_instr
("\} else \{")
443 else_seq
.compile_to_c
(v
)
451 redef fun compile_to_c
(v
)
453 v
.add_location
(location
)
454 v
.local_labels
.add
(self)
455 var mark
= iescape_mark
456 if mark
!= null then v
.marks_to_seq
[mark
] = self
457 v
.add_instr
("while(1) \{")
469 redef fun compile_to_c
(v
)
471 v
.add_location
(location
)
472 v
.add_goto
(v
.marks_to_seq
[iescape_mark
])
477 redef fun compile_to_c
(v
)
479 v
.add_location
(location
)
480 var args
= v
.registers
(exprs
)
482 # Compile closure definitions
483 var old_el
= v
.escaped_labels
484 var closdefs
= closure_defs
485 var closctx
: nullable String = null # The closure context of closdefs
486 if closdefs
!= null then
487 # Get the closure context
491 closctx
= "(&(fra.me))"
494 # First aditionnal arguments is the closure context
497 # We are in a new escape boundary
498 v
.escaped_labels
= new HashMap[ISeq, Int]
500 # Compile each closures and add each sub-function as an other additionnal parameter
501 for cd
in closdefs
do
503 var cn
= cd
.compile_closure
(v
)
511 # Compile the real call
512 var call
= compile_call_to_c
(v
, args
)
513 var res
: nullable Writer = call
516 if closctx
!= null then
517 var els
= v
.escaped_labels
518 v
.escaped_labels
= old_el
519 # Is there possible escapes?
520 if not els
.is_empty
then
521 # Call in a tmp variable to avoid 'break' overwrite
535 # What are the expected escape indexes
536 v
.new_instr
.add
("switch (").add
(closctx
).add
("->has_broke) \{\n")
538 # No escape occured, continue as usual
539 v
.add_instr
("case 0: break;")
540 var lls
= v
.local_labels
541 var iels
= els
.iterator
542 var forward_escape
= false
546 # Local escape occured
547 # Clear the has_broke information and go to the target
548 v
.new_instr
.add
("case ").add
(iels
.item
.to_s
).add
(": ").add
(closctx
).add
("->has_broke = 0; goto ").add
(v
.lab
(seq
)).add
(";\n")
550 # Forward escape occured: register the escape label
552 v
.register_escape_label
(seq
)
553 forward_escape
= true
557 # If forward escape occured, just pass to the next one
558 if forward_escape
then
559 # Do not need to copy 'has_broke' value since it is shared by the next one.
560 # So just exit the C function.
561 v
.new_instr
.add
("default: goto ").add
(v
.lab
(v
.return_label
.as(not null))).add
(";\n")
569 var w
= new_result
(v
)
574 # The single invocation witout fancy stuffs
575 private fun compile_call_to_c
(v
: I2CCompilerVisitor, args
: Array[String]): Writer is abstract
579 redef fun compile_call_to_c
(v
, args
)
583 # do not compile explicit calls from native methods
584 # theses are really manually called in the native implementation
585 if is_explicit_from_extern
then return w
588 if prop
.global
.is_init
then args
.add
("init_table")
589 w
.add
(prop
.global
.meth_call
)
593 w
.add_all
(args
, ", ")
600 redef fun compile_call_to_c
(v
, args
)
602 # do not compile explicit calls from native methods
603 # theses are really manually called in the native implementation
604 if is_explicit_from_extern
then return new Writer
607 if prop
.global
.is_init
then args
.add
("init_table")
609 w
.add
(prop
.super_meth_call
)
613 w
.add_all
(args
, ", ")
620 redef fun compile_call_to_c
(v
, args
)
624 # do not compile explicit calls from native methods
625 # theses are really manually called in the native implementation
626 if is_explicit_from_extern
then return w
629 w
.add
(stype
.local_class
.to_s
)
631 w
.add
(property
.global
.intro
.cname
)
633 w
.add_all
(args
, ", ")
639 redef class IAllocateInstance
640 redef fun compile_to_c
(v
)
642 v
.add_location
(location
)
643 var w
= new_result
(v
)
645 w
.add
(stype
.local_class
.cname
)
650 redef class ICheckInstance
651 redef fun compile_to_c
(v
)
653 v
.add_location
(location
)
654 var w
= new_result
(v
)
656 w
.add
(stype
.local_class
.cname
)
658 w
.add
(v
.register
(expr
))
663 redef class IInitAttributes
664 redef fun compile_to_c
(v
)
666 v
.add_location
(location
)
668 w
.add
("INIT_ATTRIBUTES__")
669 w
.add
(stype
.local_class
.cname
)
671 w
.add
(v
.register
(expr
))
676 redef class IStaticCall
677 redef fun compile_call_to_c
(v
, args
)
680 if prop
.global
.is_init
then args
.add
("init_table")
682 w
.add
(property
.cname
)
684 w
.add_all
(args
, ", ")
691 redef fun compile_to_c
(v
)
693 v
.add_location
(location
)
694 if method
.is_intern
then
695 compile_intern_method_to_c
(v
)
696 else if not method
.global
.is_init
then
697 compile_extern_method_to_c
(v
)
701 fun compile_extern_method_to_c
(v
: I2CCompilerVisitor)
703 var ename
= "{method.friendly_extern_name(method.local_class)}___out"
705 var sig
= method
.signature
706 assert exprs
.length
== sig
.arity
+ 1
708 var regs
= v
.registers
(exprs
)
710 var args
= new Array[String]
712 for i
in [0..sig
.arity
[ do
715 var s
= "{ename}({args.join(", ")})"
717 if need_result
then s
= s
# sig.return_type.boxtype(s)
718 var w
= new_result
(v
)
722 fun compile_intern_method_to_c
(v
: I2CCompilerVisitor)
724 var sig
= method
.signature
725 assert exprs
.length
== sig
.arity
+ 1
726 var c
= method
.local_class
.name
728 var regs
= v
.registers
(exprs
)
729 var s
: nullable String = null
730 if c
== once
"Int".to_symbol
then
731 if n
== once
"object_id".to_symbol
then
733 else if n
== once
"unary -".to_symbol
then
734 s
= "TAG_Int(-UNTAG_Int({regs[0]}))"
735 else if n
== once
"output".to_symbol
then
736 s
= "printf(\"%ld\\n\
", UNTAG_Int({regs[0]}));"
737 else if n
== once
"ascii".to_symbol
then
738 s
= "TAG_Char(UNTAG_Int({regs[0]}))"
739 else if n
== once
"succ".to_symbol
then
740 s
= "TAG_Int(UNTAG_Int({regs[0]})+1)"
741 else if n
== once
"prec".to_symbol
then
742 s
= "TAG_Int(UNTAG_Int({regs[0]})-1)"
743 else if n
== once
"to_f".to_symbol
then
744 s
= "BOX_Float((float)UNTAG_Int({regs[0]}))"
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_Int(UNTAG_Int({regs[0]})/UNTAG_Int({regs[1]}))"
753 else if n
== once
"%".to_symbol
then
754 s
= "TAG_Int(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
"<=".to_symbol
then
760 s
= "TAG_Bool(UNTAG_Int({regs[0]})<=UNTAG_Int({regs[1]}))"
761 else if n
== once
">=".to_symbol
then
762 s
= "TAG_Bool(UNTAG_Int({regs[0]})>=UNTAG_Int({regs[1]}))"
763 else if n
== once
"lshift".to_symbol
then
764 s
= "TAG_Int(UNTAG_Int({regs[0]})<<UNTAG_Int({regs[1]}))"
765 else if n
== once
"rshift".to_symbol
then
766 s
= "TAG_Int(UNTAG_Int({regs[0]})>>UNTAG_Int({regs[1]}))"
767 else if n
== once
"==".to_symbol
then
768 s
= "TAG_Bool(({regs[0]})==({regs[1]}))"
769 else if n
== once
"!=".to_symbol
then
770 s
= "TAG_Bool(({regs[0]})!=({regs[1]}))"
772 else if c
== once
"Float".to_symbol
then
773 if n
== once
"object_id".to_symbol
then
774 s
= "TAG_Int((bigint)UNBOX_Float({regs[0]}))"
775 else if n
== once
"unary -".to_symbol
then
776 s
= "BOX_Float(-UNBOX_Float({regs[0]}))"
777 else if n
== once
"output".to_symbol
then
778 s
= "printf(\"%f\\n\
", UNBOX_Float({regs[0]}));"
779 else if n
== once
"to_i".to_symbol
then
780 s
= "TAG_Int((bigint)UNBOX_Float({regs[0]}))"
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
= "BOX_Float(UNBOX_Float({regs[0]})*UNBOX_Float({regs[1]}))"
787 else if n
== once
"/".to_symbol
then
788 s
= "BOX_Float(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 else if n
== once
"<=".to_symbol
then
794 s
= "TAG_Bool(UNBOX_Float({regs[0]})<=UNBOX_Float({regs[1]}))"
795 else if n
== once
">=".to_symbol
then
796 s
= "TAG_Bool(UNBOX_Float({regs[0]})>=UNBOX_Float({regs[1]}))"
798 else if c
== once
"Char".to_symbol
then
799 if n
== once
"object_id".to_symbol
then
800 s
= "TAG_Int(UNTAG_Char({regs[0]}))"
801 else if n
== once
"unary -".to_symbol
then
802 s
= "TAG_Char(-UNTAG_Char({regs[0]}))"
803 else if n
== once
"output".to_symbol
then
804 s
= "printf(\"%c\
", (unsigned char)UNTAG_Char({regs[0]}));"
805 else if n
== once
"ascii".to_symbol
then
806 s
= "TAG_Int((unsigned char)UNTAG_Char({regs[0]}))"
807 else if n
== once
"succ".to_symbol
then
808 s
= "TAG_Char(UNTAG_Char({regs[0]})+1)"
809 else if n
== once
"prec".to_symbol
then
810 s
= "TAG_Char(UNTAG_Char({regs[0]})-1)"
811 else if n
== once
"to_i".to_symbol
then
812 s
= "TAG_Int(UNTAG_Char({regs[0]})-'0')"
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_Char(UNTAG_Char({regs[0]})/UNTAG_Char({regs[1]}))"
821 else if n
== once
"%".to_symbol
then
822 s
= "TAG_Char(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(UNTAG_Char({regs[0]})<=UNTAG_Char({regs[1]}))"
829 else if n
== once
">=".to_symbol
then
830 s
= "TAG_Bool(UNTAG_Char({regs[0]})>=UNTAG_Char({regs[1]}))"
831 else if n
== once
"==".to_symbol
then
832 s
= "TAG_Bool(({regs[0]})==({regs[1]}))"
833 else if n
== once
"!=".to_symbol
then
834 s
= "TAG_Bool(({regs[0]})!=({regs[1]}))"
836 else if c
== once
"Bool".to_symbol
then
837 if n
== once
"object_id".to_symbol
then
838 s
= "TAG_Int(UNTAG_Bool({regs[0]}))"
839 else if n
== once
"unary -".to_symbol
then
840 s
= "TAG_Bool(-UNTAG_Bool({regs[0]}))"
841 else if n
== once
"output".to_symbol
then
842 s
= "(void)printf(UNTAG_Bool({regs[0]})?\"true\\n\
":\"false\\n\
");"
843 else if n
== once
"ascii".to_symbol
then
844 s
= "TAG_Bool(UNTAG_Bool({regs[0]}))"
845 else if n
== once
"to_i".to_symbol
then
846 s
= "TAG_Int(UNTAG_Bool({regs[0]}))"
847 else if n
== once
"==".to_symbol
then
848 s
= "TAG_Bool(({regs[0]})==({regs[1]}))"
849 else if n
== once
"!=".to_symbol
then
850 s
= "TAG_Bool(({regs[0]})!=({regs[1]}))"
852 else if c
== once
"NativeArray".to_symbol
then
853 if n
== once
"object_id".to_symbol
then
854 s
= "TAG_Int(((Nit_NativeArray){regs[0]})->object_id)"
855 else if n
== once
"[]".to_symbol
then
856 s
= "((Nit_NativeArray){regs[0]})->val[UNTAG_Int({regs[1]})]"
857 else if n
== once
"[]=".to_symbol
then
858 s
= "((Nit_NativeArray){regs[0]})->val[UNTAG_Int({regs[1]})]={regs[2]}"
859 else if n
== once
"copy_to".to_symbol
then
860 s
= "(void)memcpy(((Nit_NativeArray ){regs[1]})->val, ((Nit_NativeArray){regs[0]})->val, UNTAG_Int({regs[2]})*sizeof(val_t))"
862 else if c
== once
"NativeString".to_symbol
then
863 if n
== once
"object_id".to_symbol
then
864 s
= "TAG_Int(UNBOX_NativeString({regs[0]}))"
865 else if n
== once
"atoi".to_symbol
then
866 s
= "TAG_Int(atoi(UNBOX_NativeString({regs[0]})))"
867 else if n
== once
"[]".to_symbol
then
868 s
= "TAG_Char(UNBOX_NativeString({regs[0]})[UNTAG_Int({regs[1]})])"
869 else if n
== once
"[]=".to_symbol
then
870 s
= "UNBOX_NativeString({regs[0]})[UNTAG_Int({regs[1]})]=UNTAG_Char({regs[2]});"
871 else if n
== once
"copy_to".to_symbol
then
872 s
= "(void)memcpy(UNBOX_NativeString({regs[1]})+UNTAG_Int({regs[4]}), UNBOX_NativeString({regs[0]})+UNTAG_Int({regs[3]}), UNTAG_Int({regs[2]}));"
874 else if c
== once
"Sys".to_symbol
then
875 if n
== once
"force_garbage_collection".to_symbol
then
876 s
= "Nit_gc_force_garbage_collection()"
877 else if n
== once
"native_argc".to_symbol
then
878 s
= "TAG_Int(glob_argc)"
879 else if n
== once
"native_argv".to_symbol
then
880 s
= "BOX_NativeString(glob_argv[UNTAG_Int({regs[1]})])"
882 else if n
== once
"object_id".to_symbol
then
883 s
= "TAG_Int((bigint)((obj_t){regs[0]})[1].object_id)"
884 else if n
== once
"sys".to_symbol
then
886 else if n
== once
"is_same_type".to_symbol
then
887 s
= "TAG_Bool((VAL2VFT({regs[0]})==VAL2VFT({regs[1]})))"
888 else if n
== once
"exit".to_symbol
then
889 s
= "exit(UNTAG_Int({regs[1]}));"
890 else if n
== once
"calloc_array".to_symbol
then
891 s
= "NEW_NativeArray(UNTAG_Int({regs[1]}), sizeof(val_t))"
892 else if n
== once
"calloc_string".to_symbol
then
893 s
= "BOX_NativeString((char*)raw_alloc((UNTAG_Int({regs[1]}) * sizeof(char))))"
894 # Add output_class_name native implementation
895 else if n
== once
"output_class_name".to_symbol
then
896 s
= "printf(\"%s\\n\
", VAL2VFT({regs[0]})[2].cname);"
897 # Add class_name implementation
898 else if n
== once
"native_class_name".to_symbol
then
899 s
= "BOX_NativeString(VAL2VFT({regs[0]})[2].cname);"
904 if ll
!= null then v
.add_instr
("fprintf(stderr, \"{ll.to_s}: \
");")
905 v
.add_instr
("fprintf(stderr, \"Fatal error
: unknown
intern method
{method.full_name}.\\n\
");")
906 v
.add_instr
("nit_exit(1);")
909 if result
== null then
910 v
.new_instr
.add
(s
).add
(";\n")
911 else if need_result
then
912 var w
= new_result
(v
)
918 redef class IIntValue
919 redef fun compile_to_c
(v
)
921 v
.add_location
(location
)
922 var w
= new_result
(v
)
923 w
.add
("TAG_Int(").add
(value
.to_s
).add
(")")
927 redef class IBoolValue
928 redef fun compile_to_c
(v
)
930 v
.add_location
(location
)
931 var w
= new_result
(v
)
933 if value
then w
.add
("1") else w
.add
("0")
938 redef class ICharValue
939 redef fun compile_to_c
(v
)
941 v
.add_location
(location
)
942 var w
= new_result
(v
)
943 w
.add
("TAG_Char(").add
(value
).add
(")")
947 redef class IFloatValue
948 redef fun compile_to_c
(v
)
950 v
.add_location
(location
)
951 var w
= new_result
(v
)
952 w
.add
("BOX_Float(").add
(value
).add
(")")
956 redef class IStringValue
957 redef fun compile_to_c
(v
)
959 v
.add_location
(location
)
960 var w
= new_result
(v
)
961 w
.add
("BOX_NativeString(\"").add(value).add("\
")")
966 redef fun compile_to_c
(v
)
968 v
.add_location
(location
)
970 w
.add
("nit_abort(\"")
972 if texts.length > 1 then
980 w.add(module_location.cname)
984 w.add(ll.line_start.to_s)
993 redef fun compile_to_c(v)
995 if not need_result then return
996 var e = v.register(expr)
997 var r = v.register(result.as(not null))
998 if e == r then return
999 v.add_location(location)
1008 redef class IAttrRead
1009 redef fun compile_to_c(v)
1011 if not need_result then return
1012 v.add_location(location)
1013 var w = new_result(v)
1014 w.add(property.global.attr_access)
1016 w.add(v.register(expr))
1021 redef class IAttrIsset
1022 redef fun compile_to_c(v)
1024 if not need_result then return
1025 v.add_location(location)
1026 var w = new_result(v)
1028 w.add(property.global.attr_access)
1030 w.add(v.register(expr))
1031 w.add(")!=NIT_NULL)")
1035 redef class IAttrWrite
1036 redef fun compile_to_c(v)
1038 v.add_location(location)
1040 w.add(property.global.attr_access)
1042 w.add(v.register(expr1))
1044 w.add(v.register(expr2))
1049 redef class ITypeCheck
1050 redef fun compile_to_c(v)
1052 if not need_result then return
1053 v.add_location(location)
1054 var recv = v.register(expr2)
1055 var w = new_result(v)
1057 if expr2.stype.is_nullable then
1058 if stype.is_nullable then
1061 w.add("==NIT_NULL) || ")
1062 else if stype.as_nullable == expr2.stype then
1064 w.add("!=NIT_NULL)")
1069 w.add("!=NIT_NULL) && ")
1072 # FIXME handle formaltypes
1074 if t isa MMVirtualType then
1075 var slf = v.register(expr1)
1076 var g = t.property.global
1080 w.add(g.vt_class_color)
1085 w.add(g.vt_class_id)
1093 var g = t.local_class.global
1108 redef fun compile_to_c(v)
1110 if not need_result then return
1111 v.add_location(location)
1112 var w = new_result(v)
1114 var t1 = expr1.stype
1115 var t2 = expr2.stype
1116 if t1 isa MMTypeNone then
1117 if t2 isa MMTypeNone then
1120 else if t2.is_nullable then
1121 w.add(v.register(expr2))
1122 w.add("==NIT_NULL)")
1128 else if t1.is_nullable then
1129 if t2 isa MMTypeNone then
1130 w.add(v.register(expr1))
1131 w.add("==NIT_NULL)")
1133 else if t2.is_nullable then
1134 w.add("IS_EQUAL_NN(")
1136 w.add("IS_EQUAL_ON(")
1137 w.add(v.register(expr2))
1139 w.add(v.register(expr1))
1144 if t2 isa MMTypeNone then
1147 else if t2.is_nullable then
1148 w.add("IS_EQUAL_ON(")
1150 w.add("IS_EQUAL_OO(")
1153 w.add(v.register(expr1))
1155 w.add(v.register(expr2))
1161 redef fun compile_to_c(v)
1163 if not need_result then return
1164 v.add_location(location)
1165 var w = new_result(v)
1166 w.add("TAG_Bool(!UNTAG_Bool(")
1167 w.add(v.register(expr))
1173 redef fun compile_to_c(v)
1175 v.add_location(location)
1176 var i = v.new_number
1177 var res = result.as(not null)
1178 if res.stype.is_nullable then
1179 v.add_decl("static val_t once_value_
{i}; static int once_bool_
{i}; /* Once value
*/")
1180 v.add_instr("if (!once_bool_
{i}) \
{")
1182 # Since the value is not nullable, we use the null value to represent the boolean
1183 v.add_decl("static val_t once_value_
{i}; /* Once value
*/")
1184 v.add_instr("if (!once_value_
{i}) \
{")
1187 body.compile_to_c(v)
1188 var e = v.register(res)
1189 v.add_instr("once_value_
{i} = {e};")
1190 v.add_instr("register_static_object
(&once_value_
{i});")
1191 if res.stype.is_nullable then v.add_instr("once_bool_
{i} = true;")
1193 v.add_instr("\
} else {e} = once_value_
{i};")
1194 var w = new_result(v)
1199 redef class IClosCall
1200 redef fun compile_to_c(v: I2CCompilerVisitor)
1202 v.add_location(location)
1204 var args: Array[String]
1206 ivar = "closctx-
>closure_funs
[{v.closures[closure_decl]}]"
1207 args = ["closctx-
>closure_ctx
"]
1209 ivar = "CREG[{v.closures[closure_decl]}]"
1210 args = ["closctx_param
"]
1212 args.append(v.registers(exprs))
1214 var s = "(({v.clostypes[closure_decl]})({ivar}))({args.join(", ")})"
1220 v.add_instr("if ({args.first}->has_broke
) \
{")
1226 v.add_goto(v.iroutine.body)
1232 redef class IHasClos
1233 redef fun compile_to_c(v)
1235 if not need_result then return
1236 v.add_location(location)
1237 var w = new_result(v)
1240 w.add("closctx-
>closure_funs
[")
1241 w.add(v.closures[closure_decl])
1245 w.add(v.closures[closure_decl])
1252 redef class IClosureDef
1253 # Compile the closure as a separate C function in the visitor out_contexts.
1254 # Return a fun_t pointer to the function.
1255 fun compile_closure(v: I2CCompilerVisitor): String
1259 # We are now in a closure
1260 var cfc_old = v.closure
1263 # We are now in a escape boundary
1264 var lls_old = v.local_labels
1265 v.local_labels = new HashSet[ISeq]
1267 # We are now in a new C context
1268 var decl_writer_old = cv.decl_writer
1269 var writer_old = cv.writer
1270 cv.writer = cv.top_writer.sub
1271 cv.decl_writer = cv.header_writer.sub
1273 # Generate the C function
1274 var cname = "OC_{v.basecname}_
{v.new_number}"
1275 var args = compile_signature_to_c(v.visitor, cname, null, "struct stack_frame_t
*closctx
", null)
1276 cv.decl_writer = cv.writer.sub
1278 var s = compile_inside_to_c(v, args)
1280 v.add_instr("return;")
1282 v.add_instr("return {s};")
1288 cv.writer = writer_old
1289 cv.decl_writer = decl_writer_old
1291 v.local_labels = lls_old
1292 return "((fun_t
){cname})"