b0e1bbefc0ac4ba693c5435932c2d167b2611c67
[nit.git] / src / ssa.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2015 Julien Pagès <julien.pages@lirmm.fr>
4 #
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
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
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.
16
17 # Single-Static Assignment algorithm from an AST
18 module ssa
19
20 import semantize
21 import astbuilder
22
23 # Represent a sequence of the program
24 # A basic block is composed of several instructions without a jump
25 class BasicBlock
26 # First instruction of the basic block
27 var first: ANode is noinit
28
29 # Last instruction of the basic block
30 var last: ANode is noinit
31
32 # Direct successors
33 var successors = new Array[BasicBlock]
34
35 # Direct predecessors
36 var predecessors = new Array[BasicBlock]
37
38 # Parts of AST that contain a read to a variable
39 var read_sites = new Array[AVarFormExpr]
40
41 # Parts of AST that contain a write to a variable
42 var write_sites = new Array[AVarFormExpr]
43
44 # Parts of AST that contain a variable access (read or write)
45 var variables_sites = new Array[AExpr]
46
47 # The iterated dominance frontier of this block
48 # i.e. the set of blocks this block dominate directly or indirectly
49 var dominance_frontier: Array[BasicBlock] = new Array[BasicBlock] is lazy
50
51 # Self is the old block to link to the new,
52 # The two blocks are not linked if the current ends with a `AReturnExpr` or `ABreakExpr`
53 # i.e. self is the predecessor of `successor`
54 # `successor` The successor block
55 fun link(successor: BasicBlock)
56 do
57 # Do not link the two blocks if the current block end with a return, break or continue
58 if last isa AReturnExpr or last isa ABreakExpr or last isa AContinueExpr then return
59
60 successors.add(successor)
61 successor.predecessors.add(self)
62 end
63
64 # Self is the old block to link to the new
65 # i.e. self is the predecessor of `successor`
66 # `successor` The successor block
67 fun link_special(successor: BasicBlock)
68 do
69 # Link the two blocks even if the current block ends with a return or a break
70 successors.add(successor)
71 successor.predecessors.add(self)
72 end
73
74 # Add the `block` to the dominance frontier of this block
75 fun add_df(block: BasicBlock)
76 do
77 dominance_frontier.add(block)
78
79 # Add this block recursively in super-blocks to compute the iterated
80 # dominance frontier
81 for successor in block.successors do
82 # If this successor has not already been add to the dominance frontier
83 if not dominance_frontier.has(successor) then
84 add_df(successor)
85 end
86 end
87 end
88
89 # Compute recursively the dominance frontier of self block and its successors
90 private fun compute_df
91 do
92 # Treat each block only one time
93 df_computed = true
94
95 for s in successors do
96 add_df(s)
97
98 if not s.df_computed then s.compute_df
99 end
100 end
101
102 # Used to handle recursions by treating only one time each block
103 var treated: Bool = false
104
105 # If true, the iterated dominance frontier of this block has been computed
106 var df_computed: Bool = false
107
108 # Indicate the BasicBlock is newly created and needs to be updated
109 var need_update: Bool = false
110
111 # Indicate if the variables renaming step has been made for this block
112 var is_renaming: Bool = false
113
114 # The variables that are accessed in this block
115 var variables = new Array[Variable] is lazy
116
117 # The PhiFunction this block contains at the beginning
118 var phi_functions = new Array[PhiFunction] is lazy
119 end
120
121 # Contain the currently analyzed propdef
122 class SSA
123 # The currently analyzed APropdef
124 var propdef: APropdef
125
126 # The PhiFunction `current_propdef` contains
127 var phi_functions = new Array[PhiFunction]
128
129 # Recursively generate the basic blocks for this propdef
130 fun generate_basic_blocks
131 do
132 propdef.generate_basic_blocks(self)
133 end
134 end
135
136 redef class Variable
137 # The expressions of AST of this variable depends
138 var dep_exprs = new Array[AExpr]
139
140 # The blocks in which this variable is assigned
141 var assignment_blocks: Array[BasicBlock] = new Array[BasicBlock] is lazy
142
143 # Part of the program where this variable is read
144 var read_blocks: Array[BasicBlock] = new Array[BasicBlock] is lazy
145
146 # The stack of this variable, used for SSA renaming
147 var stack = new Array[Variable] is lazy
148
149 # The original Variable in case of renaming
150 var original_variable: nullable Variable = self
151
152 # If true, this variable is a parameter of a method
153 var parameter: Bool = false
154 end
155
156 # A PhiFunction is a kind of Variable used in SSA-construction,
157 # it is placed at the beginning of a BasicBlock with many incoming blocks
158 class PhiFunction
159 super Variable
160
161 # The dependences of this variable for SSA-Algorithm
162 var dependences = new Array[Couple[Variable, BasicBlock]]
163
164 # The position in the AST of the phi-function
165 var block: BasicBlock
166
167 # Set the dependences for the phi-function
168 # *`block` BasicBlock in which we go through the dominance-frontier
169 # *`v` The variable to looking for
170 fun add_dependences(block: BasicBlock, v: Variable)
171 do
172 # Look in which blocks of DF(block) `v` has been assigned
173 for b in block.predecessors do
174 if v.assignment_blocks.has(b) then
175 var dep = new Couple[Variable, BasicBlock](v, b)
176 dependences.add(dep)
177 end
178 end
179 end
180
181 # Print the PhiFunction with all its dependences
182 redef fun to_s: String
183 do
184 var s = ""
185 s += " dependences = [ "
186 for d in dependences do
187 s += d.first.to_s + " "
188 end
189 s += "]"
190
191 return s
192 end
193 end
194
195 redef class APropdef
196 # The variables contained in the body on this propdef
197 var variables: HashSet[Variable] = new HashSet[Variable] is lazy
198
199 # The first basic block of the code
200 var basic_block: nullable BasicBlock
201
202 # If true, the basic blocks where generated
203 var is_generated: Bool = false
204
205 # Generate all basic blocks for this code
206 fun generate_basic_blocks(ssa: SSA) is abstract
207
208 # Compute the three steps of SSA-algorithm
209 # `ssa` A new instance of SSA class initialized with `self`
210 fun compute_ssa(ssa: SSA)
211 do
212 if is_generated then return
213
214 # The first step is to generate the basic blocks
215 generate_basic_blocks(ssa)
216
217 # The propdef has no body (abstract)
218 if not is_generated then return
219
220 # Once basic blocks were generated, compute SSA algorithm
221 compute_phi(ssa)
222 rename_variables(ssa)
223 ssa_destruction(ssa)
224 end
225
226 # Compute the first phase of SSA algorithm: placing phi-functions
227 fun compute_phi(ssa: SSA)
228 do
229 var root_block = basic_block.as(not null)
230
231 # Compute the iterated dominance frontier of the graph of basic blocks
232 root_block.compute_df
233
234 # Places where a phi-function is added per variable
235 var phi_blocks = new HashMap[Variable, Array[BasicBlock]]
236
237 # For each variables in the propdef
238 for v in variables do
239 var phi_variables = new Array[BasicBlock]
240
241 var read_blocks = new Array[BasicBlock]
242 read_blocks.add_all(v.read_blocks)
243 read_blocks.add_all(v.assignment_blocks)
244
245 # While we have not treated each part accessing `v`
246 while not read_blocks.is_empty do
247 # Remove a block from the array
248 var block = read_blocks.shift
249
250 # For each block in the dominance frontier of `block`
251 for df in block.dominance_frontier do
252 # If we have not yet put a phi-function at the beginning of this block
253 if not phi_variables.has(df) then
254 phi_variables.add(df)
255
256 # Create a new phi-function and set its dependences
257 var phi = new PhiFunction("phi", df)
258 phi.add_dependences(df, v)
259 phi.block = df
260 phi.original_variable = phi
261 phi.declared_type = v.declared_type
262
263 # Indicate this phi-function is assigned in this block
264 phi.assignment_blocks.add(block)
265 ssa.phi_functions.add(phi)
266
267 # Add a phi-function at the beginning of df for variable v
268 df.phi_functions.add(phi)
269
270 if not v.read_blocks.has(df) or not v.assignment_blocks.has(df) then read_blocks.add(df)
271 end
272 end
273 end
274
275 # Add `phi-variables` to the global map
276 phi_blocks[v] = phi_variables
277 end
278 end
279
280 # Compute the second phase of SSA algorithm: renaming variables
281 # NOTE: `compute_phi` must has been called before
282 fun rename_variables(ssa: SSA)
283 do
284 # A counter for each variable
285 # The key is the variable, the value the number of assignment into the variable
286 var counter = new HashMap[Variable, Int]
287
288 for v in variables do
289 counter[v] = 0
290 v.stack.push(v)
291 end
292
293 for phi in ssa.phi_functions do counter[phi] = 0
294
295 # Launch the recursive renaming from the root block
296 rename(basic_block.as(not null), counter, ssa)
297 end
298
299 # Recursively rename each variable from `block`
300 # *`block` The starting basic block
301 # *`counter` The key is the variable, the value the number of assignment into the variable
302 fun rename(block: BasicBlock, counter: HashMap[Variable, Int], ssa: SSA)
303 do
304 if block.is_renaming then return
305
306 block.is_renaming = true
307
308 # For each phi-function of this block
309 for phi in block.phi_functions do
310 generate_name(phi, counter, block.first, ssa)
311
312 # Replace the phi into the block
313 block.phi_functions[block.phi_functions.index_of(phi)] = phi.original_variable.stack.last.as(PhiFunction)
314 end
315
316 # For each variable read in `block`
317 for vread in block.read_sites do
318 # Replace the old variable in AST
319 vread.variable = vread.variable.original_variable.stack.last
320 end
321
322 # For each variable write
323 for vwrite in block.write_sites do
324 generate_name(vwrite.variable.as(not null), counter, vwrite, ssa)
325
326 var new_version = vwrite.variable.original_variable.stack.last
327
328 # Set dependence of the new variable
329 if vwrite isa AVarReassignExpr then
330 new_version.dep_exprs.add(vwrite.n_value)
331 else if vwrite isa AVarAssignExpr then
332 new_version.dep_exprs.add(vwrite.n_value)
333 end
334
335 # Replace the old variable by the last created
336 vwrite.variable = new_version
337 end
338
339 # Rename occurrence of old names in phi-function
340 for successor in block.dominance_frontier do
341 for sphi in successor.phi_functions do
342 # Go over the couples in the phi dependences to rename variables
343 for couple in sphi.dependences do
344 if couple.second == block then
345 # Rename this variable
346 couple.first = couple.first.original_variable.stack.last
347 end
348 end
349 end
350 end
351
352 # Recurse in successor blocks
353 for successor in block.successors do
354 rename(successor, counter, ssa)
355 end
356
357 # Pop old names off the stack for each phi-function
358 for phi in block.phi_functions do
359 if not phi.stack.is_empty then phi.stack.pop
360 end
361 end
362
363 # Generate a new version of the variable `v` and return it
364 # *`v` The variable for which we generate a name
365 # *`counter` The key is the variable, the value the number of assignment into the variable
366 # *`expr` The AST node in which the assignment of v is made
367 # *`ssa` The instance of SSA
368 fun generate_name(v: Variable, counter: HashMap[Variable, Int], expr: ANode, ssa: SSA): Variable
369 do
370 var original_variable = v.original_variable.as(not null)
371
372 var i = counter[original_variable]
373
374 var new_version: Variable
375
376 # Create a new version of Variable
377 if original_variable isa PhiFunction then
378 var block = original_variable.block
379 new_version = new PhiFunction(original_variable.name + i.to_s, block)
380 new_version.dependences.add_all(original_variable.dependences)
381 ssa.phi_functions.add(new_version)
382 else
383 new_version = new Variable(original_variable.name + i.to_s)
384 new_version.declared_type = expr.as(AVarFormExpr).variable.declared_type
385 variables.add(new_version)
386 end
387
388 # Recopy the fields into the new version
389 new_version.location = expr.location
390 new_version.original_variable = original_variable
391
392 # Push a new version on the stack
393 original_variable.stack.add(new_version)
394 counter[v] = i + 1
395
396 return new_version
397 end
398
399 # Transform SSA-representation into an executable code (delete phi-functions)
400 # `ssa` Current instance of SSA
401 fun ssa_destruction(ssa: SSA)
402 do
403 var builder = new ASTBuilder(mpropdef.mclassdef.mmodule, mpropdef.mclassdef.bound_mtype)
404
405 # Iterate over all phi-functions
406 for phi in ssa.phi_functions do
407 for dep in phi.dependences do
408 # dep.second is the block where we need to create a varassign
409 var var_read = builder.make_var_read(dep.first, dep.first.declared_type.as(not null))
410 var nvar = builder.make_var_assign(dep.first, var_read)
411
412 var block = dep.second.last.parent
413
414 # This variable read must be add to a ABlockExpr
415 if block isa ABlockExpr then
416 block.add(nvar)
417 end
418
419 propagate_dependences(phi, phi.block)
420 ssa.propdef.variables.add(dep.first)
421 end
422 end
423 end
424
425 # Propagate the dependences of the phi-functions into following variables
426 # `phi` The PhiFunction
427 # `block` Current block where we propagate dependences
428 fun propagate_dependences(phi: PhiFunction, block: BasicBlock)
429 do
430 # Treat each block once
431 if block.treated then return
432
433 # For each variable access site in the block
434 for site in block.variables_sites do
435 if site isa AVarExpr then
436 # Propagate the dependences of the phi-function in variables after the phi
437 for dep in phi.dependences do
438 for expr in dep.first.dep_exprs do
439 if site.variable.dep_exprs.has(expr) then break
440
441 if dep.first.original_variable == site.variable.original_variable then
442 site.variable.dep_exprs.add(expr)
443 end
444 end
445 end
446 else
447 # The site is a variable write, we stop the propagation
448 return
449 end
450 end
451
452 block.treated = true
453
454 # If we do not meet a variable write, continue the propagation
455 for b in block.successors do propagate_dependences(phi, b)
456 end
457 end
458
459 redef class AAttrPropdef
460 redef fun generate_basic_blocks(ssa: SSA)
461 do
462 basic_block = new BasicBlock
463 basic_block.first = self
464 basic_block.last = self
465
466 # Add the self variable
467 if self.selfvariable != null then variables.add(selfvariable.as(not null))
468
469 # Recursively goes into the nodes
470 if n_block != null then
471 n_block.generate_basic_blocks(ssa, basic_block.as(not null))
472 is_generated = true
473 end
474 end
475 end
476
477 redef class AMethPropdef
478
479 # The return variable of the propdef
480 # Create an empty variable for the return of the method
481 # and treat returns like variable assignments
482 var returnvar: Variable = new Variable("returnvar")
483
484 redef fun generate_basic_blocks(ssa: SSA)
485 do
486 basic_block = new BasicBlock
487 basic_block.first = self
488 basic_block.last = self
489
490 # If the method has a signature
491 if n_signature != null then
492 for p in n_signature.n_params do
493 # Add parameters to the local variables
494 variables.add(p.variable.as(not null))
495 p.variable.parameter = true
496 end
497 end
498
499 # Add the return variable
500 variables.add(returnvar)
501
502 # Add the self variable
503 if self.selfvariable != null then variables.add(selfvariable.as(not null))
504
505 # Recursively goes into the nodes
506 if n_block != null then
507 n_block.generate_basic_blocks(ssa, basic_block.as(not null))
508 is_generated = true
509 end
510 end
511 end
512
513 redef class AExpr
514 # Generate recursively basic block for this expression
515 # *`ssa` An instance of the SSA class initialized with the enclosing `APropdef`
516 # *`old_block` A basic block not completely filled
517 # Return the last created block (the last block can be nested)
518 fun generate_basic_blocks(ssa: SSA, old_block: BasicBlock): BasicBlock
519 do
520 return old_block
521 end
522 end
523
524 redef class AVarFormExpr
525 # The original variable
526 var original_variable: nullable Variable = variable
527 end
528
529 redef class AVarExpr
530 redef fun generate_basic_blocks(ssa, old_block)
531 do
532 self.variable.as(not null).read_blocks.add(old_block)
533 old_block.variables.add(self.variable.as(not null))
534
535 self.variable.as(not null).original_variable = self.variable.as(not null)
536 # Save this read site in the block
537 old_block.read_sites.add(self)
538 old_block.variables_sites.add(self)
539
540 return old_block
541 end
542 end
543
544 redef class AVardeclExpr
545 redef fun generate_basic_blocks(ssa, old_block)
546 do
547 var decl = self.variable.as(not null)
548
549 # Add the corresponding variable to the enclosing mpropdef
550 ssa.propdef.variables.add(decl)
551
552 decl.original_variable = decl
553 decl.assignment_blocks.add(old_block)
554 old_block.variables.add(decl)
555
556 if self.n_expr != null then
557 self.variable.dep_exprs.add(self.n_expr.as(not null))
558 old_block = self.n_expr.generate_basic_blocks(ssa, old_block)
559 end
560
561 return old_block
562 end
563 end
564
565 redef class AVarAssignExpr
566 redef fun generate_basic_blocks(ssa, old_block)
567 do
568 self.variable.as(not null).assignment_blocks.add(old_block)
569 old_block.variables.add(self.variable.as(not null))
570 self.variable.as(not null).original_variable = self.variable.as(not null)
571
572 # Save this write site in the block
573 old_block.write_sites.add(self)
574 old_block.variables_sites.add(self)
575
576 ssa.propdef.variables.add(self.variable.as(not null))
577
578 return self.n_value.generate_basic_blocks(ssa, old_block)
579 end
580 end
581
582 redef class AVarReassignExpr
583 redef fun generate_basic_blocks(ssa, old_block)
584 do
585 self.variable.as(not null).assignment_blocks.add(old_block)
586 old_block.variables.add(self.variable.as(not null))
587 self.variable.as(not null).original_variable = self.variable.as(not null)
588
589 # Save this write site in the block
590 old_block.write_sites.add(self)
591 old_block.variables_sites.add(self)
592
593 ssa.propdef.variables.add(self.variable.as(not null))
594 return self.n_value.generate_basic_blocks(ssa, old_block)
595 end
596 end
597
598 redef class ABreakExpr
599 redef fun generate_basic_blocks(ssa, old_block)
600 do
601 # Finish the old block
602 old_block.last = self
603
604 return old_block
605 end
606 end
607
608 redef class AContinueExpr
609 redef fun generate_basic_blocks(ssa, old_block)
610 do
611 return old_block
612 end
613 end
614
615 redef class AReturnExpr
616 redef fun generate_basic_blocks(ssa, old_block)
617 do
618 # The return just set the current block and stop the recursion
619 if self.n_expr != null then
620 old_block = self.n_expr.generate_basic_blocks(ssa, old_block)
621
622 # Store the return expression in the dependences of the dedicated returnvar
623 if ssa.propdef isa AMethPropdef then
624 ssa.propdef.as(AMethPropdef).returnvar.dep_exprs.add(n_expr.as(not null))
625 end
626 end
627
628 old_block.last = self
629
630 return old_block
631 end
632 end
633
634 redef class AAssertExpr
635 redef fun generate_basic_blocks(ssa, old_block)
636 do
637 self.n_expr.generate_basic_blocks(ssa, old_block)
638
639 # The condition of the assert is the last expression of the previous block
640 old_block.last = self.n_expr
641
642 # The block if the assert fail
643 var block_false = new BasicBlock
644
645 if self.n_else != null then
646 block_false.first = self.n_else.as(not null)
647 block_false.last = self.n_else.as(not null)
648 self.n_else.generate_basic_blocks(ssa, block_false)
649 else
650 block_false.first = self
651 block_false.first = self
652 end
653
654 old_block.link(block_false)
655
656 # The block if the assert is true: the execution continue
657 var block_true = new BasicBlock
658 block_true.first = self
659 block_true.last = self
660
661 old_block.link(block_true)
662
663 return block_true
664 end
665 end
666
667 redef class AOrExpr
668 redef fun generate_basic_blocks(ssa, old_block)
669 do
670 self.n_expr.generate_basic_blocks(ssa, old_block)
671 return self.n_expr2.generate_basic_blocks(ssa, old_block)
672 end
673 end
674
675 redef class AImpliesExpr
676 redef fun generate_basic_blocks(ssa, old_block)
677 do
678 self.n_expr.generate_basic_blocks(ssa, old_block)
679 return self.n_expr2.generate_basic_blocks(ssa, old_block)
680 end
681 end
682
683 redef class AAndExpr
684 redef fun generate_basic_blocks(ssa, old_block)
685 do
686 self.n_expr.generate_basic_blocks(ssa, old_block)
687 return self.n_expr2.generate_basic_blocks(ssa, old_block)
688 end
689 end
690
691 redef class ANotExpr
692 redef fun generate_basic_blocks(ssa, old_block)
693 do
694 return self.n_expr.generate_basic_blocks(ssa, old_block)
695 end
696 end
697
698 redef class AOrElseExpr
699 redef fun generate_basic_blocks(ssa, old_block)
700 do
701 self.n_expr.generate_basic_blocks(ssa, old_block)
702 return self.n_expr2.generate_basic_blocks(ssa, old_block)
703 end
704 end
705
706 redef class AArrayExpr
707 redef fun generate_basic_blocks(ssa, old_block)
708 do
709 for nexpr in self.n_exprs do
710 old_block = nexpr.generate_basic_blocks(ssa, old_block)
711 end
712
713 return old_block
714 end
715 end
716
717 redef class ASuperstringExpr
718 redef fun generate_basic_blocks(ssa, old_block)
719 do
720 for nexpr in self.n_exprs do old_block = nexpr.generate_basic_blocks(ssa, old_block)
721
722 return old_block
723 end
724 end
725
726 redef class ACrangeExpr
727 redef fun generate_basic_blocks(ssa, old_block)
728 do
729 self.n_expr.generate_basic_blocks(ssa, old_block)
730 return self.n_expr2.generate_basic_blocks(ssa, old_block)
731 end
732 end
733
734 redef class AOrangeExpr
735 redef fun generate_basic_blocks(ssa, old_block)
736 do
737 self.n_expr.generate_basic_blocks(ssa, old_block)
738 return self.n_expr2.generate_basic_blocks(ssa, old_block)
739 end
740 end
741
742 redef class AIsaExpr
743 redef fun generate_basic_blocks(ssa, old_block)
744 do
745 return self.n_expr.generate_basic_blocks(ssa, old_block)
746 end
747 end
748
749 redef class AAsCastExpr
750 redef fun generate_basic_blocks(ssa, old_block)
751 do
752 return self.n_expr.generate_basic_blocks(ssa, old_block)
753 end
754 end
755
756 redef class AAsNotnullExpr
757 redef fun generate_basic_blocks(ssa, old_block)
758 do
759 return self.n_expr.generate_basic_blocks(ssa, old_block)
760 end
761 end
762
763 redef class AParExpr
764 redef fun generate_basic_blocks(ssa, old_block)
765 do
766 return self.n_expr.generate_basic_blocks(ssa, old_block)
767 end
768 end
769
770 redef class AOnceExpr
771 redef fun generate_basic_blocks(ssa, old_block)
772 do
773 return self.n_expr.generate_basic_blocks(ssa, old_block)
774 end
775 end
776
777 redef class ASendExpr
778 redef fun generate_basic_blocks(ssa, old_block)
779 do
780 # A call does not finish the current block,
781 # because we create intra-procedural basic blocks here
782
783 # Recursively goes into arguments to find variables if any
784 for e in self.raw_arguments do e.generate_basic_blocks(ssa, old_block)
785
786 return self.n_expr.generate_basic_blocks(ssa, old_block)
787 end
788 end
789
790 redef class ASendReassignFormExpr
791 redef fun generate_basic_blocks(ssa, old_block)
792 do
793 self.n_expr.generate_basic_blocks(ssa, old_block)
794
795 # Recursively goes into arguments to find variables if any
796 for e in self.raw_arguments do e.generate_basic_blocks(ssa, old_block)
797
798 return self.n_value.generate_basic_blocks(ssa, old_block)
799 end
800 end
801
802 redef class ASuperExpr
803 redef fun generate_basic_blocks(ssa, old_block)
804 do
805 # Recursively goes into arguments to find variables if any
806 for arg in self.n_args.n_exprs do arg.generate_basic_blocks(ssa, old_block)
807
808 return old_block
809 end
810 end
811
812 redef class ANewExpr
813 redef fun generate_basic_blocks(ssa, old_block)
814 do
815 for e in self.n_args.n_exprs do e.generate_basic_blocks(ssa, old_block)
816
817 return old_block
818 end
819 end
820
821 redef class AAttrExpr
822 redef fun generate_basic_blocks(ssa, old_block)
823 do
824 return self.n_expr.generate_basic_blocks(ssa, old_block)
825 end
826 end
827
828 redef class AAttrAssignExpr
829 redef fun generate_basic_blocks(ssa, old_block)
830 do
831 return self.n_expr.generate_basic_blocks(ssa, old_block)
832 end
833 end
834
835 redef class AAttrReassignExpr
836 redef fun generate_basic_blocks(ssa, old_block)
837 do
838 return self.n_expr.generate_basic_blocks(ssa, old_block)
839 end
840 end
841
842 redef class AIssetAttrExpr
843 redef fun generate_basic_blocks(ssa, old_block)
844 do
845 return self.n_expr.generate_basic_blocks(ssa, old_block)
846 end
847 end
848
849 redef class ABlockExpr
850 # The block needs to know if a new block is created
851 redef fun generate_basic_blocks(ssa, old_block)
852 do
853 var last_block = old_block
854 var current_block: BasicBlock
855
856 # Recursively continue in the body of the block
857 for i in [0..self.n_expr.length[ do
858 current_block = self.n_expr[i].generate_basic_blocks(ssa, last_block)
859
860 if current_block.need_update then
861 if i < (self.n_expr.length-1) then
862 # Current_block must be filled
863 current_block.first = self.n_expr[i+1]
864 current_block.last = self.n_expr[i+1]
865 current_block.need_update = false
866 else
867 # Put the current block at the end of the block
868 current_block.first = last_block.last
869 current_block.last = last_block.last
870 end
871 end
872
873 if not current_block.last isa AEscapeExpr or current_block.last isa AReturnExpr then
874 # Re-affected the last block
875 current_block.last = self.n_expr[i]
876 end
877
878 last_block = current_block
879 end
880
881 return last_block
882 end
883 end
884
885 redef class AIfExpr
886 redef fun generate_basic_blocks(ssa, old_block)
887 do
888 # Terminate the previous block
889 old_block.last = self
890
891 # We start two new blocks if the if has two branches
892 var block_then = new BasicBlock
893
894 # Visit the test of the if
895 self.n_expr.generate_basic_blocks(ssa, old_block)
896
897 # Launch the recursion in two successors if they exist
898 if self.n_then != null then
899 old_block.link(block_then)
900
901 block_then.first = self.n_then.as(not null)
902 block_then.last = self.n_then.as(not null)
903 self.n_then.generate_basic_blocks(ssa, block_then)
904 end
905
906 var block_else = new BasicBlock
907
908 if self.n_else != null then
909 old_block.link(block_else)
910
911 block_else.first = self.n_else.as(not null)
912 block_else.last = self.n_else.as(not null)
913 self.n_else.generate_basic_blocks(ssa, block_else)
914 end
915
916 # Create a new BasicBlock to represent the two successor
917 # branches of the if
918 var new_block = new BasicBlock
919 new_block.first = self
920 new_block.last = self
921
922 if self.n_then != null then block_then.link(new_block)
923
924 # The new block needs to be filled by the caller
925 new_block.need_update = true
926
927 if block_else.predecessors.length != 0 then block_else.link(new_block)
928
929 return new_block
930 end
931 end
932
933 redef class AIfexprExpr
934 redef fun generate_basic_blocks(ssa, old_block)
935 do
936 # Terminate the previous block
937 old_block.last = self
938
939 # We start two new blocks if the if has two branches
940 var block_then = new BasicBlock
941
942 # Visit the test of the if
943 self.n_expr.generate_basic_blocks(ssa, old_block)
944
945 # Launch the recursion in two successors if they exist
946 old_block.link(block_then)
947
948 block_then.first = self.n_then
949 block_then.last = self.n_then
950 self.n_then.generate_basic_blocks(ssa, block_then)
951
952 var block_else = new BasicBlock
953
954 old_block.link(block_else)
955
956 block_else.first = self.n_else
957 block_else.last = self.n_else
958 self.n_else.generate_basic_blocks(ssa, block_else)
959
960 # Create a new BasicBlock to represent the two successor
961 # branches of the if
962 var new_block = new BasicBlock
963 new_block.first = self
964 new_block.last = self
965
966 block_then.link(new_block)
967
968 # The new block needs to be filled by the caller
969 new_block.need_update = true
970
971 block_else.link(new_block)
972
973 return new_block
974 end
975 end
976
977 redef class ADoExpr
978 redef fun generate_basic_blocks(ssa, old_block)
979 do
980 old_block.last = self
981
982 # The beginning of the block is the first instruction
983 var block = new BasicBlock
984 block.first = self.n_block.as(not null)
985 block.last = self.n_block.as(not null)
986
987 old_block.link(block)
988 return self.n_block.generate_basic_blocks(ssa, block)
989 end
990 end
991
992 redef class AWhileExpr
993 redef fun generate_basic_blocks(ssa, old_block)
994 do
995 old_block.last = self
996
997 # The beginning of the block is the test of the while
998 var block = new BasicBlock
999 block.first = self.n_expr
1000 block.last = self.n_block.as(not null)
1001
1002 old_block.link(block)
1003
1004 self.n_expr.generate_basic_blocks(ssa, old_block)
1005 var inside_block = self.n_block.generate_basic_blocks(ssa, block)
1006
1007 # Link the inside of the block to the previous block
1008 block.link_special(old_block)
1009
1010 # Create a new Block after the while
1011 var new_block = new BasicBlock
1012 new_block.need_update = true
1013
1014 old_block.link_special(new_block)
1015
1016 return new_block
1017 end
1018 end
1019
1020 redef class ALoopExpr
1021 redef fun generate_basic_blocks(ssa, old_block)
1022 do
1023 old_block.last = self
1024
1025 # The beginning of the block is the first instruction
1026 var block = new BasicBlock
1027 block.first = self.n_block.as(not null)
1028 block.last = self.n_block.as(not null)
1029
1030 old_block.link(block)
1031 self.n_block.generate_basic_blocks(ssa, block)
1032
1033 return block
1034 end
1035 end
1036
1037 redef class AForExpr
1038 redef fun generate_basic_blocks(ssa, old_block)
1039 do
1040 old_block.last = self
1041
1042 # The beginning of the block is the first instruction
1043 var block = new BasicBlock
1044 block.first = self.n_expr
1045 block.last = self.n_block.as(not null)
1046
1047 # Visit the test of the if
1048 self.n_expr.generate_basic_blocks(ssa, block)
1049
1050 # Collect the variables declared in the for
1051 for v in variables do
1052 ssa.propdef.variables.add(v)
1053 end
1054
1055 old_block.link(block)
1056
1057 block.link(old_block)
1058
1059 var new_block = new BasicBlock
1060 new_block.need_update = true
1061
1062 return new_block
1063 end
1064 end