X-Git-Url: http://nitlanguage.org diff --git a/src/icode/icode_tools.nit b/src/icode/icode_tools.nit index 0b48de9..1071959 100644 --- a/src/icode/icode_tools.nit +++ b/src/icode/icode_tools.nit @@ -15,6 +15,7 @@ # limitations under the License. # Tools to manipulate intermediace nit code representation +module icode_tools import icode_builder # A simple visitor to visit icode structures @@ -93,10 +94,16 @@ end redef class ICodeBuilder # Inline an iroutine in the current icode sequence - fun inline_routine(routine: IRoutine, args: Sequence[IRegister]): nullable IRegister + # 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 + 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 @@ -117,8 +124,26 @@ redef class ICodeBuilder #seq.icodes.add(new IMove(dico[routine.params[i]]), args[i])) end + # 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 - seq.icodes.add(routine.body.dup_with(d)) + routine.body.dup_with(d) return res end end @@ -139,7 +164,7 @@ private class ICodeDupContext end # Return a correct bunch of registers - fun dup_iregs(regs: Sequence[IRegister]): Sequence[IRegister] + fun dup_iregs(regs: Sequence[IRegister]): Array[IRegister] do var a = new Array[IRegister].with_capacity(regs.length) for r in regs do @@ -148,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 @@ -184,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 @@ -213,13 +289,10 @@ 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 @@ -251,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 @@ -335,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