1b1994897Sopenharmony_ci# Panda Intermediate representation(IR) design
2b1994897Sopenharmony_ci
3b1994897Sopenharmony_ciThis document describes Panda IR design with the following goals  
4b1994897Sopenharmony_ci* Possibility to implement various optimizations and analyses  
5b1994897Sopenharmony_ci* Support all the features and instructions of Panda bytecode
6b1994897Sopenharmony_ci* Focus on ARM64 architecture
7b1994897Sopenharmony_ci* Compiler overhead about 100000 native instructions per a bytecode instruction(standard for JIT compilers)
8b1994897Sopenharmony_ci* Be able to convert to other IR and back
9b1994897Sopenharmony_ci
10b1994897Sopenharmony_ci## Optimizations and analyses
11b1994897Sopenharmony_ci
12b1994897Sopenharmony_ciIn the development process, it is very important to have auxiliary functionality for various code transformations and analyses. The structure of the IR should be as clear as possible and make it possible to implement various algorithms. The panda IR should contribute to this.  
13b1994897Sopenharmony_ciAlso in the compilation process, the order of execution of optimizations and analyses is very important. Firstly there are dependencies between different passes. Second, often some optimization creates a context for others.  
14b1994897Sopenharmony_ciThe first goal of the Panda IR to be able to change the order of the passes, add and delete passes(If 2 passes have a dependency we must take this into account). We should be able to  change the order of the passes by options.  
15b1994897Sopenharmony_ciSecond, we need to support the transfer of information between optimizations.  
16b1994897Sopenharmony_ci
17b1994897Sopenharmony_ci### List of the optimizations
18b1994897Sopenharmony_ci
19b1994897Sopenharmony_ci* [IrBuilder](../compiler/docs/ir_builder.md)
20b1994897Sopenharmony_ci* [BranchElimination](../compiler/docs/branch_elimination_doc.md)
21b1994897Sopenharmony_ci* [ChecksElimination](../compiler/docs/check_elimination_doc.md)
22b1994897Sopenharmony_ci* [Cleanup](../compiler/docs/cleanup_doc.md)
23b1994897Sopenharmony_ci* [Constant Folding](../compiler/docs/constant_folding_doc.md)
24b1994897Sopenharmony_ci* [Inlining](../compiler/docs/inlining.md)
25b1994897Sopenharmony_ci* Inlining
26b1994897Sopenharmony_ci* [LICM](../compiler/docs/licm_doc.md)
27b1994897Sopenharmony_ci* [Lowering](../compiler/docs/lowering_doc.md)
28b1994897Sopenharmony_ci* [Load Store Elimination (LSE)](../compiler/docs/lse_doc.md)
29b1994897Sopenharmony_ci* [Memory Coalescing](../compiler/docs/memory_coalescing_doc.md)
30b1994897Sopenharmony_ci* [Peepholes](../compiler/docs/peephole_doc.md)
31b1994897Sopenharmony_ci* [Value Numbering](../compiler/docs/vn_doc.md)
32b1994897Sopenharmony_ci
33b1994897Sopenharmony_ci### Analyses
34b1994897Sopenharmony_ci
35b1994897Sopenharmony_ci* Alias Analysis
36b1994897Sopenharmony_ci* Bounds Analysis
37b1994897Sopenharmony_ci* Domtree
38b1994897Sopenharmony_ci* Linear Order
39b1994897Sopenharmony_ci* Liveness Analysis
40b1994897Sopenharmony_ci* Monitor Analysis
41b1994897Sopenharmony_ci* Reverse Post Order(RPO)
42b1994897Sopenharmony_ci
43b1994897Sopenharmony_ci### Potential optimizations
44b1994897Sopenharmony_ci
45b1994897Sopenharmony_ciThe benefits of some optimizations are not obvious or do need profiling information to implement them. We will have them in mind, but will make the implementation, after performance analyzing the code.
46b1994897Sopenharmony_ci
47b1994897Sopenharmony_ci* Remove cold path
48b1994897Sopenharmony_ci* MAW(Memory access widening)/Merge memory
49b1994897Sopenharmony_ci* [Block duplication](https://en.wikipedia.org/wiki/Loop_unswitching)
50b1994897Sopenharmony_ci
51b1994897Sopenharmony_ci!NOTE It is possible to write other optimizations based on the specifics of the language and VM
52b1994897Sopenharmony_ci
53b1994897Sopenharmony_ci### The order of optimizations
54b1994897Sopenharmony_ci
55b1994897Sopenharmony_ciWe will try to make it possible to pass optimizations in an arbitrary order. Some restrictions will still be: register allocation and code generation at the end, inlining at the beginning. Some optimization(DCE, Peephole) will be called several times.  
56b1994897Sopenharmony_ci
57b1994897Sopenharmony_ci## Features
58b1994897Sopenharmony_ci
59b1994897Sopenharmony_ci* Using profile information for IFC and speculative optimizations
60b1994897Sopenharmony_ci* Supporting side exits for de-optimizations and removing cold code.
61b1994897Sopenharmony_ci* Converting to LLVM IR
62b1994897Sopenharmony_ci* Independence from Runtime(all profile and runtime information will be contained in a special class with default values)
63b1994897Sopenharmony_ci* Common properties will be introduced for the instructions, making it easier to add new instructions
64b1994897Sopenharmony_ci
65b1994897Sopenharmony_ci## Instruction set
66b1994897Sopenharmony_ci
67b1994897Sopenharmony_ciPanda IR needs to combine the properties of high and low level IRs.
68b1994897Sopenharmony_ci
69b1994897Sopenharmony_ciHigh level:
70b1994897Sopenharmony_ci
71b1994897Sopenharmony_ciPanda bytecode has more than 200 instructions. We need to convert all Bytecode instructions in IR instructions with minimal overhead(ideally one to one).  
72b1994897Sopenharmony_ciThe specifics and properties of instructions should be taken into account in optimizations and codegen.  
73b1994897Sopenharmony_ci
74b1994897Sopenharmony_ciLow level:
75b1994897Sopenharmony_ci
76b1994897Sopenharmony_ciThe main target is ARM64. So Panda IR should be able to do arm specific optimizations. For this, need to support ARMv8-M Instruction Set(only those instructions that are needed)
77b1994897Sopenharmony_ci
78b1994897Sopenharmony_ciProposal:
79b1994897Sopenharmony_ci
80b1994897Sopenharmony_ciIR contains high- and low-level instructions with a single interface. 
81b1994897Sopenharmony_ciIn the first step, Panda bytecode is converted to high level instruction and architecturally independent optimizations are made.  
82b1994897Sopenharmony_ciAt the second step, the instructions will be split on several low level instructions(close to assembler instructions) for additional optimizations.
83b1994897Sopenharmony_ci
84b1994897Sopenharmony_ci## Overhead
85b1994897Sopenharmony_ci
86b1994897Sopenharmony_ciOverhead is the time that requires for compile.  
87b1994897Sopenharmony_ciTypically, an overhead is considered to be the average number of 'native' instructions(ARM) that are spent compiling a single 'guest' instruction(from Bytecode).  
88b1994897Sopenharmony_ciThe more and more complex optimizations we do, the more overhead we get. We need to find a balance between performance and the overhead needed to achieve it. For example, the optimization [Unroll](https://en.wikipedia.org/wiki/Loop_unrolling) allows to remove unnecessary loop induction variables and dependencies between loop iterations, but it increases the size of the code that leads to increases overhead. We should apply this optimization only if the benefit from it exceeds the increase in overhead costs.  
89b1994897Sopenharmony_ci
90b1994897Sopenharmony_ciIn Ahead-Of-Time(AOT) mode the overhead is less critical for us, so we can do more optimizations.  
91b1994897Sopenharmony_ciIn Just-In-Time(JIT) mode need to strictly control the overhead to get the overall performance increase(time on compile + time on execution).
92b1994897Sopenharmony_ci
93b1994897Sopenharmony_ciThe goal is overhead about 100000 native instructions per guest (standard for JIT compilers)
94b1994897Sopenharmony_ci
95b1994897Sopenharmony_ci## Compatibility
96b1994897Sopenharmony_ci
97b1994897Sopenharmony_ciTo be able to integrate into existing compilers, as well as to compare efficiency, to need the ability to convert to Panda Ir and back.  
98b1994897Sopenharmony_ciThe converter from LLVM IR and back will allow using different LLVM optimizations.
99b1994897Sopenharmony_ci
100b1994897Sopenharmony_ci## IR structure
101b1994897Sopenharmony_ci
102b1994897Sopenharmony_ci### Rationale
103b1994897Sopenharmony_ci
104b1994897Sopenharmony_ciThe most of used IR in compilers: classical CFG(Control Flow Graph) with SSA(Static Single Assignment) form(used in LLVM, WebKit, HHVM, CoreCLR, IonMonkey) and Sea-of-Nodes(Hotspot, V8 Turbofan).
105b1994897Sopenharmony_ciWe decided to choose the CFG with SSA form for the following reasons:
106b1994897Sopenharmony_ci1. It is more common in compilers and easier to understand
107b1994897Sopenharmony_ci2. Sea-of-Nodes has a big overhead for IR constructing and scheduling phases, that makes impossible to make lightweight tier 1 (applying a small number of optimizations with minimal overhead for fast code generation)
108b1994897Sopenharmony_ci
109b1994897Sopenharmony_ci### Graph
110b1994897Sopenharmony_ci
111b1994897Sopenharmony_ciThe main class is a **Graph**. It contains all information for compiler such as: 
112b1994897Sopenharmony_ci * Information about the method for which transformations are made
113b1994897Sopenharmony_ci * pointer to RuntimeInterface - class with all Runtime information
114b1994897Sopenharmony_ci * Vector of pointers to **BasicBlocks**
115b1994897Sopenharmony_ci * Information about the current status(constructerd or not RPO, DomTree e.t.c)
116b1994897Sopenharmony_ci * Information to be transmitted between passes
117b1994897Sopenharmony_ci * Pass manager
118b1994897Sopenharmony_ci
119b1994897Sopenharmony_ciClass **Graph** allows creating new instructions, adding and removing blocks, constructing RPO, DomTree and e.t.c
120b1994897Sopenharmony_ci
121b1994897Sopenharmony_ci### BasicBlock
122b1994897Sopenharmony_ci
123b1994897Sopenharmony_ci**BasicBlock** is a class that describes a linear part of executable code. BasicBlock contains:
124b1994897Sopenharmony_ci * A double-linked list of instructions, which are contained in the block
125b1994897Sopenharmony_ci * List of predecessors: vector of pointers to the BasicBlocks from which we can get into the current block
126b1994897Sopenharmony_ci * List of successors: vector of pointers to the BasicBlocks in which we can get from the current block
127b1994897Sopenharmony_ci * Information about DomTree
128b1994897Sopenharmony_ci
129b1994897Sopenharmony_ciClass **BasicBlock** allows adding and removing instructions in the BasicBlock, adding and removing successors and predecessors, getting dominate block and dominated blocks e.t.c
130b1994897Sopenharmony_ciThe Graph always begins from **start** BasicBlock and finishes **end** BasicBlock.  
131b1994897Sopenharmony_ci**Start** BasicBlock doesn't have predecessors and have one successor. Only SafePoint, Constants and Parameter instructions can be contained in start BasicBlock.  
132b1994897Sopenharmony_ci**End** BasicBlock doesn't have successors and doesn't contain instructions.  
133b1994897Sopenharmony_ci
134b1994897Sopenharmony_ci**BasicBlock** can not have more than one incoming or outgoing edges into the same block.
135b1994897Sopenharmony_ciWhen control flow look like that, we must keep an empty block on the edge. Left graph can not be optimized to right one when block 3 have no instructions.
136b1994897Sopenharmony_ci
137b1994897Sopenharmony_ci```
138b1994897Sopenharmony_ci      [1]           [1]
139b1994897Sopenharmony_ci      |  \          |  \
140b1994897Sopenharmony_ci      |  [3]  -x->  |   |
141b1994897Sopenharmony_ci      |  /          |  /
142b1994897Sopenharmony_ci      [2]           [2]
143b1994897Sopenharmony_ci
144b1994897Sopenharmony_ci```
145b1994897Sopenharmony_ci
146b1994897Sopenharmony_ciEmpty blocks pass covers this situation and do not remove such an empty block when there are `Phi` instructions in block 2 with different inputs from those incoming edges. When there are no such `Phi`s we can easily remove the second edge too.
147b1994897Sopenharmony_ci
148b1994897Sopenharmony_ciAnother solution may be to introduce `Select` instructions on early stage. Third solution is to keep special `Mov` instructions in block 3, but this contradicts to SSA form ideas and experiments show that this is less effective, as we keep to much `Mov`-only blocks.
149b1994897Sopenharmony_ci
150b1994897Sopenharmony_ci| Bench | Empty Blocks | Mov-Blocks |
151b1994897Sopenharmony_ci| ------ | ------ | ------ |
152b1994897Sopenharmony_ci| access-fannkuch-c2p | 0 | 1 |
153b1994897Sopenharmony_ci| math-spectral-norm-c2p | 0 | 1 |
154b1994897Sopenharmony_ci| bitops-bitwise-and-c2p | 0 | 0 |
155b1994897Sopenharmony_ci| bitops-bits-in-byte-c2p | 0 | 1 |
156b1994897Sopenharmony_ci| bitops-3bit-bits-in-byte-c2p | 0 | 1 |
157b1994897Sopenharmony_ci| access-nsieve-c2p | 0 | 1 |
158b1994897Sopenharmony_ci| controlflow-recursive-c2p | 0 | 25 |
159b1994897Sopenharmony_ci| 3d-morph-c2p  | 0 | 3 |
160b1994897Sopenharmony_ci| math-partial-sums | 1 | 1 |
161b1994897Sopenharmony_ci| controlflow-recursive | 1 | 86 |
162b1994897Sopenharmony_ci| bitops-nsieve-bits | 1 | 2 |
163b1994897Sopenharmony_ci| access-binary-trees | 3 | 4 |
164b1994897Sopenharmony_ci| access-nbody | 1 | 11 |
165b1994897Sopenharmony_ci| 3d-morph | 1 | 3 |
166b1994897Sopenharmony_ci| access-fannkuch | 1 | 2 |
167b1994897Sopenharmony_ci| access-nsieve | 1 | 2 |
168b1994897Sopenharmony_ci| bitops-3bit-bits-in-byte | 1 | 3 |
169b1994897Sopenharmony_ci| bitops-bits-in-byte | 1 | 3 |
170b1994897Sopenharmony_ci| math-spectral-norm  | 1 | 4 |
171b1994897Sopenharmony_ci| bitops-bitwise-and | 0 | 0 |
172b1994897Sopenharmony_ci| math-cordic  | 1 | 2 |
173b1994897Sopenharmony_ci
174b1994897Sopenharmony_ci### Instructions
175b1994897Sopenharmony_ci
176b1994897Sopenharmony_ciInstructions are implemented by class inheritance.
177b1994897Sopenharmony_ci
178b1994897Sopenharmony_ci**Inst** is a base class with main information about an instruction.
179b1994897Sopenharmony_ci * Opcode(name) of the instruction
180b1994897Sopenharmony_ci * pc(address) instruction in bytecode/file
181b1994897Sopenharmony_ci * Type of instruction(bool, uint8, uint32, float, double e.t.c)
182b1994897Sopenharmony_ci * Pointers to next and previous  Inst in the BasicBlock
183b1994897Sopenharmony_ci * Array of inputs (instructions whose result this Inst uses)(class Inst has virtual method that returns empty array. Derived classes override this method and return non empty array)
184b1994897Sopenharmony_ci * List of users (instructions which use result from the Inst)
185b1994897Sopenharmony_ci * Properties
186b1994897Sopenharmony_ci
187b1994897Sopenharmony_ciClass **Inst** allows adding and removing users and inputs
188b1994897Sopenharmony_ci
189b1994897Sopenharmony_ciClass **FixedInputsInst** inherits from **Inst** for instruction with a fixed number of inputs(operands).  
190b1994897Sopenharmony_ciClass **DynamicInputsInst** inherits from **Inst** for instruction with a variable number of inputs(operands).  
191b1994897Sopenharmony_ciClass **CompareInst** inherits from **Inst** for instruction with predicate. It contain information about type of conditional code(EQ, NE, LT, LE and e.t.c).  
192b1994897Sopenharmony_ciClass **ConstantInst** inherits from **Inst** for constant instruction. It contains a constant and type of the constant. Constants are contained only in start block.   
193b1994897Sopenharmony_ciClass **ParameterInst** inherits from **Inst** for input parameter. It contains a type of parameter and parameter number. Parameters are contained only in start block.   
194b1994897Sopenharmony_ciClass **UnaryOperation** inherits from **FixedInputsInst** for instruction with a single input. The class is used for instructions NOT, NEG, ABS e.t.c.  
195b1994897Sopenharmony_ciClass **BinaryOperation** inherits from **FixedInputsInst** for instruction with two inputs. The class is used for instructions ADD, SUB, MUL e.t.c.  
196b1994897Sopenharmony_ci
197b1994897Sopenharmony_ciClass **CallInst** inherits from **DynamicInputsInst** for call instructions.  
198b1994897Sopenharmony_ciClass **PhiInst** inherits from **DynamicInputsInst** for phi instructions.   
199b1994897Sopenharmony_ci
200b1994897Sopenharmony_ci#### Mixin
201b1994897Sopenharmony_ci
202b1994897Sopenharmony_ci**Mixin** are classes with properties or data which uses different instruction classes. For example:
203b1994897Sopenharmony_ci
204b1994897Sopenharmony_ci**ImmediateMixin** is inherited in instruction classes with immediate(BinaryImmOperation, ReturnInstI and so on)  
205b1994897Sopenharmony_ci**ConditionMixin** is inherited in instruction classes with conditional code(CompareInst, SelectInst, IfInst and so on)  
206b1994897Sopenharmony_ci**TypeIdMixin** is inherited in instruction classes wich uses TypeId(LoadObjectInst, StoreObjectInst, NewObjectInst and so on)  
207b1994897Sopenharmony_ci
208b1994897Sopenharmony_ci#### Constant instruction
209b1994897Sopenharmony_ci
210b1994897Sopenharmony_ciConstant instructions(**ConstantInst**) can have type FLOAT32, FLOAT64 and INT64. Constants all integer types and reference saves as INT64. All integer instructions can have constant input with INT64 type.
211b1994897Sopenharmony_ciAll constants instruction are contaned in **Start BasicBlock**. There are not two equal constant(equal value and type) in Graph. The Graph function *indOrCreateConstant* is used for adding constant in Graph. 
212b1994897Sopenharmony_ci
213b1994897Sopenharmony_ci#### Parameter instruction
214b1994897Sopenharmony_ci
215b1994897Sopenharmony_ciParameter instruction(**ParameterInst**) contain a type of parameter and parameter number. Parameters are contained only in  **Start BasicBlock**. The Graph function *AddNewParameter* is used for adding parameter in Graph. 
216b1994897Sopenharmony_ci
217b1994897Sopenharmony_ci#### instruction.yaml
218b1994897Sopenharmony_ci
219b1994897Sopenharmony_ci**instruction.yaml** contains next information for each instruction:
220b1994897Sopenharmony_ci* Opcode
221b1994897Sopenharmony_ci* class
222b1994897Sopenharmony_ci* signature(supported type of inputs and type of destination for the instruction)
223b1994897Sopenharmony_ci* flags
224b1994897Sopenharmony_ci* description
225b1994897Sopenharmony_ci
226b1994897Sopenharmony_ci**instruction.yaml** is used for generating instructions and describing them. 
227b1994897Sopenharmony_ci
228b1994897Sopenharmony_ci!NOTE **instruction.yaml** isn't used for generating checks for instruction. We plan to support this.
229b1994897Sopenharmony_ci
230b1994897Sopenharmony_ci### Exceptions
231b1994897Sopenharmony_ci
232b1994897Sopenharmony_ciDetails: (../compiler/docs/try_catch_blocks_ir.md)
233b1994897Sopenharmony_ci 
234b1994897Sopenharmony_ci## Reverse Post Order(RPO) tree
235b1994897Sopenharmony_ci
236b1994897Sopenharmony_ci**RPO** builds blocks list for reverse post-order traversal. In RPO iteration, a BasicBlock is visited before any of its successor BasicBlocks has been visited, except when the successor is reached by a back edge. **RPO** is implemented as a separate class, which returns the vector of pointers to BasicBlocks for the Graph.  There is an option to invalidate the vector. In this case, the vector will be built from scratch after the next request for it(if the option to invalidate isn't set, the current RPO vector is returned). RPO is invalidated after Control Flow transformations: removing or adding blocks or edges between blocks. Also, it provides methods for updating an existing tree.
237b1994897Sopenharmony_ci
238b1994897Sopenharmony_ciClass **RPO** allows constructing RPO vector, adding or removing blocks to the vector.
239b1994897Sopenharmony_ci
240b1994897Sopenharmony_ci## DomTree building
241b1994897Sopenharmony_ci
242b1994897Sopenharmony_ciA BasicBlock "A" dominates a BasicBlock "B" if every path from the "start" to "B" must go through "A".
243b1994897Sopenharmony_ci**DomTree** is implemented as a separate class, but it makes only constructing the tree. The Dominator tree itself is stored in class **BasicBlock**. Each BasicBlock has a pointer on dominate block and vector of pointers to blocks which he dominates. **BasicBlock** has function changing the dominate block and the vector(adding, removing). As in the case of
244b1994897Sopenharmony_ci **RPO**, class **DomTree** has an option to invalidate the tree, but unlike **RPO**, the tree rebuilding doesn't happen automatically, the developer has to monitor it himself and call the construct function if necessary.
245b1994897Sopenharmony_ci
246b1994897Sopenharmony_ci## Instruction Iterators
247b1994897Sopenharmony_ci
248b1994897Sopenharmony_ciThe block instructions form a doubly linked list. At the beginning are Phi instructions, and then all the rest.
249b1994897Sopenharmony_ci**Iteration** over instructions can be passed in direct/reverse order. ‘IterationType’ defines instructions that are iterated: phi-instructions, non-phi-instructions or all instructions. “SafeIterator“ is keeping the next instruction in case of removing current instruction. 
250b1994897Sopenharmony_ciList of the **iterators**: *PhiInstIter*, *InstIter*, *AllInstIter*, *InstReverseIter*, *PhiInstSafeIter*, *InstSafeIter*, *AllInstSafeIter*, *PhiInstSafeReverseIter*, *InstSafeReverseIter*, *AllInstSafeReverseIter*
251b1994897Sopenharmony_ci
252b1994897Sopenharmony_ci## Data Flow Graph
253b1994897Sopenharmony_ci
254b1994897Sopenharmony_ciData flow graph is widely used by almost all optimizations, therefore it greatly affects overhead of the JIT. The most basic and frequent use is an iterating over inputs or users. One of the approaches to make iterating more effective is to store data in sequence container, such as array or vector, thereby elements much more likely will be in the processor cache.
255b1994897Sopenharmony_ci
256b1994897Sopenharmony_ci**User** of the instruction is an object that points to the consumer instruction and its corresponding input.
257b1994897Sopenharmony_ci
258b1994897Sopenharmony_ci**Input** is the object that describes which instruction defines value for corresponding operand of the owned instruction.
259b1994897Sopenharmony_ci
260b1994897Sopenharmony_ciInstructions can have various count of users and this count doesn't depend on the instruction type. Therefore storing users in sequence container has one big drawback - frequent storage reallocation, that leads to memory fragmentation (IR uses arena allocator) and additional overhead.
261b1994897Sopenharmony_ci
262b1994897Sopenharmony_ciOn the other hand, inputs depend on instruction type and mostly have fixed count. Thus, they should be stored in sequence container.
263b1994897Sopenharmony_ci
264b1994897Sopenharmony_ciFollowing scheme shows how Panda JIT organizes inputs and users in the memory:
265b1994897Sopenharmony_ci
266b1994897Sopenharmony_ci![def-use structure](images/def-use-structure.png)
267b1994897Sopenharmony_ci
268b1994897Sopenharmony_ciThere are two types of def-use storage: in memory right before instruction class and in separate memory chunk.
269b1994897Sopenharmony_ci- First case is used in instructions with fixed number of inputs. Storage is allocated right before instruction object and it is never reallocated. Most instructions belongs to this category.
270b1994897Sopenharmony_ci- Second category is the instructions with dynamic number of inputs, such as Phi instructions. Its def-use storage is allocated separately from instruction object, both storage and instruction are coupled by pointers to each other. In case when new input is appended and the capacity of the storage is equal to its size, whole storage is reallocated. This behavior is exactly similar to classical vector implementations. This brings additional amortized complexity to this category.
271b1994897Sopenharmony_ci
272b1994897Sopenharmony_ciBoth, user and input have properties field that have following information:
273b1994897Sopenharmony_ci- index of input/user
274b1994897Sopenharmony_ci- overall number of inputs
275b1994897Sopenharmony_ci- flag that shows whether storage is dynamic
276b1994897Sopenharmony_ci- additional info about input:
277b1994897Sopenharmony_ci  1. if instruction is SaveState: virtual register number
278b1994897Sopenharmony_ci  2. if instruction is Phi: number of basic block predecessor edge
279b1994897Sopenharmony_ci
280b1994897Sopenharmony_ciWith this field it is possible to get instruction that owns given user or input.
281b1994897Sopenharmony_ci
282b1994897Sopenharmony_ciThis kind of storage have been chosen because it avoids usage of virtual methods and dynamic containers for all instruction. Instead, each access to def-use structures is just checking whether storage is dynamic and further processing of the corresponding type of def-use storage. Instead of indirect call we have one condition branch which has good branch prediction, because of most instructions have fixed number of inputs.
283b1994897Sopenharmony_ci
284b1994897Sopenharmony_ci## Visitor
285b1994897Sopenharmony_ci
286b1994897Sopenharmony_ciClass **GraphVisitor** allows to go through the blocks of the graph in RPO order and then all the instructions of the block. At the same time Visit functions are called by the opcode of the instruction or by its group affiliation.  
287b1994897Sopenharmony_ci
288b1994897Sopenharmony_ci## Pass manager
289b1994897Sopenharmony_ci
290b1994897Sopenharmony_ci!TODO Sherstennikov Mikhail add description 
291b1994897Sopenharmony_ci
292b1994897Sopenharmony_ci## Lowering
293b1994897Sopenharmony_ci
294b1994897Sopenharmony_ci**Lowering pass** makes low level instructions(which are more close to machine code).  
295b1994897Sopenharmony_ciSome instructions may not appear before this pass. But at the moment we do not have any checks on this
296b1994897Sopenharmony_ci
297b1994897Sopenharmony_ci## Register allocation
298b1994897Sopenharmony_ci
299b1994897Sopenharmony_ciRegister allocation is a process of assigning CPU registers to instructions.  
300b1994897Sopenharmony_ciThere are 2 based algorithm: Graph-coloring allocation(by Gregory John Chaitin) and Linear Scan(by Massimiliano Poletto)
301b1994897Sopenharmony_ciWe use "Linear Scan" algorithm because it has less overhead(the graph coloring algorithm having a quadratic cost).  
302b1994897Sopenharmony_ci
303b1994897Sopenharmony_ciIn the future, we plan to implement Graph-coloring algorithm, because it gives better code, and select the type of allocator depending on the context.  
304b1994897Sopenharmony_ci
305b1994897Sopenharmony_ci## Code generator
306b1994897Sopenharmony_ci
307b1994897Sopenharmony_ciCode generation is a complex process that converts IR code into the machine code.  
308b1994897Sopenharmony_ciAt the moment, we consider Arm64 as the main architecture.  
309b1994897Sopenharmony_ciWe chose the standard vixl library for сode generation to make implementation faster and avoid possible errors.  
310b1994897Sopenharmony_ciThe vixl-library created by ARM-developers for easy implement assembly-generation and emulation. 
311b1994897Sopenharmony_ciIt is used in HHVM, IonMonkey, DartVM and proved its reliability.
312b1994897Sopenharmony_ci
313b1994897Sopenharmony_ciIn the future, we plan to make fully own implementation for more optimal code generation(in terms of overhead and performance).
314b1994897Sopenharmony_ci
315b1994897Sopenharmony_ci!TODO Gorban Igor update description
316b1994897Sopenharmony_ci
317b1994897Sopenharmony_ci## Example of use
318b1994897Sopenharmony_ci
319b1994897Sopenharmony_ci### Create Graph
320b1994897Sopenharmony_ci
321b1994897Sopenharmony_ci```
322b1994897Sopenharmony_ciGraph* graph = new (allocator) Graph(&allocator_, panda_file_, /*method_idx*/ -1, /*is_arm64*/ true);
323b1994897Sopenharmony_ci```
324b1994897Sopenharmony_ci
325b1994897Sopenharmony_ci### Create blocks and CFG
326b1994897Sopenharmony_ci
327b1994897Sopenharmony_ci```
328b1994897Sopenharmony_ciBasicBlock* start = graph->CreateStartBlock();
329b1994897Sopenharmony_ciBasicBlock* end = graph->CreateEndBlock();
330b1994897Sopenharmony_ciBasicBlock* block = graph->CreateEmptyBlock();
331b1994897Sopenharmony_ci
332b1994897Sopenharmony_cistart->AddSucc(block);
333b1994897Sopenharmony_ciblock->AddSucc(end);
334b1994897Sopenharmony_ciblock->AddSucc(block);
335b1994897Sopenharmony_ci```
336b1994897Sopenharmony_ci
337b1994897Sopenharmony_ci### Create instruction and add in a block
338b1994897Sopenharmony_ci
339b1994897Sopenharmony_ci```
340b1994897Sopenharmony_ciConstantInst* constant = graph->FindOrCreateConstant(value);
341b1994897Sopenharmony_ciParameterInst* param = graph->AddNewParameter(slot_num, type);
342b1994897Sopenharmony_ciInst* phi1 = graph->CreateInst(Opcode::Phi);
343b1994897Sopenharmony_ciInst* ph2 = graph->CreateInst(Opcode::Phi);
344b1994897Sopenharmony_ciInst* compare = graph->CreateInst(Opcode::Compare);
345b1994897Sopenharmony_ciInst* add = graph->CreateInst(Opcode::Add);
346b1994897Sopenharmony_ciblock->AppendPhi(phi1);
347b1994897Sopenharmony_ciblock->AppendInst(compare);
348b1994897Sopenharmony_ciblock->InsertAfter(phi2, phi1);
349b1994897Sopenharmony_ciblock->InsertBefore(add, compare);
350b1994897Sopenharmony_ci
351b1994897Sopenharmony_cifor (auto inst : block->PhiInsts()) {
352b1994897Sopenharmony_ci    ASSERT(inst->GetOpcode() == Opcode::Phi)
353b1994897Sopenharmony_ci    ......
354b1994897Sopenharmony_ci}
355b1994897Sopenharmony_cifor (auto inst : block->Insts()) {
356b1994897Sopenharmony_ci    ASSERT(inst->GetOpcode() != Opcode::Phi)
357b1994897Sopenharmony_ci    ......
358b1994897Sopenharmony_ci}
359b1994897Sopenharmony_cifor (auto inst : block->AllInsts()) {
360b1994897Sopenharmony_ci    ......
361b1994897Sopenharmony_ci}
362b1994897Sopenharmony_cifor (auto inst : block->InstsSafe()) {
363b1994897Sopenharmony_ci    if (inst->GetOpcode() == Opcode::Add) {
364b1994897Sopenharmony_ci        block->EraseInst(inst);
365b1994897Sopenharmony_ci    }
366b1994897Sopenharmony_ci}
367b1994897Sopenharmony_ci```
368b1994897Sopenharmony_ci
369b1994897Sopenharmony_ci### Visitors:
370b1994897Sopenharmony_ci
371b1994897Sopenharmony_ci```
372b1994897Sopenharmony_ci struct ExampleVisitor: public GraphVisitor {
373b1994897Sopenharmony_ci     using GraphVisitor::GraphVisitor;
374b1994897Sopenharmony_ci
375b1994897Sopenharmony_ci     // Specify blocks to visit and their order
376b1994897Sopenharmony_ci     const ArenaVector<BasicBlock *> &GetBlocksToVisit() const override
377b1994897Sopenharmony_ci     {
378b1994897Sopenharmony_ci         return GetGraph()->GetBlocksRPO();
379b1994897Sopenharmony_ci     }
380b1994897Sopenharmony_ci     // Print special message for Mul instruction
381b1994897Sopenharmony_ci     static void VisitMul(GraphVisitor* v, Inst* inst) {
382b1994897Sopenharmony_ci         std::cerr << "Multiply instruction\n";
383b1994897Sopenharmony_ci     }
384b1994897Sopenharmony_ci     // For all other instructions print its opcode
385b1994897Sopenharmony_ci     void VisitDefault(Inst* inst) override {
386b1994897Sopenharmony_ci         std::cerr << OPCODE_NAMES[(int)inst->GetOpcode()] << std::endl;
387b1994897Sopenharmony_ci     }
388b1994897Sopenharmony_ci     // Visitor for all instructions which are the instance of the BinaryOperation
389b1994897Sopenharmony_ci     void VisitInst(BinaryOperation* inst) override {
390b1994897Sopenharmony_ci         std::cerr << "Visit binary operation\n";
391b1994897Sopenharmony_ci     }
392b1994897Sopenharmony_ci     #include "visitor.inc"
393b1994897Sopenharmony_ci};
394b1994897Sopenharmony_ci....
395b1994897Sopenharmony_ci    ExampleVisitor visitor(graph);
396b1994897Sopenharmony_ci    visitor.VisitGraph();
397b1994897Sopenharmony_ci```
398b1994897Sopenharmony_ci
399b1994897Sopenharmony_ci
400