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
24 # Compiler context from ICode to C
25 class I2CCompilerVisitor
27 var _ids
: HashMap[Object, String] = new HashMap[Object, String]
28 # Associate other things
29 var _ids2
: HashMap[Object, String] = new HashMap[Object, String]
31 # Return the string associated with a register
32 fun register
(e
: IRegister): String
34 if e
.stype
isa MMTypeNone then return "NIT_NULL"
36 if closure
and not e
.is_local
then ids
= _ids2
37 if ids
.has_key
(e
) then
42 # The register is dead
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}]"
56 strs
= once
new HashMap[Int, String]
57 if not strs
.has_key
(i
) then strs
[i
] = "fra.me.REG[{i}]"
66 # Return the strings associated with registers
67 fun registers
(a
: Collection[IRegister]): Array[String]
69 var r
= new Array[String].with_capacity
(a
.length
)
76 var _last_number
: Int = 0
77 # Give a new unique number (unique for the visitor)
84 # Return the string associated with a escape label
85 fun lab
(e
: ISeq): String
87 if _ids
.has_key
(e
) then
90 var s
= "label{new_number}"
96 # The rank (number) of each closure
97 readable var _closures
: HashMap[IClosureDecl, String] = new HashMap[IClosureDecl, String]
99 # The functionnal type of each closure
100 readable var _clostypes
: HashMap[IClosureDecl, String] = new HashMap[IClosureDecl, String]
102 # label locally accessibles
103 readable writable var _local_labels
: HashSet[ISeq] = new HashSet[ISeq]
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]
109 # Register a escape to a non local label and return an index identifying the label
110 fun register_escape_label
(e
: ISeq): Int
112 if _escaped_labels
.has_key
(e
) then
113 return _escaped_labels
[e
]
115 var res
= _escaped_labels
.length
+ 1
116 _escaped_labels
[e
] = res
121 # Add a C label mark (if needed)
122 fun add_label
(e
: ISeq)
124 if _ids
.has_key
(e
) then
125 add_instr
("{_ids[e]}: while(0);")
129 # Add a goto to a label (even outside a closure)
130 fun add_goto
(seq
: ISeq)
132 if local_labels
.has
(seq
) then
133 add_instr
("goto {lab(seq)};")
136 var ind
= register_escape_label
(seq
)
137 add_instr
("closctx->has_broke = {ind};")
138 add_instr
("goto {lab(return_label.as(not null))};")
142 # Association between IEscapeMarks and visited ISeq
143 readable var _marks_to_seq
: Map[IEscapeMark, ISeq] = new HashMap[IEscapeMark, ISeq]
145 # Are we in a closure ?
146 readable writable var _closure
: Bool = false
148 # The current compiler visitor
149 readable var _visitor
: CompilerVisitor
151 # The current compiled iroutine
152 readable var _iroutine
: IRoutine
154 # The return label of the current compiling C function
155 readable writable var _return_label
: nullable ISeq = null
157 fun add_decl
(s
: String)
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
166 var w
= visitor
.writer
167 var l
= _next_location
169 visitor
.add_indent
(w
)
173 w
.add
(l
.line_start
.to_s
)
175 _next_location
= null
177 visitor
.add_indent
(w
)
181 fun add_instr
(s
: String)
183 new_instr
.add
(s
).add
("\n")
196 fun add_assignment
(to
, from
: String)
198 visitor
.add_assignment
(to
, from
)
201 var _last_location
: nullable Location = null
202 var _next_location
: nullable Location = null
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)
208 var last
= _last_location
209 if last
== l
or l
== null then return
211 if last
!= null and last
.file
== l
.file
and last
.line_start
== l
.line_start
then
218 # The C fonction name of the iroutine
219 readable var _basecname
: String
221 init(v
: CompilerVisitor, ir
: IRoutine, cname
: String)
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]
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
241 cparams
.add
("val_t p{i}")
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")
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}")
260 if after_params
!= null then cparams
.add
(after_params
)
262 if result
!= null then r
= "val_t"
264 if cparams
.is_empty
then
267 p
= cparams
.join
(", ")
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})\{")
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
280 # Create and push the stack frame
282 if location
!= null then
283 ll
= location
.line_start
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;")
289 v
.add_decl
("struct \{struct stack_frame_t me;\} fra;")
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};")
298 # Declare/initialize local variables
299 for i
in [0..std_slots_nb
[ do
300 v
.add_instr
("fra.me.REG[{i}] = NIT_NULL;")
302 for i
in [0..tag_slots_nb
[ do
303 v
.add_decl
("val_t REGB{i};")
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;")
313 if r
.slot_index
!= null then v
.add_assignment
(v
.register
(r
), args
[k
])
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
329 if cs
.return_type
!= null then r
= "val_t"
330 v
.clostypes
[iclosdecl
] = "{r} (*)({subparams.join(", ")})"
333 v
.add_decl
("val_t tmp;")
336 var old_rl
= v
.return_label
337 v
.return_label
= body
342 v
.add_instr
("stack_frame_head = fra.me.prev;")
343 v
.return_label
= old_rl
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
356 var v
= new I2CCompilerVisitor(cv
, self, cname
)
357 return compile_inside_to_c
(v
, args
)
362 # Full compilation of the icode
363 fun compile_to_c
(v
: I2CCompilerVisitor) is abstract
365 # Is a result really needed
366 private fun need_result
: Bool
369 return r
!= null and r
.slot_index
!= null
372 # Store s in the result value of self
373 private fun store_result
(v
: I2CCompilerVisitor, w
: nullable Writer)
376 if r
!= null and r
.slot_index
!= null then
379 w2
.add
(v
.register
(r
))
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
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
396 assert need_result
or not is_pure
399 if r
!= null and r
.slot_index
!= null then
400 w2
.add
(v
.register
(r
))
410 redef fun compile_to_c
(v
)
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
424 redef fun compile_to_c
(v
)
426 v
.add_location
(location
)
428 w
.add
("if (UNTAG_Bool(")
429 w
.add
(v
.register
(expr
))
431 if not then_seq
.icodes
.is_empty
then
433 then_seq
.compile_to_c
(v
)
436 if not else_seq
.icodes
.is_empty
then
437 v
.add_instr
("\} else \{")
439 else_seq
.compile_to_c
(v
)
447 redef fun compile_to_c
(v
)
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) \{")
465 redef fun compile_to_c
(v
)
467 v
.add_location
(location
)
468 v
.add_goto
(v
.marks_to_seq
[iescape_mark
])
473 redef fun compile_to_c
(v
)
475 v
.add_location
(location
)
476 var args
= v
.registers
(exprs
)
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
487 closctx
= "(&(fra.me))"
490 # First aditionnal arguments is the closure context
493 # We are in a new escape boundary
494 v
.escaped_labels
= new HashMap[ISeq, Int]
496 # Compile each closures and add each sub-function as an other additionnal parameter
497 for cd
in closdefs
do
499 var cn
= cd
.compile_closure
(v
)
507 # Compile the real call
508 var call
= compile_call_to_c
(v
, args
)
509 var res
: nullable Writer = call
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
531 # What are the expected escape indexes
532 v
.new_instr
.add
("switch (").add
(closctx
).add
("->has_broke) \{\n")
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
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")
546 # Forward escape occured: register the escape label
548 v
.register_escape_label
(seq
)
549 forward_escape
= true
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")
565 var w
= new_result
(v
)
570 # The single invocation witout fancy stuffs
571 private fun compile_call_to_c
(v
: I2CCompilerVisitor, args
: Array[String]): Writer is abstract
575 redef fun compile_call_to_c
(v
, args
)
579 if prop
.global
.is_init
then args
.add
("init_table")
580 w
.add
(prop
.global
.meth_call
)
584 w
.add_all
(args
, ", ")
591 redef fun compile_call_to_c
(v
, args
)
594 if prop
.global
.is_init
then args
.add
("init_table")
596 w
.add
(prop
.super_meth_call
)
600 w
.add_all
(args
, ", ")
607 redef fun compile_call_to_c
(v
, args
)
611 w
.add
(stype
.local_class
.to_s
)
613 w
.add
(property
.global
.intro
.cname
)
615 w
.add_all
(args
, ", ")
621 redef class IAllocateInstance
622 redef fun compile_to_c
(v
)
624 v
.add_location
(location
)
625 var w
= new_result
(v
)
627 w
.add
(stype
.local_class
.cname
)
632 redef class ICheckInstance
633 redef fun compile_to_c
(v
)
635 v
.add_location
(location
)
636 var w
= new_result
(v
)
638 w
.add
(stype
.local_class
.cname
)
640 w
.add
(v
.register
(expr
))
645 redef class IInitAttributes
646 redef fun compile_to_c
(v
)
648 v
.add_location
(location
)
650 w
.add
("INIT_ATTRIBUTES__")
651 w
.add
(stype
.local_class
.cname
)
653 w
.add
(v
.register
(expr
))
658 redef class IStaticCall
659 redef fun compile_call_to_c
(v
, args
)
662 if prop
.global
.is_init
then args
.add
("init_table")
664 w
.add
(property
.cname
)
666 w
.add_all
(args
, ", ")
673 redef fun compile_to_c
(v
)
675 v
.add_location
(location
)
676 if method
.is_intern
then
677 compile_intern_method_to_c
(v
)
679 compile_extern_method_to_c
(v
)
683 fun compile_extern_method_to_c
(v
: I2CCompilerVisitor)
685 var ename
= method
.extern_name
.as(not null)#"{method.module.name}_{method.local_class.name}_{method.local_class.name}_{method.name}_{method.signature.arity}"
686 var sig
= method
.signature
687 assert exprs
.length
== sig
.arity
+ 1
689 var regs
= v
.registers
(exprs
)
691 var args
= new Array[String]
692 args
.add
(sig
.recv
.unboxtype
(regs
[0]))
693 for i
in [0..sig
.arity
[ do
694 args
.add
(sig
[i
].unboxtype
(regs
[i
+1]))
696 var s
= "{ename}({args.join(", ")})"
698 if need_result
then s
= sig
.return_type
.boxtype
(s
)
699 var w
= new_result
(v
)
703 fun compile_intern_method_to_c
(v
: I2CCompilerVisitor)
705 var sig
= method
.signature
706 assert exprs
.length
== sig
.arity
+ 1
707 var c
= method
.local_class
.name
709 var regs
= v
.registers
(exprs
)
710 var s
: nullable String = null
711 if c
== once
"Int".to_symbol
then
712 if n
== once
"object_id".to_symbol
then
714 else if n
== once
"unary -".to_symbol
then
715 s
= "TAG_Int(-UNTAG_Int({regs[0]}))"
716 else if n
== once
"output".to_symbol
then
717 s
= "printf(\"%ld\\n\
", UNTAG_Int({regs[0]}));"
718 else if n
== once
"ascii".to_symbol
then
719 s
= "TAG_Char(UNTAG_Int({regs[0]}))"
720 else if n
== once
"succ".to_symbol
then
721 s
= "TAG_Int(UNTAG_Int({regs[0]})+1)"
722 else if n
== once
"prec".to_symbol
then
723 s
= "TAG_Int(UNTAG_Int({regs[0]})-1)"
724 else if n
== once
"to_f".to_symbol
then
725 s
= "BOX_Float((float)UNTAG_Int({regs[0]}))"
726 else if n
== once
"+".to_symbol
then
727 s
= "TAG_Int(UNTAG_Int({regs[0]})+UNTAG_Int({regs[1]}))"
728 else if n
== once
"-".to_symbol
then
729 s
= "TAG_Int(UNTAG_Int({regs[0]})-UNTAG_Int({regs[1]}))"
730 else if n
== once
"*".to_symbol
then
731 s
= "TAG_Int(UNTAG_Int({regs[0]})*UNTAG_Int({regs[1]}))"
732 else if n
== once
"/".to_symbol
then
733 s
= "TAG_Int(UNTAG_Int({regs[0]})/UNTAG_Int({regs[1]}))"
734 else if n
== once
"%".to_symbol
then
735 s
= "TAG_Int(UNTAG_Int({regs[0]})%UNTAG_Int({regs[1]}))"
736 else if n
== once
"<".to_symbol
then
737 s
= "TAG_Bool(UNTAG_Int({regs[0]})<UNTAG_Int({regs[1]}))"
738 else if n
== once
">".to_symbol
then
739 s
= "TAG_Bool(UNTAG_Int({regs[0]})>UNTAG_Int({regs[1]}))"
740 else if n
== once
"<=".to_symbol
then
741 s
= "TAG_Bool(UNTAG_Int({regs[0]})<=UNTAG_Int({regs[1]}))"
742 else if n
== once
">=".to_symbol
then
743 s
= "TAG_Bool(UNTAG_Int({regs[0]})>=UNTAG_Int({regs[1]}))"
744 else if n
== once
"lshift".to_symbol
then
745 s
= "TAG_Int(UNTAG_Int({regs[0]})<<UNTAG_Int({regs[1]}))"
746 else if n
== once
"rshift".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_Bool(({regs[0]})==({regs[1]}))"
750 else if n
== once
"!=".to_symbol
then
751 s
= "TAG_Bool(({regs[0]})!=({regs[1]}))"
753 else if c
== once
"Float".to_symbol
then
754 if n
== once
"object_id".to_symbol
then
755 s
= "TAG_Int((bigint)UNBOX_Float({regs[0]}))"
756 else if n
== once
"unary -".to_symbol
then
757 s
= "BOX_Float(-UNBOX_Float({regs[0]}))"
758 else if n
== once
"output".to_symbol
then
759 s
= "printf(\"%f\\n\
", UNBOX_Float({regs[0]}));"
760 else if n
== once
"to_i".to_symbol
then
761 s
= "TAG_Int((bigint)UNBOX_Float({regs[0]}))"
762 else if n
== once
"+".to_symbol
then
763 s
= "BOX_Float(UNBOX_Float({regs[0]})+UNBOX_Float({regs[1]}))"
764 else if n
== once
"-".to_symbol
then
765 s
= "BOX_Float(UNBOX_Float({regs[0]})-UNBOX_Float({regs[1]}))"
766 else if n
== once
"*".to_symbol
then
767 s
= "BOX_Float(UNBOX_Float({regs[0]})*UNBOX_Float({regs[1]}))"
768 else if n
== once
"/".to_symbol
then
769 s
= "BOX_Float(UNBOX_Float({regs[0]})/UNBOX_Float({regs[1]}))"
770 else if n
== once
"<".to_symbol
then
771 s
= "TAG_Bool(UNBOX_Float({regs[0]})<UNBOX_Float({regs[1]}))"
772 else if n
== once
">".to_symbol
then
773 s
= "TAG_Bool(UNBOX_Float({regs[0]})>UNBOX_Float({regs[1]}))"
774 else if n
== once
"<=".to_symbol
then
775 s
= "TAG_Bool(UNBOX_Float({regs[0]})<=UNBOX_Float({regs[1]}))"
776 else if n
== once
">=".to_symbol
then
777 s
= "TAG_Bool(UNBOX_Float({regs[0]})>=UNBOX_Float({regs[1]}))"
779 else if c
== once
"Char".to_symbol
then
780 if n
== once
"object_id".to_symbol
then
781 s
= "TAG_Int(UNTAG_Char({regs[0]}))"
782 else if n
== once
"unary -".to_symbol
then
783 s
= "TAG_Char(-UNTAG_Char({regs[0]}))"
784 else if n
== once
"output".to_symbol
then
785 s
= "printf(\"%c\
", (unsigned char)UNTAG_Char({regs[0]}));"
786 else if n
== once
"ascii".to_symbol
then
787 s
= "TAG_Int((unsigned char)UNTAG_Char({regs[0]}))"
788 else if n
== once
"succ".to_symbol
then
789 s
= "TAG_Char(UNTAG_Char({regs[0]})+1)"
790 else if n
== once
"prec".to_symbol
then
791 s
= "TAG_Char(UNTAG_Char({regs[0]})-1)"
792 else if n
== once
"to_i".to_symbol
then
793 s
= "TAG_Int(UNTAG_Char({regs[0]})-'0')"
794 else if n
== once
"+".to_symbol
then
795 s
= "TAG_Char(UNTAG_Char({regs[0]})+UNTAG_Char({regs[1]}))"
796 else if n
== once
"-".to_symbol
then
797 s
= "TAG_Char(UNTAG_Char({regs[0]})-UNTAG_Char({regs[1]}))"
798 else if n
== once
"*".to_symbol
then
799 s
= "TAG_Char(UNTAG_Char({regs[0]})*UNTAG_Char({regs[1]}))"
800 else if n
== once
"/".to_symbol
then
801 s
= "TAG_Char(UNTAG_Char({regs[0]})/UNTAG_Char({regs[1]}))"
802 else if n
== once
"%".to_symbol
then
803 s
= "TAG_Char(UNTAG_Char({regs[0]})%UNTAG_Char({regs[1]}))"
804 else if n
== once
"<".to_symbol
then
805 s
= "TAG_Bool(UNTAG_Char({regs[0]})<UNTAG_Char({regs[1]}))"
806 else if n
== once
">".to_symbol
then
807 s
= "TAG_Bool(UNTAG_Char({regs[0]})>UNTAG_Char({regs[1]}))"
808 else if n
== once
"<=".to_symbol
then
809 s
= "TAG_Bool(UNTAG_Char({regs[0]})<=UNTAG_Char({regs[1]}))"
810 else if n
== once
">=".to_symbol
then
811 s
= "TAG_Bool(UNTAG_Char({regs[0]})>=UNTAG_Char({regs[1]}))"
812 else if n
== once
"==".to_symbol
then
813 s
= "TAG_Bool(({regs[0]})==({regs[1]}))"
814 else if n
== once
"!=".to_symbol
then
815 s
= "TAG_Bool(({regs[0]})!=({regs[1]}))"
817 else if c
== once
"Bool".to_symbol
then
818 if n
== once
"object_id".to_symbol
then
819 s
= "TAG_Int(UNTAG_Bool({regs[0]}))"
820 else if n
== once
"unary -".to_symbol
then
821 s
= "TAG_Bool(-UNTAG_Bool({regs[0]}))"
822 else if n
== once
"output".to_symbol
then
823 s
= "(void)printf(UNTAG_Bool({regs[0]})?\"true\\n\
":\"false\\n\
");"
824 else if n
== once
"ascii".to_symbol
then
825 s
= "TAG_Bool(UNTAG_Bool({regs[0]}))"
826 else if n
== once
"to_i".to_symbol
then
827 s
= "TAG_Int(UNTAG_Bool({regs[0]}))"
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]}))"
833 else if c
== once
"NativeArray".to_symbol
then
834 if n
== once
"object_id".to_symbol
then
835 s
= "TAG_Int(((Nit_NativeArray){regs[0]})->object_id)"
836 else if n
== once
"[]".to_symbol
then
837 s
= "((Nit_NativeArray){regs[0]})->val[UNTAG_Int({regs[1]})]"
838 else if n
== once
"[]=".to_symbol
then
839 s
= "((Nit_NativeArray){regs[0]})->val[UNTAG_Int({regs[1]})]={regs[2]}"
840 else if n
== once
"copy_to".to_symbol
then
841 s
= "(void)memcpy(((Nit_NativeArray ){regs[1]})->val, ((Nit_NativeArray){regs[0]})->val, UNTAG_Int({regs[2]})*sizeof(val_t))"
843 else if c
== once
"NativeString".to_symbol
then
844 if n
== once
"object_id".to_symbol
then
845 s
= "TAG_Int(UNBOX_NativeString({regs[0]}))"
846 else if n
== once
"atoi".to_symbol
then
847 s
= "TAG_Int(atoi(UNBOX_NativeString({regs[0]})))"
848 else if n
== once
"[]".to_symbol
then
849 s
= "TAG_Char(UNBOX_NativeString({regs[0]})[UNTAG_Int({regs[1]})])"
850 else if n
== once
"[]=".to_symbol
then
851 s
= "UNBOX_NativeString({regs[0]})[UNTAG_Int({regs[1]})]=UNTAG_Char({regs[2]});"
852 else if n
== once
"copy_to".to_symbol
then
853 s
= "(void)memcpy(UNBOX_NativeString({regs[1]})+UNTAG_Int({regs[4]}), UNBOX_NativeString({regs[0]})+UNTAG_Int({regs[3]}), UNTAG_Int({regs[2]}));"
855 else if n
== once
"object_id".to_symbol
then
856 s
= "TAG_Int((bigint)((obj_t){regs[0]})[1].object_id)"
857 else if n
== once
"sys".to_symbol
then
859 else if n
== once
"is_same_type".to_symbol
then
860 s
= "TAG_Bool((VAL2VFT({regs[0]})==VAL2VFT({regs[1]})))"
861 else if n
== once
"exit".to_symbol
then
862 s
= "exit(UNTAG_Int({regs[1]}));"
863 else if n
== once
"calloc_array".to_symbol
then
864 s
= "NEW_NativeArray(UNTAG_Int({regs[1]}), sizeof(val_t))"
865 else if n
== once
"calloc_string".to_symbol
then
866 s
= "BOX_NativeString((char*)raw_alloc((UNTAG_Int({regs[1]}) * sizeof(char))))"
870 if ll
!= null then v
.add_instr
("fprintf(stderr, \"{ll.to_s}: \
");")
871 v
.add_instr
("fprintf(stderr, \"Fatal error
: unknown
intern method
{method.full_name}.\\n\
");")
872 v
.add_instr
("nit_exit(1);")
875 if result
== null then
876 v
.new_instr
.add
(s
).add
(";\n")
877 else if need_result
then
878 var w
= new_result
(v
)
884 redef class IIntValue
885 redef fun compile_to_c
(v
)
887 v
.add_location
(location
)
888 var w
= new_result
(v
)
889 w
.add
("TAG_Int(").add
(value
.to_s
).add
(")")
893 redef class IBoolValue
894 redef fun compile_to_c
(v
)
896 v
.add_location
(location
)
897 var w
= new_result
(v
)
899 if value
then w
.add
("true") else w
.add
("false")
904 redef class ICharValue
905 redef fun compile_to_c
(v
)
907 v
.add_location
(location
)
908 var w
= new_result
(v
)
909 w
.add
("TAG_Char(").add
(value
).add
(")")
913 redef class IFloatValue
914 redef fun compile_to_c
(v
)
916 v
.add_location
(location
)
917 var w
= new_result
(v
)
918 w
.add
("BOX_Float(").add
(value
).add
(")")
922 redef class IStringValue
923 redef fun compile_to_c
(v
)
925 v
.add_location
(location
)
926 var w
= new_result
(v
)
927 w
.add
("BOX_NativeString(\"").add(value).add("\
")")
932 redef fun compile_to_c
(v
)
934 v
.add_location
(location
)
936 w
.add
("nit_abort(\"")
938 if texts.length > 1 then
946 w.add(module_location.cname)
950 w.add(ll.line_start.to_s)
959 redef fun compile_to_c(v)
961 if not need_result then return
962 var e = v.register(expr)
963 var r = v.register(result.as(not null))
964 if e == r then return
965 v.add_location(location)
974 redef class IAttrRead
975 redef fun compile_to_c(v)
977 if not need_result then return
978 v.add_location(location)
979 var w = new_result(v)
980 w.add(property.global.attr_access)
982 w.add(v.register(expr))
987 redef class IAttrIsset
988 redef fun compile_to_c(v)
990 if not need_result then return
991 v.add_location(location)
992 var w = new_result(v)
994 w.add(property.global.attr_access)
996 w.add(v.register(expr))
997 w.add(")!=NIT_NULL)")
1001 redef class IAttrWrite
1002 redef fun compile_to_c(v)
1004 v.add_location(location)
1006 w.add(property.global.attr_access)
1008 w.add(v.register(expr1))
1010 w.add(v.register(expr2))
1015 redef class ITypeCheck
1016 redef fun compile_to_c(v)
1018 if not need_result then return
1019 # FIXME handle formaltypes
1020 v.add_location(location)
1021 var g = stype.local_class.global
1022 var recv = v.register(expr)
1023 var w = new_result(v)
1025 if expr.stype.is_nullable then
1026 if stype.is_nullable then
1029 w.add("==NIT_NULL) || ")
1030 else if stype.as_nullable == expr.stype then
1032 w.add("!=NIT_NULL)")
1037 w.add("!=NIT_NULL) && ")
1053 redef fun compile_to_c(v)
1055 if not need_result then return
1056 v.add_location(location)
1057 var w = new_result(v)
1059 var t1 = expr1.stype
1060 var t2 = expr2.stype
1061 if t1 isa MMTypeNone then
1062 if t2 isa MMTypeNone then
1065 else if t2.is_nullable then
1066 w.add(v.register(expr2))
1067 w.add("==NIT_NULL)")
1073 else if t1.is_nullable then
1074 if t2 isa MMTypeNone then
1075 w.add(v.register(expr1))
1076 w.add("==NIT_NULL)")
1078 else if t2.is_nullable then
1079 w.add("IS_EQUAL_NN(")
1081 w.add("IS_EQUAL_ON(")
1082 w.add(v.register(expr2))
1084 w.add(v.register(expr1))
1089 if t2 isa MMTypeNone then
1092 else if t2.is_nullable then
1093 w.add("IS_EQUAL_ON(")
1095 w.add("IS_EQUAL_OO(")
1098 w.add(v.register(expr1))
1100 w.add(v.register(expr2))
1106 redef fun compile_to_c(v)
1108 if not need_result then return
1109 v.add_location(location)
1110 var w = new_result(v)
1111 w.add("TAG_Bool(!UNTAG_Bool(")
1112 w.add(v.register(expr))
1118 redef fun compile_to_c(v)
1120 v.add_location(location)
1121 var i = v.new_number
1122 var res = result.as(not null)
1123 if res.stype.is_nullable then
1124 v.add_decl("static val_t once_value_
{i}; static int once_bool_
{i}; /* Once value
*/")
1125 v.add_instr("if (!once_bool_
{i}) \
{")
1127 # Since the value is not nullable, we use the null value to represent the boolean
1128 v.add_decl("static val_t once_value_
{i}; /* Once value
*/")
1129 v.add_instr("if (!once_value_
{i}) \
{")
1132 body.compile_to_c(v)
1133 var e = v.register(res)
1134 v.add_instr("once_value_
{i} = {e};")
1135 v.add_instr("register_static_object
(&once_value_
{i});")
1136 if res.stype.is_nullable then v.add_instr("once_bool_
{i} = true;")
1138 v.add_instr("\
} else {e} = once_value_
{i};")
1139 var w = new_result(v)
1144 redef class IClosCall
1145 redef fun compile_to_c(v: I2CCompilerVisitor)
1147 v.add_location(location)
1149 var args: Array[String]
1151 ivar = "closctx-
>closure_funs
[{v.closures[closure_decl]}]"
1152 args = ["closctx-
>closure_ctx
"]
1154 ivar = "CREG[{v.closures[closure_decl]}]"
1155 args = ["closctx_param
"]
1157 args.append(v.registers(exprs))
1159 var s = "(({v.clostypes[closure_decl]})({ivar}))({args.join(", ")})"
1165 v.add_instr("if ({args.first}->has_broke
) \
{")
1171 v.add_goto(v.iroutine.body)
1177 redef class IHasClos
1178 redef fun compile_to_c(v)
1180 if not need_result then return
1181 v.add_location(location)
1182 var w = new_result(v)
1185 w.add("closctx-
>closure_funs
[")
1186 w.add(v.closures[closure_decl])
1190 w.add(v.closures[closure_decl])
1197 redef class IClosureDef
1198 # Compile the closure as a separate C function in the visitor out_contexts.
1199 # Return a fun_t pointer to the function.
1200 fun compile_closure(v: I2CCompilerVisitor): String
1204 # We are now in a closure
1205 var cfc_old = v.closure
1208 # We are now in a escape boundary
1209 var lls_old = v.local_labels
1210 v.local_labels = new HashSet[ISeq]
1212 # We are now in a new C context
1213 var decl_writer_old = cv.decl_writer
1214 var writer_old = cv.writer
1215 cv.writer = cv.top_writer.sub
1216 cv.decl_writer = cv.header_writer.sub
1218 # Generate the C function
1219 var cname = "OC_{v.basecname}_
{v.new_number}"
1220 var args = compile_signature_to_c(v.visitor, cname, null, "struct stack_frame_t
*closctx
", null)
1221 cv.decl_writer = cv.writer.sub
1223 var s = compile_inside_to_c(v, args)
1225 v.add_instr("return;")
1227 v.add_instr("return {s};")
1233 cv.writer = writer_old
1234 cv.decl_writer = decl_writer_old
1236 v.local_labels = lls_old
1237 return "((fun_t
){cname})"