dc454a2fe8354502881c77a9fb60a9025073d718
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 redef fun visit_iregister_read
(ic
: ICode, r
: IRegister)
40 if r
._is_local
and r
._local_iroutine
!= _current_ir
then
41 if r
._local_iroutine
== null then
42 r
._local_iroutine
= _current_ir
49 else if pass
== 1 and _lasts
.has_key
(r
) and _lasts
[r
] == ic
then
54 redef fun visit_iregister_write
(ic
: ICode, r
: IRegister)
59 if r
._is_local
and r
._local_iroutine
!= _current_ir
then
60 if r
._local_iroutine
== null then
61 r
._local_iroutine
= _current_ir
67 # The first write make it live
68 if not _firsts
.has_key
(r
) then _firsts
[r
] = ic
69 # A read iregistre is stile live on a write
70 if _lasts
.has_key
(r
) then _lasts
[r
] = ic
71 else if pass
== 1 then
72 if _firsts
[r
] == ic
then
74 else if _lasts
.has_key
(r
) and _lasts
[r
] == ic
then
80 # Iregister from outside a loop/closure cannot die inside the loop/closure
81 # So, the only register that can die in loops/closure are those born inside the loop/closure
83 # Registers born in the current loop/closure
84 # So they can die immediatly if needed
85 var _live
: HashSet[IRegister] = new HashSet[IRegister]
87 # Registers born outsde the current loop/closure that wanted to die
88 # Thez will be effectively freed at the end of the loop/closure
89 var _deferred
: HashSet[IRegister] = new HashSet[IRegister]
91 # Free the deferred that can be freed
92 # "Can" because of neested loops/closures
93 # new_def will be cleared and used as the new _deferred attribute
94 fun deferred_free
(new_def
: HashSet[IRegister])
96 var old_def
= _deferred
97 if not old_def
.is_empty
then
106 redef fun visit_icode
(ic
)
108 if _pass
== 1 and ic
isa ILoop then
110 var new_live
= new HashSet[IRegister]
114 deferred_free
(new_live
)
120 redef fun visit_closure_defs
(closdefs
)
124 var new_live
= new HashSet[IRegister]
128 deferred_free
(new_live
)
134 # The current iroutine
135 # Used to detect locality of iregisters
136 var _current_ir
: IRoutine
138 redef fun visit_iroutine
(ir
)
142 var old_ir
= _current_ir
144 for r
in ir
.params
do
153 var old_tag_slots
= _tag_slots
154 _tag_slots
= new SlotGroup
155 var old_std_slots
= _std_slots
156 if ir
isa IClosureDef then
157 _std_slots
= new SlotGroup
159 for r
in ir
.params
do
163 if res
!= null then free
(res
)
164 ir
._tag_slots_nb
= _tag_slots
._next_index
165 _tag_slots
= old_tag_slots
166 ir
._std_slots_nb
= _std_slots
._next_index
167 _std_slots
= old_std_slots
171 # Global slots are used for non local registers and some main iroutine registers
172 var _global_slots
: SlotGroup = new SlotGroup
174 # Standad slots are used for local generic registers
175 # In main iroutine, _global_slots == _std_slots
176 var _std_slots
: SlotGroup
178 # Tag slots are used to store local tagged object registers
179 var _tag_slots
: SlotGroup = new SlotGroup
181 # Assign a slot to a register according to its locality and its type
182 fun register
(r
: IRegister)
184 if not _lasts
.has_key
(r
) then return
185 assert r
._slot_index
== null
187 if not r
._is_local
then
188 _global_slots
.register
(r
)
189 else if r
.stype
.is_tagged
then
190 r
._in_tag_slots
= true
191 _tag_slots
.register
(r
)
193 _std_slots
.register
(r
)
197 # Release a register, thus its slot can be reused
198 fun free
(r
: IRegister)
200 var i
= r
._slot_index
201 if i
== null then return
202 if not _live
.has
(r
) then
204 else if _lasts
.has_key
(r
) then
205 if r
._in_tag_slots
then
207 else if r
._is_local
then
210 _global_slots
.free
(r
)
212 _lasts
.remove_at
(r
) # Free a register only once
216 # What is the first occurences of iregisters
217 # So that a slot is not needed before
218 var _firsts
: HashMap[IRegister, Object] = new HashMap[IRegister, Object]
220 # What is the last occurences of iregisters
221 # So that a slot may be no more needed after
222 # ("may" because of loops/closure)
223 var _lasts
: HashMap[IRegister, Object] = new HashMap[IRegister, Object]
225 # Run the slot allocation
226 fun iroutine_slot_allocation
237 _std_slots
= _global_slots
241 # Group or equivalent slots shared by registers
243 # The free slots in the group
244 var _free
: List[Int] = new List[Int]
247 var _next_index
: Int = 0
249 # Assign a slot to the register
250 fun register
(r
: IRegister)
252 if _free
.is_empty
then
253 r
._slot_index
= _next_index
256 r
._slot_index
= _free
.pop
260 # Reuse the slot of the register
261 fun free
(r
: IRegister)
263 _free
.push
(r
._slot_index
.as(not null))
268 # The number of standard slots (stored in an array)
269 readable var _std_slots_nb
: Int = 0
271 # The number of tag slots
272 readable var _tag_slots_nb
: Int = 0
274 fun allocate_iregister_slots
276 var v
= new IRegisterSlotAllocationVisitor(self)
277 v
.iroutine_slot_allocation
281 redef class IRegister
282 # The slot index of the register in its slot group
283 # Is null if the iregister is dead
284 # (or if iregister slot allocation is not performed yet)
285 readable writable var _slot_index
: nullable Int
287 # Is the register local to a single iroutine?
288 readable writable var _is_local
: Bool = true
290 # If is_local, then what iroutine
291 readable writable var _local_iroutine
: nullable IRoutine
293 # Is the register stored in the tag slot group?
294 readable writable var _in_tag_slots
: Bool = false