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