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 # iregisters slot allocation
18 package allocate_iregister_slots
21 private import primitive_info
23 # The main class that performs the iregister slot allocation
24 # The algorithm is quite naive but works
28 # * IMove optimization
29 class IRegisterSlotAllocationVisitor
31 # The visitor works in two pass:
32 # First pass is used to detect first and last iregisters occurences and slot groups
33 # Second pass is used to assign an effective slot to iregsiters
36 # Update locality information of r according to the current iroutine
37 fun mark_locality
(r
: IRegister)
39 if r
._is_local
and r
._local_iroutine
!= _current_ir
then
40 if r
._local_iroutine
== null then
41 r
._local_iroutine
= _current_ir
48 redef fun visit_iregister_read
(ic
: ICode, r
: IRegister)
55 else if pass
== 1 and _lasts
.has_key
(r
) and _lasts
[r
] == ic
then
60 redef fun visit_iregister_write
(ic
: ICode, r
: IRegister)
66 # The first write make it live
67 if not _firsts
.has_key
(r
) then _firsts
[r
] = ic
68 # A read iregistre is stile live on a write
69 if _lasts
.has_key
(r
) then _lasts
[r
] = ic
70 else if pass
== 1 then
71 if _firsts
[r
] == ic
then
73 else if _lasts
.has_key
(r
) and _lasts
[r
] == ic
then
79 # Iregister from outside a loop/closure cannot die inside the loop/closure
80 # So, the only register that can die in loops/closure are those born inside the loop/closure
82 # Registers born in the current loop/closure
83 # So they can die immediatly if needed
84 var _live
: HashSet[IRegister] = new HashSet[IRegister]
86 # Registers born outsde the current loop/closure that wanted to die
87 # Thez will be effectively freed at the end of the loop/closure
88 var _deferred
: HashSet[IRegister] = new HashSet[IRegister]
90 # Free the deferred that can be freed
91 # "Can" because of neested loops/closures
92 # new_def will be cleared and used as the new _deferred attribute
93 fun deferred_free
(new_def
: HashSet[IRegister])
95 var old_def
= _deferred
96 if not old_def
.is_empty
then
105 redef fun visit_icode
(ic
)
107 if _pass
== 1 and ic
isa ILoop then
109 var new_live
= new HashSet[IRegister]
113 deferred_free
(new_live
)
119 redef fun visit_closure_defs
(closdefs
)
123 var new_live
= new HashSet[IRegister]
127 deferred_free
(new_live
)
133 # The current iroutine
134 # Used to detect locality of iregisters
135 var _current_ir
: IRoutine
137 redef fun visit_iroutine
(ir
)
141 var old_ir
= _current_ir
143 for r
in ir
.params
do
154 var old_tag_slots
= _tag_slots
155 _tag_slots
= new SlotGroup
156 var old_std_slots
= _std_slots
157 if ir
isa IClosureDef then
158 _std_slots
= new SlotGroup
160 for r
in ir
.params
do
164 if res
!= null then free
(res
)
165 ir
._tag_slots_nb
= _tag_slots
._next_index
166 _tag_slots
= old_tag_slots
167 ir
._std_slots_nb
= _std_slots
._next_index
168 _std_slots
= old_std_slots
172 # Global slots are used for non local registers and some main iroutine registers
173 var _global_slots
: SlotGroup = new SlotGroup
175 # Standad slots are used for local generic registers
176 # In main iroutine, _global_slots == _std_slots
177 var _std_slots
: SlotGroup
179 # Tag slots are used to store local tagged object registers
180 var _tag_slots
: SlotGroup = new SlotGroup
182 # Assign a slot to a register according to its locality and its type
183 fun register
(r
: IRegister)
185 if not _lasts
.has_key
(r
) then return
186 assert r
._slot_index
== null
188 if not r
._is_local
then
189 _global_slots
.register
(r
)
190 else if r
.stype
.is_tagged
then
191 r
._in_tag_slots
= true
192 _tag_slots
.register
(r
)
194 _std_slots
.register
(r
)
198 # Release a register, thus its slot can be reused
199 fun free
(r
: IRegister)
201 var i
= r
._slot_index
202 if i
== null then return
203 if not _live
.has
(r
) then
205 else if _lasts
.has_key
(r
) then
206 if r
._in_tag_slots
then
208 else if r
._is_local
then
211 _global_slots
.free
(r
)
213 _lasts
.remove_at
(r
) # Free a register only once
217 # What is the first occurences of iregisters
218 # So that a slot is not needed before
219 var _firsts
: HashMap[IRegister, Object] = new HashMap[IRegister, Object]
221 # What is the last occurences of iregisters
222 # So that a slot may be no more needed after
223 # ("may" because of loops/closure)
224 var _lasts
: HashMap[IRegister, Object] = new HashMap[IRegister, Object]
226 # Run the slot allocation
227 fun iroutine_slot_allocation
238 _std_slots
= _global_slots
242 # Group or equivalent slots shared by registers
244 # The free slots in the group
245 var _free
: List[Int] = new List[Int]
248 var _next_index
: Int = 0
250 # Assign a slot to the register
251 fun register
(r
: IRegister)
253 if _free
.is_empty
then
254 r
._slot_index
= _next_index
257 r
._slot_index
= _free
.pop
261 # Reuse the slot of the register
262 fun free
(r
: IRegister)
264 _free
.push
(r
._slot_index
.as(not null))
269 # The number of standard slots (stored in an array)
270 readable var _std_slots_nb
: Int = 0
272 # The number of tag slots
273 readable var _tag_slots_nb
: Int = 0
275 fun allocate_iregister_slots
277 var v
= new IRegisterSlotAllocationVisitor(self)
278 v
.iroutine_slot_allocation
282 redef class IRegister
283 # The slot index of the register in its slot group
284 # Is null if the iregister is dead
285 # (or if iregister slot allocation is not performed yet)
286 readable writable var _slot_index
: nullable Int
288 # Is the register local to a single iroutine?
289 readable writable var _is_local
: Bool = true
291 # If is_local, then what iroutine
292 readable writable var _local_iroutine
: nullable IRoutine
294 # Is the register stored in the tag slot group?
295 readable writable var _in_tag_slots
: Bool = false