_a2a_selfhost_binop.nx source
↩ module page · 142 lines · 4271 B
1// Self-host pipeline exercising binary operators.
2// Source: `func main() -> i64 { return 2 + 3 * 4 }`
3// Expected: IR with CONST_I64(2), CONST_I64(3), CONST_I64(4), MUL, ADD, RETURN
4
5import "syscalls.nx"
6import "nx_nlex.nx"
7import "nx_nparse.nx"
8import "nx_nir.nx"
9import "nx_nx86.nx"
10
11func main() -> i64 {
12 let src: *u8 = sys_mmap(64)
13 src[0] = 102 as u8 // f
14 src[1] = 117 as u8
15 src[2] = 110 as u8
16 src[3] = 99 as u8
17 src[4] = 32 as u8
18 src[5] = 109 as u8
19 src[6] = 97 as u8
20 src[7] = 105 as u8
21 src[8] = 110 as u8
22 src[9] = 40 as u8
23 src[10] = 41 as u8
24 src[11] = 32 as u8
25 src[12] = 45 as u8
26 src[13] = 62 as u8
27 src[14] = 32 as u8
28 src[15] = 105 as u8
29 src[16] = 54 as u8
30 src[17] = 52 as u8
31 src[18] = 32 as u8
32 src[19] = 123 as u8
33 src[20] = 32 as u8
34 src[21] = 114 as u8
35 src[22] = 101 as u8
36 src[23] = 116 as u8
37 src[24] = 117 as u8
38 src[25] = 114 as u8
39 src[26] = 110 as u8
40 src[27] = 32 as u8
41 src[28] = 50 as u8 // 2
42 src[29] = 32 as u8
43 src[30] = 43 as u8 // +
44 src[31] = 32 as u8
45 src[32] = 51 as u8 // 3
46 src[33] = 32 as u8
47 src[34] = 42 as u8 // *
48 src[35] = 32 as u8
49 src[36] = 52 as u8 // 4
50 src[37] = 32 as u8
51 src[38] = 125 as u8 // }
52
53 let lex: *NxNLexer = nx_nlex_new(src, 39, 64)
54 let n_tok: i64 = nx_nlex_run(lex)
55
56 let parser: *NxNParser = nx_nparse_new(lex, 64)
57 let func_idx: i64 = nx_nparse_run(parser)
58 if func_idx < 0 { return 2 }
59
60 let ir: *NxIrFunc = nx_nir_lower_func(parser, func_idx, 64)
61 if ir == (0 as *NxIrFunc) { return 3 }
62
63 // Expected IR for `2 + 3 * 4`:
64 // v0 = CONST 2
65 // v1 = CONST 3
66 // v2 = CONST 4
67 // v3 = MUL v1 v2 (3 * 4)
68 // v4 = ADD v0 v3 (2 + (3*4))
69 // v5 = RETURN v4
70 // Total 6 instructions.
71 if ir.n_instrs != 6 { return 4 }
72
73 let i0: *NxInstr = nx_nir_instr_at(ir, 0)
74 if i0.opcode != NX_IR_CONST_I64 { return 5 }
75 if i0.op0 != 2 { return 6 }
76
77 let i1: *NxInstr = nx_nir_instr_at(ir, 1)
78 if i1.opcode != NX_IR_CONST_I64 { return 7 }
79 if i1.op0 != 3 { return 8 }
80
81 let i2: *NxInstr = nx_nir_instr_at(ir, 2)
82 if i2.opcode != NX_IR_CONST_I64 { return 9 }
83 if i2.op0 != 4 { return 10 }
84
85 let i3: *NxInstr = nx_nir_instr_at(ir, 3)
86 if i3.opcode != NX_IR_MUL { return 11 }
87 if i3.op0 != 1 { return 12 } // refers v1
88 if i3.op1 != 2 { return 13 } // refers v2
89
90 let i4: *NxInstr = nx_nir_instr_at(ir, 4)
91 if i4.opcode != NX_IR_ADD { return 14 }
92 if i4.op0 != 0 { return 15 } // refers v0
93 if i4.op1 != 3 { return 16 } // refers v3 (MUL)
94
95 let i5: *NxInstr = nx_nir_instr_at(ir, 5)
96 if i5.opcode != NX_IR_RETURN { return 17 }
97
98 // Stage 4: emit asm + verify it contains 'imulq', 'addq', 'popq', 'ret'
99 let asm: *NxAsmBuf = nx_asm_new(4096)
100 nx_nx86_emit_func(asm, src, ir)
101 var found_imul: i64 = 0
102 var found_add: i64 = 0
103 var found_ret: i64 = 0
104 var i: i64 = 0
105 while i < asm.len - 5 {
106 if asm.buf[i] as i64 == 105 { // 'i'
107 if asm.buf[i+1] as i64 == 109 { // 'm'
108 if asm.buf[i+2] as i64 == 117 { // 'u'
109 if asm.buf[i+3] as i64 == 108 { // 'l'
110 if asm.buf[i+4] as i64 == 113 { // 'q'
111 found_imul = 1
112 }
113 }
114 }
115 }
116 }
117 if asm.buf[i] as i64 == 97 { // 'a'
118 if asm.buf[i+1] as i64 == 100 { // 'd'
119 if asm.buf[i+2] as i64 == 100 { // 'd'
120 if asm.buf[i+3] as i64 == 113 { // 'q'
121 found_add = 1
122 }
123 }
124 }
125 }
126 if asm.buf[i] as i64 == 114 { // 'r'
127 if asm.buf[i+1] as i64 == 101 { // 'e'
128 if asm.buf[i+2] as i64 == 116 { // 't'
129 if asm.buf[i+3] as i64 == 10 {
130 found_ret = 1
131 }
132 }
133 }
134 }
135 i = i + 1
136 }
137 if found_imul != 1 { return 20 }
138 if found_add != 1 { return 21 }
139 if found_ret != 1 { return 22 }
140
141 return 0
142}