X-Git-Url: http://nitlanguage.org diff --git a/src/icode/icode_tools.nit b/src/icode/icode_tools.nit index 5186233..1071959 100644 --- a/src/icode/icode_tools.nit +++ b/src/icode/icode_tools.nit @@ -15,7 +15,8 @@ # limitations under the License. # Tools to manipulate intermediace nit code representation -import icode_base +module icode_tools +import icode_builder # A simple visitor to visit icode structures class ICodeVisitor @@ -91,45 +92,79 @@ class ICodeVisitor end end -redef class IRoutine - # Inline an iroutine in an icode sequence - fun inline_in_seq(seq: ISeq, args: IndexedCollection[IRegister]): nullable IRegister +redef class ICodeBuilder + # Inline an iroutine in the current icode sequence + # Require that routine != self.iroutine + fun inline_routine(routine: IRoutine, args: Sequence[IRegister], closdefs: nullable Sequence[nullable IClosureDef]): nullable IRegister do - var d = new ICodeDupContext - if args.length != params.length then print "{args.length} != {params.length}" - assert args.length == params.length + assert routine != self.iroutine + var d = new ICodeDupContext(self) + assert args.length == routine.params.length + var closdecls = routine.closure_decls + var cdefsa = if closdefs != null then closdefs.length else 0 + var cdeclsa = if closdecls != null then closdecls.length else 0 + assert cdefsa <= cdeclsa + + # Fill register duplicate association + var dico = d._registers + var res = routine.result + if res != null then + var res2 = new_register(res.stype) + dico[res] = res2 + res = res2 + end + for reg in routine.registers do + assert not dico.has_key(reg) + dico[reg] = new_register(reg.stype) + end for i in [0..args.length[ do # FIXME The following assumes that params are readonly. # The alternative is safe but add one move :/ - d._registers[params[i]] = args[i] - #seq.icodes.add(new IMove(d.dup_ireg(params[i]), args[i])) + dico[routine.params[i]] = args[i] + #seq.icodes.add(new IMove(dico[routine.params[i]]), args[i])) end - seq.icodes.add(body.dup_with(d)) - var r = result - if r != null then r = d.dup_ireg(r) - return r + + # Fill escape mark association + for m in routine.escape_marks do + var m2 = new IEscapeMark + iroutine.escape_marks.add(m2) + d._marks[m] = m2 + end + + # Fill closure association + if closdecls != null then + var cdico = d._closures + for i in [0..cdefsa[ do + cdico[closdecls[i]] = closdefs[i] + end + for i in [cdefsa..cdeclsa[ do + cdico[closdecls[i]] = null + end + end + + # Process inlining + routine.body.dup_with(d) + return res end end # This class stores reference to allow correct duplication of icodes private class ICodeDupContext - # Duplicate one register - # Subsequent invocation will return the same register + # Return the correct register + # * a duplicate of the local register 'r' of the inlined iroutine + # * 'r' else (it is a register of the caller iroutine) fun dup_ireg(r: IRegister): IRegister do var rs = _registers if rs.has_key(r) then return rs[r] else - var r2 = new IRegister(r.stype) - rs[r] = r2 - return r2 + return r end end - # Duplicate a bunch of registers - # Subsequent invocation will return the same registers - fun dup_iregs(regs: IndexedCollection[IRegister]): IndexedCollection[IRegister] + # Return a correct bunch of registers + fun dup_iregs(regs: Sequence[IRegister]): Array[IRegister] do var a = new Array[IRegister].with_capacity(regs.length) for r in regs do @@ -138,27 +173,71 @@ private class ICodeDupContext return a end - # The associoation between old_seq and new_seq - # Directly used by the IEscape - var _seqs: Map[ISeq, ISeq] = new HashMap[ISeq, ISeq] - # The assocation between old_ireg and new_ireg # Used by dup_ireg var _registers: Map[IRegister, IRegister] = new HashMap[IRegister, IRegister] + + # Return the correct escape mark + # * a duplicate of the local escape mark 'm' of the inlined iroutine + # * 'r' else (it is a escape mark of the caller iroutine) + fun dup_mark(m: IEscapeMark): IEscapeMark + do + var ms = _marks + if ms.has_key(m) then + return ms[m] + else + return m + end + end + + # The associoation between old_seq and new_seq + # Used by dup_mark + var _marks: Map[IEscapeMark, IEscapeMark] = new HashMap[IEscapeMark, IEscapeMark] + + # The association between a closure_decl and its closure_def (if any) + var _closures: Map[IClosureDecl, nullable IClosureDef] = new ArrayMap[IClosureDecl, nullable IClosureDef] + + # The current code builder + var _icb: ICodeBuilder + + init(icb: ICodeBuilder) + do + _icb = icb + end end redef class ICode - # Duplicate the current icode (generic part) - private fun dup_with(d: ICodeDupContext): ICode + # Duplicate the current icode in the icode builder of the ICodeDupContext + private fun dup_with(d: ICodeDupContext) do var c = inner_dup_with(d) + if self isa ICodeN then + assert c isa ICodeN + var cdecl = closure_defs + if cdecl != null then + # Duplicate the colsure definitions + var cdecl2 = new Array[nullable IClosureDef].with_capacity(cdecl.length) + for cd in cdecl do + if cd == null then + cdecl2.add(null) + else + var r = cd.result + if r != null then r = d.dup_ireg(r) + var cd2 = new IClosureDef(d.dup_iregs(cd.params), r) + cdecl2.add(cd2) + cd.body.dup_seq_to(d, cd2.body) + end + end + c.closure_defs = cdecl2 + end + end var r = result if r != null then c.result = d.dup_ireg(r) c.location = location - return c + d._icb.seq.icodes.add(c) end - # Duplicate the current icode (specific part) + # Simle partial duplication of the current icode private fun inner_dup_with(d: ICodeDupContext): ICode is abstract end @@ -174,9 +253,16 @@ redef class ISeq # Note: dest must be empty and not modified afted duplication or IEscapes may be wrongly duplicated private fun dup_seq_to(d: ICodeDupContext, dest: ISeq) do - d._seqs[self] = dest + var old_seq = d._icb.seq + d._icb.seq = dest for c in icodes do - dest.icodes.add(c.dup_with(d)) + c.dup_with(d) + end + d._icb.seq = old_seq + assert dest.iescape_mark == null + var mark = iescape_mark + if mark != null then + dest.iescape_mark = d.dup_mark(mark) end end end @@ -203,20 +289,17 @@ end redef class IEscape redef fun inner_dup_with(d) do - if d._seqs.has_key(seq) then - # Jump to a duplicated sequence - return new IEscape(d._seqs[seq]) - else - # Jump to an englobing unduplicated sequence - return new IEscape(seq) - end + # Get the associated mark (duplicated of not) + var mark = d.dup_mark(iescape_mark) + # Jump to the mark + return new IEscape(mark) end end redef class IAbort redef fun inner_dup_with(d) do - return new IAbort(texts, property_location, module_location) + return new IAbort(texts, module_location) end end @@ -241,29 +324,108 @@ redef class INew end end -redef class IClosCall +redef class IAllocateInstance + redef fun inner_dup_with(d) + do + return new IAllocateInstance(stype) + end +end + +redef class IStaticCall + redef fun inner_dup_with(d) + do + return new IStaticCall(property, d.dup_iregs(exprs)) + end +end + +redef class ICheckInstance + redef fun inner_dup_with(d) + do + return new ICheckInstance(stype, d.dup_ireg(expr)) + end +end + +redef class IInitAttributes redef fun inner_dup_with(d) do - var c2 = new IClosCall(closure_decl, d.dup_iregs(exprs)) - var bs = break_seq - if bs != null then - var bs2 = new ISeq - c2.break_seq = bs2 - bs.dup_seq_to(d, bs2) + return new IInitAttributes(stype, d.dup_ireg(expr)) + end +end + +redef class IClosCall + redef fun dup_with(d) + do + if d._closures.has_key(closure_decl) then + # The icloscall need to be replaced with an inlined closdef + var closdef = d._closures[closure_decl] + if closdef == null then + # Default is already guarded and inlined + return + end + # Break sequence cannot be inlined :/ + assert break_seq == null + # Inline the closdef + var res = d._icb.inline_routine(closdef, d.dup_iregs(exprs), null) + if result != null then + assert res != null + d._icb.stmt(new IMove(d.dup_ireg(result.as(not null)), res)) + end + else + # Standard icloscall duplication + super end - return c2 + end + + redef fun inner_dup_with(d) + do + return new IClosCall(closure_decl, exprs) end end redef class INative redef fun inner_dup_with(d) do - var c2 = new INative(code, d.dup_iregs(exprs)) + var c2 = new INative(method, d.dup_iregs(exprs)) c2.is_pure = is_pure return c2 end end +redef class IIntValue + redef fun inner_dup_with(d) + do + return new IIntValue(value) + end +end + +redef class IBoolValue + redef fun inner_dup_with(d) + do + return new IBoolValue(value) + end +end + +redef class IStringValue + redef fun inner_dup_with(d) + do + return new IStringValue(value) + end +end + +redef class IFloatValue + redef fun inner_dup_with(d) + do + return new IFloatValue(value) + end +end + +redef class ICharValue + redef fun inner_dup_with(d) + do + return new ICharValue(value) + end +end + redef class IMove redef fun inner_dup_with(d) do @@ -325,6 +487,18 @@ end redef class IHasClos redef fun inner_dup_with(d) do - return new IHasClos(closure_decl) + if d._closures.has_key(closure_decl) then + # closdef will be inlined + var closdef = d._closures[closure_decl] + var res: IRegister + if closdef != null then + res = d._icb.lit_true_reg + else + res = d._icb.lit_false_reg + end + return new IMove(d.dup_ireg(result.as(not null)), res) + else + return new IHasClos(closure_decl) + end end end