# limitations under the License.
# Generate C code from intermediate code representation
-package compiling_icode
+module compiling_icode
import icode
private import analysis
+import primitive_info
import compiling_base
# Compiler context from ICode to C
if not strs.has_key(i) then strs[i] = "REGB{i}"
else if closure and not e.is_local then
strs = once new HashMap[Int, String]
- if not strs.has_key(i) then strs[i] = "closctx->variable[{i}]"
+ if not strs.has_key(i) then strs[i] = "closctx->REG[{i}]"
else
strs = once new HashMap[Int, String]
- if not strs.has_key(i) then strs[i] = "REG[{i}]"
+ if not strs.has_key(i) then strs[i] = "fra.me.REG[{i}]"
end
s = strs[i]
ids[e] = s
end
# The rank (number) of each closure
- readable var _closures: HashMap[IClosureDecl, Int] = new HashMap[IClosureDecl, Int]
+ readable var _closures: HashMap[IClosureDecl, String] = new HashMap[IClosureDecl, String]
# The functionnal type of each closure
readable var _clostypes: HashMap[IClosureDecl, String] = new HashMap[IClosureDecl, String]
else
assert closure
var ind = register_escape_label(seq)
- add_instr("closctx->has_broke = (val_t*){ind};")
+ add_instr("closctx->has_broke = {ind};")
add_instr("goto {lab(return_label.as(not null))};")
end
end
+ # Association between IEscapeMarks and visited ISeq
+ readable var _marks_to_seq: Map[IEscapeMark, ISeq] = new HashMap[IEscapeMark, ISeq]
+
# Are we in a closure ?
readable writable var _closure: Bool = false
visitor.add_decl(s)
end
- fun add_instr(s: String)
+ # Prepare a new instuction (indent, comment)
+ # Caller must ensure to add a new line to finish its instr
+ fun new_instr: Writer
do
+ var w = visitor.writer
var l = _next_location
if l != null then
- visitor.add_instr("/* ", l.file, ":", l.line_start.to_s, " */")
+ visitor.add_indent(w)
+ w.add("/* ")
+ w.add(l.file.filename)
+ w.add(":")
+ w.add(l.line_start.to_s)
+ w.add(" */\n")
_next_location = null
end
- visitor.add_instr(s)
+ visitor.add_indent(w)
+ return w
+ end
+
+ fun add_instr(s: String)
+ do
+ new_instr.add(s).add("\n")
end
fun indent
cparams.add("val_t p{i}")
end
if closure_decls != null then
+ cparams.add("struct stack_frame_t *closctx_param")
for i in [0..closure_decls.length[ do
var closcn = "CLOS_{cname}_{i}"
var cs = closure_decls[i].closure.signature
var subparams = new Array[String] # Parameters of the closure
- subparams.add("struct WBT_ *")
+ subparams.add("struct stack_frame_t *")
for j in [0..cs.arity[ do
subparams.add("val_t")
end
var rr = "void"
if cs.return_type != null then rr = "val_t"
v.add_decl("typedef {rr} (*{closcn})({subparams.join(", ")});")
- cargs.add("wd{i}")
- cparams.add("struct WBT_ *wd{i}")
+ cargs.add("clos_fun{i}")
+ cparams.add("fun_t clos_fun{i}")
end
end
if after_params != null then cparams.add(after_params)
else
p = cparams.join(", ")
end
- if human_name != null then v.add_decl("#define LOCATE_", cname, " \"", human_name, "\"")
- v.add_decl(r, " ", cname, "(", p, ");")
- v.add_decl("typedef ", r, " (*", cname, "_t)(", p, ");")
- v.add_instr(r, " ", cname, "(", p, ")\{")
+ if human_name != null then
+ v.add_instr("static const char LOCATE_{cname}[] = \"{human_name}\";")
+ end
+ v.add_decl("{r} {cname}({p});")
+ v.add_decl("typedef {r} (*{cname}_t)({p});")
+ v.add_instr("{r} {cname}({p})\{")
v.indent
return cargs
end
# Compile the body of the routine, return the result value is any
fun compile_inside_to_c(v: I2CCompilerVisitor, args: Array[String]): nullable String
do
- # Add the trace
+ # Create and push the stack frame
var ll = 0
if location != null then
ll = location.line_start
end
- v.add_decl("struct trace_t trace = \{NULL, NULL, {ll}, LOCATE_{v.basecname}\};")
- v.add_instr("trace.prev = tracehead; tracehead = &trace;")
- v.add_instr("trace.file = LOCATE_{v.visitor.module.name};")
-
- # Add local variables
- if std_slots_nb == 0 then
- v.add_decl("val_t *REG = NULL;")
+ # Encapsulate the frame ('me') in a larger structure ('fra') that has enough space to store the local variables (REG)
+ if std_slots_nb > 1 then
+ v.add_decl("struct \{struct stack_frame_t me; val_t MORE_REG[{std_slots_nb-1}];\} fra;")
else
- v.add_decl("val_t REG[{std_slots_nb}];")
+ v.add_decl("struct \{struct stack_frame_t me;\} fra;")
+ end
+ v.add_instr("fra.me.prev = stack_frame_head; stack_frame_head = &fra.me;")
+ v.add_instr("fra.me.file = LOCATE_{v.visitor.mmmodule.cname};")
+ v.add_instr("fra.me.line = {ll};")
+ v.add_instr("fra.me.meth = LOCATE_{v.basecname};")
+ v.add_instr("fra.me.has_broke = 0;")
+ v.add_instr("fra.me.REG_size = {std_slots_nb};")
+ v.add_instr("fra.me.nitni_local_ref_head = NULL;")
+
+ # Declare/initialize local variables
+ for i in [0..std_slots_nb[ do
+ v.add_instr("fra.me.REG[{i}] = NIT_NULL;")
end
for i in [0..tag_slots_nb[ do
v.add_decl("val_t REGB{i};")
end
var iclosdecls = closure_decls
if iclosdecls != null then
- v.add_decl("struct WBT_ *CREG[{iclosdecls.length}];")
- else
- v.add_decl("struct WBT_ **CREG = NULL;")
+ v.add_decl("fun_t CREG[{iclosdecls.length}];")
+ v.add_instr("fra.me.closure_ctx = closctx_param;")
+ v.add_instr("fra.me.closure_funs = CREG;")
end
var k = 0
for r in params do
for i in [0..iclosdecls.length[ do
var iclosdecl = iclosdecls[i]
v.add_instr("CREG[{i}] = {args[params.length+i]};")
- v.closures[iclosdecl] = i
+ v.closures[iclosdecl] = i.to_s
var cs = iclosdecl.closure.signature # Closure signature
var subparams = new Array[String] # Parameters of the closure
- subparams.add("struct WBT_ *")
+ subparams.add("struct stack_frame_t *")
for j in [0..cs.arity[ do
var p = "val_t"
subparams.add(p)
# Compile body
body.compile_to_c(v)
- v.add_instr("tracehead = trace.prev;")
+ v.add_instr("stack_frame_head = fra.me.prev;")
v.return_label = old_rl
var r = result
if r != null then
end
# Full compilation of the routine
- # Including optimization and other stuff.
# cv must be in the correct function
fun compile_to_c(cv: CompilerVisitor, cname: String, args: Array[String]): nullable String
do
- optimize(cv.module)
var v = new I2CCompilerVisitor(cv, self, cname)
return compile_inside_to_c(v, args)
end
redef class ICode
# Full compilation of the icode
- fun compile_to_c(v: I2CCompilerVisitor)
- do
- v.add_location(location)
- store_result(v, inner_compile_to_c(v))
- end
+ fun compile_to_c(v: I2CCompilerVisitor) is abstract
# Is a result really needed
private fun need_result: Bool
end
# Store s in the result value of self
- private fun store_result(v: I2CCompilerVisitor, s: nullable String)
+ private fun store_result(v: I2CCompilerVisitor, w: nullable Writer)
do
var r = result
if r != null and r.slot_index != null then
- assert s != null
- v.add_assignment(v.register(r), s)
- else if s != null and not is_pure then
+ assert w != null
+ var w2 = v.new_instr
+ w2.add(v.register(r))
+ w2.add(" = ")
+ w2.append(w)
+ w2.add(";\n")
+ else if w != null and not is_pure then
# ICode with side effects must be evaluated
# even if the result is not wanted
- v.add_instr(s + ";")
+ var w2 = v.new_instr
+ w2.append(w)
+ w2.add(";\n")
end
end
- # Compilation of without the result assigment
- # Return the right value is case of expression
- # Return the full expression (witout ;) in case of statement
- private fun inner_compile_to_c(v: I2CCompilerVisitor): nullable String is abstract
+ # Prepare a writer if the expression icode need to be compiled
+ # * Result assigment is automatic if needed
+ private fun new_result(v: I2CCompilerVisitor): Writer
+ do
+ assert need_result or not is_pure
+ var w2 = v.new_instr
+ var r = result
+ if r != null and r.slot_index != null then
+ w2.add(v.register(r))
+ w2.add(" = ")
+ end
+ var w = w2.sub
+ w2.add(";\n")
+ return w
+ end
end
redef class ISeq
- redef fun inner_compile_to_c(v)
+ redef fun compile_to_c(v)
do
+ v.add_location(location)
v.local_labels.add(self)
+ var mark = iescape_mark
+ if mark != null then v.marks_to_seq[mark] = self
for ic in icodes do
ic.compile_to_c(v)
end
v.add_label(self)
- return null
end
end
redef class IIf
- redef fun inner_compile_to_c(v)
+ redef fun compile_to_c(v)
do
- v.add_instr("if (UNTAG_Bool({v.register(expr)})) \{")
+ v.add_location(location)
+ var w = v.new_instr
+ w.add("if (UNTAG_Bool(")
+ w.add(v.register(expr))
+ w.add(")) \{\n")
if not then_seq.icodes.is_empty then
v.indent
- then_seq.inner_compile_to_c(v)
+ then_seq.compile_to_c(v)
v.unindent
end
if not else_seq.icodes.is_empty then
- v.add_instr("} else \{")
+ v.add_instr("\} else \{")
v.indent
- else_seq.inner_compile_to_c(v)
+ else_seq.compile_to_c(v)
v.unindent
end
- v.add_instr("}")
- return null
+ v.add_instr("\}")
end
end
redef class ILoop
- redef fun inner_compile_to_c(v)
+ redef fun compile_to_c(v)
do
+ v.add_location(location)
v.local_labels.add(self)
+ var mark = iescape_mark
+ if mark != null then v.marks_to_seq[mark] = self
v.add_instr("while(1) \{")
v.indent
for ic in icodes do
ic.compile_to_c(v)
end
v.unindent
- v.add_instr("}")
+ v.add_instr("\}")
v.add_label(self)
- return null
end
end
redef class IEscape
- redef fun inner_compile_to_c(v)
+ redef fun compile_to_c(v)
do
- v.add_goto(seq)
- return null
+ v.add_location(location)
+ v.add_goto(v.marks_to_seq[iescape_mark])
end
end
# Compile closure definitions
var old_el = v.escaped_labels
var closdefs = closure_defs
- var closcns: nullable Array[String] = null
+ var closctx: nullable String = null # The closure context of closdefs
if closdefs != null then
+ # Get the closure context
+ if v.closure then
+ closctx = "closctx"
+ else
+ closctx = "(&(fra.me))"
+ end
+
+ # First aditionnal arguments is the closure context
+ args.add(closctx)
+
+ # We are in a new escape boundary
v.escaped_labels = new HashMap[ISeq, Int]
- closcns = new Array[String]
+
+ # Compile each closures and add each sub-function as an other additionnal parameter
for cd in closdefs do
if cd != null then
var cn = cd.compile_closure(v)
args.add(cn)
- closcns.add(cn)
else
args.add("NULL")
end
end
end
- var s = compile_call_to_c(v, args)
- var r: nullable String = s
+ # Compile the real call
+ var call = compile_call_to_c(v, args)
+ var res: nullable Writer = call
# Intercept escapes
- if closcns != null then
+ if closctx != null then
var els = v.escaped_labels
v.escaped_labels = old_el
# Is there possible escapes?
if not els.is_empty then
# Call in a tmp variable to avoid 'break' overwrite
+ var w = v.new_instr
if need_result then
- r = "tmp"
- v.add_assignment(r, s)
+ w.add("tmp")
+ w.add(" = ")
+ w.append(call)
+ w.add(";\n")
+ res = new Writer
+ res.add("tmp")
else
- r = null
- v.add_instr(s + ";")
- end
- # What is the escape index (if any?)
- # It's computed as the union of has_broke
- var switcha = new Array[String]
- for cn in closcns do
- switcha.add("((int)({cn}->has_broke))")
+ res = null
+ w.append(call)
+ w.add(";\n")
end
- var switch = switcha.join(" | ")
# What are the expected escape indexes
- v.add_instr("switch ({switch}) \{")
+ v.new_instr.add("switch (").add(closctx).add("->has_broke) \{\n")
v.indent
# No escape occured, continue as usual
v.add_instr("case 0: break;")
var seq = iels.key
if lls.has(seq) then
# Local escape occured
- v.add_instr("case {iels.item}: goto {v.lab(seq)};")
+ # Clear the has_broke information and go to the target
+ v.new_instr.add("case ").add(iels.item.to_s).add(": ").add(closctx).add("->has_broke = 0; goto ").add(v.lab(seq)).add(";\n")
else
# Forward escape occured: register the escape label
assert v.closure
end
iels.next
end
- # Forward escape occured, just pass to the next one
+ # If forward escape occured, just pass to the next one
if forward_escape then
- v.add_instr("default: closctx->has_broke = (val_t*)({switch}); goto {v.lab(v.return_label.as(not null))};")
+ # Do not need to copy 'has_broke' value since it is shared by the next one.
+ # So just exit the C function.
+ v.new_instr.add("default: goto ").add(v.lab(v.return_label.as(not null))).add(";\n")
end
v.unindent
v.add_instr("\}")
end
end
- store_result(v, r)
+ if res != null then
+ var w = new_result(v)
+ w.append(res)
+ end
end
- redef fun inner_compile_to_c(v) do abort
-
# The single invocation witout fancy stuffs
- private fun compile_call_to_c(v: I2CCompilerVisitor, args: Array[String]): String is abstract
+ private fun compile_call_to_c(v: I2CCompilerVisitor, args: Array[String]): Writer is abstract
end
redef class ICall
redef fun compile_call_to_c(v, args)
do
+ var w = new Writer
+
+ # do not compile explicit calls from native methods
+ # theses are really manually called in the native implementation
+ if is_explicit_from_extern then return w
+
var prop = property
if prop.global.is_init then args.add("init_table")
- if prop.name == (once ("add".to_symbol)) and prop.local_class.name == (once ("Array".to_symbol)) then
- return "{prop.cname}({args.join(", ")})"
- else
- return "{prop.global.meth_call}({args[0]})({args.join(", ")})"
- end
+ w.add(prop.global.meth_call)
+ w.add("(")
+ w.add(args.first)
+ w.add(")(")
+ w.add_all(args, ", ")
+ w.add(")")
+ return w
end
end
redef class ISuper
redef fun compile_call_to_c(v, args)
do
+ # do not compile explicit calls from native methods
+ # theses are really manually called in the native implementation
+ if is_explicit_from_extern then return new Writer
+
var prop = property
if prop.global.is_init then args.add("init_table")
- return "{prop.super_meth_call}({args[0]})({args.join(", ")})"
+ var w = new Writer
+ w.add(prop.super_meth_call)
+ w.add("(")
+ w.add(args.first)
+ w.add(")(")
+ w.add_all(args, ", ")
+ w.add(")")
+ return w
end
end
redef class INew
redef fun compile_call_to_c(v, args)
do
- return "NEW_{stype.local_class}_{property.global.intro.cname}({args.join(", ")})"
+ var w = new Writer
+
+ # do not compile explicit calls from native methods
+ # theses are really manually called in the native implementation
+ if is_explicit_from_extern then return w
+
+ w.add("NEW_")
+ w.add(stype.local_class.to_s)
+ w.add("_")
+ w.add(property.global.intro.cname)
+ w.add("(")
+ w.add_all(args, ", ")
+ w.add(")")
+ return w
+ end
+end
+
+redef class IAllocateInstance
+ redef fun compile_to_c(v)
+ do
+ v.add_location(location)
+ var w = new_result(v)
+ w.add("NEW_")
+ w.add(stype.local_class.cname)
+ w.add("()")
+ end
+end
+
+redef class ICheckInstance
+ redef fun compile_to_c(v)
+ do
+ v.add_location(location)
+ var w = new_result(v)
+ w.add("CHECKNEW_")
+ w.add(stype.local_class.cname)
+ w.add("(")
+ w.add(v.register(expr))
+ w.add(")")
+ end
+end
+
+redef class IInitAttributes
+ redef fun compile_to_c(v)
+ do
+ v.add_location(location)
+ var w = v.new_instr
+ w.add("INIT_ATTRIBUTES__")
+ w.add(stype.local_class.cname)
+ w.add("(")
+ w.add(v.register(expr))
+ w.add(");\n")
+ end
+end
+
+redef class IStaticCall
+ redef fun compile_call_to_c(v, args)
+ do
+ var prop = property
+ if prop.global.is_init then args.add("init_table")
+ var w = new Writer
+ w.add(property.cname)
+ w.add("(")
+ w.add_all(args, ", ")
+ w.add(")")
+ return w
end
end
redef class INative
- redef fun inner_compile_to_c(v)
+ redef fun compile_to_c(v)
do
- if exprs.is_empty then
- return code
- else
- var res = new Buffer
- var i = 0
- var c = code.split_with("@@@")
- for s in c do
- res.append(s)
- if i < exprs.length and i < c.length-1 then
- res.append(v.register(exprs[i]))
- end
- i += 1
+ v.add_location(location)
+ if method.is_intern then
+ compile_intern_method_to_c(v)
+ else if not method.global.is_init then
+ compile_extern_method_to_c(v)
+ end
+ end
+
+ fun compile_extern_method_to_c(v: I2CCompilerVisitor)
+ do
+ var ename = "{method.friendly_extern_name(method.local_class)}___out"
+
+ var sig = method.signature
+ assert exprs.length == sig.arity + 1
+
+ var regs = v.registers(exprs)
+
+ var args = new Array[String]
+ args.add(regs[0])
+ for i in [0..sig.arity[ do
+ args.add(regs[i+1])
+ end
+ var s = "{ename}({args.join(", ")})"
+
+ if need_result then s = s # sig.return_type.boxtype(s)
+ var w = new_result(v)
+ w.add(s)
+ end
+
+ fun compile_intern_method_to_c(v: I2CCompilerVisitor)
+ do
+ var sig = method.signature
+ assert exprs.length == sig.arity + 1
+ var c = method.local_class.name
+ var n = method.name
+ var regs = v.registers(exprs)
+ var s: nullable String = null
+ if c == once "Int".to_symbol then
+ if n == once "object_id".to_symbol then
+ s = regs[0]
+ else if n == once "unary -".to_symbol then
+ s = "TAG_Int(-UNTAG_Int({regs[0]}))"
+ else if n == once "output".to_symbol then
+ s = "printf(\"%ld\\n\", UNTAG_Int({regs[0]}));"
+ else if n == once "ascii".to_symbol then
+ s = "TAG_Char(UNTAG_Int({regs[0]}))"
+ else if n == once "succ".to_symbol then
+ s = "TAG_Int(UNTAG_Int({regs[0]})+1)"
+ else if n == once "prec".to_symbol then
+ s = "TAG_Int(UNTAG_Int({regs[0]})-1)"
+ else if n == once "to_f".to_symbol then
+ s = "BOX_Float((float)UNTAG_Int({regs[0]}))"
+ else if n == once "+".to_symbol then
+ s = "TAG_Int(UNTAG_Int({regs[0]})+UNTAG_Int({regs[1]}))"
+ else if n == once "-".to_symbol then
+ s = "TAG_Int(UNTAG_Int({regs[0]})-UNTAG_Int({regs[1]}))"
+ else if n == once "*".to_symbol then
+ s = "TAG_Int(UNTAG_Int({regs[0]})*UNTAG_Int({regs[1]}))"
+ else if n == once "/".to_symbol then
+ s = "TAG_Int(UNTAG_Int({regs[0]})/UNTAG_Int({regs[1]}))"
+ else if n == once "%".to_symbol then
+ s = "TAG_Int(UNTAG_Int({regs[0]})%UNTAG_Int({regs[1]}))"
+ else if n == once "<".to_symbol then
+ s = "TAG_Bool(UNTAG_Int({regs[0]})<UNTAG_Int({regs[1]}))"
+ else if n == once ">".to_symbol then
+ s = "TAG_Bool(UNTAG_Int({regs[0]})>UNTAG_Int({regs[1]}))"
+ else if n == once "<=".to_symbol then
+ s = "TAG_Bool(UNTAG_Int({regs[0]})<=UNTAG_Int({regs[1]}))"
+ else if n == once ">=".to_symbol then
+ s = "TAG_Bool(UNTAG_Int({regs[0]})>=UNTAG_Int({regs[1]}))"
+ else if n == once "lshift".to_symbol then
+ s = "TAG_Int(UNTAG_Int({regs[0]})<<UNTAG_Int({regs[1]}))"
+ else if n == once "rshift".to_symbol then
+ s = "TAG_Int(UNTAG_Int({regs[0]})>>UNTAG_Int({regs[1]}))"
+ else if n == once "==".to_symbol then
+ s = "TAG_Bool(({regs[0]})==({regs[1]}))"
+ else if n == once "!=".to_symbol then
+ s = "TAG_Bool(({regs[0]})!=({regs[1]}))"
+ end
+ else if c == once "Float".to_symbol then
+ if n == once "object_id".to_symbol then
+ s = "TAG_Int((bigint)UNBOX_Float({regs[0]}))"
+ else if n == once "unary -".to_symbol then
+ s = "BOX_Float(-UNBOX_Float({regs[0]}))"
+ else if n == once "output".to_symbol then
+ s = "printf(\"%f\\n\", UNBOX_Float({regs[0]}));"
+ else if n == once "to_i".to_symbol then
+ s = "TAG_Int((bigint)UNBOX_Float({regs[0]}))"
+ else if n == once "+".to_symbol then
+ s = "BOX_Float(UNBOX_Float({regs[0]})+UNBOX_Float({regs[1]}))"
+ else if n == once "-".to_symbol then
+ s = "BOX_Float(UNBOX_Float({regs[0]})-UNBOX_Float({regs[1]}))"
+ else if n == once "*".to_symbol then
+ s = "BOX_Float(UNBOX_Float({regs[0]})*UNBOX_Float({regs[1]}))"
+ else if n == once "/".to_symbol then
+ s = "BOX_Float(UNBOX_Float({regs[0]})/UNBOX_Float({regs[1]}))"
+ else if n == once "<".to_symbol then
+ s = "TAG_Bool(UNBOX_Float({regs[0]})<UNBOX_Float({regs[1]}))"
+ else if n == once ">".to_symbol then
+ s = "TAG_Bool(UNBOX_Float({regs[0]})>UNBOX_Float({regs[1]}))"
+ else if n == once "<=".to_symbol then
+ s = "TAG_Bool(UNBOX_Float({regs[0]})<=UNBOX_Float({regs[1]}))"
+ else if n == once ">=".to_symbol then
+ s = "TAG_Bool(UNBOX_Float({regs[0]})>=UNBOX_Float({regs[1]}))"
+ end
+ else if c == once "Char".to_symbol then
+ if n == once "object_id".to_symbol then
+ s = "TAG_Int(UNTAG_Char({regs[0]}))"
+ else if n == once "unary -".to_symbol then
+ s = "TAG_Char(-UNTAG_Char({regs[0]}))"
+ else if n == once "output".to_symbol then
+ s = "printf(\"%c\", (unsigned char)UNTAG_Char({regs[0]}));"
+ else if n == once "ascii".to_symbol then
+ s = "TAG_Int((unsigned char)UNTAG_Char({regs[0]}))"
+ else if n == once "succ".to_symbol then
+ s = "TAG_Char(UNTAG_Char({regs[0]})+1)"
+ else if n == once "prec".to_symbol then
+ s = "TAG_Char(UNTAG_Char({regs[0]})-1)"
+ else if n == once "to_i".to_symbol then
+ s = "TAG_Int(UNTAG_Char({regs[0]})-'0')"
+ else if n == once "+".to_symbol then
+ s = "TAG_Char(UNTAG_Char({regs[0]})+UNTAG_Char({regs[1]}))"
+ else if n == once "-".to_symbol then
+ s = "TAG_Char(UNTAG_Char({regs[0]})-UNTAG_Char({regs[1]}))"
+ else if n == once "*".to_symbol then
+ s = "TAG_Char(UNTAG_Char({regs[0]})*UNTAG_Char({regs[1]}))"
+ else if n == once "/".to_symbol then
+ s = "TAG_Char(UNTAG_Char({regs[0]})/UNTAG_Char({regs[1]}))"
+ else if n == once "%".to_symbol then
+ s = "TAG_Char(UNTAG_Char({regs[0]})%UNTAG_Char({regs[1]}))"
+ else if n == once "<".to_symbol then
+ s = "TAG_Bool(UNTAG_Char({regs[0]})<UNTAG_Char({regs[1]}))"
+ else if n == once ">".to_symbol then
+ s = "TAG_Bool(UNTAG_Char({regs[0]})>UNTAG_Char({regs[1]}))"
+ else if n == once "<=".to_symbol then
+ s = "TAG_Bool(UNTAG_Char({regs[0]})<=UNTAG_Char({regs[1]}))"
+ else if n == once ">=".to_symbol then
+ s = "TAG_Bool(UNTAG_Char({regs[0]})>=UNTAG_Char({regs[1]}))"
+ else if n == once "==".to_symbol then
+ s = "TAG_Bool(({regs[0]})==({regs[1]}))"
+ else if n == once "!=".to_symbol then
+ s = "TAG_Bool(({regs[0]})!=({regs[1]}))"
end
- return res.to_s
+ else if c == once "Bool".to_symbol then
+ if n == once "object_id".to_symbol then
+ s = "TAG_Int(UNTAG_Bool({regs[0]}))"
+ else if n == once "unary -".to_symbol then
+ s = "TAG_Bool(-UNTAG_Bool({regs[0]}))"
+ else if n == once "output".to_symbol then
+ s = "(void)printf(UNTAG_Bool({regs[0]})?\"true\\n\":\"false\\n\");"
+ else if n == once "ascii".to_symbol then
+ s = "TAG_Bool(UNTAG_Bool({regs[0]}))"
+ else if n == once "to_i".to_symbol then
+ s = "TAG_Int(UNTAG_Bool({regs[0]}))"
+ else if n == once "==".to_symbol then
+ s = "TAG_Bool(({regs[0]})==({regs[1]}))"
+ else if n == once "!=".to_symbol then
+ s = "TAG_Bool(({regs[0]})!=({regs[1]}))"
+ end
+ else if c == once "NativeArray".to_symbol then
+ if n == once "object_id".to_symbol then
+ s = "TAG_Int(((Nit_NativeArray){regs[0]})->object_id)"
+ else if n == once "[]".to_symbol then
+ s = "((Nit_NativeArray){regs[0]})->val[UNTAG_Int({regs[1]})]"
+ else if n == once "[]=".to_symbol then
+ s = "((Nit_NativeArray){regs[0]})->val[UNTAG_Int({regs[1]})]={regs[2]}"
+ else if n == once "copy_to".to_symbol then
+ s = "(void)memcpy(((Nit_NativeArray ){regs[1]})->val, ((Nit_NativeArray){regs[0]})->val, UNTAG_Int({regs[2]})*sizeof(val_t))"
+ end
+ else if c == once "NativeString".to_symbol then
+ if n == once "object_id".to_symbol then
+ s = "TAG_Int(UNBOX_NativeString({regs[0]}))"
+ else if n == once "atoi".to_symbol then
+ s = "TAG_Int(atoi(UNBOX_NativeString({regs[0]})))"
+ else if n == once "[]".to_symbol then
+ s = "TAG_Char(UNBOX_NativeString({regs[0]})[UNTAG_Int({regs[1]})])"
+ else if n == once "[]=".to_symbol then
+ s = "UNBOX_NativeString({regs[0]})[UNTAG_Int({regs[1]})]=UNTAG_Char({regs[2]});"
+ else if n == once "copy_to".to_symbol then
+ s = "(void)memcpy(UNBOX_NativeString({regs[1]})+UNTAG_Int({regs[4]}), UNBOX_NativeString({regs[0]})+UNTAG_Int({regs[3]}), UNTAG_Int({regs[2]}));"
+ end
+ else if c == once "Sys".to_symbol then
+ if n == once "force_garbage_collection".to_symbol then
+ s = "Nit_gc_force_garbage_collection()"
+ else if n == once "native_argc".to_symbol then
+ s = "TAG_Int(glob_argc)"
+ else if n == once "native_argv".to_symbol then
+ s = "BOX_NativeString(glob_argv[UNTAG_Int({regs[1]})])"
+ end
+ else if n == once "object_id".to_symbol then
+ s = "TAG_Int((bigint)((obj_t){regs[0]})[1].object_id)"
+ else if n == once "sys".to_symbol then
+ s = "(G_sys)"
+ else if n == once "is_same_type".to_symbol then
+ s = "TAG_Bool((VAL2VFT({regs[0]})==VAL2VFT({regs[1]})))"
+ else if n == once "exit".to_symbol then
+ s = "exit(UNTAG_Int({regs[1]}));"
+ else if n == once "calloc_array".to_symbol then
+ s = "NEW_NativeArray(UNTAG_Int({regs[1]}), sizeof(val_t))"
+ else if n == once "calloc_string".to_symbol then
+ s = "BOX_NativeString((char*)raw_alloc((UNTAG_Int({regs[1]}) * sizeof(char))))"
+ # Add output_class_name native implementation
+ else if n == once "output_class_name".to_symbol then
+ s = "printf(\"%s\\n\", VAL2VFT({regs[0]})[2].cname);"
+ # Add class_name implementation
+ else if n == once "native_class_name".to_symbol then
+ s = "BOX_NativeString(VAL2VFT({regs[0]})[2].cname);"
+ end
+
+ if s == null then
+ var ll = location
+ if ll != null then v.add_instr("fprintf(stderr, \"{ll.to_s}: \");")
+ v.add_instr("fprintf(stderr, \"Fatal error: unknown intern method {method.full_name}.\\n\");")
+ v.add_instr("nit_exit(1);")
+ s = "NIT_NULL"
+ end
+ if result == null then
+ v.new_instr.add(s).add(";\n")
+ else if need_result then
+ var w = new_result(v)
+ w.add(s)
end
end
end
+redef class IIntValue
+ redef fun compile_to_c(v)
+ do
+ v.add_location(location)
+ var w = new_result(v)
+ w.add("TAG_Int(").add(value.to_s).add(")")
+ end
+end
+
+redef class IBoolValue
+ redef fun compile_to_c(v)
+ do
+ v.add_location(location)
+ var w = new_result(v)
+ w.add("TAG_Bool(")
+ if value then w.add("1") else w.add("0")
+ w.add(")")
+ end
+end
+
+redef class ICharValue
+ redef fun compile_to_c(v)
+ do
+ v.add_location(location)
+ var w = new_result(v)
+ w.add("TAG_Char(").add(value).add(")")
+ end
+end
+
+redef class IFloatValue
+ redef fun compile_to_c(v)
+ do
+ v.add_location(location)
+ var w = new_result(v)
+ w.add("BOX_Float(").add(value).add(")")
+ end
+end
+
+redef class IStringValue
+ redef fun compile_to_c(v)
+ do
+ v.add_location(location)
+ var w = new_result(v)
+ w.add("BOX_NativeString(\"").add(value).add("\")")
+ end
+end
+
redef class IAbort
- redef fun inner_compile_to_c(v)
+ redef fun compile_to_c(v)
do
- var s = new Buffer.from("fprintf(stderr")
- for t in texts do
- s.append(", \"{t}\"")
+ v.add_location(location)
+ var w = v.new_instr
+ w.add("nit_abort(\"")
+ w.add(texts[0])
+ if texts.length > 1 then
+ w.add("\", \"")
+ w.add(texts[1])
+ w.add("\"")
+ else
+ w.add("\", NULL")
end
- s.append(");")
- v.add_instr(s.to_s)
-
+ w.add(", LOCATE_")
+ w.add(module_location.cname)
var ll = location
- s = new Buffer.from("fprintf(stderr, \" (%s")
- if ll != null then
- s.append(":%d")
- end
- s.append(")\\n\", LOCATE_{module_location.name}")
if ll != null then
- s.append(", {ll.line_start}")
+ w.add(", ")
+ w.add(ll.line_start.to_s)
+ else
+ w.add(", 0")
end
- s.append(");")
- v.add_instr(s.to_s)
-
- v.add_instr("nit_exit(1);")
- return null
+ w.add(");\n")
end
end
redef class IMove
- redef fun inner_compile_to_c(v)
+ redef fun compile_to_c(v)
do
- return v.register(expr)
+ if not need_result then return
+ var e = v.register(expr)
+ var r = v.register(result.as(not null))
+ if e == r then return
+ v.add_location(location)
+ var w = v.new_instr
+ w.add(r)
+ w.add(" = ")
+ w.add(e)
+ w.add(";\n")
end
end
redef class IAttrRead
- redef fun inner_compile_to_c(v)
+ redef fun compile_to_c(v)
do
- return "{property.global.attr_access}({v.register(expr)})"
+ if not need_result then return
+ v.add_location(location)
+ var w = new_result(v)
+ w.add(property.global.attr_access)
+ w.add("(")
+ w.add(v.register(expr))
+ w.add(")")
end
end
redef class IAttrIsset
- redef fun inner_compile_to_c(v)
+ redef fun compile_to_c(v)
do
- return "TAG_Bool({property.global.attr_access}({v.register(expr)})!=NIT_NULL)"
+ if not need_result then return
+ v.add_location(location)
+ var w = new_result(v)
+ w.add("TAG_Bool(")
+ w.add(property.global.attr_access)
+ w.add("(")
+ w.add(v.register(expr))
+ w.add(")!=NIT_NULL)")
end
end
redef class IAttrWrite
- redef fun inner_compile_to_c(v)
+ redef fun compile_to_c(v)
do
- v.add_instr("{property.global.attr_access}({v.register(expr1)}) = {v.register(expr2)};")
- return null
+ v.add_location(location)
+ var w = v.new_instr
+ w.add(property.global.attr_access)
+ w.add("(")
+ w.add(v.register(expr1))
+ w.add(") = ")
+ w.add(v.register(expr2))
+ w.add(";\n")
end
end
redef class ITypeCheck
- redef fun inner_compile_to_c(v)
+ redef fun compile_to_c(v)
do
- # FIXME handle formaltypes
- var g = stype.local_class.global
- var recv = v.register(expr)
- var s = ""
- if expr.stype.is_nullable then
+ if not need_result then return
+ v.add_location(location)
+ var recv = v.register(expr2)
+ var w = new_result(v)
+ w.add("TAG_Bool(")
+ if expr2.stype.is_nullable then
if stype.is_nullable then
- s = "({recv}==NIT_NULL) || "
- else if stype.as_nullable == expr.stype then
- return "TAG_Bool({recv}!=NIT_NULL)"
+ w.add("(")
+ w.add(recv)
+ w.add("==NIT_NULL) || ")
+ else if stype.as_nullable == expr2.stype then
+ w.add(recv)
+ w.add("!=NIT_NULL)")
+ return
else
- s = "({recv}!=NIT_NULL) && "
+ w.add("(")
+ w.add(recv)
+ w.add("!=NIT_NULL) && ")
end
end
- return "TAG_Bool({s}VAL_ISA({recv}, {g.color_id}, {g.id_id})) /*cast {stype}*/"
+ # FIXME handle formaltypes
+ var t = stype
+ if t isa MMVirtualType then
+ var slf = v.register(expr1)
+ var g = t.property.global
+ w.add("VAL_ISA(")
+ w.add(recv)
+ w.add(", ")
+ w.add(g.vt_class_color)
+ w.add("(")
+ w.add(slf)
+ w.add(")")
+ w.add(", ")
+ w.add(g.vt_class_id)
+ w.add("(")
+ w.add(slf)
+ w.add(")")
+ w.add(")) /*cast ")
+ w.add(t.to_s)
+ w.add("*/")
+ else
+ var g = t.local_class.global
+ w.add("VAL_ISA(")
+ w.add(recv)
+ w.add(", ")
+ w.add(g.color_id)
+ w.add(", ")
+ w.add(g.id_id)
+ w.add(")) /*cast ")
+ w.add(t.to_s)
+ w.add("*/")
+ end
end
end
redef class IIs
- redef fun inner_compile_to_c(v)
+ redef fun compile_to_c(v)
do
+ if not need_result then return
+ v.add_location(location)
+ var w = new_result(v)
+ w.add("TAG_Bool(")
var t1 = expr1.stype
var t2 = expr2.stype
if t1 isa MMTypeNone then
if t2 isa MMTypeNone then
- return "TAG_Bool(1)"
+ w.add("1)")
+ return
else if t2.is_nullable then
- return "TAG_Bool({v.register(expr2)}==NIT_NULL)"
+ w.add(v.register(expr2))
+ w.add("==NIT_NULL)")
+ return
else
- return "TAG_Bool(0)"
+ w.add("0)")
+ return
end
else if t1.is_nullable then
if t2 isa MMTypeNone then
- return "TAG_Bool({v.register(expr1)}==NIT_NULL)"
+ w.add(v.register(expr1))
+ w.add("==NIT_NULL)")
+ return
else if t2.is_nullable then
- return "TAG_Bool(IS_EQUAL_NN({v.register(expr1)},{v.register(expr2)}))"
+ w.add("IS_EQUAL_NN(")
else
- return "TAG_Bool(IS_EQUAL_ON({v.register(expr2)},{v.register(expr1)}))"
+ w.add("IS_EQUAL_ON(")
+ w.add(v.register(expr2))
+ w.add(",")
+ w.add(v.register(expr1))
+ w.add("))")
+ return
end
else
if t2 isa MMTypeNone then
- return "TAG_Bool(0)"
+ w.add("0)")
+ return
else if t2.is_nullable then
- return "TAG_Bool(IS_EQUAL_ON({v.register(expr1)},{v.register(expr2)}))"
+ w.add("IS_EQUAL_ON(")
else
- return "TAG_Bool(IS_EQUAL_OO({v.register(expr1)},{v.register(expr2)}))"
+ w.add("IS_EQUAL_OO(")
end
end
+ w.add(v.register(expr1))
+ w.add(",")
+ w.add(v.register(expr2))
+ w.add("))")
end
end
redef class INot
- redef fun inner_compile_to_c(v)
+ redef fun compile_to_c(v)
do
- return "TAG_Bool(!UNTAG_Bool({v.register(expr)}))"
+ if not need_result then return
+ v.add_location(location)
+ var w = new_result(v)
+ w.add("TAG_Bool(!UNTAG_Bool(")
+ w.add(v.register(expr))
+ w.add("))")
end
end
redef class IOnce
- redef fun inner_compile_to_c(v)
+ redef fun compile_to_c(v)
do
+ v.add_location(location)
var i = v.new_number
var res = result.as(not null)
if res.stype.is_nullable then
end
v.indent
body.compile_to_c(v)
- var e = v.register(result.as(not null))
+ var e = v.register(res)
v.add_instr("once_value_{i} = {e};")
+ v.add_instr("register_static_object(&once_value_{i});")
if res.stype.is_nullable then v.add_instr("once_bool_{i} = true;")
v.unindent
- v.add_instr("} else {e} = once_value_{i};")
- return e
+ v.add_instr("\} else {e} = once_value_{i};")
+ var w = new_result(v)
+ w.add(e)
end
end
do
v.add_location(location)
var ivar: String
+ var args: Array[String]
if v.closure then
- ivar = "closctx->closurevariable[{v.closures[closure_decl]}]"
+ ivar = "closctx->closure_funs[{v.closures[closure_decl]}]"
+ args = ["closctx->closure_ctx"]
else
ivar = "CREG[{v.closures[closure_decl]}]"
+ args = ["closctx_param"]
end
- var args = [ivar]
args.append(v.registers(exprs))
- var s = "(({v.clostypes[closure_decl]})({ivar}->fun))({args.join(", ")})"
- store_result(v, s)
+ var s = "(({v.clostypes[closure_decl]})({ivar}))({args.join(", ")})"
+ var w = new Writer
+ w.add(s)
+ store_result(v, w)
- v.add_instr("if ({ivar}->has_broke) \{")
+ # Intercept escape
+ v.add_instr("if ({args.first}->has_broke) \{")
v.indent
var bs = break_seq
if bs != null then
v.unindent
v.add_instr("\}")
end
-
- redef fun inner_compile_to_c(v) do abort
end
redef class IHasClos
- redef fun inner_compile_to_c(v)
+ redef fun compile_to_c(v)
do
- var ivar: String
+ if not need_result then return
+ v.add_location(location)
+ var w = new_result(v)
+ w.add("TAG_Bool(")
if v.closure then
- ivar = "closctx->closurevariable[{v.closures[closure_decl]}]"
+ w.add("closctx->closure_funs[")
+ w.add(v.closures[closure_decl])
+ w.add("]")
else
- ivar = "CREG[{v.closures[closure_decl]}]"
+ w.add("CREG[")
+ w.add(v.closures[closure_decl])
+ w.add("]")
end
- return "TAG_Bool({ivar} != NULL)"
+ w.add(" != NULL)")
end
end
-
redef class IClosureDef
+ # Compile the closure as a separate C function in the visitor out_contexts.
+ # Return a fun_t pointer to the function.
fun compile_closure(v: I2CCompilerVisitor): String
do
+ var cv = v.visitor
+
+ # We are now in a closure
var cfc_old = v.closure
v.closure = true
+
+ # We are now in a escape boundary
var lls_old = v.local_labels
v.local_labels = new HashSet[ISeq]
- var cv = v.visitor
- var ctx_old = cv.ctx
- cv.ctx = new CContext
- cv.out_contexts.add(cv.ctx)
+ # We are now in a new C context
+ var decl_writer_old = cv.decl_writer
+ var writer_old = cv.writer
+ cv.writer = cv.top_writer.sub
+ cv.decl_writer = cv.header_writer.sub
+ # Generate the C function
var cname = "OC_{v.basecname}_{v.new_number}"
- var args = compile_signature_to_c(v.visitor, cname, null, "struct WBT_ *closctx", null)
- var ctx_old2 = cv.ctx
- cv.ctx = new CContext
+ var args = compile_signature_to_c(v.visitor, cname, null, "struct stack_frame_t *closctx", null)
+ cv.decl_writer = cv.writer.sub
var s = compile_inside_to_c(v, args)
if s == null then
else
v.add_instr("return {s};")
end
-
- ctx_old2.append(cv.ctx)
- cv.ctx = ctx_old2
v.unindent
- v.add_instr("}")
- cv.ctx = ctx_old
+ v.add_instr("\}")
+ # Restore things
+ cv.writer = writer_old
+ cv.decl_writer = decl_writer_old
v.closure = cfc_old
-
- # Build closure
- var closcnv = "wbclos{v.new_number}"
- v.add_decl("struct WBT_ {closcnv};")
- v.add_instr("{closcnv}.fun = (fun_t){cname};")
- v.add_instr("{closcnv}.has_broke = NULL;")
- if cfc_old then
- v.add_instr("{closcnv}.variable = closctx->variable;")
- v.add_instr("{closcnv}.closurevariable = closctx->closurevariable;")
- else
- v.add_instr("{closcnv}.variable = REG;")
- v.add_instr("{closcnv}.closurevariable = CREG;")
- end
-
v.local_labels = lls_old
- return "(&{closcnv})"
+ return "((fun_t){cname})"
end
end