code wiki / _hdl_build / nx_boolhunt.nx

nx_boolhunt.nx source

↩ module page · 144 lines · 8208 B

1// nx_boolhunt.nx -- the team HUNTS its own search space: it enumerates EVERY 3-input boolean 2// function (all 256 truth tables), finds each one's provably-minimal circuit, and races the 3// compiler on each -- discovering, ITSELF, the functions where its exhaustive search beats 4// the compiler's heuristics (and the ones where it's behind, which name the ops it should 5// next author). No human picks the functions; the team sweeps the whole space. The team 6// generates the C for each truth table (sum-of-products) so the compiler can compile it. 7// license_tier: ORIGINAL 8 9import "nx_boolsynth.nx" // bl_find (minimal boolean circuit) 10import "nx_gcc_race.nx" // gr_race_cv / gr_newest_gcc / gr_exists (race + count) 11import "nx_engineer_crash.nx" // eng_link + eng_run (verify the team's emit by execution) 12const K_MAGIC_4096: i64 = 4096 13const K_MAGIC_8192: i64 = 8192 14 15func bh_emit(buf: *u8, oi: i64, s: *u8) -> i64 { var j: i64 = 0; while s[j] != (0 as u8) { buf[oi] = s[j]; oi = oi + 1; j = j + 1 } return oi } 16 17// generate the sum-of-products C function for a truth table into <path>: 18// long f(long a,long b,long c){ return (lit&lit&lit) | ... ; } 19// where the columns are a=0xAA, b=0xCC, c=0xF0 (so bit p of tt is the minterm (a_p,b_p,c_p)). 20func bool_gen_c(tt: i64, path: *u8) -> i64 { 21 let buf: *u8 = sys_mmap(K_MAGIC_4096) 22 var oi: i64 = bh_emit(buf, 0, "long f(long a,long b,long c){return " as *u8) 23 if (tt & 255) == 0 { oi = bh_emit(buf, oi, "0" as *u8) } 24 else { 25 var first: i64 = 1 26 var p: i64 = 0 27 while p < 8 { 28 if ((tt >> p) & 1) == 1 { 29 if first == 0 { oi = bh_emit(buf, oi, "|" as *u8) } 30 first = 0 31 oi = bh_emit(buf, oi, "(" as *u8) 32 if ((170 >> p) & 1) == 1 { oi = bh_emit(buf, oi, "a" as *u8) } else { oi = bh_emit(buf, oi, "(~a)" as *u8) } 33 oi = bh_emit(buf, oi, "&" as *u8) 34 if ((204 >> p) & 1) == 1 { oi = bh_emit(buf, oi, "b" as *u8) } else { oi = bh_emit(buf, oi, "(~b)" as *u8) } 35 oi = bh_emit(buf, oi, "&" as *u8) 36 if ((240 >> p) & 1) == 1 { oi = bh_emit(buf, oi, "c" as *u8) } else { oi = bh_emit(buf, oi, "(~c)" as *u8) } 37 oi = bh_emit(buf, oi, ")" as *u8) 38 } 39 p = p + 1 40 } 41 } 42 oi = bh_emit(buf, oi, ";}\n" as *u8) 43 let fd: i64 = sys_openat_wr(path, 0x1a4) 44 if fd < 0 { return 0 - 1 } 45 sys_write(fd, buf, oi); sys_close(fd) 46 return 0 47} 48 49// ---- boolean machine-code EMITTER (3-input a=rdi,b=rsi,c=rdx -> result rax) so the team's 50// size is its REAL emitted instruction count, an HONEST race vs the compiler's insn count. ---- 51func bse_rn(buf: *u8, oi: i64, id: i64) -> i64 { 52 if id == 0 { return bh_emit(buf, oi, "%rax" as *u8) } 53 if id == 1 { return bh_emit(buf, oi, "%rcx" as *u8) } 54 if id == 2 { return bh_emit(buf, oi, "%rdx" as *u8) } 55 if id == 6 { return bh_emit(buf, oi, "%rsi" as *u8) } 56 if id == 7 { return bh_emit(buf, oi, "%rdi" as *u8) } 57 if id == 8 { return bh_emit(buf, oi, "%r8" as *u8) } 58 if id == 9 { return bh_emit(buf, oi, "%r9" as *u8) } 59 if id == 10 { return bh_emit(buf, oi, "%r10" as *u8) } 60 return bh_emit(buf, oi, "%r11" as *u8) 61} 62func bse_opmn(o: i64) -> *u8 { 63 if o == BL_AND { return " andq " as *u8 } 64 if o == BL_OR { return " orq " as *u8 } 65 return " xorq " as *u8 66} 67// emit synth body; icnt[0]=instruction count (ex ret). slots: 0->rdi 1->rsi 2->rdx, op t->slot t+3. 68func bse_emit_synth(op: *i64, a: *i64, b: *i64, L: i64, buf: *u8, oi: i64, icnt: *i64) -> i64 { 69 let nsl: i64 = L + 3 70 let lu: *i64 = sys_mmap(8 * (nsl + 1)) as *i64 71 var i: i64 = 0 72 while i < nsl { lu[i] = 0 - 1; i = i + 1 } 73 var t: i64 = 0 74 while t < L { if a[t] > lu[a[t]] { lu[a[t]] = t } if bl_is_unary(op[t]) == 0 { if b[t] > lu[b[t]] { lu[b[t]] = t } } t = t + 1 } 75 let sreg: *i64 = sys_mmap(8 * (nsl + 1)) as *i64 76 sreg[0] = 7; sreg[1] = 6; sreg[2] = 2 77 let pool: *i64 = sys_mmap(8 * 8) as *i64 78 pool[0]=11; pool[1]=10; pool[2]=9; pool[3]=8; pool[4]=1; pool[5]=0 79 var psz: i64 = 6 80 var ic: i64 = 0 81 t = 0 82 while t < L { 83 let o: i64 = op[t] 84 let sa: i64 = a[t] 85 let aReg: i64 = sreg[sa] 86 var dst: i64 = 0 - 1 87 if lu[sa] == t { if sa >= 3 { dst = aReg } } // reuse a dead computed operand 88 if dst < 0 { dst = pool[psz - 1]; psz = psz - 1 } 89 if bl_is_unary(o) == 1 { 90 if dst != aReg { oi = bh_emit(buf, oi, " movq " as *u8); oi = bse_rn(buf, oi, aReg); oi = bh_emit(buf, oi, ", " as *u8); oi = bse_rn(buf, oi, dst); oi = bh_emit(buf, oi, "\n" as *u8); ic = ic + 1 } 91 oi = bh_emit(buf, oi, " notq " as *u8); oi = bse_rn(buf, oi, dst); oi = bh_emit(buf, oi, "\n" as *u8); ic = ic + 1 92 } else { 93 let sb: i64 = b[t] 94 let bReg: i64 = sreg[sb] 95 if dst == aReg { oi = bh_emit(buf, oi, bse_opmn(o)); oi = bse_rn(buf, oi, bReg); oi = bh_emit(buf, oi, ", " as *u8); oi = bse_rn(buf, oi, dst); oi = bh_emit(buf, oi, "\n" as *u8); ic = ic + 1 } 96 else { if dst == bReg { oi = bh_emit(buf, oi, bse_opmn(o)); oi = bse_rn(buf, oi, aReg); oi = bh_emit(buf, oi, ", " as *u8); oi = bse_rn(buf, oi, dst); oi = bh_emit(buf, oi, "\n" as *u8); ic = ic + 1 } 97 else { oi = bh_emit(buf, oi, " movq " as *u8); oi = bse_rn(buf, oi, aReg); oi = bh_emit(buf, oi, ", " as *u8); oi = bse_rn(buf, oi, dst); oi = bh_emit(buf, oi, "\n" as *u8); ic = ic + 1 98 oi = bh_emit(buf, oi, bse_opmn(o)); oi = bse_rn(buf, oi, bReg); oi = bh_emit(buf, oi, ", " as *u8); oi = bse_rn(buf, oi, dst); oi = bh_emit(buf, oi, "\n" as *u8); ic = ic + 1 } } 99 } 100 sreg[t + 3] = dst 101 if lu[sa] == t { if sa >= 3 { if aReg != dst { pool[psz] = aReg; psz = psz + 1 } } } 102 t = t + 1 103 } 104 let rr: i64 = sreg[L + 2] 105 if rr != 0 { oi = bh_emit(buf, oi, " movq " as *u8); oi = bse_rn(buf, oi, rr); oi = bh_emit(buf, oi, ", %rax\n" as *u8); ic = ic + 1 } 106 oi = bh_emit(buf, oi, " ret\n" as *u8) 107 icnt[0] = ic 108 return oi 109} 110// full program: driver sets rdi=0xAA,rsi=0xCC,rdx=0xF0 (the truth-table columns), calls synth, 111// exits with (result & 255) -- which IS the truth table, so a run verifies correctness exhaustively. 112func bse_emit_full(op: *i64, a: *i64, b: *i64, L: i64, buf: *u8, icnt: *i64) -> i64 { 113 var oi: i64 = bh_emit(buf, 0, " .att_syntax prefix\n .text\n .globl _start\n_start:\n movabsq $170, %rdi\n movabsq $204, %rsi\n movabsq $240, %rdx\n call synth\n andq $255, %rax\n movq %rax, %rdi\n movabsq $60, %rax\n syscall\nsynth:\n" as *u8) 114 oi = bse_emit_synth(op, a, b, L, buf, oi, icnt) 115 return oi 116} 117 118// race one truth table HONESTLY: emit the team's circuit, run it (verify == tt), count its 119// instructions, vs best compiler insns. res[0]=team_insns 1=best_comp 2=verdict 3=verified 120func bool_hunt_one(tt: i64, gccpath: *u8, res: *i64) -> i64 { 121 let op: *i64 = sys_mmap(8 * 12) as *i64 122 let a: *i64 = sys_mmap(8 * 12) as *i64 123 let b: *i64 = sys_mmap(8 * 12) as *i64 124 let buf: *u8 = sys_mmap(K_MAGIC_8192) 125 let icnt: *i64 = sys_mmap(8) as *i64 126 let L: i64 = bl_find(tt, op, a, b, 6) 127 res[3] = 0 128 if L <= 0 { res[0] = 1; res[1] = 1; res[2] = 0; if L == 0 { res[3] = 1 } return 0 } // trivial (input/const) 129 let blen: i64 = bse_emit_full(op, a, b, L, buf, icnt) 130 let fd: i64 = sys_openat_wr("/tmp/bht.s" as *u8, 0x1a4) 131 if fd >= 0 { sys_write(fd, buf, blen); sys_close(fd) } 132 res[0] = icnt[0] 133 if eng_link("/tmp/bht.s" as *u8, "/tmp/bht.elf" as *u8) == 0 { if eng_run("/tmp/bht.elf" as *u8, 0 as *u8) == (tt & 255) { res[3] = 1 } } 134 bool_gen_c(tt, "/tmp/bh.c" as *u8) 135 var best: i64 = gr_race_cv(gccpath, "/tmp/bh.c" as *u8, "/tmp/bh.o" as *u8, "/tmp/bh.txt" as *u8, "f" as *u8) 136 if gr_exists("/usr/bin/clang" as *u8) == 1 { 137 let cc: i64 = gr_race_cv("/usr/bin/clang" as *u8, "/tmp/bh.c" as *u8, "/tmp/bh2.o" as *u8, "/tmp/bh2.txt" as *u8, "f" as *u8) 138 if cc > 0 { if cc < best { best = cc } } 139 } 140 res[1] = best 141 res[2] = 0 142 if best > 0 { if res[0] < best { res[2] = 1 } if res[0] > best { res[2] = 0 - 1 } } 143 return 0 144}