1b1994897Sopenharmony_ci# Irtoc tool 2b1994897Sopenharmony_ci 3b1994897Sopenharmony_ci**Irtoc**(Ir-To-Code) tool is aimed to compile a manually created IR (intermediate representation) to the target code. 4b1994897Sopenharmony_ci 5b1994897Sopenharmony_ciBuilding flow: 6b1994897Sopenharmony_ci 7b1994897Sopenharmony_ci 8b1994897Sopenharmony_ci 9b1994897Sopenharmony_ci## Irtoc language 10b1994897Sopenharmony_ci 11b1994897Sopenharmony_ci> WARNING: this part is still under development. Thus, some things may be changed in the final implementation. 12b1994897Sopenharmony_ci 13b1994897Sopenharmony_ciIrtoc DSL is a wrapper above the `IrConstructor`. It reads compiler's `instructions.yaml` file to get information about instructions. As output it generates c++ code, that uses `IrConstructor` to build IR. 14b1994897Sopenharmony_ci 15b1994897Sopenharmony_ciEach opcode in the IR instructions has corresponding token in the irtoc lang. For example, IR instruction `Add`: 16b1994897Sopenharmony_ci``` 17b1994897Sopenharmony_ci - opcode: Add 18b1994897Sopenharmony_ci base: BinaryOperation 19b1994897Sopenharmony_ci signature: [d-number, number, number] 20b1994897Sopenharmony_ci flags: [commutative, acc_write, acc_read, ifcvt] 21b1994897Sopenharmony_ci description: Add two inputs. 22b1994897Sopenharmony_ci``` 23b1994897Sopenharmony_cihas keyword with the same name `Add` and with same signature: 24b1994897Sopenharmony_ci``` 25b1994897Sopenharmony_civar = Add(input1, input2) 26b1994897Sopenharmony_ci``` 27b1994897Sopenharmony_ci 28b1994897Sopenharmony_ciAll property setters that IrConstructor provides (`i64`, `bool`, `Pc`, `CC`, etc) are 29b1994897Sopenharmony_ciavailable in Irtoc lang. They can be set in the similar way as in the IrConstructor: 30b1994897Sopenharmony_ci``` 31b1994897Sopenharmony_civar = Add(input1, input2).i64.CC(:CC_GE).pc(123) 32b1994897Sopenharmony_ci``` 33b1994897Sopenharmony_ci### Pseudo instructions 34b1994897Sopenharmony_ciPseudo instructions are not a real IR instructions in terms of compiler, those instructions are needed only as helpers 35b1994897Sopenharmony_cifor Irtoc. For example, for creating a control flow: Label, Else, While. 36b1994897Sopenharmony_ci 37b1994897Sopenharmony_ciPseudo instructions are described like regular instructions in the `instructions.yaml` file, but in the separate section `pseudo_instructions`. 38b1994897Sopenharmony_ci 39b1994897Sopenharmony_ci### Data flow 40b1994897Sopenharmony_ci 41b1994897Sopenharmony_ciIn last example variable `var` holds the newly created instruction `Add` and it can be input for the further instructions. 42b1994897Sopenharmony_ciThus, dataflow is constructing like in other general-purpose language: assign variable - use variable: 43b1994897Sopenharmony_ci``` 44b1994897Sopenharmony_civar = Add(input1, input2).i64.CC(:CC_GE).pc(123) 45b1994897Sopenharmony_ciReturn(var).i64 46b1994897Sopenharmony_ci``` 47b1994897Sopenharmony_ciAlso it is possible to omit variables and create instruction in-place: 48b1994897Sopenharmony_ci``` 49b1994897Sopenharmony_ciReturn(Add(input1, input2).i64.CC(:CC_GE).pc(123)).i64 50b1994897Sopenharmony_ci``` 51b1994897Sopenharmony_ci 52b1994897Sopenharmony_ci### Control flow 53b1994897Sopenharmony_ci 54b1994897Sopenharmony_ciIrtoc uses instruction `If` and pseudo instruction `Else` to express conditional execution. 55b1994897Sopenharmony_ci 56b1994897Sopenharmony_ciFor example, add 1 to the biggest value: 57b1994897Sopenharmony_ci``` 58b1994897Sopenharmony_cifunction TestIncMaxValue(params: {a: i64, b: i64}) { 59b1994897Sopenharmony_ci If(a, b).CC(:CC_GE) { 60b1994897Sopenharmony_ci v1 = Add(a, 1).i64 61b1994897Sopenharmony_ci } Else { 62b1994897Sopenharmony_ci v2 = Add(b, 1).i64 63b1994897Sopenharmony_ci } 64b1994897Sopenharmony_ci phi = Phi(v1, v2) 65b1994897Sopenharmony_ci Return(phi).i64 66b1994897Sopenharmony_ci} 67b1994897Sopenharmony_ci``` 68b1994897Sopenharmony_ci 69b1994897Sopenharmony_ciAfter automatic phi insertion will be implemented: 70b1994897Sopenharmony_ci``` 71b1994897Sopenharmony_cifunction TestIncMaxValue(params: {a: i64, b: i64}) { 72b1994897Sopenharmony_ci If(a, b).CC(:CC_GE) { 73b1994897Sopenharmony_ci v = Add(a, 1).i64 74b1994897Sopenharmony_ci } Else { 75b1994897Sopenharmony_ci v = Add(b, 1).i64 76b1994897Sopenharmony_ci } 77b1994897Sopenharmony_ci Return(v).i64 78b1994897Sopenharmony_ci} 79b1994897Sopenharmony_ci``` 80b1994897Sopenharmony_ci 81b1994897Sopenharmony_ci`While` statement has the following semantic: 82b1994897Sopenharmony_ci``` 83b1994897Sopenharmony_cifunction SumSequence(params: {start: u64, end: u64}) { 84b1994897Sopenharmony_ci res = 0 85b1994897Sopenharmony_ci While (start, end).cc(ne) { 86b1994897Sopenharmony_ci res = Add(res, start) 87b1994897Sopenharmony_ci start = Add(start, 1) 88b1994897Sopenharmony_ci } 89b1994897Sopenharmony_ci 90b1994897Sopenharmony_ci Return.u32(res) 91b1994897Sopenharmony_ci} 92b1994897Sopenharmony_ci``` 93b1994897Sopenharmony_ci 94b1994897Sopenharmony_ciUsing labels: 95b1994897Sopenharmony_ci 96b1994897Sopenharmony_ci``` 97b1994897Sopenharmony_cifunction SumSequence(params: {start: u64, end: u64}) { 98b1994897Sopenharmony_ci res = 0 99b1994897Sopenharmony_ci 100b1994897Sopenharmony_ci Label(head) 101b1994897Sopenharmony_ci If (start, end).cc(ne) { 102b1994897Sopenharmony_ci Goto(exit) 103b1994897Sopenharmony_ci } 104b1994897Sopenharmony_ci 105b1994897Sopenharmony_ci res = Add(res, start) 106b1994897Sopenharmony_ci start = Add(start, 1) 107b1994897Sopenharmony_ci Goto(head) 108b1994897Sopenharmony_ci 109b1994897Sopenharmony_ci Label(exit) 110b1994897Sopenharmony_ci 111b1994897Sopenharmony_ci Return.u32(res) 112b1994897Sopenharmony_ci} 113b1994897Sopenharmony_ci``` 114b1994897Sopenharmony_ci 115b1994897Sopenharmony_ci## Dedicated registers 116b1994897Sopenharmony_ci 117b1994897Sopenharmony_ciSometimes there will be need to specify target register for the input parameter or other entities within a script. 118b1994897Sopenharmony_ci 119b1994897Sopenharmony_ciFor such needs, each function takes registers map as an input: 120b1994897Sopenharmony_ci``` 121b1994897Sopenharmony_ciregmap_tls = {ARM64: {tr: 28}, 122b1994897Sopenharmony_ci ARM32: {tr: 12}, 123b1994897Sopenharmony_ci X86_64: {tr: 15}} 124b1994897Sopenharmony_cifunction CallEntrypoint(params: {offset: u64, tls: ptr(tr)}, regmap=regmap_tls) { 125b1994897Sopenharmony_ci entry = Load(tr, offset) 126b1994897Sopenharmony_ci Call(entry) 127b1994897Sopenharmony_ci} 128b1994897Sopenharmony_ci``` 129b1994897Sopenharmony_ciIt will be transformed to the folloiwng code for Arm64 target: 130b1994897Sopenharmony_ci``` 131b1994897Sopenharmony_ciCOMPILE(CallEntrypoint) { 132b1994897Sopenharmony_ci GRAPH(GetGraph()) { 133b1994897Sopenharmony_ci PARAMETER(0, 1).u64(); 134b1994897Sopenharmony_ci PARAMETER(1, 1).ptr().DstReg(28); // for x86 will be `.DstReg(15)` 135b1994897Sopenharmony_ci ... 136b1994897Sopenharmony_ci } 137b1994897Sopenharmony_ci} 138b1994897Sopenharmony_ci``` 139b1994897Sopenharmony_ciSo, 28 register will be reserved for the life interval started by the second parameter. 140