code wiki / (root) / _a2a_selfhost_let.nx

_a2a_selfhost_let.nx source

↩ module page · 137 lines · 3823 B

1// Self-host: `func main() -> i64 { let x = 7 ; return x + 1 }` 2// Expected IR: CONST(7), STORE_LOCAL(slot0,v0), LOAD_LOCAL(slot0), CONST(1), ADD, RETURN 3 4import "syscalls.nx" 5import "nx_nlex.nx" 6import "nx_nparse.nx" 7import "nx_nir.nx" 8import "nx_nx86.nx" 9 10func main() -> i64 { 11 let src: *u8 = sys_mmap(96) 12 src[0] = 102 as u8 // f 13 src[1] = 117 as u8 14 src[2] = 110 as u8 15 src[3] = 99 as u8 16 src[4] = 32 as u8 17 src[5] = 109 as u8 18 src[6] = 97 as u8 19 src[7] = 105 as u8 20 src[8] = 110 as u8 21 src[9] = 40 as u8 22 src[10] = 41 as u8 23 src[11] = 32 as u8 24 src[12] = 45 as u8 25 src[13] = 62 as u8 26 src[14] = 32 as u8 27 src[15] = 105 as u8 28 src[16] = 54 as u8 29 src[17] = 52 as u8 30 src[18] = 32 as u8 31 src[19] = 123 as u8 32 src[20] = 32 as u8 33 // let 34 src[21] = 108 as u8 // l 35 src[22] = 101 as u8 // e 36 src[23] = 116 as u8 // t 37 src[24] = 32 as u8 38 src[25] = 120 as u8 // x 39 src[26] = 32 as u8 40 src[27] = 61 as u8 // = 41 src[28] = 32 as u8 42 src[29] = 55 as u8 // 7 43 src[30] = 32 as u8 44 src[31] = 59 as u8 // ; 45 src[32] = 32 as u8 46 // return 47 src[33] = 114 as u8 48 src[34] = 101 as u8 49 src[35] = 116 as u8 50 src[36] = 117 as u8 51 src[37] = 114 as u8 52 src[38] = 110 as u8 53 src[39] = 32 as u8 54 // x 55 src[40] = 120 as u8 56 src[41] = 32 as u8 57 src[42] = 43 as u8 // + 58 src[43] = 32 as u8 59 src[44] = 49 as u8 // 1 60 src[45] = 32 as u8 61 src[46] = 125 as u8 // } 62 63 let lex: *NxNLexer = nx_nlex_new(src, 47, 64) 64 let n_tok: i64 = nx_nlex_run(lex) 65 66 let parser: *NxNParser = nx_nparse_new(lex, 64) 67 let func_idx: i64 = nx_nparse_run(parser) 68 if func_idx < 0 { return 2 } 69 70 // Parser should have 1 local: 'x' 71 if parser.n_locals != 1 { return 3 } 72 73 let ir: *NxIrFunc = nx_nir_lower_func(parser, func_idx, 64) 74 if ir == (0 as *NxIrFunc) { return 4 } 75 76 // Expected: 6 instructions 77 // v0 = CONST 7 78 // v1 = STORE_LOCAL slot0, v0 79 // v2 = LOAD_LOCAL slot0 80 // v3 = CONST 1 81 // v4 = ADD v2 v3 82 // v5 = RETURN v4 83 if ir.n_instrs != 6 { return 5 } 84 if ir.n_locals != 1 { return 6 } 85 86 let i0: *NxInstr = nx_nir_instr_at(ir, 0) 87 if i0.opcode != NX_IR_CONST_I64 { return 7 } 88 if i0.op0 != 7 { return 8 } 89 90 let i1: *NxInstr = nx_nir_instr_at(ir, 1) 91 if i1.opcode != NX_IR_STORE_LOCAL { return 9 } 92 if i1.op0 != 0 { return 10 } 93 if i1.op1 != 0 { return 11 } // refers to v0 94 95 let i2: *NxInstr = nx_nir_instr_at(ir, 2) 96 if i2.opcode != NX_IR_LOAD_LOCAL { return 12 } 97 if i2.op0 != 0 { return 13 } 98 99 let i4: *NxInstr = nx_nir_instr_at(ir, 4) 100 if i4.opcode != NX_IR_ADD { return 14 } 101 102 let i5: *NxInstr = nx_nir_instr_at(ir, 5) 103 if i5.opcode != NX_IR_RETURN { return 15 } 104 105 // Generate asm + verify stack-frame allocation + movq to/from -8(%rbp) 106 let asm: *NxAsmBuf = nx_asm_new(4096) 107 nx_nx86_emit_func(asm, src, ir) 108 109 var found_subq: i64 = 0 110 var found_neg_offset: i64 = 0 111 var i: i64 = 0 112 while i < asm.len - 5 { 113 // 'subq' 114 if asm.buf[i] as i64 == 115 { 115 if asm.buf[i+1] as i64 == 117 { 116 if asm.buf[i+2] as i64 == 98 { 117 if asm.buf[i+3] as i64 == 113 { 118 found_subq = 1 119 } 120 } 121 } 122 } 123 // '-8(' for the negative-offset addressing 124 if asm.buf[i] as i64 == 45 { // '-' 125 if asm.buf[i+1] as i64 == 56 { // '8' 126 if asm.buf[i+2] as i64 == 40 { // '(' 127 found_neg_offset = 1 128 } 129 } 130 } 131 i = i + 1 132 } 133 if found_subq != 1 { return 20 } 134 if found_neg_offset != 1 { return 21 } 135 136 return 0 137}