518623340aa411711e6b756cb708d4593b83a155
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 # Tools to manipulate intermediace nit code representation
20 # A simple visitor to visit icode structures
22 # Called when a iregister is read in a icode
23 fun visit_iregister_read
(ic
: ICode, r
: IRegister) do end
25 # Called when a iregister is wrote in a icode
26 fun visit_iregister_write
(ic
: ICode, r
: IRegister) do end
28 # The current icode iterator.
29 # Can be used to insert_before, used to change the item or deleted
30 readable var _current_icode
: nullable ListIterator[ICode] = null
32 # Called when a icode is visited
33 # Automatically visits iregisters and sub-icodes
34 fun visit_icode
(ic
: nullable ICode)
36 if ic
== null then return
38 var old_icode
= _current_icode
39 var cur
= ic
.icodes
.iterator
46 _current_icode
= old_icode
47 else if ic
isa IIf then
48 visit_iregister_read
(ic
, ic
.expr
)
49 visit_icode
(ic
.then_seq
)
50 visit_icode
(ic
.else_seq
)
51 else if ic
isa IOnce then
53 else if ic
isa ICode1 then
54 visit_iregister_read
(ic
, ic
.expr
)
55 else if ic
isa ICode2 then
56 visit_iregister_read
(ic
, ic
.expr1
)
57 visit_iregister_read
(ic
, ic
.expr2
)
58 else if ic
isa ICodeN then
60 visit_iregister_read
(ic
, e
)
62 var closdefs
= ic
.closure_defs
63 if ic
isa IClosCall then
64 visit_icode
(ic
.break_seq
)
66 if closdefs
!= null then
67 visit_closure_defs
(closdefs
)
71 if r
!= null then visit_iregister_write
(ic
, r
)
74 # Called when closure definitions are visited
75 # Automatically visits each closure definition
76 fun visit_closure_defs
(closdefs
: Collection[nullable IClosureDef])
85 # Called when an iroutine is visited
86 # Automatically visits the body
87 # Warning: parameters of result registers are not visited
88 fun visit_iroutine
(ir
: IRoutine)
95 # Inline an iroutine in an icode sequence
96 fun inline_in_seq
(seq
: ISeq, args
: IndexedCollection[IRegister]): nullable IRegister
98 var d
= new ICodeDupContext
99 if args
.length
!= params
.length
then print
"{args.length} != {params.length}"
100 assert args
.length
== params
.length
101 for i
in [0..args
.length
[ do
102 # FIXME The following assumes that params are readonly.
103 # The alternative is safe but add one move :/
104 d
._registers
[params
[i
]] = args
[i
]
105 #seq.icodes.add(new IMove(d.dup_ireg(params[i]), args[i]))
107 seq
.icodes
.add
(body
.dup_with
(d
))
109 if r
!= null then r
= d
.dup_ireg
(r
)
114 # This class stores reference to allow correct duplication of icodes
115 private class ICodeDupContext
116 # Duplicate one register
117 # Subsequent invocation will return the same register
118 fun dup_ireg
(r
: IRegister): IRegister
121 if rs
.has_key
(r
) then
124 var r2
= new IRegister(r
.stype
)
130 # Duplicate a bunch of registers
131 # Subsequent invocation will return the same registers
132 fun dup_iregs
(regs
: IndexedCollection[IRegister]): IndexedCollection[IRegister]
134 var a
= new Array[IRegister].with_capacity
(regs
.length
)
141 # The associoation between old_seq and new_seq
142 # Directly used by the IEscape
143 var _seqs
: Map[ISeq, ISeq] = new HashMap[ISeq, ISeq]
145 # The assocation between old_ireg and new_ireg
147 var _registers
: Map[IRegister, IRegister] = new HashMap[IRegister, IRegister]
151 # Duplicate the current icode (generic part)
152 private fun dup_with
(d
: ICodeDupContext): ICode
154 var c
= inner_dup_with
(d
)
156 if r
!= null then c
.result
= d
.dup_ireg
(r
)
157 c
.location
= location
161 # Duplicate the current icode (specific part)
162 private fun inner_dup_with
(d
: ICodeDupContext): ICode is abstract
166 redef fun inner_dup_with
(d
)
173 # Duplicate each icode and store them in dest
174 # Note: dest must be empty and not modified afted duplication or IEscapes may be wrongly duplicated
175 private fun dup_seq_to
(d
: ICodeDupContext, dest
: ISeq)
179 dest
.icodes
.add
(c
.dup_with
(d
))
185 redef fun inner_dup_with
(d
)
194 redef fun inner_dup_with
(d
)
196 var c2
= new IIf(d
.dup_ireg
(expr
))
197 then_seq
.dup_seq_to
(d
, c2
.then_seq
)
198 else_seq
.dup_seq_to
(d
, c2
.else_seq
)
204 redef fun inner_dup_with
(d
)
206 if d
._seqs
.has_key
(seq
) then
207 # Jump to a duplicated sequence
208 return new IEscape(d
._seqs
[seq
])
210 # Jump to an englobing unduplicated sequence
211 return new IEscape(seq
)
217 redef fun inner_dup_with
(d
)
219 return new IAbort(texts
, property_location
, module_location
)
224 redef fun inner_dup_with
(d
)
226 return new ICall(property
, d
.dup_iregs
(exprs
))
231 redef fun inner_dup_with
(d
)
233 return new ISuper(property
, d
.dup_iregs
(exprs
))
238 redef fun inner_dup_with
(d
)
240 return new INew(stype
, property
, d
.dup_iregs
(exprs
))
244 redef class IClosCall
245 redef fun inner_dup_with
(d
)
247 var c2
= new IClosCall(closure_decl
, d
.dup_iregs
(exprs
))
252 bs
.dup_seq_to
(d
, bs2
)
259 redef fun inner_dup_with
(d
)
261 var c2
= new INative(code
, d
.dup_iregs
(exprs
))
268 redef fun inner_dup_with
(d
)
270 return new IMove(d
.dup_ireg
(result
.as(not null)), d
.dup_ireg
(expr
))
274 redef class IAttrRead
275 redef fun inner_dup_with
(d
)
277 return new IAttrRead(property
, d
.dup_ireg
(expr
))
281 redef class IAttrWrite
282 redef fun inner_dup_with
(d
)
284 return new IAttrWrite(property
, d
.dup_ireg
(expr1
), d
.dup_ireg
(expr2
))
288 redef class IAttrIsset
289 redef fun inner_dup_with
(d
)
291 return new IAttrIsset(property
, d
.dup_ireg
(expr
))
295 redef class ITypeCheck
296 redef fun inner_dup_with
(d
)
298 return new ITypeCheck(d
.dup_ireg
(expr
), stype
)
303 redef fun inner_dup_with
(d
)
305 return new IIs(d
.dup_ireg
(expr1
), d
.dup_ireg
(expr2
))
310 redef fun inner_dup_with
(d
)
312 return new INot(d
.dup_ireg
(expr
))
317 redef fun inner_dup_with
(d
)
320 body
.dup_seq_to
(d
, c2
.body
)
326 redef fun inner_dup_with
(d
)
328 return new IHasClos(closure_decl
)