[
  {
    "path": "Makefile",
    "content": "# output architecture: x64, x86, arm\nOUT = x64\n\nCC = cc\nCFLAGS = -Wall -O2 -DNEATCC_`echo $(OUT) | tr \"[:lower:]\" \"[:upper:]\"`\nLDFLAGS =\n\nOBJS = ncc.o tok.o out.o cpp.o gen.o int.o reg.o mem.o $(OUT).o\n\nall: ncc\n%.o: %.c ncc.h $(OUT).h\n\t$(CC) -c $(CFLAGS) $<\nncc: $(OBJS)\n\t$(CC) -o $@ $(OBJS) $(LDFLAGS)\nclean:\n\trm -f *.o ncc\n"
  },
  {
    "path": "README",
    "content": "NEATCC\n======\n\nNeatcc is an ARM/x86(-64) C compiler.  It supports a large subset of\nANSI C but lacks some of its features, the most important of which are\nstruct bitfields, inline assembly, and floating point types.\n"
  },
  {
    "path": "arm.c",
    "content": "/* architecture-dependent code generation for ARM */\n#include <stdlib.h>\n#include <string.h>\n#include \"ncc.h\"\n\n#define MIN(a, b)\t\t((a) < (b) ? (a) : (b))\n#define ALIGN(x, a)\t\t(((x) + (a) - 1) & ~((a) - 1))\n#define oi4(i)\t\t\toi((i), 4)\n\n#define REG_DP\t\t10\t/* data pointer register */\n#define REG_TMP\t\t12\t/* temporary register */\n#define REG_LR\t\t14\t/* link register */\n#define REG_PC\t\t15\t/* program counter */\n#define REG_RET\t\t0\t/* returned value register */\n\n#define I_AND\t\t0x00\n#define I_EOR\t\t0x01\n#define I_SUB\t\t0x02\n#define I_RSB\t\t0x03\n#define I_ADD\t\t0x04\n#define I_TST\t\t0x08\n#define I_CMP\t\t0x0a\n#define I_ORR\t\t0x0c\n#define I_MOV\t\t0x0d\n#define I_MVN\t\t0x0f\n\nint tmpregs[] = {4, 5, 6, 7, 8, 9, 3, 2, 1, 0};\nint argregs[] = {0, 1, 2, 3};\n\nstatic struct mem cs;\t\t/* generated code */\n\n/* code generation functions */\nstatic char *ointbuf(long n, int l)\n{\n\tstatic char buf[16];\n\tint i;\n\tfor (i = 0; i < l; i++) {\n\t\tbuf[i] = n & 0xff;\n\t\tn >>= 8;\n\t}\n\treturn buf;\n}\n\nstatic void oi(long n, int l)\n{\n\tmem_put(&cs, ointbuf(n, l), l);\n}\n\nstatic void oi_at(long pos, long n, int l)\n{\n\tmem_cpy(&cs, pos, ointbuf(n, l), l);\n}\n\nstatic long opos(void)\n{\n\treturn mem_len(&cs);\n}\n\n/* compiled division functions; div.s contains the source */\nstatic int udivdi3[] = {\n\t0xe3a02000, 0xe3a03000, 0xe1110001, 0x0a00000a,\n\t0xe1b0c211, 0xe2822001, 0x5afffffc, 0xe3a0c001,\n\t0xe2522001, 0x4a000004, 0xe1500211, 0x3afffffb,\n\t0xe0400211, 0xe083321c, 0xeafffff8, 0xe1a01000,\n\t0xe1a00003, 0xe1a0f00e,\n};\nstatic int umoddi3[] = {\n\t0xe92d4000, 0xebffffeb, 0xe1a00001, 0xe8bd8000,\n};\nstatic int divdi3[] = {\n\t0xe92d4030, 0xe1a04000, 0xe1a05001, 0xe1100000,\n\t0x42600000, 0xe1110001, 0x42611000, 0xebffffe1,\n\t0xe1340005, 0x42600000, 0xe1140004, 0x42611000,\n\t0xe8bd8030,\n};\nstatic int moddi3[] = {\n\t0xe92d4000, 0xebfffff0, 0xe1a00001, 0xe8bd8000,\n};\n\nstatic long *rel_sym;\t\t/* relocation symbols */\nstatic long *rel_flg;\t\t/* relocation flags */\nstatic long *rel_off;\t\t/* relocation offsets */\nstatic long rel_n, rel_sz;\t/* relocation count */\n\nstatic long lab_sz;\t\t/* label count */\nstatic long *lab_loc;\t\t/* label offsets in cs */\nstatic long jmp_n, jmp_sz;\t/* jump count */\nstatic long *jmp_off;\t\t/* jump offsets */\nstatic long *jmp_dst;\t\t/* jump destinations */\nstatic long jmp_ret;\t\t/* the position of the last return jmp */\n\nstatic void lab_add(long id)\n{\n\twhile (id >= lab_sz) {\n\t\tint lab_n = lab_sz;\n\t\tlab_sz = MAX(128, lab_sz * 2);\n\t\tlab_loc = mextend(lab_loc, lab_n, lab_sz, sizeof(*lab_loc));\n\t}\n\tlab_loc[id] = opos();\n}\n\nstatic void jmp_add(long off, long dst)\n{\n\tif (jmp_n == jmp_sz) {\n\t\tjmp_sz = MAX(128, jmp_sz * 2);\n\t\tjmp_off = mextend(jmp_off, jmp_n, jmp_sz, sizeof(*jmp_off));\n\t\tjmp_dst = mextend(jmp_dst, jmp_n, jmp_sz, sizeof(*jmp_dst));\n\t}\n\tjmp_off[jmp_n] = off;\n\tjmp_dst[jmp_n] = dst;\n\tjmp_n++;\n}\n\nvoid i_label(long id)\n{\n\tlab_add(id + 1);\n}\n\nstatic void rel_add(long sym, long flg, long off)\n{\n\tif (rel_n == rel_sz) {\n\t\trel_sz = MAX(128, rel_sz * 2);\n\t\trel_sym = mextend(rel_sym, rel_n, rel_sz, sizeof(*rel_sym));\n\t\trel_flg = mextend(rel_flg, rel_n, rel_sz, sizeof(*rel_flg));\n\t\trel_off = mextend(rel_off, rel_n, rel_sz, sizeof(*rel_off));\n\t}\n\trel_sym[rel_n] = sym;\n\trel_flg[rel_n] = flg;\n\trel_off[rel_n] = off;\n\trel_n++;\n}\n\nstatic int putdiv = 0;\t\t/* output div/mod functions */\nstatic int func_call;\t\t/* */\n\nstatic void i_call(long sym, long off);\n\nstatic void i_div(char *func)\n{\n\tputdiv = 1;\n\tfunc_call = 1;\n\ti_call(out_sym(func), 0);\n}\n\n/* data pool */\nstatic long *num_off;\t\t\t/* data immediate value */\nstatic long *num_sym;\t/* relocation data symbol name */\nstatic int num_n, num_sz;\n\nstatic int pool_find(long sym, long off)\n{\n\tint i;\n\tfor (i = 0; i < num_n; i++)\n\t\tif (sym == num_sym[i] && off == num_off[i])\n\t\t\treturn i << 2;\n\tif (num_n == num_sz) {\n\t\tnum_sz = MAX(128, num_sz * 2);\n\t\tnum_off = mextend(num_off, num_n, num_sz, sizeof(*num_off));\n\t\tnum_sym = mextend(num_sym, num_n, num_sz, sizeof(*num_sym));\n\t}\n\tnum_off[i] = off;\n\tnum_sym[i] = sym;\n\treturn (num_n++) << 2;\n}\n\nstatic int pool_num(long num)\n{\n\treturn pool_find(-1, num);\n}\n\nstatic int pool_reloc(long sym, long off)\n{\n\treturn pool_find(sym, off);\n}\n\nstatic void pool_write(void)\n{\n\tint i;\n\tfor (i = 0; i < num_n; i++) {\n\t\tif (num_sym[i] >= 0)\n\t\t\trel_add(num_sym[i], OUT_CS, opos());\n\t\toi4(num_off[i]);\n\t}\n}\n\n/*\n * data processing:\n * +---------------------------------------+\n * |COND|00|I| op |S| Rn | Rd |  operand2  |\n * +---------------------------------------+\n *\n * S: set condition code\n * Rn: first operand\n * Rd: destination operand\n *\n * I=0 operand2=| shift  | Rm |\n * I=1 operand2=|rota|  imm   |\n */\n#define ADD(op, rd, rn, s, i, cond)\t\\\n\t(((cond) << 28) | ((i) << 25) | ((s) << 20) | \\\n\t\t((op) << 21) | ((rn) << 16) | ((rd) << 12))\n\nstatic int add_encimm(unsigned n)\n{\n\tint i = 0;\n\twhile (i < 12 && (n >> ((4 + i) << 1)))\n\t\ti++;\n\treturn (n >> (i << 1)) | (((16 - i) & 0x0f) << 8);\n}\n\nstatic unsigned add_decimm(int n)\n{\n\tint rot = (16 - ((n >> 8) & 0x0f)) & 0x0f;\n\treturn (n & 0xff) << (rot << 1);\n}\n\nstatic int add_rndimm(unsigned n)\n{\n\tint rot = (n >> 8) & 0x0f;\n\tint num = n & 0xff;\n\tif (rot == 0)\n\t\treturn n;\n\tif (num == 0xff) {\n\t\tnum = 0;\n\t\trot = (rot + 12) & 0x0f;\n\t}\n\treturn ((num + 1) & 0xff) | (rot << 8);\n}\n\nstatic int opcode_add(int op)\n{\n\t/* opcode for O_ADD, O_SUB, O_AND, O_OR, O_XOR */\n\tstatic int rx[] = {I_ADD, I_SUB, I_AND, I_ORR, I_EOR};\n\treturn rx[op & 0x0f];\n}\n\nstatic void i_add(int op, int rd, int rn, int rm)\n{\n\toi4(ADD(opcode_add(op), rd, rn, 0, 0, 14) | rm);\n}\n\nstatic void i_add_imm(int op, int rd, int rn, long n)\n{\n\toi4(ADD(opcode_add(op), rd, rn, 0, 1, 14) | add_encimm(n));\n}\n\nstatic void i_ldr(int l, int rd, int rn, int off, int bt);\n\nstatic void i_num(int rd, long n)\n{\n\tint enc = add_encimm(n);\n\tif (n == add_decimm(enc)) {\n\t\toi4(ADD(I_MOV, rd, 0, 0, 1, 14) | enc);\n\t\treturn;\n\t}\n\tenc = add_encimm(-n - 1);\n\tif (~n == add_decimm(enc)) {\n\t\toi4(ADD(I_MVN, rd, 0, 0, 1, 14) | enc);\n\t\treturn;\n\t}\n\ti_ldr(1, rd, REG_DP, pool_num(n), LONGSZ);\n}\n\nstatic void i_add_anyimm(int rd, int rn, long n)\n{\n\tint neg = n < 0;\n\tint imm = add_encimm(neg ? -n : n);\n\tif (imm == add_decimm(neg ? -n : n)) {\n\t\toi4(ADD(neg ? I_SUB : I_ADD, rd, rn, 0, 1, 14) | imm);\n\t} else {\n\t\ti_num(rd, n);\n\t\ti_add(O_ADD, rd, rd, rn);\n\t}\n}\n\n/*\n * multiply\n * +----------------------------------------+\n * |COND|000000|A|S| Rd | Rn | Rs |1001| Rm |\n * +----------------------------------------+\n *\n * Rd: destination\n * A: accumulate\n * C: set condition codes\n *\n * I=0 operand2=| shift  | Rm |\n * I=1 operand2=|rota|  imm   |\n */\n#define MUL(rd, rn, rs)\t\t\\\n\t((14 << 28) | ((rd) << 16) | ((0) << 12) | ((rn) << 8) | ((9) << 4) | (rm))\n\nstatic void i_mul(int rd, int rn, int rm)\n{\n\toi4(MUL(rd, rn, rm));\n}\n\nstatic int opcode_set(long op)\n{\n\t/* lt, ge, eq, ne, le, gt */\n\tstatic int ucond[] = {3, 2, 0, 1, 9, 8};\n\tstatic int scond[] = {11, 10, 0, 1, 13, 12};\n\tlong bt = O_T(op);\n\treturn bt & T_MSIGN ? scond[op & 0x0f] : ucond[op & 0x0f];\n}\n\nstatic void i_tst(int rn, int rm)\n{\n\toi4(ADD(I_TST, 0, rn, 1, 0, 14) | rm);\n}\n\nstatic void i_cmp(int rn, int rm)\n{\n\toi4(ADD(I_CMP, 0, rn, 1, 0, 14) | rm);\n}\n\nstatic void i_cmp_imm(int rn, long n)\n{\n\toi4(ADD(I_CMP, 0, rn, 1, 1, 14) | add_encimm(n));\n}\n\nstatic void i_set(int cond, int rd)\n{\n\toi4(ADD(I_MOV, rd, 0, 0, 1, 14));\n\toi4(ADD(I_MOV, rd, 0, 0, 1, opcode_set(cond)) | 1);\n}\n\n#define SM_LSL\t\t0\n#define SM_LSR\t\t1\n#define SM_ASR\t\t2\n\nstatic int opcode_shl(long op)\n{\n\tif (op & 0x0f)\n\t\treturn O_T(op) & T_MSIGN ? SM_ASR : SM_LSR;\n\treturn SM_LSL;\n}\n\nstatic void i_shl(long op, int rd, int rm, int rs)\n{\n\tint sm = opcode_shl(op);\n\toi4(ADD(I_MOV, rd, 0, 0, 0, 14) | (rs << 8) | (sm << 5) | (1 << 4) | rm);\n}\n\nstatic void i_shl_imm(long op, int rd, int rn, long n)\n{\n\tint sm = opcode_shl(op);\n\toi4(ADD(I_MOV, rd, 0, 0, 0, 14) | (n << 7) | (sm << 5) | rn);\n}\n\nvoid i_mov(int rd, int rn)\n{\n\toi4(ADD(I_MOV, rd, 0, 0, 0, 14) | rn);\n}\n\n/*\n * single data transfer:\n * +------------------------------------------+\n * |COND|01|I|P|U|B|W|L| Rn | Rd |   offset   |\n * +------------------------------------------+\n *\n * I: immediate/offset\n * P: post/pre indexing\n * U: down/up\n * B: byte/word\n * W: writeback\n * L: store/load\n * Rn: base register\n * Rd: source/destination register\n *\n * I=0 offset=| immediate |\n * I=1 offset=| shift  | Rm |\n *\n * halfword and signed data transfer\n * +----------------------------------------------+\n * |COND|000|P|U|0|W|L| Rn | Rd |0000|1|S|H|1| Rm |\n * +----------------------------------------------+\n *\n * +----------------------------------------------+\n * |COND|000|P|U|1|W|L| Rn | Rd |off1|1|S|H|1|off2|\n * +----------------------------------------------+\n *\n * S: signed\n * H: halfword\n */\n#define LDR(l, rd, rn, b, u, p, w)\t\t\\\n\t((14 << 28) | (1 << 26) | ((p) << 24) | ((b) << 22) | ((u) << 23) | \\\n\t((w) << 21) | ((l) << 20) | ((rn) << 16) | ((rd) << 12))\n#define LDRH(l, rd, rn, s, h, u, i)\t\\\n\t((14 << 28) | (1 << 24) | ((u) << 23) | ((i) << 22) | ((l) << 20) | \\\n\t((rn) << 16) | ((rd) << 12) | ((s) << 6) | ((h) << 5) | (9 << 4))\n\nstatic void i_ldr(int l, int rd, int rn, int off, int bt)\n{\n\tint b = T_SZ(bt) == 1;\n\tint h = T_SZ(bt) == 2;\n\tint s = l && (bt & T_MSIGN);\n\tint half = h || (b && s);\n\tint maximm = half ? 0x100 : 0x1000;\n\tint neg = off < 0;\n\tif (neg)\n\t\toff = -off;\n\twhile (off >= maximm) {\n\t\tint imm = add_encimm(off);\n\t\toi4(ADD(neg ? I_SUB : I_ADD, REG_TMP, rn, 0, 1, 14) | imm);\n\t\trn = REG_TMP;\n\t\toff -= add_decimm(imm);\n\t}\n\tif (!half)\n\t\toi4(LDR(l, rd, rn, b, !neg, 1, 0) | off);\n\telse\n\t\toi4(LDRH(l, rd, rn, s, h, !neg, 1) |\n\t\t\t((off & 0xf0) << 4) | (off & 0x0f));\n}\n\nstatic void i_sym(int rd, long sym, long off)\n{\n\tint doff = pool_reloc(sym, off);\n\ti_ldr(1, rd, REG_DP, doff, LONGSZ);\n}\n\nstatic void i_neg(int rd, int r1)\n{\n\toi4(ADD(I_RSB, rd, r1, 0, 1, 14));\n}\n\nstatic void i_not(int rd, int r1)\n{\n\toi4(ADD(I_MVN, rd, 0, 0, 0, 14) | r1);\n}\n\nstatic void i_lnot(int rd, int r1)\n{\n\ti_tst(r1, r1);\n\ti_set(O_EQ, rd);\n}\n\n/* rd = rd & ((1 << bits) - 1) */\nstatic void i_zx(int rd, int r1, int bits)\n{\n\tif (bits <= 8) {\n\t\toi4(ADD(I_AND, rd, r1, 0, 1, 14) | add_encimm((1 << bits) - 1));\n\t} else {\n\t\ti_shl_imm(O_SHL, rd, r1, 32 - bits);\n\t\ti_shl_imm(O_SHR, rd, rd, 32 - bits);\n\t}\n}\n\nstatic void i_sx(int rd, int r1, int bits)\n{\n\ti_shl_imm(O_SHL, rd, r1, 32 - bits);\n\ti_shl_imm(O_MK(O_SHR, SLNG), rd, rd, 32 - bits);\n}\n\n/*\n * branch:\n * +-----------------------------------+\n * |COND|101|L|         offset         |\n * +-----------------------------------+\n *\n * L: link\n */\n#define BL(cond, l, o)\t(((cond) << 28) | (5 << 25) | ((l) << 24) | \\\n\t\t\t\t((((o) - 8) >> 2) & 0x00ffffff))\nstatic long i_jmp(long op, long rn, long rm)\n{\n\tlong pos;\n\tif (O_C(op) == O_JMP) {\n\t\tpos = opos();\n\t\toi4(BL(14, 0, 0));\n\t\treturn pos;\n\t}\n\tif (O_C(op) & O_JZ) {\n\t\ti_tst(rn, rn);\n\t\tpos = opos();\n\t\toi4(BL(O_C(op) == O_JZ ? 0 : 1, 0, 0));\n\t\treturn pos;\n\t}\n\tif (O_C(op) & O_JCC) {\n\t\tif (op & O_NUM)\n\t\t\ti_cmp_imm(rn, rm);\n\t\telse\n\t\t\ti_cmp(rn, rm);\n\t\tpos = opos();\n\t\toi4(BL(opcode_set(op), 0, 0));\n\t\treturn pos;\n\t}\n\treturn -1;\n}\n\nstatic void i_memcpy(int rd, int rs, int rn)\n{\n\toi4(ADD(I_SUB, rn, rn, 1, 1, 14) | 1);\n\toi4(BL(4, 0, 16));\n\toi4(LDR(1, REG_TMP, rs, 1, 1, 0, 0) | 1);\n\toi4(LDR(0, REG_TMP, rd, 1, 1, 0, 0) | 1);\n\toi4(BL(14, 0, -16));\n}\n\nstatic void i_memset(int rd, int rs, int rn)\n{\n\toi4(ADD(I_SUB, rn, rn, 1, 1, 14) | 1);\n\toi4(BL(4, 0, 12));\n\toi4(LDR(0, rs, rd, 1, 1, 0, 0) | 1);\n\toi4(BL(14, 0, -12));\n}\n\nstatic void i_call_reg(int rd)\n{\n\ti_mov(REG_LR, REG_PC);\n\ti_mov(REG_PC, rd);\n}\n\nstatic void i_call(long sym, long off)\n{\n\trel_add(sym, OUT_CS | OUT_RLREL | OUT_RL24, opos());\n\toi4(BL(14, 1, off));\n}\n\nint i_imm(long lim, long n)\n{\n\treturn add_decimm(add_encimm(n)) == n;\n}\n\nlong i_reg(long op, long *rd, long *r1, long *r2, long *r3, long *tmp)\n{\n\tlong oc = O_C(op);\n\t*rd = 0;\n\t*r1 = 0;\n\t*r2 = 0;\n\t*r3 = 0;\n\t*tmp = 0;\n\tif (oc & O_MOV) {\n\t\t*rd = R_TMPS;\n\t\t*r1 = oc & (O_NUM | O_SYM) ? 32 : R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc & O_MUL && oc & (O_NUM | O_SYM))\n\t\treturn 1;\n\tif (oc == O_DIV || oc == O_MOD) {\n\t\t*rd = 1 << REG_RET;\n\t\t*r1 = 1 << argregs[0];\n\t\t*r2 = 1 << argregs[1];\n\t\t*tmp = R_TMPS & ~R_PERM;\n\t\treturn 0;\n\t}\n\tif (oc & O_BOP) {\n\t\t*rd = R_TMPS;\n\t\t*r1 = R_TMPS;\n\t\t*r2 = op & O_NUM ? 0 : R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc & O_UOP) {\n\t\t*rd = R_TMPS;\n\t\t*r1 = op & O_NUM ? 0 : R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc == O_MSET || oc == O_MCPY) {\n\t\t*r1 = 1 << 4;\n\t\t*r2 = 1 << 5;\n\t\t*r3 = 1 << 6;\n\t\t*tmp = (1 << 4) | (1 << 6) | (oc == O_MCPY ? (1 << 5) : 0);\n\t\treturn 0;\n\t}\n\tif (oc == O_RET) {\n\t\t*r1 = (1 << REG_RET);\n\t\treturn 0;\n\t}\n\tif (oc & O_CALL) {\n\t\t*rd = (1 << REG_RET);\n\t\t*r1 = oc & O_SYM ? 0 : R_TMPS;\n\t\t*tmp = R_TMPS & ~R_PERM;\n\t\treturn 0;\n\t}\n\tif (oc & O_LD) {\n\t\t*rd = R_TMPS;\n\t\t*r1 = R_TMPS;\n\t\t*r2 = oc & O_NUM ? 0 : R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc & O_ST) {\n\t\t*r1 = R_TMPS;\n\t\t*r2 = R_TMPS;\n\t\t*r3 = oc & O_NUM ? 0 : R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc & O_JZ) {\n\t\t*r1 = R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc & O_JCC) {\n\t\t*r1 = R_TMPS;\n\t\t*r2 = oc & O_NUM ? 0 : R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc == O_JMP)\n\t\treturn 0;\n\treturn 1;\n}\n\nlong i_ins(long op, long rd, long r1, long r2, long r3)\n{\n\tlong oc = O_C(op);\n\tlong bt = O_T(op);\n\tif (op & O_ADD) {\n\t\tif (op & O_NUM) {\n\t\t\tif (i_imm(0, r2))\n\t\t\t\ti_add_imm(op, rd, r1, r2);\n\t\t\telse\n\t\t\t\ti_add_anyimm(rd, r1, r2);\n\t\t} else {\n\t\t\ti_add(op, rd, r1, r2);\n\t\t}\n\t}\n\tif (op & O_SHL) {\n\t\tif (op & O_NUM)\n\t\t\ti_shl_imm(op, rd, r1, r2);\n\t\telse\n\t\t\ti_shl(op, rd, r1, r2);\n\t}\n\tif (op & O_MUL) {\n\t\tif (oc == O_MUL)\n\t\t\ti_mul(rd, r1, r2);\n\t\tif (oc == O_DIV)\n\t\t\ti_div(O_T(op) & T_MSIGN ? \"__divdi3\" : \"__udivdi3\");\n\t\tif (oc == O_MOD)\n\t\t\ti_div(O_T(op) & T_MSIGN ? \"__moddi3\" : \"__umoddi3\");\n\t\treturn 0;\n\t}\n\tif (oc & O_CMP) {\n\t\tif (op & O_NUM)\n\t\t\ti_cmp_imm(r1, r2);\n\t\telse\n\t\t\ti_cmp(r1, r2);\n\t\ti_set(op, rd);\n\t\treturn 0;\n\t}\n\tif (oc & O_UOP) {\n\t\tif (oc == O_NEG)\n\t\t\ti_neg(rd, r1);\n\t\tif (oc == O_NOT)\n\t\t\ti_not(rd, r1);\n\t\tif (oc == O_LNOT)\n\t\t\ti_lnot(rd, r1);\n\t\treturn 0;\n\t}\n\tif (oc == O_CALL) {\n\t\tfunc_call = 1;\n\t\ti_call_reg(r1);\n\t\treturn 0;\n\t}\n\tif (oc == (O_CALL | O_SYM)) {\n\t\tfunc_call = 1;\n\t\ti_call(r1, r2);\n\t\treturn 0;\n\t}\n\tif (oc == (O_MOV | O_SYM)) {\n\t\ti_sym(rd, r1, r2);\n\t\treturn 0;\n\t}\n\tif (oc == (O_MOV | O_NUM)) {\n\t\ti_num(rd, r1);\n\t\treturn 0;\n\t}\n\tif (oc == O_MSET) {\n\t\ti_memset(r1, r2, r3);\n\t\treturn 0;\n\t}\n\tif (oc == O_MCPY) {\n\t\ti_memcpy(r1, r2, r3);\n\t\treturn 0;\n\t}\n\tif (oc == O_RET) {\n\t\tjmp_ret = opos();\n\t\tjmp_add(i_jmp(O_JMP, 0, 0), 0);\n\t\treturn 0;\n\t}\n\tif (oc == (O_LD | O_NUM)) {\n\t\ti_ldr(1, rd, r1, r2, bt);\n\t\treturn 0;\n\t}\n\tif (oc == (O_ST | O_NUM)) {\n\t\ti_ldr(0, r1, r2, r3, bt);\n\t\treturn 0;\n\t}\n\tif (oc == O_MOV) {\n\t\tif (T_SZ(bt) == LONGSZ)\n\t\t\ti_mov(rd, r1);\n\t\telse {\n\t\t\tif (bt & T_MSIGN)\n\t\t\t\ti_sx(rd, r1, T_SZ(bt) * 8);\n\t\t\telse\n\t\t\t\ti_zx(rd, r1, T_SZ(bt) * 8);\n\t\t}\n\t\treturn 0;\n\t}\n\tif (oc & O_JXX) {\n\t\tjmp_add(i_jmp(op, r1, r2), r3 + 1);\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n\nvoid i_wrap(int argc, long sargs, long spsub, int initfp, long sregs, long sregs_pos)\n{\n\tlong body_n;\n\tvoid *body;\n\tlong diff;\t\t/* prologue length */\n\tlong dpadd;\n\tint nsargs = 0;\t\t/* number of saved arguments */\n\tint initdp = num_n > 0;\t/* initialize data pointer */\n\tlong pregs = 1;\t\t/* registers saved in function prologue */\n\tint i;\n\tif (func_call)\n\t\tinitfp = 1;\n\tif (!initfp && !spsub && !initdp && !sargs && argc < N_ARGS)\n\t\tpregs = 0;\n\tinitfp = initfp || pregs;\n\t/* removing the last jmp to the epilogue */\n\tif (jmp_ret + 4 == opos()) {\n\t\tmem_cut(&cs, jmp_ret);\n\t\tjmp_n--;\n\t}\n\tlab_add(0);\t\t/* the return label */\n\tbody_n = mem_len(&cs);\n\tbody = mem_get(&cs);\n\t/* generating function prologue */\n\tfor (i = 0; i < N_ARGS; i++)\n\t\tif ((1 << argregs[i]) & sargs)\n\t\t\tnsargs++;\n\tif (nsargs & 0x1) {\t\t\t/* keeping stack 8-aligned */\n\t\tfor (i = 0; i < N_ARGS; i++)\n\t\t\tif (!((1 << argregs[i]) & sargs))\n\t\t\t\tbreak;\n\t\tsargs |= 1 << argregs[i];\n\t}\n\tif (sargs)\n\t\toi4(0xe92d0000 | sargs);\t/* stmfd sp!, {r0-r3} */\n\tif (pregs) {\n\t\toi4(0xe1a0c00d);\t\t/* mov   r12, sp */\n\t\toi4(0xe92d5c00);\t\t/* stmfd sp!, {sl, fp, ip, lr} */\n\t}\n\tif (initfp)\n\t\toi4(0xe1a0b00d);\t\t/* mov   fp, sp */\n\tif (sregs) {\t/* sregs_pos should be encoded as immediate */\n\t\tint npos = add_decimm(add_rndimm(add_encimm(-sregs_pos)));\n\t\tspsub += npos + sregs_pos;\n\t\tsregs_pos = -npos;\n\t}\n\tif (spsub) {\t\t\t\t/* sub   sp, sp, xx */\n\t\tspsub = ALIGN(spsub, 8);\n\t\tspsub = add_decimm(add_rndimm(add_encimm(spsub)));\n\t\toi4(0xe24dd000 | add_encimm(spsub));\n\t}\n\tif (initdp) {\n\t\tdpadd = opos();\n\t\toi4(0xe28fa000);\t\t/* add   dp, pc, xx */\n\t}\n\tif (sregs) {\t\t\t\t/* saving registers */\n\t\toi4(0xe24bc000 | add_encimm(-sregs_pos));\n\t\toi4(0xe88c0000 | sregs);\t/* stmea ip, {r4-r9} */\n\t}\n\tdiff = mem_len(&cs);\n\tmem_put(&cs, body, body_n);\n\tfree(body);\n\t/* generating function epilogue */\n\tif (sregs) {\t\t\t\t/* restoring saved registers */\n\t\toi4(0xe24bc000 | add_encimm(-sregs_pos));\n\t\toi4(0xe89c0000 | sregs);\t/* ldmfd ip, {r4-r9} */\n\t}\n\tif (pregs) {\n\t\toi4(0xe89bac00);\t\t/* ldmfd fp, {sl, fp, sp, pc} */\n\t} else {\n\t\toi4(0xe1a0f00e);\t\t/* mov   pc, lr */\n\t}\n\t/* adjusting code offsets */\n\tfor (i = 0; i < rel_n; i++)\n\t\trel_off[i] += diff;\n\tfor (i = 0; i < jmp_n; i++)\n\t\tjmp_off[i] += diff;\n\tfor (i = 0; i < lab_sz; i++)\n\t\tlab_loc[i] += diff;\n\t/* writing the data pool */\n\tif (initdp) {\n\t\tint dpoff = opos() - dpadd - 8;\n\t\tdpoff = add_decimm(add_rndimm(add_encimm(dpoff)));\n\t\tmem_putz(&cs, dpadd + dpoff + 8 - opos());\n\t\t/* fill data ptr addition: dp = pc + xx */\n\t\toi_at(dpadd, 0xe28fa000 | add_encimm(dpoff), 4);\n\t}\n\tpool_write();\n}\n\nstatic void i_fill(long src, long dst)\n{\n\tlong *d = mem_buf(&cs) + src;\n\tlong c = (*d & 0xff000000) | (((dst - src - 8) >> 2) & 0x00ffffff);\n\toi_at(src, c, 4);\n}\n\nvoid i_code(char **c, long *c_len, long **rsym, long **rflg, long **roff, long *rcnt)\n{\n\tint i;\n\tfor (i = 0; i < jmp_n; i++)\t/* filling jmp destinations */\n\t\ti_fill(jmp_off[i], lab_loc[jmp_dst[i]]);\n\t*c_len = mem_len(&cs);\n\t*c = mem_get(&cs);\n\t*rsym = rel_sym;\n\t*rflg = rel_flg;\n\t*roff = rel_off;\n\t*rcnt = rel_n;\n\trel_sym = NULL;\n\trel_flg = NULL;\n\trel_off = NULL;\n\trel_n = 0;\n\trel_sz = 0;\n\tjmp_n = 0;\n\tnum_n = 0;\n\tfunc_call = 0;\n}\n\nvoid i_done(void)\n{\n\tif (putdiv) {\n\t\to_code(\"__udivdi3\", (void *) udivdi3, sizeof(udivdi3));\n\t\to_code(\"__umoddi3\", (void *) umoddi3, sizeof(umoddi3));\n\t\to_code(\"__divdi3\", (void *) divdi3, sizeof(divdi3));\n\t\to_code(\"__moddi3\", (void *) moddi3, sizeof(moddi3));\n\t}\n\tfree(jmp_off);\n\tfree(jmp_dst);\n\tfree(lab_loc);\n\tfree(num_sym);\n\tfree(num_off);\n}\n"
  },
  {
    "path": "arm.h",
    "content": "/* architecture-dependent header for ARM */\n#define LONGSZ\t\t4\t/* word size */\n#define I_ARCH\t\t\"__arm__\"\n\n#define N_REGS\t\t16\t/* number of registers */\n#define N_TMPS\t\t10\t/* number of tmp registers */\n#define N_ARGS\t\t4\t/* number of arg registers */\n#define R_TMPS\t\t0x03ff\t/* mask of tmp registers */\n#define R_ARGS\t\t0x000f\t/* mask of arg registers */\n#define R_PERM\t\t0x0ff0\t/* mask of callee-saved registers */\n\n/* special registers */\n#define REG_FP\t\t11\t/* frame pointer register */\n#define REG_SP\t\t13\t/* stack pointer register */\n\n/* stack positions */\n#define I_ARG0\t\t(-16)\t/* offset of the first argument from FP */\n#define I_LOC0\t\t0\t/* offset of the first local from FP */\n"
  },
  {
    "path": "cpp.c",
    "content": "/* neatcc preprocessor */\n#include <ctype.h>\n#include <fcntl.h>\n#include <stdarg.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include \"ncc.h\"\n\nstatic char *buf;\nstatic long len;\nstatic long cur;\n\nstatic struct macro {\n\tchar name[NAMELEN];\t/* macro name */\n\tchar def[MDEFLEN];\t/* macro definition */\n\tchar args[NARGS][NAMELEN];\n\tint nargs;\t\t/* number of arguments */\n\tint isfunc;\t\t/* macro is a function */\n\tint undef;\t\t/* macro is removed */\n} macros[NDEFS];\nstatic int mcount = 1;\t\t/* number of macros */\nstatic int mhead[256];\t\t/* macro hash table heads */\nstatic int mnext[NDEFS];\t/* macro hash table next entries */\n\n#define BUF_FILE\t\t0\n#define BUF_MACRO\t\t1\n#define BUF_ARG\t\t\t2\n#define BUF_EVAL\t\t3\n#define BUF_TEMP\t\t4\n\n/* preprocessing input buffers for files, macros and macro arguments */\nstatic struct buf {\n\tchar *buf;\n\tlong len;\n\tlong cur;\n\tint type;\n\t/* for BUF_FILE */\n\tchar path[NAMELEN];\n\t/* for BUF_MACRO */\n\tstruct macro *macro;\n\tchar args[NARGS][MARGLEN];\t/* arguments passed to a macro */\n\t/* for BUF_ARG */\n\tint arg_buf;\t\t\t/* the bufs index of the owning macro */\n} bufs[NBUFS];\nstatic int bufs_n;\nstatic int bufs_limit = 0;\t\t/* cpp_read() limit; useful in cpp_eval() */\n\nvoid die(char *fmt, ...)\n{\n\tva_list ap;\n\tchar msg[512];\n\tva_start(ap, fmt);\n\tvsprintf(msg, fmt, ap);\n\tva_end(ap);\n\twrite(2, msg, strlen(msg));\n\texit(1);\n}\n\nstatic void buf_new(int type, char *dat, long dlen)\n{\n\tif (bufs_n) {\n\t\tbufs[bufs_n - 1].buf = buf;\n\t\tbufs[bufs_n - 1].cur = cur;\n\t\tbufs[bufs_n - 1].len = len;\n\t}\n\tif (bufs_n >= NBUFS)\n\t\tdie(\"nomem: NBUFS reached!\\n\");\n\tbufs_n++;\n\tcur = 0;\n\tbuf = dat;\n\tlen = dlen;\n\tbufs[bufs_n - 1].type = type;\n}\n\nstatic void buf_file(char *path, char *dat, int dlen)\n{\n\tbuf_new(BUF_FILE, dat, dlen);\n\tstrcpy(bufs[bufs_n - 1].path, path ? path : \"\");\n}\n\nstatic int macro_arg(struct macro *m, char *arg);\n\nstatic void buf_macro(struct macro *m)\n{\n\tstruct mem mem;\n\tchar *s = m->def;\n\tchar arg[NAMELEN];\n\tint len;\n\tint quote = 0;\n\tmem_init(&mem);\n\twhile (*s) {\n\t\tint numsign = 0;\n\t\tif (quote && s[0] == quote)\n\t\t\tquote = 0;\n\t\telse if (!quote && s[0] == '\"')\n\t\t\tquote = s[0];\n\t\telse if (!quote && s[0] == '\\'')\n\t\t\tquote = s[0];\n\t\tif (!quote && s[0] == '#')\n\t\t\tnumsign = s[1] == '#' ? 2 : 1;\n\t\tif (numsign && s[numsign]) {\n\t\t\tstruct buf *mbuf = &bufs[bufs_n];\n\t\t\tchar *r = s + numsign;\n\t\t\tchar *d = arg;\n\t\t\twhile (*r && d - arg < sizeof(arg) - 1 &&\n\t\t\t\t\t(isalnum((unsigned char) *r) || *r == '_'))\n\t\t\t\t*d++ = *r++;\n\t\t\t*d++ = '\\0';\n\t\t\tif (macro_arg(m, arg) >= 0) {\n\t\t\t\tchar *def = mbuf->args[macro_arg(m, arg)];\n\t\t\t\tif (def && numsign == 1) {\n\t\t\t\t\tmem_putc(&mem, '\\\"');\n\t\t\t\t\twhile (*def) {\n\t\t\t\t\t\tif (*def == '\\\"')\n\t\t\t\t\t\t\tmem_putc(&mem, '\\\\');\n\t\t\t\t\t\tmem_putc(&mem, (unsigned char) *def++);\n\t\t\t\t\t}\n\t\t\t\t\tmem_putc(&mem, '\\\"');\n\t\t\t\t\ts = r;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (def && numsign == 2) {\n\t\t\t\t\twhile (*def)\n\t\t\t\t\t\tmem_putc(&mem, (unsigned char) *def++);\n\t\t\t\t\ts = r;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (quote && s[0] == '\\\\')\n\t\t\tmem_putc(&mem, (unsigned char) *s++);\n\t\tif (s[0])\n\t\t\tmem_putc(&mem, (unsigned char) *s++);\n\t}\n\tlen = mem_len(&mem);\n\tbuf_new(BUF_MACRO, mem_get(&mem), len);\n\tmem_done(&mem);\n\tbufs[bufs_n - 1].macro = m;\n}\n\nstatic void buf_arg(char *arg, int mbuf)\n{\n\tbuf_new(BUF_ARG, arg, strlen(arg));\n\tbufs[bufs_n - 1].arg_buf = mbuf;\n}\n\nstatic void buf_pop(void)\n{\n\tbufs_n--;\n\tif (bufs[bufs_n].type == BUF_FILE || bufs[bufs_n].type == BUF_MACRO)\n\t\tfree(buf);\n\tif (bufs_n) {\n\t\tcur = bufs[bufs_n - 1].cur;\n\t\tlen = bufs[bufs_n - 1].len;\n\t\tbuf = bufs[bufs_n - 1].buf;\n\t}\n}\n\nstatic int buf_iseval(void)\n{\n\tint i;\n\tfor (i = bufs_n - 1; i >= 0; i--)\n\t\tif (bufs[i].type == BUF_EVAL)\n\t\t\treturn 1;\n\treturn 0;\n}\n\nstatic size_t file_size(int fd)\n{\n\tstruct stat st;\n\tif (!fstat(fd, &st))\n\t\treturn st.st_size;\n\treturn 0;\n}\n\nstatic int include_file(char *path)\n{\n\tint fd = open(path, O_RDONLY);\n\tint n = 0, nr = 0;\n\tchar *dat;\n\tint size;\n\tif (fd == -1)\n\t\treturn -1;\n\tsize = file_size(fd) + 1;\n\tdat = malloc(size);\n\twhile ((n = read(fd, dat + nr, size - nr)) > 0)\n\t\tnr += n;\n\tclose(fd);\n\tdat[nr] = '\\0';\n\tbuf_file(path, dat, nr);\n\treturn 0;\n}\n\nint cpp_init(char *path)\n{\n\treturn include_file(path);\n}\n\nstatic int jumpws(void)\n{\n\tint old = cur;\n\twhile (cur < len && isspace(buf[cur]))\n\t\tcur++;\n\treturn cur == old;\n}\n\nstatic void read_word(char *dst)\n{\n\tjumpws();\n\twhile (cur < len && (isalnum(buf[cur]) || buf[cur] == '_'))\n\t\t*dst++ = buf[cur++];\n\t*dst = '\\0';\n}\n\nstatic int jumpcomment(void)\n{\n\tif (buf[cur] == '/' && buf[cur + 1] == '*') {\n\t\twhile (++cur < len) {\n\t\t\tif (buf[cur] == '*' && buf[cur + 1] == '/') {\n\t\t\t\tcur += 2;\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t}\n\tif (buf[cur] == '/' && buf[cur + 1] == '/') {\n\t\twhile (++cur < len && buf[cur] != '\\n')\n\t\t\tif (buf[cur] == '\\\\')\n\t\t\t\tcur++;\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n\nstatic int jumpstr(void)\n{\n\tif (buf[cur] == '\\'') {\n\t\twhile (++cur < len && buf[cur] != '\\'')\n\t\t\tif (buf[cur] == '\\\\')\n\t\t\t\tcur++;\n\t\tcur++;\n\t\treturn 0;\n\t}\n\tif (buf[cur] == '\"') {\n\t\twhile (++cur < len && buf[cur] != '\"')\n\t\t\tif (buf[cur] == '\\\\')\n\t\t\t\tcur++;\n\t\tcur++;\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n\nstatic void read_tilleol(char *dst)\n{\n\twhile (cur < len && isspace(buf[cur]) && buf[cur] != '\\n')\n\t\tcur++;\n\twhile (cur < len && buf[cur] != '\\n') {\n\t\tint last = cur;\n\t\tif (buf[cur] == '\\\\' && buf[cur + 1] == '\\n') {\n\t\t\tcur += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!jumpstr()) {\n\t\t\tmemcpy(dst, buf + last, cur - last);\n\t\t\tdst += cur - last;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!jumpcomment())\n\t\t\tcontinue;\n\t\t*dst++ = buf[cur++];\n\t}\n\t*dst = '\\0';\n}\n\nstatic char *locs[NLOCS] = {};\nstatic int nlocs = 0;\n\n/* header directory */\nvoid cpp_path(char *s)\n{\n\tlocs[nlocs++] = s;\n}\n\nstatic int include_find(char *name, int std)\n{\n\tint i;\n\tfor (i = std ? nlocs - 1 : nlocs; i >= 0; i--) {\n\t\tchar path[1 << 10];\n\t\tif (locs[i])\n\t\t\tsprintf(path, \"%s/%s\", locs[i], name);\n\t\telse\n\t\t\tstrcpy(path, name);\n\t\tif (!include_file(path))\n\t\t\treturn 0;\n\t}\n\treturn -1;\n}\n\nstatic void readarg(char *s)\n{\n\tint depth = 0;\n\tint beg = cur;\n\twhile (cur < len && (depth || (buf[cur] != ',' && buf[cur] != ')'))) {\n\t\tif (!jumpstr() || !jumpcomment())\n\t\t\tcontinue;\n\t\tswitch (buf[cur++]) {\n\t\tcase '(':\n\t\tcase '[':\n\t\tcase '{':\n\t\t\tdepth++;\n\t\t\tbreak;\n\t\tcase ')':\n\t\tcase ']':\n\t\tcase '}':\n\t\t\tdepth--;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (s) {\n\t\tmemcpy(s, buf + beg, cur - beg);\n\t\ts[cur - beg] = '\\0';\n\t}\n}\n\n/* find a macro; if undef is nonzero, search #undef-ed macros too */\nstatic int macro_find(char *name, int undef)\n{\n\tint i = mhead[(unsigned char) name[0]];\n\twhile (i > 0) {\n\t\tif (!strcmp(name, macros[i].name))\n\t\t\tif (!macros[i].undef || undef)\n\t\t\t\treturn i;\n\t\ti = mnext[i];\n\t}\n\treturn -1;\n}\n\nstatic void macro_undef(char *name)\n{\n\tint i = macro_find(name, 0);\n\tif (i >= 0)\n\t\tmacros[i].undef = 1;\n}\n\nstatic int macro_new(char *name)\n{\n\tint i = macro_find(name, 1);\n\tif (i >= 0)\n\t\treturn i;\n\tif (mcount >= NDEFS)\n\t\tdie(\"nomem: NDEFS reached!\\n\");\n\ti = mcount++;\n\tstrcpy(macros[i].name, name);\n\tmnext[i] = mhead[(unsigned char) name[0]];\n\tmhead[(unsigned char) name[0]] = i;\n\treturn i;\n}\n\nstatic void macro_define(void)\n{\n\tchar name[NAMELEN];\n\tstruct macro *d;\n\tread_word(name);\n\td = &macros[macro_new(name)];\n\td->isfunc = 0;\n\td->nargs = 0;\n\td->undef = 0;\n\tif (buf[cur] == '(') {\n\t\tcur++;\n\t\tjumpws();\n\t\twhile (cur < len && buf[cur] != ')') {\n\t\t\treadarg(d->args[d->nargs++]);\n\t\t\tjumpws();\n\t\t\tif (buf[cur] != ',')\n\t\t\t\tbreak;\n\t\t\tcur++;\n\t\t\tjumpws();\n\t\t}\n\t\tcur++;\n\t\td->isfunc = 1;\n\t}\n\tread_tilleol(d->def);\n}\n\nstatic char ebuf[MARGLEN];\nstatic int elen;\nstatic int ecur;\n\nstatic long evalexpr(void);\n\nstatic long cpp_eval(void)\n{\n\tchar evalbuf[MARGLEN];\n\tint old_limit;\n\tlong ret, clen;\n\tchar *cbuf;\n\tread_tilleol(evalbuf);\n\tbuf_new(BUF_EVAL, evalbuf, strlen(evalbuf));\n\telen = 0;\n\tecur = 0;\n\told_limit = bufs_limit;\n\tbufs_limit = bufs_n;\n\twhile (!cpp_read(&cbuf, &clen)) {\n\t\tmemcpy(ebuf + elen, cbuf, clen);\n\t\telen += clen;\n\t}\n\tbufs_limit = old_limit;\n\tret = evalexpr();\n\tbuf_pop();\n\treturn ret;\n}\n\nstatic void jumpifs(int jumpelse)\n{\n\tint depth = 0;\n\twhile (cur < len) {\n\t\tif (buf[cur] == '#') {\n\t\t\tchar cmd[NAMELEN];\n\t\t\tcur++;\n\t\t\tread_word(cmd);\n\t\t\tif (!strcmp(\"else\", cmd))\n\t\t\t\tif (!depth && !jumpelse)\n\t\t\t\t\tbreak;\n\t\t\tif (!strcmp(\"elif\", cmd))\n\t\t\t\tif (!depth && !jumpelse && cpp_eval())\n\t\t\t\t\tbreak;\n\t\t\tif (!strcmp(\"endif\", cmd)) {\n\t\t\t\tif (!depth)\n\t\t\t\t\tbreak;\n\t\t\t\telse\n\t\t\t\t\tdepth--;\n\t\t\t}\n\t\t\tif (!strcmp(\"ifdef\", cmd) || !strcmp(\"ifndef\", cmd) ||\n\t\t\t\t\t!strcmp(\"if\", cmd))\n\t\t\t\tdepth++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!jumpcomment())\n\t\t\tcontinue;\n\t\tif (!jumpstr())\n\t\t\tcontinue;\n\t\tcur++;\n\t}\n}\n\nstatic int cpp_cmd(void)\n{\n\tchar cmd[NAMELEN];\n\tcur++;\n\tread_word(cmd);\n\tif (!strcmp(\"define\", cmd)) {\n\t\tmacro_define();\n\t\treturn 0;\n\t}\n\tif (!strcmp(\"undef\", cmd)) {\n\t\tchar name[NAMELEN];\n\t\tread_word(name);\n\t\tmacro_undef(name);\n\t\treturn 0;\n\t}\n\tif (!strcmp(\"ifdef\", cmd) || !strcmp(\"ifndef\", cmd) ||\n\t\t\t\t\t\t!strcmp(\"if\", cmd)) {\n\t\tchar name[NAMELEN];\n\t\tint matched = 0;\n\t\tif (cmd[2]) {\n\t\t\tint not = cmd[2] == 'n';\n\t\t\tread_word(name);\n\t\t\tmatched = not ? macro_find(name, 0) < 0 :\n\t\t\t\t\tmacro_find(name, 0) >= 0;\n\t\t} else {\n\t\t\tmatched = cpp_eval();\n\t\t}\n\t\tif (!matched)\n\t\t\tjumpifs(0);\n\t\treturn 0;\n\t}\n\tif (!strcmp(\"else\", cmd) || !strcmp(\"elif\", cmd)) {\n\t\tjumpifs(1);\n\t\treturn 0;\n\t}\n\tif (!strcmp(\"endif\", cmd))\n\t\treturn 0;\n\tif (!strcmp(\"include\", cmd)) {\n\t\tchar file[NAMELEN];\n\t\tchar *s, *e;\n\t\tjumpws();\n\t\ts = buf + cur + 1;\n\t\te = strchr(buf + cur + 1, buf[cur] == '\"' ? '\"' : '>');\n\t\tmemcpy(file, s, e - s);\n\t\tfile[e - s] = '\\0';\n\t\tcur += e - s + 2;\n\t\tif (include_find(file, *e == '>') == -1)\n\t\t\terr(\"cannot include <%s>\\n\", file);\n\t\treturn 0;\n\t}\n\terr(\"unknown directive <%s>\\n\", cmd);\n\treturn 1;\n}\n\nstatic int macro_arg(struct macro *m, char *arg)\n{\n\tint i;\n\tfor (i = 0; i < m->nargs; i++)\n\t\tif (!strcmp(arg, m->args[i]))\n\t\t\treturn i;\n\treturn -1;\n}\n\nstatic int buf_arg_find(char *name)\n{\n\tint i;\n\tfor (i = bufs_n - 1; i >= 0; i--) {\n\t\tstruct buf *mbuf = &bufs[i];\n\t\tstruct macro *m = mbuf->macro;\n\t\tif (mbuf->type == BUF_MACRO && macro_arg(m, name) >= 0)\n\t\t\treturn i;\n\t\tif (mbuf->type == BUF_ARG)\n\t\t\ti = mbuf->arg_buf;\n\t}\n\treturn -1;\n}\n\nstatic void macro_expand(char *name)\n{\n\tstruct macro *m;\n\tint mbuf;\n\tif ((mbuf = buf_arg_find(name)) >= 0) {\n\t\tint arg = macro_arg(bufs[mbuf].macro, name);\n\t\tchar *dat = bufs[mbuf].args[arg];\n\t\tbuf_arg(dat, mbuf);\n\t\treturn;\n\t}\n\tm = &macros[macro_find(name, 0)];\n\tif (!m->isfunc) {\n\t\tbuf_macro(m);\n\t\treturn;\n\t}\n\tjumpws();\n\tif (buf[cur] == '(') {\n\t\tint i = 0;\n\t\tstruct buf *mbuf = &bufs[bufs_n];\n\t\tcur++;\n\t\tjumpws();\n\t\twhile (cur < len && buf[cur] != ')') {\n\t\t\treadarg(mbuf->args[i++]);\n\t\t\tjumpws();\n\t\t\tif (buf[cur] != ',')\n\t\t\t\tbreak;\n\t\t\tcur++;\n\t\t\tjumpws();\n\t\t}\n\t\twhile (i < m->nargs)\n\t\t\tmbuf->args[i++][0] = '\\0';\n\t\tcur++;\n\t\tbuf_macro(m);\n\t}\n}\n\nstatic int buf_expanding(char *macro)\n{\n\tint i;\n\tfor (i = bufs_n - 1; i >= 0; i--) {\n\t\tif (bufs[i].type == BUF_ARG)\n\t\t\treturn 0;\n\t\tif (bufs[i].type == BUF_MACRO &&\n\t\t\t\t!strcmp(macro, bufs[i].macro->name))\n\t\t\treturn 1;\n\t}\n\treturn 0;\n}\n\n/* return 1 for plain macros and arguments and 2 for function macros */\nstatic int expandable(char *word)\n{\n\tint i;\n\tif (buf_arg_find(word) >= 0)\n\t\treturn 1;\n\tif (buf_expanding(word))\n\t\treturn 0;\n\ti = macro_find(word, 0);\n\treturn i >= 0 ? macros[i].isfunc + 1 : 0;\n}\n\nvoid cpp_define(char *name, char *def)\n{\n\tchar tmp_buf[MDEFLEN];\n\tsprintf(tmp_buf, \"%s\\t%s\", name, def);\n\tbuf_new(BUF_TEMP, tmp_buf, strlen(tmp_buf));\n\tmacro_define();\n\tbuf_pop();\n}\n\nstatic int seen_macro;\t\t/* seen a macro; 2 if a function macro */\nstatic char seen_name[NAMELEN];\t/* the name of the last macro */\n\nstatic int hunk_off;\nstatic int hunk_len;\n\nint cpp_read(char **obuf, long *olen)\n{\n\tint old, end;\n\tint jump_name = 0;\n\t*olen = 0;\n\t*obuf = \"\";\n\tif (seen_macro == 1) {\n\t\tmacro_expand(seen_name);\n\t\tseen_macro = 0;\n\t}\n\tif (cur == len) {\n\t\tif (bufs_n < bufs_limit + 1)\n\t\t\treturn 1;\n\t\tbuf_pop();\n\t}\n\told = cur;\n\tif (cur < len && buf[cur] == '#')\n\t\tif (!cpp_cmd())\n\t\t\treturn 0;\n\twhile (cur < len) {\n\t\tif (!jumpws())\n\t\t\tcontinue;\n\t\tif (buf[cur] == '#')\n\t\t\tbreak;\n\t\tif (!jumpcomment())\n\t\t\tcontinue;\n\t\tif (seen_macro == 2) {\n\t\t\tif (buf[cur] == '(')\n\t\t\t\tmacro_expand(seen_name);\n\t\t\tseen_macro = 0;\n\t\t\told = cur;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!jumpstr())\n\t\t\tcontinue;\n\t\tif (isalnum(buf[cur]) || buf[cur] == '_') {\n\t\t\tchar word[NAMELEN];\n\t\t\tread_word(word);\n\t\t\tseen_macro = expandable(word);\n\t\t\tif (seen_macro) {\n\t\t\t\tstrcpy(seen_name, word);\n\t\t\t\tjump_name = 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (buf_iseval() && !strcmp(\"defined\", word)) {\n\t\t\t\tint parens = 0;\n\t\t\t\tjumpws();\n\t\t\t\tif (buf[cur] == '(') {\n\t\t\t\t\tparens = 1;\n\t\t\t\t\tcur++;\n\t\t\t\t}\n\t\t\t\tread_word(word);\n\t\t\t\tif (parens) {\n\t\t\t\t\tjumpws();\n\t\t\t\t\tcur++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tcur++;\n\t}\n\t/* macros are expanded later; ignoring their names */\n\tend = jump_name ? cur - strlen(seen_name) : cur;\n\tif (!buf_iseval()) {\n\t\thunk_off += hunk_len;\n\t\thunk_len = end - old;\n\t}\n\t*obuf = buf + old;\n\t*olen = end - old;\n\treturn 0;\n}\n\n/* preprocessor constant expression evaluation */\n\n#define TOK2(a)\t\t((a)[0] << 16 | (a)[1] << 8)\n#define TOK_NAME\t256\n#define TOK_NUM\t\t257\n#define TOK_EOF\t\t-1\n\nstatic char etok[NAMELEN];\nstatic int enext;\n\nstatic char *tok2[] = {\n\t\"<<\", \">>\", \"&&\", \"||\", \"==\", \"!=\", \"<=\", \">=\"\n};\n\nstatic int eval_tok(void)\n{\n\tchar *s = etok;\n\tint i;\n\twhile (ecur < elen) {\n\t\twhile (ecur < elen && isspace(ebuf[ecur]))\n\t\t\tecur++;\n\t\tif (ebuf[ecur] == '/' && ebuf[ecur + 1] == '*') {\n\t\t\twhile (ecur < elen && (ebuf[ecur - 2] != '*' ||\n\t\t\t\t\t\tebuf[ecur - 1] != '/'))\n\t\t\t\tecur++;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\tif (ecur >= elen)\n\t\treturn TOK_EOF;\n\tif (isalpha(ebuf[ecur]) || ebuf[ecur] == '_') {\n\t\twhile (isalnum(ebuf[ecur]) || ebuf[ecur] == '_')\n\t\t\t*s++ = ebuf[ecur++];\n\t\t*s = '\\0';\n\t\treturn TOK_NAME;\n\t}\n\tif (isdigit(ebuf[ecur])) {\n\t\twhile (isdigit(ebuf[ecur]))\n\t\t\t*s++ = ebuf[ecur++];\n\t\twhile (tolower(ebuf[ecur]) == 'u' || tolower(ebuf[ecur]) == 'l')\n\t\t\tecur++;\n\t\t*s = '\\0';\n\t\treturn TOK_NUM;\n\t}\n\tfor (i = 0; i < LEN(tok2); i++)\n\t\tif (TOK2(tok2[i]) == TOK2(ebuf + ecur)) {\n\t\t\tint ret = TOK2(tok2[i]);\n\t\t\tecur += 2;\n\t\t\treturn ret;\n\t\t}\n\treturn ebuf[ecur++];\n}\n\nstatic int eval_see(void)\n{\n\tif (enext == -1)\n\t\tenext = eval_tok();\n\treturn enext;\n}\n\nstatic int eval_get(void)\n{\n\tif (enext != -1) {\n\t\tint ret = enext;\n\t\tenext = -1;\n\t\treturn ret;\n\t}\n\treturn eval_tok();\n}\n\nstatic long eval_num(void)\n{\n\treturn atol(etok);\n}\n\nstatic int eval_jmp(int tok)\n{\n\tif (eval_see() == tok) {\n\t\teval_get();\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n\nstatic void eval_expect(int tok)\n{\n\teval_jmp(tok);\n}\n\nstatic char *eval_id(void)\n{\n\treturn etok;\n}\n\nstatic long evalcexpr(void);\n\nstatic long evalatom(void)\n{\n\tif (!eval_jmp(TOK_NUM))\n\t\treturn eval_num();\n\tif (!eval_jmp(TOK_NAME)) {\n\t\tint parens = !eval_jmp('(');\n\t\tlong ret;\n\t\teval_expect(TOK_NAME);\n\t\tret = macro_find(eval_id(), 0) >= 0;\n\t\tif (parens)\n\t\t\teval_expect(')');\n\t\treturn ret;\n\t}\n\tif (!eval_jmp('(')) {\n\t\tlong ret = evalcexpr();\n\t\teval_expect(')');\n\t\treturn ret;\n\t}\n\treturn -1;\n}\n\nstatic long evalpre(void)\n{\n\tif (!eval_jmp('!'))\n\t\treturn !evalpre();\n\tif (!eval_jmp('-'))\n\t\treturn -evalpre();\n\tif (!eval_jmp('~'))\n\t\treturn ~evalpre();\n\treturn evalatom();\n}\n\nstatic long evalmul(void)\n{\n\tlong ret = evalpre();\n\twhile (1) {\n\t\tif (!eval_jmp('*')) {\n\t\t\tret *= evalpre();\n\t\t\tcontinue;\n\t\t}\n\t\tif (!eval_jmp('/')) {\n\t\t\tret /= evalpre();\n\t\t\tcontinue;\n\t\t}\n\t\tif (!eval_jmp('%')) {\n\t\t\tret %= evalpre();\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\treturn ret;\n}\n\nstatic long evaladd(void)\n{\n\tlong ret = evalmul();\n\twhile (1) {\n\t\tif (!eval_jmp('+')) {\n\t\t\tret += evalmul();\n\t\t\tcontinue;\n\t\t}\n\t\tif (!eval_jmp('-')) {\n\t\t\tret -= evalmul();\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\treturn ret;\n}\n\nstatic long evalshift(void)\n{\n\tlong ret = evaladd();\n\twhile (1) {\n\t\tif (!eval_jmp(TOK2(\"<<\"))) {\n\t\t\tret <<= evaladd();\n\t\t\tcontinue;\n\t\t}\n\t\tif (!eval_jmp(TOK2(\">>\"))) {\n\t\t\tret >>= evaladd();\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\treturn ret;\n}\n\nstatic long evalcmp(void)\n{\n\tlong ret = evalshift();\n\twhile (1) {\n\t\tif (!eval_jmp('<')) {\n\t\t\tret = ret < evalshift();\n\t\t\tcontinue;\n\t\t}\n\t\tif (!eval_jmp('>')) {\n\t\t\tret = ret > evalshift();\n\t\t\tcontinue;\n\t\t}\n\t\tif (!eval_jmp(TOK2(\"<=\"))) {\n\t\t\tret = ret <= evalshift();\n\t\t\tcontinue;\n\t\t}\n\t\tif (!eval_jmp(TOK2(\">=\"))) {\n\t\t\tret = ret >= evalshift();\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\treturn ret;\n}\n\nstatic long evaleq(void)\n{\n\tlong ret = evalcmp();\n\twhile (1) {\n\t\tif (!eval_jmp(TOK2(\"==\"))) {\n\t\t\tret = ret == evalcmp();\n\t\t\tcontinue;\n\t\t}\n\t\tif (!eval_jmp(TOK2(\"!=\"))) {\n\t\t\tret = ret != evalcmp();\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\treturn ret;\n}\n\nstatic long evalbitand(void)\n{\n\tlong ret = evaleq();\n\twhile (!eval_jmp('&'))\n\t\tret &= evaleq();\n\treturn ret;\n}\n\nstatic long evalxor(void)\n{\n\tlong ret = evalbitand();\n\twhile (!eval_jmp('^'))\n\t\tret ^= evalbitand();\n\treturn ret;\n}\n\nstatic long evalbitor(void)\n{\n\tlong ret = evalxor();\n\twhile (!eval_jmp('|'))\n\t\tret |= evalxor();\n\treturn ret;\n}\n\nstatic long evaland(void)\n{\n\tlong ret = evalbitor();\n\twhile (!eval_jmp(TOK2(\"&&\")))\n\t\tret = ret && evalbitor();\n\treturn ret;\n}\n\nstatic long evalor(void)\n{\n\tlong ret = evaland();\n\twhile (!eval_jmp(TOK2(\"||\")))\n\t\tret = ret || evaland();\n\treturn ret;\n}\n\nstatic long evalcexpr(void)\n{\n\tlong ret = evalor();\n\tif (eval_jmp('?'))\n\t\treturn ret;\n\tif (ret)\n\t\treturn evalor();\n\twhile (eval_get() != ':')\n\t\t;\n\treturn evalor();\n}\n\nstatic long evalexpr(void)\n{\n\tenext = -1;\n\treturn evalcexpr();\n}\n\nstatic int buf_loc(char *s, int off)\n{\n\tchar *e = s + off;\n\tint n = 1;\n\twhile ((s = strchr(s, '\\n')) && s < e) {\n\t\tn++;\n\t\ts++;\n\t}\n\treturn n;\n}\n\nchar *cpp_loc(long addr)\n{\n\tstatic char loc[256];\n\tint line = -1;\n\tint i;\n\tfor (i = bufs_n - 1; i > 0; i--)\n\t\tif (bufs[i].type == BUF_FILE)\n\t\t\tbreak;\n\tif (addr >= hunk_off && i == bufs_n - 1)\n\t\tline = buf_loc(buf, (cur - hunk_len) + (addr - hunk_off));\n\telse\n\t\tline = buf_loc(bufs[i].buf, bufs[i].cur);\n\tsprintf(loc, \"%s:%d\", bufs[i].path, line);\n\treturn loc;\n}\n"
  },
  {
    "path": "div.s",
    "content": "@ ARM software division implementation\n@ These functions are assembled using neatas and are included in gen.c\n.global __udivdi3\n__udivdi3:\n\tmov\tr2, #0\n\tmov\tr3, #0\n\n\t@ zero divider\n\ttst\tr1, r1\n\tbeq\t.end\n\n\t@ shift the operand\n.shl:\n\tmovs\tr12, r1, LSL r2\n\tadd\tr2, r2, #1\n\tbpl\t.shl\n\n\tmov\tr12, #1\n\n\t@ the main division algorithm\n.shr:\n\tsubs\tr2, r2, #1\n\tbmi\t.end\n\tcmps\tr0, r1, LSL r2\n\tbcc\t.shr\n\tsub\tr0, r0, r1, LSL r2\n\tadd\tr3, r3, r12, LSL r2\n\tb\t.shr\n.end:\n\tmov\tr1, r0\n\tmov\tr0, r3\n\tmov\tpc, lr\n\n.global __umoddi3\n__umoddi3:\n\tstmfd\tsp!, {lr}\n\tbl\t__udivdi3\n\tmov\tr0, r1\n\tldmfd\tsp!, {pc}\n\n.global __divdi3\n__divdi3:\n\tstmfd\tsp!, {r4, r5, lr}\n\n\tmov\tr4, r0\n\tmov\tr5, r1\n\n\t@ handle negative operands\n\ttst\tr0, r0\n\trsbmi\tr0, r0, #0\n\ttst\tr1, r1\n\trsbmi\tr1, r1, #0\n\n\tbl\t__udivdi3\n\n\t@ result is negative\n\tteq\tr4, r5\n\trsbmi\tr0, r0, #0\n\ttst\tr4, r4\n\trsbmi\tr1, r1, #0\n\n\tldmfd\tsp!, {r4, r5, pc}\n\n.global __moddi3\n__moddi3:\n\tstmfd\tsp!, {lr}\n\tbl\t__divdi3\n\tmov\tr0, r1\n\tldmfd\tsp!, {pc}\n"
  },
  {
    "path": "gen.c",
    "content": "/* neatcc code generation */\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include \"ncc.h\"\n\nstatic struct mem ds;\t\t/* data segment */\nstatic struct mem cs;\t\t/* code segment */\nstatic long bsslen;\t\t/* bss segment size */\nstatic struct ic *ic;\t\t/* current instruction stream */\nstatic long ic_n;\t\t/* number of instructions in ic[] */\nstatic long ic_i;\t\t/* current instruction */\nstatic long *ic_luse;\t\t/* last instruction in which values are used */\n\nstatic long *loc_off;\t\t/* offset of locals on the stack */\nstatic long loc_n, loc_sz;\t/* number of locals */\nstatic long loc_pos;\t\t/* current stack position */\nstatic int *loc_mem;\t\t/* local was accessed on the stack */\n\nstatic char (*ds_name)[NAMELEN];/* data section symbols */\nstatic long *ds_off;\t\t/* data section offsets */\nstatic long ds_n, ds_sz;\t/* number of data section symbols */\n\nstatic int func_argc;\t\t/* number of arguments */\nstatic int func_varg;\t\t/* varargs */\nstatic int func_regs;\t\t/* used registers */\nstatic int func_maxargs;\t/* the maximum number of arguments on the stack */\nstatic long *ic_bbeg;\t\t/* whether each instruction begins a basic block */\n\nstatic long ra_vmap[N_REGS];\t/* register to intermediate value assignments */\nstatic long ra_lmap[N_REGS];\t/* register to local assignments */\nstatic long *ra_gmask;\t\t/* the mask of good registers for each value */\nstatic long ra_live[NTMPS];\t/* live values */\nstatic int ra_vmax;\t\t/* the number of values stored on the stack */\n\nstatic long loc_add(long pos)\n{\n\tif (loc_n >= loc_sz) {\n\t\tloc_sz = MAX(128, loc_sz * 2);\n\t\tloc_off = mextend(loc_off, loc_n, loc_sz, sizeof(loc_off[0]));\n\t}\n\tloc_off[loc_n] = pos;\n\treturn loc_n++;\n}\n\nlong o_mklocal(long sz)\n{\n\tloc_pos += ALIGN(sz, ULNG);\n\treturn loc_add(loc_pos);\n}\n\nvoid o_rmlocal(long addr, long sz)\n{\n}\n\nlong o_arg2loc(int i)\n{\n\treturn i;\n}\n\nvoid o_bsnew(char *name, long size, int global)\n{\n\tout_def(name, OUT_BSS | (global ? OUT_GLOB : 0), bsslen, size);\n\tbsslen += ALIGN(size, OUT_ALIGNMENT);\n}\n\nlong o_dsnew(char *name, long size, int global)\n{\n\tint idx;\n\tif (ds_n >= ds_sz) {\n\t\tds_sz = MAX(128, ds_sz * 2);\n\t\tds_name = mextend(ds_name, ds_n, ds_sz, sizeof(ds_name[0]));\n\t\tds_off = mextend(ds_off, ds_n, ds_sz, sizeof(ds_off[0]));\n\t}\n\tidx = ds_n++;\n\tstrcpy(ds_name[idx], name);\n\tds_off[idx] = mem_len(&ds);\n\tout_def(name, OUT_DS | (global ? OUT_GLOB : 0), mem_len(&ds), size);\n\tmem_putz(&ds, ALIGN(size, OUT_ALIGNMENT));\n\treturn ds_off[idx];\n}\n\nvoid o_dscpy(long addr, void *buf, long len)\n{\n\tmem_cpy(&ds, addr, buf, len);\n}\n\nstatic int dat_off(char *name)\n{\n\tint i;\n\tfor (i = 0; i < ds_n; i++)\n\t\tif (!strcmp(name, ds_name[i]))\n\t\t\treturn ds_off[i];\n\treturn 0;\n}\n\nvoid o_dsset(char *name, long off, long bt)\n{\n\tlong sym_off = dat_off(name) + off;\n\tlong num, roff, rsym;\n\tif (!o_popnum(&num)) {\n\t\tmem_cpy(&ds, sym_off, &num, T_SZ(bt));\n\t} else if (!o_popsym(&rsym, &roff)) {\n\t\tout_rel(rsym, OUT_DS, sym_off);\n\t\tmem_cpy(&ds, sym_off, &roff, T_SZ(bt));\n\t} else {\n\t\terr(\"illegal assignment to static variables\\n\");\n\t}\n}\n\nstatic int ra_vreg(int val)\n{\n\tint i;\n\tfor (i = 0; i < LEN(ra_vmap); i++)\n\t\tif (ra_vmap[i] == val)\n\t\t\treturn i;\n\treturn -1;\n}\n\nstatic int ra_lreg(int loc)\n{\n\tint i;\n\tfor (i = 0; i < LEN(ra_lmap); i++)\n\t\tif (ra_lmap[i] == loc)\n\t\t\treturn i;\n\treturn -1;\n}\n\n/* mask of registers assigned to locals */\nstatic long ra_lmask(void)\n{\n\tlong m = 0;\n\tint i;\n\tfor (i = 0; i < LEN(ra_lmap); i++)\n\t\tif (ra_lmap[i] >= 0)\n\t\t\tm |= (1 << i);\n\treturn m;\n}\n\n/* mask of registers assigned to values */\nstatic long ra_vmask(void)\n{\n\tlong m = 0;\n\tint i;\n\tfor (i = 0; i < LEN(ra_vmap); i++)\n\t\tif (ra_vmap[i] >= 0)\n\t\t\tm |= (1 << i);\n\treturn m;\n}\n\n/* find a temporary register specified in the given mask */\nstatic long ra_regscn(long mask)\n{\n\tint i;\n\tfor (i = 0; i < N_TMPS; i++)\n\t\tif ((1 << tmpregs[i]) & mask)\n\t\t\treturn tmpregs[i];\n\treturn -1;\n}\n\n/* find a register, with the given good, acceptable, and bad register masks */\nstatic long ra_regget(long iv, long gmask, long amask, long bmask)\n{\n\tlong lmask, vmask;\n\tgmask &= ~bmask & amask;\n\tamask &= ~bmask;\n\tif (ra_vreg(iv) >= 0 && (1 << ra_vreg(iv)) & (gmask | amask))\n\t\treturn ra_vreg(iv);\n\tvmask = ra_vmask();\n\tlmask = ra_lmask();\n\tif (ra_regscn(gmask & ~vmask & ~lmask) >= 0)\n\t\treturn ra_regscn(gmask & ~vmask & ~lmask);\n\tif (ra_regscn(amask & ~vmask & ~lmask) >= 0)\n\t\treturn ra_regscn(amask & ~vmask & ~lmask);\n\tif (ra_regscn(gmask) >= 0)\n\t\treturn ra_regscn(gmask);\n\tif (ra_regscn(amask) >= 0)\n\t\treturn ra_regscn(amask);\n\tdie(\"neatcc: cannot allocate an acceptable register\\n\");\n\treturn 0;\n}\n\n/* find a free and cheap register */\nstatic long ra_regcheap(long mask)\n{\n\treturn ra_regscn(mask & (func_regs | (R_TMPS & ~R_PERM)) &\n\t\t\t~ra_lmask() & ~ra_vmask());\n}\n\n/* allocate registers for the current instruction */\nstatic void ra_map(int *rd, int *r1, int *r2, int *r3, long *mt)\n{\n\tlong md, m1, m2, m3;\n\tstruct ic *c = &ic[ic_i];\n\tlong all = 0;\n\tint n = ic_regcnt(c);\n\tint oc = O_C(c->op);\n\tint i;\n\t*rd = -1;\n\t*r1 = -1;\n\t*r2 = -1;\n\t*r3 = -1;\n\t*mt = 0;\n\t/* optimizing loading locals: point to local's register */\n\tif (oc == (O_LD | O_LOC) && ra_lreg(c->a1) >= 0 &&\n\t\t\tra_vmap[ra_lreg(c->a1)] < 0) {\n\t\t*rd = ra_lreg(c->a1);\n\t\tfunc_regs |= 1 << *rd;\n\t\treturn;\n\t}\n\t/* do not use argument registers to hold call destination */\n\tif (oc & O_CALL)\n\t\tfor (i = 0; i < MIN(c->a3, N_ARGS); i++)\n\t\t\tall |= (1 << argregs[i]);\n\t/* instructions on locals can be simplified */\n\tif (oc & O_LOC) {\n\t\tif (oc & O_MOV)\n\t\t\toc = O_ADD | O_NUM;\n\t\tif (oc & (O_ST | O_LD))\n\t\t\toc = (oc & ~O_LOC) & O_NUM;\n\t}\n\tif (i_reg(c->op, &md, &m1, &m2, &m3, mt))\n\t\tdie(\"neatcc: instruction %08lx not supported\\n\", c->op);\n\t/*\n\t * the registers used in global register allocation should not\n\t * be used in the last instruction of a basic block.\n\t */\n\tif (c->op & (O_JZ | O_JCC))\n\t\tfor (i = 0; i < LEN(ra_lmap); i++)\n\t\t\tif (reg_rmap(ic_i, i) >= 0 && ra_lmap[i] != reg_rmap(ic_i, i))\n\t\t\t\tall |= (1 << i);\n\t/* allocating registers for the operands */\n\tif (n >= 2) {\n\t\t*r2 = ra_regget(c->a2, m2, m2, all);\n\t\tall |= (1 << *r2);\n\t}\n\tif (n >= 1) {\n\t\t*r1 = ra_regget(c->a1, m1, m1, all);\n\t\tall |= (1 << *r1);\n\t}\n\tif (n >= 3) {\n\t\t*r3 = ra_regget(c->a3, m3, m3, all);\n\t\tall |= (1 << *r3);\n\t}\n\tif (c->op & O_OUT) {\n\t\tlong m4 = (md ? md : m1) & ~all;\n\t\tlong a4 = md ? ic_i : c->a1;\n\t\tif (n >= 1 && !md)\n\t\t\t*rd = *r1;\n\t\telse if (ra_gmask[ic_i] & md & ~all)\n\t\t\t*rd = ra_regget(ic_i, ra_gmask[ic_i], md, 0);\n\t\telse if (n >= 2 && md & (1 << *r2) && ic_luse[*r2] <= ic_i)\n\t\t\t*rd = *r2;\n\t\telse if (n >= 1 && md & (1 << *r1) && ic_luse[*r1] <= ic_i)\n\t\t\t*rd = *r1;\n\t\telse\n\t\t\t*rd = ra_regget(ic_i, ra_gmask[ic_i], md, 0);\n\t\t/* if overwriting a local, use another register */\n\t\tif (ra_lmap[*rd] >= 0)\n\t\t\tif (m4 & ~(1 << *rd))\n\t\t\t\t*rd = ra_regget(a4, ra_gmask[ic_i], m4 & ~(1 << *rd), 0);\n\t\tif (n >= 1 && !md)\n\t\t\t*r1 = *rd;\n\t\tall |= (1 << *rd);\n\t}\n\tfunc_regs |= all | *mt;\n}\n\nstatic long iv_rank(long iv)\n{\n\tint i;\n\tfor (i = 0; i < LEN(ra_live); i++)\n\t\tif (ra_live[i] == iv)\n\t\t\treturn i;\n\tdie(\"neatcc: the specified value is not live\\n\");\n\treturn 0;\n}\n\nstatic long iv_addr(long rank)\n{\n\treturn loc_pos + rank * ULNG + ULNG;\n}\n\nstatic void loc_toreg(long loc, long off, int reg, int bt)\n{\n\tloc_mem[loc]++;\n\ti_ins(O_MK(O_LD | O_NUM, bt), reg, REG_FP, -loc_off[loc] + off, 0);\n}\n\nstatic void loc_tomem(long loc, long off, int reg, int bt)\n{\n\tloc_mem[loc]++;\n\ti_ins(O_MK(O_ST | O_NUM, bt), 0, reg, REG_FP, -loc_off[loc] + off);\n}\n\nstatic void loc_toadd(long loc, long off, int reg)\n{\n\tloc_mem[loc]++;\n\ti_ins(O_ADD | O_NUM, reg, REG_FP, -loc_off[loc] + off, 0);\n}\n\n/* return nonzero if the local is read at least once in this basic block */\nstatic int loc_isread(long loc)\n{\n\tint i;\n\tfor (i = ic_i + 1; i < ic_n && !ic_bbeg[i]; i++)\n\t\tif (ic[i].op & O_LOC)\n\t\t\treturn ic[i].op & O_LD;\n\treturn 0;\n}\n\nstatic void val_toreg(long val, int reg)\n{\n\ti_ins(O_MK(O_LD | O_NUM, ULNG), reg, REG_FP, -iv_addr(iv_rank(val)), 0);\n}\n\nstatic void val_tomem(long val, int reg)\n{\n\tlong rank = iv_rank(val);\n\tra_vmax = MAX(ra_vmax, rank + 1);\n\ti_ins(O_MK(O_ST | O_NUM, ULNG), 0, reg, REG_FP, -iv_addr(rank));\n}\n\n/* move the value to the stack */\nstatic void ra_spill(int reg)\n{\n\tif (ra_vmap[reg] >= 0) {\n\t\tval_tomem(ra_vmap[reg], reg);\n\t\tra_vmap[reg] = -1;\n\t}\n\tif (ra_lmap[reg] >= 0) {\n\t\tif (ra_lmap[reg] == reg_rmap(ic_i, reg))\n\t\t\tloc_tomem(ra_lmap[reg], 0, reg, ULNG);\n\t\tra_lmap[reg] = -1;\n\t}\n}\n\n/* set the value to the given register */\nstatic void ra_vsave(long iv, int reg)\n{\n\tint i;\n\tra_vmap[reg] = iv;\n\tfor (i = 0; i < LEN(ra_live); i++)\n\t\tif (ra_live[i] < 0)\n\t\t\tbreak;\n\tif (i == LEN(ra_live))\n\t\tdie(\"neatcc: too many live values\\n\");\n\tra_live[i] = iv;\n}\n\n/* load the value into a register */\nstatic void ra_vload(long iv, int reg)\n{\n\tif (ra_vmap[reg] == iv)\n\t\treturn;\n\tif (ra_vmap[reg] >= 0 || ra_lmap[reg] >= 0)\n\t\tra_spill(reg);\n\tif (ra_vreg(iv) >= 0) {\n\t\ti_ins(O_MK(O_MOV, ULNG), reg, ra_vreg(iv), 0, 0);\n\t\tra_vmap[ra_vreg(iv)] = -1;\n\t} else {\n\t\tval_toreg(iv, reg);\n\t}\n\tra_vmap[reg] = iv;\n}\n\n/* the value is no longer needed */\nstatic void ra_vdrop(long iv)\n{\n\tint i;\n\tfor (i = 0; i < LEN(ra_live); i++)\n\t\tif (ra_live[i] == iv)\n\t\t\tra_live[i] = -1;\n\tif (ra_vreg(iv) >= 0)\n\t\tra_vmap[ra_vreg(iv)] = -1;\n}\n\n/* move the given value to memory or a free register */\nstatic void ra_vmove(long iv, long mask)\n{\n\tint src = ra_vreg(iv);\n\tint dst = ra_regcheap(mask);\n\tif (dst >= 0 && ra_vmap[dst] < 0 && ra_lmap[dst] < 0) {\n\t\ti_ins(O_MK(O_MOV, ULNG), dst, src, 0, 0);\n\t\tra_vmap[dst] = iv;\n\t} else {\n\t\tval_tomem(iv, src);\n\t}\n\tra_vmap[src] = -1;\n}\n\n/* load the value of local loc into register reg */\nstatic void ra_lload(long loc, long off, int reg, int bt)\n{\n\tint greg = reg_lmap(ic_i, loc);\n\tif (greg >= 0) {\n\t\tint lreg = ra_lreg(loc);\n\t\t/* values using the same register */\n\t\tif (ra_vmap[greg] >= 0)\n\t\t\tra_vmove(ra_vmap[greg],\n\t\t\t\tra_gmask[ra_vmap[greg]] & ~(1 << reg));\n\t\tif (lreg >= 0) {\n\t\t\tra_lmap[lreg] = -1;\n\t\t\tif (lreg != greg)\n\t\t\t\ti_ins(O_MK(O_MOV, bt), greg, lreg, 0, 0);\n\t\t} else {\n\t\t\tloc_toreg(loc, off, greg, bt);\n\t\t}\n\t\tra_lmap[greg] = loc;\n\t}\n\tif (ra_lreg(loc) < 0 && reg_safe(loc) && loc_isread(loc)) {\n\t\tra_lmap[reg] = loc;\n\t\tloc_toreg(loc, off, reg, bt);\n\t}\n\tif (ra_lreg(loc) >= 0) {\n\t\tif (ra_lreg(loc) != reg)\n\t\t\ti_ins(O_MK(O_MOV, bt), reg, ra_lreg(loc), 0, 0);\n\t} else {\n\t\tloc_toreg(loc, off, reg, bt);\n\t}\n}\n\n/* register reg contains the value of local loc */\nstatic void ra_lsave(long loc, long off, int reg, int bt)\n{\n\tint lreg = ra_lreg(loc);\n\tint greg = reg_lmap(ic_i, loc);\n\tif (greg >= 0) {\n\t\tif (lreg >= 0 && lreg != greg)\n\t\t\tra_lmap[lreg] = -1;\n\t\tif (ra_vmap[greg] >= 0)\t/* values using the same register */\n\t\t\tra_vmove(ra_vmap[greg],\n\t\t\t\tra_gmask[ra_vmap[greg]] & ~(1 << reg));\n\t\ti_ins(O_MK(O_MOV, bt), greg, reg, 0, 0);\n\t\tra_lmap[greg] = loc;\n\t} else {\n\t\tif (lreg >= 0)\n\t\t\tra_lmap[lreg] = -1;\n\t\tloc_tomem(loc, off, reg, bt);\n\t\tif (ra_lmap[reg] < 0 && reg_safe(loc) && loc_isread(loc))\n\t\t\tra_lmap[reg] = loc;\n\t}\n}\n\n/* end of a basic block */\nstatic void ra_bbend(void)\n{\n\tint i;\n\t/* save values to memory */\n\tfor (i = 0; i < LEN(ra_vmap); i++)\n\t\tif (ra_vmap[i] >= 0)\n\t\t\tra_spill(i);\n\t/* dropping local caches */\n\tfor (i = 0; i < LEN(ra_lmap); i++)\n\t\tif (ra_lmap[i] != reg_rmap(ic_i, i) && ra_lmap[i] >= 0)\n\t\t\tra_spill(i);\n\t/* load global register allocations from memory */\n\tfor (i = 0; i < LEN(ra_lmap); i++) {\n\t\tif (ra_lmap[i] != reg_rmap(ic_i, i)) {\n\t\t\tra_lmap[i] = reg_rmap(ic_i, i);\n\t\t\tloc_toreg(ra_lmap[i], 0, i, ULNG);\n\t\t}\n\t}\n}\n\nstatic void ra_init(struct ic *ic, long ic_n)\n{\n\tlong md, m1, m2, m3, mt;\n\tint i, j;\n\tic_bbeg = calloc(ic_n, sizeof(ic_bbeg[0]));\n\tra_gmask = calloc(ic_n, sizeof(ra_gmask[0]));\n\tloc_mem = calloc(loc_n, sizeof(loc_mem[0]));\n\t/* ic_bbeg */\n\tfor (i = 0; i < ic_n; i++) {\n\t\tif (i + 1 < ic_n && ic[i].op & (O_JXX | O_RET))\n\t\t\tic_bbeg[i + 1] = 1;\n\t\tif (ic[i].op & O_JXX && ic[i].a3 < ic_n)\n\t\t\tic_bbeg[ic[i].a3] = 1;\n\t}\n\t/* ra_gmask */\n\tfor (i = 0; i < ic_n; i++) {\n\t\tint n = ic_regcnt(ic + i);\n\t\tint op = ic[i].op;\n\t\ti_reg(op, &md, &m1, &m2, &m3, &mt);\n\t\tif (n >= 1)\n\t\t\tra_gmask[ic[i].a1] = m1;\n\t\tif (n >= 2)\n\t\t\tra_gmask[ic[i].a2] = m2;\n\t\tif (n >= 3)\n\t\t\tra_gmask[ic[i].a3] = m3;\n\t\tif (O_C(op) == (O_ST | O_LOC) && reg_lmap(i, ic[i].a2))\n\t\t\tra_gmask[ic[i].a1] = 1 << reg_lmap(i, ic[i].a2);\n\t\tif (op & O_CALL)\n\t\t\tfor (j = 0; j < MIN(N_ARGS, ic[i].a3); j++)\n\t\t\t\tra_gmask[ic[i].args[j]] = 1 << argregs[j];\n\t}\n\t/* ra_vmap */\n\tfor (i = 0; i < LEN(ra_vmap); i++)\n\t\tra_vmap[i] = -1;\n\t/* ra_lmap */\n\tfor (i = 0; i < LEN(ra_lmap); i++)\n\t\tra_lmap[i] = reg_rmap(0, i);\n\tfunc_regs |= reg_mask();\n\t/* ra_live */\n\tfor (i = 0; i < LEN(ra_live); i++)\n\t\tra_live[i] = -1;\n\tra_vmax = 0;\n\tfunc_maxargs = 0;\n}\n\nstatic void ra_done(void)\n{\n\tfree(ic_bbeg);\n\tfree(ra_gmask);\n\tfree(loc_mem);\n}\n\nstatic void ic_gencode(struct ic *ic, long ic_n)\n{\n\tint rd, r1, r2, r3;\n\tlong mt;\n\tint i, j;\n\t/* loading arguments in their allocated registers */\n\tfor (i = 0; i < LEN(ra_lmap); i++) {\n\t\tint loc = ra_lmap[i];\n\t\tif (loc >= 0 && loc < func_argc)\n\t\t\tif (loc >= N_ARGS || i != argregs[loc])\n\t\t\t\tloc_toreg(loc, 0, i, ULNG);\n\t}\n\t/* generating code */\n\tfor (i = 0; i < ic_n; i++) {\n\t\tlong op = ic[i].op;\n\t\tlong oc = O_C(op);\n\t\tint n = ic_regcnt(ic + i);\n\t\tic_i = i;\n\t\ti_label(i);\n\t\tra_map(&rd, &r1, &r2, &r3, &mt);\n\t\tif (oc & O_CALL) {\n\t\t\tint argc = ic[i].a3;\n\t\t\tint aregs = MIN(N_ARGS, argc);\n\t\t\t/* arguments passed via stack */\n\t\t\tfor (j = argc - 1; j >= aregs; --j) {\n\t\t\t\tint v = ic[i].args[j];\n\t\t\t\tint rx = ra_vreg(v) >= 0 ? ra_vreg(v) : rd;\n\t\t\t\tra_vload(v, rx);\n\t\t\t\ti_ins(O_MK(O_ST | O_NUM, ULNG), 0,\n\t\t\t\t\trx, REG_SP, (j - aregs) * ULNG);\n\t\t\t\tra_vdrop(v);\n\t\t\t}\n\t\t\tfunc_maxargs = MAX(func_maxargs, argc - aregs);\n\t\t\t/* arguments passed via registers */\n\t\t\tfor (j = aregs - 1; j >= 0; --j)\n\t\t\t\tra_vload(ic[i].args[j], argregs[j]);\n\t\t}\n\t\t/* loading the operands */\n\t\tif (n >= 1)\n\t\t\tra_vload(ic[i].a1, r1);\n\t\tif (n >= 2)\n\t\t\tra_vload(ic[i].a2, r2);\n\t\tif (n >= 3)\n\t\t\tra_vload(ic[i].a3, r3);\n\t\t/* dropping values that are no longer used */\n\t\tfor (j = 0; j < LEN(ra_live); j++)\n\t\t\tif (ra_live[j] >= 0 && ic_luse[ra_live[j]] <= i)\n\t\t\t\tra_vdrop(ra_live[j]);\n\t\t/* saving values stored in registers that may change */\n\t\tfor (j = 0; j < N_REGS; j++)\n\t\t\tif (mt & (1 << j))\n\t\t\t\tra_spill(j);\n\t\t/* overwriting a value that is needed later (unless loading a local to its register) */\n\t\tif (oc & O_OUT)\n\t\t\tif (oc != (O_LD | O_LOC) || ra_lmap[rd] != ic[i].a1 ||\n\t\t\t\t\tra_vmap[rd] >= 0)\n\t\t\t\tra_spill(rd);\n\t\t/* before the last instruction of a basic block; for jumps */\n\t\tif (i + 1 < ic_n && ic_bbeg[i + 1] && oc & O_JXX)\n\t\t\tra_bbend();\n\t\t/* performing the instruction */\n\t\tif (oc & O_BOP)\n\t\t\ti_ins(op, rd, r1, oc & O_NUM ? ic[i].a2 : r2, 0);\n\t\tif (oc & O_UOP)\n\t\t\ti_ins(op, rd, r1, r2, 0);\n\t\tif (oc == (O_LD | O_NUM))\n\t\t\ti_ins(op, rd, r1, ic[i].a2, 0);\n\t\tif (oc == (O_LD | O_LOC))\n\t\t\tra_lload(ic[i].a1, ic[i].a2, rd, O_T(op));\n\t\tif (oc == (O_ST | O_NUM))\n\t\t\ti_ins(op, 0, r1, r2, ic[i].a3);\n\t\tif (oc == (O_ST | O_LOC))\n\t\t\tra_lsave(ic[i].a2, ic[i].a3, r1, O_T(op));\n\t\tif (oc == O_RET)\n\t\t\ti_ins(op, 0, r1, 0, 0);\n\t\tif (oc == O_MOV)\n\t\t\ti_ins(op, rd, r1, 0, 0);\n\t\tif (oc == (O_MOV | O_NUM))\n\t\t\ti_ins(op, rd, ic[i].a1, 0, 0);\n\t\tif (oc == (O_MOV | O_LOC))\n\t\t\tloc_toadd(ic[i].a1, ic[i].a2, rd);\n\t\tif (oc == (O_MOV | O_SYM))\n\t\t\ti_ins(op, rd, ic[i].a1, ic[i].a2, 0);\n\t\tif (oc == O_CALL)\n\t\t\ti_ins(op, rd, r1, 0, 0);\n\t\tif (oc == (O_CALL | O_SYM))\n\t\t\ti_ins(op, rd, ic[i].a1, ic[i].a2, 0);\n\t\tif (oc == O_JMP)\n\t\t\ti_ins(op, 0, 0, 0, ic[i].a3);\n\t\tif (oc & O_JZ)\n\t\t\ti_ins(op, 0, r1, 0, ic[i].a3);\n\t\tif (oc & O_JCC)\n\t\t\ti_ins(op, 0, r1, oc & O_NUM ? ic[i].a2 : r2, ic[i].a3);\n\t\tif (oc == O_MSET)\n\t\t\ti_ins(op, 0, r1, r2, r3);\n\t\tif (oc == O_MCPY)\n\t\t\ti_ins(op, 0, r1, r2, r3);\n\t\t/* saving back the output register */\n\t\tif (oc & O_OUT && ic_luse[i] > i)\n\t\t\tra_vsave(ic_i, rd);\n\t\t/* after the last instruction of a basic block */\n\t\tif (i + 1 < ic_n && ic_bbeg[i + 1] && !(oc & O_JXX))\n\t\t\tra_bbend();\n\t}\n\ti_label(ic_n);\n}\n\nstatic void ic_reset(void)\n{\n\to_tmpdrop(-1);\n\to_back(0);\n\tfree(loc_off);\n\tloc_off = NULL;\n\tloc_n = 0;\n\tloc_sz = 0;\n\tloc_pos = I_LOC0;\n}\n\nvoid o_func_beg(char *name, int argc, int global, int varg)\n{\n\tint i;\n\tfunc_argc = argc;\n\tfunc_varg = varg;\n\tfunc_regs = 0;\n\tic_reset();\n\tfor (i = 0; i < argc; i++)\n\t\tloc_add(I_ARG0 + -i * ULNG);\n\tout_def(name, (global ? OUT_GLOB : 0) | OUT_CS, mem_len(&cs), 0);\n}\n\nvoid o_code(char *name, char *c, long c_len)\n{\n\tout_def(name, OUT_CS, mem_len(&cs), 0);\n\tmem_put(&cs, c, c_len);\n}\n\nvoid o_func_end(void)\n{\n\tlong spsub;\n\tlong sargs = 0;\n\tlong sargs_last = -1;\n\tlong sregs_pos;\n\tchar *c;\n\tlong c_len, *rsym, *rflg, *roff, rcnt;\n\tint leaf = 1;\n\tint locs = 0;\t\t\t/* accessing locals on the stack */\n\tint i;\n\tic_get(&ic, &ic_n);\t\t/* the intermediate code */\n\treg_init(ic, ic_n);\t\t/* global register allocation */\n\tra_init(ic, ic_n);\t\t/* initialize register allocation */\n\tic_luse = ic_lastuse(ic, ic_n);\n\tic_gencode(ic, ic_n);\t\t/* generating machine code */\n\tfree(ic_luse);\n\t/* deciding which arguments to save */\n\tfor (i = 0; i < func_argc; i++)\n\t\tif (loc_mem[i])\n\t\t\tsargs_last = i + 1;\n\tfor (i = 0; i < N_ARGS && (func_varg || i < sargs_last); i++)\n\t\tsargs |= 1 << argregs[i];\n\t/* computing the amount of stack subtraction */\n\tfor (i = 0; i < loc_n; i++)\n\t\tif (loc_mem[i])\n\t\t\tlocs = 1;\n\tspsub = (locs || ra_vmax) ? loc_pos + ra_vmax * ULNG : 0;\n\tfor (i = 0; i < N_TMPS; i++)\n\t\tif (((1 << tmpregs[i]) & func_regs & R_PERM) != 0)\n\t\t\tspsub += ULNG;\n\tsregs_pos = spsub;\n\tspsub += func_maxargs * ULNG;\n\t/* leaf functions */\n\tfor (i = 0; i < ic_n; i++)\n\t\tif (ic[i].op & O_CALL)\n\t\t\tleaf = 0;\n\t/* adding function prologue and epilogue */\n\ti_wrap(func_argc, sargs, spsub, spsub || locs || !leaf,\n\t\tfunc_regs & R_PERM, -sregs_pos);\n\tra_done();\n\ti_code(&c, &c_len, &rsym, &rflg, &roff, &rcnt);\n\tfor (i = 0; i < rcnt; i++)\t/* adding the relocations */\n\t\tout_rel(rsym[i], rflg[i], roff[i] + mem_len(&cs));\n\tmem_put(&cs, c, c_len);\t\t/* appending function code */\n\tfree(c);\n\tfree(rsym);\n\tfree(rflg);\n\tfree(roff);\n\tfor (i = 0; i < ic_n; i++)\n\t\tic_free(&ic[i]);\n\tfree(ic);\n\treg_done();\n\tic_reset();\n}\n\nvoid o_write(int fd)\n{\n\ti_done();\n\tout_write(fd, mem_buf(&cs), mem_len(&cs), mem_buf(&ds), mem_len(&ds));\n\tfree(loc_off);\n\tfree(ds_name);\n\tfree(ds_off);\n\tmem_done(&cs);\n\tmem_done(&ds);\n}\n"
  },
  {
    "path": "int.c",
    "content": "/* neatcc intermediate code generation */\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include \"ncc.h\"\n\nstatic struct ic *ic;\t\t/* intermediate code */\nstatic long ic_n, ic_sz;\t/* number of instructions in ic[] */\nstatic long iv[NTMPS];\t\t/* operand stack */\nstatic long iv_n;\t\t/* number of values in iv[] */\nstatic long *lab_loc;\t\t/* label locations */\nstatic long lab_n, lab_sz;\t/* number of labels in lab_loc[] */\nstatic long lab_last;\t\t/* the last label target */\n\nstatic int io_num(void);\nstatic int io_mul2(void);\nstatic int io_cmp(void);\nstatic int io_jmp(void);\nstatic int io_addr(void);\nstatic int io_loc(void);\nstatic int io_imm(void);\nstatic int io_call(void);\nstatic void io_deadcode(void);\n\nstatic void iv_put(long n);\n\nstatic struct ic *ic_put(long op, long arg1, long arg2, long arg3)\n{\n\tstruct ic *c;\n\tif (ic_n == ic_sz) {\n\t\tic_sz = MAX(128, ic_sz * 2);\n\t\tic = mextend(ic, ic_n, ic_sz, sizeof(*ic));\n\t}\n\tc = &ic[ic_n++];\n\tc->op = op;\n\tc->a1 = arg1;\n\tc->a2 = arg2;\n\tc->a3 = arg3;\n\tif (op & O_OUT)\n\t\tiv_put(ic_n - 1);\n\treturn c;\n}\n\nstatic void ic_back(long pos)\n{\n\tint i;\n\tfor (i = pos; i < ic_n; i++)\n\t\tif (ic[i].op & O_CALL)\n\t\t\tfree(ic[i].args);\n\tic_n = pos;\n}\n\nstatic long iv_pop(void)\n{\n\treturn iv[--iv_n];\n}\n\nstatic long iv_get(int n)\n{\n\treturn iv[iv_n - n - 1];\n}\n\nstatic void iv_put(long n)\n{\n\tiv[iv_n++] = n;\n}\n\nstatic void iv_drop(int n)\n{\n\tiv_n = MAX(0, iv_n - n);\n}\n\nstatic void iv_swap(int x, int y)\n{\n\tlong v = iv[iv_n - x - 1];\n\tiv[iv_n - x - 1] = iv[iv_n - y - 1];\n\tiv[iv_n - y - 1] = v;\n}\n\nstatic void iv_dup(void)\n{\n\tiv[iv_n] = iv[iv_n - 1];\n\tiv_n++;\n}\n\nvoid o_num(long n)\n{\n\tic_put(O_MOV | O_NUM, n, 0, 0);\n}\n\nvoid o_local(long id)\n{\n\tic_put(O_MOV | O_LOC, id, 0, 0);\n}\n\nvoid o_sym(char *sym)\n{\n\tic_put(O_MOV | O_SYM, out_sym(sym), 0, 0);\n}\n\nvoid o_tmpdrop(int n)\n{\n\tiv_drop(n >= 0 ? n : iv_n);\n}\n\nvoid o_tmpswap(void)\n{\n\tiv_swap(0, 1);\n}\n\nvoid o_tmpcopy(void)\n{\n\tiv_dup();\n}\n\n/* return one if the given value is constant */\nstatic int ic_const(long iv)\n{\n\tlong oc = O_C(ic[iv].op);\n\treturn oc & O_MOV && oc & (O_NUM | O_SYM | O_LOC);\n}\n\n/* return one if the given value is a simple load */\nstatic int ic_load(long iv)\n{\n\tlong oc = O_C(ic[iv].op);\n\tint i;\n\tif (oc & O_LD && oc & (O_NUM | O_SYM | O_LOC)) {\n\t\tfor (i = iv + 1; i < ic_n; i++)\n\t\t\tif (ic[i].op & O_ST)\n\t\t\t\treturn 0;\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\nvoid o_bop(long op)\n{\n\tint r1 = iv_pop();\n\tint r2 = iv_pop();\n\t/* load constants as late as possible */\n\tif (opt(1) && ic_const(r2) && !ic_const(r1)) {\n\t\tic_put(ic[r2].op, ic[r2].a1, ic[r2].a2, ic[r2].a3);\n\t\tr2 = iv_pop();\n\t}\n\tic_put(op, r2, r1, 0);\n\tif (opt(1)) {\n\t\tio_num();\n\t\tio_mul2();\n\t\tio_addr();\n\t\tio_imm();\n\t}\n}\n\nvoid o_uop(long op)\n{\n\tint r1 = iv_pop();\n\tic_put(op, r1, 0, 0);\n\tif (opt(1)) {\n\t\tio_num();\n\t\tio_cmp();\n\t}\n}\n\nvoid o_assign(long bt)\n{\n\tint rv = iv_pop();\n\tint lv = iv_pop();\n\t/* load constants as late as possible */\n\tif (opt(1) && (ic_const(lv) || ic_load(lv))) {\n\t\tic_put(ic[lv].op, ic[lv].a1, ic[lv].a2, ic[lv].a3);\n\t\tlv = iv_pop();\n\t}\n\tic_put(O_MK(O_ST | O_NUM, bt), rv, lv, 0);\n\tiv_put(rv);\n\tif (opt(1))\n\t\tio_loc();\n}\n\nvoid o_deref(long bt)\n{\n\tint r1 = iv_pop();\n\tic_put(O_MK(O_LD | O_NUM, bt), r1, 0, 0);\n\tif (opt(1))\n\t\tio_loc();\n}\n\nvoid o_cast(long bt)\n{\n\tif (T_SZ(bt) != ULNG) {\n\t\tint r1 = iv_pop();\n\t\tic_put(O_MK(O_MOV, bt), r1, 0, 0);\n\t\tif (opt(1))\n\t\t\tio_num();\n\t}\n}\n\nvoid o_memcpy(void)\n{\n\tint r2 = iv_pop();\n\tint r1 = iv_pop();\n\tint r0 = iv_pop();\n\tic_put(O_MCPY, r0, r1, r2);\n}\n\nvoid o_memset(void)\n{\n\tint r2 = iv_pop();\n\tint r1 = iv_pop();\n\tint r0 = iv_pop();\n\tic_put(O_MSET, r0, r1, r2);\n}\n\nvoid o_call(int argc, int ret)\n{\n\tstruct ic *c;\n\tlong *args = malloc(argc * sizeof(c->args[0]));\n\tint r1, i;\n\tfor (i = argc - 1; i >= 0; --i)\n\t\targs[i] = iv_pop();\n\tfor (i = argc - 1; i >= 0; --i) {\n\t\tint iv = args[i];\n\t\t/* load constants as late as possible */\n\t\tif (opt(1) && (ic_const(iv) || ic_load(iv))) {\n\t\t\tic_put(ic[iv].op, ic[iv].a1, ic[iv].a2, ic[iv].a3);\n\t\t\targs[i] = iv_pop();\n\t\t}\n\t}\n\tr1 = iv_pop();\n\tc = ic_put(O_CALL, r1, 0, argc);\n\tc->args = args;\n\tiv_drop(ret == 0);\n\tif (opt(1))\n\t\tio_call();\n}\n\nvoid o_ret(int ret)\n{\n\tif (!ret)\n\t\to_num(0);\n\tic_put(O_RET, iv_pop(), 0, 0);\n}\n\nvoid o_label(long id)\n{\n\twhile (id >= lab_sz) {\n\t\tlab_sz = MAX(128, lab_sz * 2);\n\t\tlab_loc = mextend(lab_loc, lab_n, lab_sz, sizeof(*lab_loc));\n\t}\n\twhile (lab_n <= id)\n\t\tlab_loc[lab_n++] = -1;\n\tlab_loc[id] = ic_n;\n\tlab_last = ic_n;\n}\n\nvoid o_jmp(long id)\n{\n\tic_put(O_JMP, 0, 0, id);\n}\n\nvoid o_jz(long id)\n{\n\tic_put(O_JZ, iv_pop(), 0, id);\n\tif (opt(1))\n\t\tio_jmp();\n}\n\nint o_popnum(long *n)\n{\n\tif (ic_num(ic, iv_get(0), n))\n\t\treturn 1;\n\tiv_drop(1);\n\treturn 0;\n}\n\nint o_popsym(long *sym, long *off)\n{\n\tif (ic_sym(ic, iv_get(0), sym, off))\n\t\treturn 1;\n\tiv_drop(1);\n\treturn 0;\n}\n\nlong o_mark(void)\n{\n\treturn ic_n;\n}\n\nvoid o_back(long mark)\n{\n\tic_back(mark);\n}\n\nvoid ic_get(struct ic **c, long *n)\n{\n\tint i;\n\tif (!ic_n || ~ic[ic_n - 1].op & O_RET || lab_last == ic_n)\n\t\to_ret(0);\n\tfor (i = 0; i < ic_n; i++)\t/* filling branch targets */\n\t\tif (ic[i].op & O_JXX)\n\t\t\tic[i].a3 = lab_loc[ic[i].a3];\n\tio_deadcode();\t\t\t/* removing dead code */\n\t*c = ic;\n\t*n = ic_n;\n\tic = NULL;\n\tic_n = 0;\n\tic_sz = 0;\n\tiv_n = 0;\n\tfree(lab_loc);\n\tlab_loc = NULL;\n\tlab_n = 0;\n\tlab_sz = 0;\n\tlab_last = 0;\n}\n\nvoid ic_free(struct ic *ic)\n{\n\tif (ic->op & O_CALL)\n\t\tfree(ic->args);\n}\n\n/* intermediate code queries */\n\nstatic long cb(long op, long *r, long a, long b)\n{\n\tswitch (O_C(op)) {\n\tcase O_ADD:\n\t\t*r = a + b;\n\t\tbreak;\n\tcase O_SUB:\n\t\t*r = a - b;\n\t\tbreak;\n\tcase O_AND:\n\t\t*r = a & b;\n\t\tbreak;\n\tcase O_OR:\n\t\t*r = a | b;\n\t\tbreak;\n\tcase O_XOR:\n\t\t*r = a ^ b;\n\t\tbreak;\n\tcase O_MUL:\n\t\t*r = a * b;\n\t\tbreak;\n\tcase O_DIV:\n\t\tif (!b)\n\t\t\treturn 1;\n\t\t*r = a / b;\n\t\tbreak;\n\tcase O_MOD:\n\t\tif (!b)\n\t\t\treturn 1;\n\t\t*r = a % b;\n\t\tbreak;\n\tcase O_SHL:\n\t\t*r = a << b;\n\t\tbreak;\n\tcase O_SHR:\n\t\t*r = O_T(op) & T_MSIGN ? a >> b : (unsigned long) a >> b;\n\t\tbreak;\n\tcase O_LT:\n\t\t*r = a < b;\n\t\tbreak;\n\tcase O_GT:\n\t\t*r = a > b;\n\t\tbreak;\n\tcase O_LE:\n\t\t*r = a <= b;\n\t\tbreak;\n\tcase O_GE:\n\t\t*r = a >= b;\n\t\tbreak;\n\tcase O_EQ:\n\t\t*r = a == b;\n\t\tbreak;\n\tcase O_NE:\n\t\t*r = a != b;\n\t\tbreak;\n\t}\n\treturn 0;\n}\n\nstatic long cu(int op, long i)\n{\n\tswitch (O_C(op)) {\n\tcase O_NEG:\n\t\treturn -i;\n\tcase O_NOT:\n\t\treturn ~i;\n\tcase O_LNOT:\n\t\treturn !i;\n\t}\n\treturn 0;\n}\n\nstatic long c_cast(long n, unsigned bt)\n{\n\tif (!(bt & T_MSIGN) && T_SZ(bt) != ULNG)\n\t\tn &= ((1l << (long) (T_SZ(bt) * 8)) - 1);\n\tif (bt & T_MSIGN && T_SZ(bt) != ULNG &&\n\t\t\t\tn > (1l << (T_SZ(bt) * 8 - 1)))\n\t\tn = -((1l << (T_SZ(bt) * 8)) - n);\n\treturn n;\n}\n\nint ic_num(struct ic *ic, long iv, long *n)\n{\n\tlong n1, n2;\n\tlong oc = O_C(ic[iv].op);\n\tlong bt = O_T(ic[iv].op);\n\tif (oc & O_MOV && oc & O_NUM) {\n\t\t*n = ic[iv].a1;\n\t\treturn 0;\n\t}\n\tif (oc & O_BOP) {\n\t\tif (ic_num(ic, ic[iv].a1, &n1))\n\t\t\treturn 1;\n\t\tif (ic_num(ic, ic[iv].a2, &n2))\n\t\t\treturn 1;\n\t\treturn cb(ic[iv].op, n, n1, n2);\n\t}\n\tif (oc & O_UOP) {\n\t\tif (ic_num(ic, ic[iv].a1, &n1))\n\t\t\treturn 1;\n\t\t*n = cu(ic[iv].op, n1);\n\t\treturn 0;\n\t}\n\tif (oc & O_MOV && !(oc & (O_NUM | O_LOC | O_SYM))) {\n\t\tif (ic_num(ic, ic[iv].a1, &n1))\n\t\t\treturn 1;\n\t\t*n = c_cast(n1, bt);\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n\nint ic_sym(struct ic *ic, long iv, long *sym, long *off)\n{\n\tlong n;\n\tlong oc = O_C(ic[iv].op);\n\tif (oc & O_MOV && oc & O_SYM) {\n\t\t*sym = ic[iv].a1;\n\t\t*off = ic[iv].a2;\n\t\treturn 0;\n\t}\n\tif (oc == O_ADD) {\n\t\tif ((ic_sym(ic, ic[iv].a1, sym, off) ||\n\t\t\t\tic_num(ic, ic[iv].a2, &n)) &&\n\t\t\t(ic_sym(ic, ic[iv].a2, sym, off) ||\n\t\t\t\tic_num(ic, ic[iv].a1, &n)))\n\t\t\treturn 1;\n\t\t*off += n;\n\t\treturn 0;\n\t}\n\tif (oc == O_SUB) {\n\t\tif (ic_sym(ic, ic[iv].a1, sym, off) ||\n\t\t\t\tic_num(ic, ic[iv].a2, &n))\n\t\t\treturn 1;\n\t\t*off -= n;\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n\nstatic int ic_off(struct ic *ic, long iv, long *base_iv, long *off)\n{\n\tlong n;\n\tlong oc = O_C(ic[iv].op);\n\tif (oc == (O_ADD | O_NUM)) {\n\t\t*base_iv = ic[iv].a1;\n\t\t*off = ic[iv].a2;\n\t\treturn 0;\n\t}\n\tif (oc == (O_SUB | O_NUM)) {\n\t\t*base_iv = ic[iv].a1;\n\t\t*off = -ic[iv].a2;\n\t\treturn 0;\n\t}\n\tif (oc == O_ADD) {\n\t\tif ((ic_off(ic, ic[iv].a1, base_iv, off) ||\n\t\t\t\tic_num(ic, ic[iv].a2, &n)) &&\n\t\t\t(ic_off(ic, ic[iv].a2, base_iv, off) ||\n\t\t\t\tic_num(ic, ic[iv].a1, &n)))\n\t\t\treturn 1;\n\t\t*off += n;\n\t\treturn 0;\n\t}\n\tif (oc == O_SUB) {\n\t\tif (ic_off(ic, ic[iv].a1, base_iv, off) ||\n\t\t\t\tic_num(ic, ic[iv].a2, &n))\n\t\t\treturn 1;\n\t\t*off -= n;\n\t\treturn 0;\n\t}\n\t*base_iv = iv;\n\t*off = 0;\n\treturn 0;\n}\n\n/* number of register arguments */\nint ic_regcnt(struct ic *ic)\n{\n\tlong o = ic->op;\n\tif (o & O_BOP)\n\t\treturn o & (O_NUM | O_SYM | O_LOC) ? 1 : 2;\n\tif (o & O_UOP)\n\t\treturn o & (O_NUM | O_SYM | O_LOC) ? 0 : 1;\n\tif (o & O_CALL)\n\t\treturn o & (O_NUM | O_SYM | O_LOC) ? 0 : 1;\n\tif (o & O_MOV)\n\t\treturn o & (O_NUM | O_SYM | O_LOC) ? 0 : 1;\n\tif (o & O_MEM)\n\t\treturn 3;\n\tif (o & O_JMP)\n\t\treturn 0;\n\tif (o & O_JZ)\n\t\treturn 1;\n\tif (o & O_JCC)\n\t\treturn o & (O_NUM | O_SYM | O_LOC) ? 1 : 2;\n\tif (o & O_RET)\n\t\treturn 1;\n\tif (o & O_LD)\n\t\treturn ((o & O_NUM) != 0);\n\tif (o & O_ST)\n\t\treturn 1 + ((o & O_NUM) != 0);\n\treturn 0;\n}\n\n/*\n * The returned array indicates the last instruction in\n * which the value produced by each instruction is used.\n */\nlong *ic_lastuse(struct ic *ic, long ic_n)\n{\n\tlong *luse = calloc(ic_n, sizeof(luse[0]));\n\tint i, j;\n\tfor (i = ic_n - 1; i >= 0; --i) {\n\t\tint n = ic_regcnt(ic + i);\n\t\tif (!luse[i])\n\t\t\tif (!(ic[i].op & O_OUT) || ic[i].op & O_CALL)\n\t\t\t\tluse[i] = -1;\n\t\tif (!luse[i])\n\t\t\tcontinue;\n\t\tif (n >= 1 && !luse[ic[i].a1])\n\t\t\tluse[ic[i].a1] = i;\n\t\tif (n >= 2 && !luse[ic[i].a2])\n\t\t\tluse[ic[i].a2] = i;\n\t\tif (n >= 3 && !luse[ic[i].a3])\n\t\t\tluse[ic[i].a3] = i;\n\t\tif (ic[i].op & O_CALL)\n\t\t\tfor (j = 0; j < ic[i].a3; j++)\n\t\t\t\tif (!luse[ic[i].args[j]])\n\t\t\t\t\tluse[ic[i].args[j]] = i;\n\t}\n\treturn luse;\n}\n\n/* intermediate code optimisations */\n\n/* constant folding */\nstatic int io_num(void)\n{\n\tlong n;\n\tif (!ic_num(ic, iv_get(0), &n)) {\n\t\tiv_drop(1);\n\t\to_num(n);\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n\nstatic int log2a(unsigned long n)\n{\n\tint i = 0;\n\tfor (i = 0; i < LONGSZ * 8; i++)\n\t\tif (n & (1u << i))\n\t\t\tbreak;\n\tif (i == LONGSZ * 8 || !(n >> (i + 1)))\n\t\treturn i;\n\treturn -1;\n}\n\nstatic long iv_num(long n)\n{\n\to_num(n);\n\treturn iv_pop();\n}\n\n/* optimised multiplication operations for powers of two */\nstatic int io_mul2(void)\n{\n\tlong iv = iv_get(0);\n\tlong n, p;\n\tlong r1, r2;\n\tlong oc = O_C(ic[iv].op);\n\tlong bt = O_T(ic[iv].op);\n\tif (!(oc & O_MUL))\n\t\treturn 1;\n\tif (oc == O_MUL && !ic_num(ic, ic[iv].a1, &n)) {\n\t\tlong t = ic[iv].a1;\n\t\tic[iv].a1 = ic[iv].a2;\n\t\tic[iv].a2 = t;\n\t}\n\tif (ic_num(ic, ic[iv].a2, &n))\n\t\treturn 1;\n\tp = log2a(n);\n\tif (n && p < 0)\n\t\treturn 1;\n\tif (oc == O_MUL) {\n\t\tiv_drop(1);\n\t\tif (n == 1) {\n\t\t\tiv_put(ic[iv].a1);\n\t\t\treturn 0;\n\t\t}\n\t\tif (n == 0) {\n\t\t\to_num(0);\n\t\t\treturn 0;\n\t\t}\n\t\tr2 = iv_num(p);\n\t\tic_put(O_MK(O_SHL, ULNG), ic[iv].a1, r2, 0);\n\t\treturn 0;\n\t}\n\tif (oc == O_DIV && ~bt & T_MSIGN) {\n\t\tiv_drop(1);\n\t\tif (n == 1) {\n\t\t\tiv_put(ic[iv].a1);\n\t\t\treturn 0;\n\t\t}\n\t\tr2 = iv_num(p);\n\t\tic_put(O_MK(O_SHR, ULNG), ic[iv].a1, r2, 0);\n\t\treturn 0;\n\t}\n\tif (oc == O_MOD && ~bt & T_MSIGN) {\n\t\tiv_drop(1);\n\t\tif (n == 1) {\n\t\t\to_num(0);\n\t\t\treturn 0;\n\t\t}\n\t\tr2 = iv_num(LONGSZ * 8 - p);\n\t\tic_put(O_MK(O_SHL, ULNG), ic[iv].a1, r2, 0);\n\t\tr1 = iv_pop();\n\t\tr2 = iv_num(LONGSZ * 8 - p);\n\t\tic_put(O_MK(O_SHR, ULNG), r1, r2, 0);\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n\n/* optimise comparison */\nstatic int io_cmp(void)\n{\n\tlong iv = iv_get(0);\n\tlong cmp = ic[iv].a1;\n\tif (O_C(ic[iv].op) == O_LNOT && ic[cmp].op & O_CMP) {\n\t\tiv_drop(1);\n\t\tic[cmp].op ^= 1;\n\t\tiv_put(cmp);\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n\n/* optimise branch instructions after comparison */\nstatic int io_jmp(void)\n{\n\tstruct ic *c = &ic[ic_n - 1];\n\tlong oc = O_C(c->op);\n\tif (oc & O_JZ && O_C(ic[c->a1].op) == O_LNOT) {\n\t\tc->a1 = ic[c->a1].a1;\n\t\tc->op ^= 1;\n\t\treturn 0;\n\t}\n\tif (oc & O_JZ && O_C(ic[c->a1].op) & O_CMP) {\n\t\tlong cop = (ic[c->a1].op & ~O_CMP) | O_JCC;\n\t\tc->op = O_C(c->op) == O_JZ ? cop ^ 1 : cop;\n\t\tc->a2 = ic[c->a1].a2;\n\t\tc->a1 = ic[c->a1].a1;\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n\n/* optimise accessing locals or symbols with an offset */\nstatic int io_addr(void)\n{\n\tlong iv, off;\n\tif (ic_off(ic, iv_get(0), &iv, &off) || iv == iv_get(0))\n\t\treturn 1;\n\tif (ic[iv].op & O_MOV && ic[iv].op & O_LOC) {\n\t\tiv_drop(1);\n\t\tic_put(O_MOV | O_LOC, ic[iv].a1, ic[iv].a2 + off, 0);\n\t\treturn 0;\n\t}\n\tif (ic[iv].op & O_MOV && ic[iv].op & O_SYM) {\n\t\tiv_drop(1);\n\t\tic_put(O_MOV | O_SYM, ic[iv].a1, ic[iv].a2 + off, 0);\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n\nstatic int imm_ok(long op, long n, int arg)\n{\n\tlong m[5];\n\tif (i_reg(op | O_NUM, m + 0, m + 1, m + 2, m + 3, m + 4))\n\t\treturn 0;\n\treturn i_imm(m[arg], n);\n}\n\n/* optimise loading and storing locals */\nstatic int io_loc(void)\n{\n\tstruct ic *c = &ic[ic_n - 1];\n\tlong iv, off;\n\tif (c->op & O_LD && c->op & O_NUM) {\n\t\tif (ic_off(ic, c->a1, &iv, &off))\n\t\t\treturn 1;\n\t\tif (ic[iv].op & O_MOV && ic[iv].op & O_LOC) {\n\t\t\tc->op = (c->op & ~O_NUM) | O_LOC;\n\t\t\tc->a1 = ic[iv].a1;\n\t\t\tc->a2 += ic[iv].a2 + off;\n\t\t\treturn 0;\n\t\t}\n\t\tif (imm_ok(c->op, off, 2)) {\n\t\t\tc->a1 = iv;\n\t\t\tc->a2 += off;\n\t\t}\n\t\treturn 0;\n\t}\n\tif (c->op & O_ST && c->op & O_NUM) {\n\t\tif (ic_off(ic, c->a2, &iv, &off))\n\t\t\treturn 1;\n\t\tif (ic[iv].op & O_MOV && ic[iv].op & O_LOC) {\n\t\t\tc->op = (c->op & ~O_NUM) | O_LOC;\n\t\t\tc->a2 = ic[iv].a1;\n\t\t\tc->a3 += ic[iv].a2 + off;\n\t\t\treturn 0;\n\t\t}\n\t\tif (imm_ok(c->op, off, 3)) {\n\t\t\tc->a2 = iv;\n\t\t\tc->a3 += off;\n\t\t}\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n\n/* reverse the order of comparison operands (e.g., <= to >=) */\nstatic int flip_cond(int op) {\n\t/* lt -> gt, ge -> le, eq -> eq, ne -> ne, le -> ge, gt -> lt */\n\tstatic int cond[] = {5, 4, 2, 3, 1, 0};\n\treturn (op & ~0x0f) | cond[op & 0x0f];\n}\n\n/* use instruction immediates */\nstatic int io_imm(void)\n{\n\tstruct ic *c = &ic[ic_n - 1];\n\tlong oc = O_C(c->op);\n\tlong n;\n\tif (oc & (O_NUM | O_LOC | O_SYM))\n\t\treturn 1;\n\tif (oc == O_ADD || oc == O_MUL || oc == O_AND || oc == O_OR ||\n\t\t\toc == O_XOR || oc == O_EQ || oc == O_NE) {\n\t\tif (!ic_num(ic, c->a1, &n)) {\n\t\t\tlong t = c->a1;\n\t\t\tc->a1 = c->a2;\n\t\t\tc->a2 = t;\n\t\t}\n\t}\n\tif (oc == O_LT || oc == O_GE || oc == O_LE || oc == O_GT) {\n\t\tif (!ic_num(ic, c->a1, &n)) {\n\t\t\tint t = c->a1;\n\t\t\tc->a1 = c->a2;\n\t\t\tc->a2 = t;\n\t\t\tc->op = flip_cond(c->op);\n\t\t}\n\t}\n\tif (oc & O_JCC && !ic_num(ic, c->a1, &n)) {\n\t\tint t = c->a1;\n\t\tc->a1 = c->a2;\n\t\tc->a2 = t;\n\t\tc->op = flip_cond(c->op);\n\t}\n\tif (oc & O_JCC && !ic_num(ic, c->a2, &n) && imm_ok(c->op, n, 2)) {\n\t\tc->op |= O_NUM;\n\t\tc->a2 = n;\n\t\treturn 0;\n\t}\n\tif (!(oc & O_BOP) || ic_num(ic, c->a2, &n))\n\t\treturn 1;\n\tif ((oc == O_ADD || oc == O_SUB || oc & O_SHL) && n == 0) {\n\t\tiv_drop(1);\n\t\tiv_put(c->a1);\n\t\treturn 0;\n\t}\n\tif (imm_ok(c->op, n, 2)) {\n\t\tc->op |= O_NUM;\n\t\tc->a2 = n;\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n\n/* calling symbols */\nstatic int io_call(void)\n{\n\tstruct ic *c = &ic[ic_n - 1];\n\tlong sym, off;\n\tif (c->op & O_CALL && !ic_sym(ic, c->a1, &sym, &off) && !off) {\n\t\tc->op |= O_SYM;\n\t\tc->a1 = sym;\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n\n/* remove dead code */\nstatic void io_deadcode(void)\n{\n\tchar *live;\n\tlong *nidx;\n\tlong src = 0, dst = 0;\n\tint i, j;\n\t/* liveness analysis */\n\tlive = calloc(ic_n, sizeof(live[0]));\n\tfor (i = ic_n - 1; i >= 0; i--) {\n\t\tint n = ic_regcnt(ic + i);\n\t\tif (!(ic[i].op & O_OUT) || ic[i].op & O_CALL)\n\t\t\tlive[i] = 1;\n\t\tif (!live[i])\n\t\t\tcontinue;\n\t\tif (n >= 1)\n\t\t\tlive[ic[i].a1] = 1;\n\t\tif (n >= 2)\n\t\t\tlive[ic[i].a2] = 1;\n\t\tif (n >= 3)\n\t\t\tlive[ic[i].a3] = 1;\n\t\tif (ic[i].op & O_CALL)\n\t\t\tfor (j = 0; j < ic[i].a3; j++)\n\t\t\t\tlive[ic[i].args[j]] = 1;\n\t}\n\t/* the new indices of intermediate instructions */\n\tnidx = calloc(ic_n, sizeof(nidx[0]));\n\twhile (src < ic_n) {\n\t\twhile (src < ic_n && !live[src]) {\n\t\t\tnidx[src] = dst;\n\t\t\tic_free(&ic[src++]);\n\t\t}\n\t\tif (src < ic_n) {\n\t\t\tnidx[src] = dst;\n\t\t\tif (src != dst)\n\t\t\t\tmemcpy(ic + dst, ic + src, sizeof(ic[src]));\n\t\t\tsrc++;\n\t\t\tdst++;\n\t\t}\n\t}\n\tic_n = dst;\n\t/* adjusting arguments and branch targets */\n\tfor (i = 0; i < ic_n; i++) {\n\t\tint n = ic_regcnt(ic + i);\n\t\tif (n >= 1)\n\t\t\tic[i].a1 = nidx[ic[i].a1];\n\t\tif (n >= 2)\n\t\t\tic[i].a2 = nidx[ic[i].a2];\n\t\tif (n >= 3)\n\t\t\tic[i].a3 = nidx[ic[i].a3];\n\t\tif (ic[i].op & O_JXX)\n\t\t\tic[i].a3 = nidx[ic[i].a3];\n\t\tif (ic[i].op & O_CALL)\n\t\t\tfor (j = 0; j < ic[i].a3; j++)\n\t\t\t\tic[i].args[j] = nidx[ic[i].args[j]];\n\t}\n\tfree(live);\n\tfree(nidx);\n}\n"
  },
  {
    "path": "mem.c",
    "content": "#include <stdarg.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"ncc.h\"\n\n#define MEMSZ\t\t512\n\nstatic void mem_extend(struct mem *mem)\n{\n\tchar *s = mem->s;\n\tmem->sz = mem->sz ? mem->sz + mem->sz : MEMSZ;\n\tmem->s = malloc(mem->sz);\n\tif (mem->n)\n\t\tmemcpy(mem->s, s, mem->n);\n\tfree(s);\n}\n\nvoid mem_init(struct mem *mem)\n{\n\tmemset(mem, 0, sizeof(*mem));\n}\n\nvoid mem_done(struct mem *mem)\n{\n\tfree(mem->s);\n\tmemset(mem, 0, sizeof(*mem));\n}\n\nvoid mem_cut(struct mem *mem, long pos)\n{\n\tmem->n = pos < mem->n ? pos : mem->n;\n}\n\nvoid mem_cpy(struct mem *mem, long off, void *buf, long len)\n{\n\twhile (mem->n + off + len + 1 >= mem->sz)\n\t\tmem_extend(mem);\n\tmemcpy(mem->s + off, buf, len);\n}\n\nvoid mem_put(struct mem *mem, void *buf, long len)\n{\n\tmem_cpy(mem, mem->n, buf, len);\n\tmem->n += len;\n}\n\nvoid mem_putc(struct mem *mem, int c)\n{\n\tif (mem->n + 2 >= mem->sz)\n\t\tmem_extend(mem);\n\tmem->s[mem->n++] = c;\n}\n\nvoid mem_putz(struct mem *mem, long sz)\n{\n\twhile (mem->n + sz + 1 >= mem->sz)\n\t\tmem_extend(mem);\n\tmemset(mem->s + mem->n, 0, sz);\n\tmem->n += sz;\n}\n\n/* return a pointer to mem's buffer; valid as long as mem is not modified */\nvoid *mem_buf(struct mem *mem)\n{\n\tif (!mem->s)\n\t\treturn \"\";\n\tmem->s[mem->n] = '\\0';\n\treturn mem->s;\n}\n\nlong mem_len(struct mem *mem)\n{\n\treturn mem->n;\n}\n\nvoid *mem_get(struct mem *mem)\n{\n\tvoid *ret;\n\tif (!mem->s)\n\t\tmem_extend(mem);\n\tret = mem->s;\n\tmem_init(mem);\n\treturn ret;\n}\n"
  },
  {
    "path": "ncc.c",
    "content": "/*\n * THE NEATCC C COMPILER\n *\n * Copyright (C) 2010-2016 Ali Gholami Rudi\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n/*\n * neatcc parser\n *\n * The parser reads tokens from the tokenizer (tok_*) and calls the\n * appropriate code generation functions (o_*).  The generator\n * maintains a stack of values pushed via, for instance, o_num()\n * and generates the necessary code for the accesses to the items\n * in this stack, like o_bop() for performing a binary operations\n * on the top two items of the stack.  The parser maintains the\n * types of values pushed to the generator stack in its type stack\n * (ts_*).  For instance, for binary operations two types are\n * popped first and the resulting type is pushed to the type stack\n * (ts_binop()).\n *\n */\n#include <ctype.h>\n#include <fcntl.h>\n#include <unistd.h>\n#include <stdarg.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdio.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include \"ncc.h\"\n\n#define ALIGN(x, a)\t\t(((x) + (a) - 1) & ~((a) - 1))\n#define MIN(a, b)\t\t((a) < (b) ? (a) : (b))\n#define MAX(a, b)\t\t((a) < (b) ? (b) : (a))\n\n#define TYPE_BT(t)\t\t((t)->ptr ? ULNG : (t)->bt)\n#define TYPE_SZ(t)\t\t((t)->ptr ? ULNG : (t)->bt & T_MSIZE)\n#define TYPE_VOID(t)\t\t(!(t)->bt && !(t)->flags && !(t)->ptr)\n\n/* type->flag values */\n#define T_ARRAY\t\t0x01\n#define T_STRUCT\t0x02\n#define T_FUNC\t\t0x04\n\n/* variable definition flags */\n#define F_STATIC\t0x01\n#define F_EXTERN\t0x02\n\nstruct type {\n\tunsigned bt;\n\tunsigned flags;\n\tint ptr;\n\tint id;\t\t/* for structs, functions and arrays */\n\tint addr;\t/* the address is passed to gen.c; deref for value */\n};\n\n/* type stack */\nstatic struct type ts[NTMPS];\nstatic int nts;\n\nstatic void ts_push_bt(unsigned bt)\n{\n\tts[nts].ptr = 0;\n\tts[nts].flags = 0;\n\tts[nts].addr = 0;\n\tts[nts++].bt = bt;\n#ifdef NCCWORDCAST\n\to_cast(bt);\t\t/* casting to architecture word */\n#endif\n}\n\nstatic void ts_push(struct type *t)\n{\n\tstruct type *d = &ts[nts++];\n\tmemcpy(d, t, sizeof(*t));\n}\n\nstatic void ts_push_addr(struct type *t)\n{\n\tts_push(t);\n\tts[nts - 1].addr = 1;\n}\n\nstatic void ts_pop(struct type *type)\n{\n\tnts--;\n\tif (type)\n\t\t*type = ts[nts];\n}\n\nvoid err(char *fmt, ...)\n{\n\tva_list ap;\n\tchar msg[512];\n\tva_start(ap, fmt);\n\tvsprintf(msg, fmt, ap);\n\tva_end(ap);\n\tdie(\"%s: %s\", cpp_loc(tok_addr()), msg);\n}\n\nvoid *mextend(void *old, long oldsz, long newsz, long memsz)\n{\n\tvoid *new = malloc(newsz * memsz);\n\tmemcpy(new, old, oldsz * memsz);\n\tmemset(new + oldsz * memsz, 0, (newsz - oldsz) * memsz);\n\tfree(old);\n\treturn new;\n}\n\nstruct name {\n\tchar name[NAMELEN];\n\tchar elfname[NAMELEN];\t/* local elf name for function static variables */\n\tstruct type type;\n\tlong addr;\t\t/* local stack offset, global data addr, struct offset */\n};\n\nstatic struct name *locals;\nstatic int locals_n, locals_sz;\nstatic struct name *globals;\nstatic int globals_n, globals_sz;\n\nstatic void local_add(struct name *name)\n{\n\tif (locals_n >= locals_sz) {\n\t\tlocals_sz = MAX(128, locals_sz * 2);\n\t\tlocals = mextend(locals, locals_n, locals_sz, sizeof(locals[0]));\n\t}\n\tmemcpy(&locals[locals_n++], name, sizeof(*name));\n}\n\nstatic int local_find(char *name)\n{\n\tint i;\n\tfor (i = locals_n - 1; i >= 0; --i)\n\t\tif (!strcmp(locals[i].name, name))\n\t\t\treturn i;\n\treturn -1;\n}\n\nstatic int global_find(char *name)\n{\n\tint i;\n\tfor (i = globals_n - 1; i >= 0; i--)\n\t\tif (!strcmp(name, globals[i].name))\n\t\t\treturn i;\n\treturn -1;\n}\n\nstatic void global_add(struct name *name)\n{\n\tif (globals_n >= globals_sz) {\n\t\tglobals_sz = MAX(128, globals_sz * 2);\n\t\tglobals = mextend(globals, globals_n, globals_sz, sizeof(globals[0]));\n\t}\n\tmemcpy(&globals[globals_n++], name, sizeof(*name));\n}\n\n#define LABEL()\t\t\t(++label)\n\nstatic int label;\t\t/* last used label id */\nstatic int l_break;\t\t/* current break label */\nstatic int l_cont;\t\t/* current continue label */\n\nstatic struct enumval {\n\tchar name[NAMELEN];\n\tint n;\n} *enums;\nstatic int enums_n, enums_sz;\n\nstatic void enum_add(char *name, int val)\n{\n\tstruct enumval *ev;\n\tif (enums_n >= enums_sz) {\n\t\tenums_sz = MAX(128, enums_sz * 2);\n\t\tenums = mextend(enums, enums_n, enums_sz, sizeof(enums[0]));\n\t}\n\tev = &enums[enums_n++];\n\tstrcpy(ev->name, name);\n\tev->n = val;\n}\n\nstatic int enum_find(int *val, char *name)\n{\n\tint i;\n\tfor (i = enums_n - 1; i >= 0; --i)\n\t\tif (!strcmp(name, enums[i].name)) {\n\t\t\t*val = enums[i].n;\n\t\t\treturn 0;\n\t\t}\n\treturn 1;\n}\n\nstatic struct typdefinfo {\n\tchar name[NAMELEN];\n\tstruct type type;\n} *typedefs;\nstatic int typedefs_n, typedefs_sz;\n\nstatic void typedef_add(char *name, struct type *type)\n{\n\tstruct typdefinfo *ti;\n\tif (typedefs_n >= typedefs_sz) {\n\t\ttypedefs_sz = MAX(128, typedefs_sz * 2);\n\t\ttypedefs = mextend(typedefs, typedefs_n, typedefs_sz,\n\t\t\t\t\tsizeof(typedefs[0]));\n\t}\n\tti = &typedefs[typedefs_n++];\n\tstrcpy(ti->name, name);\n\tmemcpy(&ti->type, type, sizeof(*type));\n}\n\nstatic int typedef_find(char *name)\n{\n\tint i;\n\tfor (i = typedefs_n - 1; i >= 0; --i)\n\t\tif (!strcmp(name, typedefs[i].name))\n\t\t\treturn i;\n\treturn -1;\n}\n\nstatic struct array {\n\tstruct type type;\n\tint n;\n} *arrays;\nstatic int arrays_n, arrays_sz;\n\nstatic int array_add(struct type *type, int n)\n{\n\tstruct array *a;\n\tif (arrays_n >= arrays_sz) {\n\t\tarrays_sz = MAX(128, arrays_sz * 2);\n\t\tarrays = mextend(arrays, arrays_n, arrays_sz, sizeof(arrays[0]));\n\t}\n\ta = &arrays[arrays_n++];\n\tmemcpy(&a->type, type, sizeof(*type));\n\ta->n = n;\n\treturn a - arrays;\n}\n\nstatic void array2ptr(struct type *t)\n{\n\tif (t->flags & T_ARRAY && !t->ptr) {\n\t\tmemcpy(t, &arrays[t->id].type, sizeof(*t));\n\t\tt->ptr++;\n\t}\n}\n\nstatic struct structinfo {\n\tchar name[NAMELEN];\n\tstruct name fields[NFIELDS];\n\tint nfields;\n\tint isunion;\n\tint size;\n} *structs;\nstatic int structs_n, structs_sz;\n\nstatic int struct_find(char *name, int isunion)\n{\n\tint i;\n\tfor (i = structs_n - 1; i >= 0; --i)\n\t\tif (*structs[i].name && !strcmp(name, structs[i].name) &&\n\t\t\t\tstructs[i].isunion == isunion)\n\t\t\treturn i;\n\tif (structs_n >= structs_sz) {\n\t\tstructs_sz = MAX(128, structs_sz * 2);\n\t\tstructs = mextend(structs, structs_n, structs_sz, sizeof(structs[0]));\n\t}\n\ti = structs_n++;\n\tmemset(&structs[i], 0, sizeof(structs[i]));\n\tstrcpy(structs[i].name, name);\n\tstructs[i].isunion = isunion;\n\treturn i;\n}\n\nstatic struct name *struct_field(int id, char *name)\n{\n\tstruct structinfo *si = &structs[id];\n\tint i;\n\tfor (i = 0; i < si->nfields; i++)\n\t\tif (!strcmp(name, si->fields[i].name))\n\t\t\treturn &si->fields[i];\n\terr(\"unknown field <%s>\\n\", name);\n\treturn NULL;\n}\n\n/* return t's size */\nstatic int type_totsz(struct type *t)\n{\n\tif (t->ptr)\n\t\treturn ULNG;\n\tif (t->flags & T_ARRAY)\n\t\treturn arrays[t->id].n * type_totsz(&arrays[t->id].type);\n\treturn t->flags & T_STRUCT ? structs[t->id].size : T_SZ(t->bt);\n}\n\n/* return t's dereferenced size */\nstatic unsigned type_szde(struct type *t)\n{\n\tstruct type de = *t;\n\tarray2ptr(&de);\n\tde.ptr--;\n\treturn type_totsz(&de);\n}\n\n/* dereference stack top if t->addr (ie. address is pushed to gen.c) */\nstatic void ts_de(int deref)\n{\n\tstruct type *t = &ts[nts - 1];\n\tarray2ptr(t);\n\tif (deref && t->addr && (t->ptr || !(t->flags & T_FUNC)))\n\t\to_deref(TYPE_BT(t));\n\tt->addr = 0;\n}\n\n/* pop stack pop to *t and dereference if t->addr */\nstatic void ts_pop_de(struct type *t)\n{\n\tts_de(1);\n\tts_pop(t);\n}\n\n/* pop the top 2 stack values and dereference them if t->addr */\nstatic void ts_pop_de2(struct type *t1, struct type *t2)\n{\n\tts_pop_de(t1);\n\to_tmpswap();\n\tts_pop_de(t2);\n\to_tmpswap();\n}\n\n/* the previous identifier; to handle labels */\nstatic char tok_previden[NAMELEN];\n\nstatic char *tok_iden(void)\n{\n\tsnprintf(tok_previden, sizeof(tok_previden), \"%s\", tok_get());\n\treturn tok_previden;\n}\n\nstatic int tok_jmp(char *tok)\n{\n\tif (strcmp(tok, tok_see()))\n\t\treturn 1;\n\ttok_get();\n\treturn 0;\n}\n\nstatic int tok_comes(char *tok)\n{\n\treturn !strcmp(tok, tok_see());\n}\n\nstatic void tok_req(char *tok)\n{\n\tchar *got = tok_get();\n\tif (strcmp(tok, got))\n\t\terr(\"syntax error (expected <%s> but got <%s>)\\n\", tok, got);\n}\n\nstatic int tok_grp(void)\n{\n\tint c = (unsigned char) tok_see()[0];\n\tif (c == '\"')\n\t\treturn '\"';\n\tif (c == '\\'' || isdigit(c))\n\t\treturn '0';\n\tif (c == '_' || isalpha(c))\n\t\treturn 'a';\n\treturn 0;\n}\n\n/* the result of a binary operation on variables of type bt1 and bt2 */\nstatic unsigned bt_op(unsigned bt1, unsigned bt2)\n{\n\t/* Type conversion according to ISO9899, sec. 6.3.1.8.\n\t * http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf\n\t *\n\t * Summary:\n\t *  Size: Always convert to largest size.\n\t *  Sign:\n\t *    - Same sign: Keep sign.\n\t *    - Same size or unsigned larger: Convert to unsigned.\n\t *    - Signed larger: Convert to signed.\n\t */\n\tint sz = MAX(T_SZ(bt1), T_SZ(bt2));\n\t/* the unsigned operand is at least as large as the signed one */\n\tif ((!T_SG(bt1) && T_SG(bt2) && T_SZ(bt1) >= T_SZ(bt2)) ||\n\t\t\t(T_SG(bt1) && !T_SG(bt2) && T_SZ(bt1) <= T_SZ(bt2)))\n\t\treturn MAX(sz, UINT);\n\treturn T_SG(bt1) | T_SG(bt2) | MAX(sz, UINT);\n}\n\n/* the result of a unary operation on variables of bt */\nstatic unsigned bt_uop(unsigned bt)\n{\n\treturn bt_op(bt, SINT);\n}\n\n/* push the result of a binary operation on the type stack */\nstatic void ts_binop(int op)\n{\n\tstruct type t1, t2;\n\tunsigned bt1, bt2, bt;\n\tts_pop_de2(&t1, &t2);\n\tbt1 = TYPE_BT(&t1);\n\tbt2 = TYPE_BT(&t2);\n\tbt = bt_op(bt1, bt2);\n\tif (op == O_DIV || op == O_MOD)\n\t\tbt = T_MK(bt2 & T_MSIGN, bt);\n\to_bop(O_MK(op, bt));\n\tts_push_bt(bt);\n}\n\n/* push the result of an additive binary operation on the type stack */\nstatic void ts_addop(int op)\n{\n\tstruct type t1, t2;\n\tts_pop_de2(&t1, &t2);\n\tif (!t1.ptr && !t2.ptr) {\n\t\to_bop(op);\n\t\tts_push_bt(bt_op(TYPE_BT(&t1), TYPE_BT(&t2)));\n\t\treturn;\n\t}\n\tif (t1.ptr && !t2.ptr)\n\t\to_tmpswap();\n\tif (!t1.ptr && t2.ptr)\n\t\tif (type_szde(&t2) > 1) {\n\t\t\to_num(type_szde(&t2));\n\t\t\to_bop(O_MUL);\n\t\t}\n\tif (t1.ptr && !t2.ptr)\n\t\to_tmpswap();\n\to_bop(op);\n\tif (t1.ptr && t2.ptr) {\n\t\tint sz = type_szde(&t1);\n\t\tif (sz > 1) {\n\t\t\to_num(sz);\n\t\t\to_bop(O_DIV);\n\t\t}\n\t\tts_push_bt(SLNG);\n\t} else {\n\t\tts_push(t1.ptr ? &t1 : &t2);\n\t}\n}\n\n/* function prototypes for parsing function and variable declarations */\nstatic int readname(struct type *main, char *name, struct type *base);\nstatic int readtype(struct type *type);\nstatic int readdefs(void (*def)(long data, struct name *name, unsigned flags),\n\t\t\tlong data);\nstatic int readdefs_int(void (*def)(long data, struct name *name, unsigned flags),\n\t\t\tlong data);\n\n/* function prototypes for parsing initializer expressions */\nstatic int initsize(void);\nstatic void initexpr(struct type *t, int off, void *obj,\n\t\tvoid (*set)(void *obj, int off, struct type *t));\n\nstatic int type_alignment(struct type *t)\n{\n\tif (t->flags & T_ARRAY && !t->ptr)\n\t\treturn type_alignment(&arrays[t->id].type);\n\tif (t->flags & T_STRUCT && !t->ptr)\n\t\treturn type_alignment(&structs[t->id].fields[0].type);\n\treturn MIN(ULNG, type_totsz(t));\n}\n\nstatic void structdef(long data, struct name *name, unsigned flags)\n{\n\tstruct structinfo *si = &structs[data];\n\tif (si->isunion) {\n\t\tname->addr = 0;\n\t\tif (si->size < type_totsz(&name->type))\n\t\t\tsi->size = type_totsz(&name->type);\n\t} else {\n\t\tstruct type *t = &name->type;\n\t\tint alignment = type_alignment(t);\n\t\tif (t->flags & T_ARRAY && !t->ptr)\n\t\t\talignment = MIN(ULNG, type_totsz(&arrays[t->id].type));\n\t\tsi->size = ALIGN(si->size, alignment);\n\t\tname->addr = si->size;\n\t\tsi->size += type_totsz(&name->type);\n\t}\n\tmemcpy(&si->fields[si->nfields++], name, sizeof(*name));\n}\n\nstatic int struct_create(char *name, int isunion)\n{\n\tint id = struct_find(name, isunion);\n\ttok_req(\"{\");\n\twhile (tok_jmp(\"}\")) {\n\t\treaddefs(structdef, id);\n\t\ttok_req(\";\");\n\t}\n\treturn id;\n}\n\nstatic void readexpr(void);\n\nstatic void enum_create(void)\n{\n\tlong n = 0;\n\ttok_req(\"{\");\n\twhile (tok_jmp(\"}\")) {\n\t\tchar name[NAMELEN];\n\t\tstrcpy(name, tok_get());\n\t\tif (!tok_jmp(\"=\")) {\n\t\t\treadexpr();\n\t\t\tts_pop_de(NULL);\n\t\t\tif (o_popnum(&n))\n\t\t\t\terr(\"const expr expected!\\n\");\n\t\t}\n\t\tenum_add(name, n++);\n\t\ttok_jmp(\",\");\n\t}\n}\n\n/* used to differentiate labels from case and cond exprs */\nstatic int ncexpr;\nstatic int caseexpr;\n\nstatic void readpre(void);\n\nstatic char *tmp_str(char *buf, int len)\n{\n\tstatic char name[NAMELEN];\n\tstatic int id;\n\tsprintf(name, \"__neatcc.s%d\", id++);\n\tbuf[len] = '\\0';\n\to_dscpy(o_dsnew(name, len + 1, 0), buf, len + 1);\n\treturn name;\n}\n\nstatic void readprimary(void)\n{\n\tif (tok_grp() == '0') {\n\t\tlong n;\n\t\tint bt = tok_num(tok_get(), &n);\n\t\to_num(n);\n\t\tts_push_bt(bt);\n\t\treturn;\n\t}\n\tif (tok_grp() == '\"') {\n\t\tstruct type t = {};\t/* char type inside the arrays */\n\t\tstruct type a = {};\t/* the char array type */\n\t\tchar *buf = tok_get() + 1;\n\t\tint len = tok_len() - 2;\n\t\tt.bt = 1 | T_MSIGN;\n\t\ta.id = array_add(&t, len + 1);\n\t\ta.flags = T_ARRAY;\n\t\to_sym(tmp_str(buf, len));\n\t\tts_push(&a);\n\t\treturn;\n\t}\n\tif (tok_grp() == 'a') {\n\t\tstruct name unkn = {\"\"};\n\t\tchar *name = unkn.name;\n\t\tint n;\n\t\tstrcpy(name, tok_iden());\n\t\t/* don't search for labels here */\n\t\tif (!ncexpr && !caseexpr && tok_comes(\":\"))\n\t\t\treturn;\n\t\tif ((n = local_find(name)) != -1) {\n\t\t\tstruct name *l = &locals[n];\n\t\t\to_local(l->addr);\n\t\t\tts_push_addr(&l->type);\n\t\t\treturn;\n\t\t}\n\t\tif ((n = global_find(name)) != -1) {\n\t\t\tstruct name *g = &globals[n];\n\t\t\to_sym(*g->elfname ? g->elfname : g->name);\n\t\t\tts_push_addr(&g->type);\n\t\t\treturn;\n\t\t}\n\t\tif (!enum_find(&n, name)) {\n\t\t\to_num(n);\n\t\t\tts_push_bt(SINT);\n\t\t\treturn;\n\t\t}\n\t\tif (!tok_comes(\"(\"))\n\t\t\terr(\"unknown symbol <%s>\\n\", name);\n\t\tglobal_add(&unkn);\n\t\to_sym(unkn.name);\n\t\tts_push_bt(ULNG);\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"(\")) {\n\t\tstruct type t;\n\t\tif (!readtype(&t)) {\n\t\t\tstruct type o;\n\t\t\ttok_req(\")\");\n\t\t\treadpre();\n\t\t\tts_pop_de(&o);\n\t\t\tts_push(&t);\n\t\t\tif (!t.ptr || !o.ptr)\n\t\t\t\to_cast(TYPE_BT(&t));\n\t\t} else {\n\t\t\treadexpr();\n\t\t\twhile (tok_jmp(\")\")) {\n\t\t\t\ttok_req(\",\");\n\t\t\t\tts_pop(NULL);\n\t\t\t\to_tmpdrop(1);\n\t\t\t\treadexpr();\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n}\n\nstatic void arrayderef(void)\n{\n\tstruct type t;\n\tint sz;\n\tts_pop_de(NULL);\n\tts_pop(&t);\n\tif (!(t.flags & T_ARRAY && !t.ptr) && t.addr) {\n\t\to_tmpswap();\n\t\to_deref(TYPE_BT(&t));\n\t\to_tmpswap();\n\t}\n\tarray2ptr(&t);\n\tt.ptr--;\n\tsz = type_totsz(&t);\n\tt.addr = 1;\n\tif (sz > 1) {\n\t\to_num(sz);\n\t\to_bop(O_MUL);\n\t}\n\to_bop(O_ADD);\n\tts_push(&t);\n}\n\nstatic void inc_post(int op)\n{\n\tstruct type t = ts[nts - 1];\n\t/* pushing the value before inc */\n\to_tmpcopy();\n\tts_de(1);\n\to_tmpswap();\n\n\t/* increment by 1 or pointer size */\n\to_tmpcopy();\n\tts_push(&t);\n\tts_pop_de(&t);\n\to_num(t.ptr > 0 ? type_szde(&t) : 1);\n\to_bop(op);\n\n\t/* assign back */\n\to_assign(TYPE_BT(&t));\n\to_tmpdrop(1);\n}\n\nstatic void readfield(void)\n{\n\tstruct name *field;\n\tstruct type t;\n\tts_pop(&t);\n\tarray2ptr(&t);\n\tfield = struct_field(t.id, tok_get());\n\tif (field->addr) {\n\t\to_num(field->addr);\n\t\to_bop(O_ADD);\n\t}\n\tts_push_addr(&field->type);\n}\n\nstatic struct funcinfo {\n\tstruct type args[NARGS];\n\tstruct type ret;\n\tint nargs;\n\tint varg;\n\t/* function and argument names; useful only when defining */\n\tchar argnames[NARGS][NAMELEN];\n\tchar name[NAMELEN];\n} *funcs;\nstatic int funcs_n, funcs_sz;\n\nstatic int func_create(struct type *ret, char *name, char argnames[][NAMELEN],\n\t\t\tstruct type *args, int nargs, int varg)\n{\n\tstruct funcinfo *fi;\n\tint i;\n\tif (funcs_n >= funcs_sz) {\n\t\tfuncs_sz = MAX(128, funcs_sz * 2);\n\t\tfuncs = mextend(funcs, funcs_n, funcs_sz, sizeof(funcs[0]));\n\t}\n\tfi = &funcs[funcs_n++];\n\tmemcpy(&fi->ret, ret, sizeof(*ret));\n\tfor (i = 0; i < nargs; i++)\n\t\tmemcpy(&fi->args[i], &args[i], sizeof(*ret));\n\tfi->nargs = nargs;\n\tfi->varg = varg;\n\tstrcpy(fi->name, name ? name : \"\");\n\tfor (i = 0; i < nargs; i++)\n\t\tstrcpy(fi->argnames[i], argnames[i]);\n\treturn fi - funcs;\n}\n\nstatic void readcall(void)\n{\n\tstruct type t;\n\tstruct funcinfo *fi;\n\tint argc = 0;\n\tts_pop(&t);\n\tif (t.flags & T_FUNC && t.ptr > 0)\n\t\to_deref(ULNG);\n\tif (!tok_comes(\")\")) {\n\t\tdo {\n\t\t\treadexpr();\n\t\t\tts_pop_de(NULL);\n\t\t\targc++;\n\t\t} while (!tok_jmp(\",\"));\n\t}\n\ttok_req(\")\");\n\tfi = t.flags & T_FUNC ? &funcs[t.id] : NULL;\n\to_call(argc, fi ? TYPE_BT(&fi->ret) : SINT);\n\tif (fi) {\n\t\tif (TYPE_BT(&fi->ret))\n\t\t\to_cast(TYPE_BT(&fi->ret));\n\t\tts_push(&fi->ret);\n\t} else {\n\t\tts_push_bt(SINT);\n\t}\n}\n\nstatic void readpost(void)\n{\n\treadprimary();\n\twhile (1) {\n\t\tif (!tok_jmp(\"[\")) {\n\t\t\treadexpr();\n\t\t\ttok_req(\"]\");\n\t\t\tarrayderef();\n\t\t\tcontinue;\n\t\t}\n\t\tif (!tok_jmp(\"(\")) {\n\t\t\treadcall();\n\t\t\tcontinue;\n\t\t}\n\t\tif (!tok_jmp(\"++\")) {\n\t\t\tinc_post(O_ADD);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!tok_jmp(\"--\")) {\n\t\t\tinc_post(O_SUB);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!tok_jmp(\".\")) {\n\t\t\treadfield();\n\t\t\tcontinue;\n\t\t}\n\t\tif (!tok_jmp(\"->\")) {\n\t\t\tts_de(1);\n\t\t\treadfield();\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n}\n\nstatic void inc_pre(int op)\n{\n\tstruct type t;\n\treadpre();\n\t/* copy the destination */\n\to_tmpcopy();\n\tts_push(&ts[nts - 1]);\n\t/* increment by 1 or pointer size */\n\tts_pop_de(&t);\n\to_num(t.ptr > 0 ? type_szde(&t) : 1);\n\to_bop(op);\n\t/* assign the result */\n\to_assign(TYPE_BT(&t));\n\tts_de(0);\n}\n\nstatic void readpre(void)\n{\n\tstruct type t;\n\tif (!tok_jmp(\"&\")) {\n\t\treadpre();\n\t\tts_pop(&t);\n\t\tif (!t.addr)\n\t\t\terr(\"cannot use the address\\n\");\n\t\tt.ptr++;\n\t\tt.addr = 0;\n\t\tts_push(&t);\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"*\")) {\n\t\treadpre();\n\t\tts_pop(&t);\n\t\tarray2ptr(&t);\n\t\tif (!t.ptr)\n\t\t\terr(\"dereferencing non-pointer\\n\");\n\t\tif (t.addr)\n\t\t\to_deref(TYPE_BT(&t));\n\t\tt.ptr--;\n\t\tt.addr = 1;\n\t\tts_push(&t);\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"!\")) {\n\t\treadpre();\n\t\tts_pop_de(NULL);\n\t\to_uop(O_LNOT);\n\t\tts_push_bt(SINT);\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"+\")) {\n\t\treadpre();\n\t\tts_de(1);\n\t\tts_pop(&t);\n\t\tts_push_bt(bt_uop(TYPE_BT(&t)));\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"-\")) {\n\t\treadpre();\n\t\tts_de(1);\n\t\tts_pop(&t);\n\t\to_uop(O_NEG);\n\t\tts_push_bt(bt_uop(TYPE_BT(&t)));\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"~\")) {\n\t\treadpre();\n\t\tts_de(1);\n\t\tts_pop(&t);\n\t\to_uop(O_NOT);\n\t\tts_push_bt(bt_uop(TYPE_BT(&t)));\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"++\")) {\n\t\tinc_pre(O_ADD);\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"--\")) {\n\t\tinc_pre(O_SUB);\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"sizeof\")) {\n\t\tstruct type t;\n\t\tint op = !tok_jmp(\"(\");\n\t\tif (readtype(&t)) {\n\t\t\tlong m = o_mark();\n\t\t\tif (op)\n\t\t\t\treadexpr();\n\t\t\telse\n\t\t\t\treadpre();\n\t\t\to_back(m);\n\t\t\tts_pop(&t);\n\t\t\to_tmpdrop(1);\n\t\t}\n\t\to_num(type_totsz(&t));\n\t\tts_push_bt(ULNG);\n\t\tif (op)\n\t\t\ttok_req(\")\");\n\t\treturn;\n\t}\n\treadpost();\n}\n\nstatic void readmul(void)\n{\n\treadpre();\n\twhile (1) {\n\t\tif (!tok_jmp(\"*\")) {\n\t\t\treadpre();\n\t\t\tts_binop(O_MUL);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!tok_jmp(\"/\")) {\n\t\t\treadpre();\n\t\t\tts_binop(O_DIV);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!tok_jmp(\"%\")) {\n\t\t\treadpre();\n\t\t\tts_binop(O_MOD);\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n}\n\nstatic void readadd(void)\n{\n\treadmul();\n\twhile (1) {\n\t\tif (!tok_jmp(\"+\")) {\n\t\t\treadmul();\n\t\t\tts_addop(O_ADD);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!tok_jmp(\"-\")) {\n\t\t\treadmul();\n\t\t\tts_addop(O_SUB);\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n}\n\nstatic void shift(int op)\n{\n\tstruct type t;\n\treadadd();\n\tts_pop_de2(NULL, &t);\n\to_bop(O_MK(op, TYPE_BT(&t)));\n\tts_push_bt(bt_uop(TYPE_BT(&t)));\n}\n\nstatic void readshift(void)\n{\n\treadadd();\n\twhile (1) {\n\t\tif (!tok_jmp(\"<<\")) {\n\t\t\tshift(O_SHL);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!tok_jmp(\">>\")) {\n\t\t\tshift(O_SHR);\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n}\n\nstatic void cmp(int op)\n{\n\tstruct type t1, t2;\n\tint bt;\n\treadshift();\n\tts_pop_de2(&t1, &t2);\n\tbt = bt_op(TYPE_BT(&t1), TYPE_BT(&t2));\n\to_bop(O_MK(op, bt));\n\tts_push_bt(SINT);\n}\n\nstatic void readcmp(void)\n{\n\treadshift();\n\twhile (1) {\n\t\tif (!tok_jmp(\"<\")) {\n\t\t\tcmp(O_LT);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!tok_jmp(\">\")) {\n\t\t\tcmp(O_GT);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!tok_jmp(\"<=\")) {\n\t\t\tcmp(O_LE);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!tok_jmp(\">=\")) {\n\t\t\tcmp(O_GE);\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n}\n\nstatic void eq(int op)\n{\n\treadcmp();\n\tts_pop_de2(NULL, NULL);\n\to_bop(op);\n\tts_push_bt(SINT);\n}\n\nstatic void readeq(void)\n{\n\treadcmp();\n\twhile (1) {\n\t\tif (!tok_jmp(\"==\")) {\n\t\t\teq(O_EQ);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!tok_jmp(\"!=\")) {\n\t\t\teq(O_NE);\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n}\n\nstatic void readbitand(void)\n{\n\treadeq();\n\twhile (!tok_jmp(\"&\")) {\n\t\treadeq();\n\t\tts_binop(O_AND);\n\t}\n}\n\nstatic void readxor(void)\n{\n\treadbitand();\n\twhile (!tok_jmp(\"^\")) {\n\t\treadbitand();\n\t\tts_binop(O_XOR);\n\t}\n}\n\nstatic void readbitor(void)\n{\n\treadxor();\n\twhile (!tok_jmp(\"|\")) {\n\t\treadxor();\n\t\tts_binop(O_OR);\n\t}\n}\n\nstatic void savelocal(long val, int bt)\n{\n\to_local(val);\n\to_tmpswap();\n\to_assign(bt);\n\to_tmpdrop(1);\n}\n\nstatic void loadlocal(long val, int bt)\n{\n\to_local(val);\n\to_deref(bt);\n\to_rmlocal(val, bt);\n}\n\nstatic void readand(void)\n{\n\tint l_out, l_fail;\n\tlong val;\n\treadbitor();\n\tif (!tok_comes(\"&&\"))\n\t\treturn;\n\tval = o_mklocal(UINT);\n\tl_out = LABEL();\n\tl_fail = LABEL();\n\tts_pop_de(NULL);\n\to_jz(l_fail);\n\twhile (!tok_jmp(\"&&\")) {\n\t\treadbitor();\n\t\tts_pop_de(NULL);\n\t\to_jz(l_fail);\n\t}\n\to_num(1);\n\tsavelocal(val, UINT);\n\to_jmp(l_out);\n\to_label(l_fail);\n\to_num(0);\n\tsavelocal(val, UINT);\n\to_label(l_out);\n\tloadlocal(val, SINT);\n\tts_push_bt(SINT);\n}\n\nstatic void reador(void)\n{\n\tint l_pass, l_end;\n\tlong val;\n\treadand();\n\tif (!tok_comes(\"||\"))\n\t\treturn;\n\tval = o_mklocal(UINT);\n\tl_pass = LABEL();\n\tl_end = LABEL();\n\tts_pop_de(NULL);\n\to_uop(O_LNOT);\n\to_jz(l_pass);\n\twhile (!tok_jmp(\"||\")) {\n\t\treadand();\n\t\tts_pop_de(NULL);\n\t\to_uop(O_LNOT);\n\t\to_jz(l_pass);\n\t}\n\to_num(0);\n\tsavelocal(val, SINT);\n\to_jmp(l_end);\n\to_label(l_pass);\n\to_num(1);\n\tsavelocal(val, SINT);\n\to_label(l_end);\n\tloadlocal(val, SINT);\n\tts_push_bt(SINT);\n}\n\nstatic void readcexpr(void);\n\nstatic int readcexpr_const(void)\n{\n\tlong c, m = 0;\n\tif (o_popnum(&c))\n\t\treturn -1;\n\tif (!c)\n\t\tm = o_mark();\n\treadcexpr();\n\t/* both branches yield the same type; so ignore the first */\n\tts_pop_de(NULL);\n\ttok_req(\":\");\n\tif (!c) {\n\t\to_back(m);\n\t\to_tmpdrop(1);\n\t}\n\tif (c)\n\t\tm = o_mark();\n\treadcexpr();\n\t/* making sure t->addr == 0 on both branches */\n\tts_de(1);\n\tif (c) {\n\t\to_back(m);\n\t\to_tmpdrop(1);\n\t}\n\treturn 0;\n}\n\nstatic void readcexpr(void)\n{\n\treador();\n\tif (tok_jmp(\"?\"))\n\t\treturn;\n\tncexpr++;\n\tts_pop_de(NULL);\n\tif (readcexpr_const()) {\n\t\tlong val = 0;\n\t\tint l_fail = LABEL();\n\t\tint l_end = LABEL();\n\t\tstruct type ret;\n\t\to_jz(l_fail);\n\t\treadcexpr();\n\t\t/* both branches yield the same type; so ignore the first */\n\t\tts_pop_de(&ret);\n\t\tif (!TYPE_VOID(&ret)) {\n\t\t\tval = o_mklocal(ULNG);\n\t\t\tsavelocal(val, ULNG);\n\t\t}\n\t\to_jmp(l_end);\n\n\t\ttok_req(\":\");\n\t\to_label(l_fail);\n\t\treadcexpr();\n\t\t/* making sure t->addr == 0 on both branches */\n\t\tts_de(1);\n\t\tif (!TYPE_VOID(&ret)) {\n\t\t\tsavelocal(val, ULNG);\n\t\t}\n\t\to_label(l_end);\n\t\tif (!TYPE_VOID(&ret)) {\n\t\t\tloadlocal(val, ULNG);\n\t\t}\n\t}\n\tncexpr--;\n}\n\nstatic void opassign(int op, int ptrop)\n{\n\tstruct type t = ts[nts - 1];\n\to_tmpcopy();\n\tts_push(&t);\n\treadexpr();\n\tif (op == O_ADD || op == O_SUB)\n\t\tts_addop(op);\n\telse\n\t\tts_binop(op);\n\to_assign(TYPE_BT(&ts[nts - 2]));\n\tts_pop(NULL);\n\tts_de(0);\n}\n\nstatic void doassign(void)\n{\n\tstruct type t = ts[nts - 1];\n\tif (!t.ptr && t.flags & T_STRUCT) {\n\t\tts_pop(NULL);\n\t\to_num(type_totsz(&t));\n\t\to_memcpy();\n\t} else {\n\t\tts_pop_de(NULL);\n\t\to_assign(TYPE_BT(&ts[nts - 1]));\n\t\tts_de(0);\n\t}\n}\n\nstatic void readexpr(void)\n{\n\treadcexpr();\n\tif (!tok_jmp(\"=\")) {\n\t\treadexpr();\n\t\tdoassign();\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"+=\")) {\n\t\topassign(O_ADD, 1);\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"-=\")) {\n\t\topassign(O_SUB, 1);\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"*=\")) {\n\t\topassign(O_MUL, 0);\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"/=\")) {\n\t\topassign(O_DIV, 0);\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"%=\")) {\n\t\topassign(O_MOD, 0);\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"<<=\")) {\n\t\topassign(O_SHL, 0);\n\t\treturn;\n\t}\n\tif (!tok_jmp(\">>=\")) {\n\t\topassign(O_SHR, 0);\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"&=\")) {\n\t\topassign(O_AND, 0);\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"|=\")) {\n\t\topassign(O_OR, 0);\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"^=\")) {\n\t\topassign(O_XOR, 0);\n\t\treturn;\n\t}\n}\n\nstatic void readestmt(void)\n{\n\tdo {\n\t\to_tmpdrop(-1);\n\t\tnts = 0;\n\t\treadexpr();\n\t} while (!tok_jmp(\",\"));\n}\n\n#define F_GLOBAL(flags)\t\t(!((flags) & F_STATIC))\n\nstatic void globalinit(void *obj, int off, struct type *t)\n{\n\tstruct name *name = obj;\n\tchar *elfname = *name->elfname ? name->elfname : name->name;\n\tif (t->flags & T_ARRAY && tok_grp() == '\"') {\n\t\tstruct type *t_de = &arrays[t->id].type;\n\t\tif (!t_de->ptr && !t_de->flags && TYPE_SZ(t_de) == 1) {\n\t\t\tchar *buf = tok_get() + 1;\n\t\t\tint len = tok_len() - 2;\n\t\t\tbuf[len] = '\\0';\n\t\t\to_dscpy(name->addr + off, buf, len + 1);\n\t\t\treturn;\n\t\t}\n\t}\n\treadexpr();\n\tts_de(1);\n\to_dsset(elfname, off, TYPE_BT(t));\n\tts_pop(NULL);\n}\n\nstatic void readfunc(struct name *name, int flags);\n\nstatic void globaldef(long data, struct name *name, unsigned flags)\n{\n\tstruct type *t = &name->type;\n\tchar *elfname = *name->elfname ? name->elfname : name->name;\n\tint sz;\n\tif (t->flags & T_ARRAY && !t->ptr && !arrays[t->id].n)\n\t\tif (~flags & F_EXTERN)\n\t\t\tarrays[t->id].n = initsize();\n\tsz = type_totsz(t);\n\tif (!(flags & F_EXTERN) && (!(t->flags & T_FUNC) || t->ptr)) {\n\t\tif (tok_comes(\"=\"))\n\t\t\tname->addr = o_dsnew(elfname, sz, F_GLOBAL(flags));\n\t\telse\n\t\t\to_bsnew(elfname, sz, F_GLOBAL(flags));\n\t}\n\tglobal_add(name);\n\tif (!tok_jmp(\"=\"))\n\t\tinitexpr(t, 0, name, globalinit);\n\tif (tok_comes(\"{\") && name->type.flags & T_FUNC)\n\t\treadfunc(name, flags);\n}\n\n/* generate the address of local + off */\nstatic void o_localoff(long addr, int off)\n{\n\to_local(addr);\n\tif (off) {\n\t\to_num(off);\n\t\to_bop(O_ADD);\n\t}\n}\n\nstatic void localinit(void *obj, int off, struct type *t)\n{\n\tlong addr = *(long *) obj;\n\tif (t->flags & T_ARRAY && tok_grp() == '\"') {\n\t\tstruct type *t_de = &arrays[t->id].type;\n\t\tif (!t_de->ptr && !t_de->flags && TYPE_SZ(t_de) == 1) {\n\t\t\tchar *buf = tok_get() + 1;\n\t\t\tint len = tok_len() - 2;\n\t\t\to_localoff(addr, off);\n\t\t\to_sym(tmp_str(buf, len));\n\t\t\to_num(len + 1);\n\t\t\to_memcpy();\n\t\t\to_tmpdrop(1);\n\t\t\treturn;\n\t\t}\n\t}\n\to_localoff(addr, off);\n\tts_push(t);\n\treadexpr();\n\tdoassign();\n\tts_pop(NULL);\n\to_tmpdrop(1);\n}\n\n/* current function name */\nstatic char func_name[NAMELEN];\n\nstatic void localdef(long data, struct name *name, unsigned flags)\n{\n\tstruct type *t = &name->type;\n\tif ((flags & F_EXTERN) || ((t->flags & T_FUNC) && !t->ptr)) {\n\t\tglobal_add(name);\n\t\treturn;\n\t}\n\tif (flags & F_STATIC) {\n\t\tsprintf(name->elfname, \"__neatcc.%s.%s\", func_name, name->name);\n\t\tglobaldef(data, name, flags);\n\t\treturn;\n\t}\n\tif (t->flags & T_ARRAY && !t->ptr && !arrays[t->id].n)\n\t\tarrays[t->id].n = initsize();\n\tname->addr = o_mklocal(type_totsz(&name->type));\n\tlocal_add(name);\n\tif (!tok_jmp(\"=\")) {\n\t\t/* this is not necessary for \"struct x = y\" */\n\t\tif (t->flags & (T_ARRAY | T_STRUCT) && !t->ptr) {\n\t\t\to_local(name->addr);\n\t\t\to_num(0);\n\t\t\to_num(type_totsz(t));\n\t\t\to_memset();\n\t\t\to_tmpdrop(1);\n\t\t}\n\t\tinitexpr(t, 0, &name->addr, localinit);\n\t}\n}\n\nstatic void typedefdef(long data, struct name *name, unsigned flags)\n{\n\ttypedef_add(name->name, &name->type);\n}\n\nstatic void readstmt(void);\n\nstatic void readswitch(void)\n{\n\tint o_break = l_break;\n\tlong val_addr = o_mklocal(ULNG);\n\tstruct type t;\n\tint ncases = 0;\t\t\t/* number of case labels */\n\tint l_failed = LABEL();\t\t/* address of last failed jmp */\n\tint l_matched = LABEL();\t/* address of last walk through jmp */\n\tint l_default = 0;\t\t/* default case label */\n\tl_break = LABEL();\n\ttok_req(\"(\");\n\treadexpr();\n\tts_pop_de(&t);\n\to_local(val_addr);\n\to_tmpswap();\n\to_assign(TYPE_BT(&t));\n\to_tmpdrop(1);\n\ttok_req(\")\");\n\ttok_req(\"{\");\n\twhile (tok_jmp(\"}\")) {\n\t\tif (!tok_comes(\"case\") && !tok_comes(\"default\")) {\n\t\t\treadstmt();\n\t\t\tcontinue;\n\t\t}\n\t\tif (ncases)\n\t\t\to_jmp(l_matched);\n\t\tif (!strcmp(\"case\", tok_get())) {\n\t\t\to_label(l_failed);\n\t\t\tl_failed = LABEL();\n\t\t\tcaseexpr = 1;\n\t\t\treadexpr();\n\t\t\tts_pop_de(NULL);\n\t\t\tcaseexpr = 0;\n\t\t\to_local(val_addr);\n\t\t\to_deref(TYPE_BT(&t));\n\t\t\to_bop(O_EQ);\n\t\t\to_jz(l_failed);\n\t\t\to_tmpdrop(1);\n\t\t} else {\n\t\t\tif (!ncases)\n\t\t\t\to_jmp(l_failed);\n\t\t\tl_default = LABEL();\n\t\t\to_label(l_default);\n\t\t}\n\t\ttok_req(\":\");\n\t\to_label(l_matched);\n\t\tl_matched = LABEL();\n\t\tncases++;\n\t}\n\to_rmlocal(val_addr, ULNG);\n\to_jmp(l_break);\n\to_label(l_failed);\n\tif (l_default)\n\t\to_jmp(l_default);\n\to_label(l_break);\n\tl_break = o_break;\n}\n\nstatic char (*label_name)[NAMELEN];\nstatic int *label_ids;\nstatic int label_n, label_sz;\n\nstatic int label_id(char *name)\n{\n\tint i;\n\tif (label_n >= label_sz) {\n\t\tlabel_sz = MAX(128, label_sz * 2);\n\t\tlabel_name = mextend(label_name, label_n, label_sz,\n\t\t\t\t\tsizeof(label_name[0]));\n\t\tlabel_ids = mextend(label_ids, label_n, label_sz,\n\t\t\t\t\tsizeof(label_ids[0]));\n\t}\n\tfor (i = label_n - 1; i >= 0; --i)\n\t\tif (!strcmp(label_name[i], name))\n\t\t\treturn label_ids[i];\n\tstrcpy(label_name[label_n], name);\n\tlabel_ids[label_n] = LABEL();\n\treturn label_ids[label_n++];\n}\n\nstatic void readstmt(void)\n{\n\to_tmpdrop(-1);\n\tnts = 0;\n\tif (!tok_jmp(\"{\")) {\n\t\tint _nlocals = locals_n;\n\t\tint _nglobals = globals_n;\n\t\tint _nenums = enums_n;\n\t\tint _ntypedefs = typedefs_n;\n\t\tint _nstructs = structs_n;\n\t\tint _nfuncs = funcs_n;\n\t\tint _narrays = arrays_n;\n\t\twhile (tok_jmp(\"}\"))\n\t\t\treadstmt();\n\t\tlocals_n = _nlocals;\n\t\tenums_n = _nenums;\n\t\ttypedefs_n = _ntypedefs;\n\t\tstructs_n = _nstructs;\n\t\tfuncs_n = _nfuncs;\n\t\tarrays_n = _narrays;\n\t\tglobals_n = _nglobals;\n\t\treturn;\n\t}\n\tif (!readdefs(localdef, 0)) {\n\t\ttok_req(\";\");\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"typedef\")) {\n\t\treaddefs(typedefdef, 0);\n\t\ttok_req(\";\");\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"if\")) {\n\t\tint l_fail = LABEL();\n\t\tint l_end = LABEL();\n\t\ttok_req(\"(\");\n\t\treadestmt();\n\t\ttok_req(\")\");\n\t\tts_pop_de(NULL);\n\t\to_jz(l_fail);\n\t\treadstmt();\n\t\tif (!tok_jmp(\"else\")) {\n\t\t\to_jmp(l_end);\n\t\t\to_label(l_fail);\n\t\t\treadstmt();\n\t\t\to_label(l_end);\n\t\t} else {\n\t\t\to_label(l_fail);\n\t\t}\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"while\")) {\n\t\tint o_break = l_break;\n\t\tint o_cont = l_cont;\n\t\tl_break = LABEL();\n\t\tl_cont = LABEL();\n\t\to_label(l_cont);\n\t\ttok_req(\"(\");\n\t\treadestmt();\n\t\ttok_req(\")\");\n\t\tts_pop_de(NULL);\n\t\to_jz(l_break);\n\t\treadstmt();\n\t\to_jmp(l_cont);\n\t\to_label(l_break);\n\t\tl_break = o_break;\n\t\tl_cont = o_cont;\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"do\")) {\n\t\tint o_break = l_break;\n\t\tint o_cont = l_cont;\n\t\tint l_beg = LABEL();\n\t\tl_break = LABEL();\n\t\tl_cont = LABEL();\n\t\to_label(l_beg);\n\t\treadstmt();\n\t\ttok_req(\"while\");\n\t\ttok_req(\"(\");\n\t\to_label(l_cont);\n\t\treadexpr();\n\t\tts_pop_de(NULL);\n\t\to_uop(O_LNOT);\n\t\to_jz(l_beg);\n\t\ttok_req(\")\");\n\t\to_label(l_break);\n\t\ttok_req(\";\");\n\t\tl_break = o_break;\n\t\tl_cont = o_cont;\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"for\")) {\n\t\tint o_break = l_break;\n\t\tint o_cont = l_cont;\n\t\tint l_check = LABEL();\t/* for condition label */\n\t\tint l_body = LABEL();\t/* for block label */\n\t\tl_cont = LABEL();\n\t\tl_break = LABEL();\n\t\ttok_req(\"(\");\n\t\tif (!tok_comes(\";\"))\n\t\t\treadestmt();\n\t\ttok_req(\";\");\n\t\to_label(l_check);\n\t\tif (!tok_comes(\";\")) {\n\t\t\treadestmt();\n\t\t\tts_pop_de(NULL);\n\t\t\to_jz(l_break);\n\t\t}\n\t\ttok_req(\";\");\n\t\to_jmp(l_body);\n\t\to_label(l_cont);\n\t\tif (!tok_comes(\")\"))\n\t\t\treadestmt();\n\t\ttok_req(\")\");\n\t\to_jmp(l_check);\n\t\to_label(l_body);\n\t\treadstmt();\n\t\to_jmp(l_cont);\n\t\to_label(l_break);\n\t\tl_break = o_break;\n\t\tl_cont = o_cont;\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"switch\")) {\n\t\treadswitch();\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"return\")) {\n\t\tint ret = !tok_comes(\";\");\n\t\tif (ret) {\n\t\t\treadexpr();\n\t\t\tts_pop_de(NULL);\n\t\t}\n\t\ttok_req(\";\");\n\t\to_ret(ret);\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"break\")) {\n\t\ttok_req(\";\");\n\t\to_jmp(l_break);\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"continue\")) {\n\t\ttok_req(\";\");\n\t\to_jmp(l_cont);\n\t\treturn;\n\t}\n\tif (!tok_jmp(\"goto\")) {\n\t\to_jmp(label_id(tok_get()));\n\t\ttok_req(\";\");\n\t\treturn;\n\t}\n\treadestmt();\n\t/* labels */\n\tif (!tok_jmp(\":\")) {\n\t\to_label(label_id(tok_previden));\n\t\treturn;\n\t}\n\ttok_req(\";\");\n}\n\nstatic void readfunc(struct name *name, int flags)\n{\n\tstruct funcinfo *fi = &funcs[name->type.id];\n\tint i;\n\tstrcpy(func_name, fi->name);\n\to_func_beg(func_name, fi->nargs, F_GLOBAL(flags), fi->varg);\n\tfor (i = 0; i < fi->nargs; i++) {\n\t\tstruct name arg = {\"\", \"\", fi->args[i], o_arg2loc(i)};\n\t\tstrcpy(arg.name, fi->argnames[i]);\n\t\tlocal_add(&arg);\n\t}\n\tlabel = 0;\n\tlabel_n = 0;\n\treadstmt();\n\to_func_end();\n\tfunc_name[0] = '\\0';\n\tlocals_n = 0;\n}\n\nstatic void readdecl(void)\n{\n\tif (!tok_jmp(\"typedef\")) {\n\t\treaddefs(typedefdef, 0);\n\t\ttok_req(\";\");\n\t\treturn;\n\t}\n\treaddefs_int(globaldef, 0);\n\ttok_jmp(\";\");\n}\n\nstatic void parse(void)\n{\n\twhile (tok_jmp(\"\"))\n\t\treaddecl();\n}\n\nstatic void compat_macros(void)\n{\n\tcpp_define(\"__STDC__\", \"\");\n\tcpp_define(\"__linux__\", \"\");\n\tcpp_define(I_ARCH, \"\");\n\tcpp_define(\"__neatcc__\", \"\");\n\n\t/* ignored keywords */\n\tcpp_define(\"const\", \"\");\n\tcpp_define(\"register\", \"\");\n\tcpp_define(\"volatile\", \"\");\n\tcpp_define(\"inline\", \"\");\n\tcpp_define(\"restrict\", \"\");\n\tcpp_define(\"__inline__\", \"\");\n\tcpp_define(\"__restrict__\", \"\");\n\tcpp_define(\"__attribute__(x)\", \"\");\n\tcpp_define(\"__builtin_va_list__\", \"long\");\n}\n\nstatic int ncc_opt = 2;\n\n/* return one if the given optimization level is enabled */\nint opt(int level)\n{\n\treturn level <= ncc_opt;\n}\n\nint main(int argc, char *argv[])\n{\n\tchar obj[128] = \"\";\n\tint ofd = 1;\n\tint cpp = 0;\n\tint i;\n\tcompat_macros();\n\tfor (i = 1; i < argc && argv[i][0] == '-'; i++) {\n\t\tif (argv[i][1] == 'I')\n\t\t\tcpp_path(argv[i][2] ? argv[i] + 2 : argv[++i]);\n\t\tif (argv[i][1] == 'O')\n\t\t\tncc_opt = argv[i][2] ? atoi(argv[i] + 2) : 2;\n\t\tif (argv[i][1] == 'E')\n\t\t\tcpp = 1;\n\t\tif (argv[i][1] == 'D') {\n\t\t\tchar *name = argv[i] + 2;\n\t\t\tchar *def = \"\";\n\t\t\tchar *eq = strchr(name, '=');\n\t\t\tif (eq) {\n\t\t\t\t*eq = '\\0';\n\t\t\t\tdef = eq + 1;\n\t\t\t}\n\t\t\tcpp_define(name, def);\n\t\t}\n\t\tif (argv[i][1] == 'o')\n\t\t\tstrcpy(obj, argv[i][2] ? argv[i] + 2 : argv[++i]);\n\t\tif (argv[i][1] == 'h') {\n\t\t\tprintf(\"Usage: %s [options] source\\n\", argv[0]);\n\t\t\tprintf(\"\\n\");\n\t\t\tprintf(\"Options:\\n\");\n\t\t\tprintf(\"  -I dir     \\tspecify a header directory\\n\");\n\t\t\tprintf(\"  -o out     \\tspecify output file name\\n\");\n\t\t\tprintf(\"  -E         \\tpreprocess only\\n\");\n\t\t\tprintf(\"  -Dname=val \\tdefine a macro\\n\");\n\t\t\tprintf(\"  -On        \\toptimize (-O0 to disable)\\n\");\n\t\t\treturn 0;\n\t\t}\n\t}\n\tif (i == argc)\n\t\tdie(\"neatcc: no file given\\n\");\n\tif (cpp_init(argv[i]))\n\t\tdie(\"neatcc: cannot open <%s>\\n\", argv[i]);\n\tif (cpp) {\n\t\tlong clen;\n\t\tchar *cbuf;\n\t\tif (*obj)\n\t\t\tofd = open(obj, O_WRONLY | O_TRUNC | O_CREAT, 0600);\n\t\twhile (!cpp_read(&cbuf, &clen))\n\t\t\twrite(ofd, cbuf, clen);\n\t\tif (*obj)\n\t\t\tclose(ofd);\n\t\treturn 0;\n\t}\n\tout_init(0);\n\tparse();\n\tif (!*obj) {\n\t\tchar *cp = strrchr(argv[i], '/');\n\t\tstrcpy(obj, cp ? cp + 1 : argv[i]);\n\t\tobj[strlen(obj) - 1] = 'o';\n\t}\n\tfree(locals);\n\tfree(globals);\n\tfree(label_name);\n\tfree(label_ids);\n\tfree(funcs);\n\tfree(typedefs);\n\tfree(structs);\n\tfree(arrays);\n\ttok_done();\n\tofd = open(obj, O_WRONLY | O_TRUNC | O_CREAT, 0600);\n\to_write(ofd);\n\tclose(ofd);\n\treturn 0;\n}\n\n\f\n/* parsing function and variable declarations */\n\n/* read the base type of a variable */\nstatic int basetype(struct type *type, unsigned *flags)\n{\n\tint sign = 1;\n\tint size = UINT;\n\tint done = 0;\n\tint i = 0;\n\tint isunion;\n\tchar name[NAMELEN] = \"\";\n\t*flags = 0;\n\ttype->flags = 0;\n\ttype->ptr = 0;\n\ttype->addr = 0;\n\twhile (!done) {\n\t\tif (!tok_jmp(\"static\")) {\n\t\t\t*flags |= F_STATIC;\n\t\t} else if (!tok_jmp(\"extern\")) {\n\t\t\t*flags |= F_EXTERN;\n\t\t} else if (!tok_jmp(\"void\")) {\n\t\t\tsign = 0;\n\t\t\tsize = 0;\n\t\t\tdone = 1;\n\t\t} else if (!tok_jmp(\"int\")) {\n\t\t\tdone = 1;\n\t\t} else if (!tok_jmp(\"char\")) {\n\t\t\tsize = UCHR;\n\t\t\tdone = 1;\n\t\t} else if (!tok_jmp(\"short\")) {\n\t\t\tsize = USHT;\n\t\t} else if (!tok_jmp(\"long\")) {\n\t\t\tsize = ULNG;\n\t\t} else if (!tok_jmp(\"signed\")) {\n\t\t\tsign = 1;\n\t\t} else if (!tok_jmp(\"unsigned\")) {\n\t\t\tsign = 0;\n\t\t} else if (tok_comes(\"union\") || tok_comes(\"struct\")) {\n\t\t\tisunion = !strcmp(\"union\", tok_get());\n\t\t\tif (tok_grp() == 'a')\n\t\t\t\tstrcpy(name, tok_get());\n\t\t\tif (tok_comes(\"{\"))\n\t\t\t\ttype->id = struct_create(name, isunion);\n\t\t\telse\n\t\t\t\ttype->id = struct_find(name, isunion);\n\t\t\ttype->flags |= T_STRUCT;\n\t\t\ttype->bt = ULNG;\n\t\t\treturn 0;\n\t\t} else if (!tok_jmp(\"enum\")) {\n\t\t\tif (tok_grp() == 'a')\n\t\t\t\ttok_get();\n\t\t\tif (tok_comes(\"{\"))\n\t\t\t\tenum_create();\n\t\t\ttype->bt = SINT;\n\t\t\treturn 0;\n\t\t} else {\n\t\t\tif (tok_grp() == 'a') {\n\t\t\t\tint id = typedef_find(tok_see());\n\t\t\t\tif (id != -1) {\n\t\t\t\t\ttok_get();\n\t\t\t\t\tmemcpy(type, &typedefs[id].type,\n\t\t\t\t\t\tsizeof(*type));\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!i)\n\t\t\t\treturn 1;\n\t\t\tdone = 1;\n\t\t\tcontinue;\n\t\t}\n\t\ti++;\n\t}\n\ttype->bt = size | (sign ? T_MSIGN : 0);\n\treturn 0;\n}\n\nstatic void readptrs(struct type *type)\n{\n\twhile (!tok_jmp(\"*\")) {\n\t\ttype->ptr++;\n\t\tif (!type->bt)\n\t\t\ttype->bt = 1;\n\t}\n}\n\n/* read function arguments */\nstatic int readargs(struct type *args, char argnames[][NAMELEN], int *varg)\n{\n\tint nargs = 0;\n\ttok_req(\"(\");\n\t*varg = 0;\n\twhile (!tok_comes(\")\")) {\n\t\tif (!tok_jmp(\"...\")) {\n\t\t\t*varg = 1;\n\t\t\tbreak;\n\t\t}\n\t\tif (readname(&args[nargs], argnames[nargs], NULL)) {\n\t\t\t/* argument has no type, assume int */\n\t\t\tmemset(&args[nargs], 0, sizeof(struct type));\n\t\t\targs[nargs].bt = SINT;\n\t\t\tstrcpy(argnames[nargs], tok_get());\n\t\t}\n\t\t/* argument arrays are pointers */\n\t\tarray2ptr(&args[nargs]);\n\t\tnargs++;\n\t\tif (tok_jmp(\",\"))\n\t\t\tbreak;\n\t}\n\ttok_req(\")\");\n\t/* void argument */\n\tif (nargs == 1 && !TYPE_BT(&args[0]))\n\t\treturn 0;\n\treturn nargs;\n}\n\n/* read K&R function arguments */\nstatic void krdef(long data, struct name *name, unsigned flags)\n{\n\tstruct funcinfo *fi = &funcs[data];\n\tint i;\n\tfor (i = 0; i < fi->nargs; i++)\n\t\tif (!strcmp(fi->argnames[i], name->name))\n\t\t\tmemcpy(&fi->args[i], &name->type, sizeof(name->type));\n}\n\n/*\n * readarrays() parses array specifiers when reading a definition in\n * readname().  The \"type\" parameter contains the type contained in the\n * inner array; for instance, type in \"int *a[10][20]\" would be an int\n * pointer.  When returning, the \"type\" parameter is changed to point\n * to the final array.  The function returns a pointer to the type in\n * the inner array; this is useful when the type is not complete yet,\n * like when creating an array of function pointers as in\n * \"int (*f[10])(int)\".  If there is no array brackets, NULL is returned.\n */\nstatic struct type *readarrays(struct type *type)\n{\n\tlong arsz[16];\n\tstruct type *inner = NULL;\n\tint nar = 0;\n\tint i;\n\twhile (!tok_jmp(\"[\")) {\n\t\tlong n = 0;\n\t\tif (tok_jmp(\"]\")) {\n\t\t\treadexpr();\n\t\t\tts_pop_de(NULL);\n\t\t\tif (o_popnum(&n))\n\t\t\t\terr(\"const expr expected\\n\");\n\t\t\ttok_req(\"]\");\n\t\t}\n\t\tarsz[nar++] = n;\n\t}\n\tfor (i = nar - 1; i >= 0; i--) {\n\t\ttype->id = array_add(type, arsz[i]);\n\t\tif (!inner)\n\t\t\tinner = &arrays[type->id].type;\n\t\ttype->flags = T_ARRAY;\n\t\ttype->bt = ULNG;\n\t\ttype->ptr = 0;\n\t}\n\treturn inner;\n}\n\nstatic struct type *innertype(struct type *t)\n{\n\twhile (t->flags & T_ARRAY && !t->ptr)\n\t\tt = &arrays[t->id].type;\n\treturn t;\n}\n\nstatic void innertype_modify(struct type *t, struct type *s)\n{\n\tstruct type *inner = innertype(t);\n\tint ptr = inner->ptr;\n\tmemcpy(inner, s, sizeof(*inner));\n\tinner->ptr = ptr;\n}\n\n/*\n * readname() reads a variable definition; the name is copied into\n * \"name\" and the type is copied into \"main\" argument.  The \"base\"\n * argument, if not NULL, indicates the base type of the variable.\n * For instance, the base type of \"a\" and \"b\" in \"int *a, b[10]\" is\n * \"int\".  If NULL, basetype() is called directly to read the base\n * type of the variable.  readname() returns zero, only if the\n * variable can be read.\n */\nstatic int readname(struct type *main, char *name, struct type *base)\n{\n\tstruct type type;\t/* the main type */\n\tstruct type btype;\t/* type before parenthesis; e.g. \"int *\" in \"int *(*p)[10] */\n\tint paren;\n\tunsigned flags;\n\tif (name)\n\t\t*name = '\\0';\n\tif (!base) {\n\t\tif (basetype(&type, &flags))\n\t\t\treturn 1;\n\t} else {\n\t\ttype = *base;\n\t}\n\treadptrs(&type);\n\tparen = !tok_jmp(\"(\");\n\tif (paren) {\n\t\tbtype = type;\n\t\treadptrs(&type);\n\t}\n\tif (tok_grp() == 'a' && name)\n\t\tstrcpy(name, tok_get());\n\treadarrays(&type);\n\tif (paren)\n\t\ttok_req(\")\");\n\tif (tok_comes(\"(\")) {\n\t\tstruct type args[NARGS];\n\t\tchar argnames[NARGS][NAMELEN];\n\t\tint varg = 0;\n\t\tint nargs = readargs(args, argnames, &varg);\n\t\tstruct type rtype = type;\t/* return type */\n\t\tstruct type ftype = {0};\t/* function type */\n\t\tif (paren)\n\t\t\trtype = btype;\n\t\tftype.flags = T_FUNC;\n\t\tftype.bt = ULNG;\n\t\tftype.id = func_create(&rtype, name, argnames, args, nargs, varg);\n\t\tif (paren)\n\t\t\tinnertype_modify(&type, &ftype);\n\t\telse\n\t\t\ttype = ftype;\n\t\tif (!tok_comes(\";\"))\n\t\t\twhile (!tok_comes(\"{\") && !readdefs(krdef, type.id))\n\t\t\t\ttok_req(\";\");\n\t} else {\n\t\tif (paren && readarrays(&btype))\n\t\t\t\tinnertype_modify(&type, &btype);\n\t}\n\t*main = type;\n\treturn 0;\n}\n\nstatic int readtype(struct type *type)\n{\n\treturn readname(type, NULL, NULL);\n}\n\n/*\n * readdefs() reads a variable definition statement.  The definition\n * can appear in different contexts: global variables, function\n * local variables, struct fields, and typedefs.  For each defined\n * variable, def() callback is called with the appropriate name\n * struct and flags; the callback should finish parsing the definition\n * by possibly reading the initializer expression and saving the name\n * struct.\n */\nstatic int readdefs(void (*def)(long data, struct name *name, unsigned flags),\n\t\t\tlong data)\n{\n\tstruct type base;\n\tunsigned base_flags;\n\tif (basetype(&base, &base_flags))\n\t\treturn 1;\n\tif (tok_comes(\";\") || tok_comes(\"{\"))\n\t\treturn 0;\n\tdo {\n\t\tstruct name name = {{\"\"}};\n\t\tif (readname(&name.type, name.name, &base))\n\t\t\tbreak;\n\t\tdef(data, &name, base_flags);\n\t} while (!tok_jmp(\",\"));\n\treturn 0;\n}\n\n/* just like readdefs, but default to int type; for handling K&R functions */\nstatic int readdefs_int(void (*def)(long data, struct name *name, unsigned flags),\n\t\t\tlong data)\n{\n\tstruct type base;\n\tunsigned flags = 0;\n\tint nobase = 0;\n\tif (basetype(&base, &flags)) {\n\t\tnobase = 1;\n\t\tif (tok_grp() != 'a')\n\t\t\treturn 1;\n\t\tmemset(&base, 0, sizeof(base));\n\t\tbase.bt = SINT;\n\t}\n\tif (!tok_comes(\";\")) {\n\t\tdo {\n\t\t\tstruct name name = {{\"\"}};\n\t\t\tif (readname(&name.type, name.name, &base))\n\t\t\t\tbreak;\n\t\t\tif (nobase && tok_grp() == 'a')\n\t\t\t\terr(\"type missing!\\n\");\n\t\t\tdef(data, &name, flags);\n\t\t} while (!tok_jmp(\",\"));\n\t}\n\treturn 0;\n}\n\n\f\n/* parsing initializer expressions */\n\nstatic void jumpbrace(void)\n{\n\tint depth = 0;\n\twhile (!tok_comes(\"}\") || depth--)\n\t\tif (!strcmp(\"{\", tok_get()))\n\t\t\tdepth++;\n\ttok_req(\"}\");\n}\n\n/* compute the size of the initializer expression */\nstatic int initsize(void)\n{\n\tlong addr = tok_addr();\n\tint n = 0;\n\tif (tok_jmp(\"=\"))\n\t\treturn 0;\n\tif (tok_grp() == '\"') {\n\t\ttok_get();\n\t\tn = tok_len() - 2 + 1;\n\t\ttok_jump(addr);\n\t\treturn n;\n\t}\n\ttok_req(\"{\");\n\twhile (tok_jmp(\"}\")) {\n\t\tlong idx = n;\n\t\tif (!tok_jmp(\"[\")) {\n\t\t\treadexpr();\n\t\t\tts_pop_de(NULL);\n\t\t\to_popnum(&idx);\n\t\t\ttok_req(\"]\");\n\t\t\ttok_req(\"=\");\n\t\t}\n\t\tif (n < idx + 1)\n\t\t\tn = idx + 1;\n\t\twhile (!tok_comes(\"}\") && !tok_comes(\",\"))\n\t\t\tif (!strcmp(\"{\", tok_get()))\n\t\t\t\tjumpbrace();\n\t\ttok_jmp(\",\");\n\t}\n\ttok_jump(addr);\n\treturn n;\n}\n\n/* read the initializer expression and initialize basic types using set() cb */\nstatic void initexpr(struct type *t, int off, void *obj,\n\t\tvoid (*set)(void *obj, int off, struct type *t))\n{\n\tif (tok_jmp(\"{\")) {\n\t\tset(obj, off, t);\n\t\treturn;\n\t}\n\tif (!t->ptr && t->flags & T_STRUCT) {\n\t\tstruct structinfo *si = &structs[t->id];\n\t\tint i;\n\t\tfor (i = 0; i < si->nfields && !tok_comes(\"}\"); i++) {\n\t\t\tstruct name *field = &si->fields[i];\n\t\t\tif (!tok_jmp(\".\")) {\n\t\t\t\tfield = struct_field(t->id, tok_get());\n\t\t\t\ttok_req(\"=\");\n\t\t\t}\n\t\t\tinitexpr(&field->type, off + field->addr, obj, set);\n\t\t\tif (tok_jmp(\",\"))\n\t\t\t\tbreak;\n\t\t}\n\t} else if (t->flags & T_ARRAY) {\n\t\tstruct type t_de = arrays[t->id].type;\n\t\tint i;\n\t\t/* handling extra braces as in: char s[] = {\"sth\"} */\n\t\tif (TYPE_SZ(&t_de) == 1 && tok_grp() == '\"') {\n\t\t\tset(obj, off, t);\n\t\t\ttok_req(\"}\");\n\t\t\treturn;\n\t\t}\n\t\tfor (i = 0; !tok_comes(\"}\"); i++) {\n\t\t\tlong idx = i;\n\t\t\tstruct type it = t_de;\n\t\t\tif (!tok_jmp(\"[\")) {\n\t\t\t\treadexpr();\n\t\t\t\tts_pop_de(NULL);\n\t\t\t\to_popnum(&idx);\n\t\t\t\ttok_req(\"]\");\n\t\t\t\ttok_req(\"=\");\n\t\t\t}\n\t\t\tif (!tok_comes(\"{\") && (tok_grp() != '\"' ||\n\t\t\t\t\t\t!(it.flags & T_ARRAY)))\n\t\t\t\tit = *innertype(&t_de);\n\t\t\tinitexpr(&it, off + type_totsz(&it) * idx, obj, set);\n\t\t\tif (tok_jmp(\",\"))\n\t\t\t\tbreak;\n\t\t}\n\t}\n\ttok_req(\"}\");\n}\n"
  },
  {
    "path": "ncc.h",
    "content": "/*\n * THE NEATCC C COMPILER\n *\n * This header file is organized as follows:\n *\n * 0. helper functions and data structures\n * 1. ncc.c -> tok.c: the interface for reading tokens\n * 2. ncc.c -> int.c: the interface for generating the intermediate code\n * 3. int.c -> gen.c: the intermediate code\n * 4. gen.c -> x64.c: the interface for generating the final code\n * 5. gen.c -> out.c: the interface for generating object files\n */\n\n/* SECTION ZERO: Helper Functions */\n/* predefined array limits; (p.f. means per function) */\n#define NARGS\t\t32\t\t/* number of function/macro arguments */\n#define NTMPS\t\t64\t\t/* number of expression temporaries */\n#define NFIELDS\t\t128\t\t/* number of fields in structs */\n#define NAMELEN\t\t128\t\t/* size of identifiers */\n#define NDEFS\t\t4096\t\t/* number of macros */\n#define MARGLEN\t\t1024\t\t/* size of macro arguments */\n#define MDEFLEN\t\t2048\t\t/* size of macro definitions */\n#define NBUFS\t\t32\t\t/* macro expansion stack depth */\n#define NLOCS\t\t1024\t\t/* number of header search paths */\n\n#define LEN(a)\t\t(sizeof(a) / sizeof((a)[0]))\n#define ALIGN(x, a)\t(((x) + (a) - 1) & ~((a) - 1))\n#define MIN(a, b)\t((a) < (b) ? (a) : (b))\n#define MAX(a, b)\t((a) < (b) ? (b) : (a))\n\nvoid *mextend(void *old, long oldsz, long newsz, long memsz);\nvoid die(char *msg, ...);\nvoid err(char *fmt, ...);\nint opt(int level);\n\n/* variable length buffer */\nstruct mem {\n\tchar *s;\t\t/* allocated buffer */\n\tlong sz;\t\t/* buffer size */\n\tlong n;\t\t\t/* length of data stored in s */\n};\n\nvoid mem_init(struct mem *mem);\nvoid mem_done(struct mem *mem);\nvoid mem_cut(struct mem *mem, long pos);\nvoid *mem_buf(struct mem *mem);\nvoid mem_put(struct mem *mem, void *buf, long len);\nvoid mem_putc(struct mem *mem, int c);\nvoid mem_putz(struct mem *mem, long sz);\nvoid mem_cpy(struct mem *mem, long off, void *buf, long len);\nlong mem_len(struct mem *mem);\nvoid *mem_get(struct mem *mem);\n\n/* SECTION ONE: Tokenisation */\nvoid tok_init(char *path);\nvoid tok_done(void);\nchar *tok_see(void);\t\t/* return the current token; a static buffer */\nchar *tok_get(void);\t\t/* return and consume the current token */\nlong tok_len(void);\t\t/* the length of the last token */\nlong tok_num(char *tok, long *n);\nlong tok_addr(void);\nvoid tok_jump(long addr);\n\nint cpp_init(char *path);\nvoid cpp_path(char *s);\nvoid cpp_define(char *name, char *def);\nchar *cpp_loc(long addr);\nint cpp_read(char **buf, long *len);\n\n/* SECTION TWO: Intermediate Code Generation */\n/* basic type meaning */\n#define T_MSIZE\t\t0x000f\n#define T_MSIGN\t\t0x0010\n#define T_SZ(bt)\t((bt) & T_MSIZE)\n#define T_SG(bt)\t((bt) & T_MSIGN)\n#define T_MK(sign, size)\t(((sign) & T_MSIGN) | ((size) & T_MSIZE))\n\n/* number of bytes in basic types */\n#define ULNG\t\t(LONGSZ)\n#define UINT\t\t(4)\n#define USHT\t\t(2)\n#define UCHR\t\t(1)\n/* basic types */\n#define SLNG\t\t(ULNG | T_MSIGN)\n#define SINT\t\t(UINT | T_MSIGN)\n#define SSHT\t\t(USHT | T_MSIGN)\n#define SCHR\t\t(UCHR | T_MSIGN)\n\n/*\n * Intermediate instruction operands\n * R: register, N: immediate, S: symbol, L: local,\n * D: displacement, G: label, C: arguments\n */\n/* Instruction\t\t\t\trd\tr1\tr2\tr3 */\n#define O_ADD\t0x000010\t/*\tR\tR\tRN\t-  */\n#define O_SHL\t0x000020\t/*\tR\tR\tRN\t-  */\n#define O_MUL\t0x000040\t/*\tR\tR\tRN\t-  */\n#define O_CMP\t0x000080\t/*\tR\tR\tRN\t-  */\n#define O_UOP\t0x000100\t/*\tR\tR\t-\t-  */\n#define O_CALL\t0x000200\t/*\tR\tRS\tD\tC  */\n#define O_MOV\t0x000400\t/*\tR\tRNSL\tD\t-  */\n#define O_MEM\t0x000800\t/*\t-\tR\tR\tR  */\n#define O_JMP\t0x001000\t/*\t-\t-\t-\tG  */\n#define O_JZ\t0x002000\t/*\t-\tR\t-\tG  */\n#define O_JCC\t0x004000\t/*\t-\tR\tRN\tG  */\n#define O_RET\t0x008000\t/*\t-\tR\t-\t-  */\n#define O_LD\t0x010000\t/*\tR\tRSL\tD\t-  */\n#define O_ST\t0x020000\t/*\t-\tR\tRSL\tD  */\n/* opcode flags: num, loc, sym */\n#define O_NUM\t0x100000\t/* instruction immediate */\n#define O_LOC\t0x200000\t/* local (frame pointer displacement) */\n#define O_SYM\t0x400000\t/* symbols (relocations and offset) */\n/* other members of instruction groups */\n#define O_SUB\t\t(1 | O_ADD)\n#define O_AND\t\t(2 | O_ADD)\n#define O_OR\t\t(3 | O_ADD)\n#define O_XOR\t\t(4 | O_ADD)\n#define O_SHR\t\t(1 | O_SHL)\n#define O_DIV\t\t(1 | O_MUL)\n#define O_MOD\t\t(2 | O_MUL)\n#define O_LT\t\t(0 | O_CMP)\n#define O_GE\t\t(1 | O_CMP)\n#define O_EQ\t\t(2 | O_CMP)\n#define O_NE\t\t(3 | O_CMP)\n#define O_LE\t\t(4 | O_CMP)\n#define O_GT\t\t(5 | O_CMP)\n#define O_NEG\t\t(0 | O_UOP)\n#define O_NOT\t\t(1 | O_UOP)\n#define O_LNOT\t\t(2 | O_UOP)\n#define O_MSET\t\t(0 | O_MEM)\n#define O_MCPY\t\t(1 | O_MEM)\n#define O_JNZ\t\t(1 | O_JZ)\n/* instruction masks */\n#define O_BOP\t\t(O_ADD | O_MUL | O_CMP | O_SHL)\n#define O_OUT\t\t(O_BOP | O_UOP | O_CALL | O_MOV | O_LD)\n#define O_JXX\t\t(O_JMP | O_JZ | O_JCC)\n/* instruction operand type */\n#define O_C(op)\t\t((op) & 0xffffff)\t/* operation code */\n#define O_T(op)\t\t((op) >> 24)\t/* instruction operand type */\n#define O_MK(op, bt)\t((op) | ((bt) << 24))\n\n/* operations on the stack */\nvoid o_bop(long op);\t\t/* binary operation */\nvoid o_uop(long op);\t\t/* unary operation */\nvoid o_cast(long bt);\nvoid o_memcpy(void);\nvoid o_memset(void);\nvoid o_call(int argc, int ret);\nvoid o_ret(int ret);\nvoid o_assign(long bt);\nvoid o_deref(long bt);\nvoid o_load(void);\nint o_popnum(long *num);\nint o_popsym(long *sym, long *off);\n/* pushing values to the stack */\nvoid o_num(long n);\nvoid o_local(long addr);\nvoid o_sym(char *sym);\nvoid o_tmpdrop(int n);\nvoid o_tmpswap(void);\nvoid o_tmpcopy(void);\n/* handling locals */\nlong o_mklocal(long size);\nvoid o_rmlocal(long addr, long sz);\nlong o_arg2loc(int i);\n/* branches */\nvoid o_label(long id);\nvoid o_jmp(long id);\nvoid o_jz(long id);\nlong o_mark(void);\nvoid o_back(long mark);\n/* data/bss sections */\nlong o_dsnew(char *name, long size, int global);\nvoid o_dscpy(long addr, void *buf, long len);\nvoid o_dsset(char *name, long off, long bt);\nvoid o_bsnew(char *name, long size, int global);\n/* functions */\nvoid o_func_beg(char *name, int argc, int global, int vararg);\nvoid o_func_end(void);\nvoid o_code(char *name, char *c, long c_len);\n/* output */\nvoid o_write(int fd);\n\n/* SECTION THREE: The Intermediate Code */\n/* intermediate code instructions */\nstruct ic {\n\tlong op;\t\t/* instruction opcode */\n\tlong a1;\t\t/* first argument */\n\tlong a2;\t\t/* second argument */\n\tlong a3;\t\t/* more information, like jump target */\n\tlong *args;\t\t/* call arguments */\n};\n\n/* get the generated intermediate code */\nvoid ic_get(struct ic **c, long *n);\nint ic_num(struct ic *ic, long iv, long *num);\nint ic_sym(struct ic *ic, long iv, long *sym, long *off);\nlong *ic_lastuse(struct ic *ic, long ic_n);\nvoid ic_free(struct ic *ic);\nint ic_regcnt(struct ic *ic);\n\n/* global register allocation */\nvoid reg_init(struct ic *ic, long ic_n);\nlong reg_mask(void);\nint reg_lmap(long ic, long loc);\nint reg_rmap(long ic, long reg);\nint reg_safe(long loc);\nvoid reg_done(void);\n\n/* SECTION FOUR: Final Code Generation */\n/*\n * To make maintaining different architectures easier and to unify the\n * optimizations, I have merged the code generation for different\n * architectures.  The i_*() functions are now the low level\n * architecture-specific code generation entry points.  The\n * differences between RISC and CISC architectures, actually the\n * annoying asymmetry in CISC architecture, has made this interface\n * more complex than it could have ideally been.  Nevertheless,\n * the benefits of extracting gen.c and the cleaner design,\n * especially with the presence of the optimizations, outweighs the\n * added complexity.  Overall, there were many challenges for\n * extracting gen.c including:\n * + Different register sets; caller/callee saved and argument registers\n * + CISC-style instructions that work on limited registers and parameters\n * + Different instruction formats and immediate value limitations\n * + Generating epilog, prolog, and local variable addresses when optimizing\n *\n * I tried to make this interface as small as possible.  The key\n * functions and macros described next.\n *\n * i_reg() returns the mask of allowed registers for each\n * operand of an instruction.  The first argument op, specifies\n * the instruction (O_* macros); i_reg() sets the value r0, r1,\n * and r2 to indicate the mask of acceptable registers for the\n * first, second, and third operands of the instruction.\n * The value of these masks may be changed to zero to indicate\n * fewer than three operands.  If md is zero while m1 is not,\n * the destination register should be equal to the first register,\n * as in CISC architectures.  mt denotes the mask of registers\n * that may lose their contents after the instruction.\n *\n * i_ins() generates code for the given instruction.  The arguments\n * indicate the instruction and its operands.  The code is generated\n * by calling os() and oi() functions and the current position in\n * the code segment is obtained by calling opos().  For branch\n * instructions, i_ins() returns the position of branch offset in\n * code segment, to be filled later with i_fill().\n *\n * Some macros should be defined in architecture-dependent headers\n * and a few variables should be defined for each architecture,\n * such as tmpregs, which is an array of register numbers that\n * can be used for holding temporaries and argregs, which is an\n * array of register numbers for holding the first N_ARGS arguments.\n * Consult x64.h as an example, for the macros defined for each\n * architecture.\n *\n */\n#ifdef NEATCC_ARM\n#include \"arm.h\"\n#endif\n#ifdef NEATCC_X64\n#include \"x64.h\"\n#endif\n#ifdef NEATCC_X86\n#include \"x86.h\"\n#endif\n\n/* architecture-specific operations */\nlong i_reg(long op, long *rd, long *r1, long *r2, long *r3, long *mt);\nlong i_ins(long op, long rd, long r1, long r2, long r3);\nint i_imm(long lim, long n);\nvoid i_label(long id);\nvoid i_wrap(int argc, long sargs, long spsub, int initfp, long sregs, long sregs_pos);\nvoid i_code(char **c, long *c_len, long **rsym, long **rflg, long **roff, long *rcnt);\nvoid i_done(void);\n\nextern int tmpregs[];\nextern int argregs[];\n\n/* SECTION FIVE: Object File Generation */\n#define OUT_CS\t\t0x0001\t\t/* code segment symbol */\n#define OUT_DS\t\t0x0002\t\t/* data segment symbol */\n#define OUT_BSS\t\t0x0004\t\t/* bss segment symbol */\n\n#define OUT_GLOB\t0x0010\t\t/* global symbol */\n\n#define OUT_RLREL\t0x0020\t\t/* relative relocation */\n#define OUT_RLSX\t0x0040\t\t/* sign extend relocation */\n#define OUT_RL24\t0x0400\t\t/* 3-byte relocation */\n#define OUT_RL32\t0x0800\t\t/* 4-byte relocation */\n\n#define OUT_ALIGNMENT\t16\t\t/* section alignment */\n\nvoid out_init(long flags);\n\nlong out_sym(char *name);\nvoid out_def(char *name, long flags, long off, long len);\nvoid out_rel(long id, long flags, long off);\n\nvoid out_write(int fd, char *cs, long cslen, char *ds, long dslen);\n"
  },
  {
    "path": "out.c",
    "content": "/* neatcc ELF object generation */\n#include <elf.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include \"ncc.h\"\n\n#define ALIGN(x, a)\t\t(((x) + (a) - 1) & ~((a) - 1))\n\n#define SEC_TEXT\t\t1\n#define SEC_REL\t\t\t2\n#define SEC_SYMS\t\t3\n#define SEC_SYMSTR\t\t4\n#define SEC_DAT\t\t\t5\n#define SEC_DATREL\t\t6\n#define SEC_BSS\t\t\t7\n#define NSECS\t\t\t8\n\n/* simplified elf struct and macro names */\n#if LONGSZ == 8\n#  define USERELA\t1\n#  define Elf_Ehdr\tElf64_Ehdr\n#  define Elf_Shdr\tElf64_Shdr\n#  define Elf_Sym\tElf64_Sym\n#  define Elf_Rel\tElf64_Rela\n#  define ELF_ST_INFO\tELF64_ST_INFO\n#  define ELF_ST_BIND\tELF64_ST_BIND\n#  define ELF_R_SYM\tELF64_R_SYM\n#  define ELF_R_TYPE\tELF64_R_TYPE\n#  define ELF_R_INFO\tELF64_R_INFO\n#else\n#  define USERELA\t0\n#  define Elf_Ehdr\tElf32_Ehdr\n#  define Elf_Shdr\tElf32_Shdr\n#  define Elf_Sym\tElf32_Sym\n#  define Elf_Rel\tElf32_Rel\n#  define ELF_ST_INFO\tELF32_ST_INFO\n#  define ELF_ST_BIND\tELF32_ST_BIND\n#  define ELF_R_SYM\tELF32_R_SYM\n#  define ELF_R_TYPE\tELF32_R_TYPE\n#  define ELF_R_INFO\tELF32_R_INFO\n#endif\n\nstatic Elf_Ehdr ehdr;\nstatic Elf_Shdr shdr[NSECS];\nstatic Elf_Sym *syms;\nstatic long syms_n, syms_sz;\nstatic char *symstr;\nstatic long symstr_n, symstr_sz;\n\nstatic Elf_Rel *dsrel;\nstatic long dsrel_n, dsrel_sz;\nstatic Elf_Rel *csrel;\nstatic long csrel_n, csrel_sz;\n\nvoid err(char *msg, ...);\nstatic int rel_type(int flags);\nstatic void ehdr_init(Elf_Ehdr *ehdr);\n\nstatic long symstr_add(char *name)\n{\n\tlong len = strlen(name) + 1;\n\tif (symstr_n + len >= symstr_sz) {\n\t\tsymstr_sz = MAX(512, symstr_sz * 2);\n\t\tsymstr = mextend(symstr, symstr_n, symstr_sz, sizeof(symstr[0]));\n\t}\n\tstrcpy(symstr + symstr_n, name);\n\tsymstr_n += len;\n\treturn symstr_n - len;\n}\n\nstatic long sym_find(char *name)\n{\n\tint i;\n\tfor (i = 0; i < syms_n; i++)\n\t\tif (!strcmp(name, symstr + syms[i].st_name))\n\t\t\treturn i;\n\treturn -1;\n}\n\nstatic Elf_Sym *put_sym(char *name)\n{\n\tlong found = sym_find(name);\n\tElf_Sym *sym;\n\tif (found >= 0)\n\t\treturn &syms[found];\n\tif (syms_n >= syms_sz) {\n\t\tsyms_sz = MAX(128, syms_sz * 2);\n\t\tsyms = mextend(syms, syms_n, syms_sz, sizeof(syms[0]));\n\t}\n\tsym = &syms[syms_n++];\n\tsym->st_name = symstr_add(name);\n\tsym->st_shndx = SHN_UNDEF;\n\tsym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC);\n\treturn sym;\n}\n\n#define SYMLOCAL(i)\t\t(ELF_ST_BIND(syms[i].st_info) == STB_LOCAL)\n\nstatic void mvrela(long *mv, Elf_Rel *rels, long n)\n{\n\tlong i;\n\tfor (i = 0; i < n; i++) {\n\t\tint sym = ELF_R_SYM(rels[i].r_info);\n\t\tint type = ELF_R_TYPE(rels[i].r_info);\n\t\trels[i].r_info = ELF_R_INFO(mv[sym], type);\n\t}\n}\n\nstatic int syms_sort(void)\n{\n\tlong *mv;\n\tint i, j;\n\tint glob_beg = 1;\n\tmv = malloc(syms_n * sizeof(mv[0]));\n\tfor (i = 0; i < syms_n; i++)\n\t\tmv[i] = i;\n\ti = 1;\n\tj = syms_n - 1;\n\twhile (1) {\n\t\tElf_Sym t;\n\t\twhile (i < j && SYMLOCAL(i))\n\t\t\ti++;\n\t\twhile (j >= i && !SYMLOCAL(j))\n\t\t\tj--;\n\t\tif (i >= j)\n\t\t\tbreak;\n\t\tt = syms[j];\n\t\tsyms[j] = syms[i];\n\t\tsyms[i] = t;\n\t\tmv[i] = j;\n\t\tmv[j] = i;\n\t}\n\tglob_beg = j + 1;\n\tmvrela(mv, csrel, csrel_n);\n\tmvrela(mv, dsrel, dsrel_n);\n\tfree(mv);\n\treturn glob_beg;\n}\n\nvoid out_init(long flags)\n{\n\tput_sym(\"\");\n}\n\n/* return a symbol identifier */\nvoid out_def(char *name, long flags, long off, long len)\n{\n\tElf_Sym *sym = put_sym(name);\n\tint type = (flags & OUT_CS) ? STT_FUNC : STT_OBJECT;\n\tint bind = (flags & OUT_GLOB) ? STB_GLOBAL : STB_LOCAL;\n\tif (flags & OUT_CS)\n\t\tsym->st_shndx = SEC_TEXT;\n\tif (flags & OUT_DS)\n\t\tsym->st_shndx = SEC_DAT;\n\tif (flags & OUT_BSS)\n\t\tsym->st_shndx = SEC_BSS;\n\tsym->st_info = ELF_ST_INFO(bind, type);\n\tsym->st_value = off;\n\tsym->st_size = len;\n}\n\nlong out_sym(char *name)\n{\n\treturn put_sym(name) - syms;\n}\n\nstatic void out_csrel(long idx, long off, int flags)\n{\n\tElf_Rel *r;\n\tif (csrel_n >= csrel_sz) {\n\t\tcsrel_sz = MAX(128, csrel_sz * 2);\n\t\tcsrel = mextend(csrel, csrel_n, csrel_sz, sizeof(csrel[0]));\n\t}\n\tr = &csrel[csrel_n++];\n\tr->r_offset = off;\n\tr->r_info = ELF_R_INFO(idx, rel_type(flags));\n}\n\nstatic void out_dsrel(long idx, long off, int flags)\n{\n\tElf_Rel *r;\n\tif (dsrel_n >= dsrel_sz) {\n\t\tdsrel_sz = MAX(128, dsrel_sz * 2);\n\t\tdsrel = mextend(dsrel, dsrel_n, dsrel_sz, sizeof(dsrel[0]));\n\t}\n\tr = &dsrel[dsrel_n++];\n\tr->r_offset = off;\n\tr->r_info = ELF_R_INFO(idx, rel_type(flags));\n}\n\nvoid out_rel(long idx, long flags, long off)\n{\n\tif (flags & OUT_DS)\n\t\tout_dsrel(idx, off, flags);\n\telse\n\t\tout_csrel(idx, off, flags);\n}\n\nstatic long bss_len(void)\n{\n\tlong len = 0;\n\tint i;\n\tfor (i = 0; i < syms_n; i++) {\n\t\tlong end = syms[i].st_value + syms[i].st_size;\n\t\tif (syms[i].st_shndx == SEC_BSS)\n\t\t\tif (len < end)\n\t\t\t\tlen = end;\n\t}\n\treturn len;\n}\n\nvoid out_write(int fd, char *cs, long cslen, char *ds, long dslen)\n{\n\tElf_Shdr *text_shdr = &shdr[SEC_TEXT];\n\tElf_Shdr *rela_shdr = &shdr[SEC_REL];\n\tElf_Shdr *symstr_shdr = &shdr[SEC_SYMSTR];\n\tElf_Shdr *syms_shdr = &shdr[SEC_SYMS];\n\tElf_Shdr *dat_shdr = &shdr[SEC_DAT];\n\tElf_Shdr *datrel_shdr = &shdr[SEC_DATREL];\n\tElf_Shdr *bss_shdr = &shdr[SEC_BSS];\n\tunsigned long offset = sizeof(ehdr);\n\n\t/* workaround for the idiotic gnuld; use neatld instead! */\n\ttext_shdr->sh_name = symstr_add(\".cs\");\n\trela_shdr->sh_name = symstr_add(USERELA ? \".rela.cs\" : \".rels.cs\");\n\tdat_shdr->sh_name = symstr_add(\".ds\");\n\tdatrel_shdr->sh_name = symstr_add(USERELA ? \".rela.ds\" : \".rels.ds\");\n\n\tehdr.e_ident[0] = 0x7f;\n\tehdr.e_ident[1] = 'E';\n\tehdr.e_ident[2] = 'L';\n\tehdr.e_ident[3] = 'F';\n\tehdr.e_ident[4] = LONGSZ == 8 ? ELFCLASS64 : ELFCLASS32;\n\tehdr.e_ident[5] = ELFDATA2LSB;\n\tehdr.e_ident[6] = EV_CURRENT;\n\tehdr.e_type = ET_REL;\n\tehdr_init(&ehdr);\n\tehdr.e_version = EV_CURRENT;\n\tehdr.e_ehsize = sizeof(ehdr);\n\tehdr.e_shentsize = sizeof(shdr[0]);\n\tehdr.e_shoff = offset;\n\tehdr.e_shnum = NSECS;\n\tehdr.e_shstrndx = SEC_SYMSTR;\n\toffset += sizeof(shdr[0]) * NSECS;\n\n\ttext_shdr->sh_type = SHT_PROGBITS;\n\ttext_shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;\n\ttext_shdr->sh_offset = offset;\n\ttext_shdr->sh_size = cslen;\n\ttext_shdr->sh_entsize = 1;\n\ttext_shdr->sh_addralign = OUT_ALIGNMENT;\n\toffset += text_shdr->sh_size;\n\n\trela_shdr->sh_type = USERELA ? SHT_RELA : SHT_REL;\n\trela_shdr->sh_link = SEC_SYMS;\n\trela_shdr->sh_info = SEC_TEXT;\n\trela_shdr->sh_offset = offset;\n\trela_shdr->sh_size = csrel_n * sizeof(csrel[0]);\n\trela_shdr->sh_entsize = sizeof(csrel[0]);\n\toffset += rela_shdr->sh_size;\n\n\tsyms_shdr->sh_type = SHT_SYMTAB;\n\tsyms_shdr->sh_offset = offset;\n\tsyms_shdr->sh_size = syms_n * sizeof(syms[0]);\n\tsyms_shdr->sh_entsize = sizeof(syms[0]);\n\tsyms_shdr->sh_link = SEC_SYMSTR;\n\tsyms_shdr->sh_info = syms_sort();\n\toffset += syms_shdr->sh_size;\n\n\tdat_shdr->sh_type = SHT_PROGBITS;\n\tdat_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;\n\tdat_shdr->sh_offset = offset;\n\tdat_shdr->sh_size = dslen;\n\tdat_shdr->sh_entsize = 1;\n\tdat_shdr->sh_addralign = OUT_ALIGNMENT;\n\toffset += dat_shdr->sh_size;\n\n\tdatrel_shdr->sh_type = USERELA ? SHT_RELA : SHT_REL;\n\tdatrel_shdr->sh_offset = offset;\n\tdatrel_shdr->sh_size = dsrel_n * sizeof(dsrel[0]);\n\tdatrel_shdr->sh_entsize = sizeof(dsrel[0]);\n\tdatrel_shdr->sh_link = SEC_SYMS;\n\tdatrel_shdr->sh_info = SEC_DAT;\n\toffset += datrel_shdr->sh_size;\n\n\tbss_shdr->sh_type = SHT_NOBITS;\n\tbss_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;\n\tbss_shdr->sh_offset = offset;\n\tbss_shdr->sh_size = bss_len();\n\tbss_shdr->sh_entsize = 1;\n\tbss_shdr->sh_addralign = OUT_ALIGNMENT;\n\n\tsymstr_shdr->sh_type = SHT_STRTAB;\n\tsymstr_shdr->sh_offset = offset;\n\tsymstr_shdr->sh_size = symstr_n;\n\tsymstr_shdr->sh_entsize = 1;\n\toffset += symstr_shdr->sh_size;\n\n\twrite(fd, &ehdr, sizeof(ehdr));\n\twrite(fd, shdr,  NSECS * sizeof(shdr[0]));\n\twrite(fd, cs, cslen);\n\twrite(fd, csrel, csrel_n * sizeof(csrel[0]));\n\twrite(fd, syms, syms_n * sizeof(syms[0]));\n\twrite(fd, ds, dslen);\n\twrite(fd, dsrel, dsrel_n * sizeof(dsrel[0]));\n\twrite(fd, symstr, symstr_n);\n\n\tfree(syms);\n\tfree(symstr);\n\tfree(csrel);\n\tfree(dsrel);\n}\n\n/* architecture dependent functions */\n\n#ifdef NEATCC_ARM\nstatic void ehdr_init(Elf_Ehdr *ehdr)\n{\n\tehdr->e_machine = EM_ARM;\n\tehdr->e_flags = EF_ARM_EABI_VER4;\n}\n\nstatic int rel_type(int flags)\n{\n\tif (flags & OUT_RL24)\n\t\treturn R_ARM_PC24;\n\treturn flags & OUT_RLREL ? R_ARM_REL32 : R_ARM_ABS32;\n\n}\n#endif\n\n#ifdef NEATCC_X64\nstatic void ehdr_init(Elf_Ehdr *ehdr)\n{\n\tehdr->e_machine = EM_X86_64;\n}\n\nstatic int rel_type(int flags)\n{\n\tif (flags & OUT_RLREL)\n\t\treturn R_X86_64_PC32;\n\tif (flags & OUT_RL32)\n\t\treturn flags & OUT_RLSX ? R_X86_64_32S : R_X86_64_32;\n\treturn R_X86_64_64;\n}\n#endif\n\n#ifdef NEATCC_X86\nstatic void ehdr_init(Elf_Ehdr *ehdr)\n{\n\tehdr->e_machine = EM_386;\n}\n\nstatic int rel_type(int flags)\n{\n\treturn flags & OUT_RLREL ? R_386_PC32 : R_386_32;\n}\n#endif\n"
  },
  {
    "path": "reg.c",
    "content": "/* neatcc global register allocation */\n#include <stdio.h>\n#include <stdlib.h>\n#include \"ncc.h\"\n\n#define IC_LLD(ic, i)\t\t(O_C((ic)[i].op) == (O_LD | O_LOC) ? (ic)[i].a1 : -1)\n#define IC_LST(ic, i)\t\t(O_C((ic)[i].op) == (O_ST | O_LOC) ? (ic)[i].a2 : -1)\n\nstatic int ic_loc(struct ic *ic, long iv, long *loc, long *off)\n{\n\tlong oc = O_C(ic[iv].op);\n\tif (oc == (O_LD | O_LOC) || oc == (O_MOV | O_LOC)) {\n\t\t*loc = ic[iv].a1;\n\t\t*off = ic[iv].a2;\n\t\treturn 0;\n\t}\n\tif (oc == (O_ST | O_LOC)) {\n\t\t*loc = ic[iv].a2;\n\t\t*off = ic[iv].a3;\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n\n/* local live region */\nstruct rgn {\n\tlong loc;\t/* local number */\n\tlong beg;\t/* region start (instruction number) */\n\tlong end;\t/* region end */\n\tlong cnt;\t/* number of accesses */\n\tint reg;\t/* register allocated to this region */\n};\n\nstatic struct rgn *rgn;\t\t/* live regions */\nstatic int rgn_n;\t\t/* number of entries in rgn[] */\nstatic int rgn_sz;\t\t/* size of rgn[] */\n\nstatic int *loc_ptr;\t\t/* if the address of locals is accessed */\nstatic int loc_n;\t\t/* number of locals */\n\nstatic long *dst_head;\t\t/* lists of jumps to each instruction */\nstatic long *dst_next;\t\t/* next entries in dst_head[] lists */\n\nstatic void rgn_add(long loc, long beg, long end, long cnt)\n{\n\tint i;\n\tfor (i = 0; i < rgn_n; i++) {\n\t\tif (rgn[i].loc == loc && rgn[i].beg < end && rgn[i].end > beg) {\n\t\t\tif (beg > rgn[i].beg)\n\t\t\t\tbeg = rgn[i].beg;\n\t\t\tif (end < rgn[i].end)\n\t\t\t\tend = rgn[i].end;\n\t\t\tcnt += rgn[i].cnt;\n\t\t\trgn[i].loc = -1;\n\t\t}\n\t}\n\tfor (i = 0; i < rgn_n; i++)\n\t\tif (rgn[i].loc < 0)\n\t\t\tbreak;\n\tif (i == rgn_n) {\n\t\tif (rgn_n >= rgn_sz) {\n\t\t\trgn_sz = MAX(16, rgn_sz * 2);\n\t\t\trgn = mextend(rgn, rgn_n, rgn_sz, sizeof(rgn[0]));\n\t\t}\n\t\trgn_n++;\n\t}\n\trgn[i].loc = loc;\n\trgn[i].beg = beg;\n\trgn[i].end = end;\n\trgn[i].cnt = cnt;\n\trgn[i].reg = -1;\n}\n\n/* return nonzero if register reg is free from beg till end */\nstatic int rgn_available(long beg, long end, int reg)\n{\n\tint i;\n\tfor (i = 0; i < rgn_n; i++)\n\t\tif (rgn[i].reg == reg)\n\t\t\tif (rgn[i].beg < end && rgn[i].end > beg)\n\t\t\t\treturn 0;\n\treturn 1;\n}\n\nstatic long reg_region(struct ic *ic, long ic_n, long loc, long pos,\n\t\tlong *beg, long *end, char *mark)\n{\n\tlong cnt = 0;\n\tlong dst;\n\tfor (; pos >= 0; pos--) {\n\t\tif (pos < *beg)\n\t\t\t*beg = pos;\n\t\tif (pos + 1 > *end)\n\t\t\t*end = pos + 1;\n\t\tif (mark[pos])\n\t\t\tbreak;\n\t\tmark[pos] = 1;\n\t\tif (IC_LST(ic, pos) == loc)\n\t\t\tbreak;\n\t\tif (IC_LLD(ic, pos) == loc)\n\t\t\tcnt++;\n\t\tdst = dst_head[pos];\n\t\twhile (dst >= 0) {\n\t\t\tcnt += reg_region(ic, ic_n, loc, dst, beg, end, mark);\n\t\t\tdst = dst_next[dst];\n\t\t}\n\t\tif (pos > 0 && ic[pos - 1].op & O_JMP)\n\t\t\tbreak;\n\t}\n\treturn cnt;\n}\n\n/* compute local's live regions */\nstatic void reg_regions(struct ic *ic, long ic_n, long loc)\n{\n\tchar *mark;\n\tlong beg, end;\n\tlong cnt;\n\tlong i;\n\tmark = calloc(ic_n, sizeof(mark[0]));\n\tfor (i = 0; i < ic_n; i++) {\n\t\tif (IC_LLD(ic, i) == loc && !mark[i]) {\n\t\t\tbeg = i;\n\t\t\tend = i + 1;\n\t\t\tcnt = reg_region(ic, ic_n, loc, i, &beg, &end, mark);\n\t\t\trgn_add(loc, beg, end, cnt);\n\t\t}\n\t}\n\tfor (i = 0; i < ic_n; i++)\n\t\tif (IC_LST(ic, i) == loc && !mark[i])\n\t\t\trgn_add(loc, i, i + 1, 1);\n\tfree(mark);\n}\n\n/* number of times a local is accessed */\nstatic long reg_loccnt(struct ic *ic, long ic_n, long loc)\n{\n\tlong cnt = 0;\n\tlong i;\n\tfor (i = 0; i < ic_n; i++)\n\t\tif (IC_LLD(ic, i) == loc || IC_LST(ic, i) == loc)\n\t\t\tcnt++;\n\treturn cnt;\n}\n\n/* perform global register allocation */\nstatic void reg_glob(int leaf)\n{\n\tint *srt;\n\tint regs[N_REGS];\n\tint i, j;\n\tint regs_max = MIN(N_TMPS >> 1, 4);\n\tlong regs_mask = leaf ? R_TMPS : R_PERM;\n\tint regs_n = 0;\n\tfor (i = leaf ? 1 : 3; i < N_TMPS && regs_n < regs_max; i++)\n\t\tif ((1 << i) & regs_mask)\n\t\t\tregs[regs_n++] = i;\n\tsrt = malloc(rgn_n * sizeof(srt[0]));\n\t/* sorting locals */\n\tfor (i = 0; i < rgn_n; i++) {\n\t\tfor (j = i - 1; j >= 0 && rgn[i].cnt > rgn[srt[j]].cnt; j--)\n\t\t\tsrt[j + 1] = srt[j];\n\t\tsrt[j + 1] = i;\n\t}\n\t/* allocating registers */\n\tfor (i = 0; i < rgn_n; i++) {\n\t\tint r = srt[i];\n\t\tlong loc = rgn[r].loc;\n\t\tlong beg = rgn[r].beg;\n\t\tlong end = rgn[r].end;\n\t\tif (loc < 0 || loc_ptr[loc])\n\t\t\tcontinue;\n\t\tif (leaf && loc < N_ARGS && beg == 0 &&\n\t\t\t\trgn_available(beg, end, argregs[loc])) {\n\t\t\trgn[r].reg = argregs[loc];\n\t\t\tcontinue;\n\t\t}\n\t\tfor (j = 0; j < regs_n; j++)\n\t\t\tif (rgn_available(beg, end, regs[j]))\n\t\t\t\tbreak;\n\t\tif (j < regs_n)\n\t\t\trgn[r].reg = regs[j];\n\t}\n\tfree(srt);\n}\n\nvoid reg_init(struct ic *ic, long ic_n)\n{\n\tlong loc, off;\n\tint *loc_sz;\n\tint leaf = 1;\n\tlong i;\n\tfor (i = 0; i < ic_n; i++)\n\t\tif (ic[i].op & O_LOC && !ic_loc(ic, i, &loc, &off))\n\t\t\tif (loc + 1 >= loc_n)\n\t\t\t\tloc_n = loc + 1;\n\tloc_ptr = calloc(loc_n, sizeof(loc_ptr[0]));\n\tloc_sz = calloc(loc_n, sizeof(loc_sz[0]));\n\tfor (i = 0; i < loc_n; i++)\n\t\tloc_ptr[i] = !opt(1);\n\tfor (i = 0; i < ic_n; i++) {\n\t\tlong oc = O_C(ic[i].op);\n\t\tif (ic_loc(ic, i, &loc, &off))\n\t\t\tcontinue;\n\t\tif (oc == (O_LD | O_LOC) || oc == (O_ST | O_LOC)) {\n\t\t\tint sz = T_SZ(O_T(ic[i].op));\n\t\t\tif (!loc_sz[loc])\n\t\t\t\tloc_sz[loc] = sz;\n\t\t\tif (off || sz < 2 || sz != loc_sz[loc])\n\t\t\t\tloc_ptr[loc]++;\n\t\t}\n\t\tif (oc == (O_MOV | O_LOC))\n\t\t\tloc_ptr[loc]++;\n\t}\n\tfree(loc_sz);\n\tfor (i = 0; i < ic_n; i++)\n\t\tif (ic[i].op & O_CALL)\n\t\t\tleaf = 0;\n\tdst_head = malloc(ic_n * sizeof(dst_head[0]));\n\tdst_next = malloc(ic_n * sizeof(dst_next[0]));\n\tfor (i = 0; i < ic_n; i++)\n\t\tdst_head[i] = -1;\n\tfor (i = 0; i < ic_n; i++)\n\t\tdst_next[i] = -1;\n\tfor (i = 0; i < ic_n; i++) {\n\t\tif (ic[i].op & O_JXX) {\n\t\t\tdst_next[i] = dst_head[ic[i].a3];\n\t\t\tdst_head[ic[i].a3] = i;\n\t\t}\n\t}\n\tfor (i = 0; i < loc_n; i++) {\n\t\tif (!loc_ptr[i] && opt(2))\n\t\t\treg_regions(ic, ic_n, i);\n\t\tif (!loc_ptr[i] && !opt(2))\n\t\t\trgn_add(i, 0, ic_n, reg_loccnt(ic, ic_n, i));\n\t}\n\treg_glob(leaf);\n}\n\nlong reg_mask(void)\n{\n\tlong ret = 0;\n\tint i;\n\tfor (i = 0; i < rgn_n; i++)\n\t\tif (rgn[i].reg >= 0)\n\t\t\tret |= 1 << rgn[i].reg;\n\treturn ret;\n}\n\n/* return the allocated register of local loc */\nint reg_lmap(long c, long loc)\n{\n\tint i;\n\tfor (i = 0; i < rgn_n; i++)\n\t\tif (rgn[i].loc == loc)\n\t\t\tif (rgn[i].beg <= c && rgn[i].end > c)\n\t\t\t\treturn rgn[i].reg;\n\treturn -1;\n}\n\n/* return the local to which register reg is allocated */\nint reg_rmap(long c, long reg)\n{\n\tint i;\n\tfor (i = 0; i < rgn_n; i++)\n\t\tif (rgn[i].reg == reg)\n\t\t\tif (rgn[i].beg <= c && rgn[i].end > c)\n\t\t\t\treturn rgn[i].loc;\n\treturn -1;\n}\n\nvoid reg_done(void)\n{\n\tfree(dst_head);\n\tfree(dst_next);\n\tfree(loc_ptr);\n\tfree(rgn);\n\tloc_ptr = NULL;\n\trgn = NULL;\n\trgn_sz = 0;\n\trgn_n = 0;\n\tloc_n = 0;\n}\n\nint reg_safe(long loc)\n{\n\treturn loc < loc_n && !loc_ptr[loc];\n}\n"
  },
  {
    "path": "tok.c",
    "content": "/* neatcc tokenizer */\n#include <ctype.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include \"ncc.h\"\n\nstatic struct mem tok_mem;\t/* the data read via cpp_read() so far */\nstatic struct mem tok;\t\t/* the previous token */\nstatic char *buf;\nstatic long off, off_pre;\t/* current and previous positions */\nstatic long len;\nstatic int tok_set;\t\t/* the current token was read */\n\nstatic char *tok3[] = {\n\t\"<<=\", \">>=\", \"...\", \"<<\", \">>\", \"++\", \"--\", \"+=\", \"-=\", \"*=\", \"/=\",\n\t\"%=\", \"|=\", \"&=\", \"^=\", \"&&\", \"||\", \"==\", \"!=\", \"<=\", \">=\", \"->\"\n};\n\nstatic char *find_tok3(char *r)\n{\n\tint i;\n\tfor (i = 0; i < LEN(tok3); i++) {\n\t\tchar *s = tok3[i];\n\t\tif (s[0] == r[0] && s[1] == r[1] && (!s[2] || s[2] == r[2]))\n\t\t\treturn s;\n\t}\n\treturn NULL;\n}\n\nstatic char *esc_code = \"abefnrtv\";\nstatic char *esc = \"\\a\\b\\e\\f\\n\\r\\t\\v\";\nstatic char *digs = \"0123456789abcdef\";\n\nstatic int esc_char(int *c, char *s)\n{\n\tif (*s != '\\\\') {\n\t\t*c = (unsigned char) *s;\n\t\treturn 1;\n\t}\n\tif (strchr(esc_code, (unsigned char) s[1])) {\n\t\t*c = esc[strchr(esc_code, (unsigned char) s[1]) - esc_code];\n\t\treturn 2;\n\t}\n\tif (isdigit(s[1]) || s[1] == 'x') {\n\t\tint ret = 0;\n\t\tint base = 8;\n\t\tint i = 1;\n\t\tchar *d;\n\t\tif (s[1] == 'x') {\n\t\t\tbase = 16;\n\t\t\ti++;\n\t\t}\n\t\twhile ((d = memchr(digs, tolower(s[i]), base))) {\n\t\t\tret *= base;\n\t\t\tret += d - digs;\n\t\t\ti++;\n\t\t}\n\t\t*c = ret;\n\t\treturn i;\n\t}\n\t*c = (unsigned char) s[1];\n\treturn 2;\n}\n\nlong tok_num(char *tok, long *num)\n{\n\tint base = 10;\n\tlong num_bt = 4 | T_MSIGN;\n\tif (tok[0] == '0' && tolower(tok[1]) == 'x') {\n\t\tnum_bt &= ~T_MSIGN;\n\t\tbase = 16;\n\t\ttok += 2;\n\t}\n\tif (strchr(digs, tolower((unsigned char) tok[0]))) {\n\t\tlong result = 0;\n\t\tchar *c;\n\t\tif (base == 10 && tok[0] == '0')\n\t\t\tbase = 8;\n\t\twhile (tok[0] && (c = strchr(digs, tolower((unsigned char) tok[0])))) {\n\t\t\tresult *= base;\n\t\t\tresult += c - digs;\n\t\t\ttok++;\n\t\t}\n\t\t*num = result;\n\t\twhile (tok[0]) {\n\t\t\tint c = tolower((unsigned char) tok[0]);\n\t\t\tif (c != 'u' && c != 'l')\n\t\t\t\tbreak;\n\t\t\tif (c == 'u')\n\t\t\t\tnum_bt &= ~T_MSIGN;\n\t\t\tif (c == 'l')\n\t\t\t\tnum_bt = (num_bt & T_MSIGN) | LONGSZ;\n\t\t\ttok++;\n\t\t}\n\t\treturn num_bt;\n\t}\n\tif (tok[0] == '\\'') {\n\t\tint ret;\n\t\tesc_char(&ret, tok + 1);\n\t\t*num = ret;\n\t\treturn num_bt;\n\t}\n\treturn 0;\n}\n\nstatic int id_char(int c)\n{\n\treturn isalnum(c) || c == '_';\n}\n\nstatic int skipws(void)\n{\n\tlong clen;\n\tchar *cbuf;\n\twhile (1) {\n\t\tif (off == len) {\n\t\t\tclen = 0;\n\t\t\twhile (!clen)\n\t\t\t\tif (cpp_read(&cbuf, &clen))\n\t\t\t\t\treturn 1;\n\t\t\tmem_put(&tok_mem, cbuf, clen);\n\t\t\tbuf = mem_buf(&tok_mem);\n\t\t\tlen = mem_len(&tok_mem);\n\t\t}\n\t\twhile (off < len && isspace(buf[off]))\n\t\t\toff++;\n\t\tif (off == len)\n\t\t\tcontinue;\n\t\tif (buf[off] == '\\\\' && buf[off + 1] == '\\n') {\n\t\t\toff += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tif (buf[off] == '/' && buf[off + 1] == '/') {\n\t\t\twhile (++off < len && buf[off] != '\\n')\n\t\t\t\tif (buf[off] == '\\\\')\n\t\t\t\t\toff++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (buf[off] == '/' && buf[off + 1] == '*') {\n\t\t\twhile (++off < len) {\n\t\t\t\tif (buf[off] == '*' && buf[off + 1] == '/') {\n\t\t\t\t\toff += 2;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\treturn 0;\n}\n\nstatic int tok_read(void)\n{\n\tchar *t3;\n\tint c;\n\toff_pre = off;\n\tmem_cut(&tok, 0);\n\tif (skipws())\n\t\treturn 1;\n\tif (buf[off] == '\"') {\n\t\tmem_putc(&tok, '\"');\n\t\twhile (buf[off] == '\"') {\n\t\t\toff++;\n\t\t\twhile (off < len && buf[off] != '\"') {\n\t\t\t\tif (buf[off] == '\\\\') {\n\t\t\t\t\toff += esc_char(&c, buf + off);\n\t\t\t\t\tmem_putc(&tok, c);\n\t\t\t\t} else {\n\t\t\t\t\tmem_putc(&tok, (unsigned char) buf[off++]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (off >= len || buf[off++] != '\"')\n\t\t\t\treturn 1;\n\t\t\tif (skipws())\n\t\t\t\treturn 1;\n\t\t}\n\t\tmem_putc(&tok, '\"');\n\t\treturn 0;\n\t}\n\tif (isdigit((unsigned char) buf[off])) {\n\t\tif (buf[off] == '0' && (buf[off + 1] == 'x' || buf[off + 1] == 'X')) {\n\t\t\tmem_putc(&tok, (unsigned char) buf[off++]);\n\t\t\tmem_putc(&tok, (unsigned char) buf[off++]);\n\t\t}\n\t\twhile (off < len && strchr(digs, tolower((unsigned char) buf[off])))\n\t\t\tmem_putc(&tok, (unsigned char) buf[off++]);\n\t\twhile (off < len && strchr(\"uUlL\", (unsigned char) buf[off]))\n\t\t\tmem_putc(&tok, (unsigned char) buf[off++]);\n\t\treturn 0;\n\t}\n\tif (buf[off] == '\\'') {\n\t\tint c, i;\n\t\tint n = esc_char(&c, buf + off + 1) + 1 + 1;\n\t\tfor (i = 0; i < n; i++)\n\t\t\tmem_putc(&tok, (unsigned char) buf[off++]);\n\t\treturn 0;\n\t}\n\tif (id_char((unsigned char) buf[off])) {\n\t\twhile (off < len && id_char((unsigned char) buf[off]))\n\t\t\tmem_putc(&tok, (unsigned char) buf[off++]);\n\t\treturn 0;\n\t}\n\tif (off + 2 <= len && (t3 = find_tok3(buf + off))) {\n\t\toff += strlen(t3);\n\t\tmem_put(&tok, t3, strlen(t3));\n\t\treturn 0;\n\t}\n\tif (strchr(\";,{}()[]<>*&!=+-/%?:|^~.\", (unsigned char) buf[off])) {\n\t\tmem_putc(&tok, (unsigned char) buf[off++]);\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n\nchar *tok_get(void)\n{\n\tif (!tok_set)\n\t\tif (tok_read())\n\t\t\treturn \"\";\n\ttok_set = 0;\n\treturn mem_buf(&tok);\n}\n\nchar *tok_see(void)\n{\n\tif (!tok_set)\n\t\tif (tok_read())\n\t\t\treturn \"\";\n\ttok_set = 1;\n\treturn mem_buf(&tok);\n}\n\nlong tok_len(void)\n{\n\treturn mem_len(&tok);\n}\n\nlong tok_addr(void)\n{\n\treturn tok_set ? off_pre : off;\n}\n\nvoid tok_jump(long addr)\n{\n\toff = addr;\n\toff_pre = -1;\n\ttok_set = 0;\n}\n\nvoid tok_done(void)\n{\n\tmem_done(&tok);\n\tmem_done(&tok_mem);\n}\n"
  },
  {
    "path": "x64.c",
    "content": "/* architecture-dependent code generation for x86_64 */\n#include <stdlib.h>\n#include \"ncc.h\"\n\n/* x86-64 registers, without r8-r15 */\n#define R_RAX\t\t0x00\n#define R_RCX\t\t0x01\n#define R_RDX\t\t0x02\n#define R_RBX\t\t0x03\n#define R_RSP\t\t0x04\n#define R_RBP\t\t0x05\n#define R_RSI\t\t0x06\n#define R_RDI\t\t0x07\n\n#define REG_RET\t\tR_RAX\n\n/* x86 opcodes */\n#define I_MOV\t\t0x89\n#define I_MOVI\t\t0xc7\n#define I_MOVIR\t\t0xb8\n#define I_MOVR\t\t0x8b\n#define I_MOVSXD\t0x63\n#define I_SHX\t\t0xd3\n#define I_CMP\t\t0x3b\n#define I_TST\t\t0x85\n#define I_LEA\t\t0x8d\n#define I_NOT\t\t0xf7\n#define I_CALL\t\t0xff\n#define I_MUL\t\t0xf7\n#define I_XOR\t\t0x33\n#define I_CQO\t\t0x99\n#define I_PUSH\t\t0x50\n#define I_POP\t\t0x58\n\n#define MIN(a, b)\t\t((a) < (b) ? (a) : (b))\n#define ALIGN(x, a)\t\t(((x) + (a) - 1) & ~((a) - 1))\n\nint tmpregs[] = {0, 7, 6, 2, 1, 8, 9, 10, 11, 3, 12, 13, 14, 15};\nint argregs[] = {7, 6, 2, 1, 8, 9};\n\n#define OP2(o2, o1)\t\t(0x010000 | ((o2) << 8) | (o1))\n#define O2(op)\t\t\t(((op) >> 8) & 0xff)\n#define O1(op)\t\t\t((op) & 0xff)\n#define MODRM(m, r1, r2)\t((m) << 6 | (r1) << 3 | (r2))\n#define REX(r1, r2)\t\t(0x48 | (((r1) & 8) >> 1) | (((r2) & 8) >> 3))\n\nstatic struct mem cs;\t\t/* generated code */\n\n/* code generation functions */\nstatic void os(void *s, int n)\n{\n\tmem_put(&cs, s, n);\n}\n\nstatic char *ointbuf(long n, int l)\n{\n\tstatic char buf[16];\n\tint i;\n\tfor (i = 0; i < l; i++) {\n\t\tbuf[i] = n & 0xff;\n\t\tn >>= 8;\n\t}\n\treturn buf;\n}\n\nstatic void oi(long n, int l)\n{\n\tmem_put(&cs, ointbuf(n, l), l);\n}\n\nstatic void oi_at(long pos, long n, int l)\n{\n\tmem_cpy(&cs, pos, ointbuf(n, l), l);\n}\n\nstatic long opos(void)\n{\n\treturn mem_len(&cs);\n}\n\nstatic void op_x(int op, int r1, int r2, int bt)\n{\n\tint sz = T_SZ(bt);\n\tint rex = 0;\n\tif (sz == 8)\n\t\trex |= 8;\n\tif (sz == 1)\n\t\trex |= 0x40;\n\tif (r1 & 0x8)\n\t\trex |= 4;\n\tif (r2 & 0x8)\n\t\trex |= 1;\n\tif (sz == 2)\n\t\toi(0x66, 1);\n\tif (rex)\n\t\toi(rex | 0x40, 1);\n\tif (op & 0x10000)\n\t\toi(O2(op), 1);\n\toi(sz == 1 ? O1(op) & ~0x1 : O1(op), 1);\n}\n\n#define op_mr\t\top_rm\n\n/* op_*(): r=reg, m=mem, i=imm, s=sym */\nstatic void op_rm(int op, int src, int base, int off, int bt)\n{\n\tint dis = off == (char) off ? 1 : 4;\n\tint mod = dis == 4 ? 2 : 1;\n\tif (!off && (base & 7) != R_RBP)\n\t\tmod = 0;\n\top_x(op, src, base, bt);\n\toi(MODRM(mod, src & 0x07, base & 0x07), 1);\n\tif ((base & 7) == R_RSP)\n\t\toi(0x24, 1);\n\tif (mod)\n\t\toi(off, dis);\n}\n\nstatic void op_rr(int op, int src, int dst, int bt)\n{\n\top_x(op, src, dst, bt);\n\toi(MODRM(3, src & 0x07, dst & 0x07), 1);\n}\n\n#define movrx_bt(bt)\t\t(((bt) == 4) ? 4 : LONGSZ)\n\nstatic int movrx_op(int bt, int mov)\n{\n\tint sz = T_SZ(bt);\n\tif (sz == 4)\n\t\treturn bt & T_MSIGN ? I_MOVSXD : mov;\n\tif (sz == 2)\n\t\treturn OP2(0x0f, bt & T_MSIGN ? 0xbf : 0xb7);\n\tif (sz == 1)\n\t\treturn OP2(0x0f, bt & T_MSIGN ? 0xbe : 0xb6);\n\treturn mov;\n}\n\nstatic void mov_r2r(int rd, int r1, unsigned bt)\n{\n\tif (rd != r1 || T_SZ(bt) != LONGSZ)\n\t\top_rr(movrx_op(bt, I_MOVR), rd, r1, movrx_bt(bt));\n}\n\nstatic void i_push(int reg)\n{\n\top_x(I_PUSH | (reg & 0x7), 0, reg, LONGSZ);\n}\n\nstatic void i_pop(int reg)\n{\n\top_x(I_POP | (reg & 0x7), 0, reg, LONGSZ);\n}\n\nvoid i_mov(int rd, int rn)\n{\n\top_rr(movrx_op(LONGSZ, I_MOVR), rd, rn, movrx_bt(LONGSZ));\n}\n\nstatic void i_add(int op, int rd, int r1, int r2)\n{\n\t/* opcode for O_ADD, O_SUB, O_AND, O_OR, O_XOR */\n\tstatic int rx[] = {0003, 0053, 0043, 0013, 0063};\n\top_rr(rx[op & 0x0f], rd, r2, LONGSZ);\n}\n\nstatic void i_add_imm(int op, int rd, int rn, long n)\n{\n\t/* opcode for O_ADD, O_SUB, O_AND, O_OR, O_XOR */\n\tstatic int rx[] = {0xc0, 0xe8, 0xe0, 0xc8, 0xf0};\n\tunsigned char s[4] = {REX(0, rd), 0x83, rx[op & 0x0f] | (rd & 7), n & 0xff};\n\tos((void *) s, 4);\n}\n\nstatic void i_num(int rd, long n)\n{\n\tif (!n) {\n\t\top_rr(I_XOR, rd, rd, 4);\n\t\treturn;\n\t}\n\tif (n < 0 && -n <= 0xffffffff) {\n\t\top_rr(I_MOVI, 0, rd, LONGSZ);\n\t\toi(n, 4);\n\t} else {\n\t\tint len = 8;\n\t\tif (n > 0 && n <= 0xffffffff)\n\t\t\tlen = 4;\n\t\top_x(I_MOVIR + (rd & 7), 0, rd, len);\n\t\toi(n, len);\n\t}\n}\n\nstatic void i_mul(int rd, int r1, int r2)\n{\n\tif (r2 != R_RDX)\n\t\ti_num(R_RDX, 0);\n\top_rr(I_MUL, 4, r2, LONGSZ);\n}\n\nstatic void i_div(int op, int rd, int r1, int r2)\n{\n\tlong bt = O_T(op);\n\tif (r2 != R_RDX) {\n\t\tif (bt & T_MSIGN)\n\t\t\top_x(I_CQO, R_RAX, R_RDX, LONGSZ);\n\t\telse\n\t\t\ti_num(R_RDX, 0);\n\t}\n\top_rr(I_MUL, bt & T_MSIGN ? 7 : 6, r2, LONGSZ);\n}\n\nstatic void i_tst(int rn, int rm)\n{\n\top_rr(I_TST, rn, rm, LONGSZ);\n}\n\nstatic void i_cmp(int rn, int rm)\n{\n\top_rr(I_CMP, rn, rm, LONGSZ);\n}\n\nstatic void i_cmp_imm(int rn, long n)\n{\n\tunsigned char s[4] = {REX(0, rn), 0x83, 0xf8 | rn, n & 0xff};\n\tos(s, 4);\n}\n\nstatic void i_shl(int op, int rd, int r1, int rs)\n{\n\tlong bt = O_T(op);\n\tint sm = 4;\n\tif ((op & 0x0f) == 1)\n\t\tsm = bt & T_MSIGN ? 7 : 5;\n\top_rr(I_SHX, sm, rd, LONGSZ);\n}\n\nstatic void i_shl_imm(int op, int rd, int rn, long n)\n{\n\tlong bt = O_T(op);\n\tint sm = (op & 0x1) ? (bt & T_MSIGN ? 0xf8 : 0xe8) : 0xe0;\n\tchar s[4] = {REX(0, rn), 0xc1, sm | (rn & 7), n & 0xff};\n\tos(s, 4);\n}\n\nstatic void i_neg(int rd)\n{\n\top_rr(I_NOT, 3, rd, LONGSZ);\n}\n\nstatic void i_not(int rd)\n{\n\top_rr(I_NOT, 2, rd, LONGSZ);\n}\n\nstatic int i_cond(long op)\n{\n\t/* lt, ge, eq, ne, le, gt */\n\tstatic int ucond[] = {0x92, 0x93, 0x94, 0x95, 0x96, 0x97};\n\tstatic int scond[] = {0x9c, 0x9d, 0x94, 0x95, 0x9e, 0x9f};\n\tlong bt = O_T(op);\n\treturn bt & T_MSIGN ? scond[op & 0x0f] : ucond[op & 0x0f];\n}\n\nstatic void i_set(long op, int rd)\n{\n\tchar set[] = \"\\x0f\\x00\\xc0\";\n\tset[1] = i_cond(op);\n\tos(set, 3);\t\t\t/* setl al */\n\tos(\"\\x48\\x0f\\xb6\\xc0\", 4);\t/* movzx rax, al */\n}\n\nstatic void i_lnot(int rd)\n{\n\tchar cmp[] = \"\\x00\\x83\\xf8\\x00\";\n\tcmp[0] = REX(0, rd);\n\tcmp[2] |= rd & 7;\n\tos(cmp, 4);\t\t/* cmp rax, 0 */\n\ti_set(O_EQ, rd);\n}\n\nstatic void jx(int x, int nbytes)\n{\n\tchar op[2] = {0x0f};\n\tif (nbytes == 1) {\n\t\top[0] = 0x70 | (x & 0x0f);\n\t\tos(op, 1);\t\t/* jx $addr */\n\t} else {\n\t\top[1] = x;\n\t\tos(op, 2);\t\t/* jx $addr */\n\t}\n}\n\n/* generate cmp or tst before a conditional jump */\nstatic void i_jcmp(long op, long rn, long rm)\n{\n\tif (op & O_JZ)\n\t\ti_tst(rn, rn);\n\tif (op & O_JCC) {\n\t\tif (op & O_NUM)\n\t\t\ti_cmp_imm(rn, rm);\n\t\telse\n\t\t\ti_cmp(rn, rm);\n\t}\n}\n\n/* generate a jump instruction and return the of its displacement */\nstatic long i_jmp(long op, int nb)\n{\n\tif (op & O_JZ)\n\t\tjx(O_C(op) == O_JZ ? 0x84 : 0x85, nb);\n\telse if (op & O_JCC)\n\t\tjx(i_cond(op) & ~0x10, nb);\n\telse\n\t\tos(nb == 1 ? \"\\xeb\" : \"\\xe9\", 1);\n\toi(0, nb);\n\treturn opos() - nb;\n}\n\n/* the length of a jump instruction opcode */\nstatic int i_jlen(long op, int nb)\n{\n\tif (op & (O_JZ | O_JCC))\n\t\treturn nb ? 2 : 1;\n\treturn 1;\n}\n\n/* zero extend */\nstatic void i_zx(int rd, int r1, int bits)\n{\n\tif (bits & 0x07) {\n\t\ti_shl_imm(O_SHL, rd, rd, LONGSZ * 8 - bits);\n\t\ti_shl_imm(O_SHR, rd, rd, LONGSZ * 8 - bits);\n\t} else {\n\t\tmov_r2r(rd, r1, bits >> 3);\n\t}\n}\n\n/* sign extend */\nstatic void i_sx(int rd, int r1, int bits)\n{\n\tmov_r2r(rd, r1, T_MSIGN | (bits >> 3));\n}\n\nstatic void i_cast(int rd, int rn, int bt)\n{\n\tif (T_SZ(bt) == 8) {\n\t\tif (rd != rn)\n\t\t\ti_mov(rd, rn);\n\t} else {\n\t\tif (bt & T_MSIGN)\n\t\t\ti_sx(rd, rn, T_SZ(bt) * 8);\n\t\telse\n\t\t\ti_zx(rd, rn, T_SZ(bt) * 8);\n\t}\n}\n\nstatic void i_add_anyimm(int rd, int rn, long n)\n{\n\top_rm(I_LEA, rd, rn, n, LONGSZ);\n}\n\nstatic long *rel_sym;\t\t/* relocation symbols */\nstatic long *rel_flg;\t\t/* relocation flags */\nstatic long *rel_off;\t\t/* relocation offsets */\nstatic long rel_n, rel_sz;\t/* relocation count */\n\nstatic long lab_sz;\t\t/* label count */\nstatic long *lab_loc;\t\t/* label offsets in cs */\nstatic long jmp_n, jmp_sz;\t/* jump count */\nstatic long *jmp_off;\t\t/* jump offsets */\nstatic long *jmp_dst;\t\t/* jump destinations */\nstatic long *jmp_op;\t\t/* jump opcode */\nstatic long jmp_ret;\t\t/* the position of the last return jmp */\n\nstatic void lab_add(long id)\n{\n\twhile (id >= lab_sz) {\n\t\tint lab_n = lab_sz;\n\t\tlab_sz = MAX(128, lab_sz * 2);\n\t\tlab_loc = mextend(lab_loc, lab_n, lab_sz, sizeof(*lab_loc));\n\t}\n\tlab_loc[id] = opos();\n}\n\nstatic void jmp_add(long op, long off, long dst)\n{\n\tif (jmp_n == jmp_sz) {\n\t\tjmp_sz = MAX(128, jmp_sz * 2);\n\t\tjmp_off = mextend(jmp_off, jmp_n, jmp_sz, sizeof(*jmp_off));\n\t\tjmp_dst = mextend(jmp_dst, jmp_n, jmp_sz, sizeof(*jmp_dst));\n\t\tjmp_op = mextend(jmp_op, jmp_n, jmp_sz, sizeof(*jmp_op));\n\t}\n\tjmp_off[jmp_n] = off;\n\tjmp_dst[jmp_n] = dst;\n\tjmp_op[jmp_n] = op;\n\tjmp_n++;\n}\n\nvoid i_label(long id)\n{\n\tlab_add(id + 1);\n}\n\nstatic void i_rel(long sym, long flg, long off)\n{\n\tif (rel_n == rel_sz) {\n\t\trel_sz = MAX(128, rel_sz * 2);\n\t\trel_sym = mextend(rel_sym, rel_n, rel_sz, sizeof(*rel_sym));\n\t\trel_flg = mextend(rel_flg, rel_n, rel_sz, sizeof(*rel_flg));\n\t\trel_off = mextend(rel_off, rel_n, rel_sz, sizeof(*rel_off));\n\t}\n\trel_sym[rel_n] = sym;\n\trel_flg[rel_n] = flg;\n\trel_off[rel_n] = off;\n\trel_n++;\n}\n\nstatic void i_sym(int rd, int sym, int off)\n{\n\tint sz = X64_ABS_RL & OUT_RL32 ? 4 : LONGSZ;\n\tif (X64_ABS_RL & OUT_RLSX)\n\t\top_rr(I_MOVI, 0, rd, sz);\n\telse\n\t\top_x(I_MOVIR + (rd & 7), 0, rd, sz);\n\ti_rel(sym, OUT_CS | X64_ABS_RL, opos());\n\toi(off, sz);\n}\n\nstatic void i_saveargs(long sargs)\n{\n\tint i;\n\tos(\"\\x58\", 1);\t\t/* pop rax */\n\tfor (i = N_ARGS - 1; i >= 0; i--)\n\t\tif ((1 << argregs[i]) & sargs)\n\t\t\ti_push(argregs[i]);\n\tos(\"\\x50\", 1);\t\t/* push rax */\n}\n\nstatic void i_subsp(long val)\n{\n\tif (!val)\n\t\treturn;\n\tif (val <= 127 && val >= -128) {\n\t\tos(\"\\x48\\x83\\xec\", 3);\n\t\toi(val, 1);\n\t} else {\n\t\tos(\"\\x48\\x81\\xec\", 3);\n\t\toi(val, 4);\n\t}\n}\n\nstatic int regs_count(long regs)\n{\n\tint cnt = 0;\n\tint i;\n\tfor (i = 0; i < N_REGS; i++)\n\t\tif (((1 << i) & R_TMPS) & regs)\n\t\t\tcnt++;\n\treturn cnt;\n}\n\nstatic void regs_save(long sregs, long dis)\n{\n\tint i;\n\tfor (i = 0; i < N_REGS; i++)\n\t\tif (((1 << i) & R_TMPS) & sregs)\n\t\t\ti_push(i);\n\tif (dis)\n\t\ti_subsp(dis);\n}\n\nstatic void regs_load(long sregs, long dis)\n{\n\tint i;\n\tif (dis)\n\t\ti_subsp(-dis);\n\tfor (i = N_REGS - 1; i >= 0; --i)\n\t\tif (((1 << i) & R_TMPS) & sregs)\n\t\t\ti_pop(i);\n}\n\nvoid i_wrap(int argc, long sargs, long spsub, int initfp, long sregs, long sregs_pos)\n{\n\tlong body_n;\n\tvoid *body;\n\tlong diff;\t\t/* prologue length */\n\tint nsargs = 0;\t\t/* number of saved arguments */\n\tint mod16;\t\t/* 16-byte alignment */\n\tint i;\n\t/* removing the last jmp to the epilogue */\n\tif (jmp_ret + i_jlen(O_JMP, 4) + 4 == opos()) {\n\t\tmem_cut(&cs, jmp_ret);\n\t\tjmp_n--;\n\t}\n\tlab_add(0);\t\t\t\t/* the return label */\n\tbody_n = mem_len(&cs);\n\tbody = mem_get(&cs);\n\t/* generating function prologue */\n\tif (sargs)\n\t\ti_saveargs(sargs);\n\tif (initfp) {\n\t\tos(\"\\x55\", 1);\t\t\t/* push rbp */\n\t\tos(\"\\x48\\x89\\xe5\", 3);\t\t/* mov rbp, rsp */\n\t}\n\tfor (i = 0; i < N_ARGS; i++)\n\t\tif ((1 << argregs[i]) & sargs)\n\t\t\tnsargs++;\n\tmod16 = (spsub + nsargs * LONGSZ) % 16;\t/* forcing 16-byte alignment */\n\tif (spsub) {\n\t\tspsub = spsub + (16 - mod16);\n\t\ti_subsp(sregs ? -sregs_pos - regs_count(sregs) * ULNG : spsub);\n\t}\n\tif (sregs)\t\t/* saving registers */\n\t\tregs_save(sregs, spsub + sregs_pos);\n\tdiff = mem_len(&cs);\n\tmem_put(&cs, body, body_n);\n\tfree(body);\n\t/* generating function epilogue */\n\tif (sregs)\t\t/* restoring saved registers */\n\t\tregs_load(sregs, spsub + sregs_pos);\n\tif (initfp)\n\t\tos(\"\\xc9\", 1);\t\t\t/* leave */\n\tif (sargs) {\n\t\tos(\"\\xc2\", 1);\t\t\t/* ret n */\n\t\toi(nsargs * LONGSZ, 2);\n\t} else {\n\t\tos(\"\\xc3\", 1);\t\t\t/* ret */\n\t}\n\t/* adjusting code offsets */\n\tfor (i = 0; i < rel_n; i++)\n\t\trel_off[i] += diff;\n\tfor (i = 0; i < jmp_n; i++)\n\t\tjmp_off[i] += diff;\n\tfor (i = 0; i < lab_sz; i++)\n\t\tlab_loc[i] += diff;\n}\n\n/* introduce shorter jumps, if possible */\nstatic void i_shortjumps(int *nb)\n{\n\tlong off = 0;\t/* current code offset */\n\tlong dif = 0;\t/* the difference after changing jump instructions */\n\tint rel = 0;\t/* current relocation */\n\tint lab = 1;\t/* current label */\n\tlong c_len = mem_len(&cs);\n\tchar *c = mem_get(&cs);\n\tint i;\n\tfor (i = 0; i < jmp_n; i++)\n\t\tnb[i] = abs(lab_loc[jmp_dst[i]] - jmp_off[i]) < 0x70 ? 1 : 4;\n\tfor (i = 0; i < jmp_n; i++) {\n\t\tlong cur = jmp_off[i] - i_jlen(jmp_op[i], 4);\n\t\twhile (rel < rel_n && rel_off[rel] <= cur)\n\t\t\trel_off[rel++] += dif;\n\t\twhile (lab < lab_sz && lab_loc[lab] <= cur)\n\t\t\tlab_loc[lab++] += dif;\n\t\tmem_put(&cs, c + off, cur - off);\n\t\tjmp_off[i] = i_jmp(jmp_op[i], nb[i]);\n\t\toff = cur + i_jlen(jmp_op[i], 4) + 4;\n\t\tdif = mem_len(&cs) - off;\n\t}\n\twhile (rel < rel_n)\n\t\trel_off[rel++] += dif;\n\twhile (lab < lab_sz)\n\t\tlab_loc[lab++] += dif;\n\tlab_loc[0] += dif;\n\tmem_put(&cs, c + off, c_len - off);\n\tfree(c);\n}\n\nvoid i_code(char **c, long *c_len, long **rsym, long **rflg, long **roff, long *rcnt)\n{\n\tint *nb;\t/* number of bytes necessary for jump displacements */\n\tint i;\n\t/* more compact jmp instructions */\n\tnb = malloc(jmp_n * sizeof(nb[0]));\n\tfor (i = 0; i < jmp_n; i++)\n\t\tnb[i] = 4;\n\ti_shortjumps(nb);\n\tfor (i = 0; i < jmp_n; i++)\t/* filling jmp destinations */\n\t\toi_at(jmp_off[i], lab_loc[jmp_dst[i]] -\n\t\t\t\tjmp_off[i] - nb[i], nb[i]);\n\tfree(nb);\n\t*c_len = mem_len(&cs);\n\t*c = mem_get(&cs);\n\t*rsym = rel_sym;\n\t*rflg = rel_flg;\n\t*roff = rel_off;\n\t*rcnt = rel_n;\n\trel_sym = NULL;\n\trel_flg = NULL;\n\trel_off = NULL;\n\trel_n = 0;\n\trel_sz = 0;\n\tjmp_n = 0;\n}\n\nvoid i_done(void)\n{\n\tfree(jmp_off);\n\tfree(jmp_dst);\n\tfree(jmp_op);\n\tfree(lab_loc);\n}\n\nlong i_reg(long op, long *rd, long *r1, long *r2, long *r3, long *tmp)\n{\n\tint oc = O_C(op);\n\t*rd = 0;\n\t*r1 = 0;\n\t*r2 = 0;\n\t*r3 = 0;\n\t*tmp = 0;\n\tif (oc & O_MOV) {\n\t\t*rd = R_TMPS;\n\t\t*r1 = oc & (O_NUM | O_SYM) ? 32 : R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc & O_ADD) {\n\t\t*r1 = R_TMPS;\n\t\t*r2 = oc & O_NUM ? (oc == O_ADD ? 32 : 8) : R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc & O_SHL) {\n\t\tif (oc & O_NUM) {\n\t\t\t*r1 = R_TMPS;\n\t\t\t*r2 = 8;\n\t\t} else {\n\t\t\t*r2 = 1 << R_RCX;\n\t\t\t*r1 = R_TMPS & ~*r2;\n\t\t}\n\t\treturn 0;\n\t}\n\tif (oc & O_MUL) {\n\t\tif (oc & O_NUM)\n\t\t\treturn 1;\n\t\t*rd = oc == O_MOD ? (1 << R_RDX) : (1 << R_RAX);\n\t\t*r1 = (1 << R_RAX);\n\t\t*r2 = R_TMPS & ~*rd & ~*r1;\n\t\tif (oc == O_DIV)\n\t\t\t*r2 &= ~(1 << R_RDX);\n\t\t*tmp = (1 << R_RDX) | (1 << R_RAX);\n\t\treturn 0;\n\t}\n\tif (oc & O_CMP) {\n\t\t*rd = 1 << R_RAX;\n\t\t*r1 = R_TMPS;\n\t\t*r2 = oc & O_NUM ? 8 : R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc & O_UOP) {\n\t\tif (oc == O_LNOT)\n\t\t\t*r1 = 1 << R_RAX;\n\t\telse\n\t\t\t*r1 = R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc == O_MSET) {\n\t\t*r1 = 1 << R_RDI;\n\t\t*r2 = 1 << R_RAX;\n\t\t*r3 = 1 << R_RCX;\n\t\t*tmp = (1 << R_RDI) | (1 << R_RCX);\n\t\treturn 0;\n\t}\n\tif (oc == O_MCPY) {\n\t\t*r1 = 1 << R_RDI;\n\t\t*r2 = 1 << R_RSI;\n\t\t*r3 = 1 << R_RCX;\n\t\t*tmp = (1 << R_RDI) | (1 << R_RSI) | (1 << R_RCX);\n\t\treturn 0;\n\t}\n\tif (oc == O_RET) {\n\t\t*r1 = (1 << REG_RET);\n\t\treturn 0;\n\t}\n\tif (oc & O_CALL) {\n\t\t*rd = (1 << REG_RET);\n\t\t*r1 = oc & O_SYM ? 0 : R_TMPS;\n\t\t*tmp = R_TMPS & ~R_PERM;\n\t\treturn 0;\n\t}\n\tif (oc & O_LD) {\n\t\t*rd = R_TMPS;\n\t\t*r1 = R_TMPS;\n\t\t*r2 = oc & O_NUM ? 32 : R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc & O_ST) {\n\t\t*r1 = R_TMPS;\n\t\t*r2 = R_TMPS;\n\t\t*r3 = oc & O_NUM ? 32 : R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc & O_JZ) {\n\t\t*r1 = R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc & O_JCC) {\n\t\t*r1 = R_TMPS;\n\t\t*r2 = oc & O_NUM ? 8 : R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc == O_JMP)\n\t\treturn 0;\n\treturn 1;\n}\n\nint i_imm(long lim, long n)\n{\n\tlong max = (1 << (lim - 1)) - 1;\n\treturn n <= max && n + 1 >= -max;\n}\n\nlong i_ins(long op, long rd, long r1, long r2, long r3)\n{\n\tlong oc = O_C(op);\n\tlong bt = O_T(op);\n\tif (oc & O_ADD) {\n\t\tif (oc & O_NUM) {\n\t\t\tif (rd == r1 && r2 <= 127 && r2 >= -128)\n\t\t\t\ti_add_imm(op, r1, r1, r2);\n\t\t\telse\n\t\t\t\ti_add_anyimm(rd, r1, r2);\n\t\t} else {\n\t\t\ti_add(op, r1, r1, r2);\n\t\t}\n\t}\n\tif (oc & O_SHL) {\n\t\tif (oc & O_NUM)\n\t\t\ti_shl_imm(op, r1, r1, r2);\n\t\telse\n\t\t\ti_shl(op, r1, r1, r2);\n\t}\n\tif (oc & O_MUL) {\n\t\tif (oc == O_MUL)\n\t\t\ti_mul(R_RAX, r1, r2);\n\t\tif (oc == O_DIV)\n\t\t\ti_div(op, R_RAX, r1, r2);\n\t\tif (oc == O_MOD)\n\t\t\ti_div(op, R_RDX, r1, r2);\n\t\treturn 0;\n\t}\n\tif (oc & O_CMP) {\n\t\tif (oc & O_NUM)\n\t\t\ti_cmp_imm(r1, r2);\n\t\telse\n\t\t\ti_cmp(r1, r2);\n\t\ti_set(op, rd);\n\t\treturn 0;\n\t}\n\tif (oc & O_UOP) {\t/* uop */\n\t\tif (oc == O_NEG)\n\t\t\ti_neg(r1);\n\t\tif (oc == O_NOT)\n\t\t\ti_not(r1);\n\t\tif (oc == O_LNOT)\n\t\t\ti_lnot(r1);\n\t\treturn 0;\n\t}\n\tif (oc == O_CALL) {\n\t\top_rr(I_CALL, 2, r1, LONGSZ);\n\t\treturn 0;\n\t}\n\tif (oc == (O_CALL | O_SYM)) {\n\t\tos(\"\\xe8\", 1);\t\t/* call $x */\n\t\ti_rel(r1, OUT_CS | OUT_RLREL, opos());\n\t\toi(-4 + r2, 4);\n\t\treturn 0;\n\t}\n\tif (oc == (O_MOV | O_SYM)) {\n\t\ti_sym(rd, r1, r2);\n\t\treturn 0;\n\t}\n\tif (oc == (O_MOV | O_NUM)) {\n\t\ti_num(rd, r1);\n\t\treturn 0;\n\t}\n\tif (oc == O_MSET) {\n\t\tos(\"\\xfc\\xf3\\xaa\", 3);\t\t/* cld; rep stosb */\n\t\treturn 0;\n\t}\n\tif (oc == O_MCPY) {\n\t\tos(\"\\xfc\\xf3\\xa4\", 3);\t\t/* cld; rep movs */\n\t\treturn 0;\n\t}\n\tif (oc == O_RET) {\n\t\tjmp_ret = opos();\n\t\tjmp_add(O_JMP, i_jmp(op, 4), 0);\n\t\treturn 0;\n\t}\n\tif (oc == (O_LD | O_NUM)) {\n\t\top_rm(movrx_op(bt, I_MOVR), rd, r1, r2, movrx_bt(bt));\n\t\treturn 0;\n\t}\n\tif (oc == (O_ST | O_NUM)) {\n\t\top_rm(I_MOV, r1, r2, r3, bt);\n\t\treturn 0;\n\t}\n\tif (oc == O_MOV) {\n\t\ti_cast(rd, r1, bt);\n\t\treturn 0;\n\t}\n\tif (oc & O_JXX) {\n\t\ti_jcmp(op, r1, r2);\n\t\tjmp_add(op, i_jmp(op, 4), r3 + 1);\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n"
  },
  {
    "path": "x64.h",
    "content": "/* architecture-dependent header for x86_64 */\n#define LONGSZ\t\t8\t/* word size */\n#define I_ARCH\t\t\"__x86_64__\"\n\n#define N_REGS\t\t16\t/* number of registers */\n#define N_TMPS\t\t14\t/* number of tmp registers */\n#define N_ARGS\t\t6\t/* number of arg registers */\n#define R_TMPS\t\t0xffcf\t/* mask of tmp registers */\n#define R_ARGS\t\t0x03c6\t/* mask of arg registers */\n#define R_PERM\t\t0xf008\t/* mask of callee-saved registers */\n\n#define REG_FP\t\t5\t/* frame pointer register */\n#define REG_SP\t\t4\t/* stack pointer register */\n\n#define I_ARG0\t\t(-16)\t/* offset of the first argument from FP */\n#define I_LOC0\t\t0\t/* offset of the first local from FP */\n\n#define X64_ABS_RL\t(OUT_RL32)\t/* x86_64 memory model */\n"
  },
  {
    "path": "x86.c",
    "content": "/* architecture-dependent code generation for x86 */\n#include <stdlib.h>\n#include \"ncc.h\"\n\n/* x86-64 registers, without r8-r15 */\n#define R_RAX\t\t0x00\n#define R_RCX\t\t0x01\n#define R_RDX\t\t0x02\n#define R_RBX\t\t0x03\n#define R_RSP\t\t0x04\n#define R_RBP\t\t0x05\n#define R_RSI\t\t0x06\n#define R_RDI\t\t0x07\n\n#define REG_RET\t\tR_RAX\n#define R_BYTE\t\t0x0007\n\n/* x86 opcodes */\n#define I_MOV\t\t0x89\n#define I_MOVI\t\t0xc7\n#define I_MOVIR\t\t0xb8\n#define I_MOVR\t\t0x8b\n#define I_MOVSXD\t0x63\n#define I_SHX\t\t0xd3\n#define I_CMP\t\t0x3b\n#define I_TST\t\t0x85\n#define I_LEA\t\t0x8d\n#define I_NOT\t\t0xf7\n#define I_CALL\t\t0xff\n#define I_MUL\t\t0xf7\n#define I_XOR\t\t0x33\n#define I_CQO\t\t0x99\n#define I_PUSH\t\t0x50\n#define I_POP\t\t0x58\n\n#define MIN(a, b)\t\t((a) < (b) ? (a) : (b))\n#define ALIGN(x, a)\t\t(((x) + (a) - 1) & ~((a) - 1))\n\nint tmpregs[] = {0, 1, 2, 6, 7, 3};\nint argregs[] = {0};\n\n#define OP2(o2, o1)\t\t(0x010000 | ((o2) << 8) | (o1))\n#define O2(op)\t\t\t(((op) >> 8) & 0xff)\n#define O1(op)\t\t\t((op) & 0xff)\n#define MODRM(m, r1, r2)\t((m) << 6 | (r1) << 3 | (r2))\n\nstatic struct mem cs;\t\t/* generated code */\n\n/* code generation functions */\nstatic void os(void *s, int n)\n{\n\tmem_put(&cs, s, n);\n}\n\nstatic char *ointbuf(long n, int l)\n{\n\tstatic char buf[16];\n\tint i;\n\tfor (i = 0; i < l; i++) {\n\t\tbuf[i] = n & 0xff;\n\t\tn >>= 8;\n\t}\n\treturn buf;\n}\n\nstatic void oi(long n, int l)\n{\n\tmem_put(&cs, ointbuf(n, l), l);\n}\n\nstatic void oi_at(long pos, long n, int l)\n{\n\tmem_cpy(&cs, pos, ointbuf(n, l), l);\n}\n\nstatic long opos(void)\n{\n\treturn mem_len(&cs);\n}\n\nstatic void op_x(int op, int r1, int r2, int bt)\n{\n\tint sz = T_SZ(bt);\n\tif (sz == 2)\n\t\toi(0x66, 1);\n\tif (op & 0x10000)\n\t\toi(O2(op), 1);\n\toi(sz == 1 ? O1(op) & ~0x1 : O1(op), 1);\n}\n\n#define op_mr\t\top_rm\n\n/* op_*(): r=reg, m=mem, i=imm, s=sym */\nstatic void op_rm(int op, int src, int base, int off, int bt)\n{\n\tint dis = off == (char) off ? 1 : 4;\n\tint mod = dis == 4 ? 2 : 1;\n\tif (!off && (base & 7) != R_RBP)\n\t\tmod = 0;\n\top_x(op, src, base, bt);\n\toi(MODRM(mod, src & 0x07, base & 0x07), 1);\n\tif ((base & 7) == R_RSP)\n\t\toi(0x24, 1);\n\tif (mod)\n\t\toi(off, dis);\n}\n\nstatic void op_rr(int op, int src, int dst, int bt)\n{\n\top_x(op, src, dst, bt);\n\toi(MODRM(3, src & 0x07, dst & 0x07), 1);\n}\n\n#define movrx_bt(bt)\t\t(LONGSZ)\n\nstatic int movrx_op(int bt, int mov)\n{\n\tint sz = T_SZ(bt);\n\tif (sz == 2)\n\t\treturn OP2(0x0f, bt & T_MSIGN ? 0xbf : 0xb7);\n\tif (sz == 1)\n\t\treturn OP2(0x0f, bt & T_MSIGN ? 0xbe : 0xb6);\n\treturn mov;\n}\n\nstatic void mov_r2r(int rd, int r1, unsigned bt)\n{\n\tif (rd != r1 || T_SZ(bt) != LONGSZ)\n\t\top_rr(movrx_op(bt, I_MOVR), rd, r1, movrx_bt(bt));\n}\n\nstatic void i_push(int reg)\n{\n\top_x(I_PUSH | (reg & 0x7), 0, reg, LONGSZ);\n}\n\nstatic void i_pop(int reg)\n{\n\top_x(I_POP | (reg & 0x7), 0, reg, LONGSZ);\n}\n\nstatic void i_mov(int rd, int rn)\n{\n\top_rr(movrx_op(LONGSZ, I_MOVR), rd, rn, movrx_bt(LONGSZ));\n}\n\nstatic void i_add(int op, int rd, int r1, int r2)\n{\n\t/* opcode for O_ADD, O_SUB, O_AND, O_OR, O_XOR */\n\tstatic int rx[] = {0003, 0053, 0043, 0013, 0063};\n\top_rr(rx[op & 0x0f], rd, r2, LONGSZ);\n}\n\nstatic void i_add_imm(int op, int rd, int rn, long n)\n{\n\t/* opcode for O_ADD, O_SUB, O_AND, O_OR, O_XOR */\n\tstatic int rx[] = {0xc0, 0xe8, 0xe0, 0xc8, 0xf0};\n\tunsigned char s[4] = {0x83, rx[op & 0x0f] | rd, n & 0xff};\n\tos((void *) s, 3);\n}\n\nstatic void i_num(int rd, long n)\n{\n\tif (!n) {\n\t\top_rr(I_XOR, rd, rd, 4);\n\t\treturn;\n\t} else {\n\t\top_x(I_MOVIR + (rd & 7), 0, rd, LONGSZ);\n\t\toi(n, LONGSZ);\n\t}\n}\n\nstatic void i_mul(int rd, int r1, int r2)\n{\n\tif (r2 != R_RDX)\n\t\ti_num(R_RDX, 0);\n\top_rr(I_MUL, 4, r2, LONGSZ);\n}\n\nstatic void i_div(int op, int rd, int r1, int r2)\n{\n\tlong bt = O_T(op);\n\tif (r2 != R_RDX) {\n\t\tif (bt & T_MSIGN)\n\t\t\top_x(I_CQO, R_RAX, R_RDX, LONGSZ);\n\t\telse\n\t\t\ti_num(R_RDX, 0);\n\t}\n\top_rr(I_MUL, bt & T_MSIGN ? 7 : 6, r2, LONGSZ);\n}\n\nstatic void i_tst(int rn, int rm)\n{\n\top_rr(I_TST, rn, rm, LONGSZ);\n}\n\nstatic void i_cmp(int rn, int rm)\n{\n\top_rr(I_CMP, rn, rm, LONGSZ);\n}\n\nstatic void i_cmp_imm(int rn, long n)\n{\n\tunsigned char s[4] = {0x83, 0xf8 | rn, n & 0xff};\n\tos(s, 3);\n}\n\nstatic void i_shl(int op, int rd, int r1, int rs)\n{\n\tlong bt = O_T(op);\n\tint sm = 4;\n\tif ((op & 0x0f) == 1)\n\t\tsm = bt & T_MSIGN ? 7 : 5;\n\top_rr(I_SHX, sm, rd, LONGSZ);\n}\n\nstatic void i_shl_imm(int op, int rd, int rn, long n)\n{\n\tlong bt = O_T(op);\n\tint sm = (op & 0x1) ? (bt & T_MSIGN ? 0xf8 : 0xe8) : 0xe0;\n\tchar s[4] = {0xc1, sm | rn, n & 0xff};\n\tos(s, 3);\n}\n\nstatic void i_neg(int rd)\n{\n\top_rr(I_NOT, 3, rd, LONGSZ);\n}\n\nstatic void i_not(int rd)\n{\n\top_rr(I_NOT, 2, rd, LONGSZ);\n}\n\nstatic int i_cond(long op)\n{\n\t/* lt, ge, eq, ne, le, gt */\n\tstatic int ucond[] = {0x92, 0x93, 0x94, 0x95, 0x96, 0x97};\n\tstatic int scond[] = {0x9c, 0x9d, 0x94, 0x95, 0x9e, 0x9f};\n\tlong bt = O_T(op);\n\treturn bt & T_MSIGN ? scond[op & 0x0f] : ucond[op & 0x0f];\n}\n\nstatic void i_set(long op, int rd)\n{\n\tchar set[] = \"\\x0f\\x00\\xc0\";\n\tset[1] = i_cond(op);\n\tos(set, 3);\t\t\t/* setl al */\n\tos(\"\\x0f\\xb6\\xc0\", 3);\t\t/* movzx rax, al */\n}\n\nstatic void i_lnot(int rd)\n{\n\tchar cmp[] = \"\\x83\\xf8\\x00\";\n\tcmp[1] |= rd;\n\tos(cmp, 3);\t\t/* cmp rax, 0 */\n\ti_set(O_EQ, rd);\n}\n\nstatic void jx(int x, int nbytes)\n{\n\tchar op[2] = {0x0f};\n\tif (nbytes == 1) {\n\t\toi(0x70 | (x & 0x0f), 1);\t/* jx $addr */\n\t} else {\n\t\top[1] = x;\n\t\tos(op, 2);\t\t\t/* jx $addr */\n\t}\n}\n\n/* generate cmp or tst before a conditional jump */\nstatic void i_jcmp(long op, long rn, long rm)\n{\n\tif (op & O_JZ)\n\t\ti_tst(rn, rn);\n\tif (op & O_JCC) {\n\t\tif (op & O_NUM)\n\t\t\ti_cmp_imm(rn, rm);\n\t\telse\n\t\t\ti_cmp(rn, rm);\n\t}\n}\n\n/* generate a jump instruction and return the of its displacement */\nstatic long i_jmp(long op, int nb)\n{\n\tif (op & O_JZ)\n\t\tjx(O_C(op) == O_JZ ? 0x84 : 0x85, nb);\n\telse if (op & O_JCC)\n\t\tjx(i_cond(op) & ~0x10, nb);\n\telse\n\t\tos(nb == 1 ? \"\\xeb\" : \"\\xe9\", 1);\n\toi(0, nb);\n\treturn opos() - nb;\n}\n\n/* the length of a jump instruction opcode */\nstatic int i_jlen(long op, int nb)\n{\n\tif (op & (O_JZ | O_JCC))\n\t\treturn nb ? 2 : 1;\n\treturn 1;\n}\n\n/* zero extend */\nstatic void i_zx(int rd, int r1, int bits)\n{\n\tif (bits & 0x07) {\n\t\ti_shl_imm(O_SHL, rd, rd, LONGSZ * 8 - bits);\n\t\ti_shl_imm(O_SHR, rd, rd, LONGSZ * 8 - bits);\n\t} else {\n\t\tmov_r2r(rd, r1, bits >> 3);\n\t}\n}\n\n/* sign extend */\nstatic void i_sx(int rd, int r1, int bits)\n{\n\tmov_r2r(rd, r1, T_MSIGN | (bits >> 3));\n}\n\nstatic void i_cast(int rd, int rn, int bt)\n{\n\tif (T_SZ(bt) == 8) {\n\t\tif (rd != rn)\n\t\t\ti_mov(rd, rn);\n\t} else {\n\t\tif (bt & T_MSIGN)\n\t\t\ti_sx(rd, rn, T_SZ(bt) * 8);\n\t\telse\n\t\t\ti_zx(rd, rn, T_SZ(bt) * 8);\n\t}\n}\n\nstatic void i_add_anyimm(int rd, int rn, long n)\n{\n\top_rm(I_LEA, rd, rn, n, LONGSZ);\n}\n\nstatic long *rel_sym;\t\t/* relocation symbols */\nstatic long *rel_flg;\t\t/* relocation flags */\nstatic long *rel_off;\t\t/* relocation offsets */\nstatic long rel_n, rel_sz;\t/* relocation count */\n\nstatic long lab_sz;\t\t/* label count */\nstatic long *lab_loc;\t\t/* label offsets in cs */\nstatic long jmp_n, jmp_sz;\t/* jump count */\nstatic long *jmp_off;\t\t/* jump offsets */\nstatic long *jmp_dst;\t\t/* jump destinations */\nstatic long *jmp_op;\t\t/* jump opcode */\nstatic long jmp_ret;\t\t/* the position of the last return jmp */\n\nstatic void lab_add(long id)\n{\n\twhile (id >= lab_sz) {\n\t\tint lab_n = lab_sz;\n\t\tlab_sz = MAX(128, lab_sz * 2);\n\t\tlab_loc = mextend(lab_loc, lab_n, lab_sz, sizeof(*lab_loc));\n\t}\n\tlab_loc[id] = opos();\n}\n\nstatic void jmp_add(long op, long off, long dst)\n{\n\tif (jmp_n == jmp_sz) {\n\t\tjmp_sz = MAX(128, jmp_sz * 2);\n\t\tjmp_off = mextend(jmp_off, jmp_n, jmp_sz, sizeof(*jmp_off));\n\t\tjmp_dst = mextend(jmp_dst, jmp_n, jmp_sz, sizeof(*jmp_dst));\n\t\tjmp_op = mextend(jmp_op, jmp_n, jmp_sz, sizeof(*jmp_op));\n\t}\n\tjmp_off[jmp_n] = off;\n\tjmp_dst[jmp_n] = dst;\n\tjmp_op[jmp_n] = op;\n\tjmp_n++;\n}\n\nvoid i_label(long id)\n{\n\tlab_add(id + 1);\n}\n\nstatic void i_rel(long sym, long flg, long off)\n{\n\tif (rel_n == rel_sz) {\n\t\trel_sz = MAX(128, rel_sz * 2);\n\t\trel_sym = mextend(rel_sym, rel_n, rel_sz, sizeof(*rel_sym));\n\t\trel_flg = mextend(rel_flg, rel_n, rel_sz, sizeof(*rel_flg));\n\t\trel_off = mextend(rel_off, rel_n, rel_sz, sizeof(*rel_off));\n\t}\n\trel_sym[rel_n] = sym;\n\trel_flg[rel_n] = flg;\n\trel_off[rel_n] = off;\n\trel_n++;\n}\n\nstatic void i_sym(int rd, int sym, int off)\n{\n\top_x(I_MOVIR + (rd & 7), 0, rd, LONGSZ);\n\ti_rel(sym, OUT_CS, opos());\n\toi(off, LONGSZ);\n}\n\nstatic void i_subsp(long val)\n{\n\tif (!val)\n\t\treturn;\n\tif (val <= 127 && val >= -128) {\n\t\tos(\"\\x83\\xec\", 2);\n\t\toi(val, 1);\n\t} else {\n\t\tos(\"\\x81\\xec\", 2);\n\t\toi(val, 4);\n\t}\n}\n\nstatic int regs_count(long regs)\n{\n\tint cnt = 0;\n\tint i;\n\tfor (i = 0; i < N_REGS; i++)\n\t\tif (((1 << i) & R_TMPS) & regs)\n\t\t\tcnt++;\n\treturn cnt;\n}\n\nstatic void regs_save(long sregs, long dis)\n{\n\tint i;\n\tfor (i = 0; i < N_REGS; i++)\n\t\tif (((1 << i) & R_TMPS) & sregs)\n\t\t\ti_push(i);\n\tif (dis)\n\t\ti_subsp(dis);\n}\n\nstatic void regs_load(long sregs, long dis)\n{\n\tint i;\n\tif (dis)\n\t\ti_subsp(-dis);\n\tfor (i = N_REGS - 1; i >= 0; --i)\n\t\tif (((1 << i) & R_TMPS) & sregs)\n\t\t\ti_pop(i);\n}\n\nvoid i_wrap(int argc, long sargs, long spsub, int initfp, long sregs, long sregs_pos)\n{\n\tlong body_n;\n\tvoid *body;\n\tlong diff;\t\t/* prologue length */\n\tint i;\n\t/* removing the last jmp to the epilogue */\n\tif (jmp_ret + i_jlen(O_JMP, 4) + 4 == opos()) {\n\t\tmem_cut(&cs, jmp_ret);\n\t\tjmp_n--;\n\t}\n\tlab_add(0);\t\t\t\t/* the return label */\n\tbody_n = mem_len(&cs);\n\tbody = mem_get(&cs);\n\t/* generating function prologue */\n\tif (initfp) {\n\t\tos(\"\\x55\", 1);\t\t\t/* push rbp */\n\t\tos(\"\\x89\\xe5\", 2);\t\t/* mov rbp, rsp */\n\t}\n\tif (spsub) {\n\t\tspsub = ALIGN(spsub, 8);\n\t\ti_subsp(sregs ? -sregs_pos - regs_count(sregs) * ULNG : spsub);\n\t}\n\tif (sregs)\t\t/* saving registers */\n\t\tregs_save(sregs, spsub + sregs_pos);\n\tdiff = mem_len(&cs);\n\tmem_put(&cs, body, body_n);\n\tfree(body);\n\t/* generating function epilogue */\n\tif (sregs)\t\t/* restoring saved registers */\n\t\tregs_load(sregs, spsub + sregs_pos);\n\tif (initfp)\n\t\tos(\"\\xc9\", 1);\t\t\t/* leave */\n\tos(\"\\xc3\", 1);\t\t\t\t/* ret */\n\t/* adjusting code offsets */\n\tfor (i = 0; i < rel_n; i++)\n\t\trel_off[i] += diff;\n\tfor (i = 0; i < jmp_n; i++)\n\t\tjmp_off[i] += diff;\n\tfor (i = 0; i < lab_sz; i++)\n\t\tlab_loc[i] += diff;\n}\n\n/* introduce shorter jumps, if possible */\nstatic void i_shortjumps(int *nb)\n{\n\tlong off = 0;\t/* current code offset */\n\tlong dif = 0;\t/* the difference after changing jump instructions */\n\tint rel = 0;\t/* current relocation */\n\tint lab = 1;\t/* current label */\n\tlong c_len = mem_len(&cs);\n\tchar *c = mem_get(&cs);\n\tint i;\n\tfor (i = 0; i < jmp_n; i++)\n\t\tnb[i] = abs(lab_loc[jmp_dst[i]] - jmp_off[i]) < 0x70 ? 1 : 4;\n\tfor (i = 0; i < jmp_n; i++) {\n\t\tlong cur = jmp_off[i] - i_jlen(jmp_op[i], 4);\n\t\twhile (rel < rel_n && rel_off[rel] <= cur)\n\t\t\trel_off[rel++] += dif;\n\t\twhile (lab < lab_sz && lab_loc[lab] <= cur)\n\t\t\tlab_loc[lab++] += dif;\n\t\tmem_put(&cs, c + off, cur - off);\n\t\tjmp_off[i] = i_jmp(jmp_op[i], nb[i]);\n\t\toff = cur + i_jlen(jmp_op[i], 4) + 4;\n\t\tdif = mem_len(&cs) - off;\n\t}\n\twhile (rel < rel_n)\n\t\trel_off[rel++] += dif;\n\twhile (lab < lab_sz)\n\t\tlab_loc[lab++] += dif;\n\tlab_loc[0] += dif;\n\tmem_put(&cs, c + off, c_len - off);\n\tfree(c);\n}\n\nvoid i_code(char **c, long *c_len, long **rsym, long **rflg, long **roff, long *rcnt)\n{\n\tint *nb;\t/* number of bytes necessary for jump displacements */\n\tint i;\n\t/* more compact jmp instructions */\n\tnb = malloc(jmp_n * sizeof(nb[0]));\n\tfor (i = 0; i < jmp_n; i++)\n\t\tnb[i] = 4;\n\ti_shortjumps(nb);\n\tfor (i = 0; i < jmp_n; i++)\t/* filling jmp destinations */\n\t\toi_at(jmp_off[i], lab_loc[jmp_dst[i]] -\n\t\t\t\tjmp_off[i] - nb[i], nb[i]);\n\tfree(nb);\n\t*c_len = mem_len(&cs);\n\t*c = mem_get(&cs);\n\t*rsym = rel_sym;\n\t*rflg = rel_flg;\n\t*roff = rel_off;\n\t*rcnt = rel_n;\n\trel_sym = NULL;\n\trel_flg = NULL;\n\trel_off = NULL;\n\trel_n = 0;\n\trel_sz = 0;\n\tjmp_n = 0;\n}\n\nvoid i_done(void)\n{\n\tfree(jmp_off);\n\tfree(jmp_dst);\n\tfree(jmp_op);\n\tfree(lab_loc);\n}\n\nlong i_reg(long op, long *rd, long *r1, long *r2, long *r3, long *tmp)\n{\n\tlong oc = O_C(op);\n\tlong bt = O_T(op);\n\t*rd = 0;\n\t*r1 = 0;\n\t*r2 = 0;\n\t*r3 = 0;\n\t*tmp = 0;\n\tif (oc & O_MOV) {\n\t\t*rd = R_TMPS;\n\t\tif (oc & (O_NUM | O_SYM))\n\t\t\t*r1 = 32;\n\t\telse\n\t\t\t*r1 = T_SZ(bt) == 1 ? R_BYTE : R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc & O_ADD) {\n\t\t*r1 = R_TMPS;\n\t\t*r2 = oc & O_NUM ? (oc == O_ADD ? 32 : 8) : R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc & O_SHL) {\n\t\tif (oc & O_NUM) {\n\t\t\t*r1 = R_TMPS;\n\t\t\t*r2 = 8;\n\t\t} else {\n\t\t\t*r2 = 1 << R_RCX;\n\t\t\t*r1 = R_TMPS & ~*r2;\n\t\t}\n\t\treturn 0;\n\t}\n\tif (oc & O_MUL) {\n\t\tif (oc & O_NUM)\n\t\t\treturn 1;\n\t\t*rd = oc == O_MOD ? (1 << R_RDX) : (1 << R_RAX);\n\t\t*r1 = (1 << R_RAX);\n\t\t*r2 = R_TMPS & ~*rd & ~*r1;\n\t\tif (oc == O_DIV)\n\t\t\t*r2 &= ~(1 << R_RDX);\n\t\t*tmp = (1 << R_RDX) | (1 << R_RAX);\n\t\treturn 0;\n\t}\n\tif (oc & O_CMP) {\n\t\t*rd = 1 << R_RAX;\n\t\t*r1 = R_TMPS;\n\t\t*r2 = oc & O_NUM ? 8 : R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc & O_UOP) {\n\t\tif (oc == O_LNOT)\n\t\t\t*r1 = 1 << R_RAX;\n\t\telse\n\t\t\t*r1 = R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc == O_MSET) {\n\t\t*r1 = 1 << R_RDI;\n\t\t*r2 = 1 << R_RAX;\n\t\t*r3 = 1 << R_RCX;\n\t\t*tmp = (1 << R_RDI) | (1 << R_RCX);\n\t\treturn 0;\n\t}\n\tif (oc == O_MCPY) {\n\t\t*r1 = 1 << R_RDI;\n\t\t*r2 = 1 << R_RSI;\n\t\t*r3 = 1 << R_RCX;\n\t\t*tmp = (1 << R_RDI) | (1 << R_RSI) | (1 << R_RCX);\n\t\treturn 0;\n\t}\n\tif (oc == O_RET) {\n\t\t*r1 = (1 << REG_RET);\n\t\treturn 0;\n\t}\n\tif (oc & O_CALL) {\n\t\t*rd = (1 << REG_RET);\n\t\t*r1 = oc & O_SYM ? 0 : R_TMPS;\n\t\t*tmp = R_TMPS & ~R_PERM;\n\t\treturn 0;\n\t}\n\tif (oc & O_LD) {\n\t\t*rd = T_SZ(bt) == 1 ? R_BYTE : R_TMPS;\n\t\t*r1 = R_TMPS;\n\t\t*r2 = oc & O_NUM ? 32 : R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc & O_ST) {\n\t\t*r1 = T_SZ(bt) == 1 ? R_BYTE : R_TMPS;\n\t\t*r2 = R_TMPS;\n\t\t*r3 = oc & O_NUM ? 32 : R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc & O_JZ) {\n\t\t*r1 = R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc & O_JCC) {\n\t\t*r1 = R_TMPS;\n\t\t*r2 = oc & O_NUM ? 8 : R_TMPS;\n\t\treturn 0;\n\t}\n\tif (oc == O_JMP)\n\t\treturn 0;\n\treturn 1;\n}\n\nint i_imm(long lim, long n)\n{\n\tlong max = (1 << (lim - 1)) - 1;\n\treturn n <= max && n + 1 >= -max;\n}\n\nlong i_ins(long op, long rd, long r1, long r2, long r3)\n{\n\tlong oc = O_C(op);\n\tlong bt = O_T(op);\n\tif (oc & O_ADD) {\n\t\tif (oc & O_NUM) {\n\t\t\tif (rd == r1 && r2 <= 127 && r2 >= -128)\n\t\t\t\ti_add_imm(op, r1, r1, r2);\n\t\t\telse\n\t\t\t\ti_add_anyimm(rd, r1, r2);\n\t\t} else {\n\t\t\ti_add(op, r1, r1, r2);\n\t\t}\n\t}\n\tif (oc & O_SHL) {\n\t\tif (oc & O_NUM)\n\t\t\ti_shl_imm(op, r1, r1, r2);\n\t\telse\n\t\t\ti_shl(op, r1, r1, r2);\n\t}\n\tif (oc & O_MUL) {\n\t\tif (oc == O_MUL)\n\t\t\ti_mul(R_RAX, r1, r2);\n\t\tif (oc == O_DIV)\n\t\t\ti_div(op, R_RAX, r1, r2);\n\t\tif (oc == O_MOD)\n\t\t\ti_div(op, R_RDX, r1, r2);\n\t\treturn 0;\n\t}\n\tif (oc & O_CMP) {\n\t\tif (oc & O_NUM)\n\t\t\ti_cmp_imm(r1, r2);\n\t\telse\n\t\t\ti_cmp(r1, r2);\n\t\ti_set(op, rd);\n\t\treturn 0;\n\t}\n\tif (oc & O_UOP) {\t/* uop */\n\t\tif (oc == O_NEG)\n\t\t\ti_neg(r1);\n\t\tif (oc == O_NOT)\n\t\t\ti_not(r1);\n\t\tif (oc == O_LNOT)\n\t\t\ti_lnot(r1);\n\t\treturn 0;\n\t}\n\tif (oc == O_CALL) {\n\t\top_rr(I_CALL, 2, r1, LONGSZ);\n\t\treturn 0;\n\t}\n\tif (oc == (O_CALL | O_SYM)) {\n\t\tos(\"\\xe8\", 1);\t\t/* call $x */\n\t\ti_rel(r1, OUT_CS | OUT_RLREL, opos());\n\t\toi(-4, 4);\n\t\treturn 0;\n\t}\n\tif (oc == (O_MOV | O_SYM)) {\n\t\ti_sym(rd, r1, r2);\n\t\treturn 0;\n\t}\n\tif (oc == (O_MOV | O_NUM)) {\n\t\ti_num(rd, r1);\n\t\treturn 0;\n\t}\n\tif (oc == O_MSET) {\n\t\tos(\"\\xfc\\xf3\\xaa\", 3);\t\t/* cld; rep stosb */\n\t\treturn 0;\n\t}\n\tif (oc == O_MCPY) {\n\t\tos(\"\\xfc\\xf3\\xa4\", 3);\t\t/* cld; rep movs */\n\t\treturn 0;\n\t}\n\tif (oc == O_RET) {\n\t\tjmp_ret = opos();\n\t\tjmp_add(O_JMP, i_jmp(op, 4), 0);\n\t\treturn 0;\n\t}\n\tif (oc == (O_LD | O_NUM)) {\n\t\top_rm(movrx_op(bt, I_MOVR), rd, r1, r2, movrx_bt(bt));\n\t\treturn 0;\n\t}\n\tif (oc == (O_ST | O_NUM)) {\n\t\top_rm(I_MOV, r1, r2, r3, bt);\n\t\treturn 0;\n\t}\n\tif (oc == O_MOV) {\n\t\ti_cast(rd, r1, bt);\n\t\treturn 0;\n\t}\n\tif (oc & O_JXX) {\n\t\ti_jcmp(op, r1, r2);\n\t\tjmp_add(op, i_jmp(op, 4), r3 + 1);\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n"
  },
  {
    "path": "x86.h",
    "content": "/* architecture-dependent header for x86 */\n#define LONGSZ\t\t4\t/* word size */\n#define I_ARCH\t\t\"__i386__\"\n\n#define N_REGS\t\t8\t/* number of registers */\n#define N_TMPS\t\t6\t/* number of tmp registers */\n#define N_ARGS\t\t0\t/* number of arg registers */\n#define R_TMPS\t\t0x00cf\t/* mask of tmp registers */\n#define R_ARGS\t\t0x0000\t/* mask of arg registers */\n#define R_PERM\t\t0x00c8\t/* mask of callee-saved registers */\n\n#define REG_FP\t\t5\t/* frame pointer register */\n#define REG_SP\t\t4\t/* stack pointer register */\n\n#define I_ARG0\t\t(-8)\t/* offset of the first argument from FP */\n#define I_LOC0\t\t0\t/* offset of the first local from FP */\n"
  }
]