From 5d0c4cf3fc288434c41cba52dd998ab1d7375a7b Mon Sep 17 00:00:00 2001 From: Valery Ushakov Date: Sun, 26 Jan 2020 04:10:20 +0300 Subject: Fix Moscow timezone. DST changes started in 1981 but used several different patterns. Moscow briefly used EET/EEST timezone in 1991, but switched back on January 19, 1992. Since this file format cannot express this, just ignore it. MSK/MSD just went on as usual, it's just Moscow was not actually in it. It moved to GMT+4 without DST changes in 2011. Technically this should be called "MSK" (with a different offset), but just treat it as permanent DST (which it was) and let it be called "MSD". (Again, the file format cannot express this properly). It moved back to GMT+3 without DST changes in 2014. --- locale/Moscow | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/locale/Moscow b/locale/Moscow index 475def6c..f56a511f 100644 --- a/locale/Moscow +++ b/locale/Moscow @@ -1,12 +1,32 @@ MSK 10800 MSD 14400 -638330400 657079200 670384800 688528800 701834400 719978400 -733284000 752032800 764733600 783482400 796183200 814932000 -828237600 846381600 859687200 877831200 891136800 909280800 -922586400 941335200 954036000 972784800 985485600 1004234400 -1017540000 1035684000 1048989600 1067133600 1080439200 1099188000 -1111888800 1130637600 1143338400 1162087200 1174788000 1193536800 -1206842400 1224986400 1238292000 1256436000 1269741600 1288490400 -1301191200 1319940000 1332640800 1351389600 1364695200 1382839200 -1396144800 1414288800 1427594400 1445738400 1459044000 1477792800 -1490493600 1509242400 1521943200 1540692000 1553997600 1572141600 -1585447200 1603591200 1616896800 1635645600 1648346400 +354931200 370738800 +386467200 402274800 +418003200 433810800 +449625600 465357600 +481082400 496807200 +512532000 528256800 +543981600 559706400 +575431200 591156000 +606880800 622605600 +638330400 654660000 +670384800 686109600 +701834400 717559200 +733284000 749008800 +764733600 780458400 +796183200 811908000 +828237600 846381600 +859687200 877831200 +891136800 909280800 +922586400 941335200 +954036000 972784800 +985485600 1004234400 +1017540000 1035684000 +1048989600 1067133600 +1080439200 1099188000 +1111888800 1130637600 +1143338400 1162087200 +1174788000 1193536800 +1206842400 1224986400 +1238292000 1256436000 +1269741600 1288490400 +1301191200 1414285200 -- cgit v1.2.3 From c82cb0a62100fbcab34a1466b49fc687fc570af6 Mon Sep 17 00:00:00 2001 From: Valery Ushakov Date: Sat, 7 Mar 2020 04:41:06 +0300 Subject: Silently ignore x-special/gnome-copied-files requests. Modern desktops seem to like to send it a lot so don't spam the user with repeated messages about it. --- emu/port/win-x11a.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/emu/port/win-x11a.c b/emu/port/win-x11a.c index 569287b6..bbc65761 100644 --- a/emu/port/win-x11a.c +++ b/emu/port/win-x11a.c @@ -1613,11 +1613,11 @@ if(0) iprint("xselect target=%d requestor=%d property=%d selection=%d\n", 8, PropModeReplace, (uchar*)clip.buf, strlen(clip.buf)); qunlock(&clip.lk); }else{ - iprint("get %d\n", xe->target); name = XGetAtomName(xd, xe->target); if(name == nil) - iprint("XGetAtomName failed\n"); - else if(strcmp(name, "TIMESTAMP") != 0) + name = ""; + if(strcmp(name, "TIMESTAMP") != 0 + && strcmp(name, "x-special/gnome-copied-files") != 0) iprint("%s: cannot handle selection request for '%s' (%d)\n", argv0, name, (int)xe->target); r.xselection.property = None; } -- cgit v1.2.3 From 83beab8bbcbec5a219996d2118aa15bebc108e91 Mon Sep 17 00:00:00 2001 From: David Boddie Date: Sat, 18 Jul 2020 16:33:54 +0200 Subject: Fixed case 60 which used an ARMv4 instruction regardless of version. Fixed case 22 to avoid using the pre/post-indexing flag with non-load instructions. --- utils/5l/asm.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/utils/5l/asm.c b/utils/5l/asm.c index 53d51c45..d693eea6 100644 --- a/utils/5l/asm.c +++ b/utils/5l/asm.c @@ -902,13 +902,15 @@ PP = p; r = o->param; o1 = olr(instoffset, r, p->to.reg, p->scond); - o2 = oprrr(ASLL, p->scond); - o3 = oprrr(ASRA, p->scond); r = p->to.reg; if(p->as == AMOVB) { + o2 = oprrr(ASLL, p->scond & ~C_PBIT); + o3 = oprrr(ASRA, p->scond & ~C_PBIT); o2 |= (24<<7)|(r)|(r<<12); o3 |= (24<<7)|(r)|(r<<12); } else { + o2 = oprrr(ASLL, p->scond); + o3 = oprrr(ASRA, p->scond); o2 |= (16<<7)|(r)|(r<<12); if(p->as == AMOVHU) o3 = oprrr(ASRL, p->scond); @@ -1195,15 +1197,18 @@ PP = p; o1 |= 1<<22; break; - case 60: /* movb R(R),R -> ldrsb indexed */ + case 60: /* movb R(R),R -> ldrb indexed */ if(p->from.reg == NREG) { diag("byte MOV from shifter operand"); goto mov; } if(p->from.offset&(~0xf)) - diag("bad shift in LDRSB"); - o1 = olhrr(p->from.offset, p->from.reg, p->to.reg, p->scond); - o1 ^= (1<<5)|(1<<6); + diag("bad shift in LDRB"); + o1 = olr(p->from.offset, p->from.reg, p->to.reg, p->scond); + if(p->as == AMOVB) { + o1 |= 1<<22; /* B */ + o1 ^= 1<<25; /* instruction with Rm */ + } break; case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */ -- cgit v1.2.3 From ed97654bd7a11d480b44505c8300d06b42e5fefe Mon Sep 17 00:00:00 2001 From: Charles Forsyth Date: Sat, 25 Jul 2020 14:18:21 +0100 Subject: remove .hgignore --- .hgignore | 74 --------------------------------------------------------------- 1 file changed, 74 deletions(-) delete mode 100644 .hgignore diff --git a/.hgignore b/.hgignore deleted file mode 100644 index bdd6041c..00000000 --- a/.hgignore +++ /dev/null @@ -1,74 +0,0 @@ -syntax: glob -*.[8qkv5967o] -*.obj -[8qkv965o].out -[8qkv965o].emu -obj.out -obj.map -vc*.pdb -y.output -y.tab.[ch] -y.debug -*.a -emu/*/*.root.[ch] -emu/*/errstr.h -emu/*/srv.h -emu/*/srvm.h -[A-Z]*/*/bin/?[acl] -[A-Z]*/*/bin/5coff -[A-Z]*/*/bin/5cv -[A-Z]*/*/bin/acid -[A-Z]*/*/bin/asm -[A-Z]*/*/bin/data2s -[A-Z]*/*/bin/emu -[A-Z]*/*/bin/limbo -Nt/*/bin/?[acl].exe -Nt/*/bin/5coff.exe -Nt/*/bin/5cv.exe -Nt/*/bin/acid.exe -Nt/*/bin/asm.exe -Nt/*/bin/data2s.exe -Nt/*/bin/emu.exe -Nt/*/bin/limbo.exe -Nt/*/bin/ftl.exe -Nt/*/bin/iar.exe -Nt/*/bin/idea.exe -Nt/*/bin/inm.exe -Nt/*/bin/kprof.exe -Nt/*/bin/ksize.exe -Nt/*/bin/kstrip.exe -Nt/*/bin/md5sum.exe -Nt/*/bin/mkppcimage.exe -Nt/*/bin/ms2.exe -Nt/*/bin/ndate.exe -Nt/*/bin/ntsrv.exe -Nt/*/bin/sqz.exe -Nt/*/bin/srclist.exe -Nt/*/bin/styxtest.exe -emu/Nt/*.map -emu/Nt/*.exe -keydb/keys -keydb/countersigned -keydb/signed -keydb/signerkey -tmp/* - -syntax: regexp -^appl/.*.dis -^appl/.*.sbl -^tmp/.* -^contrib/.* -^usr/\.* -^grid/.* -^libinterp/cryptmod.h -^libinterp/drawmod.h -^libinterp/freetypemod.h -^libinterp/ipintsmod.h -^libinterp/keyring.h -^libinterp/keyringif.h -^libinterp/loadermod.h -^libinterp/mathmod.h -^libinterp/runt.h -^libinterp/sysmod.h -^libinterp/tkmod.h -^limbo/runt.h -- cgit v1.2.3 From 2a571cc0ece4073eb56d5ccfc3e061a09a353e13 Mon Sep 17 00:00:00 2001 From: Richard Miller Date: Mon, 9 Nov 2020 11:33:44 +0000 Subject: Add riscv and riscv64 support to libmach --- utils/include/a.out.h | 4 +- utils/include/mach.h | 12 + utils/libmach/elf.h | 1 + utils/libmach/executable.c | 30 ++ utils/libmach/i.c | 70 +++++ utils/libmach/idb.c | 697 +++++++++++++++++++++++++++++++++++++++++++++ utils/libmach/iobj.c | 134 +++++++++ utils/libmach/j.c | 70 +++++ utils/libmach/mkfile | 4 + utils/libmach/obj.c | 6 +- utils/libmach/setmach.c | 16 +- utils/libmach/uregi.h | 57 ++++ utils/libmach/uregj.h | 39 +++ 13 files changed, 1136 insertions(+), 4 deletions(-) create mode 100644 utils/libmach/i.c create mode 100644 utils/libmach/idb.c create mode 100644 utils/libmach/iobj.c create mode 100644 utils/libmach/j.c create mode 100644 utils/libmach/uregi.h create mode 100644 utils/libmach/uregj.h diff --git a/utils/include/a.out.h b/utils/include/a.out.h index 86c7d061..915cdaae 100644 --- a/utils/include/a.out.h +++ b/utils/include/a.out.h @@ -31,9 +31,11 @@ struct Exec #define S_MAGIC _MAGIC(HDR_MAGIC, 26) /* amd64 */ #define T_MAGIC _MAGIC(HDR_MAGIC, 27) /* powerpc64 */ #define R_MAGIC _MAGIC(HDR_MAGIC, 28) /* arm64 */ +#define Z_MAGIC _MAGIC(0, 29) /* riscv */ +#define Y_MAGIC _MAGIC(0, 30) /* riscv64 */ #define MIN_MAGIC 8 -#define MAX_MAGIC 28 /* <= 90 */ +#define MAX_MAGIC 30 /* <= 90 */ #define DYN_MAGIC 0x80000000 /* dlm */ diff --git a/utils/include/mach.h b/utils/include/mach.h index 1c8d7a83..25e89279 100644 --- a/utils/include/mach.h +++ b/utils/include/mach.h @@ -16,6 +16,8 @@ * powerpc, * powerpc64 * arm64 + * riscv + * riscv64 */ enum { @@ -36,6 +38,8 @@ enum MAMD64, MPOWER64, MARM64, + MRISCV, + MRISCV64, /* types of executables */ FNONE = 0, /* unidentified */ FMIPS, /* v.out */ @@ -67,6 +71,10 @@ enum FPOWER64B, /* 9.out bootable */ FARM64, /* arm64 */ FARM64B, /* arm64 bootable */ + FRISCV, /* riscv */ + FRISCVB, /* riscv bootable */ + FRISCV64, /* riscv64 */ + FRISCV64B, /* riscv64 bootable */ ANONE = 0, /* dissembler types */ AMIPS, @@ -85,6 +93,8 @@ enum AAMD64, APOWER64, AARM64, + ARISCV, + ARISCV64, /* object file types */ Obj68020 = 0, /* .2 */ ObjSparc, /* .k */ @@ -103,6 +113,8 @@ enum ObjSpim, /* .0 */ ObjPower64, /* .9 */ ObjArm64, /* .4? */ + ObjRiscv, /* .i */ + ObjRiscv64, /* .j */ Maxobjtype, CNONE = 0, /* symbol table classes */ diff --git a/utils/libmach/elf.h b/utils/libmach/elf.h index 6bd483d2..e945ba11 100644 --- a/utils/libmach/elf.h +++ b/utils/libmach/elf.h @@ -84,6 +84,7 @@ enum { ARM = 40, /* ARM */ AMD64 = 62, /* Amd64 */ ARM64 = 183, /* ARM64 */ + RISCV = 243, /* RISC-V */ NO_VERSION = 0, /* version, ident[VERSION] */ CURRENT = 1, diff --git a/utils/libmach/executable.c b/utils/libmach/executable.c index b9954f0a..2734cf44 100644 --- a/utils/libmach/executable.c +++ b/utils/libmach/executable.c @@ -65,6 +65,8 @@ extern Mach mamd64; extern Mach marm; extern Mach mpower; extern Mach mpower64; +extern Mach mriscv; +extern Mach mriscv64; ExecTable exectab[] = { @@ -203,6 +205,24 @@ ExecTable exectab[] = sizeof(Exec), leswal, armdotout }, + { Z_MAGIC, /* riscv i.out */ + "riscv executable", + nil, + FRISCV, + 0, + &mriscv, + sizeof(Exec), + beswal, + common }, + { Y_MAGIC, /* riscv j.out */ + "riscv64 executable", + nil, + FRISCV64, + 0, + &mriscv64, + sizeof(Exec), + beswal, + common }, { 0 }, }; @@ -357,6 +377,12 @@ commonboot(Fhdr *fp) fp->name = "amd64 plan 9 boot image"; fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize); break; + case FRISCV: + fp->type = FRISCVB; + fp->txtaddr = (u32int)fp->entry; + fp->name = "riscv plan 9 boot image"; + fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize); + break; default: return; } @@ -580,6 +606,10 @@ elfdotout(int fd, Fhdr *fp, ExecHdr *hp) mach = &marm; fp->type = FARM; break; + case RISCV: + mach = &mriscv; + fp->type = FRISCV; + break; default: return 0; } diff --git a/utils/libmach/i.c b/utils/libmach/i.c new file mode 100644 index 00000000..659ca3c3 --- /dev/null +++ b/utils/libmach/i.c @@ -0,0 +1,70 @@ +/* + * RISC-V definition + */ +#include +#include +#include "uregi.h" +#include + +#define REGOFF(x) offsetof(struct Ureg, x) +#define REGSIZE sizeof(struct Ureg) + +Reglist riscvreglist[] = { + {"PC", REGOFF(pc), RINT, 'X'}, + {"SP", REGOFF(r27), RINT, 'X'}, + {"R31", REGOFF(r31), RINT, 'X'}, + {"R30", REGOFF(r30), RINT, 'X'}, + {"R28", REGOFF(r28), RINT, 'X'}, + {"R27", REGOFF(r27), RINT, 'X'}, + {"R26", REGOFF(r26), RINT, 'X'}, + {"R25", REGOFF(r25), RINT, 'X'}, + {"R24", REGOFF(r24), RINT, 'X'}, + {"R23", REGOFF(r23), RINT, 'X'}, + {"R22", REGOFF(r22), RINT, 'X'}, + {"R21", REGOFF(r21), RINT, 'X'}, + {"R20", REGOFF(r20), RINT, 'X'}, + {"R19", REGOFF(r19), RINT, 'X'}, + {"R18", REGOFF(r18), RINT, 'X'}, + {"R17", REGOFF(r17), RINT, 'X'}, + {"R16", REGOFF(r16), RINT, 'X'}, + {"R15", REGOFF(r15), RINT, 'X'}, + {"R14", REGOFF(r14), RINT, 'X'}, + {"R13", REGOFF(r13), RINT, 'X'}, + {"R12", REGOFF(r12), RINT, 'X'}, + {"R11", REGOFF(r11), RINT, 'X'}, + {"R10", REGOFF(r10), RINT, 'X'}, + {"R9", REGOFF(r9), RINT, 'X'}, + {"R8", REGOFF(r8), RINT, 'X'}, + {"R7", REGOFF(r7), RINT, 'X'}, + {"R6", REGOFF(r6), RINT, 'X'}, + {"R5", REGOFF(r5), RINT, 'X'}, + {"R4", REGOFF(r4), RINT, 'X'}, + {"R3", REGOFF(r3), RINT, 'X'}, + {"R2", REGOFF(r2), RINT, 'X'}, + {"R1", REGOFF(r1), RINT, 'X'}, + { 0 } +}; + + /* the machine description */ +Mach mriscv = +{ + "riscv", + MRISCV, /* machine type */ + riscvreglist, /* register set */ + REGSIZE, /* register set size */ + 0, /* fp register set size */ + "PC", /* name of PC */ + "SP", /* name of SP */ + "R1", /* name of link register */ + "setSB", /* static base register name */ + 0, /* static base register value */ + 0x1000, /* page size */ + 0x80000000ULL, /* kernel base */ + 0xC0000000ULL, /* kernel text mask */ + 0x3FFFFFFFULL, /* user stack top */ + 2, /* quantization of pc */ + 4, /* szaddr */ + 4, /* szreg */ + 4, /* szfloat */ + 8, /* szdouble */ +}; diff --git a/utils/libmach/idb.c b/utils/libmach/idb.c new file mode 100644 index 00000000..62df623e --- /dev/null +++ b/utils/libmach/idb.c @@ -0,0 +1,697 @@ +#include +#include +#include +#include "ic/i.out.h" + +static char *riscvexcep(Map*, Rgetter); + +/* + * RISCV-specific debugger interface + */ + +typedef struct Instr Instr; +struct Instr +{ + Map *map; + ulong w; + uvlong addr; + char *fmt; + int n; + int op; + int func3; + int func7; + char rs1, rs2, rs3, rd; + char rv64; + long imm; + + char* curr; /* fill point in buffer */ + char* end; /* end of buffer */ +}; + +typedef struct Optab Optab; +struct Optab { + int func7; + int op[8]; +}; + +typedef struct Opclass Opclass; +struct Opclass { + char *fmt; + Optab tab[4]; +}; + +/* Major opcodes */ +enum { + OLOAD, OLOAD_FP, Ocustom_0, OMISC_MEM, OOP_IMM, OAUIPC, OOP_IMM_32, O48b, + OSTORE, OSTORE_FP, Ocustom_1, OAMO, OOP, OLUI, OOP_32, O64b, + OMADD, OMSUB, ONMSUB, ONMADD, OOP_FP, Ores_0, Ocustom_2, O48b_2, + OBRANCH, OJALR, Ores_1, OJAL, OSYSTEM, Ores_2, Ocustom_3, O80b +}; + +/* copy anames from compiler */ +static +#include "ic/enam.c" + +static Opclass opOLOAD = { + "a,d", + 0, AMOVB, AMOVH, AMOVW, AMOV, AMOVBU, AMOVHU, AMOVWU, 0, +}; +static Opclass opOLOAD_FP = { + "a,fd", + 0, 0, 0, AMOVF, AMOVD, 0, 0, 0, 0, +}; +static Opclass opOMISC_MEM = { + "", + 0, AFENCE, AFENCE_I,0, 0, 0, 0, 0, 0, +}; +static Opclass opOOP_IMM = { + "$i,s,d", + 0x20, 0, 0, 0, 0, 0, ASRA, 0, 0, + 0, AADD, ASLL, ASLT, ASLTU, AXOR, ASRL, AOR, AAND, +}; +static Opclass opOAUIPC = { + "$i(PC),d", + 0, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI, +}; +static Opclass opOOP_IMM_32 = { + "$i,s,d", + 0x20, 0, 0, 0, 0, 0, ASRAW, 0, 0, + 0, AADDW, ASLLW, 0, 0, 0, ASRLW, 0, 0, +}; +static Opclass opOSTORE = { + "2,a", + 0, AMOVB, AMOVH, AMOVW, AMOV, 0, 0, 0, 0, +}; +static Opclass opOSTORE_FP = { + "f2,a", + 0, 0, 0, AMOVF, AMOVD, 0, 0, 0, 0, +}; +static Opclass opOAMO = { + "7,2,s,d", + 0x04, 0, 0, ASWAP_W,ASWAP_D,0, 0, 0, 0, + 0x08, 0, 0, ALR_W, ALR_D, 0, 0, 0, 0, + 0x0C, 0, 0, ASC_W, ASC_D, 0, 0, 0, 0, + 0, 0, 0, AAMO_W, AAMO_D, 0, 0, 0, 0, +}; +static Opclass opOOP = { + "2,s,d", + 0x01, AMUL, AMULH, AMULHSU,AMULHU, ADIV, ADIVU, AREM, AREMU, + 0x20, ASUB, 0, 0, 0, 0, ASRA, 0, 0, + 0, AADD, ASLL, ASLT, ASLTU, AXOR, ASRL, AOR, AAND, +}; +static Opclass opOLUI = { + "$i,d", + 0, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI, +}; +static Opclass opOOP_32 = { + "2,s,d", + 0x01, AMULW, 0, 0, 0, ADIVW, ADIVUW, AREMW, AREMUW, + 0x20, ASUBW, 0, 0, 0, 0, ASRAW, 0, 0, + 0, AADDW, ASLLW, 0, 0, 0, ASRLW, 0, 0, +}; +static Opclass opOBRANCH = { + "2,s,p", + 0, ABEQ, ABNE, 0, 0, ABLT, ABGE, ABLTU, ABGEU, +}; +static Opclass opOJALR = { + "d,a", + 0, AJALR, AJALR, AJALR, AJALR, AJALR, AJALR, AJALR, AJALR, +}; +static Opclass opOJAL = { + "d,p", + 0, AJAL, AJAL, AJAL, AJAL, AJAL, AJAL, AJAL, AJAL, +}; +static Opclass opOSYSTEM = { + "", + 0, ASYS, ACSRRW, ACSRRS, ACSRRC, 0, ACSRRWI,ACSRRSI,ACSRRCI, +}; +static char fmtcsr[] = "c,s,d"; +static char fmtcsri[] = "c,js,d"; +static char *fmtOSYSTEM[8] = { + "$i", fmtcsr, fmtcsr, fmtcsr, "", fmtcsri, fmtcsri, fmtcsri, +}; +static Opclass opOOP_FP = { + "fs,fd", + 0x0, AADDF, ASUBF, AMULF, ADIVF, AMOVF, 0, 0, 0, + 0x1, AMOVDF, 0, 0, 0, 0, 0, 0, 0, + 0x2, ACMPLEF,ACMPLTF,ACMPEQF,0, 0, 0, 0, 0, + 0x3, AMOVFW, 0, AMOVFV, 0, AMOVWF, AMOVUF, AMOVVF, AMOVUVF, +}; +static Opclass opOOP_DP = { + "f2,fs,fd", + 0x0, AADDD, ASUBD, AMULD, ADIVD, AMOVD, 0, 0, 0, + 0x1, AMOVFD, 0, 0, 0, 0, 0, 0, 0, + 0x2, ACMPLED,ACMPLTD,ACMPEQD,0, 0, 0, 0, 0, + 0x3, AMOVDW, 0, AMOVDV, 0, AMOVWD, AMOVUD, AMOVVD, AMOVUVD, +}; + +typedef struct Compclass Compclass; +struct Compclass { + char *fmt; + uchar immbits[18]; +}; + +static Compclass rv32compressed[0x2D] = { +/* 00-07 ([1:0] = 0) ([15:13] = 0-7) */ + {"ADDI4SPN $i,d", 22, 6, 5, 11, 12, 7, 8, 9, 10}, /* 12:5 → 5:4|9:6|2|3 */ + {"FLD a,fd", 24, 10, 11, 12, 5, 6}, /* 12:10|6:5 → 5:3|7:6 */ + {"LW a,d", 25, 6, 10, 11, 12, 5}, /* 12:10|6:5 → 5:2|6 */ + {"FLW a,fd", 25, 6, 10, 11, 12, 5}, /* 12:10|6:5 → 5:2|6 rv32 */ + {"? ", 0}, + {"FSD f2,a", 24, 10, 11, 12, 5, 6}, /* 12:10|6:5 → 5:3|7:6 */ + {"SW 2,a", 25, 6, 10, 11, 12, 5}, /* 12:10|6:5 → 5:2|6 */ + {"FSW f2,a", 25, 6, 10, 11, 12, 5}, /* 12:10|6:5 → 5:2|6 rv32 */ + +/* 08-0F ([1:0] = 1) ([15:13] = 0-7 not 4) */ + {"ADDI $i,d", ~26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → * 5:0 */ + {"JAL p", ~20, 3, 4, 5, 11, 2, 7, 6, 9, 10, 8, 12}, /* 12:2 → * 11|4|9:8|10|6|7|3:1|5 rv32 D*/ + {"LI $i,d", ~26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → * 5:0 */ + {"LUI $i,d", ~14, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → * 17:12 */ + {"? ", 0}, + {"J p", ~20, 3, 4, 5, 11, 2, 7, 6, 9, 10, 8, 12}, /* 12:2 → * 11|4|9:8|10|6|7|3:1|5 */ + {"BEQZ s,p", ~23, 3, 4, 10, 11, 2, 5, 6, 12}, /* 12:10|6:2 → * 8|4|3|7:6|2:1|5 */ + {"BNEZ s,p", ~23, 3, 4, 10, 11, 2, 5, 6, 12}, /* 12:10|6:2 → * 8|4|3|7:6|2:1|5 */ + +/* 10-17 ([1:0] = 2) ([15:13] = 0-7 not 4) */ + {"SLLI $i,d", 26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → 5:0 */ + {"FLDSP i,fd", 23, 5, 6, 12, 2, 3, 4}, /* 12|6:2 → 5:3|8:6 */ + {"LWSP i,d", 24, 4, 5, 6, 12, 2, 3}, /* 12|6:2 → 5:2|7:6 */ + {"FLWSP i,fd", 24, 4, 5, 6, 12, 2, 3}, /* 12|6:2 → 5:2|7:6 rv32 */ + {"? ", 0}, + {"FSDSP f2,$i", 23, 10, 11, 12, 7, 8, 9}, /* 12:7 → 5:3|8:6 */ + {"SWSP 2,$i", 24, 9, 10, 11, 12, 7, 8}, /* 12:7 → 5:2|7:6 */ + {"FSWSP f2,$i", 24, 9, 10, 11, 12, 7, 8}, /* 12:7 → 5:2|7:6 rv32 */ + +/* 18-1A ([1:0] = 1) ([15:13] = 4) ([11:10] = 0-2) */ + {"SRLI $i,d", 26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → 5:0 */ + {"SRAI $i,d", 26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → 5:0 */ + {"ANDI $i,d", ~26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → * 5:0 */ + +/* 1B-22 ([1:0] = 1) ([15:13] = 4) ([11:10] = 3) ([12] = 0-1) ([6:5] = 0-3) */ + {"SUB 2,d", 0}, + {"XOR 2,d", 0}, + {"OR 2,d", 0}, + {"AND 2,d", 0}, + {"SUBW 2,d", 0}, /* rv64 */ + {"ADDW 2,d", 0}, /* rv64 */ + {"? ", 0}, + {"? ", 0}, + +/* 23-26 ([1:0] = 2) ([15:13] = 4) ((rs2 != 0) = 0-1) */ + {"JR s", 0}, + {"MV 2,d", 0}, + {"JALR s", 0}, + {"ADD 2,d", 0}, + +/* 27-27 ([1:0] = 1) ([15:13] = 3) ( rd = 2) */ + {"ADDI16SP $i", ~22, 6, 2, 5, 3, 4, 12}, /* 12|6:2 → * 9|4|6|8:7|5 */ + +/* 28-2C rv64 alternates */ + {"LD a,d", 24, 10, 11, 12, 5, 6}, /* 12:10|6:5 → 5:3|7:6 */ + {"SD 2,a", 24, 10, 11, 12, 5, 6}, /* 12:10|6:5 → 5:3|7:6 */ + {"ADDIW $i,d", ~26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → * 5:0 */ + {"LDSP i,d", 23, 5, 6, 12, 2, 3, }, /* 12|6:2 → 5:3|8:6 */ + {"SDSP 2,i", 23, 10, 11, 12, 7, 8, 9} /* 12:7 → 5:3|8:6 */ +}; + +/* map major opcodes to opclass table */ +static Opclass *opclass[32] = { + [OLOAD] &opOLOAD, + [OLOAD_FP] &opOLOAD_FP, + [OMISC_MEM] &opOMISC_MEM, + [OOP_IMM] &opOOP_IMM, + [OAUIPC] &opOAUIPC, + [OOP_IMM_32] &opOOP_IMM_32, + [OSTORE] &opOSTORE, + [OSTORE_FP] &opOSTORE_FP, + [OAMO] &opOAMO, + [OOP] &opOOP, + [OLUI] &opOLUI, + [OOP_FP] &opOOP_FP, + [OOP_32] &opOOP_32, + [OBRANCH] &opOBRANCH, + [OJALR] &opOJALR, + [OJAL] &opOJAL, + [OSYSTEM] &opOSYSTEM, +}; + +/* + * Print value v as name[+offset] + */ +static int +gsymoff(char *buf, int n, ulong v, int space) +{ + Symbol s; + int r; + long delta; + + r = delta = 0; /* to shut compiler up */ + if (v) { + r = findsym(v, space, &s); + if (r) + delta = v-s.value; + if (delta < 0) + delta = -delta; + } + if (v == 0 || r == 0 || delta >= 4096) + return snprint(buf, n, "#%lux", v); + if (strcmp(s.name, ".string") == 0) + return snprint(buf, n, "#%lux", v); + if (!delta) + return snprint(buf, n, "%s", s.name); + if (s.type != 't' && s.type != 'T') + return snprint(buf, n, "%s+%llux", s.name, v-s.value); + else + return snprint(buf, n, "#%lux", v); +} + +#pragma varargck argpos bprint 2 + +static void +bprint(Instr *i, char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + i->curr = vseprint(i->curr, i->end, fmt, arg); + va_end(arg); +} + +static void +format(Instr *i, char *opcode, char *f) +{ + int c; + long imm; + char reg; + + reg = 'R'; + if(opcode != nil){ + bprint(i, "%s", opcode); + if(f == 0) + return; + bprint(i, "\t"); + }else + bprint(i, "C."); + for(; (c = *f); f++){ + switch(c){ + default: + bprint(i, "%c", c); + break; + case ' ': + bprint(i, "\t"); + break; + case 'f': + reg = 'F'; + break; + case 'j': + reg = '$'; + break; + case 's': + bprint(i, "%c%d", reg, i->rs1); + reg = 'R'; + break; + case '2': + bprint(i, "%c%d", reg, i->rs2); + reg = 'R'; + break; + case '3': + bprint(i, "%c%d", reg, i->rs3); + break; + case 'd': + bprint(i, "%c%d", reg, i->rd); + reg = 'R'; + break; + case 'i': + imm = i->imm; + if(imm < 0) + bprint(i, "-%lux", -imm); + else + bprint(i, "%lux", imm); + break; + case 'p': + imm = i->addr + i->imm; + i->curr += gsymoff(i->curr, i->end-i->curr, imm, CANY); + break; + case 'a': + if(i->rs1 == REGSB && mach->sb){ + i->curr += gsymoff(i->curr, i->end-i->curr, i->imm+mach->sb, CANY); + bprint(i, "(SB)"); + break; + } + bprint(i, "%lx(R%d)", i->imm, i->rs1); + break; + case '7': + bprint(i, "%ux", i->func7); + break; + case 'c': + bprint(i, "CSR(%lx)", i->imm&0xFFF); + break; + } + } +} + +static int +badinst(Instr *i) +{ + format(i, "???", 0); + return 4; +} + +static long +immshuffle(uint w, uchar *p) +{ + int shift, i; + ulong imm; + + shift = *p++; + imm = 0; + while((i = *p++) != 0){ + imm >>= 1; + if((w>>i) & 0x01) + imm |= (1<<31); + } + if(shift & 0x80) + imm = (long)imm >> (shift ^ 0xFF); + else + imm >>= shift; + return imm; +} + +static int +decompress(Instr *i) +{ + ushort w; + int op, aop; + Compclass *cop; + + w = i->w; + i->n = 2; + i->func3 = (w>>13)&0x7; + op = w&0x3; + i->op = op; + switch(op){ + case 0: + i->rd = 8 + ((w>>2)&0x7); + i->rs1 = 8 + ((w>>7)&0x7); + i->rs2 = i->rd; + break; + case 1: + i->rd = (w>>7)&0x1F; + if((i->func3&0x4) != 0) + i->rd = 8 + (i->rd&0x7); + i->rs1 = i->rd; + i->rs2 = 8 + ((w>>2)&0x7); + break; + case 2: + i->rd = (w>>7)&0x1F; + i->rs1 = i->rd; + i->rs2 = (w>>2)&0x1F; + } + aop = (op << 3) + i->func3; + if((aop & 0x7) == 4){ + switch(op){ + case 1: + aop = 0x18 + ((w>>10) & 0x7); + if(aop == 0x1B) + aop += (w>>5) & 0x3; + break; + case 2: + aop = 0x23 + ((w>>11) & 0x2) + (i->rs2 != 0); + break; + } + } + if(aop == 0x0B && i->rd == 2) + aop = 0x27; + if(i->rv64) switch(aop){ + case 0x03: aop = 0x28; break; + case 0x07: aop = 0x29; break; + case 0x09: aop = 0x2A; break; + case 0x13: aop = 0x2B; break; + case 0x17: aop = 0x2C; break; + } + cop = &rv32compressed[aop]; + i->fmt = cop->fmt; + i->imm = immshuffle(w, cop->immbits); + return 2; +} + +static int +decode(Map *map, uvlong pc, Instr *i) +{ + ulong w; + int op; + + if(get4(map, pc, &w) < 0) { + werrstr("can't read instruction: %r"); + return -1; + } + i->addr = pc; + i->map = map; + if((w&0x3) != 3){ + i->w = w & 0xFFFF; + return decompress(i); + } + i->w = w; + i->n = 4; + op = (w&0x7F); + i->op = op; + i->func3 = (w>>12)&0x7; + i->func7 = (w>>25)&0x7F; + i->rs1 = (w>>15)&0x1F; + i->rs2 = (w>>20)&0x1F; + i->rs3 = (w>>27)&0x1F; + i->rd = (w>>7)&0x1F; +#define FIELD(hi,lo,off) (w>>(lo-off))&(((1<<(hi-lo+1))-1)<>(lo-off)) + switch(op>>2) { + case OSTORE: /* S-type */ + case OSTORE_FP: + i->imm = SFIELD(25,5) | FIELD(11,7,0); + break; + case OBRANCH: /* B-type */ + i->imm = SFIELD(31,12) | LFIELD(7,7,11) | FIELD(30,25,5) | FIELD(11,8,1); + break; + case OOP_IMM: /* I-type */ + case OOP_IMM_32: + if(i->func3 == 1 || i->func3 == 5){ /* special case ASL/ASR */ + i->imm = FIELD(25,20,0); + break; + } + /* fall through */ + case OLOAD: + case OLOAD_FP: + case OMISC_MEM: + case OJALR: + case OSYSTEM: + i->imm = SFIELD(20,0); + break; + case OAUIPC: /* U-type */ + case OLUI: + i->imm = SFIELD(12,12); + break; + case OJAL: /* J-type */ + i->imm = SFIELD(31,20) | FIELD(19,12,12) | FIELD(20,20,11) | FIELD(30,21,1); + break; + } + return 4; +} + +static int +pseudo(Instr *i, int aop) +{ + char *op; + + switch(aop){ + case AJAL: + if(i->rd == 0){ + format(i, "JMP", "p"); + return 1; + } + break; + case AJALR: + if(i->rd == 0){ + format(i, "JMP", "a"); + return 1; + } + break; + case AADD: + if((i->op>>2) == OOP_IMM){ + op = i->rv64 ? "MOV" : "MOVW"; + if(i->rs1 == 0) + format(i, op, "$i,d"); + else if(i->rs1 == REGSB && mach->sb && i->rd != REGSB) + format(i, op, "$a,d"); + else if(i->imm == 0) + format(i, op, "s,d"); + else break; + return 1; + } + break; + } + return 0; +} + +static int +mkinstr(Instr *i) +{ + Opclass *oc; + Optab *o; + char *fmt; + int aop; + + if((i->op&0x3) != 0x3){ + format(i, nil, i->fmt); + return 2; + } + oc = opclass[i->op>>2]; + if(oc == 0) + return badinst(i); + fmt = oc->fmt; + if(oc == &opOSYSTEM) + fmt = fmtOSYSTEM[i->func3]; + if(oc == &opOOP_FP){ + if(i->func7 & 1) + oc = &opOOP_DP; + o = &oc->tab[i->func7>>5]; + switch(o->func7){ + case 0: + fmt = "f2,fs,fd"; + /* fall through */ + default: + aop = o->op[(i->func7>>2)&0x7]; + if((i->func7&~1) == 0x10){ + if(i->func3 == 0 && i->rs1 == i->rs2) + fmt = "fs,fd"; + else + aop = 0; + } + break; + case 2: + aop = o->op[i->func3]; + break; + case 3: + if(i->func7 & 0x10) + return badinst(i); + aop = o->op[(i->func7>>1)&0x4 | (i->rs2&0x3)]; + if(i->func7 & 0x8) + fmt = "s,fd"; + else + fmt = "fs,d"; + break; + } + if(aop == 0) + return badinst(i); + format(i, anames[aop], fmt); + return 4; + } + o = oc->tab; + while(o->func7 != 0 && (i->func7 != o->func7 || o->op[i->func3] == 0)) + o++; + if((aop = o->op[i->func3]) == 0) + return badinst(i); + if(pseudo(i, aop)) + return 4; + format(i, anames[aop], fmt); + return 4; +} + +static int +riscvdas(Map *map, uvlong pc, char modifier, char *buf, int n) +{ + Instr i; + + USED(modifier); + i.rv64 = 0; + i.curr = buf; + i.end = buf+n; + if(decode(map, pc, &i) < 0) + return -1; + return mkinstr(&i); +} + +static int +riscv64das(Map *map, uvlong pc, char modifier, char *buf, int n) +{ + Instr i; + + USED(modifier); + i.rv64 = 1; + i.curr = buf; + i.end = buf+n; + if(decode(map, pc, &i) < 0) + return -1; + return mkinstr(&i); +} + +static int +riscvhexinst(Map *map, uvlong pc, char *buf, int n) +{ + Instr i; + + i.curr = buf; + i.end = buf+n; + if(decode(map, pc, &i) < 0) + return -1; + if(i.end-i.curr > 2*i.n) + i.curr = _hexify(buf, i.w, 2*i.n - 1); + *i.curr = 0; + return i.n; +} + +static int +riscvinstlen(Map *map, uvlong pc) +{ + Instr i; + + return decode(map, pc, &i); +} + +static char* +riscvexcep(Map* m, Rgetter r) +{ + return "Trap"; +} + +/* + * Debugger interface + */ +Machdata riscvmach = +{ + {0x3a, 0xa0, 0x3d, 0x00}, /* break point */ + 4, /* break point size */ + + leswab, /* short to local byte order */ + leswal, /* long to local byte order */ + leswav, /* long to local byte order */ + risctrace, /* C traceback */ + riscframe, /* Frame finder */ + riscvexcep, /* print exception */ + 0, /* breakpoint fixup */ + 0, /* single precision float printer */ + 0, /* double precisioin float printer */ + 0, /* following addresses */ + riscvdas, /* symbolic disassembly */ + riscvhexinst, /* hex disassembly */ + riscvinstlen, /* instruction size */ +}; + +Machdata riscv64mach = +{ + {0x3a, 0xa0, 0x3d, 0x00}, /* break point */ + 4, /* break point size */ + + leswab, /* short to local byte order */ + leswal, /* long to local byte order */ + leswav, /* long to local byte order */ + risctrace, /* C traceback */ + riscframe, /* Frame finder */ + riscvexcep, /* print exception */ + 0, /* breakpoint fixup */ + 0, /* single precision float printer */ + 0, /* double precisioin float printer */ + 0, /* following addresses */ + riscv64das, /* symbolic disassembly */ + riscvhexinst, /* hex disassembly */ + riscvinstlen, /* instruction size */ +}; diff --git a/utils/libmach/iobj.c b/utils/libmach/iobj.c new file mode 100644 index 00000000..a789f30e --- /dev/null +++ b/utils/libmach/iobj.c @@ -0,0 +1,134 @@ +/* + * iobj.c - identify and parse a riscv object file + */ +#include +#include +#include +#include "ic/i.out.h" +#include "obj.h" + +typedef struct Addr Addr; +struct Addr +{ + char type; + char sym; + char name; +}; +static Addr addr(Biobuf*); +static char type2char(int); +static void skip(Biobuf*, int); + +int +_isi(char *s) +{ + return s[0] == ANAME /* ANAME */ + && s[1] == D_FILE /* type */ + && s[2] == 1 /* sym */ + && s[3] == '<'; /* name of file */ +} + +int +_readi(Biobuf *bp, Prog *p) +{ + int as, n; + Addr a; + + as = Bgetc(bp); /* as */ + if(as < 0) + return 0; + p->kind = aNone; + p->sig = 0; + if(as == ANAME || as == ASIGNAME){ + if(as == ASIGNAME){ + Bread(bp, &p->sig, 4); + p->sig = leswal(p->sig); + } + p->kind = aName; + p->type = type2char(Bgetc(bp)); /* type */ + p->sym = Bgetc(bp); /* sym */ + n = 0; + for(;;) { + as = Bgetc(bp); + if(as < 0) + return 0; + n++; + if(as == 0) + break; + } + p->id = malloc(n); + if(p->id == 0) + return 0; + Bseek(bp, -n, 1); + if(Bread(bp, p->id, n) != n) + return 0; + return 1; + } + if(as == ATEXT) + p->kind = aText; + else if(as == AGLOBL) + p->kind = aData; + skip(bp, 5); /* reg(1), lineno(4) */ + a = addr(bp); + addr(bp); + if(a.type != D_OREG || a.name != D_STATIC && a.name != D_EXTERN) + p->kind = aNone; + p->sym = a.sym; + return 1; +} + +static Addr +addr(Biobuf *bp) +{ + Addr a; + long off; + + a.type = Bgetc(bp); /* a.type */ + skip(bp,1); /* reg */ + a.sym = Bgetc(bp); /* sym index */ + a.name = Bgetc(bp); /* sym type */ + switch(a.type){ + default: + case D_NONE: case D_REG: case D_FREG: + break; + case D_OREG: + case D_CONST: + case D_BRANCH: + case D_CTLREG: + off = Bgetc(bp); + off |= Bgetc(bp) << 8; + off |= Bgetc(bp) << 16; + off |= Bgetc(bp) << 24; + if(off < 0) + off = -off; + if(a.sym && (a.name==D_PARAM || a.name==D_AUTO)) + _offset(a.sym, off); + break; + case D_VCONST: + case D_SCONST: + skip(bp, NSNAME); + break; + case D_FCONST: + skip(bp, 8); + break; + } + return a; +} + +static char +type2char(int t) +{ + switch(t){ + case D_EXTERN: return 'U'; + case D_STATIC: return 'b'; + case D_AUTO: return 'a'; + case D_PARAM: return 'p'; + default: return UNKNOWN; + } +} + +static void +skip(Biobuf *bp, int n) +{ + while (n-- > 0) + Bgetc(bp); +} diff --git a/utils/libmach/j.c b/utils/libmach/j.c new file mode 100644 index 00000000..26c8c4c8 --- /dev/null +++ b/utils/libmach/j.c @@ -0,0 +1,70 @@ +/* + * RISC-V RV64 definition + */ +#include +#include +#include "uregj.h" +#include + +#define REGOFF(x) offsetof(struct Ureg, x) +#define REGSIZE sizeof(struct Ureg) + +Reglist riscv64reglist[] = { + {"PC", REGOFF(pc), RINT, 'X'}, + {"SP", REGOFF(r27), RINT, 'X'}, + {"R31", REGOFF(r31), RINT, 'X'}, + {"R30", REGOFF(r30), RINT, 'X'}, + {"R28", REGOFF(r28), RINT, 'X'}, + {"R27", REGOFF(r27), RINT, 'X'}, + {"R26", REGOFF(r26), RINT, 'X'}, + {"R25", REGOFF(r25), RINT, 'X'}, + {"R24", REGOFF(r24), RINT, 'X'}, + {"R23", REGOFF(r23), RINT, 'X'}, + {"R22", REGOFF(r22), RINT, 'X'}, + {"R21", REGOFF(r21), RINT, 'X'}, + {"R20", REGOFF(r20), RINT, 'X'}, + {"R19", REGOFF(r19), RINT, 'X'}, + {"R18", REGOFF(r18), RINT, 'X'}, + {"R17", REGOFF(r17), RINT, 'X'}, + {"R16", REGOFF(r16), RINT, 'X'}, + {"R15", REGOFF(r15), RINT, 'X'}, + {"R14", REGOFF(r14), RINT, 'X'}, + {"R13", REGOFF(r13), RINT, 'X'}, + {"R12", REGOFF(r12), RINT, 'X'}, + {"R11", REGOFF(r11), RINT, 'X'}, + {"R10", REGOFF(r10), RINT, 'X'}, + {"R9", REGOFF(r9), RINT, 'X'}, + {"R8", REGOFF(r8), RINT, 'X'}, + {"R7", REGOFF(r7), RINT, 'X'}, + {"R6", REGOFF(r6), RINT, 'X'}, + {"R5", REGOFF(r5), RINT, 'X'}, + {"R4", REGOFF(r4), RINT, 'X'}, + {"R3", REGOFF(r3), RINT, 'X'}, + {"R2", REGOFF(r2), RINT, 'X'}, + {"R1", REGOFF(r1), RINT, 'X'}, + { 0 } +}; + + /* the machine description */ +Mach mriscv64 = +{ + "riscv64", + MRISCV64, /* machine type */ + riscv64reglist, /* register set */ + REGSIZE, /* register set size */ + 0, /* fp register set size */ + "PC", /* name of PC */ + "SP", /* name of SP */ + "R1", /* name of link register */ + "setSB", /* static base register name */ + 0, /* static base register value */ + 0x1000, /* page size */ + 0x80000000ULL, /* kernel base */ + 0xC0000000ULL, /* kernel text mask */ + 0x3FFFFFFFULL, /* user stack top */ + 2, /* quantization of pc */ + 8, /* szaddr */ + 8, /* szreg */ + 4, /* szfloat */ + 8, /* szdouble */ +}; diff --git a/utils/libmach/mkfile b/utils/libmach/mkfile index 9114ed66..ac474d15 100644 --- a/utils/libmach/mkfile +++ b/utils/libmach/mkfile @@ -7,12 +7,15 @@ OFILES=\ 6.$O\ 8.$O\ 9.$O\ + i.$O\ + j.$O\ k.$O\ q.$O\ t.$O\ v.$O\ 5db.$O\ 8db.$O\ + idb.$O\ kdb.$O\ qdb.$O\ tdb.$O\ @@ -21,6 +24,7 @@ OFILES=\ 6obj.$O\ 8obj.$O\ 9obj.$O\ + iobj.$O\ kobj.$O\ qobj.$O\ vobj.$O\ diff --git a/utils/libmach/obj.c b/utils/libmach/obj.c index 7b1f1b62..5f6e6250 100644 --- a/utils/libmach/obj.c +++ b/utils/libmach/obj.c @@ -28,13 +28,15 @@ int _is5(char*), _isk(char*), _isq(char*), _isv(char*), + _isi(char*), _read5(Biobuf*, Prog*), _read6(Biobuf*, Prog*), _read8(Biobuf*, Prog*), _read9(Biobuf*, Prog*), _readk(Biobuf*, Prog*), _readq(Biobuf*, Prog*), - _readv(Biobuf*, Prog*); + _readv(Biobuf*, Prog*), + _readi(Biobuf*, Prog*); typedef struct Obj Obj; typedef struct Symtab Symtab; @@ -64,6 +66,8 @@ static Obj obj[] = /*[ObjAmd64]*/ "amd64 .6", _is6, _read6, /*[ObjSpim]*/ {0, 0,}, /*[ObjPower64]*/ "power64 .9", _is9, _read9, + /*[ObjRiscv]*/ "riscv .i", _isi, _readi, + /*[ObjRiscv64]*/ "riscv64 .j", _isi, _readi, /*[Maxobjtype]*/ 0, 0 }; diff --git a/utils/libmach/setmach.c b/utils/libmach/setmach.c index 7247881c..8bfd3c18 100644 --- a/utils/libmach/setmach.c +++ b/utils/libmach/setmach.c @@ -16,9 +16,9 @@ struct machtab }; extern Mach mmips, msparc, mi386, mamd64, - marm, mmips2be, mmips2le, mpower, mpower64; + marm, mmips2be, mmips2le, mpower, mpower64, mriscv, mriscv64; extern Machdata mipsmach, sparcmach, i386mach, - armmach, mipsmach2le, powermach; + armmach, mipsmach2le, powermach, riscvmach, riscv64mach; /* * machine selection table. machines with native disassemblers should @@ -99,6 +99,18 @@ Machtab machines[] = APOWER64, &mpower64, &powermach, }, + { "riscv", + FRISCV, + FRISCVB, + ARISCV, + &mriscv, + &riscvmach, }, + { "riscv64", + FRISCV64, + FRISCV64B, + ARISCV64, + &mriscv64, + &riscv64mach, }, { 0 }, /*the terminator*/ }; diff --git a/utils/libmach/uregi.h b/utils/libmach/uregi.h new file mode 100644 index 00000000..27d202b6 --- /dev/null +++ b/utils/libmach/uregi.h @@ -0,0 +1,57 @@ +struct Ureg +{ + union { + uintptr pc; + uintptr regs[1]; + }; + uintptr r1; /* link */ + union{ + uintptr r2; + uintptr sp; + uintptr usp; + }; + uintptr r3; /* sb */ + uintptr r4; + uintptr r5; + uintptr r6; /* up in kernel */ + uintptr r7; /* m in kernel */ + union{ + uintptr r8; + uintptr arg; + uintptr ret; + }; + uintptr r9; + uintptr r10; + uintptr r11; + uintptr r12; + uintptr r13; + uintptr r14; + uintptr r15; + uintptr r16; + uintptr r17; + uintptr r18; + uintptr r19; + uintptr r20; + uintptr r21; + uintptr r22; + uintptr r23; + uintptr r24; + uintptr r25; + uintptr r26; + uintptr r27; + uintptr r28; + uintptr r29; + uintptr r30; + uintptr r31; + + /* csrs: generally supervisor ones */ + uintptr status; + uintptr ie; + union { + uintptr cause; + uintptr type; + }; + uintptr tval; /* faulting address */ + + uintptr curmode; +}; diff --git a/utils/libmach/uregj.h b/utils/libmach/uregj.h new file mode 100644 index 00000000..593da792 --- /dev/null +++ b/utils/libmach/uregj.h @@ -0,0 +1,39 @@ +struct Ureg +{ + u64int pc; + u64int r1; + union{ + u64int r2; + u64int sp; + u64int usp; + }; + u64int r3; + u64int r4; + u64int r5; + u64int r6; + u64int r7; + u64int r8; + u64int r9; + u64int r10; + u64int r11; + u64int r12; + u64int r13; + u64int r14; + u64int r15; + u64int r16; + u64int r17; + u64int r18; + u64int r19; + u64int r20; + u64int r21; + u64int r22; + u64int r23; + u64int r24; + u64int r25; + u64int r26; + u64int r27; + u64int r28; + u64int r29; + u64int r30; + u64int r31; +}; -- cgit v1.2.3 From 6e84dc968bc4eaf047fbefcba2f670940718dda8 Mon Sep 17 00:00:00 2001 From: Richard Miller Date: Mon, 9 Nov 2020 11:36:14 +0000 Subject: Add toolchain for riscv (ia ic il) and riscv64 (ja jc jl) Because the rv64 ISA is very nearly a proper superset of rv32, the compilers ic and jc are actually the same program, which compiles to .i or .j depending on how it is invoked; similarly for ia/ja and il/jl. It is also possible to invoke ia/ic/il with a '-j' option to specify 64-bit behaviour. --- utils/ia/a.h | 181 ++++++ utils/ia/a.y | 514 +++++++++++++++++ utils/ia/lex.c | 642 ++++++++++++++++++++++ utils/ia/mkfile | 31 ++ utils/ic/cgen.c | 1207 ++++++++++++++++++++++++++++++++++++++++ utils/ic/enam.c | 117 ++++ utils/ic/gc.h | 336 ++++++++++++ utils/ic/i.out.h | 224 ++++++++ utils/ic/list.c | 230 ++++++++ utils/ic/machcap.c | 9 + utils/ic/mkenam | 15 + utils/ic/mkfile | 48 ++ utils/ic/mul.c | 608 +++++++++++++++++++++ utils/ic/peep.c | 706 ++++++++++++++++++++++++ utils/ic/reg.c | 1160 +++++++++++++++++++++++++++++++++++++++ utils/ic/sgen.c | 259 +++++++++ utils/ic/swt.c | 620 +++++++++++++++++++++ utils/ic/txt.c | 1473 +++++++++++++++++++++++++++++++++++++++++++++++++ utils/il/asm.c | 966 ++++++++++++++++++++++++++++++++ utils/il/compress.c | 270 +++++++++ utils/il/l.h | 359 ++++++++++++ utils/il/list.c | 252 +++++++++ utils/il/mkfile | 39 ++ utils/il/noop.c | 341 ++++++++++++ utils/il/obj.c | 1517 +++++++++++++++++++++++++++++++++++++++++++++++++++ utils/il/optab.c | 194 +++++++ utils/il/pass.c | 589 ++++++++++++++++++++ utils/il/span.c | 525 ++++++++++++++++++ utils/mkfile | 3 + 29 files changed, 13435 insertions(+) create mode 100644 utils/ia/a.h create mode 100644 utils/ia/a.y create mode 100644 utils/ia/lex.c create mode 100644 utils/ia/mkfile create mode 100644 utils/ic/cgen.c create mode 100644 utils/ic/enam.c create mode 100644 utils/ic/gc.h create mode 100644 utils/ic/i.out.h create mode 100644 utils/ic/list.c create mode 100644 utils/ic/machcap.c create mode 100644 utils/ic/mkenam create mode 100644 utils/ic/mkfile create mode 100644 utils/ic/mul.c create mode 100644 utils/ic/peep.c create mode 100644 utils/ic/reg.c create mode 100644 utils/ic/sgen.c create mode 100644 utils/ic/swt.c create mode 100644 utils/ic/txt.c create mode 100644 utils/il/asm.c create mode 100644 utils/il/compress.c create mode 100644 utils/il/l.h create mode 100644 utils/il/list.c create mode 100644 utils/il/mkfile create mode 100644 utils/il/noop.c create mode 100644 utils/il/obj.c create mode 100644 utils/il/optab.c create mode 100644 utils/il/pass.c create mode 100644 utils/il/span.c diff --git a/utils/ia/a.h b/utils/ia/a.h new file mode 100644 index 00000000..32c27f17 --- /dev/null +++ b/utils/ia/a.h @@ -0,0 +1,181 @@ +#include +#include +#include "../ic/i.out.h" + +#ifndef EXTERN +#define EXTERN extern +#endif + +typedef struct Sym Sym; +typedef struct Gen Gen; +typedef struct Io Io; +typedef struct Hist Hist; + +#define MAXALIGN 7 +#define FPCHIP 1 +#define NSYMB 500 +#define BUFSIZ 8192 +#define HISTSZ 20 +#define NINCLUDE 10 +#define NHUNK 10000 +#define EOF (-1) +#define IGN (-2) +#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff) +#define NHASH 503 +#define STRINGSZ 200 +#define NMACRO 10 + +struct Sym +{ + Sym* link; + char* macro; + long value; + ushort type; + char *name; + char sym; +}; +#define S ((Sym*)0) + +EXTERN struct +{ + char* p; + int c; +} fi; + +struct Io +{ + Io* link; + char b[BUFSIZ]; + char* p; + short c; + short f; +}; +#define I ((Io*)0) + +EXTERN struct +{ + Sym* sym; + short type; +} h[NSYM]; + +struct Gen +{ + Sym *sym; + long offset; + short type; + short reg; + short name; + double dval; + char sval[8]; + vlong vval; +}; + +struct Hist +{ + Hist* link; + char* name; + long line; + long offset; +}; +#define H ((Hist*)0) + +enum +{ + CLAST, + CMACARG, + CMACRO, + CPREPROC, +}; + +EXTERN char debug[256]; +EXTERN Sym* hash[NHASH]; +EXTERN char* Dlist[30]; +EXTERN int nDlist; +EXTERN Hist* ehist; +EXTERN int newflag; +EXTERN Hist* hist; +EXTERN char* hunk; +EXTERN char* include[NINCLUDE]; +EXTERN Io* iofree; +EXTERN Io* ionext; +EXTERN Io* iostack; +EXTERN long lineno; +EXTERN int nerrors; +EXTERN long nhunk; +EXTERN int ninclude; +EXTERN int nosched; +EXTERN Gen nullgen; +EXTERN char* outfile; +EXTERN int pass; +EXTERN char* pathname; +EXTERN long pc; +EXTERN int peekc; +EXTERN int sym; +EXTERN char symb[NSYMB]; +EXTERN int thechar; +EXTERN char* thestring; +EXTERN long thunk; +EXTERN Biobuf obuf; + +void* alloc(long); +void* allocn(void*, long, long); +void errorexit(void); +void pushio(void); +void newio(void); +void newfile(char*, int); +Sym* slookup(char*); +Sym* lookup(void); +void syminit(Sym*); +long yylex(void); +int getc(void); +int getnsc(void); +void unget(int); +int escchar(int); +void cinit(void); +void pinit(char*); +void cclean(void); +void outcode(int, Gen*, int, Gen*); +void zname(char*, int, int); +void zaddr(Gen*, int); +void ieeedtod(Ieee*, double); +int filbuf(void); +Sym* getsym(void); +void domacro(void); +void macund(void); +void macdef(void); +void macexpand(Sym*, char*); +void macinc(void); +void macprag(void); +void maclin(void); +void macif(int); +void macend(void); +void dodefine(char*); +void prfile(long); +void outhist(void); +void linehist(char*, int); +void gethunk(void); +void yyerror(char*, ...); +int yyparse(void); +void setinclude(char*); +int assemble(char*); + +/* + * system-dependent stuff from ../cc/compat.c + */ + +enum /* keep in synch with ../cc/cc.h */ +{ + Plan9 = 1<<0, + Unix = 1<<1, + Windows = 1<<2 +}; +int mywait(int*); +int mycreat(char*, int); +int systemtype(int); +int pathchar(void); +char* mygetwd(char*, int); +int myexec(char*, char*[]); +int mydup(int, int); +int myfork(void); +int mypipe(int*); +void* mysbrk(ulong); diff --git a/utils/ia/a.y b/utils/ia/a.y new file mode 100644 index 00000000..e7470860 --- /dev/null +++ b/utils/ia/a.y @@ -0,0 +1,514 @@ +%{ +#include "a.h" +%} +%union +{ + Sym *sym; + vlong lval; + double dval; + char sval[8]; + Gen gen; +} +%left '|' +%left '^' +%left '&' +%left '<' '>' +%left '+' '-' +%left '*' '/' '%' +%token LADD LMUL LBEQ LBR LBRET LCALL LFLT2 LFLT3 +%token LMOVB LMOVBU LMOVW LMOVF LLUI LSYS LSYS0 LCSR LSWAP LAMO +%token LCONST LSP LSB LFP LPC LREG LFREG LR FR LCTL +%token LDATA LTEXT LWORD +%token LSCONST +%token LFCONST +%token LNAME LLAB LVAR +%type con expr pointer offset sreg freg oprrr +%type rreg dreg ctlreg drreg +%type addr name oreg rel imm ximm fimm +%% +prog: +| prog line + +line: + LLAB ':' + { + if($1->value != pc) + yyerror("redeclaration of %s", $1->name); + $1->value = pc; + } + line +| LNAME ':' + { + $1->type = LLAB; + $1->value = pc; + } + line +| LNAME '=' expr ';' + { + $1->type = LVAR; + $1->value = $3; + } +| LVAR '=' expr ';' + { + if($1->value != $3) + yyerror("redeclaration of %s", $1->name); + $1->value = $3; + } +| ';' +| inst ';' +| error ';' + +inst: + LADD imm ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| oprrr rreg ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LADD imm ',' sreg ',' rreg + { + outcode($1, &$2, $4, &$6); + } +| oprrr rreg ',' sreg ',' rreg + { + outcode($1, &$2, $4, &$6); + } + +| LFLT2 drreg ',' drreg + { + outcode($1, &$2, NREG, &$4); + } +| LFLT3 drreg ',' freg ',' drreg + { + outcode($1, &$2, $4, &$6); + } + +| LBEQ rreg ',' sreg ',' rel + { + outcode($1, &$2, $4, &$6); + } + +| LBEQ rreg ',' rel + { + Gen regzero; + regzero = nullgen; + regzero.type = D_REG; + regzero.reg = 0; + outcode($1, ®zero, $2.reg, &$4); + } + +| LBR rel + { + outcode($1, &nullgen, NREG, &$2); + } + +| LBR oreg + { + outcode($1, &nullgen, NREG, &$2); + } + + +| LBRET + { + outcode($1, &nullgen, NREG, &nullgen); + } + +| LCALL sreg ',' addr + { + outcode($1, &nullgen, $2, &$4); + } +| LCALL sreg ',' rel + { + outcode($1, &nullgen, $2, &$4); + } + +| LMOVB addr ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVBU addr ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVB rreg ',' addr + { + outcode($1, &$2, NREG, &$4); + } + +| LMOVF addr ',' dreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVF dreg ',' addr + { + outcode($1, &$2, NREG, &$4); + } +| LMOVF dreg ',' dreg + { + outcode($1, &$2, NREG, &$4); + } + + +| LMOVW imm ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW ximm ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW rreg ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW addr ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW rreg ',' addr + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW rreg ',' ctlreg + { + Gen regzero; + regzero = nullgen; + regzero.type = D_REG; + regzero.reg = 0; + outcode(ACSRRW, &$4, $2.reg, ®zero); + } +| LMOVW imm ',' ctlreg + { + Gen regzero; + int r = $2.offset; + if(r < 0 || r >= NREG) + yyerror("immediate value out of range"); + regzero = nullgen; + regzero.type = D_REG; + regzero.reg = 0; + outcode(ACSRRWI, &$4, r, ®zero); + } +| LMOVW ctlreg ',' rreg + { + outcode(ACSRRS, &$2, REGZERO, &$4); + } + +| LLUI name ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LLUI imm ',' rreg + { + outcode($1, &$2, NREG, &$4); + } + + +| LSYS imm + { + outcode($1, &nullgen, NREG, &$2); + } + +| LSYS0 + { + Gen syscon; + syscon = nullgen; + syscon.type = D_CONST; + syscon.offset = $1; + outcode(ASYS, &nullgen, NREG, &syscon); + } + +| LCSR ctlreg ',' sreg ',' rreg + { + outcode($1, &$2, $4, &$6); + } + +| LCSR ctlreg ',' '$' con ',' rreg + { + if($5 < 0 || $5 >= NREG) + yyerror("immediate value out of range"); + outcode($1 + (ACSRRWI-ACSRRW), &$2, $5, &$7); + } + +| LSWAP rreg ',' sreg ',' rreg + { + outcode($1, &$2, $4, &$6); + } + +| LAMO con ',' rreg ',' sreg ',' rreg + { + outcode($1, &$4, ($2<<16)|$6, &$8); + } + +| LTEXT name ',' imm + { + outcode($1, &$2, NREG, &$4); + } +| LTEXT name ',' con ',' imm + { + outcode($1, &$2, $4, &$6); + } + +| LDATA name '/' con ',' imm + { + outcode($1, &$2, $4, &$6); + } +| LDATA name '/' con ',' ximm + { + outcode($1, &$2, $4, &$6); + } +| LDATA name '/' con ',' fimm + { + outcode($1, &$2, $4, &$6); + } + +| LWORD imm + { + outcode($1, &nullgen, NREG, &$2); + } + +rel: + con '(' LPC ')' + { + $$ = nullgen; + $$.type = D_BRANCH; + $$.offset = $1 + pc; + } +| LNAME offset + { + $$ = nullgen; + if(pass == 2) + yyerror("undefined label: %s", $1->name); + $$.type = D_BRANCH; + $$.sym = $1; + $$.offset = $2; + } +| LLAB offset + { + $$ = nullgen; + $$.type = D_BRANCH; + $$.sym = $1; + $$.offset = $1->value + $2; + } + +oprrr: + LADD +| LMUL + +addr: + oreg +| name + +oreg: + '(' sreg ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.reg = $2; + $$.offset = 0; + } +| con '(' sreg ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.reg = $3; + $$.offset = $1; + } + +name: + con '(' pointer ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = $3; + $$.sym = S; + $$.offset = $1; + } +| LNAME offset '(' pointer ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = $4; + $$.sym = $1; + $$.offset = $2; + } +| LNAME '<' '>' offset '(' LSB ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = D_STATIC; + $$.sym = $1; + $$.offset = $4; + } + +offset: + { + $$ = 0; + } +| '+' con + { + $$ = $2; + } +| '-' con + { + $$ = -$2; + } + +pointer: + LSB +| LSP +| LFP + +rreg: + sreg + { + $$ = nullgen; + $$.type = D_REG; + $$.reg = $1; + } + +dreg: + freg + { + $$ = nullgen; + $$.type = D_FREG; + $$.reg = $1; + } + +drreg: + dreg +| rreg + +sreg: + LREG +| LR '(' expr ')' + { + if($3 < 0 || $3 >= NREG) + yyerror("register value out of range"); + $$ = $3; + } + +freg: + LFREG +| FR '(' expr ')' + { + if($3 < 0 || $3 >= NREG) + yyerror("register value out of range"); + $$ = $3; + } + +ctlreg: + LCTL '(' expr ')' + { + if($3 < 0 || $3 >= 0xFFF) + yyerror("CSR value out of range"); + $$ = nullgen; + $$.type = D_CTLREG; + $$.offset = $3; + } + +ximm: + '$' addr + { + $$ = $2; + $$.type = D_CONST; + } +| '$' LSCONST + { + $$ = nullgen; + $$.type = D_SCONST; + memcpy($$.sval, $2, sizeof($$.sval)); + } + +fimm: + '$' LFCONST + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = $2; + } +| '$' '-' LFCONST + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = -$3; + } + +imm: + '$' con + { + $$ = nullgen; + $$.type = D_CONST; + $$.offset = $2; + if(thechar == 'j' && (vlong)$$.offset != $2){ + $$.type = D_VCONST; + $$.vval = $2; + } + } + +con: + LCONST +| LVAR + { + $$ = $1->value; + } +| '-' con + { + $$ = -$2; + } +| '+' con + { + $$ = $2; + } +| '~' con + { + $$ = ~$2; + } +| '(' expr ')' + { + $$ = $2; + } + +expr: + con +| expr '+' expr + { + $$ = $1 + $3; + } +| expr '-' expr + { + $$ = $1 - $3; + } +| expr '*' expr + { + $$ = $1 * $3; + } +| expr '/' expr + { + $$ = $1 / $3; + } +| expr '%' expr + { + $$ = $1 % $3; + } +| expr '<' '<' expr + { + $$ = $1 << $4; + } +| expr '>' '>' expr + { + $$ = $1 >> $4; + } +| expr '&' expr + { + $$ = $1 & $3; + } +| expr '^' expr + { + $$ = $1 ^ $3; + } +| expr '|' expr + { + $$ = $1 | $3; + } diff --git a/utils/ia/lex.c b/utils/ia/lex.c new file mode 100644 index 00000000..ac12f42d --- /dev/null +++ b/utils/ia/lex.c @@ -0,0 +1,642 @@ +#include +#define EXTERN +#include "a.h" +#include "y.tab.h" + +void +main(int argc, char *argv[]) +{ + char *p; + int nout, nproc, status, i, c; + + thechar = 'i'; + p = strrchr(argv[0], '/'); + if(p == nil) + p = argv[0]; + else + p++; + if(*p == 'j') + thechar = 'j'; + memset(debug, 0, sizeof(debug)); + cinit(); + outfile = 0; + include[ninclude++] = "."; + ARGBEGIN { + default: + c = ARGC(); + if(c >= 0 || c < sizeof(debug)) + debug[c] = 1; + break; + + case 'o': + outfile = ARGF(); + break; + + case 'D': + p = ARGF(); + if(p) + Dlist[nDlist++] = p; + break; + + case 'I': + p = ARGF(); + setinclude(p); + break; + + } ARGEND + if(*argv == 0) { + print("usage: %ca [-options] file.s\n", thechar); + errorexit(); + } + if(debug['j']) + thechar = 'j'; + thestring = (thechar == 'j'? "riscv64" : "riscv"); + if(argc > 1 && systemtype(Windows)){ + print("can't assemble multiple files on windows\n"); + errorexit(); + } + if(argc > 1 && !systemtype(Windows)) { + nproc = 1; + if(p = getenv("NPROC")) + nproc = atol(p); /* */ + c = 0; + nout = 0; + for(;;) { + while(nout < nproc && argc > 0) { + i = myfork(); + if(i < 0) { + i = mywait(&status); + if(i < 0) + errorexit(); + if(status) + c++; + nout--; + continue; + } + if(i == 0) { + print("%s:\n", *argv); + if(assemble(*argv)) + errorexit(); + exits(0); + } + nout++; + argc--; + argv++; + } + i = mywait(&status); + if(i < 0) { + if(c) + errorexit(); + exits(0); + } + if(status) + c++; + nout--; + } + } + if(assemble(argv[0])) + errorexit(); + exits(0); +} + +int +assemble(char *file) +{ + char ofile[100], incfile[20], *p; + int i, of; + + strcpy(ofile, file); + p = utfrrune(ofile, pathchar()); + if(p) { + include[0] = ofile; + *p++ = 0; + } else + p = ofile; + if(outfile == 0) { + outfile = p; + if(outfile){ + p = utfrrune(outfile, '.'); + if(p) + if(p[1] == 's' && p[2] == 0) + p[0] = 0; + p = utfrune(outfile, 0); + p[0] = '.'; + p[1] = thechar; + p[2] = 0; + } else + outfile = "/dev/null"; + } + p = getenv("INCLUDE"); + if(p) { + setinclude(p); + } else { + if(systemtype(Plan9)) { + sprint(incfile,"/%s/include", thestring); + setinclude(strdup(incfile)); + } + } + + of = mycreat(outfile, 0664); + if(of < 0) { + yyerror("%ca: cannot create %s", thechar, outfile); + errorexit(); + } + Binit(&obuf, of, OWRITE); + + pass = 1; + pinit(file); + if(thechar == 'j') + dodefine("XLEN=8"); + else + dodefine("XLEN=4"); + for(i=0; itype = itab[i].type; + s->value = itab[i].value; + } + + pathname = allocn(pathname, 0, 100); + if(mygetwd(pathname, 99) == 0) { + pathname = allocn(pathname, 100, 900); + if(mygetwd(pathname, 999) == 0) + strcpy(pathname, "/???"); + } +} + +void +syminit(Sym *s) +{ + + s->type = LNAME; + s->value = 0; +} + +void +cclean(void) +{ + + outcode(AEND, &nullgen, NREG, &nullgen); + Bflush(&obuf); +} + +void +zname(char *n, int t, int s) +{ + + Bputc(&obuf, ANAME); + Bputc(&obuf, t); /* type */ + Bputc(&obuf, s); /* sym */ + while(*n) { + Bputc(&obuf, *n); + n++; + } + Bputc(&obuf, 0); +} + +void +zaddr(Gen *a, int s) +{ + vlong v; + long l; + int i; + char *n; + Ieee e; + + Bputc(&obuf, a->type); + Bputc(&obuf, a->reg); + Bputc(&obuf, s); + Bputc(&obuf, a->name); + switch(a->type) { + default: + print("unknown type %d\n", a->type); + exits("arg"); + + case D_NONE: + case D_REG: + case D_FREG: + break; + + case D_CTLREG: + case D_OREG: + case D_CONST: + case D_BRANCH: + l = a->offset; + Bputc(&obuf, l); + Bputc(&obuf, l>>8); + Bputc(&obuf, l>>16); + Bputc(&obuf, l>>24); + break; + + case D_VCONST: + v = a->vval; + Bputc(&obuf, v); + Bputc(&obuf, v>>8); + Bputc(&obuf, v>>16); + Bputc(&obuf, v>>24); + Bputc(&obuf, v>>32); + Bputc(&obuf, v>>40); + Bputc(&obuf, v>>48); + Bputc(&obuf, v>>56); + break; + + case D_SCONST: + n = a->sval; + for(i=0; idval); + Bputc(&obuf, e.l); + Bputc(&obuf, e.l>>8); + Bputc(&obuf, e.l>>16); + Bputc(&obuf, e.l>>24); + Bputc(&obuf, e.h); + Bputc(&obuf, e.h>>8); + Bputc(&obuf, e.h>>16); + Bputc(&obuf, e.h>>24); + break; + } +} + +void +outcode(int a, Gen *g1, int reg, Gen *g2) +{ + int sf, st, t; + Sym *s; + + if(pass == 1) + goto out; +jackpot: + sf = 0; + s = g1->sym; + while(s != S) { + sf = s->sym; + if(sf < 0 || sf >= NSYM) + sf = 0; + t = g1->name; + if(h[sf].type == t) + if(h[sf].sym == s) + break; + zname(s->name, t, sym); + s->sym = sym; + h[sym].sym = s; + h[sym].type = t; + sf = sym; + sym++; + if(sym >= NSYM) + sym = 1; + break; + } + st = 0; + s = g2->sym; + while(s != S) { + st = s->sym; + if(st < 0 || st >= NSYM) + st = 0; + t = g2->name; + if(h[st].type == t) + if(h[st].sym == s) + break; + zname(s->name, t, sym); + s->sym = sym; + h[sym].sym = s; + h[sym].type = t; + st = sym; + sym++; + if(sym >= NSYM) + sym = 1; + if(st == sf) + goto jackpot; + break; + } + Bputc(&obuf, a); + Bputc(&obuf, reg); + Bputc(&obuf, lineno); + Bputc(&obuf, lineno>>8); + Bputc(&obuf, lineno>>16); + Bputc(&obuf, lineno>>24); + zaddr(g1, sf); + zaddr(g2, st); + +out: + if(a != AGLOBL && a != ADATA) + pc++; +} + +void +outhist(void) +{ + Gen g; + Hist *h; + char *p, *q, *op, c; + int n; + + g = nullgen; + c = pathchar(); + for(h = hist; h != H; h = h->link) { + p = h->name; + op = 0; + /* on windows skip drive specifier in pathname */ + if(systemtype(Windows) && p && p[1] == ':'){ + p += 2; + c = *p; + } + if(p && p[0] != c && h->offset == 0 && pathname){ + /* on windows skip drive specifier in pathname */ + if(systemtype(Windows) && pathname[1] == ':') { + op = p; + p = pathname+2; + c = *p; + } else if(pathname[0] == c){ + op = p; + p = pathname; + } + } + while(p) { + q = strchr(p, c); + if(q) { + n = q-p; + if(n == 0){ + n = 1; /* leading "/" */ + *p = '/'; /* don't emit "\" on windows */ + } + q++; + } else { + n = strlen(p); + q = 0; + } + if(n) { + Bputc(&obuf, ANAME); + Bputc(&obuf, D_FILE); /* type */ + Bputc(&obuf, 1); /* sym */ + Bputc(&obuf, '<'); + Bwrite(&obuf, p, n); + Bputc(&obuf, 0); + } + p = q; + if(p == 0 && op) { + p = op; + op = 0; + } + } + g.offset = h->offset; + + Bputc(&obuf, AHISTORY); + Bputc(&obuf, 0); + Bputc(&obuf, h->line); + Bputc(&obuf, h->line>>8); + Bputc(&obuf, h->line>>16); + Bputc(&obuf, h->line>>24); + zaddr(&nullgen, 0); + zaddr(&g, 0); + } +} + +#include "../cc/lexbody" +#include "../cc/macbody" diff --git a/utils/ia/mkfile b/utils/ia/mkfile new file mode 100644 index 00000000..05ccc4dc --- /dev/null +++ b/utils/ia/mkfile @@ -0,0 +1,31 @@ +<../../mkconfig + +TARG=ia # also makes ja (for riscv64) + +OFILES=\ + y.tab.$O\ + lex.$O\ + +HFILES=\ + ../ic/i.out.h\ + y.tab.h\ + a.h\ + +YFILES=a.y\ + +LIBS=cc bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin +<$ROOT/mkfiles/mkone-$SHELLTYPE + +YFLAGS=-D1 -d +CFLAGS= $CFLAGS -I../include + +lex.$O: ../cc/macbody ../cc/lexbody + +$ROOT/$OBJDIR/lib/libcc.a: + cd ../cc + mk $MKFLAGS install + mk $MKFLAGS clean + +install:V: $BIN/ja diff --git a/utils/ic/cgen.c b/utils/ic/cgen.c new file mode 100644 index 00000000..a8bf5ea1 --- /dev/null +++ b/utils/ic/cgen.c @@ -0,0 +1,1207 @@ +#include "gc.h" + +void +cgen(Node *n, Node *nn) +{ + Node *l, *r; + Prog *p1; + Node nod, nod1, nod2, nod3, nod4; + int o; + long v, curs; + + if(debug['g']) { + prtree(nn, "cgen lhs"); + prtree(n, "cgen"); + } + if(n == Z || n->type == T) + return; + if(typecmplx[n->type->etype]) { + sugen(n, nn, n->type->width); + return; + } + l = n->left; + r = n->right; + o = n->op; + if(n->addable >= INDEXED) { + if(nn == Z) { + switch(o) { + default: + nullwarn(Z, Z); + break; + case OINDEX: + nullwarn(l, r); + break; + } + return; + } + gmove(n, nn); + return; + } + curs = cursafe; + + if(n->complex >= FNX) + if(l->complex >= FNX) + if(r != Z && r->complex >= FNX) + switch(o) { + default: + regret(&nod, r); + cgen(r, &nod); + + regsalloc(&nod1, r); + gopcode(OAS, &nod, Z, &nod1); + + regfree(&nod); + nod = *n; + nod.right = &nod1; + cgen(&nod, nn); + return; + + case OFUNC: + case OCOMMA: + case OANDAND: + case OOROR: + case OCOND: + case ODOT: + break; + } + + switch(o) { + default: + diag(n, "unknown op in cgen: %O", o); + break; + + case OAS: + if(l->op == OBIT) + goto bitas; + if(l->addable >= INDEXED && l->complex < FNX) { + if(nn != Z || r->addable < INDEXED) { + if(r->complex >= FNX && nn == Z) + regret(&nod, r); + else + regalloc(&nod, r, nn); + cgen(r, &nod); + gmove(&nod, l); + if(nn != Z) + gmove(&nod, nn); + regfree(&nod); + } else + gmove(r, l); + break; + } + if(l->complex >= r->complex) { + reglcgen(&nod1, l, Z); + if(r->addable >= INDEXED) { + gmove(r, &nod1); + if(nn != Z) + gmove(r, nn); + regfree(&nod1); + break; + } + regalloc(&nod, r, nn); + cgen(r, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + reglcgen(&nod1, l, Z); + } + gmove(&nod, &nod1); + regfree(&nod); + regfree(&nod1); + break; + + bitas: + n = l->left; + regalloc(&nod, r, nn); + if(l->complex >= r->complex) { + reglcgen(&nod1, n, Z); + cgen(r, &nod); + } else { + cgen(r, &nod); + reglcgen(&nod1, n, Z); + } + regalloc(&nod2, n, Z); + gopcode(OAS, &nod1, Z, &nod2); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + + case OBIT: + if(nn == Z) { + nullwarn(l, Z); + break; + } + bitload(n, &nod, Z, Z, nn); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + break; + + case OADD: + case OSUB: + case OAND: + case OOR: + case OXOR: + case OLSHR: + case OASHL: + case OASHR: + /* + * immediate operands + */ + if(nn != Z) + if(sconst(r)) + if(!typefd[n->type->etype]) + if(r->vconst >= -2048 && r->vconst < 2048) { + cgen(l, nn); + if(r->vconst == 0) + if(o != OAND) + break; + if(nn != Z) + gopcode(o, r, Z, nn); + break; + } + + case OLMUL: + case OLDIV: + case OLMOD: + case OMUL: + case ODIV: + case OMOD: + if(nn == Z) { + nullwarn(l, r); + break; + } + if(o == OMUL || o == OLMUL) { + if(mulcon(n, nn)) + break; + } + if(l->complex >= r->complex) { + regalloc(&nod, l, nn); + cgen(l, &nod); + regalloc(&nod1, r, Z); + cgen(r, &nod1); + gopcode(o, &nod1, Z, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + regalloc(&nod1, l, Z); + cgen(l, &nod1); + gopcode(o, &nod, &nod1, &nod); + } + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + regfree(&nod1); + break; + + case OASLSHR: + case OASASHL: + case OASASHR: + case OASAND: + case OASADD: + case OASSUB: + case OASXOR: + case OASOR: + if(l->op == OBIT) + goto asbitop; + if(sconst(r)) + if(!typefd[n->type->etype]) { + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + regalloc(&nod, r, nn); + gopcode(OAS, &nod2, Z, &nod); + gopcode(o, r, Z, &nod); + gopcode(OAS, &nod, Z, &nod2); + + regfree(&nod); + if(l->addable < INDEXED) + regfree(&nod2); + break; + } + + case OASLMUL: + case OASLDIV: + case OASLMOD: + case OASMUL: + case OASDIV: + case OASMOD: + if(l->op == OBIT) + goto asbitop; + if(l->complex >= r->complex) { + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + regalloc(&nod1, r, Z); + cgen(r, &nod1); + } else { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + } + + regalloc(&nod, n, nn); + gmove(&nod2, &nod); + gopcode(o, &nod1, Z, &nod); + gmove(&nod, &nod2); + if(nn != Z) + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + regfree(&nod1); + if(l->addable < INDEXED) + regfree(&nod2); + break; + + asbitop: + regalloc(&nod4, n, nn); + if(l->complex >= r->complex) { + bitload(l, &nod, &nod1, &nod2, &nod4); + regalloc(&nod3, r, Z); + cgen(r, &nod3); + } else { + regalloc(&nod3, r, Z); + cgen(r, &nod3); + bitload(l, &nod, &nod1, &nod2, &nod4); + } + gmove(&nod, &nod4); + gopcode(o, &nod3, Z, &nod4); + regfree(&nod3); + gmove(&nod4, &nod); + regfree(&nod4); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + + case OADDR: + if(nn == Z) { + nullwarn(l, Z); + break; + } + lcgen(l, nn); + break; + + case OFUNC: + if(l->complex >= FNX) { + if(l->op != OIND) + diag(n, "bad function call"); + + regret(&nod, l->left); + cgen(l->left, &nod); + regsalloc(&nod1, l->left); + gopcode(OAS, &nod, Z, &nod1); + regfree(&nod); + + nod = *n; + nod.left = &nod2; + nod2 = *l; + nod2.left = &nod1; + nod2.complex = 1; + cgen(&nod, nn); + + return; + } + o = reg[REGARG]; + gargs(r, &nod, &nod1); + if(l->addable < INDEXED) { + reglcgen(&nod, l, Z); + gopcode(OFUNC, Z, Z, &nod); + regfree(&nod); + } else + gopcode(OFUNC, Z, Z, l); + if(REGARG) + if(o != reg[REGARG]) + reg[REGARG]--; + if(nn != Z) { + regret(&nod, n); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + } + break; + + case OIND: + if(nn == Z) { + nullwarn(l, Z); + break; + } + regialloc(&nod, n, nn); + r = l; + while(r->op == OADD) + r = r->right; + if(sconst(r)) { + v = r->vconst; + r->vconst = 0; + cgen(l, &nod); + nod.xoffset += v; + r->vconst = v; + } else + cgen(l, &nod); + regind(&nod, n); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + break; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OLO: + case OLS: + case OHI: + case OHS: + if(nn == Z) { + nullwarn(l, r); + break; + } + boolgen(n, 1, nn); + break; + + case OANDAND: + case OOROR: + boolgen(n, 1, nn); + if(nn == Z) + patch(p, pc); + break; + + case ONOT: + if(nn == Z) { + nullwarn(l, Z); + break; + } + boolgen(n, 1, nn); + break; + + case OCOMMA: + cgen(l, Z); + cgen(r, nn); + break; + + case OCAST: + if(nn == Z) { + nullwarn(l, Z); + break; + } + /* + * convert from types l->n->nn + */ + if(nocast(l->type, n->type)) { + if(nocast(n->type, nn->type)) { + cgen(l, nn); + break; + } + } + regalloc(&nod, l, nn); + cgen(l, &nod); +#ifdef maybe + if(l->op == ONAME || l->op == OINDREG || l->op == OIND) + if(typechlp[l->type->etype] && typeilp[nn->type->etype]){ + /* load effectively does the cast */ + nod.type = types[TLONG]; + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + break; + } +#endif + regalloc(&nod1, n, &nod); + gopcode(OAS, &nod, Z, &nod1); + gopcode(OAS, &nod1, Z, nn); + regfree(&nod1); + regfree(&nod); + break; + + case ODOT: + sugen(l, nodrat, l->type->width); + if(nn != Z) { + warn(n, "non-interruptable temporary"); + nod = *nodrat; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod.xoffset += (long)r->vconst; + nod.type = n->type; + cgen(&nod, nn); + } + break; + + case OCOND: + bcgen(l, 1); + p1 = p; + cgen(r->left, nn); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + cgen(r->right, nn); + patch(p1, pc); + break; + + case OPOSTINC: + case OPOSTDEC: + v = 1; + if(l->type->etype == TIND) + v = l->type->link->width; + if(o == OPOSTDEC) + v = -v; + if(l->op == OBIT) + goto bitinc; + if(nn == Z) + goto pre; + + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + + regalloc(&nod, l, nn); + gopcode(OAS, &nod2, Z, &nod); + regalloc(&nod1, l, Z); + if(typefd[l->type->etype]) { + regalloc(&nod3, l, Z); + if(v < 0) { + gopcode(OAS, nodfconst(-v), Z, &nod3); + gopcode(OSUB, &nod3, &nod, &nod1); + } else { + gopcode(OAS, nodfconst(v), Z, &nod3); + gopcode(OADD, &nod3, &nod, &nod1); + } + regfree(&nod3); + } else + gopcode(OADD, nodconst(v), &nod, &nod1); + gopcode(OAS, &nod1, Z, &nod2); + + regfree(&nod); + regfree(&nod1); + if(l->addable < INDEXED) + regfree(&nod2); + break; + + case OPREINC: + case OPREDEC: + v = 1; + if(l->type->etype == TIND) + v = l->type->link->width; + if(o == OPREDEC) + v = -v; + if(l->op == OBIT) + goto bitinc; + + pre: + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + + regalloc(&nod, l, nn); + gopcode(OAS, &nod2, Z, &nod); + if(typefd[l->type->etype]) { + regalloc(&nod3, l, Z); + if(v < 0) { + gopcode(OAS, nodfconst(-v), Z, &nod3); + gopcode(OSUB, &nod3, Z, &nod); + } else { + gopcode(OAS, nodfconst(v), Z, &nod3); + gopcode(OADD, &nod3, Z, &nod); + } + regfree(&nod3); + } else + gopcode(OADD, nodconst(v), Z, &nod); + gopcode(OAS, &nod, Z, &nod2); + if(nn && l->op == ONAME) /* in x=++i, emit USED(i) */ + gins(ANOP, l, Z); + + regfree(&nod); + if(l->addable < INDEXED) + regfree(&nod2); + break; + + bitinc: + if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) { + bitload(l, &nod, &nod1, &nod2, Z); + gopcode(OAS, &nod, Z, nn); + gopcode(OADD, nodconst(v), Z, &nod); + bitstore(l, &nod, &nod1, &nod2, Z); + break; + } + bitload(l, &nod, &nod1, &nod2, nn); + gopcode(OADD, nodconst(v), Z, &nod); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + } + cursafe = curs; +} + +void +reglcgen(Node *t, Node *n, Node *nn) +{ + Node *r; + long v; + + regialloc(t, n, nn); + if(n->op == OIND) { + r = n->left; + while(r->op == OADD) + r = r->right; + if(sconst(r)) { + v = r->vconst; + r->vconst = 0; + lcgen(n, t); + t->xoffset += v; + r->vconst = v; + regind(t, n); + return; + } + } + lcgen(n, t); + regind(t, n); +} + +void +lcgen(Node *n, Node *nn) +{ + Prog *p1; + Node nod; + + if(debug['g']) { + prtree(nn, "lcgen lhs"); + prtree(n, "lcgen"); + } + if(n == Z || n->type == T) + return; + if(nn == Z) { + nn = &nod; + regalloc(&nod, n, Z); + } + switch(n->op) { + default: + if(n->addable < INDEXED) { + diag(n, "unknown op in lcgen: %O", n->op); + break; + } + nod = *n; + nod.op = OADDR; + nod.left = n; + nod.right = Z; + nod.type = types[TIND]; + gopcode(OAS, &nod, Z, nn); + break; + + case OCOMMA: + cgen(n->left, n->left); + lcgen(n->right, nn); + break; + + case OIND: + cgen(n->left, nn); + break; + + case OCOND: + bcgen(n->left, 1); + p1 = p; + lcgen(n->right->left, nn); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + lcgen(n->right->right, nn); + patch(p1, pc); + break; + } +} + +/* + * Conditional branch if bool(n) != true + */ +void +bcgen(Node *n, int true) +{ + + if(n->type == T) + gbranch(OGOTO); + else + boolgen(n, true, Z); +} + +/* + * If nn == Z, conditional branch if bool(n) != true + * If nn != Z, assign n = (bool(n) == true) + */ +void +boolgen(Node *n, int true, Node *nn) +{ + int o; + Prog *p1, *p2; + Node *l, *r, nod, nod1, nod2; + long curs; + + if(debug['g']) { + prtree(nn, "boolgen lhs"); + prtree(n, true? "boolgen true" : "boolgen false"); + } + curs = cursafe; + l = n->left; + r = n->right; + switch(n->op) { + + default: + regalloc(&nod, n, nn); + cgen(n, &nod); + if(nn == Z) { + o = true? OEQ : ONE; + if(typefd[n->type->etype]) { + nodreg(&nod1, n, NREG+FREGZERO); + gopcode(o, &nod, &nod1, Z); + } else + gopcode(o, &nod, Z, Z); + regfree(&nod); + break; + } + if(typefd[n->type->etype]) { + regalloc(&nod2, nn, nn); + o = true? ONE : OEQ; + nodreg(&nod1, n, NREG+FREGZERO); + gopcode(o, &nod, &nod1, &nod2); + gopcode(OAS, &nod2, Z, nn); + regfree(&nod2); + regfree(&nod); + break; + } + if(true) + gopcode(OCOND, &nod, nodconst(0), &nod); + else + gopcode(OCOND, nodconst(1), &nod, &nod); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + break; + + case OCONST: + o = vconst(n); + if(!true) + o = !o; + gbranch(OGOTO); + if(o) { + p1 = p; + gbranch(OGOTO); + patch(p1, pc); + } + goto com; + + case OCOMMA: + cgen(l, Z); + boolgen(r, true, nn); + break; + + case ONOT: + boolgen(l, !true, nn); + break; + + case OCOND: + bcgen(l, 1); + p1 = p; + bcgen(r->left, true); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + bcgen(r->right, !true); + patch(p2, pc); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + patch(p2, pc); + goto com; + + case OANDAND: + if(!true) + goto caseor; + + caseand: + bcgen(l, true); + p1 = p; + bcgen(r, !true); + p2 = p; + patch(p1, pc); + gbranch(OGOTO); + patch(p2, pc); + goto com; + + case OOROR: + if(!true) + goto caseand; + + caseor: + bcgen(l, !true); + p1 = p; + bcgen(r, !true); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + patch(p2, pc); + goto com; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OHI: + case OHS: + case OLO: + case OLS: + o = n->op; + if(l->complex >= FNX && r->complex >= FNX) { + regret(&nod, r); + cgen(r, &nod); + regsalloc(&nod1, r); + gopcode(OAS, &nod, Z, &nod1); + regfree(&nod); + nod = *n; + nod.right = &nod1; + boolgen(&nod, true, nn); + break; + } + if(true) + o = comrel[relindex(o)]; + if(nn != Z || typefd[l->type->etype]) { + if(l->complex >= r->complex) { + regalloc(&nod1, l, nn); + cgen(l, &nod1); + regalloc(&nod, r, Z); + cgen(r, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + regalloc(&nod1, l, Z); + cgen(l, &nod1); + } + if(typefd[l->type->etype]) { + if(nn != Z) { + /* fp compare for assignment */ + regalloc(&nod2, nn, nn); + gopcode(o, &nod, &nod1, &nod2); + regfree(&nod2); + } else + /* fp compare for branch */ + gopcode(o, &nod, &nod1, Z); + regfree(&nod); + regfree(&nod1); + break; + } + /* int compare for assignment */ + switch(o) { + case OEQ: + gopcode(OSUB, &nod1, &nod, &nod); + gopcode(OCOND, &nod, nodconst(0), &nod); + break; + case ONE: + gopcode(OSUB, &nod1, &nod, &nod); + gopcode(OCOND, nodconst(1), &nod, &nod); + break; + case OLE: + gopcode(OCOMMA, &nod1, &nod, &nod); + break; + case OGT: + gopcode(OCOMMA, &nod1, &nod, &nod); + gopcode(OXOR, nodconst(1), &nod, &nod); + break; + case OLT: + gopcode(OCOMMA, &nod, &nod1, &nod); + gopcode(OXOR, nodconst(1), &nod, &nod); + break; + case OGE: + gopcode(OCOMMA, &nod, &nod1, &nod); + break; + case OLS: + gopcode(OCOND, &nod1, &nod, &nod); + break; + case OHI: + gopcode(OCOND, &nod1, &nod, &nod); + gopcode(OXOR, nodconst(1), &nod, &nod); + break; + case OLO: + gopcode(OCOND, &nod, &nod1, &nod); + gopcode(OXOR, nodconst(1), &nod, &nod); + break; + case OHS: + gopcode(OCOND, &nod, &nod1, &nod); + break; + } + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + regfree(&nod1); + break; + } + /* int compare for branch */ + if(0 && sconst(l)) { + if(l->vconst == 0) { + regalloc(&nod, r, nn); + cgen(r, &nod); + gopcode(o, l, &nod, Z); + regfree(&nod); + goto com; + } + } + if(0 && sconst(r)) { + if(r->vconst == 0) { + regalloc(&nod, l, nn); + cgen(l, &nod); + gopcode(o, &nod, r, Z); + regfree(&nod); + goto com; + } + } + if(l->complex >= r->complex) { + regalloc(&nod1, l, nn); + cgen(l, &nod1); + regalloc(&nod, r, Z); + cgen(r, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + regalloc(&nod1, l, Z); + cgen(l, &nod1); + } + + gopcode(o, &nod, &nod1, Z); + regfree(&nod); + regfree(&nod1); + + com: + if(nn != Z) { + p1 = p; + gopcode(OAS, nodconst(1), Z, nn); + gbranch(OGOTO); + p2 = p; + patch(p1, pc); + gopcode(OAS, nodconst(0), Z, nn); + patch(p2, pc); + } + break; + } + cursafe = curs; +} + +void +sugen(Node *n, Node *nn, long w) +{ + Prog *p1; + Node nod0, nod1, nod2, nod3, nod4, *l, *r; + Type *t; + long pc1; + int i, m, c; + + if(n == Z || n->type == T) + return; + if(debug['g']) { + prtree(nn, "sugen lhs"); + prtree(n, "sugen"); + } + if(nn == nodrat) + if(w > nrathole) + nrathole = w; + switch(n->op) { + case OIND: + if(nn == Z) { + nullwarn(n->left, Z); + break; + } + + default: + goto copy; + + case OCONST: + if(n->type && typev[n->type->etype]) { + if(nn == Z) { + nullwarn(n->left, Z); + break; + } + + t = nn->type; + nn->type = types[TLONG]; + reglcgen(&nod1, nn, Z); + nn->type = t; + + gopcode(OAS, nod32const(n->vconst), Z, &nod1); + nod1.xoffset += SZ_LONG; + gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1); + + regfree(&nod1); + break; + } + goto copy; + + case ODOT: + l = n->left; + sugen(l, nodrat, l->type->width); + if(nn != Z) { + warn(n, "non-interruptable temporary"); + nod1 = *nodrat; + r = n->right; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod1.xoffset += (long)r->vconst; + nod1.type = n->type; + sugen(&nod1, nn, w); + } + break; + + case OSTRUCT: + /* + * rewrite so lhs has no fn call + */ + if(nn != Z && nn->complex >= FNX) { + nod1 = *n; + nod1.type = typ(TIND, n->type); + regret(&nod2, &nod1); + lcgen(nn, &nod2); + regsalloc(&nod0, &nod1); + gopcode(OAS, &nod2, Z, &nod0); + regfree(&nod2); + + nod1 = *n; + nod1.op = OIND; + nod1.left = &nod0; + nod1.right = Z; + nod1.complex = 1; + + sugen(n, &nod1, w); + return; + } + + r = n->left; + for(t = n->type->link; t != T; t = t->down) { + l = r; + if(r->op == OLIST) { + l = r->left; + r = r->right; + } + if(nn == Z) { + cgen(l, nn); + continue; + } + /* + * hand craft *(&nn + o) = l + */ + nod0 = znode; + nod0.op = OAS; + nod0.type = t; + nod0.left = &nod1; + nod0.right = l; + + nod1 = znode; + nod1.op = OIND; + nod1.type = t; + nod1.left = &nod2; + + nod2 = znode; + nod2.op = OADD; + nod2.type = typ(TIND, t); + nod2.left = &nod3; + nod2.right = &nod4; + + nod3 = znode; + nod3.op = OADDR; + nod3.type = nod2.type; + nod3.left = nn; + + nod4 = znode; + nod4.op = OCONST; + nod4.type = nod2.type; + nod4.vconst = t->offset; + + ccom(&nod0); + acom(&nod0); + xcom(&nod0); + nod0.addable = 0; + + cgen(&nod0, Z); + } + break; + + case OAS: + if(nn == Z) { + if(n->addable < INDEXED) + sugen(n->right, n->left, w); + break; + } + sugen(n->right, nodrat, w); + warn(n, "non-interruptable temporary"); + sugen(nodrat, n->left, w); + sugen(nodrat, nn, w); + break; + + case OFUNC: + if(nn == Z) { + sugen(n, nodrat, w); + break; + } + if(nn->op != OIND) { + nn = new1(OADDR, nn, Z); + nn->type = types[TIND]; + nn->addable = 0; + } else + nn = nn->left; + n = new(OFUNC, n->left, new(OLIST, nn, n->right)); + n->type = types[TVOID]; + n->left->type = types[TVOID]; + cgen(n, Z); + break; + + case OCOND: + bcgen(n->left, 1); + p1 = p; + sugen(n->right->left, nn, w); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + sugen(n->right->right, nn, w); + patch(p1, pc); + break; + + case OCOMMA: + cgen(n->left, Z); + sugen(n->right, nn, w); + break; + } + return; + +copy: + if(nn == Z) + return; + if(n->complex >= FNX && nn->complex >= FNX) { + t = nn->type; + nn->type = types[TLONG]; + regialloc(&nod1, nn, Z); + lcgen(nn, &nod1); + regsalloc(&nod2, nn); + nn->type = t; + + gopcode(OAS, &nod1, Z, &nod2); + regfree(&nod1); + + nod2.type = typ(TIND, t); + + nod1 = nod2; + nod1.op = OIND; + nod1.left = &nod2; + nod1.right = Z; + nod1.complex = 1; + nod1.type = t; + + sugen(n, &nod1, w); + return; + } + + if(n->complex > nn->complex) { + t = n->type; + n->type = types[TLONG]; + reglcgen(&nod1, n, Z); + n->type = t; + + t = nn->type; + nn->type = types[TLONG]; + reglcgen(&nod2, nn, Z); + nn->type = t; + } else { + t = nn->type; + nn->type = types[TLONG]; + reglcgen(&nod2, nn, Z); + nn->type = t; + + t = n->type; + n->type = types[TLONG]; + reglcgen(&nod1, n, Z); + n->type = t; + } + + w /= SZ_LONG; + if(w <= 5) { + layout(&nod1, &nod2, w, 0, Z); + goto out; + } + + /* + * minimize space for unrolling loop + * 3,4,5 times. (6 or more is never minimum) + * if small structure, try 2 also. + */ + c = 0; /* set */ + m = 100; + i = 3; + if(w <= 15) + i = 2; + for(; i<=5; i++) + if(i + w%i <= m) { + c = i; + m = c + w%c; + } + + regalloc(&nod3, ®node, Z); + layout(&nod1, &nod2, w%c, w/c, &nod3); + + pc1 = pc; + layout(&nod1, &nod2, c, 0, Z); + + gopcode(OSUB, nodconst(1), Z, &nod3); + nod1.op = OREGISTER; + nod1.type = types[TIND]; + gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod1); + nod2.op = OREGISTER; + nod2.type = types[TIND]; + gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod2); + + gopcode(OEQ, &nod3, Z, Z); + p->as = ABGT; + patch(p, pc1); + + regfree(&nod3); +out: + regfree(&nod1); + regfree(&nod2); +} + +void +layout(Node *f, Node *t, int c, int cv, Node *cn) +{ + Node t1, t2; + + while(c > 3) { + layout(f, t, 2, 0, Z); + c -= 2; + } + + regalloc(&t1, ®node, Z); + regalloc(&t2, ®node, Z); + t1.type = types[TLONG]; + t2.type = types[TLONG]; + if(c > 0) { + gopcode(OAS, f, Z, &t1); + f->xoffset += SZ_LONG; + } + if(cn != Z) + gopcode(OAS, nodconst(cv), Z, cn); + if(c > 1) { + gopcode(OAS, f, Z, &t2); + f->xoffset += SZ_LONG; + } + if(c > 0) { + gopcode(OAS, &t1, Z, t); + t->xoffset += SZ_LONG; + } + if(c > 2) { + gopcode(OAS, f, Z, &t1); + f->xoffset += SZ_LONG; + } + if(c > 1) { + gopcode(OAS, &t2, Z, t); + t->xoffset += SZ_LONG; + } + if(c > 2) { + gopcode(OAS, &t1, Z, t); + t->xoffset += SZ_LONG; + } + regfree(&t1); + regfree(&t2); +} diff --git a/utils/ic/enam.c b/utils/ic/enam.c new file mode 100644 index 00000000..3c3fcbc1 --- /dev/null +++ b/utils/ic/enam.c @@ -0,0 +1,117 @@ +char* anames[] = +{ + "XXX", + "ADD", + "ADDW", + "AMO_D", + "AMO_W", + "AND", + "BEQ", + "BGE", + "BGEU", + "BLT", + "BLTU", + "BNE", + "CSRRC", + "CSRRCI", + "CSRRS", + "CSRRSI", + "CSRRW", + "CSRRWI", + "DIV", + "DIVU", + "DIVUW", + "DIVW", + "FENCE", + "FENCE_I", + "JAL", + "JALR", + "LR_D", + "LR_W", + "LUI", + "MOVB", + "MOVBU", + "MOVH", + "MOVHU", + "MOV", + "MOVW", + "MOVWU", + "MUL", + "MULH", + "MULHSU", + "MULHU", + "MULW", + "OR", + "REM", + "REMU", + "REMUW", + "REMW", + "SC_D", + "SC_W", + "SLL", + "SLLW", + "SLT", + "SLTU", + "SRA", + "SRAW", + "SRL", + "SRLW", + "SUB", + "SUBW", + "SWAP_D", + "SWAP_W", + "SYS", + "XOR", + "MOVF", + "MOVD", + "MOVFD", + "MOVDF", + "MOVWF", + "MOVUF", + "MOVFW", + "MOVWD", + "MOVUD", + "MOVDW", + "ADDF", + "ADDD", + "SUBF", + "SUBD", + "MULF", + "MULD", + "DIVF", + "DIVD", + "CMPLTF", + "CMPLTD", + "CMPEQF", + "CMPEQD", + "CMPLEF", + "CMPLED", + "BGT", + "BGTU", + "BLE", + "BLEU", + "SGT", + "SGTU", + "JMP", + "RET", + "NOP", + "DATA", + "GLOBL", + "GOK", + "HISTORY", + "NAME", + "TEXT", + "WORD", + "END", + "DYNT", + "INIT", + "SIGNAME", + "DWORD", + "MOVFV", + "MOVDV", + "MOVVF", + "MOVUVF", + "MOVVD", + "MOVUVD", + "LAST", +}; diff --git a/utils/ic/gc.h b/utils/ic/gc.h new file mode 100644 index 00000000..4d756d13 --- /dev/null +++ b/utils/ic/gc.h @@ -0,0 +1,336 @@ +#include "../cc/cc.h" +#include "../ic/i.out.h" + +/* + * zc/riscv + * RISC-V 32-bit + */ +#define SZ_CHAR 1 +#define SZ_SHORT 2 +#define SZ_INT 4 +#define SZ_LONG 4 +#define SZ_IND 4 +#define SZ_FLOAT 4 +#define SZ_VLONG 8 +#define SZ_DOUBLE 8 +#define FNX 100 + +typedef struct Adr Adr; +typedef struct Prog Prog; +typedef struct Case Case; +typedef struct C1 C1; +typedef struct Multab Multab; +typedef struct Hintab Hintab; +typedef struct Var Var; +typedef struct Reg Reg; +typedef struct Rgn Rgn; + +struct Adr +{ + long offset; + double dval; + char sval[NSNAME]; + Ieee ieee; + + Sym* sym; + char type; + char reg; + char name; + char etype; +}; +#define A ((Adr*)0) + +#define INDEXED 9 +struct Prog +{ + Adr from; + Adr to; + Prog* link; + long lineno; + char as; + char reg; +}; +#define P ((Prog*)0) + +struct Case +{ + Case* link; + vlong val; + long label; + char def; + char isv; +}; +#define C ((Case*)0) + +struct C1 +{ + vlong val; + long label; +}; + +struct Multab +{ + long val; + char code[20]; +}; + +struct Hintab +{ + ushort val; + char hint[10]; +}; + +struct Var +{ + long offset; + Sym* sym; + char name; + char etype; +}; + +struct Reg +{ + long pc; + long rpo; /* reverse post ordering */ + + Bits set; + Bits use1; + Bits use2; + + Bits refbehind; + Bits refahead; + Bits calbehind; + Bits calahead; + Bits regdiff; + Bits act; + + long regu; + long loop; /* could be shorter */ + + Reg* log5; + long active; + + Reg* p1; + Reg* p2; + Reg* p2link; + Reg* s1; + Reg* s2; + Reg* link; + Prog* prog; +}; +#define R ((Reg*)0) + +#define NRGN 600 +struct Rgn +{ + Reg* enter; + short cost; + short varno; + short regno; +}; + +EXTERN long breakpc; +EXTERN long nbreak; +EXTERN Case* cases; +EXTERN Node constnode; +EXTERN Node fconstnode; +EXTERN Node vconstnode; +EXTERN long continpc; +EXTERN long curarg; +EXTERN long cursafe; +EXTERN Prog* firstp; +EXTERN Prog* lastp; +EXTERN long maxargsafe; +EXTERN int mnstring; +EXTERN Multab multab[20]; +EXTERN int hintabsize; +EXTERN Node* nodrat; +EXTERN Node* nodret; +EXTERN Node* nodsafe; +EXTERN long nrathole; +EXTERN long nstring; +EXTERN Prog* p; +EXTERN long pc; +EXTERN Node regnode; +EXTERN Node vregnode; +EXTERN char string[NSNAME]; +EXTERN Sym* symrathole; +EXTERN Node znode; +EXTERN Prog zprog; +EXTERN int reg[NREG+NREG]; +EXTERN long exregoffset; +EXTERN long exfregoffset; + +#define BLOAD(r) band(bnot(r->refbehind), r->refahead) +#define BSTORE(r) band(bnot(r->calbehind), r->calahead) +#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z]) +#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z]) + +#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32)) + +#define CLOAD 4 +#define CREF 5 +#define CINF 1000 +#define LOOP 3 + +EXTERN Rgn region[NRGN]; +EXTERN Rgn* rgp; +EXTERN int nregion; +EXTERN int nvar; + +EXTERN Bits externs; +EXTERN Bits params; +EXTERN Bits consts; +EXTERN Bits addrs; + +EXTERN long regbits; +EXTERN long exregbits; + +EXTERN int change; +EXTERN int suppress; + +EXTERN Reg* firstr; +EXTERN Reg* lastr; +EXTERN Reg zreg; +EXTERN Reg* freer; +EXTERN Var var[NVAR]; +EXTERN long* idom; +EXTERN Reg** rpo2r; +EXTERN long maxnr; + +extern char* anames[]; +extern Hintab hintab[]; + +/* + * sgen.c + */ +void codgen(Node*, Node*); +void gen(Node*); +void noretval(int); +void xcom(Node*); +int bcomplex(Node*, Node*); +void usedset(Node*, int); + +/* + * cgen.c + */ +void cgen(Node*, Node*); +void reglcgen(Node*, Node*, Node*); +void lcgen(Node*, Node*); +void bcgen(Node*, int); +void boolgen(Node*, int, Node*); +void sugen(Node*, Node*, long); +void layout(Node*, Node*, int, int, Node*); + +/* + * txt.c + */ +void ginit(void); +void gclean(void); +void nextpc(void); +void gargs(Node*, Node*, Node*); +void garg1(Node*, Node*, Node*, int, Node**); +Node* nodconst(long); +Node* nod32const(vlong); +Node* nodfconst(double); +Node* nodgconst(vlong, Type*); +void nodreg(Node*, Node*, int); +void regret(Node*, Node*); +void regalloc(Node*, Node*, Node*); +void regfree(Node*); +void regialloc(Node*, Node*, Node*); +void regsalloc(Node*, Node*); +void regaalloc1(Node*, Node*); +void regaalloc(Node*, Node*); +void regind(Node*, Node*); +void gprep(Node*, Node*); +void raddr(Node*, Prog*); +void naddr(Node*, Adr*); +void gmove(Node*, Node*); +void gins(int a, Node*, Node*); +void gopcode(int, Node*, Node*, Node*); +int samaddr(Node*, Node*); +void gbranch(int); +void patch(Prog*, long); +int sconst(Node*); +int sval(long); +void gpseudo(int, Sym*, Node*); + +/* + * swt.c + */ +int swcmp(void*, void*); +void doswit(Node*); +void swit1(C1*, int, long, Node*); +void swit2(C1*, int, long, Node*, Node*); +void casf(void); +void bitload(Node*, Node*, Node*, Node*, Node*); +void bitstore(Node*, Node*, Node*, Node*, Node*); +long outstring(char*, long); +int mulcon(Node*, Node*); +Multab* mulcon0(long); +void nullwarn(Node*, Node*); +void gextern(Sym*, Node*, long, long); +void outcode(void); +void ieeedtod(Ieee*, double); + +/* + * list + */ +void listinit(void); +int Pconv(Fmt*); +int Aconv(Fmt*); +int Dconv(Fmt*); +int Sconv(Fmt*); +int Nconv(Fmt*); +int Bconv(Fmt*); + +/* + * reg.c + */ +Reg* rega(void); +int rcmp(void*, void*); +void regopt(Prog*); +void addmove(Reg*, int, int, int); +Bits mkvar(Adr*, int); +void prop(Reg*, Bits, Bits); +void loopit(Reg*, long); +void synch(Reg*, Bits); +ulong allreg(ulong, Rgn*); +void paint1(Reg*, int); +ulong paint2(Reg*, int); +void paint3(Reg*, int, long, int); +void addreg(Adr*, int); + +/* + * peep.c + */ +void peep(void); +void excise(Reg*); +Reg* uniqp(Reg*); +Reg* uniqs(Reg*); +int regtyp(Adr*); +int regzer(Adr*); +int anyvar(Adr*); +int subprop(Reg*); +int copyprop(Reg*); +int copy1(Adr*, Adr*, Reg*, int); +int copyu(Prog*, Adr*, Adr*); + +int copyas(Adr*, Adr*); +int copyau(Adr*, Adr*); +int copyau1(Prog*, Adr*); +int copysub(Adr*, Adr*, Adr*, int); +int copysub1(Prog*, Adr*, Adr*, int); + +long RtoB(int); +long FtoB(int); +int BtoR(long); +int BtoF(long); + +#pragma varargck type "A" int +#pragma varargck type "B" Bits +#pragma varargck type "D" Adr* +#pragma varargck type "N" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "S" char* diff --git a/utils/ic/i.out.h b/utils/ic/i.out.h new file mode 100644 index 00000000..c99a9bb4 --- /dev/null +++ b/utils/ic/i.out.h @@ -0,0 +1,224 @@ +#define NSNAME 8 +#define NSYM 50 +#define NREG 32 +#define NOPROF (1<<0) +#define DUPOK (1<<1) + +/* + * Register roles are influenced by the compressed extension: + * CIW, CL, CS and CB format use only R8-R15 + * CL and CS floating load/store use only F8-F15 + * CI and CSS load/store assume stack pointer is R2 + * C.JAL assumes link register is R1 + */ +enum +{ + REGZERO = 0, /* always zero */ + REGLINK = 1, /* call return address */ + REGSP = 2, /* stack pointer */ + REGSB = 3, /* static base */ + REGTMP = 4, /* assembler temporary */ + REGEXT = 7, /* extern reg from here down */ + REGRET = 8, /* fn return value */ + REGARG = 8, /* fn arg value */ + REGALLOC = 15, /* highest reg to allocate (allow for RV32E) */ + + FREGRET = 0, /* fn return value */ + FREGEXT = 27, /* extern reg from here down */ + FREGZERO = 28, + FREGHALF = 29, + FREGONE = 30, + FREGTWO = 31, +}; + +enum as +{ + AXXX = 0, + + /* processor instructions */ + AADD, + AADDW, + AAMO_D, + AAMO_W, + AAND, + ABEQ, + ABGE, + ABGEU, + ABLT, + ABLTU, + ABNE, + ACSRRC, + ACSRRCI, + ACSRRS, + ACSRRSI, + ACSRRW, + ACSRRWI, + ADIV, + ADIVU, + ADIVUW, + ADIVW, + AFENCE, + AFENCE_I, + AJAL, + AJALR, + ALR_D, + ALR_W, + ALUI, + AMOVB, + AMOVBU, + AMOVH, + AMOVHU, + AMOV, + AMOVW, + AMOVWU, + AMUL, + AMULH, + AMULHSU, + AMULHU, + AMULW, + AOR, + AREM, + AREMU, + AREMUW, + AREMW, + ASC_D, + ASC_W, + ASLL, + ASLLW, + ASLT, + ASLTU, + ASRA, + ASRAW, + ASRL, + ASRLW, + ASUB, + ASUBW, + ASWAP_D, + ASWAP_W, + ASYS, + AXOR, + + /* floating point */ + AMOVF, /* FLW, FSW, FSGNJ.S */ + AMOVD, /* FLD, FSD, FSGNJ.D */ + AMOVFD, /* FCVT.D.S */ + AMOVDF, /* FCVT.S.D */ + AMOVWF, /* FCVT.S.W */ + AMOVUF, /* FCVT.S.WU */ + AMOVFW, /* FCVT.W.S */ + AMOVWD, /* FCVT.D.W */ + AMOVUD, /* FCVT.D.WU */ + AMOVDW, /* FCVT.W.D */ + AADDF, /* FADD.S */ + AADDD, /* FADD.D */ + ASUBF, /* FSUB.S */ + ASUBD, /* FSUB.D */ + AMULF, /* FMUL.S */ + AMULD, /* FMUL.D */ + ADIVF, /* FDIV.S */ + ADIVD, /* FDIV.D */ + ACMPLTF, /* FLT.S */ + ACMPLTD, /* FLT.D */ + ACMPEQF, /* FEQ.S */ + ACMPEQD, /* FEQ.D */ + ACMPLEF, /* FLE.S */ + ACMPLED, /* FLE.S */ + + /* floating point instructions not included */ +/* + FMADD.S FMADD.D + FMSUB.S FMSUB.D + FNMSUB.S FNMSUB.D + FNMADD.S FNMADD.D + FSQRT.S FSQRT.D + FSGNJ.S FSGNJ.D + FSGNJN.S FSGNJN.D + FSGNNX.S FSGNNX.D + FMIN.S FMIN.D + FMAX.S FMAX.D + FMV.X.W + FCLASS.S FCLASS.D + FCVT.WU.S FCVT.WU.D + FMV.W.X + */ + + + /* pseudo-ops */ + ABGT, + ABGTU, + ABLE, + ABLEU, + ASGT, + ASGTU, + AJMP, + ARET, + ANOP, + + /* C compiler pseudo-ops */ + ADATA, + AGLOBL, + AGOK, + AHISTORY, + ANAME, + ATEXT, + AWORD, + AEND, + ADYNT, + AINIT, + ASIGNAME, + + /* RV64 extension */ + ADWORD, + AMOVFV, + AMOVDV, + AMOVVF, + AMOVUVF, + AMOVVD, + AMOVUVD, + + ALAST, +}; + +/* type/name */ +enum +{ + D_GOK = 0, + D_NONE, + +/* name */ + D_EXTERN, + D_STATIC, + D_AUTO, + D_PARAM, + +/* type */ + D_BRANCH, + D_OREG, + D_CONST, + D_FCONST, + D_SCONST, + D_REG, + D_CTLREG, + D_FREG, + D_FCREG, + D_FILE, + D_FILE1, + D_VCONST, +}; + +/* + * this is the ranlib header + */ +#define SYMDEF "__.SYMDEF" + +/* + * this is the simulated IEEE floating point + */ +typedef struct ieee Ieee; +struct ieee +{ + long l; /* contains ls-man 0xffffffff */ + long h; /* contains sign 0x80000000 + exp 0x7ff00000 + ms-man 0x000fffff */ +}; diff --git a/utils/ic/list.c b/utils/ic/list.c new file mode 100644 index 00000000..ed4656ae --- /dev/null +++ b/utils/ic/list.c @@ -0,0 +1,230 @@ +#define EXTERN +#include "gc.h" + +void +listinit(void) +{ + fmtinstall('A', Aconv); + fmtinstall('P', Pconv); + fmtinstall('S', Sconv); + fmtinstall('N', Nconv); + fmtinstall('B', Bconv); + fmtinstall('D', Dconv); +} + +int +Bconv(Fmt *fp) +{ + char str[STRINGSZ], ss[STRINGSZ], *s; + Bits bits; + int i; + + str[0] = 0; + bits = va_arg(fp->args, Bits); + while(bany(&bits)) { + i = bnum(bits); + if(str[0]) + strcat(str, " "); + if(var[i].sym == S) { + sprint(ss, "$%ld", var[i].offset); + s = ss; + } else + s = var[i].sym->name; + if(strlen(str) + strlen(s) + 1 >= STRINGSZ) + break; + strcat(str, s); + bits.b[i/32] &= ~(1L << (i%32)); + } + return fmtstrcpy(fp, str); +} + +int +Pconv(Fmt *fp) +{ + char str[STRINGSZ]; + Prog *p; + int a; + + p = va_arg(fp->args, Prog*); + a = p->as; + if(a == ADATA) + sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to); + else + if(p->as == ATEXT) + sprint(str, " %A %D,%d,%D", a, &p->from, p->reg, &p->to); + else + if(p->reg == NREG) + sprint(str, " %A %D,%D", a, &p->from, &p->to); + else + if(p->from.type != D_FREG) + sprint(str, " %A %D,R%d,%D", a, &p->from, p->reg, &p->to); + else + sprint(str, " %A %D,F%d,%D", a, &p->from, p->reg, &p->to); + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + char *s; + int a; + + a = va_arg(fp->args, int); + s = "???"; + if(a >= AXXX && a < ALAST) + s = anames[a]; + return fmtstrcpy(fp, s); +} + +int +Dconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + + a = va_arg(fp->args, Adr*); + switch(a->type) { + + default: + sprint(str, "GOK-type(%d)", a->type); + break; + + case D_NONE: + str[0] = 0; + if(a->name != D_NONE || a->reg != NREG || a->sym != S) + sprint(str, "%N(R%d)(NONE)", a, a->reg); + break; + + case D_VCONST: + case D_CONST: + if(a->reg != NREG) + sprint(str, "$%N(R%d)", a, a->reg); + else + sprint(str, "$%N", a); + break; + + case D_OREG: + if(a->reg != NREG) + sprint(str, "%N(R%d)", a, a->reg); + else + sprint(str, "%N", a); + break; + + case D_REG: + sprint(str, "R%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_FREG: + sprint(str, "F%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(FREG)", a, a->reg); + break; + + case D_BRANCH: + sprint(str, "%ld(PC)", a->offset-pc); + break; + + case D_FCONST: + sprint(str, "$%.17e", a->dval); + break; + + case D_SCONST: + sprint(str, "$\"%S\"", a->sval); + break; + } + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[STRINGSZ], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9' || + c == ' ' || c == '%') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + case 0: + *p++ = 'z'; + continue; + case '\\': + case '"': + *p++ = c; + continue; + case '\n': + *p++ = 'n'; + continue; + case '\t': + *p++ = 't'; + continue; + case '\r': + *p++ = 'r'; + continue; + case '\f': + *p++ = 'f'; + continue; + } + *p++ = (c>>6) + '0'; + *p++ = ((c>>3) & 7) + '0'; + *p++ = (c & 7) + '0'; + } + *p = 0; + return fmtstrcpy(fp, str); +} + +int +Nconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + Sym *s; + + a = va_arg(fp->args, Adr*); + s = a->sym; + if(s == S) { + if(a->type == D_VCONST) + sprint(str, "%lld", *(vlong*)a->sval); + else + sprint(str, "%ld", a->offset); + goto out; + } + switch(a->name) { + default: + sprint(str, "GOK-name(%d)", a->name); + break; + + case D_NONE: + sprint(str, "%ld", a->offset); + break; + + case D_EXTERN: + sprint(str, "%s+%ld(SB)", s->name, a->offset); + break; + + case D_STATIC: + sprint(str, "%s<>+%ld(SB)", s->name, a->offset); + break; + + case D_AUTO: + sprint(str, "%s-%ld(SP)", s->name, -a->offset); + break; + + case D_PARAM: + sprint(str, "%s+%ld(FP)", s->name, a->offset); + break; + } +out: + return fmtstrcpy(fp, str); +} diff --git a/utils/ic/machcap.c b/utils/ic/machcap.c new file mode 100644 index 00000000..4da0aa91 --- /dev/null +++ b/utils/ic/machcap.c @@ -0,0 +1,9 @@ +#include "gc.h" + +int +machcap(Node *n) +{ + if(n == Z) /* test */ + return thechar == 'j'; + return 0; +} diff --git a/utils/ic/mkenam b/utils/ic/mkenam new file mode 100644 index 00000000..31c06c05 --- /dev/null +++ b/utils/ic/mkenam @@ -0,0 +1,15 @@ +ed - ../ic/i.out.h <<'!' +v/^ A/d +,s/^ A/ "/ +g/ .*$/s/// +,s/,*$/",/ +1i +char* anames[] = +{ +. +$a +}; +. +w enam.c +Q +! diff --git a/utils/ic/mkfile b/utils/ic/mkfile new file mode 100644 index 00000000..cf66563c --- /dev/null +++ b/utils/ic/mkfile @@ -0,0 +1,48 @@ +<../../mkconfig + +TARG=ic # also makes jc (for riscv64) + +OFILES=\ + cgen.$O\ + enam.$O\ + list.$O\ + mul.$O\ + peep.$O\ + pgen.$O\ + pswt.$O\ + reg.$O\ + sgen.$O\ + swt.$O\ + txt.$O\ + lex.$O\ + machcap.$O\ + +HFILES=\ + gc.h\ + i.out.h\ + ../cc/cc.h\ + +LIBS=cc bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I../include + +$ROOT/$OBJDIR/lib/libcc.a: + cd ../cc + mk $MKFLAGS install + mk $MKFLAGS clean + +../cc/y.tab.h: ../cc/cc.y + cd ../cc + mk $MKFLAGS y.tab.h + +lex.$O: ../cc/lex.c ../cc/y.tab.h + $CC -Dmain'='ccmain $CFLAGS ../cc/lex.c + +%.$O: ../cc/%.c + $CC -I. $CFLAGS ../cc/$stem.c + +install:V: $BIN/jc diff --git a/utils/ic/mul.c b/utils/ic/mul.c new file mode 100644 index 00000000..3ef56cd5 --- /dev/null +++ b/utils/ic/mul.c @@ -0,0 +1,608 @@ +#include "gc.h" + +/* + * code sequences for multiply by constant. + * [a-l][0-3] + * lsl $(A-'a'),r0,r1 + * [+][0-7] + * add r0,r1,r2 + * [-][0-7] + * sub r0,r1,r2 + */ + +static int multabp; +static long mulval; +static char* mulcp; +static long valmax; +static int shmax; + +static int docode(char *hp, char *cp, int r0, int r1); +static int gen1(int len); +static int gen2(int len, long r1); +static int gen3(int len, long r0, long r1, int flag); +enum +{ + SR1 = 1<<0, /* r1 has been shifted */ + SR0 = 1<<1, /* r0 has been shifted */ + UR1 = 1<<2, /* r1 has not been used */ + UR0 = 1<<3, /* r0 has not been used */ +}; + +Multab* +mulcon0(long v) +{ + int a1, a2, g; + Multab *m, *m1; + char hint[10]; + + if(v < 0) + v = -v; + + /* + * look in cache + */ + m = multab; + for(g=0; gval == v) { + if(m->code[0] == 0) + return 0; + return m; + } + m++; + } + + /* + * select a spot in cache to overwrite + */ + multabp++; + if(multabp < 0 || multabp >= nelem(multab)) + multabp = 0; + m = multab+multabp; + m->val = v; + mulval = v; + + /* + * look in execption hint table + */ + a1 = 0; + a2 = hintabsize; + for(;;) { + if(a1 >= a2) + goto no; + g = (a2 + a1)/2; + if(v < hintab[g].val) { + a2 = g; + continue; + } + if(v > hintab[g].val) { + a1 = g+1; + continue; + } + break; + } + + if(docode(hintab[g].hint, m->code, 1, 0)) + return m; + print("multiply table failure %ld\n", v); + m->code[0] = 0; + return 0; + +no: + /* + * try to search + */ + hint[0] = 0; + for(g=1; g<=6; g++) { + if(g >= 6 && v >= 65535) + break; + mulcp = hint+g; + *mulcp = 0; + if(gen1(g)) { + if(docode(hint, m->code, 1, 0)) + return m; + print("multiply table failure %ld\n", v); + break; + } + } + + /* + * try a recur followed by a shift + */ + g = 0; + while(!(v & 1)) { + g++; + v >>= 1; + } + if(g) { + m1 = mulcon0(v); + if(m1) { + strcpy(m->code, m1->code); + sprint(strchr(m->code, 0), "%c0", g+'a'); + return m; + } + } + m->code[0] = 0; + return 0; +} + +static int +docode(char *hp, char *cp, int r0, int r1) +{ + int c, i; + + c = *hp++; + *cp = c; + cp += 2; + switch(c) { + default: + c -= 'a'; + if(c < 1 || c >= 30) + break; + for(i=0; i<4; i++) { + switch(i) { + case 0: + if(docode(hp, cp, r0<= mulval) + break; + } + if(mulval == 1) + return 1; + + len--; + for(i=1; i<=shmax; i++) + if(gen2(len, 1<= r1 || + r1 > valmax) + return 0; + + len--; + if(len == 0) + goto calcr0; + + if(!(flag & UR1)) { + f1 = UR1|SR1; + for(i=1; i<=shmax; i++) { + x = r0< valmax) + break; + if(gen3(len, r0, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & UR0)) { + f1 = UR1|SR1; + for(i=1; i<=shmax; i++) { + x = r1< valmax) + break; + if(gen3(len, r1, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & SR1)) { + f1 = UR1|SR1|(flag&UR0); + for(i=1; i<=shmax; i++) { + x = r1< valmax) + break; + if(gen3(len, r0, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & SR0)) { + f1 = UR0|SR0|(flag&(SR1|UR1)); + + f2 = UR1|SR1; + if(flag & UR1) + f2 |= UR0; + if(flag & SR1) + f2 |= SR0; + + for(i=1; i<=shmax; i++) { + x = r0< valmax) + break; + if(x > r1) { + if(gen3(len, r1, x, f2)) { + i += 'a'; + goto out; + } + } else + if(gen3(len, x, r1, f1)) { + i += 'a'; + goto out; + } + } + } + + x = r1+r0; + if(gen3(len, r0, x, UR1)) { + i = '+'; + goto out; + } + + if(gen3(len, r1, x, UR1)) { + i = '+'; + goto out; + } + + x = r1-r0; + if(gen3(len, x, r1, UR0)) { + i = '-'; + goto out; + } + + if(x > r0) { + if(gen3(len, r0, x, UR1)) { + i = '-'; + goto out; + } + } else + if(gen3(len, x, r0, UR0)) { + i = '-'; + goto out; + } + + return 0; + +calcr0: + f1 = flag & (UR0|UR1); + if(f1 == UR1) { + for(i=1; i<=shmax; i++) { + x = r1<= mulval) { + if(x == mulval) { + i += 'a'; + goto out; + } + break; + } + } + } + + if(mulval == r1+r0) { + i = '+'; + goto out; + } + if(mulval == r1-r0) { + i = '-'; + goto out; + } + + return 0; + +out: + *--mulcp = i; + return 1; +} + +/* + * hint table has numbers that + * the search algorithm fails on. + * <1000: + * all numbers + * <5000: + * ÷ by 5 + * <10000: + * ÷ by 50 + * <65536: + * ÷ by 250 + */ +Hintab hintab[] = +{ + 683, "b++d+e+", + 687, "b+e++e-", + 691, "b++d+e+", + 731, "b++d+e+", + 811, "b++d+i+", + 821, "b++e+e+", + 843, "b+d++e+", + 851, "b+f-+e-", + 853, "b++e+e+", + 877, "c++++g-", + 933, "b+c++g-", + 981, "c-+e-d+", + 1375, "b+c+b+h-", + 1675, "d+b++h+", + 2425, "c++f-e+", + 2675, "c+d++f-", + 2750, "b+d-b+h-", + 2775, "c-+g-e-", + 3125, "b++e+g+", + 3275, "b+c+g+e+", + 3350, "c++++i+", + 3475, "c-+e-f-", + 3525, "c-+d+g-", + 3625, "c-+e-j+", + 3675, "b+d+d+e+", + 3725, "b+d-+h+", + 3925, "b+d+f-d-", + 4275, "b+g++e+", + 4325, "b+h-+d+", + 4425, "b+b+g-j-", + 4525, "b+d-d+f+", + 4675, "c++d-g+", + 4775, "b+d+b+g-", + 4825, "c+c-+i-", + 4850, "c++++i-", + 4925, "b++e-g-", + 4975, "c+f++e-", + 5500, "b+g-c+d+", + 6700, "d+b++i+", + 9700, "d++++j-", + 11000, "b+f-c-h-", + 11750, "b+d+g+j-", + 12500, "b+c+e-k+", + 13250, "b+d+e-f+", + 13750, "b+h-c-d+", + 14250, "b+g-c+e-", + 14500, "c+f+j-d-", + 14750, "d-g--f+", + 16750, "b+e-d-n+", + 17750, "c+h-b+e+", + 18250, "d+b+h-d+", + 18750, "b+g-++f+", + 19250, "b+e+b+h+", + 19750, "b++h--f-", + 20250, "b+e-l-c+", + 20750, "c++bi+e-", + 21250, "b+i+l+c+", + 22000, "b+e+d-g-", + 22250, "b+d-h+k-", + 22750, "b+d-e-g+", + 23250, "b+c+h+e-", + 23500, "b+g-c-g-", + 23750, "b+g-b+h-", + 24250, "c++g+m-", + 24750, "b+e+e+j-", + 25000, "b++dh+g+", + 25250, "b+e+d-g-", + 25750, "b+e+b+j+", + 26250, "b+h+c+e+", + 26500, "b+h+c+g+", + 26750, "b+d+e+g-", + 27250, "b+e+e+f+", + 27500, "c-i-c-d+", + 27750, "b+bd++j+", + 28250, "d-d-++i-", + 28500, "c+c-h-e-", + 29000, "b+g-d-f+", + 29500, "c+h+++e-", + 29750, "b+g+f-c+", + 30250, "b+f-g-c+", + 33500, "c-f-d-n+", + 33750, "b+d-b+j-", + 34250, "c+e+++i+", + 35250, "e+b+d+k+", + 35500, "c+e+d-g-", + 35750, "c+i-++e+", + 36250, "b+bh-d+e+", + 36500, "c+c-h-e-", + 36750, "d+e--i+", + 37250, "b+g+g+b+", + 37500, "b+h-b+f+", + 37750, "c+be++j-", + 38500, "b+e+b+i+", + 38750, "d+i-b+d+", + 39250, "b+g-l-+d+", + 39500, "b+g-c+g-", + 39750, "b+bh-c+f-", + 40250, "b+bf+d+g-", + 40500, "b+g-c+g+", + 40750, "c+b+i-e+", + 41250, "d++bf+h+", + 41500, "b+j+c+d-", + 41750, "c+f+b+h-", + 42500, "c+h++g+", + 42750, "b+g+d-f-", + 43250, "b+l-e+d-", + 43750, "c+bd+h+f-", + 44000, "b+f+g-d-", + 44250, "b+d-g--f+", + 44500, "c+e+c+h+", + 44750, "b+e+d-h-", + 45250, "b++g+j-g+", + 45500, "c+d+e-g+", + 45750, "b+d-h-e-", + 46250, "c+bd++j+", + 46500, "b+d-c-j-", + 46750, "e-e-b+g-", + 47000, "b+c+d-j-", + 47250, "b+e+e-g-", + 47500, "b+g-c-h-", + 47750, "b+f-c+h-", + 48250, "d--h+n-", + 48500, "b+c-g+m-", + 48750, "b+e+e-g+", + 49500, "c-f+e+j-", + 49750, "c+c+g++f-", + 50000, "b+e+e+k+", + 50250, "b++i++g+", + 50500, "c+g+f-i+", + 50750, "b+e+d+k-", + 51500, "b+i+c-f+", + 51750, "b+bd+g-e-", + 52250, "b+d+g-j+", + 52500, "c+c+f+g+", + 52750, "b+c+e+i+", + 53000, "b+i+c+g+", + 53500, "c+g+g-n+", + 53750, "b+j+d-c+", + 54250, "b+d-g-j-", + 54500, "c-f+e+f+", + 54750, "b+f-+c+g+", + 55000, "b+g-d-g-", + 55250, "b+e+e+g+", + 55500, "b+cd++j+", + 55750, "b+bh-d-f-", + 56250, "c+d-b+j-", + 56500, "c+d+c+i+", + 56750, "b+e+d++h-", + 57000, "b+d+g-f+", + 57250, "b+f-m+d-", + 57750, "b+i+c+e-", + 58000, "b+e+d+h+", + 58250, "c+b+g+g+", + 58750, "d-e-j--e+", + 59000, "d-i-+e+", + 59250, "e--h-m+", + 59500, "c+c-h+f-", + 59750, "b+bh-e+i-", + 60250, "b+bh-e-e-", + 60500, "c+c-g-g-", + 60750, "b+e-l-e-", + 61250, "b+g-g-c+", + 61750, "b+g-c+g+", + 62250, "f--+c-i-", + 62750, "e+f--+g+", + 64750, "b+f+d+p-", +}; +int hintabsize = nelem(hintab); diff --git a/utils/ic/peep.c b/utils/ic/peep.c new file mode 100644 index 00000000..87383a9d --- /dev/null +++ b/utils/ic/peep.c @@ -0,0 +1,706 @@ +#include "gc.h" + +void +peep(void) +{ + Reg *r, *r1, *r2; + Prog *p, *p1; + int t; +/* + * complete R structure + */ + t = 0; + for(r=firstr; r!=R; r=r1) { + r1 = r->link; + if(r1 == R) + break; + p = r->prog->link; + while(p != r1->prog) + switch(p->as) { + default: + r2 = rega(); + r->link = r2; + r2->link = r1; + + r2->prog = p; + r2->p1 = r; + r->s1 = r2; + r2->s1 = r1; + r1->p1 = r2; + + r = r2; + t++; + + case ADATA: + case AGLOBL: + case ANAME: + case ASIGNAME: + p = p->link; + } + } + + /* + * look for MOVB x,R; MOVB R,R => MOVB x,R + * look for MOVB x,R; MOVB R,S => MOVB x,R; MOVW R,S + */ + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + switch(p->as) { + default: + continue; + case AMOVH: + case AMOVHU: + case AMOVB: + case AMOVBU: + if(p->to.type != D_REG) + continue; + break; + } + r1 = r->link; + if(r1 == R) + continue; + p1 = r1->prog; + if(p1->as != p->as) + continue; + if(p1->from.type != D_REG || p1->from.reg != p->to.reg) + continue; + if(p1->to.type != D_REG) + continue; + if(p1->to.reg == p->to.reg) + excise(r1); + else + p1->as = AMOVW; + } + +loop1: + t = 0; + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + if(p->as == AMOVW || p->as == AMOVWU || p->as == AMOV || p->as == AMOVF || p->as == AMOVD) + if(regtyp(&p->to)) { + if(regtyp(&p->from)) + if(p->from.type == p->to.type) { + if(copyprop(r)) { + excise(r); + t++; + } else + if(subprop(r) && copyprop(r)) { + excise(r); + t++; + } + } + if(regzer(&p->from)) + if(p->to.type == D_REG) { + p->from.type = D_REG; + p->from.reg = 0; + if(copyprop(r)) { + excise(r); + t++; + } else + if(subprop(r) && copyprop(r)) { + excise(r); + t++; + } + } + } + } + if(t) + goto loop1; +} + +void +excise(Reg *r) +{ + Prog *p; + + p = r->prog; + p->as = ANOP; + p->from = zprog.from; + p->to = zprog.to; + p->reg = zprog.reg; /**/ +} + +Reg* +uniqp(Reg *r) +{ + Reg *r1; + + r1 = r->p1; + if(r1 == R) { + r1 = r->p2; + if(r1 == R || r1->p2link != R) + return R; + } else + if(r->p2 != R) + return R; + return r1; +} + +Reg* +uniqs(Reg *r) +{ + Reg *r1; + + r1 = r->s1; + if(r1 == R) { + r1 = r->s2; + if(r1 == R) + return R; + } else + if(r->s2 != R) + return R; + return r1; +} + +int +regzer(Adr *a) +{ + + if(a->type == D_CONST) + if(a->sym == S) + if(a->offset == 0) + return 1; + if(a->type == D_REG) + if(a->reg == 0) + return 1; + return 0; +} + +int +regtyp(Adr *a) +{ + + if(a->type == D_REG) { + if(a->reg != 0) + return 1; + return 0; + } + if(a->type == D_FREG) + return 1; + return 0; +} + +/* + * the idea is to substitute + * one register for another + * from one MOV to another + * MOV a, R0 + * ADD b, R0 / no use of R1 + * MOV R0, R1 + * would be converted to + * MOV a, R1 + * ADD b, R1 + * MOV R1, R0 + * hopefully, then the former or latter MOV + * will be eliminated by copy propagation. + */ +int +subprop(Reg *r0) +{ + Prog *p; + Adr *v1, *v2; + Reg *r; + int t; + + p = r0->prog; + v1 = &p->from; + if(!regtyp(v1)) + return 0; + v2 = &p->to; + if(!regtyp(v2)) + return 0; + for(r=uniqp(r0); r!=R; r=uniqp(r)) { + if(uniqs(r) == R) + break; + p = r->prog; + switch(p->as) { + case AJAL: + return 0; + + case ASLT: + case ASLTU: + case ASGT: + case ASGTU: + + case AADD: case AADDW: + case ASUB: case ASUBW: + case ASLL: case ASLLW: + case ASRL: case ASRLW: + case ASRA: case ASRAW: + case AOR: + case AAND: + case AXOR: + case AMUL: case AMULW: + case ADIV: case ADIVW: + case ADIVU: case ADIVUW: + + case AADDD: + case AADDF: + case ASUBD: + case ASUBF: + case AMULD: + case AMULF: + case ADIVD: + case ADIVF: + if(p->to.type == v1->type) + if(p->to.reg == v1->reg) { + if(p->reg == NREG) + p->reg = p->to.reg; + goto gotit; + } + break; + + case AMOVF: + case AMOVD: + case AMOVW: case AMOVWU: case AMOV: + if(p->to.type == v1->type) + if(p->to.reg == v1->reg) + goto gotit; + break; + } + if(copyau(&p->from, v2) || + copyau1(p, v2) || + copyau(&p->to, v2)) + break; + if(copysub(&p->from, v1, v2, 0) || + copysub1(p, v1, v2, 0) || + copysub(&p->to, v1, v2, 0)) + break; + } + return 0; + +gotit: + copysub(&p->to, v1, v2, 1); + if(debug['P']) { + print("gotit: %D->%D\n%P", v1, v2, r->prog); + if(p->from.type == v2->type) + print(" excise"); + print("\n"); + } + for(r=uniqs(r); r!=r0; r=uniqs(r)) { + p = r->prog; + copysub(&p->from, v1, v2, 1); + copysub1(p, v1, v2, 1); + copysub(&p->to, v1, v2, 1); + if(debug['P']) + print("%P\n", r->prog); + } + t = v1->reg; + v1->reg = v2->reg; + v2->reg = t; + if(debug['P']) + print("%P last\n", r->prog); + return 1; +} + +/* + * The idea is to remove redundant copies. + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * use v2 return fail + * ----------------- + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * set v2 return success + */ +int +copyprop(Reg *r0) +{ + Prog *p; + Adr *v1, *v2; + Reg *r; + + p = r0->prog; + v1 = &p->from; + v2 = &p->to; + if(copyas(v1, v2)) + return 1; + for(r=firstr; r!=R; r=r->link) + r->active = 0; + return copy1(v1, v2, r0->s1, 0); +} + +int +copy1(Adr *v1, Adr *v2, Reg *r, int f) +{ + int t; + Prog *p; + + if(r->active) { + if(debug['P']) + print("act set; return 1\n"); + return 1; + } + r->active = 1; + if(debug['P']) + print("copy %D->%D f=%d\n", v1, v2, f); + for(; r != R; r = r->s1) { + p = r->prog; + if(debug['P']) + print("%P", p); + if(!f && uniqp(r) == R) { + f = 1; + if(debug['P']) + print("; merge; f=%d", f); + } + t = copyu(p, v2, A); + switch(t) { + case 2: /* rar, cant split */ + if(debug['P']) + print("; %Drar; return 0\n", v2); + return 0; + + case 3: /* set */ + if(debug['P']) + print("; %Dset; return 1\n", v2); + return 1; + + case 1: /* used, substitute */ + case 4: /* use and set */ + if(f) { + if(!debug['P']) + return 0; + if(t == 4) + print("; %Dused+set and f=%d; return 0\n", v2, f); + else + print("; %Dused and f=%d; return 0\n", v2, f); + return 0; + } + if(copyu(p, v2, v1)) { + if(debug['P']) + print("; sub fail; return 0\n"); + return 0; + } + if(debug['P']) + print("; sub%D/%D", v2, v1); + if(t == 4) { + if(debug['P']) + print("; %Dused+set; return 1\n", v2); + return 1; + } + break; + } + if(!f) { + t = copyu(p, v1, A); + if(!f && (t == 2 || t == 3 || t == 4)) { + f = 1; + if(debug['P']) + print("; %Dset and !f; f=%d", v1, f); + } + } + if(debug['P']) + print("\n"); + if(r->s2) + if(!copy1(v1, v2, r->s2, f)) + return 0; + } + return 1; +} + +/* + * return + * 1 if v only used (and substitute), + * 2 if read-alter-rewrite + * 3 if set + * 4 if set and used + * 0 otherwise (not touched) + */ +int +copyu(Prog *p, Adr *v, Adr *s) +{ + + switch(p->as) { + + default: + if(debug['P']) + print("unknown op %A\n", p->as); + return 2; + + + case ANOP: /* read, write */ + case AMOVW: + case AMOVWU: + case AMOV: + case AMOVF: + case AMOVD: + case AMOVH: + case AMOVHU: + case AMOVB: + case AMOVBU: + case AMOVDW: + case AMOVWD: + case AMOVUD: + case AMOVFW: + case AMOVWF: + case AMOVUF: + case AMOVFD: + case AMOVDF: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + if(!copyas(&p->to, v)) + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyas(&p->to, v)) { + if(copyau(&p->from, v)) + return 4; + return 3; + } + if(copyau(&p->from, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + return 0; + + case ASLT: /* read, read, write */ + case ASLTU: + case ASGT: + case ASGTU: + case ACMPEQD: + case ACMPEQF: + case ACMPLED: + case ACMPLEF: + case ACMPLTD: + case ACMPLTF: + + case AADD: case AADDW: + case ASUB: case ASUBW: + case ASLL: case ASLLW: + case ASRL: case ASRLW: + case ASRA: case ASRAW: + case AOR: + case AAND: + case AXOR: + case AMUL: case AMULW: + case ADIV: case ADIVW: + case ADIVU: case ADIVUW: + + case AADDF: + case AADDD: + case ASUBF: + case ASUBD: + case AMULF: + case AMULD: + case ADIVF: + case ADIVD: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + if(copysub1(p, v, s, 1)) + return 1; + if(!copyas(&p->to, v)) + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyas(&p->to, v)) { + if(p->reg == NREG) + p->reg = p->to.reg; + if(copyau(&p->from, v)) + return 4; + if(copyau1(p, v)) + return 4; + return 3; + } + if(copyau(&p->from, v)) + return 1; + if(copyau1(p, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + return 0; + + case ABEQ: /* read, read */ + case ABGE: + case ABGEU: + case ABLT: + case ABLTU: + case ABNE: + case ABGT: + case ABGTU: + case ABLE: + case ABLEU: + + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + return copysub1(p, v, s, 1); + } + if(copyau(&p->from, v)) + return 1; + if(copyau1(p, v)) + return 1; + return 0; + + case AJMP: /* funny */ + if(s != A) { + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyau(&p->to, v)) + return 1; + return 0; + + case ARET: /* funny */ + if(v->type == D_REG) + if(v->reg == REGRET) + return 2; + if(v->type == D_FREG) + if(v->reg == FREGRET) + return 2; + + case AJAL: /* funny */ + if(v->type == D_REG) { + if(v->reg <= REGEXT && v->reg > exregoffset) + return 2; + if(REGARG && v->reg == REGARG) + return 2; + } + if(v->type == D_FREG) + if(v->reg <= FREGEXT && v->reg > exfregoffset) + return 2; + + if(s != A) { + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyau(&p->to, v)) + return 4; + return 3; + + case ATEXT: /* funny */ + if(v->type == D_REG) + if(v->reg == REGARG) + return 3; + return 0; + } +} + +int +a2type(Prog *p) +{ + + switch(p->as) { + case ABEQ: + case ABGE: + case ABGEU: + case ABLT: + case ABLTU: + case ABNE: + case ABGT: + case ABGTU: + case ABLE: + case ABLEU: + + case ASLT: + case ASLTU: + case ASGT: + case ASGTU: + + case AADD: case AADDW: + case ASUB: case ASUBW: + case ASLL: case ASLLW: + case ASRL: case ASRLW: + case ASRA: case ASRAW: + case AOR: + case AAND: + case AXOR: + case AMUL: case AMULW: + case ADIV: case ADIVW: + case ADIVU: case ADIVUW: + return D_REG; + + case ACMPEQD: + case ACMPEQF: + case ACMPLED: + case ACMPLEF: + case ACMPLTD: + case ACMPLTF: + + case AADDF: + case AADDD: + case ASUBF: + case ASUBD: + case AMULF: + case AMULD: + case ADIVF: + case ADIVD: + return D_FREG; + } + return D_NONE; +} + +/* + * direct reference, + * could be set/use depending on + * semantics + */ +int +copyas(Adr *a, Adr *v) +{ + + if(regtyp(v)) + if(a->type == v->type) + if(a->reg == v->reg) + return 1; + return 0; +} + +/* + * either direct or indirect + */ +int +copyau(Adr *a, Adr *v) +{ + + if(copyas(a, v)) + return 1; + if(v->type == D_REG) + if(a->type == D_OREG) + if(v->reg == a->reg) + return 1; + return 0; +} + +int +copyau1(Prog *p, Adr *v) +{ + + if(regtyp(v)) + if(p->from.type == v->type || p->to.type == v->type) + if(p->reg == v->reg) { + if(a2type(p) == v->type) + return 1; + } + return 0; +} + +/* + * substitute s for v in a + * return failure to substitute + */ +int +copysub(Adr *a, Adr *v, Adr *s, int f) +{ + + if(f) + if(copyau(a, v)) + a->reg = s->reg; + return 0; +} + +int +copysub1(Prog *p1, Adr *v, Adr *s, int f) +{ + + if(f) + if(copyau1(p1, v)) + p1->reg = s->reg; + return 0; +} diff --git a/utils/ic/reg.c b/utils/ic/reg.c new file mode 100644 index 00000000..50df739a --- /dev/null +++ b/utils/ic/reg.c @@ -0,0 +1,1160 @@ +#include "gc.h" + +void addsplits(void); + +Reg* +rega(void) +{ + Reg *r; + + r = freer; + if(r == R) { + r = alloc(sizeof(*r)); + } else + freer = r->link; + + *r = zreg; + return r; +} + +int +rcmp(void *a1, void *a2) +{ + Rgn *p1, *p2; + int c1, c2; + + p1 = (Rgn*)a1; + p2 = (Rgn*)a2; + c1 = p2->cost; + c2 = p1->cost; + if(c1 -= c2) + return c1; + return p2->varno - p1->varno; +} + +void +regopt(Prog *p) +{ + Reg *r, *r1, *r2; + Prog *p1; + int i, z; + long initpc, val, npc; + ulong vreg; + Bits bit; + struct + { + long m; + long c; + Reg* p; + } log5[6], *lp; + + firstr = R; + lastr = R; + nvar = 0; + regbits = 0; + for(z=0; zm = val; + lp->c = 0; + lp->p = R; + val /= 5L; + lp++; + } + val = 0; + for(; p != P; p = p->link) { + switch(p->as) { + case ADATA: + case AGLOBL: + case ANAME: + case ASIGNAME: + continue; + } + r = rega(); + if(firstr == R) { + firstr = r; + lastr = r; + } else { + lastr->link = r; + r->p1 = lastr; + lastr->s1 = r; + lastr = r; + } + r->prog = p; + r->pc = val; + val++; + + lp = log5; + for(i=0; i<5; i++) { + lp->c--; + if(lp->c <= 0) { + lp->c = lp->m; + if(lp->p != R) + lp->p->log5 = r; + lp->p = r; + (lp+1)->c = 0; + break; + } + lp++; + } + + r1 = r->p1; + if(r1 != R) + switch(r1->prog->as) { + case ARET: + case AJMP: + r->p1 = R; + r1->s1 = R; + } + + /* + * left side always read + */ + bit = mkvar(&p->from, p->as==AMOVW || p->as==AMOV); + for(z=0; zuse1.b[z] |= bit.b[z]; + + /* + * right side depends on opcode + */ + bit = mkvar(&p->to, 0); + if(bany(&bit)) + switch(p->as) { + default: + diag(Z, "reg: unknown asop: %A", p->as); + break; + + /* + * right side write + */ + case ANOP: + case AMOVB: + case AMOVBU: + case AMOVH: + case AMOVHU: + case AMOVW: + case AMOV: + case AMOVF: + case AMOVD: + for(z=0; zset.b[z] |= bit.b[z]; + break; + + /* + * funny + */ + case AJAL: + for(z=0; zlink) { + p = r->prog; + if(p->to.type == D_BRANCH) { + val = p->to.offset - initpc; + r1 = firstr; + while(r1 != R) { + r2 = r1->log5; + if(r2 != R && val >= r2->pc) { + r1 = r2; + continue; + } + if(r1->pc == val) + break; + r1 = r1->link; + } + if(r1 == R) { + nearln = p->lineno; + diag(Z, "ref not found\n%P", p); + continue; + } + if(r1 == r) { + nearln = p->lineno; + diag(Z, "ref to self\n%P", p); + continue; + } + r->s2 = r1; + r->p2link = r1->p2; + r1->p2 = r; + } + } + if(debug['R']) { + p = firstr->prog; + print("\n%L %D\n", p->lineno, &p->from); + } + + /* + * pass 2.5 + * find looping structure + */ + for(r = firstr; r != R; r = r->link) + r->active = 0; + change = 0; + loopit(firstr, npc); + + /* + * pass 3 + * iterate propagating usage + * back until flow graph is complete + */ +loop1: + change = 0; + for(r = firstr; r != R; r = r->link) + r->active = 0; + for(r = firstr; r != R; r = r->link) + if(r->prog->as == ARET) + prop(r, zbits, zbits); +loop11: + /* pick up unreachable code */ + i = 0; + for(r = firstr; r != R; r = r1) { + r1 = r->link; + if(r1 && r1->active && !r->active) { + prop(r, zbits, zbits); + i = 1; + } + } + if(i) + goto loop11; + if(change) + goto loop1; + + + /* + * pass 4 + * iterate propagating register/variable synchrony + * forward until graph is complete + */ +loop2: + change = 0; + for(r = firstr; r != R; r = r->link) + r->active = 0; + synch(firstr, zbits); + if(change) + goto loop2; + + addsplits(); + + if(debug['R'] && debug['v']) { + print("\nprop structure:\n"); + for(r = firstr; r != R; r = r->link) { + print("%ld:%P", r->loop, r->prog); + for(z=0; zset.b[z] | + r->refahead.b[z] | r->calahead.b[z] | + r->refbehind.b[z] | r->calbehind.b[z] | + r->use1.b[z] | r->use2.b[z]; + if(bany(&bit)) { + print("\t"); + if(bany(&r->use1)) + print(" u1=%B", r->use1); + if(bany(&r->use2)) + print(" u2=%B", r->use2); + if(bany(&r->set)) + print(" st=%B", r->set); + if(bany(&r->refahead)) + print(" ra=%B", r->refahead); + if(bany(&r->calahead)) + print(" ca=%B", r->calahead); + if(bany(&r->refbehind)) + print(" rb=%B", r->refbehind); + if(bany(&r->calbehind)) + print(" cb=%B", r->calbehind); + if(bany(&r->regdiff)) + print(" rd=%B", r->regdiff); + } + print("\n"); + } + } + + /* + * pass 5 + * isolate regions + * calculate costs (paint1) + */ + r = firstr; + if(r) { + for(z=0; zrefahead.b[z] | r->calahead.b[z]) & + ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]); + if(bany(&bit)) { + nearln = r->prog->lineno; + warn(Z, "used and not set: %B", bit); + if(debug['R'] && !debug['w']) + print("used and not set: %B\n", bit); + } + } + + for(r = firstr; r != R; r = r->link) + r->act = zbits; + rgp = region; + nregion = 0; + for(r = firstr; r != R; r = r->link) { + for(z=0; zset.b[z] & + ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]); + if(bany(&bit)) { + nearln = r->prog->lineno; + warn(Z, "set and not used: %B", bit); + if(debug['R']) + print("set and not used: %B\n", bit); + excise(r); + } + for(z=0; zact.b[z] | addrs.b[z]); + while(bany(&bit)) { + i = bnum(bit); + rgp->enter = r; + rgp->varno = i; + change = 0; + if(debug['R'] && debug['v']) + print("\n"); + paint1(r, i); + bit.b[i/32] &= ~(1L<<(i%32)); + if(change <= 0) { + if(debug['R']) + print("%L $%d: %B\n", + r->prog->lineno, change, blsh(i)); + continue; + } + rgp->cost = change; + nregion++; + if(nregion >= NRGN) { + warn(Z, "too many regions"); + goto brk; + } + rgp++; + } + } +brk: + qsort(region, nregion, sizeof(region[0]), rcmp); + + /* + * pass 6 + * determine used registers (paint2) + * replace code (paint3) + */ + rgp = region; + for(i=0; ivarno); + vreg = paint2(rgp->enter, rgp->varno); + vreg = allreg(vreg, rgp); + if(debug['R']) { + if(rgp->regno >= NREG) + print("%L $%d F%d: %B\n", + rgp->enter->prog->lineno, + rgp->cost, + rgp->regno-NREG, + bit); + else + print("%L $%d R%d: %B\n", + rgp->enter->prog->lineno, + rgp->cost, + rgp->regno, + bit); + } + if(rgp->regno != 0) + paint3(rgp->enter, rgp->varno, vreg, rgp->regno); + rgp++; + } + /* + * pass 7 + * peep-hole on basic block + */ + if(!debug['R'] || debug['P']) + peep(); + + /* + * pass 8 + * recalculate pc + */ + val = initpc; + for(r = firstr; r != R; r = r1) { + r->pc = val; + p = r->prog; + p1 = P; + r1 = r->link; + if(r1 != R) + p1 = r1->prog; + for(; p != p1; p = p->link) { + switch(p->as) { + default: + val++; + break; + + case ANOP: + case ADATA: + case AGLOBL: + case ANAME: + case ASIGNAME: + break; + } + } + } + pc = val; + + /* + * fix up branches + */ + if(debug['R']) + if(bany(&addrs)) + print("addrs: %B\n", addrs); + + r1 = 0; /* set */ + for(r = firstr; r != R; r = r->link) { + p = r->prog; + if(p->to.type == D_BRANCH) + p->to.offset = r->s2->pc; + r1 = r; + } + + /* + * last pass + * eliminate nops + * free aux structures + */ + for(p = firstr->prog; p != P; p = p->link){ + while(p->link && p->link->as == ANOP) + p->link = p->link->link; + } + if(r1 != R) { + r1->link = freer; + freer = firstr; + } +} + +void +addsplits(void) +{ + Reg *r, *r1; + int z, i; + Bits bit; + + for(r = firstr; r != R; r = r->link) { + if(r->loop > 1) + continue; + if(r->prog->as == AJAL) + continue; + for(r1 = r->p2; r1 != R; r1 = r1->p2link) { + if(r1->loop <= 1) + continue; + for(z=0; zcalbehind.b[z] & + (r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) & + ~(r->calahead.b[z] & addrs.b[z]); + while(bany(&bit)) { + i = bnum(bit); + bit.b[i/32] &= ~(1L << (i%32)); + } + } + } +} + +/* + * add mov b,rn + * just after r + */ +void +addmove(Reg *r, int bn, int rn, int f) +{ + Prog *p, *p1; + Adr *a; + Var *v; + + p1 = alloc(sizeof(*p1)); + *p1 = zprog; + p = r->prog; + + p1->link = p->link; + p->link = p1; + p1->lineno = p->lineno; + + v = var + bn; + + a = &p1->to; + a->sym = v->sym; + a->name = v->name; + a->offset = v->offset; + a->etype = v->etype; + a->type = D_OREG; + if(a->etype == TARRAY || a->sym == S) + a->type = D_CONST; + + p1->as = AMOVW; + if(v->etype == TCHAR || v->etype == TUCHAR) + p1->as = AMOVB; + if(v->etype == TSHORT || v->etype == TUSHORT) + p1->as = AMOVH; + if(v->etype == TFLOAT) + p1->as = AMOVF; + if(v->etype == TDOUBLE) + p1->as = AMOVD; + if(thechar == 'j') + if(v->etype == TVLONG || v->etype == TUVLONG || v->etype == TIND) + p1->as = AMOV; + + p1->from.type = D_REG; + p1->from.reg = rn; + if(rn >= NREG) { + p1->from.type = D_FREG; + p1->from.reg = rn-NREG; + } + if(!f) { + p1->from = *a; + *a = zprog.from; + a->type = D_REG; + a->reg = rn; + if(rn >= NREG) { + a->type = D_FREG; + a->reg = rn-NREG; + } + if(v->etype == TUCHAR) + p1->as = AMOVBU; + if(v->etype == TUSHORT) + p1->as = AMOVHU; + } + if(debug['R']) + print("%P\t.a%P\n", p, p1); +} + +Bits +mkvar(Adr *a, int docon) +{ + Var *v; + int i, t, n, et, z; + long o; + Bits bit; + Sym *s; + + t = a->type; + if(t == D_REG && a->reg != NREG) + regbits |= RtoB(a->reg); + if(t == D_FREG && a->reg != NREG) + regbits |= FtoB(a->reg); + s = a->sym; + o = a->offset; + et = a->etype; + if(s == S) { + if(t != D_CONST || !docon || a->reg != NREG) + goto none; + et = TLONG; + } + if(t == D_CONST) { + if(s == S && sval(o)) + goto none; + } + + n = a->name; + v = var; + for(i=0; isym) + if(n == v->name) + if(o == v->offset) + goto out; + v++; + } + if(s) + if(s->name[0] == '.') + goto none; + if(nvar >= NVAR) { + if(debug['w'] > 1 && s) + warn(Z, "variable not optimized: %s", s->name); + goto none; + } + i = nvar; + nvar++; + v = &var[i]; + v->sym = s; + v->offset = o; + v->etype = et; + v->name = n; + if(debug['R']) + print("bit=%2d et=%2d %D\n", i, et, a); +out: + bit = blsh(i); + if(n == D_EXTERN || n == D_STATIC) + for(z=0; zetype != et || !typechlpfd[et]) /* funny punning */ + for(z=0; zp1) { + for(z=0; zrefahead.b[z]; + if(ref.b[z] != r1->refahead.b[z]) { + r1->refahead.b[z] = ref.b[z]; + change++; + } + cal.b[z] |= r1->calahead.b[z]; + if(cal.b[z] != r1->calahead.b[z]) { + r1->calahead.b[z] = cal.b[z]; + change++; + } + } + switch(r1->prog->as) { + case AJAL: + for(z=0; zset.b[z]) | + r1->use1.b[z] | r1->use2.b[z]; + cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]); + r1->refbehind.b[z] = ref.b[z]; + r1->calbehind.b[z] = cal.b[z]; + } + if(r1->active) + break; + r1->active = 1; + } + for(; r != r1; r = r->p1) + for(r2 = r->p2; r2 != R; r2 = r2->p2link) + prop(r2, r->refbehind, r->calbehind); +} + +/* + * find looping structure + * + * 1) find reverse postordering + * 2) find approximate dominators, + * the actual dominators if the flow graph is reducible + * otherwise, dominators plus some other non-dominators. + * See Matthew S. Hecht and Jeffrey D. Ullman, + * "Analysis of a Simple Algorithm for Global Data Flow Problems", + * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts, + * Oct. 1-3, 1973, pp. 207-217. + * 3) find all nodes with a predecessor dominated by the current node. + * such a node is a loop head. + * recursively, all preds with a greater rpo number are in the loop + */ +long +postorder(Reg *r, Reg **rpo2r, long n) +{ + Reg *r1; + + r->rpo = 1; + r1 = r->s1; + if(r1 && !r1->rpo) + n = postorder(r1, rpo2r, n); + r1 = r->s2; + if(r1 && !r1->rpo) + n = postorder(r1, rpo2r, n); + rpo2r[n] = r; + n++; + return n; +} + +long +rpolca(long *idom, long rpo1, long rpo2) +{ + long t; + + if(rpo1 == -1) + return rpo2; + while(rpo1 != rpo2){ + if(rpo1 > rpo2){ + t = rpo2; + rpo2 = rpo1; + rpo1 = t; + } + while(rpo1 < rpo2){ + t = idom[rpo2]; + if(t >= rpo2) + fatal(Z, "bad idom"); + rpo2 = t; + } + } + return rpo1; +} + +int +doms(long *idom, long r, long s) +{ + while(s > r) + s = idom[s]; + return s == r; +} + +int +loophead(long *idom, Reg *r) +{ + long src; + + src = r->rpo; + if(r->p1 != R && doms(idom, src, r->p1->rpo)) + return 1; + for(r = r->p2; r != R; r = r->p2link) + if(doms(idom, src, r->rpo)) + return 1; + return 0; +} + +void +loopmark(Reg **rpo2r, long head, Reg *r) +{ + if(r->rpo < head || r->active == head) + return; + r->active = head; + r->loop += LOOP; + if(r->p1 != R) + loopmark(rpo2r, head, r->p1); + for(r = r->p2; r != R; r = r->p2link) + loopmark(rpo2r, head, r); +} + +void +loopit(Reg *r, long nr) +{ + Reg *r1; + long i, d, me; + + if(nr > maxnr) { + rpo2r = alloc(nr * sizeof(Reg*)); + idom = alloc(nr * sizeof(long)); + maxnr = nr; + } + + d = postorder(r, rpo2r, 0); + if(d > nr) + fatal(Z, "too many reg nodes"); + nr = d; + for(i = 0; i < nr / 2; i++){ + r1 = rpo2r[i]; + rpo2r[i] = rpo2r[nr - 1 - i]; + rpo2r[nr - 1 - i] = r1; + } + for(i = 0; i < nr; i++) + rpo2r[i]->rpo = i; + + idom[0] = 0; + for(i = 0; i < nr; i++){ + r1 = rpo2r[i]; + me = r1->rpo; + d = -1; + if(r1->p1 != R && r1->p1->rpo < me) + d = r1->p1->rpo; + for(r1 = r1->p2; r1 != nil; r1 = r1->p2link) + if(r1->rpo < me) + d = rpolca(idom, d, r1->rpo); + idom[i] = d; + } + + for(i = 0; i < nr; i++){ + r1 = rpo2r[i]; + r1->loop++; + if(r1->p2 != R && loophead(idom, r1)) + loopmark(rpo2r, i, r1); + } +} + +void +synch(Reg *r, Bits dif) +{ + Reg *r1; + int z; + + for(r1 = r; r1 != R; r1 = r1->s1) { + for(z=0; zrefbehind.b[z] & r1->refahead.b[z])) | + r1->set.b[z] | r1->regdiff.b[z]; + if(dif.b[z] != r1->regdiff.b[z]) { + r1->regdiff.b[z] = dif.b[z]; + change++; + } + } + if(r1->active) + break; + r1->active = 1; + for(z=0; zcalbehind.b[z] & r1->calahead.b[z]); + if(r1->s2 != R) + synch(r1->s2, dif); + } +} + +ulong +allreg(ulong b, Rgn *r) +{ + Var *v; + int i; + + v = var + r->varno; + r->regno = 0; + switch(v->etype) { + + default: + diag(Z, "unknown etype %d/%d", bitno(b), v->etype); + break; + + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TARRAY: + i = BtoR(~b); + if(i && r->cost >= 0) { + r->regno = i; + return RtoB(i); + } + break; + + case TDOUBLE: + case TFLOAT: + i = BtoF(~b); + if(i && r->cost >= 0) { + r->regno = i+NREG; + return FtoB(i); + } + break; + } + return 0; +} + +void +paint1(Reg *r, int bn) +{ + Reg *r1; + Prog *p; + int z; + ulong bb; + + z = bn/32; + bb = 1L<<(bn%32); + if(r->act.b[z] & bb) + return; + for(;;) { + if(!(r->refbehind.b[z] & bb)) + break; + r1 = r->p1; + if(r1 == R) + break; + if(!(r1->refahead.b[z] & bb)) + break; + if(r1->act.b[z] & bb) + break; + r = r1; + } + + if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) { + change -= CLOAD * r->loop; + if(debug['R'] && debug['v']) + print("%ld%P\tld %B $%d\n", r->loop, + r->prog, blsh(bn), change); + } + for(;;) { + r->act.b[z] |= bb; + p = r->prog; + + if(r->use1.b[z] & bb) { + change += CREF * r->loop; + if(debug['R'] && debug['v']) + print("%ld%P\tu1 %B $%d\n", r->loop, + p, blsh(bn), change); + } + + if((r->use2.b[z]|r->set.b[z]) & bb) { + change += CREF * r->loop; + if(debug['R'] && debug['v']) + print("%ld%P\tu2 %B $%d\n", r->loop, + p, blsh(bn), change); + } + + if(STORE(r) & r->regdiff.b[z] & bb) { + change -= CLOAD * r->loop; + if(debug['R'] && debug['v']) + print("%ld%P\tst %B $%d\n", r->loop, + p, blsh(bn), change); + } + + if(r->refbehind.b[z] & bb) + for(r1 = r->p2; r1 != R; r1 = r1->p2link) + if(r1->refahead.b[z] & bb) + paint1(r1, bn); + + if(!(r->refahead.b[z] & bb)) + break; + r1 = r->s2; + if(r1 != R) + if(r1->refbehind.b[z] & bb) + paint1(r1, bn); + r = r->s1; + if(r == R) + break; + if(r->act.b[z] & bb) + break; + if(!(r->refbehind.b[z] & bb)) + break; + } +} + +ulong +paint2(Reg *r, int bn) +{ + Reg *r1; + int z; + ulong bb, vreg; + + z = bn/32; + bb = 1L << (bn%32); + vreg = regbits; + if(!(r->act.b[z] & bb)) + return vreg; + for(;;) { + if(!(r->refbehind.b[z] & bb)) + break; + r1 = r->p1; + if(r1 == R) + break; + if(!(r1->refahead.b[z] & bb)) + break; + if(!(r1->act.b[z] & bb)) + break; + r = r1; + } + for(;;) { + r->act.b[z] &= ~bb; + + vreg |= r->regu; + + if(r->refbehind.b[z] & bb) + for(r1 = r->p2; r1 != R; r1 = r1->p2link) + if(r1->refahead.b[z] & bb) + vreg |= paint2(r1, bn); + + if(!(r->refahead.b[z] & bb)) + break; + r1 = r->s2; + if(r1 != R) + if(r1->refbehind.b[z] & bb) + vreg |= paint2(r1, bn); + r = r->s1; + if(r == R) + break; + if(!(r->act.b[z] & bb)) + break; + if(!(r->refbehind.b[z] & bb)) + break; + } + return vreg; +} + +void +paint3(Reg *r, int bn, long rb, int rn) +{ + Reg *r1; + Prog *p; + int z; + ulong bb; + + z = bn/32; + bb = 1L << (bn%32); + if(r->act.b[z] & bb) + return; + for(;;) { + if(!(r->refbehind.b[z] & bb)) + break; + r1 = r->p1; + if(r1 == R) + break; + if(!(r1->refahead.b[z] & bb)) + break; + if(r1->act.b[z] & bb) + break; + r = r1; + } + + if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) + addmove(r, bn, rn, 0); + for(;;) { + r->act.b[z] |= bb; + p = r->prog; + + if(r->use1.b[z] & bb) { + if(debug['R']) + print("%P", p); + addreg(&p->from, rn); +#ifdef maybe + switch(p->as){ + case AMOVB: + case AMOVBU: + case AMOVH: + case AMOVHU: + p->as = AMOVW; + } +#endif + if(debug['R']) + print("\t.c%P\n", p); + } + if((r->use2.b[z]|r->set.b[z]) & bb) { + if(debug['R']) + print("%P", p); + addreg(&p->to, rn); + if(debug['R']) + print("\t.c%P\n", p); + } + + if(STORE(r) & r->regdiff.b[z] & bb) + addmove(r, bn, rn, 1); + r->regu |= rb; + + if(r->refbehind.b[z] & bb) + for(r1 = r->p2; r1 != R; r1 = r1->p2link) + if(r1->refahead.b[z] & bb) + paint3(r1, bn, rb, rn); + + if(!(r->refahead.b[z] & bb)) + break; + r1 = r->s2; + if(r1 != R) + if(r1->refbehind.b[z] & bb) + paint3(r1, bn, rb, rn); + r = r->s1; + if(r == R) + break; + if(r->act.b[z] & bb) + break; + if(!(r->refbehind.b[z] & bb)) + break; + } +} + +void +addreg(Adr *a, int rn) +{ + + a->sym = 0; + a->name = D_NONE; + a->type = D_REG; + a->reg = rn; + if(rn >= NREG) { + a->type = D_FREG; + a->reg = rn-NREG; + } +} + +/* + * bit reg + * 0 R9 + * 1 R10 + * ... ... + * 6 R15 + */ +long +RtoB(int r) +{ + + if(r < 9 || r > 15) + return 0; + return 1L << (r-9); +} + +int +BtoR(long b) +{ + + b &= 0x007fL; + if(b == 0) + return 0; + return bitno(b) + 9; +} + +/* + * bit reg + * 7 F1 + * 8 F2 + * ... ... + * 31 F25 + */ +long +FtoB(int f) +{ + + if(f < 1 || f > 25) + return 0; + return 1L << (f + 6); +} + +int +BtoF(long b) +{ + + b &= 0x03ffff80L; + if(b == 0) + return 0; + return bitno(b) - 6; +} diff --git a/utils/ic/sgen.c b/utils/ic/sgen.c new file mode 100644 index 00000000..b90d8ea2 --- /dev/null +++ b/utils/ic/sgen.c @@ -0,0 +1,259 @@ +#include "gc.h" + +void +noretval(int n) +{ + + if(n & 1) { + gins(ANOP, Z, Z); + p->to.type = D_REG; + p->to.reg = REGRET; + } + if(n & 2) { + gins(ANOP, Z, Z); + p->to.type = D_FREG; + p->to.reg = FREGRET; + } +} + +/* + * calculate addressability as follows + * CONST ==> 20 $value + * NAME ==> 10 name + * REGISTER ==> 11 register + * INDREG ==> 12 *[(reg)+offset] + * &10 ==> 2 $name + * ADD(2, 20) ==> 2 $name+offset + * ADD(3, 20) ==> 3 $(reg)+offset + * &12 ==> 3 $(reg)+offset + * *11 ==> 11 ?? + * *2 ==> 10 name + * *3 ==> 12 *(reg)+offset + * calculate complexity (number of registers) + */ +void +xcom(Node *n) +{ + Node *l, *r; + int t; + + if(n == Z) + return; + l = n->left; + r = n->right; + n->addable = 0; + n->complex = 0; + switch(n->op) { + case OCONST: + n->addable = 20; + return; + + case OREGISTER: + n->addable = 11; + return; + + case OINDREG: + n->addable = 12; + return; + + case ONAME: + n->addable = 10; + return; + + case OADDR: + xcom(l); + if(l->addable == 10) + n->addable = 2; + if(l->addable == 12) + n->addable = 3; + break; + + case OIND: + xcom(l); + if(l->addable == 11) + n->addable = 12; + if(l->addable == 3) + n->addable = 12; + if(l->addable == 2) + n->addable = 10; + break; + + case OADD: + xcom(l); + xcom(r); + if(l->addable == 20) { + if(r->addable == 2) + n->addable = 2; + if(r->addable == 3) + n->addable = 3; + } + if(r->addable == 20) { + if(l->addable == 2) + n->addable = 2; + if(l->addable == 3) + n->addable = 3; + } + break; + + case OASLMUL: + case OASMUL: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OASASHL; + r->vconst = t; + r->type = types[TINT]; + goto shiftassign; + } + break; + + case OMUL: + case OLMUL: + xcom(l); + xcom(r); + t = vlog(l); + if(t >= 0) { + n->left = r; + n->right = l; + l = r; + r = n->right; + } + t = vlog(r); + if(t >= 0) { + n->op = OASHL; + r->vconst = t; + r->type = types[TINT]; + simplifyshift(n); + } + break; + + case OASLDIV: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OASLSHR; + r->vconst = t; + r->type = types[TINT]; + goto shiftassign; + } + break; + + case OLDIV: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OLSHR; + r->vconst = t; + r->type = types[TINT]; + simplifyshift(n); + } + break; + + case OASLMOD: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OASAND; + r->vconst--; + } + break; + + case OLMOD: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OAND; + r->vconst--; + } + break; + + case OLSHR: + case OASHL: + case OASHR: + xcom(l); + xcom(r); + simplifyshift(n); + break; + + case OASLSHR: + case OASASHL: + case OASASHR: + xcom(l); + xcom(r); + shiftassign: + if(typev[l->type->etype] && !machcap(n) && !typev[r->type->etype]){ + if(r->op == OCONST) + r->type = types[TVLONG]; + else{ + n->right = r = new1(OCAST, r, Z); + r->type = types[TVLONG]; + xcom(r); + } + } + break; + + default: + if(l != Z) + xcom(l); + if(r != Z) + xcom(r); + break; + } + if(n->addable >= 10) + return; + + if(l != Z) + n->complex = l->complex; + if(r != Z) { + if(r->complex == n->complex) + n->complex = r->complex+1; + else + if(r->complex > n->complex) + n->complex = r->complex; + } + if(n->complex == 0) + n->complex++; + + if(thechar == 'i' && com64(n)) + return; + + switch(n->op) { + case OFUNC: + n->complex = FNX; + break; + + case OADD: + case OXOR: + case OAND: + case OOR: + case OEQ: + case ONE: + /* + * immediate operators, make const on right + */ + if(l->op == OCONST) { + n->left = r; + n->right = l; + } + break; + + case OLT: + case OLE: + case OGT: + case OGE: + case OLO: + case OLS: + case OHI: + case OHS: + /* + * comparison operators, make const on right + */ + break; + } +} + diff --git a/utils/ic/swt.c b/utils/ic/swt.c new file mode 100644 index 00000000..06d03ae5 --- /dev/null +++ b/utils/ic/swt.c @@ -0,0 +1,620 @@ +#include "gc.h" + +void +swit1(C1 *q, int nc, long def, Node *n) +{ + Node tn; + + if(typev[n->type->etype]) + regalloc(&tn, &vregnode, Z); + else + regalloc(&tn, ®node, Z); + swit2(q, nc, def, n, &tn); + regfree(&tn); +} + +void +swit2(C1 *q, int nc, long def, Node *n, Node *tn) +{ + C1 *r; + int i; + Prog *sp; + + if(nc < 5) { + for(i=0; ival); + gmove(nodgconst(q->val, n->type), tn); + gopcode(OEQ, tn, n, Z); + patch(p, q->label); + q++; + } + gbranch(OGOTO); + patch(p, def); + return; + } + i = nc / 2; + r = q+i; + if(debug['K']) + print("case > %.8llux\n", r->val); + gmove(nodgconst(r->val, n->type), tn); + gopcode(OGT, tn, n, Z); + sp = p; + gopcode(OEQ, tn, n, Z); + patch(p, r->label); + swit2(q, i, def, n, tn); + + if(debug['K']) + print("case < %.8llux\n", r->val); + patch(sp, pc); + swit2(r+1, nc-i-1, def, n, tn); +} + +void +bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) +{ + int sh; + long v; + Node *l; + + /* + * n1 gets adjusted/masked value + * n2 gets address of cell + * n3 gets contents of cell + */ + l = b->left; + if(n2 != Z) { + regalloc(n1, l, nn); + reglcgen(n2, l, Z); + regalloc(n3, l, Z); + gopcode(OAS, n2, Z, n3); + gopcode(OAS, n3, Z, n1); + } else { + regalloc(n1, l, nn); + cgen(l, n1); + } + if(b->type->shift == 0 && typeu[b->type->etype]) { + v = ~0 + (1L << b->type->nbits); + gopcode(OAND, nodconst(v), Z, n1); + } else { + sh = 32 - b->type->shift - b->type->nbits; + if(sh > 0) + gopcode(OASHL, nodconst(sh), Z, n1); + sh += b->type->shift; + if(sh > 0) + if(typeu[b->type->etype]) + gopcode(OLSHR, nodconst(sh), Z, n1); + else + gopcode(OASHR, nodconst(sh), Z, n1); + } +} + +void +bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) +{ + long v; + Node nod, *l; + int sh; + + /* + * n1 has adjusted/masked value + * n2 has address of cell + * n3 has contents of cell + */ + l = b->left; + regalloc(&nod, l, Z); + v = ~0 + (1L << b->type->nbits); + gopcode(OAND, nodconst(v), Z, n1); + gopcode(OAS, n1, Z, &nod); + if(nn != Z) + gopcode(OAS, n1, Z, nn); + sh = b->type->shift; + if(sh > 0) + gopcode(OASHL, nodconst(sh), Z, &nod); + v <<= sh; + gopcode(OAND, nodconst(~v), Z, n3); + gopcode(OOR, n3, Z, &nod); + gopcode(OAS, &nod, Z, n2); + + regfree(&nod); + regfree(n1); + regfree(n2); + regfree(n3); +} + +long +outstring(char *s, long n) +{ + long r; + + if(suppress) + return nstring; + r = nstring; + while(n) { + string[mnstring] = *s++; + mnstring++; + nstring++; + if(mnstring >= NSNAME) { + gpseudo(ADATA, symstring, nodconst(0L)); + p->from.offset += nstring - NSNAME; + p->reg = NSNAME; + p->to.type = D_SCONST; + memmove(p->to.sval, string, NSNAME); + mnstring = 0; + } + n--; + } + return r; +} + +int +mulcon(Node *n, Node *nn) +{ + Node *l, *r, nod1, nod2; + Multab *m; + long v; + int o; + char code[sizeof(m->code)+2], *p; + + if(typefd[n->type->etype]) + return 0; + l = n->left; + r = n->right; + if(l->op == OCONST) { + l = r; + r = n->left; + } + if(r->op != OCONST) + return 0; + v = convvtox(r->vconst, n->type->etype); + if(v != r->vconst) { + if(debug['M']) + print("%L multiply conv: %lld\n", n->lineno, r->vconst); + return 0; + } + m = mulcon0(v); + if(!m) { + if(debug['M']) + print("%L multiply table: %lld\n", n->lineno, r->vconst); + return 0; + } + if(debug['M'] && debug['v']) + print("%L multiply: %ld\n", n->lineno, v); + + memmove(code, m->code, sizeof(m->code)); + code[sizeof(m->code)] = 0; + + p = code; + if(p[1] == 'i') + p += 2; + regalloc(&nod1, n, nn); + cgen(l, &nod1); + if(v < 0) + gopcode(OSUB, &nod1, nodconst(0), &nod1); + regalloc(&nod2, n, Z); + +loop: + switch(*p) { + case 0: + regfree(&nod2); + gopcode(OAS, &nod1, Z, nn); + regfree(&nod1); + return 1; + case '+': + o = OADD; + goto addsub; + case '-': + o = OSUB; + addsub: /* number is r,n,l */ + v = p[1] - '0'; + r = &nod1; + if(v&4) + r = &nod2; + n = &nod1; + if(v&2) + n = &nod2; + l = &nod1; + if(v&1) + l = &nod2; + gopcode(o, l, n, r); + break; + default: /* op is shiftcount, number is r,l */ + v = p[1] - '0'; + r = &nod1; + if(v&2) + r = &nod2; + l = &nod1; + if(v&1) + l = &nod2; + v = *p - 'a'; + if(v < 0 || v >= 32) { + diag(n, "mulcon unknown op: %c%c", p[0], p[1]); + break; + } + gopcode(OASHL, nodconst(v), l, r); + break; + } + p += 2; + goto loop; +} + +void +sextern(Sym *s, Node *a, long o, long w) +{ + long e, lw; + + for(e=0; efrom.offset += o+e; + p->reg = lw; + p->to.type = D_SCONST; + memmove(p->to.sval, a->cstring+e, lw); + } +} + +void +gextern(Sym *s, Node *a, long o, long w) +{ + + if(a->op == OCONST && typev[a->type->etype]) { + gpseudo(ADATA, s, nod32const(a->vconst)); + p->from.offset += o; + p->reg = 4; + gpseudo(ADATA, s, nod32const(a->vconst>>32)); + p->from.offset += o + 4; + p->reg = 4; + return; + } + gpseudo(ADATA, s, a); + p->from.offset += o; + p->reg = w; + if(p->to.type == D_OREG) + p->to.type = D_CONST; +} + +void zname(Biobuf*, Sym*, int); +char* zaddr(char*, Adr*, int); +void zwrite(Biobuf*, Prog*, int, int); +void outhist(Biobuf*); + +void +zwrite(Biobuf *b, Prog *p, int sf, int st) +{ + char bf[100], *bp; + + bf[0] = p->as; + bf[1] = p->reg; + bf[2] = p->lineno; + bf[3] = p->lineno>>8; + bf[4] = p->lineno>>16; + bf[5] = p->lineno>>24; + bp = zaddr(bf+6, &p->from, sf); + bp = zaddr(bp, &p->to, st); + Bwrite(b, bf, bp-bf); +} + +void +outcode(void) +{ + struct { Sym *sym; short type; } h[NSYM]; + Prog *p; + Sym *s; + int sf, st, t, sym; + + if(debug['S']) { + for(p = firstp; p != P; p = p->link) + if(p->as != ADATA && p->as != AGLOBL) + pc--; + for(p = firstp; p != P; p = p->link) { + print("%P\n", p); + if(p->as != ADATA && p->as != AGLOBL) + pc++; + } + } + outhist(&outbuf); + for(sym=0; symlink) { + jackpot: + sf = 0; + s = p->from.sym; + while(s != S) { + sf = s->sym; + if(sf < 0 || sf >= NSYM) + sf = 0; + t = p->from.name; + if(h[sf].type == t) + if(h[sf].sym == s) + break; + s->sym = sym; + zname(&outbuf, s, t); + h[sym].sym = s; + h[sym].type = t; + sf = sym; + sym++; + if(sym >= NSYM) + sym = 1; + break; + } + st = 0; + s = p->to.sym; + while(s != S) { + st = s->sym; + if(st < 0 || st >= NSYM) + st = 0; + t = p->to.name; + if(h[st].type == t) + if(h[st].sym == s) + break; + s->sym = sym; + zname(&outbuf, s, t); + h[sym].sym = s; + h[sym].type = t; + st = sym; + sym++; + if(sym >= NSYM) + sym = 1; + if(st == sf) + goto jackpot; + break; + } + zwrite(&outbuf, p, sf, st); + } + firstp = P; + lastp = P; +} + +void +outhist(Biobuf *b) +{ + Hist *h; + char *p, *q, *op, c; + Prog pg; + int n; + + pg = zprog; + pg.as = AHISTORY; + c = pathchar(); + for(h = hist; h != H; h = h->link) { + p = h->name; + op = 0; + /* on windows skip drive specifier in pathname */ + if(systemtype(Windows) && p && p[1] == ':'){ + p += 2; + c = *p; + } + if(p && p[0] != c && h->offset == 0 && pathname){ + /* on windows skip drive specifier in pathname */ + if(systemtype(Windows) && pathname[1] == ':') { + op = p; + p = pathname+2; + c = *p; + } else if(pathname[0] == c){ + op = p; + p = pathname; + } + } + while(p) { + q = utfrune(p, c); + if(q) { + n = q-p; + if(n == 0){ + n = 1; /* leading "/" */ + *p = '/'; /* don't emit "\" on windows */ + } + q++; + } else { + n = strlen(p); + q = 0; + } + if(n) { + Bputc(b, ANAME); + Bputc(b, D_FILE); + Bputc(b, 1); + Bputc(b, '<'); + Bwrite(b, p, n); + Bputc(b, 0); + } + p = q; + if(p == 0 && op) { + p = op; + op = 0; + } + } + pg.lineno = h->line; + pg.to.type = zprog.to.type; + pg.to.offset = h->offset; + if(h->offset) + pg.to.type = D_CONST; + + zwrite(b, &pg, 0, 0); + } +} + +void +zname(Biobuf *b, Sym *s, int t) +{ + char *n, bf[7]; + ulong sig; + + n = s->name; + if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){ + sig = sign(s); + bf[0] = ASIGNAME; + bf[1] = sig; + bf[2] = sig>>8; + bf[3] = sig>>16; + bf[4] = sig>>24; + bf[5] = t; + bf[6] = s->sym; + Bwrite(b, bf, 7); + s->sig = SIGDONE; + } + else{ + bf[0] = ANAME; + bf[1] = t; /* type */ + bf[2] = s->sym; /* sym */ + Bwrite(b, bf, 3); + } + Bwrite(b, n, strlen(n)+1); +} + +char* +zaddr(char *bp, Adr *a, int s) +{ + long l; + Ieee e; + + bp[0] = a->type; + bp[1] = a->reg; + bp[2] = s; + bp[3] = a->name; + bp += 4; + switch(a->type) { + default: + diag(Z, "unknown type %d in zaddr", a->type); + + case D_NONE: + case D_REG: + case D_FREG: + case D_FCREG: + break; + + case D_OREG: + case D_CONST: + case D_BRANCH: + l = a->offset; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + break; + + case D_VCONST: + l = *(long*)a->sval; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + l = *((long*)a->sval + 1); + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + break; + + case D_SCONST: + memmove(bp, a->sval, NSNAME); + bp += NSNAME; + break; + + case D_FCONST: + ieeedtod(&e, a->dval); + l = e.l; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + l = e.h; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + break; + } + return bp; +} + +long +align(long i, Type *t, int op) +{ + long o; + Type *v; + int w; + int linksave; + + o = i; + w = 1; + linksave = 0; + switch(op) { + default: + diag(Z, "unknown align opcode %d", op); + break; + + case Asu2: /* padding at end of a struct */ + if(o <= SZ_LONG) + w = SZ_LONG; + else + w = SZ_VLONG; + if(packflg) + w = packflg; + break; + + case Ael1: /* initial align of struct element */ + for(v=t; v->etype==TARRAY; v=v->link) + ; + w = v->width; + if(w <= 0 || w >= SZ_VLONG) + w = SZ_VLONG; + if(packflg) + w = packflg; + break; + + case Ael2: /* width of a struct element */ + o += t->width; + break; + + case Aarg0: /* initial passbyptr argument in arg list */ + if(typecmplx[t->etype]) { + o = align(o, types[TIND], Aarg1); + o = align(o, types[TIND], Aarg2); + } + break; + + case Aarg1: /* initial align of parameter */ + w = t->width; + if(w > 0 && w <= SZ_LONG){ + w = 1; /* little endian no adjustment */ + break; + } + if(w < SZ_VLONG) + diag(Z, "compiler bug? type %T width %d\n", t, w); + w = SZ_VLONG; + linksave = ewidth[TIND]; + break; + + case Aarg2: /* width of a parameter */ + o += t->width; + w = SZ_LONG; + break; + + case Aaut3: /* total align of automatic */ + o = align(o, t, Ael1); + o = align(o, t, Ael2); + break; + } + o = round(o + linksave, w) - linksave; + if(debug['A']) + print("align %s %ld %T = %ld\n", bnames[op], i, t, o); + return o; +} + +long +maxround(long max, long v) +{ + v = round(v, ewidth[TIND]); + if(v > max) + return v; + return max; +} diff --git a/utils/ic/txt.c b/utils/ic/txt.c new file mode 100644 index 00000000..a1327fd0 --- /dev/null +++ b/utils/ic/txt.c @@ -0,0 +1,1473 @@ +#include "gc.h" + +static long ncast64[]; + +extern void ccmain(int, char**); + +void +main(int argc, char **argv) +{ + char *p; + int oargc; + char **oargv; + + thechar = 'i'; + p = strrchr(argv[0], '/'); + if(p == nil) + p = argv[0]; + else + p++; + if(*p == 'j') + thechar = 'j'; + oargc = argc; + oargv = argv; + ARGBEGIN { + case 'j': + thechar = 'j'; + break; + case 'o': + case 'D': + case 'I': + p = ARGF(); + } ARGEND + USED(p); + + if(thechar == 'j'){ + thestring = "riscv64"; + ewidth[TIND] = 8; + }else{ + thestring = "riscv"; + ewidth[TIND] = 4; + } + ccmain(oargc, oargv); +} + +void +ginit(void) +{ + int i; + Type *t; + + exregoffset = REGEXT; + exfregoffset = FREGEXT; + listinit(); + nstring = 0; + mnstring = 0; + nrathole = 0; + pc = 0; + breakpc = -1; + continpc = -1; + cases = C; + firstp = P; + lastp = P; + tfield = types[TLONG]; + + if(thechar == 'j'){ + typeword = typechlvp; + typeswitch = typechlv; + typecmplx = typesu; + } + + zprog.link = P; + zprog.as = AGOK; + zprog.reg = NREG; + zprog.from.type = D_NONE; + zprog.from.name = D_NONE; + zprog.from.reg = NREG; + zprog.to = zprog.from; + + regnode.op = OREGISTER; + regnode.class = CEXREG; + regnode.reg = REGTMP; + regnode.complex = 0; + regnode.addable = 11; + regnode.type = types[TLONG]; + + vregnode = regnode; + vregnode.type = types[TVLONG]; + + constnode.op = OCONST; + constnode.class = CXXX; + constnode.complex = 0; + constnode.addable = 20; + constnode.type = types[TLONG]; + + vconstnode = constnode; + vconstnode.type = types[TVLONG]; + + fconstnode.op = OCONST; + fconstnode.class = CXXX; + fconstnode.complex = 0; + fconstnode.addable = 20; + fconstnode.type = types[TDOUBLE]; + + nodsafe = new(ONAME, Z, Z); + nodsafe->sym = slookup(".safe"); + nodsafe->type = types[TINT]; + nodsafe->etype = types[TINT]->etype; + nodsafe->class = CAUTO; + complex(nodsafe); + + t = typ(TARRAY, types[TCHAR]); + symrathole = slookup(".rathole"); + symrathole->class = CGLOBL; + symrathole->type = t; + + nodrat = new(ONAME, Z, Z); + nodrat->sym = symrathole; + nodrat->type = types[TIND]; + nodrat->etype = TVOID; + nodrat->class = CGLOBL; + complex(nodrat); + nodrat->type = t; + + nodret = new(ONAME, Z, Z); + nodret->sym = slookup(".ret"); + nodret->type = types[TIND]; + nodret->etype = TIND; + nodret->class = CPARAM; + nodret = new(OIND, nodret, Z); + complex(nodret); + + if(thechar == 'i'){ + com64init(); + }else{ + memmove(ncast, ncast64, NTYPE*sizeof(long)); + } + + for(i=0; itype->width = nstring; + symrathole->type->width = nrathole; + for(i=0; ilink) { + if(s->type == T) + continue; + if(s->type->width == 0) + continue; + if(s->class != CGLOBL && s->class != CSTATIC) + continue; + if(s->type == types[TENUM]) + continue; + gpseudo(AGLOBL, s, nodconst(s->type->width)); + } + nextpc(); + p->as = AEND; + outcode(); +} + +void +nextpc(void) +{ + + p = alloc(sizeof(*p)); + *p = zprog; + p->lineno = nearln; + pc++; + if(firstp == P) { + firstp = p; + lastp = p; + return; + } + lastp->link = p; + lastp = p; +} + +void +gargs(Node *n, Node *tn1, Node *tn2) +{ + long regs; + Node fnxargs[20], *fnxp; + + regs = cursafe; + + fnxp = fnxargs; + garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */ + + curarg = 0; + fnxp = fnxargs; + garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */ + + cursafe = regs; +} + +void +garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp) +{ + Node nod; + + if(n == Z) + return; + if(n->op == OLIST) { + garg1(n->left, tn1, tn2, f, fnxp); + garg1(n->right, tn1, tn2, f, fnxp); + return; + } + if(f == 0) { + if(n->complex >= FNX) { + regsalloc(*fnxp, n); + nod = znode; + nod.op = OAS; + nod.left = *fnxp; + nod.right = n; + nod.type = n->type; + cgen(&nod, Z); + (*fnxp)++; + } + return; + } + if(typecmplx[n->type->etype]) { + regaalloc(tn2, n); + if(n->complex >= FNX) { + sugen(*fnxp, tn2, n->type->width); + (*fnxp)++; + } else + sugen(n, tn2, n->type->width); + return; + } + if(REGARG && curarg == 0 && typeword[n->type->etype]) { + regaalloc1(tn1, n); + if(n->complex >= FNX) { + cgen(*fnxp, tn1); + (*fnxp)++; + } else + cgen(n, tn1); + return; + } + if(vconst(n) == 0) { + regaalloc(tn2, n); + gopcode(OAS, n, Z, tn2); + return; + } + regalloc(tn1, n, Z); + if(n->complex >= FNX) { + cgen(*fnxp, tn1); + (*fnxp)++; + } else + cgen(n, tn1); + regaalloc(tn2, n); + gopcode(OAS, tn1, Z, tn2); + regfree(tn1); +} + +Node* +nodgconst(vlong v, Type *t) +{ + if(!typev[t->etype]) + return nodconst((long)v); + vconstnode.vconst = v; + return &vconstnode; +} + +Node* +nodconst(long v) +{ + constnode.vconst = v; + return &constnode; +} + +Node* +nod32const(vlong v) +{ + constnode.vconst = v & MASK(32); + return &constnode; +} + +Node* +nodfconst(double d) +{ + fconstnode.fconst = d; + return &fconstnode; +} + +void +nodreg(Node *n, Node *nn, int reg) +{ + *n = regnode; + n->reg = reg; + n->type = nn->type; + n->lineno = nn->lineno; +} + +void +regret(Node *n, Node *nn) +{ + int r; + + r = REGRET; + if(typefd[nn->type->etype]) + r = FREGRET+NREG; + nodreg(n, nn, r); + reg[r]++; +} + +int +tmpreg(void) +{ + int i; + + for(i=REGRET+1; itype->etype) { + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TVLONG: + case TUVLONG: + case TIND: + if(o != Z && o->op == OREGISTER) { + i = o->reg; + if(i > 0 && i < NREG) + goto out; + } + j = lasti + REGRET+1; + for(i=REGRET+1; i<=REGALLOC; i++) { + if(j > REGALLOC) + j = REGRET+1; + if(reg[j] == 0) { + i = j; + goto out0; + } + j++; + } + diag(tn, "out of fixed registers"); + goto err; + + case TFLOAT: + case TDOUBLE: + if(o != Z && o->op == OREGISTER) { + i = o->reg; + if(i >= NREG && i < NREG+NREG) + goto out; + } + for(j=NREG; jtype); +err: + nodreg(n, tn, 0); + return; +out0: + lasti++; + if(lasti >= 5) + lasti = 0; +out: + reg[i]++; + nodreg(n, tn, i); +} + +void +regialloc(Node *n, Node *tn, Node *o) +{ + Node nod; + + nod = *tn; + nod.type = types[TIND]; + regalloc(n, &nod, o); +} + +void +regfree(Node *n) +{ + int i; + + i = 0; + if(n->op != OREGISTER && n->op != OINDREG) + goto err; + i = n->reg; + if(i < 0 || i >= sizeof(reg)) + goto err; + if(reg[i] <= 0) + goto err; + reg[i]--; + return; +err: + diag(n, "error in regfree: %d", i); +} + +void +regsalloc(Node *n, Node *nn) +{ + cursafe = align(cursafe + stkoff, nn->type, Aaut3) - stkoff; + maxargsafe = maxround(maxargsafe, cursafe+curarg); + *n = *nodsafe; + n->xoffset = -(stkoff + cursafe); + n->type = nn->type; + n->etype = nn->type->etype; + n->lineno = nn->lineno; +} + +void +regaalloc1(Node *n, Node *nn) +{ + nodreg(n, nn, REGARG); + reg[REGARG]++; + curarg = align(curarg, nn->type, Aarg1); + curarg = align(curarg, nn->type, Aarg2); + maxargsafe = maxround(maxargsafe, cursafe+curarg); +} + +void +regaalloc(Node *n, Node *nn) +{ + curarg = align(curarg, nn->type, Aarg1); + *n = *nn; + n->op = OINDREG; + n->reg = REGSP; + n->xoffset = curarg + ewidth[TIND]; + n->complex = 0; + n->addable = 20; + curarg = align(curarg, nn->type, Aarg2); + maxargsafe = maxround(maxargsafe, cursafe+curarg); +} + +void +regind(Node *n, Node *nn) +{ + + if(n->op != OREGISTER) { + diag(n, "regind not OREGISTER"); + return; + } + n->op = OINDREG; + n->type = nn->type; +} + +void +raddr(Node *n, Prog *p) +{ + Adr a; + + naddr(n, &a); + if(a.type == D_CONST && a.offset == 0) { + a.type = D_REG; + a.reg = 0; + } + if(a.type != D_REG && a.type != D_FREG) { + if(n) + diag(n, "bad in raddr: %O", n->op); + else + diag(n, "bad in raddr: "); + p->reg = NREG; + } else + p->reg = a.reg; +} + +void +naddr(Node *n, Adr *a) +{ + long v; + + a->type = D_NONE; + if(n == Z) + return; + switch(n->op) { + default: + bad: + diag(n, "bad in naddr: %O", n->op); + break; + + case OREGISTER: + a->type = D_REG; + a->sym = S; + a->reg = n->reg; + if(a->reg >= NREG) { + a->type = D_FREG; + a->reg -= NREG; + } + break; + + case OIND: + naddr(n->left, a); + if(a->type == D_REG) { + a->type = D_OREG; + break; + } + if(a->type == D_CONST) { + a->type = D_OREG; + break; + } + goto bad; + + case OINDREG: + a->type = D_OREG; + a->sym = S; + a->offset = n->xoffset; + a->reg = n->reg; + break; + + case ONAME: + a->etype = n->etype; + a->type = D_OREG; + a->name = D_STATIC; + a->sym = n->sym; + a->offset = n->xoffset; + if(n->class == CSTATIC) + break; + if(n->class == CEXTERN || n->class == CGLOBL) { + a->name = D_EXTERN; + break; + } + if(n->class == CAUTO) { + a->name = D_AUTO; + break; + } + if(n->class == CPARAM) { + a->name = D_PARAM; + break; + } + goto bad; + + case OCONST: + a->sym = S; + a->reg = NREG; + if(typefd[n->type->etype]) { + a->type = D_FCONST; + a->dval = n->fconst; + } else { + v = (long)n->vconst; + if(thechar == 'j' && (vlong)v != n->vconst) { + a->type = D_VCONST; + *(vlong*)a->sval = n->vconst; + } else { + a->type = D_CONST; + a->offset = n->vconst; + } + } + break; + + case OADDR: + naddr(n->left, a); + if(a->type == D_OREG) { + a->type = D_CONST; + break; + } + goto bad; + + case OADD: + if(n->left->op == OCONST) { + naddr(n->left, a); + v = a->offset; + naddr(n->right, a); + } else { + naddr(n->right, a); + v = a->offset; + naddr(n->left, a); + } + a->offset += v; + break; + + } +} + +void +fop(int as, int f1, int f2, Node *t) +{ + Node nod1, nod2, nod3; + + nodreg(&nod1, t, NREG+f1); + nodreg(&nod2, t, NREG+f2); + regalloc(&nod3, t, t); + gopcode(as, &nod1, &nod2, &nod3); + gmove(&nod3, t); + regfree(&nod3); +} + +void +gmove(Node *f, Node *t) +{ + int ft, tt, a; + Node nod; + double d; + + ft = f->type->etype; + tt = t->type->etype; + + if(ft == TDOUBLE && f->op == OCONST) { + d = f->fconst; + if(d == 0) { + a = FREGZERO; + goto ffreg; + } + if(d == 0.5) { + a = FREGHALF; + goto ffreg; + } + if(d == 1.0) { + a = FREGONE; + goto ffreg; + } + if(d == 2.0) { + a = FREGTWO; + goto ffreg; + } + if(d == -.5) { + fop(OSUB, FREGHALF, FREGZERO, t); + return; + } + if(d == -1.0) { + fop(OSUB, FREGONE, FREGZERO, t); + return; + } + if(d == -2.0) { + fop(OSUB, FREGTWO, FREGZERO, t); + return; + } + if(d == 1.5) { + fop(OADD, FREGONE, FREGHALF, t); + return; + } + if(d == 2.5) { + fop(OADD, FREGTWO, FREGHALF, t); + return; + } + if(d == 3.0) { + fop(OADD, FREGTWO, FREGONE, t); + return; + } + } + if(ft == TFLOAT && f->op == OCONST) { + d = f->fconst; + if(d == 0) { + a = FREGZERO; + ffreg: + nodreg(&nod, f, NREG+a); + gmove(&nod, t); + return; + } + } + + /* + * a load -- + * put it into a register then + * worry what to do with it. + */ + if(f->op == ONAME || f->op == OINDREG || f->op == OIND) { + switch(ft) { + default: + a = AMOV; + break; + case TFLOAT: + a = AMOVF; + break; + case TDOUBLE: + a = AMOVD; + break; + case TCHAR: + a = AMOVB; + break; + case TUCHAR: + a = AMOVBU; + break; + case TSHORT: + a = AMOVH; + break; + case TUSHORT: + a = AMOVHU; + break; + case TINT: + case TLONG: + a = AMOVW; + break; + case TUINT: + case TULONG: + a = AMOVWU; + break; + case TIND: + a = thechar == 'j' ? AMOV : AMOVW; + break; + } + if(typechlp[ft] && typeilp[tt]) + regalloc(&nod, t, t); + else + regalloc(&nod, f, t); + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + + /* + * a store -- + * put it into a register then + * store it. + */ + if(t->op == ONAME || t->op == OINDREG || t->op == OIND) { + switch(tt) { + default: + a = AMOVW; + break; + case TUCHAR: + case TCHAR: + a = AMOVB; + break; + case TUSHORT: + case TSHORT: + a = AMOVH; + break; + case TFLOAT: + a = AMOVF; + break; + case TDOUBLE: + a = AMOVD; + break; + case TVLONG: + case TUVLONG: + a = AMOV; + break; + case TIND: + a = thechar == 'j' ? AMOV : AMOVW; + break; + } + if(!typefd[ft] && vconst(f) == 0) { +#ifdef notyet + nodreg(&nod, f, REGZERO); + gins(a, &nod, t); +#else + gins(a, f, t); +#endif + return; + } + if(ft == tt) + regalloc(&nod, t, f); + else + regalloc(&nod, t, Z); + gmove(f, &nod); + gins(a, &nod, t); + regfree(&nod); + return; + } + + /* + * type x type cross table + */ + a = AGOK; + switch(ft) { + case TDOUBLE: + case TFLOAT: + switch(tt) { + case TDOUBLE: + a = AMOVD; + if(ft == TFLOAT) + a = AMOVFD; + break; + case TFLOAT: + a = AMOVDF; + if(ft == TFLOAT) + a = AMOVF; + break; + case TVLONG: + case TUVLONG: + a = AMOVDV; + if(ft == TFLOAT) + a = AMOVFV; + break; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVDW; + if(ft == TFLOAT) + a = AMOVFW; + break; + } + break; + + case TVLONG: + case TUVLONG: + fvlong: + switch(tt) { + case TDOUBLE: + a = ft == TUVLONG ? AMOVUVD : AMOVVD; + break; + case TFLOAT: + a = ft == TUVLONG ? AMOVUVF : AMOVVF; + break; + case TVLONG: + case TUVLONG: + case TIND: + a = AMOV; + break; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + + case TINT: + case TLONG: + switch(tt) { + case TDOUBLE: + gins(AMOVWD, f, t); + return; + case TFLOAT: + gins(AMOVWF, f, t); + return; + case TVLONG: + case TUVLONG: + a = AMOVW; + break; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOV; + break; + } + break; + + case TIND: + if(thechar == 'j') + goto fvlong; + /* fall through */ + case TUINT: + case TULONG: + switch(tt) { + case TDOUBLE: + gins(AMOVUD, f, t); + return; + case TFLOAT: + gins(AMOVUF, f, t); + return; + case TVLONG: + case TUVLONG: + a = AMOVWU; + break; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOV; + break; + } + break; + + case TSHORT: + switch(tt) { + case TDOUBLE: + regalloc(&nod, f, Z); + gins(AMOVH, f, &nod); + gins(AMOVWD, &nod, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVH, f, &nod); + gins(AMOVWF, &nod, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TVLONG: + case TUVLONG: + a = AMOVH; + break; + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOV; + break; + } + break; + case TUSHORT: + switch(tt) { + case TDOUBLE: + regalloc(&nod, f, Z); + gins(AMOVHU, f, &nod); + gins(AMOVWD, &nod, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVHU, f, &nod); + gins(AMOVWF, &nod, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TVLONG: + case TUVLONG: + a = AMOVHU; + break; + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOV; + break; + } + break; + case TCHAR: + switch(tt) { + case TDOUBLE: + regalloc(&nod, f, Z); + gins(AMOVB, f, &nod); + gins(AMOVWD, &nod, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVB, f, &nod); + gins(AMOVWF, &nod, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TVLONG: + case TUVLONG: + case TSHORT: + case TUSHORT: + a = AMOVB; + break; + case TCHAR: + case TUCHAR: + a = AMOV; + break; + } + break; + case TUCHAR: + switch(tt) { + case TDOUBLE: + regalloc(&nod, f, Z); + gins(AMOVBU, f, &nod); + gins(AMOVWD, &nod, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVBU, f, &nod); + gins(AMOVWF, &nod, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TVLONG: + case TUVLONG: + case TSHORT: + case TUSHORT: + a = AMOVBU; + break; + case TCHAR: + case TUCHAR: + a = AMOV; + break; + } + break; + } + if(a == AGOK) + diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type); + if(a == AMOV || (thechar == 'i' && (a == AMOVW || a == AMOVWU)) || a == AMOVF || a == AMOVD) + if(samaddr(f, t)) + return; + gins(a, f, t); +} + +void +gins(int a, Node *f, Node *t) +{ + + nextpc(); + p->as = a; + if(f != Z) + naddr(f, &p->from); + if(t != Z) + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); +} + +void +gopcode(int o, Node *f1, Node *f2, Node *t) +{ + int a, ab, et, tword; + Adr ta; + + tword = 0; + if(thechar == 'j') + if(t != Z && t->type != T) + if((et = t->type->etype) != TIND && !typev[et]) + tword = 1; + et = TLONG; + if(f1 != Z && f1->type != T) + et = f1->type->etype; + a = AGOK; + switch(o) { + case OAS: + gmove(f1, t); + return; + + case OASADD: + case OADD: + a = tword ? AADDW : AADD; + if(et == TFLOAT) + a = AADDF; + else + if(et == TDOUBLE) + a = AADDD; + break; + + case OASSUB: + case OSUB: + a = tword ? ASUBW : ASUB; + if(et == TFLOAT) + a = ASUBF; + else + if(et == TDOUBLE) + a = ASUBD; + break; + + case OASOR: + case OOR: + a = AOR; + break; + + case OASAND: + case OAND: + a = AAND; + break; + + case OASXOR: + case OXOR: + a = AXOR; + break; + + case OASLSHR: + case OLSHR: + a = tword ? ASRLW : ASRL; + break; + + case OASASHR: + case OASHR: + a = tword ? ASRAW : ASRA; + break; + + case OASASHL: + case OASHL: + a = tword ? ASLLW : ASLL; + break; + + case OFUNC: + a = AJAL; + break; + + case OCOND: + a = ASLTU; + break; + + case OCOMMA: + a = ASLT; + break; + + case OASMUL: + case OMUL: + if(et == TFLOAT) { + a = AMULF; + break; + } else + if(et == TDOUBLE) { + a = AMULD; + break; + } + a = tword ? AMULW : AMUL; + break; + + case OASDIV: + case ODIV: + if(et == TFLOAT) { + a = ADIVF; + break; + } else + if(et == TDOUBLE) { + a = ADIVD; + break; + } + a = tword ? ADIVW : ADIV; + break; + + case OASMOD: + case OMOD: + a = tword ? AREMW : AREM; + break; + + case OASLMUL: + case OLMUL: + a = tword ? AMULW : AMUL; + break; + + case OASLMOD: + case OLMOD: + a = tword ? AREMUW : AREMU; + break; + + case OASLDIV: + case OLDIV: + a = tword ? ADIVUW : ADIVU; + break; + + case OEQ: + if(!typefd[et]) { + a = ABEQ; + break; + } + a = et == TFLOAT? ACMPEQF : ACMPEQD; + ab = ABNE; + goto cmpfloat; + case ONE: + if(!typefd[et]) { + a = ABNE; + break; + } + a = et == TFLOAT? ACMPEQF : ACMPEQD; + ab = ABEQ; + goto cmpfloat; + case OLT: + if(!typefd[et]) { + a = ABLT; + break; + } + a = et == TFLOAT? ACMPLTF : ACMPLTD; + ab = ABNE; + goto cmpfloat; + case OLE: + if(!typefd[et]) { + a = ABLE; /* pseudo op */ + break; + } + a = et == TFLOAT? ACMPLEF : ACMPLED; + ab = ABNE; + goto cmpfloat; + case OGE: + if(!typefd[et]) { + a = ABGE; + break; + } + a = et == TFLOAT? ACMPLTF : ACMPLTD; + ab = ABEQ; + goto cmpfloat; + case OGT: + if(!typefd[et]) { + a = ABGT; /* pseudo op */ + break; + } + a = et == TFLOAT? ACMPLEF : ACMPLED; + ab = ABEQ; + goto cmpfloat; + case OLO: + a = ABLTU; + break; + case OLS: + a = ABLEU; /* pseudo op */ + break; + case OHS: + a = ABGEU; + break; + case OHI: + a = ABGTU; /* pseudo op */ + break; + + cmpfloat: + nextpc(); + p->as = a; + naddr(f1, &p->from); + raddr(f2, p); + if(t != Z) + naddr(t, &p->to); + else { + naddr(®node, &p->to); + p->to.reg = tmpreg(); + } + if(debug['g']) + print("%P\n", p); + if(t == Z) { + nextpc(); + p->as = ab; + naddr(®node, &p->from); + p->from.reg = tmpreg(); + if(debug['g']) + print("%P\n", p); + } else if (ab == ABNE) { + nextpc(); + p->as = AXOR; + naddr(nodconst(1), &p->from); + raddr(t, p); + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); + } + return; + } + if(a == AGOK) + diag(Z, "bad in gopcode %O", o); + nextpc(); + p->as = a; + if(f1 != Z) + naddr(f1, &p->from); + if(f2 != Z) { + naddr(f2, &ta); + p->reg = ta.reg; + if(ta.type == D_CONST && ta.offset == 0) + p->reg = REGZERO; + } + if(t != Z) + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); +} + +int +samaddr(Node *f, Node *t) +{ + + if(f->op != t->op) + return 0; + switch(f->op) { + + case OREGISTER: + if(f->reg != t->reg) + break; + return 1; + } + return 0; +} + +void +gbranch(int o) +{ + int a; + + a = AGOK; + switch(o) { + case ORETURN: + a = ARET; + break; + case OGOTO: + a = AJMP; + break; + } + nextpc(); + if(a == AGOK) { + diag(Z, "bad in gbranch %O", o); + nextpc(); + } + p->as = a; +} + +void +patch(Prog *op, long pc) +{ + + op->to.offset = pc; + op->to.type = D_BRANCH; +} + +void +gpseudo(int a, Sym *s, Node *n) +{ + + nextpc(); + p->as = a; + p->from.type = D_OREG; + p->from.sym = s; + if(a == ATEXT) + p->reg = (profileflg ? 0 : NOPROF); + p->from.name = D_EXTERN; + if(s->class == CSTATIC) + p->from.name = D_STATIC; + naddr(n, &p->to); + if(a == ADATA || a == AGLOBL) + pc--; +} + +int +sconst(Node *n) +{ + vlong vv; + + if(n->op == OCONST) { + if(!typefd[n->type->etype]) { + vv = n->vconst; + if(vv >= (vlong)(-2048) && vv < (vlong)2048) + return 1; + } + } + return 0; +} + +int +sval(long v) +{ + if(v >= -32766L && v < 32766L) + return 1; + return 0; +} + +long +exreg(Type *t) +{ + long o; + + if(typechlp[t->etype]) { + if(exregoffset <= REGTMP) + return 0; + o = exregoffset; + exregoffset--; + return o; + } + if(typefd[t->etype]) { + if(exfregoffset <= 16) + return 0; + o = exfregoffset + NREG; + exfregoffset--; + return o; + } + return 0; +} + +schar ewidth[NTYPE] = +{ + -1, /* [TXXX] */ + SZ_CHAR, /* [TCHAR] */ + SZ_CHAR, /* [TUCHAR] */ + SZ_SHORT, /* [TSHORT] */ + SZ_SHORT, /* [TUSHORT] */ + SZ_INT, /* [TINT] */ + SZ_INT, /* [TUINT] */ + SZ_LONG, /* [TLONG] */ + SZ_LONG, /* [TULONG] */ + SZ_VLONG, /* [TVLONG] */ + SZ_VLONG, /* [TUVLONG] */ + SZ_FLOAT, /* [TFLOAT] */ + SZ_DOUBLE, /* [TDOUBLE] */ + 0, /* [TIND] - set to 4 or 8 in main */ + 0, /* [TFUNC] */ + -1, /* [TARRAY] */ + 0, /* [TVOID] */ + -1, /* [TSTRUCT] */ + -1, /* [TUNION] */ + SZ_INT, /* [TENUM] */ +}; + +long ncast[NTYPE] = +{ + 0, /* [TXXX] */ + BCHAR|BUCHAR, /* [TCHAR] */ + BCHAR|BUCHAR, /* [TUCHAR] */ + BSHORT|BUSHORT, /* [TSHORT] */ + BSHORT|BUSHORT, /* [TUSHORT] */ + BINT|BUINT|BLONG|BULONG|BIND, /* [TINT] */ + BINT|BUINT|BLONG|BULONG|BIND, /* [TUINT] */ + BINT|BUINT|BLONG|BULONG|BIND, /* [TLONG] */ + BINT|BUINT|BLONG|BULONG|BIND, /* [TULONG] */ + BVLONG|BUVLONG, /* [TVLONG] */ + BVLONG|BUVLONG, /* [TUVLONG] */ + BFLOAT, /* [TFLOAT] */ + BDOUBLE, /* [TDOUBLE] */ + BLONG|BULONG|BIND, /* [TIND] */ + 0, /* [TFUNC] */ + 0, /* [TARRAY] */ + 0, /* [TVOID] */ + BSTRUCT, /* [TSTRUCT] */ + BUNION, /* [TUNION] */ + 0, /* [TENUM] */ +}; + +static long ncast64[NTYPE] = +{ + 0, /* [TXXX] */ + BCHAR|BUCHAR, /* [TCHAR] */ + BCHAR|BUCHAR, /* [TUCHAR] */ + BSHORT|BUSHORT, /* [TSHORT] */ + BSHORT|BUSHORT, /* [TUSHORT] */ + BINT|BUINT|BLONG|BULONG, /* [TINT] */ + BINT|BUINT|BLONG|BULONG, /* [TUINT] */ + BINT|BUINT|BLONG|BULONG, /* [TLONG] */ + BINT|BUINT|BLONG|BULONG, /* [TULONG] */ + BVLONG|BUVLONG|BIND, /* [TVLONG] */ + BVLONG|BUVLONG|BIND, /* [TUVLONG] */ + BFLOAT, /* [TFLOAT] */ + BDOUBLE, /* [TDOUBLE] */ + BVLONG|BUVLONG|BIND, /* [TIND] */ + 0, /* [TFUNC] */ + 0, /* [TARRAY] */ + 0, /* [TVOID] */ + BSTRUCT, /* [TSTRUCT] */ + BUNION, /* [TUNION] */ + 0, /* [TENUM] */ +}; diff --git a/utils/il/asm.c b/utils/il/asm.c new file mode 100644 index 00000000..b0b1ce8f --- /dev/null +++ b/utils/il/asm.c @@ -0,0 +1,966 @@ +#include "l.h" + +long OFFSET; + +xlong +entryvalue(void) +{ + char *a; + Sym *s; + + a = INITENTRY; + if(*a >= '0' && *a <= '9') + return atolwhex(a); + s = lookup(a, 0); + if(s->type == 0) + return INITTEXT; + if(s->type != STEXT && s->type != SLEAF) + diag("entry not text: %s", s->name); + return s->value + INITTEXT; +} + +void +asmb(void) +{ + Prog *p; + long t, etext; + Optab *o; + + if(debug['v']) + Bprint(&bso, "%5.2f asm\n", cputime()); + Bflush(&bso); + OFFSET = HEADR; + seek(cout, OFFSET, 0); + pc = 0; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + /* align on word boundary */ + if(!debug['c'] && (pc & 2) != 0){ + nopalign.pc = pc; + pc += asmout(&nopalign, oplook(&nopalign), 0); + } + curtext = p; + autosize = p->to.offset + ptrsize; + } + if(p->pc != pc) { + diag("phase error %lux sb %lux", + p->pc, pc); + if(!debug['a']) + prasm(curp); + pc = p->pc; + } + curp = p; + o = oplook(p); /* could probably avoid this call */ + pc += asmout(p, o, 0); + } + if(debug['a']) + Bprint(&bso, "\n"); + Bflush(&bso); + cflush(); + + etext = textsize; + for(t = pc; t < etext; t += sizeof(buf)-100) { + if(etext-t > sizeof(buf)-100) + datblk(t, sizeof(buf)-100, 1); + else + datblk(t, etext-t, 1); + } + + Bflush(&bso); + cflush(); + + curtext = P; + switch(HEADTYPE) { + case 0: + case 4: + OFFSET = rnd(HEADR+textsize, 4096); + seek(cout, OFFSET, 0); + break; + case 1: + case 2: + case 3: + case 5: + case 6: + OFFSET = HEADR+textsize; + seek(cout, OFFSET, 0); + break; + } + for(t = 0; t < datsize; t += sizeof(buf)-100) { + if(datsize-t > sizeof(buf)-100) + datblk(t, sizeof(buf)-100, 0); + else + datblk(t, datsize-t, 0); + } + + symsize = 0; + lcsize = 0; + if(!debug['s']) { + if(debug['v']) + Bprint(&bso, "%5.2f sym\n", cputime()); + Bflush(&bso); + switch(HEADTYPE) { + case 0: + case 4: + OFFSET = rnd(HEADR+textsize, 4096)+datsize; + seek(cout, OFFSET, 0); + break; + case 3: + case 2: + case 1: + case 5: + case 6: + OFFSET = HEADR+textsize+datsize; + seek(cout, OFFSET, 0); + break; + } + if(!debug['s']) + asmsym(); + if(debug['v']) + Bprint(&bso, "%5.2f pc\n", cputime()); + Bflush(&bso); + if(!debug['s']) + asmlc(); + cflush(); + } + + if(debug['v']) + Bprint(&bso, "%5.2f header\n", cputime()); + Bflush(&bso); + OFFSET = 0; + seek(cout, OFFSET, 0); + switch(HEADTYPE) { + case 1: + break; + case 2: + /* XXX expanded header needed? */ + t = thechar == 'j' ? 30 : 29; + lput(((((4*t)+0)*t)+7)); /* magic */ + lput(textsize); /* sizes */ + lput(datsize); + lput(bsssize); + lput(symsize); /* nsyms */ + lput(entryvalue()); /* va of entry */ + lput(0L); + lput(lcsize); + break; + case 5: + if(thechar == 'j') + elf64(243, ELFDATA2LSB, 0, nil); /* 243 is RISCV */ + else + elf32(243, ELFDATA2LSB, 0, nil); + } + cflush(); +} + +void +strnput(char *s, int n) +{ + for(; *s; s++){ + cput(*s); + n--; + } + for(; n > 0; n--) + cput(0); +} + +void +cput(int c) +{ + cbp[0] = c; + cbp++; + cbc--; + if(cbc <= 0) + cflush(); +} + +void +wput(long l) +{ + + cbp[0] = l>>8; + cbp[1] = l; + cbp += 2; + cbc -= 2; + if(cbc <= 0) + cflush(); +} + +void +wputl(long l) +{ + + cbp[0] = l; + cbp[1] = l>>8; + cbp += 2; + cbc -= 2; + if(cbc <= 0) + cflush(); +} + +void +lput(long l) +{ + + cbp[0] = l>>24; + cbp[1] = l>>16; + cbp[2] = l>>8; + cbp[3] = l; + cbp += 4; + cbc -= 4; + if(cbc <= 0) + cflush(); +} + +void +lputl(long l) +{ + + cbp[3] = l>>24; + cbp[2] = l>>16; + cbp[1] = l>>8; + cbp[0] = l; + cbp += 4; + cbc -= 4; + if(cbc <= 0) + cflush(); +} + +void +llput(vlong v) +{ + lput(v>>32); + lput(v); +} + +void +llputl(vlong v) +{ + lputl(v); + lputl(v>>32); +} + +void +cflush(void) +{ + int n; + + n = sizeof(buf.cbuf) - cbc; + if(n) + write(cout, buf.cbuf, n); + cbp = buf.cbuf; + cbc = sizeof(buf.cbuf); +} + +void +nopstat(char *f, Count *c) +{ + if(c->outof) + Bprint(&bso, "%s delay %ld/%ld (%.2f)\n", f, + c->outof - c->count, c->outof, + (double)(c->outof - c->count)/c->outof); +} + +void +asmsym(void) +{ + Prog *p; + Auto *a; + Sym *s; + int h; + + s = lookup("etext", 0); + if(s->type == STEXT) + putsymb(s->name, 'T', s->value+INITTEXT, s->version); + + for(h=0; hlink) + switch(s->type) { + case SCONST: + putsymb(s->name, 'D', s->value, s->version); + continue; + + case SSTRING: + putsymb(s->name, 'T', s->value, s->version); + continue; + + case SDATA: + putsymb(s->name, 'D', s->value+INITDAT, s->version); + continue; + + case SBSS: + putsymb(s->name, 'B', s->value+INITDAT, s->version); + continue; + + case SFILE: + putsymb(s->name, 'f', s->value, s->version); + continue; + } + + for(p=textp; p!=P; p=p->cond) { + s = p->from.sym; + if(s->type != STEXT && s->type != SLEAF) + continue; + + /* filenames first */ + for(a=p->to.autom; a; a=a->link) + if(a->type == D_FILE) + putsymb(a->asym->name, 'z', a->aoffset, 0); + else + if(a->type == D_FILE1) + putsymb(a->asym->name, 'Z', a->aoffset, 0); + + if(s->type == STEXT) + putsymb(s->name, 'T', s->value+INITTEXT, s->version); + else + putsymb(s->name, 'L', s->value+INITTEXT, s->version); + + /* frame, auto and param after */ + putsymb(".frame", 'm', p->to.offset+ptrsize, 0); + for(a=p->to.autom; a; a=a->link) + if(a->type == D_AUTO) + putsymb(a->asym->name, 'a', -a->aoffset, 0); + else + if(a->type == D_PARAM) + putsymb(a->asym->name, 'p', a->aoffset, 0); + } + if(debug['v'] || debug['n']) + Bprint(&bso, "symsize = %lud\n", symsize); + Bflush(&bso); +} + +void +putsymb(char *s, int t, vlong v, int ver) +{ + int i, f, l; + + if(t == 'f') + s++; + if(thechar == 'j'){ + l = 8; + llput(v); + }else{ + l = 4; + lput(v); + } + if(ver) + t += 'a' - 'A'; + cput(t+0x80); /* 0x80 is variable length */ + + if(t == 'Z' || t == 'z') { + cput(s[0]); + for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) { + cput(s[i]); + cput(s[i+1]); + } + cput(0); + cput(0); + i++; + } + else { + for(i=0; s[i]; i++) + cput(s[i]); + cput(0); + } + symsize += l + 1 + i + 1; + + if(debug['n']) { + if(t == 'z' || t == 'Z') { + Bprint(&bso, "%c %.8llux ", t, v); + for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) { + f = ((s[i]&0xff) << 8) | (s[i+1]&0xff); + Bprint(&bso, "/%x", f); + } + Bprint(&bso, "\n"); + return; + } + if(ver) + Bprint(&bso, "%c %.8llux %s<%d>\n", t, v, s, ver); + else + Bprint(&bso, "%c %.8llux %s\n", t, v, s); + } +} + +#define MINLC 4 +void +asmlc(void) +{ + long oldpc, oldlc; + Prog *p; + long v, s; + + oldpc = 0; + oldlc = 0; + for(p = firstp; p != P; p = p->link) { + if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) { + if(p->as == ATEXT) + curtext = p; + if(debug['L']) + Bprint(&bso, "%6lux %P\n", + p->pc, p); + continue; + } + if(debug['L']) + Bprint(&bso, "\t\t%6ld", lcsize); + v = (p->pc - oldpc) / MINLC; + while(v) { + s = 127; + if(v < 127) + s = v; + cput(s+128); /* 129-255 +pc */ + if(debug['L']) + Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128); + v -= s; + lcsize++; + } + s = p->line - oldlc; + oldlc = p->line; + oldpc = p->pc + MINLC; + if(s > 64 || s < -64) { + cput(0); /* 0 vv +lc */ + cput(s>>24); + cput(s>>16); + cput(s>>8); + cput(s); + if(debug['L']) { + if(s > 0) + Bprint(&bso, " lc+%ld(%d,%ld)\n", + s, 0, s); + else + Bprint(&bso, " lc%ld(%d,%ld)\n", + s, 0, s); + Bprint(&bso, "%6lux %P\n", + p->pc, p); + } + lcsize += 5; + continue; + } + if(s > 0) { + cput(0+s); /* 1-64 +lc */ + if(debug['L']) { + Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s); + Bprint(&bso, "%6lux %P\n", + p->pc, p); + } + } else { + cput(64-s); /* 65-128 -lc */ + if(debug['L']) { + Bprint(&bso, " lc%ld(%ld)\n", s, 64-s); + Bprint(&bso, "%6lux %P\n", + p->pc, p); + } + } + lcsize++; + } + while(lcsize & 1) { + s = 129; + cput(s); + lcsize++; + } + if(debug['v'] || debug['L']) + Bprint(&bso, "lcsize = %ld\n", lcsize); + Bflush(&bso); +} + +void +datblk(long s, long n, int str) +{ + Prog *p; + char *cast; + vlong d; + long l, fl, j; + int i, c; + + memset(buf.dbuf, 0, n+100); + for(p = datap; p != P; p = p->link) { + curp = p; + if(str != (p->from.sym->type == SSTRING)) + continue; + l = p->from.sym->value + p->from.offset - s; + c = p->reg; + i = 0; + if(l < 0) { + if(l+c <= 0) + continue; + while(l < 0) { + l++; + i++; + } + } + if(l >= n) + continue; + if(p->as != AINIT && p->as != ADYNT) { + for(j=l+(c-i)-1; j>=l; j--) + if(buf.dbuf[j]) { + print("%P\n", p); + diag("multiple initialization"); + break; + } + } + switch(p->to.type) { + default: + diag("unknown mode in initialization\n%P", p); + break; + + case D_FCONST: + switch(c) { + default: + case 4: + fl = ieeedtof(p->to.ieee); + cast = (char*)&fl; + for(; ito.ieee; + for(; ito.sval[i]; + l++; + } + break; + + case D_VCONST: + d = *p->to.vval; + goto dconst; + + case D_CONST: + d = p->to.offset; + dconst: + if(p->to.sym) { + switch(p->to.sym->type) { + case STEXT: + case SLEAF: + case SSTRING: + d += (p->to.sym->value + INITTEXT); + break; + case SDATA: + case SBSS: + d += (p->to.sym->value + INITDAT); + break; + } + } + cast = (char*)&d; + switch(c) { + default: + diag("bad nuxi %d %d\n%P", c, i, curp); + break; + case 1: + for(; iop<<2) +#define OPF (OPX | o->func3<<12) +#define OP_R(rs1,rs2,rd)\ + (OPF | rd<<7 | R(rs1)<<15 | R(rs2)<<20 | o->param<<25) +#define OP_RF(rs1,rs2,rd,rm)\ + (OPX | rm<<12 | rd<<7 | R(rs1)<<15 | R(rs2)<<20 | o->param<<25) +#define OP_RO(rs1,rs2,rd)\ + (0x3 | OOP<<2 | o->func3<<12 | rd<<7 | R(rs1)<<15 | R(rs2)<<20) +#define OP_ADD(rs1,rs2,rd)\ + (0x3 | OOP<<2 | rd<<7 | R(rs1)<<15 | R(rs2)<<20) +#define OP_I(rs1,rd,imm)\ + (OPF | rd<<7 | R(rs1)<<15 | (imm)<<20) +#define OP_FI(func3,rs1,rd,imm)\ + (OPX | func3<<12 | rd<<7 | R(rs1)<<15 | (imm)<<20) +#define OP_S(rs1,rs2,imm)\ + (OPF | (imm&0x1F)<<7 | R(rs1)<<15 | R(rs2)<<20 | (imm>>5)<<25) +#define OP_B(rs1,rs2,imm)\ + (OPF | R(rs1)<<15 | R(rs2)<<20 | (imm&0x800)>>4 | (imm&0x1E)<<7 | \ + (imm&0x7E0)<<20 | (imm&0x1000)<<19) +#define OP_U(rd,imm)\ + (0x3 | OLUI<<2 | rd<<7 | (imm&0xFFFFF000)) +#define OP_UP(rd,imm)\ + (0x3 | OAUIPC<<2 | rd<<7 | (imm&0xFFFFF000)) +#define OP_J(rd,imm)\ + (OPX | rd<<7 | (imm&0xff000) | (imm&0x800)<<9 | (imm&0x7FE)<<20 | (imm&0x100000)<<11) + +/* + * aflag: 0 - assemble to object file + * 1 - return assembled instruction + * 2 - first pass, return length of assembled instruction + * 3 - later pass, return length of assembled instruction + */ +int +asmout(Prog *p, Optab *o, int aflag) +{ + vlong vv; + long o1, o2, o3, v; + int r; + + o1 = 0; + o2 = 0; + o3 = 0; + r = p->reg; + if(r == NREG) switch(p->as){ + case AMOVF: + case AMOVD: + if(p->from.type == D_FREG && p->to.type == D_FREG) + r = p->from.reg; + break; + case AMOV: + case AJMP: + r = REGZERO; + break; + case AJAL: + r = REGLINK; + break; + default: + r = p->to.reg; + break; + } + if(!debug['c'] && o->ctype){ + o1 = asmcompressed(p, o, r, aflag == 2); + if(o1 != 0){ + switch(aflag){ + case 1: + return o1; + case 2: + case 3: + return 2; + } + if(debug['a']){ + v = p->pc + INITTEXT; + Bprint(&bso, " %.8lux: %.4lux \t%P\n", v, o1, p); + } + wputl(o1); + return 2; + } + } + if(aflag >= 2) + return o->size; + switch(o->type) { + default: + diag("unknown type %d", o->type); + if(!debug['a']) + prasm(p); + break; + + case 0: /* add S,[R,]D */ + o1 = OP_R(r, p->from.reg, p->to.reg); + break; + + case 1: /* slli $I,[R,]D */ + v = p->from.offset & 0x3F; + v |= (o->param<<5); + o1 = OP_I(r, p->to.reg, v); + break; + + case 2: /* addi $I,[R,]D */ + v = p->from.offset; + if(v < -BIG || v >= BIG) + diag("imm out of range\n%P", p); + o1 = OP_I(r, p->to.reg, v); + break; + + case 3: /* beq S,[R,]L */ + if(r == NREG) + r = REGZERO; + if(p->cond == P) + v = 0; + else + v = (p->cond->pc - pc); + if(v < -0x1000 || v >= 0x1000) + diag("branch out of range\n%P", p); + o1 = OP_B(r, p->from.reg, v); + break; + + case 4: /* jal [D,]L */ + if(p->cond == P) + v = 0; + else + v = (p->cond->pc - pc); + if(v < -0x100000 || v >= 0x100000) + diag("jump out of range\n%P", p); + o1 = OP_J(r, v); + break; + + case 5: /* jalr [D,]I(S) */ + v = regoff(&p->to); + if(v < -BIG || v >= BIG) + diag("imm out of range\n%P", p); + o1 = OP_I(classreg(&p->to), r, v); + break; + + case 6: /* sb R,I(S) */ + v = regoff(&p->to); + r = classreg(&p->to); + if(v < -BIG || v >= BIG) + diag("imm out of range\n%P", p); + o1 = OP_S(r, p->from.reg, v); + break; + + case 7: /* lb I(S),D */ + v = regoff(&p->from); + r = classreg(&p->from); + if(v < -BIG || v >= BIG) + diag("imm out of range\n%P", p); + o1 = OP_I(r, p->to.reg, v); + break; + + case 8: /* lui I,D */ + v = p->from.offset; + o1 = OP_U(p->to.reg, v); + break; + + case 9: /* lui I1,D; addi I0,D */ + v = regoff(&p->from); + if(thechar == 'j' && v >= 0x7ffff800){ + /* awkward edge case */ + o1 = OP_U(p->to.reg, -v); + v &= 0xFFF; + o2 = OP_FI(4, p->to.reg, p->to.reg, v); /* xori */ + break; + } + if(v & 0x800) + v += 0x1000; + o1 = OP_U(p->to.reg, v); + v &= 0xFFF; + o2 = OP_I(p->to.reg, p->to.reg, v); + break; + + case 10: /* sign extend */ + if(p->as == AMOVBU) { + o1 = OP_I(p->from.reg, p->to.reg, o->param); + break; + } + v = o->param; + if(thechar == 'j') + v += 32; + o1 = OP_FI(1, p->from.reg, p->to.reg, v & 0x3F); /* slli */ + o2 = OP_I(p->to.reg, p->to.reg, v); /* srli or srai */ + break; + + case 11: /* addi $I,R,D */ + v = regoff(&p->from); + if(v < -BIG || v >= BIG) + diag("imm out of range\n%P", p); + o1 = OP_I(classreg(&p->from), p->to.reg, v); + break; + + case 12: /* mov r,lext => lui/auipc I1,T; sb r,I0(T) */ + v = regoff(&p->to); + if(thechar == 'j'){ + vv = v + INITDAT + BIG - INITTEXT - pc; + v = (long)vv; + if(v != vv || (v&~0x7FF) == 0x7FFFF800) + diag("address out of range\n%P", p); + }else + v += INITDAT + BIG; + if(v & 0x800) + v += 0x1000; + o1 = thechar == 'j' ? OP_UP(REGTMP, v) : OP_U(REGTMP, v); + v &= 0xFFF; + o2 = OP_S(REGTMP, p->from.reg, v); + break; + + case 13: /* mov lext, r => lui/auipc I1,T; lb r,I0(T) */ + v = regoff(&p->from); + if(thechar == 'j'){ + vv = v + INITDAT + BIG - INITTEXT - pc; + v = (long)vv; + if(v != vv || (v&~0x7FF) == 0x7FFFF800) + diag("address out of range\n%P", p); + }else + v += INITDAT + BIG; + if(v & 0x800) + v += 0x1000; + o1 = thechar == 'j' ? OP_UP(REGTMP, v) : OP_U(REGTMP, v); + v &= 0xFFF; + o2 = OP_I(REGTMP, p->to.reg, v); + break; + + case 14: /* op $lcon,[r,]d => lui L1,T; addi $L0,T,T; op T,r,d */ + v = regoff(&p->from); + if(p->as == AMOVW || p->as == AMOV) + r = classreg(&p->from); + if(thechar == 'j' && v >= 0x7ffff800){ + /* awkward edge case */ + o1 = OP_U(p->to.reg, -v); + v &= 0xFFF; + o2 = OP_FI(4, p->to.reg, p->to.reg, v); /* xori */ + }else{ + if(v & 0x800) + v += 0x1000; + o1 = OP_U(REGTMP, v); + v &= 0xFFF; + o2 = OP_FI(0, REGTMP, REGTMP, v); /* addi */ + } + o3 = OP_RO(r, REGTMP, p->to.reg); + break; + + case 15: /* mov r,L(s) => lui L1,T; add s,T,T; sb r,L0(T) */ + v = regoff(&p->to); + r = classreg(&p->to); + if(v & 0x800) + v += 0x1000; + o1 = OP_U(REGTMP, v); + v &= 0xFFF; + o2 = OP_ADD(r, REGTMP, REGTMP); + o3 = OP_S(REGTMP, p->from.reg, v); + break; + + case 16: /* mov L(s),r => lui L1,T; add s,T,T; lb r,L0(T) */ + v = regoff(&p->from); + r = classreg(&p->from); + if(v & 0x800) + v += 0x1000; + o1 = OP_U(REGTMP, v); + v &= 0xFFF; + o2 = OP_ADD(r, REGTMP, REGTMP); + o3 = OP_I(REGTMP, p->to.reg, v); + break; + + case 17: /* fcvt S,D */ + v = 7; /* dynamic rounding mode */ + if(o->a3 == C_REG) /* convert to int? */ + v = 1; /* round towards zero */ + o1 = OP_RF(p->from.reg, o->func3, p->to.reg, v); + break; + + case 18: /* lui L1, T; jal [r,]L0(T) */ + if(p->cond == P) + v = 0; + else + v = p->cond->pc; + if(thechar == 'j'){ + vv = v + INITTEXT; + v = (long)vv; + if(v != vv || (v&~0x7FF) == 0x7FFFF800) + diag("branch out of range\n%P", p); + }else + v += INITTEXT; + if(v & 0x800) + v += 0x1000; + o1 = thechar == 'j' ? OP_UP(REGTMP, v) : OP_U(REGTMP, v); + v &= 0xFFF; + o2 = OP_I(REGTMP, r, v); + break; + + case 19: /* addiw $0, rs, rd */ + v = 0; + o1 = OP_I(p->from.reg, p->to.reg, v); + break; + + case 20: /* lui/auipc I1,D; addi I0; D */ + if(thechar == 'j'){ + vv = regoff(&p->from) + instoffx - (pc + INITTEXT); + v = (long)vv; + if(v != vv || (v&~0x7FF) == 0x7FFFF800) + diag("address %llux out of range\n%P", regoff(&p->from) + instoffx, p); + }else{ + v = regoff(&p->from) + instoffx; + } + if(v & 0x800) + v += 0x1000; + o1 = thechar == 'j' ? OP_UP(p->to.reg, v) : OP_U(p->to.reg, v); + v &= 0xFFF; + o2 = OP_I(p->to.reg, p->to.reg, v); + break; + + case 21: /* lui I,D; s[lr]ai N,D */ + vv = *p->from.vval; + v = vconshift(vv); + if(v < 0) + diag("64 bit constant error:\n%P", p); + if(v < 12) + vv <<= 12 - v; + else + vv >>= v - 12; + o1 = OP_U(p->to.reg, (long)vv); + if (v > 12) + o2 = OP_FI(1, p->to.reg, p->to.reg, v - 12); /* slli */ + else + o2 = OP_I(p->to.reg, p->to.reg, 12 - v); /* srai */ + break; + + case 22: /* CSRRx C, rs, rd */ + v = p->from.offset & 0xFFF; + o1 = OP_I(p->reg, p->to.reg, v); + break; + + case 24: /* SYS */ + v = p->to.offset & 0xFFF; + o1 = OP_I(0, 0, v); + break; + + case 25: /* word $x */ + o1 = regoff(&p->to); + break; + + case 26: /* pseudo ops */ + break; + } + if(aflag) + return o1; + v = p->pc + INITTEXT; + switch(o->size) { + default: + if(debug['a']) + Bprint(&bso, " %.8lux:\t\t%P\n", v, p); + break; + case 4: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p); + lputl(o1); + break; + case 8: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p); + lputl(o1); + lputl(o2); + break; + case 12: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p); + lputl(o1); + lputl(o2); + lputl(o3); + break; + } + return o->size; +} + diff --git a/utils/il/compress.c b/utils/il/compress.c new file mode 100644 index 00000000..e0063615 --- /dev/null +++ b/utils/il/compress.c @@ -0,0 +1,270 @@ +#include "l.h" + +#define COMPREG(r) ((r & ~0x7) == 0x8) +#define COP_CR(op,rs,rd)\ + (op | (rs)<<2 | (rd)<<7) +#define COP_CI(op,rd,i)\ + (op | (rd)<<7 | ((i)&0x20)<<7 | ((i)&0x1F)<<2) +#define COP_CIW(op,rd,i)\ + (op | (rd)<<2 | (i)<<5) +#define COP_CJ(op,i)\ + (op | (i)<<2) +#define COP_CB(op,rs,i)\ + (op | (rs)<<7 | ((i)&0x1f)<<2 | ((i)&0xE0)<<5) +#define COP_CL(op,rs,rd,i)\ + (op | (rs)<<7 | (rd)<<2 | ((i)&0x7)<<4 | ((i)&0x38)<<7) +#define COP_CSS(op,rs,i)\ + (op | (rs)<<2 | ((i)&0x3F)<<7) +#define COP_CS(op,rs2,rs1,i)\ + (op | (rs2)<<2 | (rs1)<<7 | ((i)&0x7)<<4 | ((i)&0x38)<<7) + +static int +immbits(int v, char *permute) +{ + int r, i, c; + + r = 0; + for(i = 0; (c = *permute++) != 0; i++) + r |= ((v>>c) & 0x01) << i; + return r; +} + +long +asmcjmp(int a, Prog *p, int first) +{ + long v; + + if(p->cond == P) + v = 0; + else + v = (p->cond->pc - p->pc); + if(first || ((v&0x01) == 0 && v >= -0x800 && v < 0x800)) + return COP_CJ(a, immbits(v, "\5\1\2\3\7\6\12\10\11\4\13")); + return 0; +} + +int +asmcbz(int a, Prog *p, int first) +{ + long v; + int r; + + r = p->reg; + if(r == REGZERO || r == NREG) + r = p->from.reg; + else if(p->from.reg != REGZERO) + return 0; + if(!COMPREG(r)) + return 0; + if(p->cond == P) + v = 0; + else + v = (p->cond->pc - p->pc); + if(first || ((v&0x01) == 0 && v >= -0x100 && v < 0x100)) + return COP_CB(a, r&0x7, immbits(v, "\5\1\2\6\7\3\4\10")); + return 0; +} + +int +asmcload(Prog *p, int a, uint len, uint maxoff) +{ + int v; + int r; + + v = regoff(&p->from); + if((v & (len-1)) != 0 || v < 0) + return 0; + r = classreg(&p->from); + if(COMPREG(r) && COMPREG(p->to.reg)){ + if(v < maxoff){ + v |= (v>>5) & ~0x1; + return COP_CL(a, r&0x7, p->to.reg&0x7, v); + } + }else if(r == REGSP){ + if(v < 2*maxoff){ + v |= (v>>6); + return COP_CI(a | 0x2, p->to.reg, v); + } + } + return 0; +} + +int +asmcstore(Prog *p, int a, uint len, uint maxoff) +{ + int v; + int r; + + v = regoff(&p->to); + if((v & (len-1)) != 0 || v < 0) + return 0; + r = classreg(&p->to); + if(COMPREG(r) && COMPREG(p->from.reg)){ + if(v < maxoff){ + v |= (v>>5) & ~0x1; + return COP_CS(a, p->from.reg&0x7, r&0x7, v); + } + }else if(r == REGSP){ + if(v < 2*maxoff){ + v |= (v>>6); + return COP_CSS(a | 0x2, (p->from.reg&0x1F), v); + } + } + return 0; +} + +int +asmcompressed(Prog *p, Optab *o, int r, int first) +{ + long v; + int a; + + switch(o->ctype){ + case 1: /* C.ADD */ + if(p->from.reg != REGZERO && p->to.reg != REGZERO && r == p->to.reg) + return COP_CR(0x9002, p->from.reg, r); + break; + case 2: /* C.MV */ + if(p->from.type != D_REG) + diag("compress MOVW R,R doesn't apply\n%P", p); + if(p->to.reg != REGZERO){ + if(p->from.type == D_REG && p->from.reg != REGZERO) + return COP_CR(0x8002, p->from.reg, p->to.reg); + else + return COP_CI(0x4001, p->to.reg, 0); + } + break; + case 3: /* C.JALR */ + if(r == REGLINK && p->to.reg != REGZERO && p->to.offset == 0) + return COP_CR(0x9002, 0, p->to.reg); + break; + case 4: /* C.JR */ + if(p->to.reg != REGZERO &&p->to.offset == 0) + return COP_CR(0x8002, 0, p->to.reg); + break; + case 5: /* C.AND C.OR C.SUB C.XOR */ + if(r == p->to.reg && COMPREG(p->from.reg) && COMPREG(p->to.reg)){ + v = 0x8C01; + switch(o->as){ + case AXOR: + v |= 1<<5; + break; + case AOR: + v |= 2<<5; + break; + case AAND: + v |= 3<<5; + break; + } + return COP_CR(v, p->from.reg&0x7, p->to.reg&0x7); + } + break; + case 6: /* C.LI */ + v = p->from.offset; + if(p->to.reg != REGZERO && v >= -0x20 && v < 0x20){ + return COP_CI(0x4001, p->to.reg, v); + } + break; + case 7: /* C.LUI */ + v = p->from.offset; + if((v&0xFFF) != 0) + return 0; + v >>= 12; + if(p->to.reg != REGZERO && p->to.reg != REGSP && v >= -0x20 && v < 0x20) + return COP_CI(0x6001, p->to.reg, v); + break; + case 8: /* C.SLLI */ + v = p->from.offset; + if((v & 0x20) != 0 && thechar == 'i') + break; + if(r == p->to.reg && r != REGZERO && v != 0 && (v & ~0x3F) == 0) + return COP_CI(0x0002, p->to.reg, v); + break; + case 9: /* C.SRAI C.SRLI */ + v = p->from.offset; + if((v & 0x20) != 0 && thechar == 'i') + break; + a = (o->as == ASRA) << 10; + if(r == p->to.reg && COMPREG(r) && v != 0 && (v & ~0x3F) == 0) + return COP_CI(0x8001 | a, r&0x7, v); + break; + case 10: /* C.ADDI C.ADDI16SP C.ADDI4SPN C.NOP */ + v = p->from.offset; + if(r == p->to.reg && r != REGZERO && v != 0 && v >= -0x20 && v < 0x20) + return COP_CI(0x0001, p->to.reg, v); + if(r == p->to.reg && r == REGSP && v != 0 && (v&0xF) == 0 && v >= -0x200 && v < 0x200) + return COP_CI(0x6001, REGSP, immbits(v, "\5\7\10\6\4\11")); + if(r == REGSP && COMPREG(p->to.reg) && (v&0x3) == 0 && v > 0 && v < 0x400) + return COP_CIW(0x0000, p->to.reg&0x7, immbits(v, "\3\2\6\7\10\11\4\5")); + if(r == p->to.reg && r == REGZERO && v == 0) + return COP_CI(0x0001, 0, 0); + break; + case 11: /* C.JAL (rv32) */ + if(thechar != 'i') + break; + if(r == REGLINK) + return asmcjmp(0x2001, p, first); + break; + case 12: /* C.J */ + return asmcjmp(0xA001, p, first); + break; + case 13: /* C.ANDI */ + v = p->from.offset; + if(r == p->to.reg && COMPREG(r) && v >= -0x20 && v < 0x20) + return COP_CI(0x8801, r&0x7, v); + break; + case 14: /* C.BEQZ */ + return asmcbz(0xC001, p, first); + case 15: /* C.BNEZ */ + return asmcbz(0xE001, p, first); + case 16: /* C.LW C.LWSP */ + return asmcload(p, 0x4000, 4, 0x80); + case 17: /* C.FLW, C.FLWSP (rv32) */ + if(thechar != 'i') + break; + return asmcload(p, 0x6000, 4, 0x80); + case 18: /* C.FLD, C.FLDSP */ + return asmcload(p, 0x2000, 8, 0x100); + case 19: /* C.SW C.SWSP */ + return asmcstore(p, 0xC000, 4, 0x80); + case 20: /* C.FSW, C.FSWSP (rv32) */ + if(thechar != 'i') + break; + return asmcstore(p, 0xE000, 4, 0x80); + case 21: /* C.FSD, C.FSDSP */ + return asmcstore(p, 0xA000, 8, 0x100); + case 22: /* C.ADDW C.SUBW (rv64) */ + if(thechar != 'j') + break; + if(r == p->to.reg && COMPREG(p->from.reg) && COMPREG(p->to.reg)){ + v = 0x9C01; + switch(o->as){ + case AADDW: + v |= 1<<5; + break; + } + return COP_CR(v, p->from.reg&0x7, p->to.reg&0x7); + } + break; + case 23: /* C.ADDIW (rv64) */ + if(thechar != 'j') + break; + v = p->from.offset; + if(p->as == AMOVW){ + v = 0; + r = p->from.reg; + } + if(r == p->to.reg && r != REGZERO && v >= -0x20 && v < 0x20) + return COP_CI(0x2001, p->to.reg, v); + break; + case 24: /* C.LD (rv64) */ + if(thechar != 'j') + break; + return asmcload(p, 0x6000, 8, 0x100); + case 25: /* C.SD (rv64) */ + if(thechar != 'j') + break; + return asmcstore(p, 0xE000, 8, 0x100); + } + return 0; +} diff --git a/utils/il/l.h b/utils/il/l.h new file mode 100644 index 00000000..3cb106af --- /dev/null +++ b/utils/il/l.h @@ -0,0 +1,359 @@ +#include +#include +#include "../ic/i.out.h" +#include "../ld/elf.h" + +#ifndef EXTERN +#define EXTERN extern +#endif + +typedef vlong xlong; + +typedef struct Adr Adr; +typedef struct Sym Sym; +typedef struct Autom Auto; +typedef struct Prog Prog; +typedef struct Optab Optab; +typedef struct Oprang Oprang; +typedef uchar Opcross[32][32]; +typedef struct Count Count; + +#define P ((Prog*)0) +#define S ((Sym*)0) +#define TNAME (curtext&&curtext->from.sym?curtext->from.sym->name:noname) + +struct Adr +{ + union + { + long u0offset; + char* u0sval; + Ieee* u0ieee; + vlong* u0vval; + } u0; + union + { + Auto* u1autom; + Sym* u1sym; + } u1; + char type; + char reg; + char name; + char class; +}; + +#define offset u0.u0offset +#define sval u0.u0sval +#define ieee u0.u0ieee +#define vval u0.u0vval + +#define autom u1.u1autom +#define sym u1.u1sym + +struct Prog +{ + Adr from; + Adr to; + union + { + long u0regused; + Prog* u0forwd; + } u0; + Prog* cond; + Prog* link; + long pc; + long line; + uchar mark; + uchar optab; + char as; + char reg; +}; +#define regused u0.u0regused +#define forwd u0.u0forwd + +struct Sym +{ + char *name; + short type; + short version; + short become; + short frame; + ushort file; + long value; + long sig; + Sym* link; +}; +struct Autom +{ + Sym* asym; + Auto* link; + long aoffset; + short type; +}; +struct Optab +{ + char as; + char a1; + char a3; + char type; + char ctype; + char size; + char op; + char func3; + short param; +}; +struct Oprang +{ + Optab* start; + Optab* stop; +}; +struct Count +{ + long count; + long outof; +}; + +enum +{ + STEXT = 1, + SDATA, + SBSS, + SDATA1, + SXREF, + SLEAF, + SFILE, + SCONST, + SSTRING, + + C_NONE = 0, + C_REG, + C_CTLREG, + C_FREG, + C_ZREG, + C_ZCON, + C_SCON, + C_UCON, + C_LCON, + C_VCON, + C_FCON, + C_SACON, + C_SECON, + C_LACON, + C_LECON, + C_SRCON, + C_LRCON, + C_SBRA, + C_LBRA, + C_SAUTO, + C_ZOREG, + C_SOREG, + C_LOREG, + C_LAUTO, + C_SEXT, + C_LEXT, + C_GOK, + + NSCHED = 20, + +/* mark flags */ + FOLL = 1<<0, + LABEL = 1<<1, + LEAF = 1<<2, + SYNC = 1<<3, + BRANCH = 1<<4, + COMPR = 1<<5, + SPASS = 1<<6, + + BIG = 2048, + STRINGSZ = 200, + NHASH = 10007, + NHUNK = 100000, + MINSIZ = 64, + NENT = 100, + MAXIO = 8192, + MAXHIST = 20, /* limit of path elements for history symbols */ +}; + +/* Major opcodes */ +enum { + OLOAD, OLOAD_FP, Ocustom_0, OMISC_MEM, OOP_IMM, OAUIPC, OOP_IMM_32, O48b, + OSTORE, OSTORE_FP, Ocustom_1, OAMO, OOP, OLUI, OOP_32, O64b, + OMADD, OMSUB, ONMSUB, ONMADD, OOP_FP, Ores_0, Ocustom_2, O48b_2, + OBRANCH, OJALR, Ores_1, OJAL, OSYSTEM, Ores_2, Ocustom_3, O80b +}; + +EXTERN union +{ + struct + { + uchar obuf[MAXIO]; /* output buffer */ + uchar ibuf[MAXIO]; /* input buffer */ + } u; + char dbuf[1]; +} buf; + +#define cbuf u.obuf +#define xbuf u.ibuf + +EXTERN long HEADR; /* length of header */ +EXTERN int HEADTYPE; /* type of header */ +EXTERN xlong INITDAT; /* data location */ +EXTERN xlong INITRND; /* data round above text location */ +EXTERN xlong INITTEXT; /* text location */ +EXTERN xlong INITTEXTP; /* text location (physical) */ +EXTERN char* INITENTRY; /* entry point */ +EXTERN long autosize; +EXTERN Biobuf bso; +EXTERN long bsssize; +EXTERN int cbc; +EXTERN uchar* cbp; +EXTERN int cout; +EXTERN Auto* curauto; +EXTERN Auto* curhist; +EXTERN Prog* curp; +EXTERN Prog* curtext; +EXTERN Prog* datap; +EXTERN long datsize; +EXTERN char debug[128]; +EXTERN Prog* etextp; +EXTERN Prog* firstp; +EXTERN char fnuxi4[4]; /* for 3l [sic] */ +EXTERN char fnuxi8[8]; +EXTERN char* noname; +EXTERN Sym* hash[NHASH]; +EXTERN Sym* histfrog[MAXHIST]; +EXTERN int histfrogp; +EXTERN int histgen; +EXTERN char* library[50]; +EXTERN char* libraryobj[50]; +EXTERN int libraryp; +EXTERN int xrefresolv; +EXTERN char* hunk; +EXTERN char inuxi1[1]; +EXTERN char inuxi2[2]; +EXTERN char inuxi4[4]; +EXTERN char inuxi8[8]; +EXTERN Prog* lastp; +EXTERN long lcsize; +EXTERN char literal[32]; +EXTERN int nerrors; +EXTERN long nhunk; +EXTERN Prog nopalign; +EXTERN long instoffset; +EXTERN vlong instoffx; +EXTERN Opcross opcross[10]; +EXTERN Oprang oprange[ALAST]; +EXTERN char* outfile; +EXTERN long pc; +EXTERN int ptrsize; +EXTERN uchar repop[ALAST]; +EXTERN long symsize; +EXTERN Prog* textp; +EXTERN long textsize; +EXTERN long thunk; +EXTERN int version; +EXTERN char xcmp[32][32]; +EXTERN Prog zprg; +EXTERN int dtype; +EXTERN int little; + +EXTERN struct +{ + Count branch; + Count fcmp; + Count load; + Count mfrom; + Count page; + Count jump; +} nop; + +extern char* anames[]; +extern Optab optab[]; +extern char thechar; + +#pragma varargck type "A" int +#pragma varargck type "D" Adr* +#pragma varargck type "N" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "S" char* + +#pragma varargck argpos diag 1 + +int Aconv(Fmt*); +int Dconv(Fmt*); +int Nconv(Fmt*); +int Pconv(Fmt*); +int Sconv(Fmt*); +int aclass(Adr*); +void addhist(long, int); +void append(Prog*, Prog*); +void asmb(void); +int asmcompressed(Prog*, Optab*, int, int); +void asmlc(void); +int asmout(Prog*, Optab*, int); +void asmsym(void); +vlong atolwhex(char*); +Prog* brloop(Prog*); +void buildop(void); +void buildrep(int, int); +void cflush(void); +int cmp(int, int); +int compound(Prog*); +double cputime(void); +void datblk(long, long, int); +void diag(char*, ...); +void dodata(void); +void doprof1(void); +void doprof2(void); +vlong entryvalue(void); +void errorexit(void); +void exchange(Prog*); +int find1(long, int); +void follow(void); +void gethunk(void); +void histtoauto(void); +double ieeedtod(Ieee*); +long ieeedtof(Ieee*); +int isnop(Prog*); +void ldobj(int, long, char*); +void loadlib(void); +void listinit(void); +Sym* lookup(char*, int); +void cput(int); +void llput(vlong); +void llputl(vlong); +void lput(long); +void lputl(long); +void bput(long); +void mkfwd(void); +void* mysbrk(ulong); +void names(void); +void nocache(Prog*); +void noops(void); +void nuxiinit(void); +void objfile(char*); +int ocmp(void*, void*); +long opirr(int); +Optab* oplook(Prog*); +long oprrr(int); +void patch(void); +void prasm(Prog*); +void prepend(Prog*, Prog*); +Prog* prg(void); +int pseudo(Prog*); +void putsymb(char*, int, vlong, int); +long regoff(Adr*); +int classreg(Adr*); +int relinv(int); +int relrev(int); +vlong rnd(vlong, vlong); +void span(void); +void strnput(char*, int); +void undef(void); +int vconshift(vlong); +void wput(long); +void wputl(long); +void xdefine(char*, int, long); +void xfol(Prog*); +void xfol(Prog*); +void nopstat(char*, Count*); diff --git a/utils/il/list.c b/utils/il/list.c new file mode 100644 index 00000000..93989a97 --- /dev/null +++ b/utils/il/list.c @@ -0,0 +1,252 @@ +#include "l.h" + +void +listinit(void) +{ + + fmtinstall('A', Aconv); + fmtinstall('D', Dconv); + fmtinstall('P', Pconv); + fmtinstall('S', Sconv); + fmtinstall('N', Nconv); +} + +void +prasm(Prog *p) +{ + print("%P\n", p); +} + +int +Pconv(Fmt *fp) +{ + char str[STRINGSZ], *s; + Prog *p; + int a; + + p = va_arg(fp->args, Prog*); + curp = p; + a = p->as; + if(a == ADATA || a == ADYNT || a == AINIT) + sprint(str, "(%ld) %A %D/%d,%D", + p->line, a, &p->from, p->reg, &p->to); + else{ + s = str; + s += sprint(s, "(%ld)", p->line); + if(p->reg == NREG) + sprint(s, " %A %D,%D", + a, &p->from, &p->to); + else + if(p->from.type != D_FREG) + sprint(s, " %A %D,R%d,%D", + a, &p->from, p->reg, &p->to); + else + sprint(s, " %A %D,F%d,%D", + a, &p->from, p->reg, &p->to); + } + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + char *s; + int a; + + a = va_arg(fp->args, int); + s = "???"; + if(a >= AXXX && a < ALAST) + s = anames[a]; + return fmtstrcpy(fp, s); +} + +int +Dconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + long v; + + a = va_arg(fp->args, Adr*); + switch(a->type) { + + default: + sprint(str, "GOK-type(%d)", a->type); + break; + + case D_NONE: + str[0] = 0; + if(a->name != D_NONE || a->reg != NREG || a->sym != S) + sprint(str, "%N(R%d)(NONE)", a, a->reg); + break; + + case D_CONST: + if(a->reg == NREG) + sprint(str, "$%N", a); + else + sprint(str, "$%N(R%d)", a, a->reg); + break; + + case D_VCONST: + sprint(str, "$%lld", *a->vval); + break; + + case D_OREG: + if(a->reg != NREG) + sprint(str, "%N(R%d)", a, a->reg); + else + sprint(str, "%N", a); + break; + + case D_REG: + sprint(str, "R%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_FREG: + sprint(str, "F%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_CTLREG: + sprint(str, "CSR(0x%lx)", a->offset); + break; + + case D_BRANCH: /* botch */ + if(curp->cond != P) { + v = curp->cond->pc + INITTEXT; + if(a->sym != S) + sprint(str, "%s+%.5lux(BRANCH)", a->sym->name, v); + else + sprint(str, "%.5lux(BRANCH)", v); + } else + if(a->sym != S) + sprint(str, "%s+%ld(APC)", a->sym->name, a->offset); + else + sprint(str, "%ld(APC)", a->offset); + break; + + case D_FCONST: + sprint(str, "$%e", ieeedtod(a->ieee)); + break; + + case D_SCONST: + sprint(str, "$\"%S\"", a->sval); + break; + } + return fmtstrcpy(fp, str); +} + +int +Nconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + Sym *s; + + a = va_arg(fp->args, Adr*); + s = a->sym; + switch(a->name) { + default: + sprint(str, "GOK-name(%d)", a->name); + break; + + case D_NONE: + sprint(str, "%ld", a->offset); + break; + + case D_EXTERN: + if(s == S) + sprint(str, "%ld(SB)", a->offset); + else + sprint(str, "%s+%ld(SB)", s->name, a->offset); + break; + + case D_STATIC: + if(s == S) + sprint(str, "<>+%ld(SB)", a->offset); + else + sprint(str, "%s<>+%ld(SB)", s->name, a->offset); + break; + + case D_AUTO: + if(s == S) + sprint(str, "%ld(SP)", a->offset); + else + sprint(str, "%s-%ld(SP)", s->name, -a->offset); + break; + + case D_PARAM: + if(s == S) + sprint(str, "%ld(FP)", a->offset); + else + sprint(str, "%s+%ld(FP)", s->name, a->offset); + break; + } + + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[STRINGSZ], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9' || + c == ' ' || c == '%') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + case 0: + *p++ = 'z'; + continue; + case '\\': + case '"': + *p++ = c; + continue; + case '\n': + *p++ = 'n'; + continue; + case '\t': + *p++ = 't'; + continue; + } + *p++ = (c>>6) + '0'; + *p++ = ((c>>3) & 7) + '0'; + *p++ = (c & 7) + '0'; + } + *p = 0; + return fmtstrcpy(fp, str); +} + +void +diag(char *fmt, ...) +{ + char buf[STRINGSZ], *tn; + va_list arg; + + tn = "??none??"; + if(curtext != P && curtext->from.sym != S) + tn = curtext->from.sym->name; + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + print("%s: %s\n", tn, buf); + + nerrors++; + if(nerrors > 10) { + print("too many errors\n"); + errorexit(); + } +} diff --git a/utils/il/mkfile b/utils/il/mkfile new file mode 100644 index 00000000..4a655086 --- /dev/null +++ b/utils/il/mkfile @@ -0,0 +1,39 @@ +<../../mkconfig + +TARG=il # also makes jl (for riscv64) + +OFILES=\ + asm.$O\ + compress.$O\ + list.$O\ + noop.$O\ + obj.$O\ + optab.$O\ + pass.$O\ + span.$O\ + enam.$O\ + $TARGMODEL.$O\ + elf.$O\ + +HFILES=\ + l.h\ + ../ic/i.out.h\ + ../ld/elf.h\ + +LIBS=bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I../include -I. + +enam.$O: ../ic/enam.c + $CC $CFLAGS ../ic/enam.c +elf.$O: ../ld/elf.c + $CC $CFLAGS ../ld/elf.c + +$TARGMODEL.$O: ../ld/$TARGMODEL.c + $CC $CFLAGS ../ld/$TARGMODEL.c + +install:V: $BIN/jl diff --git a/utils/il/noop.c b/utils/il/noop.c new file mode 100644 index 00000000..05426130 --- /dev/null +++ b/utils/il/noop.c @@ -0,0 +1,341 @@ +#include "l.h" + +void +noops(void) +{ + Prog *p, *q, *q1; + int o, curframe, curbecome, maxbecome; + + /* + * find leaf subroutines + * become sizes + * frame sizes + * strip NOPs + * expand RET + * expand BECOME pseudo + */ + + if(debug['v']) + Bprint(&bso, "%5.2f noops\n", cputime()); + Bflush(&bso); + + curframe = 0; + curbecome = 0; + maxbecome = 0; + curtext = 0; + + q = P; + for(p = firstp; p != P; p = p->link) { + + /* find out how much arg space is used in this TEXT */ + if(p->to.type == D_OREG && p->to.reg == REGSP) + if(p->to.offset > curframe) + curframe = p->to.offset; + + switch(p->as) { + case ATEXT: + if(curtext && curtext->from.sym) { + curtext->from.sym->frame = curframe; + curtext->from.sym->become = curbecome; + if(curbecome > maxbecome) + maxbecome = curbecome; + } + curframe = 0; + curbecome = 0; + + p->mark |= LABEL|LEAF|SYNC; + if(p->link) + p->link->mark |= LABEL; + curtext = p; + break; + + /* too hard, just leave alone */ + case AMOVW: + case AMOV: + if(p->to.type == D_CTLREG) { + p->mark |= LABEL|SYNC; + break; + } + if(p->from.type == D_CTLREG) { + p->mark |= LABEL|SYNC; + break; + } + break; + + /* too hard, just leave alone */ + case ASYS: + case AWORD: + p->mark |= LABEL|SYNC; + break; + + case ARET: + /* special form of RET is BECOME */ + if(p->from.type == D_CONST) + if(p->from.offset > curbecome) + curbecome = p->from.offset; + + if(p->link != P) + p->link->mark |= LABEL; + break; + + case ANOP: + q1 = p->link; + q->link = q1; /* q is non-nop */ + q1->mark |= p->mark; + continue; + + case AJAL: + if(curtext != P) + curtext->mark &= ~LEAF; + + case AJMP: + case ABEQ: + case ABGE: + case ABGEU: + case ABLT: + case ABLTU: + case ABNE: + p->mark |= BRANCH; + + q1 = p->cond; + if(q1 != P) { + while(q1->as == ANOP) { + q1 = q1->link; + p->cond = q1; + } + if(!(q1->mark & LEAF)) + q1->mark |= LABEL; + } else + p->mark |= LABEL; + q1 = p->link; + if(q1 != P) + q1->mark |= LABEL; + break; + } + q = p; + } + + if(curtext && curtext->from.sym) { + curtext->from.sym->frame = curframe; + curtext->from.sym->become = curbecome; + if(curbecome > maxbecome) + maxbecome = curbecome; + } + + if(debug['b']) + print("max become = %d\n", maxbecome); + xdefine("ALEFbecome", STEXT, maxbecome); + + curtext = 0; + for(p = firstp; p != P; p = p->link) { + switch(p->as) { + case ATEXT: + curtext = p; + break; + case AJAL: + if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) { + o = maxbecome - curtext->from.sym->frame; + if(o <= 0) + break; + /* calling a become or calling a variable */ + if(p->to.sym == S || p->to.sym->become) { + curtext->to.offset += o; + if(debug['b']) { + curp = p; + print("%D calling %D increase %d\n", + &curtext->from, &p->to, o); + } + } + } + break; + } + } + + for(p = firstp; p != P; p = p->link) { + o = p->as; + switch(o) { + case ATEXT: + curtext = p; + autosize = p->to.offset + ptrsize; + if(autosize <= ptrsize) { + if(curtext->mark & LEAF || autosize <= 0) { + p->to.offset = -ptrsize; + autosize = 0; + } else if(ptrsize == 4) { + p->to.offset = 4; + autosize = 8; + } + } + + q = p; + if(autosize) { + q = prg(); + q->as = AADD; + q->line = p->line; + q->from.type = D_CONST; + q->from.offset = -autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + + q->link = p->link; + p->link = q; + } else + if(!(curtext->mark & LEAF)) { + if(debug['v']) + Bprint(&bso, "save suppressed in: %s\n", + curtext->from.sym->name); + Bflush(&bso); + curtext->mark |= LEAF; + } + + if(curtext->mark & LEAF) { + if(curtext->from.sym) + curtext->from.sym->type = SLEAF; + break; + } + + q1 = prg(); + q1->as = thechar == 'j' ? AMOV : AMOVW; + q1->line = p->line; + q1->from.type = D_REG; + q1->from.reg = REGLINK; + q1->to.type = D_OREG; + q1->from.offset = 0; + q1->to.reg = REGSP; + + q1->link = q->link; + q->link = q1; + break; + + case ARET: + nocache(p); + if(p->from.type == D_CONST) + goto become; + if(curtext->mark & LEAF) { + if(!autosize) { + p->as = AJMP; + p->from = zprg.from; + p->to.type = D_OREG; + p->to.offset = 0; + p->to.reg = REGLINK; + p->mark |= BRANCH; + break; + } + + p->as = AADD; + p->from.type = D_CONST; + p->from.offset = autosize; + p->to.type = D_REG; + p->to.reg = REGSP; + + q = prg(); + q->as = AJMP; + q->line = p->line; + q->to.type = D_OREG; + q->to.offset = 0; + q->to.reg = REGLINK; + q->mark |= BRANCH; + + q->link = p->link; + p->link = q; + break; + } + p->as = thechar == 'j' ? AMOV : AMOVW; + p->from.type = D_OREG; + p->from.offset = 0; + p->from.reg = REGSP; + p->to.type = D_REG; + p->to.reg = REGLINK; + + q = p; + if(autosize) { + q = prg(); + q->as = AADD; + q->line = p->line; + q->from.type = D_CONST; + q->from.offset = autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + + q->link = p->link; + p->link = q; + } + + q1 = prg(); + q1->as = AJMP; + q1->line = p->line; + q1->to.type = D_OREG; + q1->to.offset = 0; + q1->to.reg = REGLINK; + q1->mark |= BRANCH; + + q1->link = q->link; + q->link = q1; + break; + + become: + if(curtext->mark & LEAF) { + + q = prg(); + q->line = p->line; + q->as = AJMP; + q->from = zprg.from; + q->to = p->to; + q->cond = p->cond; + q->link = p->link; + q->mark |= BRANCH; + p->link = q; + + p->as = AADD; + p->from = zprg.from; + p->from.type = D_CONST; + p->from.offset = autosize; + p->to = zprg.to; + p->to.type = D_REG; + p->to.reg = REGSP; + + break; + } + q = prg(); + q->line = p->line; + q->as = AJMP; + q->from = zprg.from; + q->to = p->to; + q->cond = p->cond; + q->link = p->link; + q->mark |= BRANCH; + p->link = q; + + q = prg(); + q->line = p->line; + q->as = AADD; + q->from.type = D_CONST; + q->from.offset = autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + q->link = p->link; + p->link = q; + + p->as = thechar == 'j' ? AMOV : AMOVW; + p->from = zprg.from; + p->from.type = D_OREG; + p->from.offset = 0; + p->from.reg = REGSP; + p->to = zprg.to; + p->to.type = D_REG; + p->to.reg = REGLINK; + + break; + } + } + + curtext = P; +} + +void +nocache(Prog *p) +{ + p->optab = 0; + p->from.class = 0; + p->to.class = 0; +} diff --git a/utils/il/obj.c b/utils/il/obj.c new file mode 100644 index 00000000..42cca8ac --- /dev/null +++ b/utils/il/obj.c @@ -0,0 +1,1517 @@ +#define EXTERN +#include "l.h" +#include + +#ifndef DEFAULT +#define DEFAULT '9' +#endif + +char *noname = ""; +char symname[] = SYMDEF; +char thechar = 'i'; +char *thestring = "riscv"; + +/* + * -H1 is headerless + * -H2 -T4128 -R4096 is plan9 format + * -H5 -T0x4000A0 -R4 is elf executable + */ + +int little; + +void +main(int argc, char *argv[]) +{ + int c; + char *a; + + Binit(&bso, 1, OWRITE); + cout = -1; + listinit(); + outfile = 0; + nerrors = 0; + curtext = P; + HEADTYPE = -1; + INITTEXT = -1; + INITTEXTP = -1; + INITDAT = -1; + INITRND = -1; + INITENTRY = 0; + ptrsize = 4; + + a = strrchr(argv[0], '/'); + if(a == nil) + a = argv[0]; + else + a++; + if(*a == 'j') + thechar = 'j'; + ARGBEGIN { + default: + c = ARGC(); + if(c >= 0 && c < sizeof(debug)) + debug[c]++; + break; + case 'o': + outfile = ARGF(); + break; + case 'E': + a = ARGF(); + if(a) + INITENTRY = a; + break; + case 'T': + a = ARGF(); + if(a) + INITTEXT = atolwhex(a); + break; + case 'P': + a = ARGF(); + if(a) + INITTEXTP = atolwhex(a); + break; + case 'D': + a = ARGF(); + if(a) + INITDAT = atolwhex(a); + break; + case 'R': + a = ARGF(); + if(a) + INITRND = atolwhex(a); + break; + case 'H': + a = ARGF(); + if(a) + HEADTYPE = atolwhex(a); + break; + } ARGEND + + USED(argc); + + if(*argv == 0) { + diag("usage: %cl [-options] objects", thechar); + errorexit(); + } + if(debug['j']) + thechar = 'j'; + if(thechar == 'j'){ + thestring = "riscv64"; + ptrsize = 8; + } + if(!debug['9'] && !debug['U'] && !debug['B']) + debug[DEFAULT] = 1; + if(HEADTYPE == -1) { + if(debug['U']) + HEADTYPE = 5; + if(debug['B']) + HEADTYPE = 1; + if(debug['9']) + HEADTYPE = 2; + } + switch(HEADTYPE) { + default: + diag("unknown -H option"); + errorexit(); + + case 1: /* headerless */ + HEADR = 0; + if(INITTEXT == -1) + INITTEXT = 0; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 8; + break; + case 2: /* plan 9 */ + HEADR = 32L; + if(INITTEXT == -1) + INITTEXT = 4128; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + case 5: /* elf executable */ + HEADR = rnd(52L+3*32L, 16); + if(INITTEXT == -1) + INITTEXT = 0; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 8; + break; + } + if (INITTEXTP == -1) + INITTEXTP = INITTEXT; + if(INITDAT != 0 && INITRND != 0) + print("warning: -D0x%llux is ignored because of -R0x%llux\n", + INITDAT, INITRND); + if(debug['v']) + Bprint(&bso, "HEADER = -H0x%d -T0x%llux -D0x%llux -R0x%llux\n", + HEADTYPE, INITTEXT, INITDAT, INITRND); + Bflush(&bso); + zprg.as = AGOK; + zprg.reg = NREG; + zprg.from.name = D_NONE; + zprg.from.type = D_NONE; + zprg.from.reg = NREG; + zprg.to = zprg.from; + nopalign = zprg; + nopalign.as = AADD; + nopalign.from.type = D_CONST; + nopalign.to.type = D_REG; + nopalign.to.reg = REGZERO; + nopalign.reg = REGZERO; + buildop(); + histgen = 0; + textp = P; + datap = P; + pc = 0; + dtype = 4; + if(outfile == 0) { + static char name[20]; + + snprint(name, sizeof name, "%c.out", thechar); + outfile = name; + } + cout = create(outfile, 1, 0775); + if(cout < 0) { + diag("%s: cannot create", outfile); + errorexit(); + } + nuxiinit(); + + version = 0; + cbp = buf.cbuf; + cbc = sizeof(buf.cbuf); + firstp = prg(); + lastp = firstp; + + if(INITENTRY == 0) { + INITENTRY = "_main"; + if(debug['p']) + INITENTRY = "_mainp"; + if(!debug['l']) + lookup(INITENTRY, 0)->type = SXREF; + } else + lookup(INITENTRY, 0)->type = SXREF; + + while(*argv) + objfile(*argv++); + if(!debug['l']) + loadlib(); + firstp = firstp->link; + if(firstp == P) + goto out; + patch(); + if(debug['p']) + if(debug['1']) + doprof1(); + else + doprof2(); + dodata(); + follow(); + if(firstp == P) + goto out; + noops(); + span(); + asmb(); + undef(); + +out: + if(debug['v']) { + Bprint(&bso, "%5.2f cpu time\n", cputime()); + Bprint(&bso, "%ld memory used\n", thunk); + Bprint(&bso, "%d sizeof adr\n", sizeof(Adr)); + Bprint(&bso, "%d sizeof prog\n", sizeof(Prog)); + } + Bflush(&bso); + errorexit(); +} + +void +loadlib(void) +{ + int i; + long h; + Sym *s; + +loop: + xrefresolv = 0; + for(i=0; ilink) + if(s->type == SXREF) + goto loop; +} + +void +errorexit(void) +{ + + if(nerrors) { + if(cout >= 0) + remove(outfile); + exits("error"); + } + exits(0); +} + +void +objfile(char *file) +{ + long off, esym, cnt, l; + int f, work; + Sym *s; + char magbuf[SARMAG]; + char name[100], pname[150]; + struct ar_hdr arhdr; + char *e, *start, *stop; + + if(file[0] == '-' && file[1] == 'l') { + if(debug['9']) + sprint(name, "/%s/lib/lib", thestring); + else + sprint(name, "/usr/%clib/lib", thechar); + strcat(name, file+2); + strcat(name, ".a"); + file = name; + } + if(debug['v']) + Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file); + Bflush(&bso); + f = open(file, 0); + if(f < 0) { + diag("cannot open file: %s", file); + errorexit(); + } + l = read(f, magbuf, SARMAG); + if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){ + /* load it as a regular file */ + l = seek(f, 0L, 2); + seek(f, 0L, 0); + ldobj(f, l, file); + close(f); + return; + } + + if(debug['v']) + Bprint(&bso, "%5.2f ldlib: %s\n", cputime(), file); + l = read(f, &arhdr, SAR_HDR); + if(l != SAR_HDR) { + diag("%s: short read on archive file symbol header", file); + goto out; + } + if(strncmp(arhdr.name, symname, strlen(symname))) { + diag("%s: first entry not symbol header", file); + goto out; + } + + esym = SARMAG + SAR_HDR + atolwhex(arhdr.size); + off = SARMAG + SAR_HDR; + + /* + * just bang the whole symbol file into memory + */ + seek(f, off, 0); + cnt = esym - off; + start = malloc(cnt + 10); + cnt = read(f, start, cnt); + if(cnt <= 0){ + close(f); + return; + } + stop = &start[cnt]; + memset(stop, 0, 10); + + work = 1; + while(work){ + if(debug['v']) + Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file); + Bflush(&bso); + work = 0; + for(e = start; e < stop; e = strchr(e+5, 0) + 1) { + s = lookup(e+5, 0); + if(s->type != SXREF) + continue; + sprint(pname, "%s(%s)", file, s->name); + if(debug['v']) + Bprint(&bso, "%5.2f library: %s\n", cputime(), pname); + Bflush(&bso); + l = e[1] & 0xff; + l |= (e[2] & 0xff) << 8; + l |= (e[3] & 0xff) << 16; + l |= (e[4] & 0xff) << 24; + seek(f, l, 0); + l = read(f, &arhdr, SAR_HDR); + if(l != SAR_HDR) + goto bad; + if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag))) + goto bad; + l = atolwhex(arhdr.size); + ldobj(f, l, pname); + if(s->type == SXREF) { + diag("%s: failed to load: %s", file, s->name); + errorexit(); + } + work = 1; + xrefresolv = 1; + } + } + return; + +bad: + diag("%s: bad or out of date archive", file); +out: + close(f); +} + +int +zaddr(uchar *p, Adr *a, Sym *h[]) +{ + int i, c; + long l; + Sym *s; + Auto *u; + + c = p[2]; + if(c < 0 || c > NSYM){ + print("sym out of range: %d\n", c); + p[0] = ALAST+1; + return 0; + } + a->type = p[0]; + a->reg = p[1]; + a->sym = h[c]; + a->name = p[3]; + c = 4; + + if(a->reg < 0 || a->reg > NREG) { + print("register out of range %d\n", a->reg); + p[0] = ALAST+1; + return 0; /* force real diagnostic */ + } + + switch(a->type) { + default: + print("unknown type %d\n", a->type); + p[0] = ALAST+1; + return 0; /* force real diagnostic */ + + case D_NONE: + case D_REG: + case D_FREG: + break; + + case D_CTLREG: + case D_BRANCH: + case D_OREG: + case D_CONST: + a->offset = p[4] | (p[5]<<8) | + (p[6]<<16) | (p[7]<<24); + c += 4; + break; + + case D_SCONST: + while(nhunk < NSNAME) + gethunk(); + a->sval = (char*)hunk; + nhunk -= NSNAME; + hunk += NSNAME; + + memmove(a->sval, p+4, NSNAME); + c += NSNAME; + break; + + case D_VCONST: + while(nhunk < 12) + gethunk(); + if((uintptr)hunk & 2){ + nhunk -= 4; + hunk += 4; + } + a->vval = (vlong*)hunk; + nhunk -= 8; + hunk += 8; + *(long*)a->vval = p[4] | (p[5]<<8) | + (p[6]<<16) | (p[7]<<24); + *((long*)a->vval + 1) = p[8] | (p[9]<<8) | + (p[10]<<16) | (p[11]<<24); + c += 8; + break; + + case D_FCONST: + while(nhunk < sizeof(Ieee)) + gethunk(); + a->ieee = (Ieee*)hunk; + nhunk -= NSNAME; + hunk += NSNAME; + + a->ieee->l = p[4] | (p[5]<<8) | + (p[6]<<16) | (p[7]<<24); + a->ieee->h = p[8] | (p[9]<<8) | + (p[10]<<16) | (p[11]<<24); + c += 8; + break; + } + s = a->sym; + if(s == S) + return c; + i = a->name; + if(i != D_AUTO && i != D_PARAM) + return c; + + l = a->offset; + for(u=curauto; u; u=u->link) + if(u->asym == s) + if(u->type == i) { + if(u->aoffset > l) + u->aoffset = l; + return c; + } + + while(nhunk < sizeof(Auto)) + gethunk(); + u = (Auto*)hunk; + nhunk -= sizeof(Auto); + hunk += sizeof(Auto); + + u->link = curauto; + curauto = u; + u->asym = s; + u->aoffset = l; + u->type = i; + return c; +} + +void +addlib(char *obj) +{ + char name[1024], comp[256], *p; + int i; + + if(histfrogp <= 0) + return; + + if(histfrog[0]->name[1] == '/') { + sprint(name, ""); + i = 1; + } else + if(histfrog[0]->name[1] == '.') { + sprint(name, "."); + i = 0; + } else { + if(debug['9']) + sprint(name, "/%s/lib", thestring); + else + sprint(name, "/usr/%clib", thechar); + i = 0; + } + + for(; iname+1); + for(;;) { + p = strstr(comp, "$O"); + if(p == 0) + break; + memmove(p+1, p+2, strlen(p+2)+1); + p[0] = thechar; + } + for(;;) { + p = strstr(comp, "$M"); + if(p == 0) + break; + if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) { + diag("library component too long"); + return; + } + memmove(p+strlen(thestring), p+2, strlen(p+2)+1); + memmove(p, thestring, strlen(thestring)); + } + if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) { + diag("library component too long"); + return; + } + strcat(name, "/"); + strcat(name, comp); + } + for(i=0; iname = malloc(2*(histfrogp+1) + 1); + + u->asym = s; + u->type = type; + u->aoffset = line; + u->link = curhist; + curhist = u; + + j = 1; + for(i=0; ivalue; + s->name[j+0] = k>>8; + s->name[j+1] = k; + j += 2; + } +} + +void +histtoauto(void) +{ + Auto *l; + + while(l = curhist) { + curhist = l->link; + l->link = curauto; + curauto = l; + } +} + +void +collapsefrog(Sym *s) +{ + int i; + + /* + * bad encoding of path components only allows + * MAXHIST components. if there is an overflow, + * first try to collapse xxx/.. + */ + for(i=1; iname+1, "..") == 0) { + memmove(histfrog+i-1, histfrog+i+1, + (histfrogp-i-1)*sizeof(histfrog[0])); + histfrogp--; + goto out; + } + + /* + * next try to collapse . + */ + for(i=0; iname+1, ".") == 0) { + memmove(histfrog+i, histfrog+i+1, + (histfrogp-i-1)*sizeof(histfrog[0])); + goto out; + } + + /* + * last chance, just truncate from front + */ + memmove(histfrog+0, histfrog+1, + (histfrogp-1)*sizeof(histfrog[0])); + +out: + histfrog[histfrogp-1] = s; +} + +void +nopout(Prog *p) +{ + p->as = ANOP; + p->from.type = D_NONE; + p->to.type = D_NONE; +} + +uchar* +readsome(int f, uchar *buf, uchar *good, uchar *stop, int max) +{ + int n; + + n = stop - good; + memmove(buf, good, stop - good); + stop = buf + n; + n = MAXIO - n; + if(n > max) + n = max; + n = read(f, stop, n); + if(n <= 0) + return 0; + return stop + n; +} + +void +ldobj(int f, long c, char *pn) +{ + long ipc; + Prog *p, *t; + uchar *bloc, *bsize, *stop; + Sym *h[NSYM], *s, *di; + int v, o, r, skip; + ulong sig; + static int files; + static char **filen; + char **nfilen; + + if((files&15) == 0){ + nfilen = malloc((files+16)*sizeof(char*)); + memmove(nfilen, filen, files*sizeof(char*)); + free(filen); + filen = nfilen; + } + filen[files++] = strdup(pn); + + bsize = buf.xbuf; + bloc = buf.xbuf; + di = S; + +newloop: + memset(h, 0, sizeof(h)); + version++; + histfrogp = 0; + ipc = pc; + skip = 0; + +loop: + if(c <= 0) + goto eof; + r = bsize - bloc; + if(r < 100 && r < c) { /* enough for largest prog */ + bsize = readsome(f, buf.xbuf, bloc, bsize, c); + if(bsize == 0) + goto eof; + bloc = buf.xbuf; + goto loop; + } + o = bloc[0]; /* as */ + if(o <= AXXX || o >= ALAST) { + diag("%s: line %ld: opcode out of range %d", pn, pc-ipc, o); + print(" probably not a .%c file\n", thechar); + errorexit(); + } + if(o == ANAME || o == ASIGNAME) { + sig = 0; + if(o == ASIGNAME){ + sig = bloc[1] | (bloc[2]<<8) | (bloc[3]<<16) | (bloc[4]<<24); + bloc += 4; + c -= 4; + } + stop = memchr(&bloc[3], 0, bsize-&bloc[3]); + if(stop == 0){ + bsize = readsome(f, buf.xbuf, bloc, bsize, c); + if(bsize == 0) + goto eof; + bloc = buf.xbuf; + stop = memchr(&bloc[3], 0, bsize-&bloc[3]); + if(stop == 0){ + fprint(2, "%s: name too long\n", pn); + errorexit(); + } + } + v = bloc[1]; /* type */ + o = bloc[2]; /* sym */ + bloc += 3; + c -= 3; + + r = 0; + if(v == D_STATIC) + r = version; + s = lookup((char*)bloc, r); + c -= &stop[1] - bloc; + bloc = stop + 1; + + if(debug['S'] && r == 0) + sig = 1729; + if(sig != 0){ + if(s->sig != 0 && s->sig != sig) + diag("incompatible type signatures %lux(%s) and %lux(%s) for %s", s->sig, filen[s->file], sig, pn, s->name); + s->sig = sig; + s->file = files-1; + } + + if(debug['W']) + print(" ANAME %s\n", s->name); + h[o] = s; + if((v == D_EXTERN || v == D_STATIC) && s->type == 0) + s->type = SXREF; + if(v == D_FILE) { + if(s->type != SFILE) { + histgen++; + s->type = SFILE; + s->value = histgen; + } + if(histfrogp < MAXHIST) { + histfrog[histfrogp] = s; + histfrogp++; + } else + collapsefrog(s); + } + goto loop; + } + + if(nhunk < sizeof(Prog)) + gethunk(); + p = (Prog*)hunk; + nhunk -= sizeof(Prog); + hunk += sizeof(Prog); + + p->as = o; + p->reg = bloc[1]; + p->line = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24); + + r = zaddr(bloc+6, &p->from, h) + 6; + r += zaddr(bloc+r, &p->to, h); + bloc += r; + c -= r; + + if(p->reg < 0 || p->reg > NREG) + diag("register out of range %d", p->reg); + + p->link = P; + p->cond = P; + + if(debug['W']) + print("%P\n", p); + + if(thechar == 'i') { + switch(o) { + case AMOV: + if(p->from.type == D_OREG || p->to.type == D_OREG) + o = AMOVW; + break; + + case AMOVW: + case AMOVWU: + if(p->from.type == D_OREG || p->to.type == D_OREG) + o = AMOVW; + else + o = AMOV; + break; + + case ADIVW: + case ADIVUW: + o = ADIV; + break; + + case AREMW: + case AREMUW: + o = AREM; + break; + + case AADDW: o = AADD; break; + case ASUBW: o = ASUB; break; + case ASLLW: o = ASLL; break; + case ASRLW: o = ASRL; break; + case ASRAW: o = ASRA; break; + case AMULW: o = AMUL; break; + } + p->as = o; + } + + switch(o) { + case AHISTORY: + if(p->to.offset == -1) { + addlib(pn); + histfrogp = 0; + goto loop; + } + addhist(p->line, D_FILE); /* 'z' */ + if(p->to.offset) + addhist(p->to.offset, D_FILE1); /* 'Z' */ + histfrogp = 0; + goto loop; + + case AEND: + histtoauto(); + if(curtext != P) + curtext->to.autom = curauto; + curauto = 0; + curtext = P; + if(c) + goto newloop; + return; + + case AGLOBL: + s = p->from.sym; + if(s == S) { + diag("GLOBL must have a name\n%P", p); + errorexit(); + } + if(s->type == 0 || s->type == SXREF) { + s->type = SBSS; + s->value = 0; + } + if(s->type != SBSS) { + diag("redefinition: %s\n%P", s->name, p); + s->type = SBSS; + s->value = 0; + } + if(p->to.offset > s->value) + s->value = p->to.offset; + break; + + case ADYNT: + if(p->to.sym == S) { + diag("DYNT without a sym\n%P", p); + break; + } + di = p->to.sym; + p->reg = 4; + if(di->type == SXREF) { + if(debug['z']) + Bprint(&bso, "%P set to %d\n", p, dtype); + di->type = SCONST; + di->value = dtype; + dtype += 4; + } + if(p->from.sym == S) + break; + + p->from.offset = di->value; + p->from.sym->type = SDATA; + if(curtext == P) { + diag("DYNT not in text: %P", p); + break; + } + p->to.sym = curtext->from.sym; + p->to.type = D_CONST; + p->link = datap; + datap = p; + break; + + case AINIT: + if(p->from.sym == S) { + diag("INIT without a sym\n%P", p); + break; + } + if(di == S) { + diag("INIT without previous DYNT\n%P", p); + break; + } + p->from.offset = di->value; + p->from.sym->type = SDATA; + p->link = datap; + datap = p; + break; + + case ADATA: + if(p->from.sym == S) { + diag("DATA without a sym\n%P", p); + break; + } + p->link = datap; + datap = p; + break; + + case AGOK: + diag("unknown opcode\n%P", p); + p->pc = pc; + pc++; + break; + + case ATEXT: + if(curtext != P) { + histtoauto(); + curtext->to.autom = curauto; + curauto = 0; + } + skip = 0; + curtext = p; + autosize = p->to.offset; + if(autosize < 0) + autosize = -ptrsize; + else if(autosize != 0){ + autosize = (autosize + 3) & ~3; + if(thechar == 'j'){ + if((autosize & 4) != 0) + autosize += 4; + }else{ + if((autosize & 4) == 0) + autosize += 4; + } + } + p->to.offset = autosize; + s = p->from.sym; + if(s == S) { + diag("TEXT must have a name\n%P", p); + errorexit(); + } + if(s->type != 0 && s->type != SXREF) { + if(p->reg & DUPOK) { + skip = 1; + goto casedef; + } + diag("redefinition: %s\n%P", s->name, p); + } + s->type = STEXT; + s->value = pc; + lastp->link = p; + lastp = p; + p->pc = pc; + pc++; + if(textp == P) { + textp = p; + etextp = p; + goto loop; + } + etextp->cond = p; + etextp = p; + break; + + case ASUB: + case ASUBW: + if(p->from.type == D_CONST) + if(p->from.name == D_NONE) { + p->from.offset = -p->from.offset; + p->as = o == ASUB ? AADD : AADDW; + } + goto casedef; + + case AMOVF: + if(skip) + goto casedef; + + if(p->from.type == D_FCONST) { + /* size sb 9 max */ + sprint(literal, "$%lux", ieeedtof(p->from.ieee)); + s = lookup(literal, 0); + if(s->type == 0) { + s->type = SBSS; + s->value = 4; + t = prg(); + t->as = ADATA; + t->line = p->line; + t->from.type = D_OREG; + t->from.sym = s; + t->from.name = D_EXTERN; + t->reg = 4; + t->to = p->from; + t->link = datap; + datap = t; + } + p->from.type = D_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + p->from.offset = 0; + } + goto casedef; + + case AMOVD: + if(skip) + goto casedef; + + if(p->from.type == D_FCONST) { + /* size sb 18 max */ + sprint(literal, "$%lux.%lux", + p->from.ieee->l, p->from.ieee->h); + s = lookup(literal, 0); + if(s->type == 0) { + s->type = SBSS; + s->value = 8; + t = prg(); + t->as = ADATA; + t->line = p->line; + t->from.type = D_OREG; + t->from.sym = s; + t->from.name = D_EXTERN; + t->reg = 8; + t->to = p->from; + t->link = datap; + datap = t; + } + p->from.type = D_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + p->from.offset = 0; + } + goto casedef; + + case ABGT: + case ABGTU: + case ABLE: + case ABLEU: + if(p->from.type == D_REG){ + p->as = relrev(p->as); + if(p->reg == NREG) + p->reg = REGZERO; + else{ + r = p->from.reg; + p->from.reg = p->reg; + p->reg = r; + } + } + goto casedef; + + case ASGT: + case ASGTU: + r = p->from.reg; + p->from.reg = p->reg; + p->reg = r; + p->as = p->as == ASGT ? ASLT : ASLTU; + goto casedef; + + case AMOV: + if(p->from.type == D_CONST && + p->from.name == D_NONE && + p->from.reg != NREG && + p->from.reg != REGZERO){ + p->as = AADD; + p->reg = p->from.reg; + p->from.reg = NREG; + } + goto casedef; + +/* + case AMUL: + case AMULXSS: + case AMULXSU: + case AMULXUU: + if(!debug['m']) + goto casedef; + if(o != AMUL || p->from.type != D_REG){ + diag("unsupported multiply operation"); + if(!debug['v']) + prasm(p); + break; + } + print("transforming multiply"); + prasm(p); + if(p->reg == NREG) + p->reg = p->to.reg; + p->as = ACUSTOM; + p->from.type = D_CONST; + p->from.name = D_NONE; + p->from.offset = 0; + p->to.type = D_CONST; + p->to.name = D_NONE; + p->to.offset = p->from.reg<<16 | p->reg<<8 | p->to.reg; + p->from.reg = NREG; + p->to.reg = NREG; + prasm(p); + goto casedef; +*/ + + default: + casedef: + if(skip) + nopout(p); + + if(p->to.type == D_BRANCH) + p->to.offset += ipc; + lastp->link = p; + lastp = p; + p->pc = pc; + pc++; + break; + } + goto loop; + +eof: + diag("truncated object file: %s", pn); +} + +Sym* +lookup(char *symb, int v) +{ + Sym *s; + char *p; + long h; + int c, l; + + h = v; + for(p=symb; c = *p; p++) + h = h+h+h + c; + l = (p - symb) + 1; + if(h < 0) + h = ~h; + h %= NHASH; + for(s = hash[h]; s != S; s = s->link) + if(s->version == v) + if(memcmp(s->name, symb, l) == 0) + return s; + + while(nhunk < sizeof(Sym)) + gethunk(); + s = (Sym*)hunk; + nhunk -= sizeof(Sym); + hunk += sizeof(Sym); + + s->name = malloc(l); + memmove(s->name, symb, l); + + s->link = hash[h]; + s->type = 0; + s->version = v; + s->value = 0; + s->sig = 0; + hash[h] = s; + return s; +} + +Prog* +prg(void) +{ + Prog *p; + + while(nhunk < sizeof(Prog)) + gethunk(); + p = (Prog*)hunk; + nhunk -= sizeof(Prog); + hunk += sizeof(Prog); + + *p = zprg; + return p; +} + +void +gethunk(void) +{ + char *h; + long nh; + + nh = NHUNK; + if(thunk >= 5L*NHUNK) { + nh = 5L*NHUNK; + if(thunk >= 25L*NHUNK) + nh = 25L*NHUNK; + } + h = mysbrk(nh); + if(h == (char*)-1) { + diag("out of memory"); + errorexit(); + } + hunk = h; + nhunk = nh; + thunk += nh; +} + +void +doprof1(void) +{ + Sym *s; + long n; + Prog *p, *q; + + if(debug['v']) + Bprint(&bso, "%5.2f profile 1\n", cputime()); + Bflush(&bso); + s = lookup("__mcount", 0); + n = 1; + for(p = firstp->link; p != P; p = p->link) { + if(p->as == ATEXT) { + q = prg(); + q->line = p->line; + q->link = datap; + datap = q; + q->as = ADATA; + q->from.type = D_OREG; + q->from.name = D_EXTERN; + q->from.offset = n*4; + q->from.sym = s; + q->reg = 4; + q->to = p->from; + q->to.type = D_CONST; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AMOVW; + p->from.type = D_OREG; + p->from.name = D_EXTERN; + p->from.sym = s; + p->from.offset = n*4 + 4; + p->to.type = D_REG; + p->to.reg = REGTMP; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AADD; + p->from.type = D_CONST; + p->from.offset = 1; + p->to.type = D_REG; + p->to.reg = REGTMP; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AMOVW; + p->from.type = D_REG; + p->from.reg = REGTMP; + p->to.type = D_OREG; + p->to.name = D_EXTERN; + p->to.sym = s; + p->to.offset = n*4 + 4; + + n += 2; + continue; + } + } + q = prg(); + q->line = 0; + q->link = datap; + datap = q; + + q->as = ADATA; + q->from.type = D_OREG; + q->from.name = D_EXTERN; + q->from.sym = s; + q->reg = 4; + q->to.type = D_CONST; + q->to.offset = n; + + s->type = SBSS; + s->value = n*4; +} + +void +doprof2(void) +{ + Sym *s2, *s4; + Prog *p, *q, *q2, *ps2, *ps4; + + if(debug['v']) + Bprint(&bso, "%5.2f profile 2\n", cputime()); + Bflush(&bso); + + if(debug['e']){ + s2 = lookup("_tracein", 0); + s4 = lookup("_traceout", 0); + }else{ + s2 = lookup("_profin", 0); + s4 = lookup("_profout", 0); + } + if(s2->type != STEXT || s4->type != STEXT) { + if(debug['e']) + diag("_tracein/_traceout not defined %d %d", s2->type, s4->type); + else + diag("_profin/_profout not defined"); + return; + } + + ps2 = P; + ps4 = P; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + if(p->from.sym == s2) { + ps2 = p; + p->reg = 1; + } + if(p->from.sym == s4) { + ps4 = p; + p->reg = 1; + } + } + } + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + if(p->reg & NOPROF) { + for(;;) { + q = p->link; + if(q == P) + break; + if(q->as == ATEXT) + break; + p = q; + } + continue; + } + + /* + * CALL profin, R2 + */ + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + if(debug['e']){ /* embedded tracing */ + q2 = prg(); + p->link = q2; + q2->link = q; + + q2->line = p->line; + q2->pc = p->pc; + + q2->as = AJMP; + q2->to.type = D_BRANCH; + q2->to.sym = p->to.sym; + q2->cond = q->link; + }else + p->link = q; + p = q; + p->as = AJAL; + p->to.type = D_BRANCH; + p->cond = ps2; + p->to.sym = s2; + + continue; + } + if(p->as == ARET) { + /* + * RET (default) + */ + if(debug['e']){ /* embedded tracing */ + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + } + /* + * RET + */ + q = prg(); + q->as = ARET; + q->from = p->from; + q->to = p->to; + q->link = p->link; + p->link = q; + + /* + * CALL profout + */ + p->as = AJAL; + p->from = zprg.from; + p->to = zprg.to; + p->to.type = D_BRANCH; + p->cond = ps4; + p->to.sym = s4; + + p = q; + + continue; + } + } +} + +void +nuxiinit(void) +{ + int i, c; + + for(i=0; i<4; i++){ + c = find1(0x04030201L, i+1); + if(i < 2) + inuxi2[i] = c; + if(i < 1) + inuxi1[i] = c; + inuxi4[i] = c; + inuxi8[i] = c; + inuxi8[i+4] = c+4; + fnuxi4[i] = c; + fnuxi8[i] = c; + fnuxi8[i+4] = c+4; + } + if(debug['v']) { + Bprint(&bso, "inuxi = "); + for(i=0; i<1; i++) + Bprint(&bso, "%d", inuxi1[i]); + Bprint(&bso, " "); + for(i=0; i<2; i++) + Bprint(&bso, "%d", inuxi2[i]); + Bprint(&bso, " "); + for(i=0; i<4; i++) + Bprint(&bso, "%d", inuxi4[i]); + Bprint(&bso, " "); + for(i=0; i<8; i++) + Bprint(&bso, "%d", inuxi8[i]); + Bprint(&bso, "\nfnuxi = "); + for(i=0; i<8; i++) + Bprint(&bso, "%d", fnuxi8[i]); + Bprint(&bso, "\n"); + } + Bflush(&bso); +} + +int +find1(long l, int c) +{ + char *p; + int i; + + p = (char*)&l; + for(i=0; i<4; i++) + if(*p++ == c) + return i; + return 0; +} + +long +ieeedtof(Ieee *ieeep) +{ + int exp; + long v; + + if(ieeep->h == 0) + return 0; + exp = (ieeep->h>>20) & ((1L<<11)-1L); + exp -= (1L<<10) - 2L; + v = (ieeep->h & 0xfffffL) << 3; + v |= (ieeep->l >> 29) & 0x7L; + if((ieeep->l >> 28) & 1) { + v++; + if(v & 0x800000L) { + v = (v & 0x7fffffL) >> 1; + exp++; + } + } + if(exp <= -126 || exp >= 130) + diag("double fp to single fp overflow"); + v |= ((exp + 126) & 0xffL) << 23; + v |= ieeep->h & 0x80000000L; + return v; +} + +double +ieeedtod(Ieee *ieeep) +{ + Ieee e; + double fr; + int exp; + + if(ieeep->h & (1L<<31)) { + e.h = ieeep->h & ~(1L<<31); + e.l = ieeep->l; + return -ieeedtod(&e); + } + if(ieeep->l == 0 && ieeep->h == 0) + return 0; + fr = ieeep->l & ((1L<<16)-1L); + fr /= 1L<<16; + fr += (ieeep->l>>16) & ((1L<<16)-1L); + fr /= 1L<<16; + fr += (ieeep->h & (1L<<20)-1L) | (1L<<20); + fr /= 1L<<21; + exp = (ieeep->h>>20) & ((1L<<11)-1L); + exp -= (1L<<10) - 2L; + return ldexp(fr, exp); +} diff --git a/utils/il/optab.c b/utils/il/optab.c new file mode 100644 index 00000000..1bf79169 --- /dev/null +++ b/utils/il/optab.c @@ -0,0 +1,194 @@ +#include "l.h" + +Optab optab[] = +{ + /* add */ AADD, C_REG, C_REG, 0,1, 4, OOP, 0, 0, + /* sub */ ASUB, C_REG, C_REG, 0,5, 4, OOP, 0, 0x20, + /* sll */ ASLL, C_REG, C_REG, 0,0, 4, OOP, 1, 0, + /* slt */ ASLT, C_REG, C_REG, 0,0, 4, OOP, 2, 0, + /* sltu */ ASLTU, C_REG, C_REG, 0,0, 4, OOP, 3, 0, + /* xor */ AXOR, C_REG, C_REG, 0,5, 4, OOP, 4, 0, + /* srl */ ASRL, C_REG, C_REG, 0,0, 4, OOP, 5, 0, + /* sra */ ASRA, C_REG, C_REG, 0,0, 4, OOP, 5, 0x20, + /* or */ AOR, C_REG, C_REG, 0,5, 4, OOP, 6, 0, + /* and */ AAND, C_REG, C_REG, 0,5, 4, OOP, 7, 0, + /* mul */ AMUL, C_REG, C_REG, 0,0, 4, OOP, 0, 0x01, + /* mulh */ AMULH, C_REG, C_REG, 0,0, 4, OOP, 1, 0x01, + /* mulhsu */ AMULHSU, C_REG, C_REG, 0,0, 4, OOP, 2, 0x01, + /* mulhu */ AMULHU, C_REG, C_REG, 0,0, 4, OOP, 3, 0x01, + /* div */ ADIV, C_REG, C_REG, 0,0, 4, OOP, 4, 0x01, + /* divu */ ADIVU, C_REG, C_REG, 0,0, 4, OOP, 5, 0x01, + /* rem */ AREM, C_REG, C_REG, 0,0, 4, OOP, 6, 0x01, + /* remu */ AREMU, C_REG, C_REG, 0,0, 4, OOP, 7, 0x01, + + /* addw */ AADDW, C_REG, C_REG, 0,22, 4, OOP_32, 0, 0, + /* subw */ ASUBW, C_REG, C_REG, 0,22, 4, OOP_32, 0, 0x20, + /* sllw */ ASLLW, C_REG, C_REG, 0,0, 4, OOP_32, 1, 0, + /* srlw */ ASRLW, C_REG, C_REG, 0,0, 4, OOP_32, 5, 0, + /* sraw */ ASRAW, C_REG, C_REG, 0,0, 4, OOP_32, 5, 0x20, + + /* mulw */ AMULW, C_REG, C_REG, 0,0, 4, OOP_32, 0, 0x01, + /* divw */ ADIVW, C_REG, C_REG, 0,0, 4, OOP_32, 4, 0x01, + /* divuw */ ADIVUW, C_REG, C_REG, 0,0, 4, OOP_32, 5, 0x01, + /* remw */ AREMW, C_REG, C_REG, 0,0, 4, OOP_32, 6, 0x01, + /* remuw */ AREMUW, C_REG, C_REG, 0,0, 4, OOP_32, 7, 0x01, + + /* slli */ ASLL, C_SCON, C_REG, 1,8, 4, OOP_IMM, 1, 0, + /* srli */ ASRL, C_SCON, C_REG, 1,9, 4, OOP_IMM, 5, 0, + /* srai */ ASRA, C_SCON, C_REG, 1,9, 4, OOP_IMM, 5, 0x20, + + /* addi */ AADD, C_SCON, C_REG, 2,10, 4, OOP_IMM, 0, 0, + /* slti */ ASLT, C_SCON, C_REG, 2,0, 4, OOP_IMM, 2, 0, + /* sltiu */ ASLTU, C_SCON, C_REG, 2,0, 4, OOP_IMM, 3, 0, + /* xori */ AXOR, C_SCON, C_REG, 2,0, 4, OOP_IMM, 4, 0, + /* ori */ AOR, C_SCON, C_REG, 2,0, 4, OOP_IMM, 6, 0, + /* andi */ AAND, C_SCON, C_REG, 2,13, 4, OOP_IMM, 7, 0, + + /* addiw */ AADDW, C_SCON, C_REG, 2,23, 4, OOP_IMM_32, 0, 0, + /* slliw */ ASLLW, C_SCON, C_REG, 2,0, 4, OOP_IMM_32, 1, 0, + /* srliw */ ASRLW, C_SCON, C_REG, 2,0, 4, OOP_IMM_32, 5, 0, + /* sraiw */ ASRAW, C_SCON, C_REG, 2,0, 4, OOP_IMM_32, 5, 0x20, + + /* beq */ ABEQ, C_REG, C_SBRA, 3,14, 4, OBRANCH, 0, 0, + /* bne */ ABNE, C_REG, C_SBRA, 3,15, 4, OBRANCH, 1, 0, + /* blt */ ABLT, C_REG, C_SBRA, 3,0, 4, OBRANCH, 4, 0, + /* bge */ ABGE, C_REG, C_SBRA, 3,0, 4, OBRANCH, 5, 0, + /* bltu */ ABLTU, C_REG, C_SBRA, 3,0, 4, OBRANCH, 6, 0, + /* bgeu */ ABGEU, C_REG, C_SBRA, 3,0, 4, OBRANCH, 7, 0, + + /* jal */ AJAL, C_NONE, C_SBRA, 4,11, 4, OJAL, 0, REGLINK, + /* jal */ AJMP, C_NONE, C_SBRA, 4,12, 4, OJAL, 0, REGZERO, + /* jal */ AJAL, C_NONE, C_LBRA, 18,0, 8, OJALR, 0, REGLINK, + /* jal */ AJMP, C_NONE, C_LBRA, 18,0, 8, OJALR, 0, REGZERO, + /* jalr */ AJAL, C_NONE, C_SOREG, 5,3, 4, OJALR, 0, REGLINK, + /* jalr */ AJMP, C_NONE, C_SOREG, 5,4, 4, OJALR, 0, REGZERO, + + /* sb */ AMOVB, C_ZREG, C_SOREG, 6,0, 4, OSTORE, 0, 0, + /* sb */ AMOVBU, C_ZREG, C_SOREG, 6,0, 4, OSTORE, 0, 0, + /* sh */ AMOVH, C_ZREG, C_SOREG, 6,0, 4, OSTORE, 1, 0, + /* sw */ AMOVW, C_ZREG, C_SOREG, 6,19, 4, OSTORE, 2, 0, + /* sd */ AMOV, C_ZREG, C_SOREG, 6,25, 4, OSTORE, 3, 0, + /* fsw */ AMOVF, C_FREG, C_SOREG, 6,20, 4, OSTORE_FP, 2, 0, + /* fsd */ AMOVD, C_FREG, C_SOREG, 6,21, 4, OSTORE_FP, 3, 0, + + /* sb */ AMOVB, C_ZREG, C_LEXT, 12,0, 8, OSTORE, 0, 0, + /* sb */ AMOVBU, C_ZREG, C_LEXT, 12,0, 8, OSTORE, 0, 0, + /* sh */ AMOVH, C_ZREG, C_LEXT, 12,0, 8, OSTORE, 1, 0, + /* sw */ AMOVW, C_ZREG, C_LEXT, 12,0, 8, OSTORE, 2, 0, + /* sd */ AMOV, C_ZREG, C_LEXT, 12,0, 8, OSTORE, 3, 0, + /* fsw */ AMOVF, C_FREG, C_LEXT, 12,0, 8, OSTORE_FP, 2, 0, + /* fsd */ AMOVD, C_FREG, C_LEXT, 12,0, 8, OSTORE_FP, 3, 0, + + /* sb */ AMOVB, C_ZREG, C_LOREG, 15,0, 12, OSTORE, 0, 0, + /* sb */ AMOVBU, C_ZREG, C_LOREG, 15,0, 12, OSTORE, 0, 0, + /* sh */ AMOVH, C_ZREG, C_LOREG, 15,0, 12, OSTORE, 1, 0, + /* sw */ AMOVW, C_ZREG, C_LOREG, 15,0, 12, OSTORE, 2, 0, + /* sd */ AMOV, C_ZREG, C_LOREG, 15,0, 12, OSTORE, 3, 0, + /* fsw */ AMOVF, C_FREG, C_LOREG, 15,0, 12, OSTORE_FP, 2, 0, + /* fsd */ AMOVD, C_FREG, C_LOREG, 15,0, 12, OSTORE_FP, 3, 0, + + /* lb */ AMOVB, C_SOREG, C_REG, 7,0, 4, OLOAD, 0, 0, + /* lh */ AMOVH, C_SOREG, C_REG, 7,0, 4, OLOAD, 1, 0, + /* lw */ AMOVW, C_SOREG, C_REG, 7,16, 4, OLOAD, 2, 0, + /* ld */ AMOV, C_SOREG, C_REG, 7,24, 4, OLOAD, 3, 0, + /* lbu */ AMOVBU, C_SOREG, C_REG, 7,0, 4, OLOAD, 4, 0, + /* lhu */ AMOVHU, C_SOREG, C_REG, 7,0, 4, OLOAD, 5, 0, + /* lwu */ AMOVWU, C_SOREG, C_REG, 7,0, 4, OLOAD, 6, 0, + /* flw */ AMOVF, C_SOREG, C_FREG, 7,17, 4, OLOAD_FP, 2, 0, + /* fld */ AMOVD, C_SOREG, C_FREG, 7,18, 4, OLOAD_FP, 3, 0, + + /* lui */ AMOV, C_UCON, C_REG, 8,7, 4, OLUI, 0, 0, + + /* lb */ AMOVB, C_LEXT, C_REG, 13,0, 8, OLOAD, 0, 0, + /* lh */ AMOVH, C_LEXT, C_REG, 13,0, 8, OLOAD, 1, 0, + /* lw */ AMOVW, C_LEXT, C_REG, 13,0, 8, OLOAD, 2, 0, + /* ld */ AMOV, C_LEXT, C_REG, 13,0, 8, OLOAD, 3, 0, + /* lbu */ AMOVBU, C_LEXT, C_REG, 13,0, 8, OLOAD, 4, 0, + /* lhu */ AMOVHU, C_LEXT, C_REG, 13,0, 8, OLOAD, 5, 0, + /* lwu */ AMOVWU, C_LEXT, C_REG, 13,0, 8, OLOAD, 6, 0, + /* flw */ AMOVF, C_LEXT, C_FREG, 13,0, 8, OLOAD_FP, 2, 0, + /* fld */ AMOVD, C_LEXT, C_FREG, 13,0, 8, OLOAD_FP, 3, 0, + + /* lb */ AMOVB, C_LOREG, C_REG, 16,0, 12, OLOAD, 0, 0, + /* lh */ AMOVH, C_LOREG, C_REG, 16,0, 12, OLOAD, 1, 0, + /* lw */ AMOVW, C_LOREG, C_REG, 16,0, 12, OLOAD, 2, 0, + /* ld */ AMOV, C_LOREG, C_REG, 16,0, 12, OLOAD, 3, 0, + /* lbu */ AMOVBU, C_LOREG, C_REG, 16,0, 12, OLOAD, 4, 0, + /* lhu */ AMOVHU, C_LOREG, C_REG, 16,0, 12, OLOAD, 5, 0, + /* lwu */ AMOVWU, C_LOREG, C_REG, 16,0, 12, OLOAD, 6, 0, + /* flw */ AMOVF, C_LOREG, C_FREG, 16,0, 12, OLOAD_FP, 2, 0, + /* fld */ AMOVD, C_LOREG, C_FREG, 16,0, 12, OLOAD_FP, 3, 0, + + /* addi */ AMOVW, C_SCON, C_REG, 11,6, 4, OOP_IMM, 0, 0, + /* addi */ AMOVW, C_SECON, C_REG, 11,0, 4, OOP_IMM, 0, 0, + /* addi */ AMOVW, C_SACON, C_REG, 11,0, 4, OOP_IMM, 0, 0, + /* lui,addi */ AMOVW, C_LCON, C_REG, 9,0, 8, OOP_IMM, 0, 0, + /* lui,addi */ AMOVW, C_LECON, C_REG, 9,0, 8, OOP_IMM, 0, 0, + /* ",",add */ AMOVW, C_LACON, C_REG, 14,0, 12, OOP_IMM, 0, 0, + + /* add */ AMOV, C_REG, C_REG, 0,2, 4, OOP, 0, 0, + /* addi */ AMOV, C_SCON, C_REG, 11,6, 4, OOP_IMM, 0, 0, + /* addi */ AMOV, C_SECON, C_REG, 11,0, 4, OOP_IMM, 0, 0, + /* addi */ AMOV, C_SACON, C_REG, 11,0, 4, OOP_IMM, 0, 0, + /* lui,addi */ AMOV, C_LCON, C_REG, 9,0, 8, OOP_IMM, 0, 0, + /* lui,addi */ AMOV, C_LECON, C_REG, 20,0, 8, OOP_IMM, 0, 0, + /* lui,s[rl]ai */ AMOV, C_VCON, C_REG, 21,0, 8, OOP_IMM, 5, 0x20, + /* ",",add */ AMOV, C_LACON, C_REG, 14,0, 12, OOP_IMM, 0, 0, + /* ",",add */ AADD, C_LCON, C_REG, 14,0, 12, OOP_IMM, 0, 0, + /* ",",and */ AAND, C_LCON, C_REG, 14,0, 12, OOP_IMM, 7, 0, + /* ",",or */ AOR, C_LCON, C_REG, 14,0, 12, OOP_IMM, 6, 0, + /* ",",xor */ AXOR, C_LCON, C_REG, 14,0, 12, OOP_IMM, 4, 0, + + /* addiw */ AMOVW, C_REG, C_REG, 19,23, 4, OOP_IMM_32, 0, 0, + /* andi */ AMOVBU, C_ZREG, C_REG, 10,0, 4, OOP_IMM, 7, 0xFF, + /* slli,srli */ AMOVHU, C_ZREG, C_REG, 10,0, 8, OOP_IMM, 5, 16, + /* slli,srli */ AMOVWU, C_ZREG, C_REG, 10,0, 8, OOP_IMM, 5, 0, + /* slli,srai */ AMOVB, C_ZREG, C_REG, 10,0, 8, OOP_IMM, 5, 24+(0x20<<5), + /* slli,srai */ AMOVH, C_ZREG, C_REG, 10,0, 8, OOP_IMM, 5, 16+(0x20<<5), + + ASYS, C_NONE, C_SCON, 24,0, 4, OSYSTEM, 0, 0, + ACSRRW, C_CTLREG, C_REG, 22,0, 4, OSYSTEM, 1, 0, + ACSRRS, C_CTLREG, C_REG, 22,0, 4, OSYSTEM, 2, 0, + ACSRRC, C_CTLREG, C_REG, 22,0, 4, OSYSTEM, 3, 0, + ACSRRWI, C_CTLREG, C_REG, 22,0, 4, OSYSTEM, 5, 0, + ACSRRSI, C_CTLREG, C_REG, 22,0, 4, OSYSTEM, 6, 0, + ACSRRCI, C_CTLREG, C_REG, 22,0, 4, OSYSTEM, 7, 0, + + AADDF, C_FREG, C_FREG, 0,0, 4, OOP_FP, 0x7, 0x00, + ASUBF, C_FREG, C_FREG, 0,0, 4, OOP_FP, 0x7, 0x04, + AMULF, C_FREG, C_FREG, 0,0, 4, OOP_FP, 0x7, 0x08, + ADIVF, C_FREG, C_FREG, 0,0, 4, OOP_FP, 0x7, 0x0c, + AADDD, C_FREG, C_FREG, 0,0, 4, OOP_FP, 0x7, 0x01, + ASUBD, C_FREG, C_FREG, 0,0, 4, OOP_FP, 0x7, 0x05, + AMULD, C_FREG, C_FREG, 0,0, 4, OOP_FP, 0x7, 0x09, + ADIVD, C_FREG, C_FREG, 0,0, 4, OOP_FP, 0x7, 0x0d, + + ACMPEQF, C_FREG, C_REG, 0,0, 4, OOP_FP, 0x2, 0x50, + ACMPLEF, C_FREG, C_REG, 0,0, 4, OOP_FP, 0x0, 0x50, + ACMPLTF, C_FREG, C_REG, 0,0, 4, OOP_FP, 0x1, 0x50, + ACMPEQD, C_FREG, C_REG, 0,0, 4, OOP_FP, 0x2, 0x51, + ACMPLED, C_FREG, C_REG, 0,0, 4, OOP_FP, 0x0, 0x51, + ACMPLTD, C_FREG, C_REG, 0,0, 4, OOP_FP, 0x1, 0x51, + + /* float move */ AMOVF, C_FREG, C_FREG, 0,0, 4, OOP_FP, 0x0, 0x10, + /* dbl move */ AMOVD, C_FREG, C_FREG, 0,0, 4, OOP_FP, 0x0, 0x11, + + /* float->dbl */ AMOVFD, C_FREG, C_FREG, 17,0, 4, OOP_FP, 0x0, 0x21, + /* dbl->float */ AMOVDF, C_FREG, C_FREG, 17,0, 4, OOP_FP, 0x1, 0x20, + /* float->int */ AMOVFW, C_FREG, C_REG, 17,0, 4, OOP_FP, 0x0, 0x60, + /* dbl->int */ AMOVDW, C_FREG, C_REG, 17,0, 4, OOP_FP, 0x0, 0x61, + /* int->float */ AMOVWF, C_REG, C_FREG, 17,0, 4, OOP_FP, 0x0, 0x68, + /* uint->float */ AMOVUF, C_REG, C_FREG, 17,0, 4, OOP_FP, 0x1, 0x68, + /* int->dbl */ AMOVWD, C_REG, C_FREG, 17,0, 4, OOP_FP, 0x0, 0x69, + /* uint->dbl */ AMOVUD, C_REG, C_FREG, 17,0, 4, OOP_FP, 0x1, 0x69, + /* float->vlong*/ AMOVFV, C_FREG, C_REG, 17,0, 4, OOP_FP, 0x2, 0x60, + /* dbl->vlong */ AMOVDV, C_FREG, C_REG, 17,0, 4, OOP_FP, 0x2, 0x61, + /* vlong->float*/ AMOVVF, C_REG, C_FREG, 17,0, 4, OOP_FP, 0x2, 0x68, + /* uvlong->float*/ AMOVUVF, C_REG, C_FREG, 17,0, 4, OOP_FP, 0x3, 0x68, + /* vlong->dbl */ AMOVVD, C_REG, C_FREG, 17,0, 4, OOP_FP, 0x2, 0x69, + /* uvlong->dbl */ AMOVUVD, C_REG, C_FREG, 17,0, 4, OOP_FP, 0x3, 0x69, + + /* - */ AWORD, C_NONE, C_LCON, 25,0, 4, 0, 0, 0, + /* - */ ATEXT, C_LEXT, C_LCON, 26,0, 0, 0, 0, 0, + /* - */ AXXX, C_NONE, C_NONE, 0,0, 0, 0, 0, 0, +}; diff --git a/utils/il/pass.c b/utils/il/pass.c new file mode 100644 index 00000000..8d3b435b --- /dev/null +++ b/utils/il/pass.c @@ -0,0 +1,589 @@ +#include "l.h" + +void +dodata(void) +{ + int i, t; + Sym *s; + Prog *p, *p1; + long orig, orig1, v; + int odd; + long long vv; + + if(debug['v']) + Bprint(&bso, "%5.2f dodata\n", cputime()); + Bflush(&bso); + for(p = datap; p != P; p = p->link) { + s = p->from.sym; + if(p->as == ADYNT || p->as == AINIT) + s->value = dtype; + if(s->type == SBSS) + s->type = SDATA; + if(s->type != SDATA) + diag("initialize non-data (%d): %s\n%P", + s->type, s->name, p); + v = p->from.offset + p->reg; + if(v > s->value) + diag("initialize bounds (%ld): %s\n%P", + s->value, s->name, p); + } + + if(debug['t']) { + /* + * pull out string constants + */ + for(p = datap; p != P; p = p->link) { + s = p->from.sym; + if(p->to.type == D_SCONST) + s->type = SSTRING; + } + } + + /* + * pass 1 + * assign 'small' variables to data segment + * (rational is that data segment is more easily + * addressed through offset on SB) + */ + odd = 4; + orig = 0; + for(i=0; ilink) { + t = s->type; + if(t != SDATA && t != SBSS) + continue; + v = s->value; + if(v == 0) { + diag("%s: no size", s->name); + v = 1; + } + while(v & 3) + v++; + s->value = v; + if(v > MINSIZ) + continue; + if(v >= 8 && (orig & odd) != 0) + orig += odd; + s->value = orig; + orig += v; + s->type = SDATA1; + } + orig1 = orig; + + /* + * pass 2 + * assign 'data' variables to data segment + */ + for(i=0; ilink) { + t = s->type; + if(t != SDATA) { + if(t == SDATA1) + s->type = SDATA; + continue; + } + v = s->value; + if((orig & odd) != 0) + orig += odd; + s->value = orig; + orig += v; + s->type = SDATA1; + } + + while(orig & 7) + orig++; + datsize = orig; + + /* + * pass 3 + * everything else to bss segment + */ + for(i=0; ilink) { + if(s->type != SBSS) + continue; + v = s->value; + if((orig & odd) != 0) + orig += odd; + s->value = orig; + orig += v; + } + while(orig & 7) + orig++; + bsssize = orig-datsize; + + /* + * pass 4 + * add literals to all large values. + * at this time: + * small data is allocated DATA + * large data is allocated DATA1 + * large bss is allocated BSS + * the new literals are loaded between + * small data and large data. + */ + orig = 0; + for(p = firstp; p != P; p = p->link) { + if(p->as != AMOV && p->as != AMOVW) + continue; + if(p->from.type != D_CONST && p->from.type != D_VCONST) + continue; + if(s = p->from.sym) { + if(!debug['r']) + continue; + t = s->type; + if(t != SDATA && t != SDATA1 && t != SBSS) + continue; + t = p->from.name; + if(t != D_EXTERN && t != D_STATIC) + continue; + v = s->value + p->from.offset; + if(v >= 0 && v <= 2*BIG) + continue; + if(!strcmp(s->name, "setSB")) + continue; + /* size should be 19 max */ + if(strlen(s->name) >= 10) /* has loader address */ + sprint(literal, "$%p.%lux", s, p->from.offset); + else + sprint(literal, "$%s.%d.%lux", s->name, s->version, p->from.offset); + } else { + if(p->from.type == D_VCONST){ + vv = *p->from.vval; + if( 0 && (v = vconshift(vv)) >= 0 && !debug['r']){ + if(v < 12) + vv <<= 12 - v; + else + vv >>= v - 12; + p->from.type = D_CONST; + p->from.offset = (long)vv & ~0xFFF; + p1 = prg(); + p1->line = p->line; + p1->to = p->to; + p1->from.type = D_CONST; + if(v < 12) { + p1->as = ASRA; + p1->from.offset = 12 - v; + } else { + p1->as = ASLL; + p1->from.offset = v - 12; + } + p1->link = p->link; + p->link = p1; + continue; + } + sprint(literal, "$%llux", vv); + } else { + if(!debug['r']) + continue; + if(p->from.name != D_NONE) + continue; + if(p->from.reg != NREG) + continue; + v = p->from.offset; + if(v >= -BIG && v < BIG) + continue; + if((v & (BIG-1)) == 0) + continue; + /* size should be 9 max */ + sprint(literal, "$%lux", v); + } + } + s = lookup(literal, 0); + if(s->type == 0) { + s->type = SDATA; + if(p->from.type == D_VCONST && (orig & odd) != 0) + orig += odd; + s->value = orig1+orig; + p1 = prg(); + p1->line = p->line; + p1->as = ADATA; + p1->from.type = D_OREG; + p1->from.sym = s; + p1->from.name = D_EXTERN; + p1->reg = p->from.type == D_VCONST ? 8 : 4; + p1->to = p->from; + p1->link = datap; + orig += p1->reg; + datap = p1; + } + if(s->type != SDATA) + diag("literal not data: %s", s->name); + if(thechar == 'i' && p->as == AMOV) + p->as = AMOVW; + p->from.type = D_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + p->from.offset = 0; + continue; + } + while(orig & 7) + orig++; + + /* + * pass 5 + * re-adjust offsets + */ + for(i=0; ilink) { + t = s->type; + if(t == SBSS) { + s->value += orig; + continue; + } + if(t == SDATA1) { + s->type = SDATA; + s->value += orig; + continue; + } + } + datsize += orig; + xdefine("setSB", SDATA, 0L+BIG); + xdefine("bdata", SDATA, 0L); + xdefine("edata", SDATA, datsize); + xdefine("end", SBSS, datsize+bsssize); + xdefine("etext", STEXT, 0L); +} + +void +undef(void) +{ + int i; + Sym *s; + + for(i=0; ilink) + if(s->type == SXREF) + diag("%s: not defined", s->name); +} + +int +relinv(int a) +{ + + switch(a) { + case ABEQ: return ABNE; + case ABNE: return ABEQ; + + case ABLT: return ABGE; + case ABGE: return ABLT; + + case ABLTU: return ABGEU; + case ABGEU: return ABLTU; + } + return 0; +} + +int +relrev(int a) +{ + switch (a) { + case ABGT: return ABLT; + case ABGTU: return ABLTU; + case ABLE: return ABGE; + case ABLEU: return ABGEU; + } + return 0; +} + +void +follow(void) +{ + if(debug['v']) + Bprint(&bso, "%5.2f follow\n", cputime()); + Bflush(&bso); + + firstp = prg(); + lastp = firstp; + xfol(textp); + + firstp = firstp->link; + lastp->link = P; +} + +void +xfol(Prog *p) +{ + Prog *q, *r; + int a, b, i; + +loop: + if(p == P) + return; + a = p->as; + if(a == ATEXT) + curtext = p; + if(a == AJMP) { + q = p->cond; + if(q != P) { + p->mark |= FOLL; + p = q; + if(!(p->mark & FOLL)) + goto loop; + } + } + if(p->mark & FOLL) { + for(i=0,q=p; i<4; i++,q=q->link) { + if(q == lastp) + break; + b = 0; /* set */ + a = q->as; + if(a == ANOP) { + i--; + continue; + } + if(a == AJMP || a == ARET) + goto copy; + if(!q->cond || (q->cond->mark&FOLL)) + continue; + b = relinv(a); + if(!b) + continue; + copy: + for(;;) { + r = prg(); + *r = *p; + if(!(r->mark&FOLL)) + print("cant happen 1\n"); + r->mark |= FOLL; + if(p != q) { + p = p->link; + lastp->link = r; + lastp = r; + continue; + } + lastp->link = r; + lastp = r; + if(a == AJMP || a == ARET) + return; + r->as = b; + r->cond = p->link; + r->link = p->cond; + if(!(r->link->mark&FOLL)) + xfol(r->link); + if(!(r->cond->mark&FOLL)) + print("cant happen 2\n"); + return; + } + } + a = AJMP; + q = prg(); + q->as = a; + q->line = p->line; + q->to.type = D_BRANCH; + q->to.offset = p->pc; + q->cond = p; + p = q; + } + p->mark |= FOLL; + lastp->link = p; + lastp = p; + if(a == AJMP || a == ARET){ + return; + } + if(p->cond != P) + if(a != AJAL && p->link != P) { + xfol(p->link); + p = p->cond; + if(p == P || (p->mark&FOLL)) + return; + goto loop; + } + p = p->link; + goto loop; +} + +void +patch(void) +{ + long c, vexit; + Prog *p, *q; + Sym *s; + int a; + + if(debug['v']) + Bprint(&bso, "%5.2f patch\n", cputime()); + Bflush(&bso); + mkfwd(); + s = lookup("exit", 0); + vexit = s->value; + for(p = firstp; p != P; p = p->link) { + a = p->as; + if(a == ATEXT) + curtext = p; + if((a == AJAL || a == AJMP || a == ARET) && + p->to.type != D_BRANCH && p->to.sym != S) { + s = p->to.sym; + if(s->type != STEXT) { + diag("undefined: %s\n%P", s->name, p); + s->type = STEXT; + s->value = vexit; + } + p->to.offset = s->value; + p->to.type = D_BRANCH; + } + if(p->to.type != D_BRANCH) + continue; + c = p->to.offset; + for(q = firstp; q != P;) { + if(q->forwd != P) + if(c >= q->forwd->pc) { + q = q->forwd; + continue; + } + if(c == q->pc) + break; + q = q->link; + } + if(q == P) { + diag("branch out of range %ld => %ld\n%P", p->pc, c, p); + p->to.type = D_NONE; + } + p->cond = q; + } + + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + if(p->cond != P) { + p->cond = brloop(p->cond); + if(p->cond != P) + if(p->to.type == D_BRANCH) + p->to.offset = p->cond->pc; + } + } +} + +#define LOG 5 +void +mkfwd(void) +{ + Prog *p; + long dwn[LOG], cnt[LOG], i; + Prog *lst[LOG]; + + for(i=0; ilink) { + if(p->as == ATEXT) + curtext = p; + i--; + if(i < 0) + i = LOG-1; + p->forwd = P; + dwn[i]--; + if(dwn[i] <= 0) { + dwn[i] = cnt[i]; + if(lst[i] != P) + lst[i]->forwd = p; + lst[i] = p; + } + } +} + +Prog* +brloop(Prog *p) +{ + Prog *q; + int c; + + for(c=0; p!=P;) { + if(p->as != AJMP) + return p; + q = p->cond; + if(q <= p) { + c++; + if(q == p || c > 5000) + break; + } + p = q; + } + return P; +} + +xlong +atolwhex(char *s) +{ + xlong n; + int f; + + n = 0; + f = 0; + while(*s == ' ' || *s == '\t') + s++; + if(*s == '-' || *s == '+') { + if(*s++ == '-') + f = 1; + while(*s == ' ' || *s == '\t') + s++; + } + if(s[0]=='0' && s[1]){ + if(s[1]=='x' || s[1]=='X'){ + s += 2; + for(;;){ + if(*s >= '0' && *s <= '9') + n = n*16 + *s++ - '0'; + else if(*s >= 'a' && *s <= 'f') + n = n*16 + *s++ - 'a' + 10; + else if(*s >= 'A' && *s <= 'F') + n = n*16 + *s++ - 'A' + 10; + else + break; + } + } else + while(*s >= '0' && *s <= '7') + n = n*8 + *s++ - '0'; + } else + while(*s >= '0' && *s <= '9') + n = n*10 + *s++ - '0'; + if(f) + n = -n; + return n; +} + +vlong +rnd(vlong v, vlong r) +{ + vlong c; + + if(r <= 0) + return v; + v += r - 1; + c = v % r; + if(c < 0) + c += r; + v -= c; + return v; +} + +int +vconshift(vlong constant) +{ + vlong orig; + long w; + int shift; + + orig = constant; + if(constant == 0) + return -1; + shift = 12; + while((constant & 0xFFF) != 0){ + shift--; + constant <<= 1; + } + while((constant & 0x1000) == 0){ + shift++; + constant >>= 1; + } + w = (long)constant; + constant = shift > 12? (vlong)w << shift - 12 : (vlong)w >> 12 - shift; + if(constant != orig) + return -1; + return shift; +} diff --git a/utils/il/span.c b/utils/il/span.c new file mode 100644 index 00000000..f54dfdc7 --- /dev/null +++ b/utils/il/span.c @@ -0,0 +1,525 @@ +#include "l.h" + +void +span(void) +{ + Prog *p, *q; + Sym *setext, *s; + Optab *o; + int m, bflag, i, spass; + long c, otxt, v; + + if(debug['v']) + Bprint(&bso, "%5.2f span\n", cputime()); + Bflush(&bso); + + bflag = 0; + c = 0; + otxt = c; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + c = (c + 3) & ~3; + p->pc = c; + o = oplook(p); + m = o->size; + if(!debug['c']){ + if(o->ctype && asmout(p, o, 2) == 2){ + bflag = 1; + p->mark |= COMPR; + m = 2; + } + } + if(m == 0) { + if(p->as == ATEXT) { + curtext = p; + autosize = p->to.offset + ptrsize; + if(p->from.sym != S) + p->from.sym->value = c; + /* need passes to resolve branches */ + if(c-otxt >= 0x1000) + bflag = 1; + otxt = c; + continue; + } + diag("zero-width instruction\n%P", p); + continue; + } + c += m; + } + + /* + * Multi-pass expansion of span dependent instructions + * Bcond JAL C.Bcond C.JAL C.JMP + */ + spass = 0; + while(bflag) { + if(debug['v']) + Bprint(&bso, "%5.2f span1\n", cputime()); + bflag = 0; + spass ^= SPASS; + c = 0; + for(p = firstp; p != P; p = p->link) { + o = oplook(p); + m = o->size; + if(p->mark&COMPR) + m = 2; + if((o->type == 3 || o->type == 4) && p->cond) { + if((p->cond->mark&SPASS) == spass) + p->pc = c; + if(m == 2){ + /* + * If instruction was compressed, check again in case + * branch range is now too large. + */ + m = asmout(p, o, 3); + if(m != 2){ + p->mark &= ~COMPR; + bflag = 1; + } + } + otxt = p->cond->pc - p->pc; + if(otxt < 0) + otxt = -otxt; + if(o->type == 3){ + /* + * If Bcond branch range exceeds 4K, replace it by the + * logically negated branch around a JMP. + */ + if(otxt >= 0x1000) { + q = prg(); + q->link = p->link; + q->line = p->line; + q->as = AJMP; + q->to.type = D_BRANCH; + q->cond = p->cond; + p->link = q; + p->as = relinv(p->as); + p->cond = q->link; + p->optab = 0; + o = oplook(p); + q->mark = spass ^ SPASS; + m = asmout(p, o, 2); + if(m == 2) + p->mark |= COMPR; + q->pc = p->pc + m; + bflag = 1; + } + }else{ + /* + * If JAL branch range exceeds 1M, change address class + * and recalculate instruction length. + */ + if(otxt >= 0x100000) { + p->to.class = C_LBRA + 1; + p->optab = 0; + o = oplook(p); + m = asmout(p, o, 3); + p->mark &= ~COMPR; + } + } + } + if(p->as == ATEXT) + c = (c + 3) & ~3; + p->pc = c; + p->mark ^= SPASS; + if(m == 0) { + if(p->as == ATEXT) { + curtext = p; + autosize = p->to.offset + ptrsize; + if(p->from.sym != S) + p->from.sym->value = c; + continue; + } + diag("zero-width instruction\n%P", p); + continue; + } + c += m; + } + } + + if(debug['t']) { + /* + * add strings to text segment + */ + c = rnd(c, 8); + for(i=0; ilink) { + if(s->type != SSTRING) + continue; + v = s->value; + while(v & 3) + v++; + s->value = c; + c += v; + } + } + + c = rnd(c, 8); + + setext = lookup("etext", 0); + if(setext != S) { + setext->value = c; + textsize = c; + } + if(INITRND) + INITDAT = rnd(INITTEXT + c, INITRND); + if(debug['v']) + Bprint(&bso, "tsize = %lux\n", textsize); + Bflush(&bso); +} + +void +xdefine(char *p, int t, long v) +{ + Sym *s; + + s = lookup(p, 0); + if(s->type == 0 || s->type == SXREF) { + s->type = t; + s->value = v; + } +} + +long +regoff(Adr *a) +{ + + instoffset = 0; + a->class = aclass(a) + 1; + return instoffset; +} + +int +classreg(Adr *a) +{ + if(a->reg == NREG) { + switch(a->class - 1) { + case C_SEXT: + case C_SECON: + case C_LECON: + return REGSB; + case C_SAUTO: + case C_LAUTO: + case C_SACON: + case C_LACON: + return REGSP; + } + } + return a->reg; +} + +int +aclass(Adr *a) +{ + Sym *s; + int t; + + switch(a->type) { + case D_NONE: + return C_NONE; + + case D_REG: + return C_REG; + + case D_CTLREG: + return C_CTLREG; + + case D_FREG: + return C_FREG; + + case D_OREG: + switch(a->name) { + case D_EXTERN: + case D_STATIC: + if(a->sym == 0 || a->sym->name == 0) { + print("null sym external\n"); + print("%D\n", a); + return C_GOK; + } + t = a->sym->type; + if(t == 0 || t == SXREF) { + diag("undefined external: %s in %s", + a->sym->name, TNAME); + a->sym->type = SDATA; + } + instoffset = a->sym->value + a->offset - BIG; + if(instoffset >= -BIG && instoffset < BIG) + return C_SEXT; + return C_LEXT; + case D_AUTO: + instoffset = autosize + a->offset; + if(instoffset >= -BIG && instoffset < BIG) + return C_SAUTO; + return C_LAUTO; + + case D_PARAM: + instoffset = autosize + a->offset + ptrsize; + if(instoffset >= -BIG && instoffset < BIG) + return C_SAUTO; + return C_LAUTO; + case D_NONE: + instoffset = a->offset; + if(instoffset == 0) + return C_ZOREG; + if(instoffset >= -BIG && instoffset < BIG) + return C_SOREG; + return C_LOREG; + } + return C_GOK; + + case D_FCONST: + return C_FCON; + + case D_VCONST: + return C_VCON; + + case D_CONST: + switch(a->name) { + + case D_NONE: + instoffset = a->offset; + if(a->reg != NREG && a->reg != REGZERO){ + if(instoffset >= -BIG && instoffset < BIG) + return C_SRCON; + return C_LRCON; + } + consize: + if(instoffset == 0) + return C_ZCON; + if(instoffset >= -0x800 && instoffset <= 0x7ff) + return C_SCON; + if((instoffset & 0xfff) == 0) + return C_UCON; + return C_LCON; + + case D_EXTERN: + case D_STATIC: + instoffx = 0; + s = a->sym; + if(s == S) + break; + t = s->type; + switch(t) { + case 0: + case SXREF: + diag("undefined external: %s in %s", + s->name, TNAME); + s->type = SDATA; + break; + case SCONST: + instoffset = s->value + a->offset; + goto consize; + case STEXT: + case SLEAF: + case SSTRING: + instoffset = s->value + a->offset; + instoffx = INITTEXT; + return C_LECON; + } + instoffset = s->value + a->offset - BIG; + if(instoffset >= -BIG && instoffset < BIG && instoffset != 0L) + return C_SECON; + instoffset = s->value + a->offset; + instoffx = INITDAT; + return C_LECON; + + case D_AUTO: + instoffset = autosize + a->offset; + if(instoffset >= -BIG && instoffset < BIG) + return C_SACON; + return C_LACON; + + case D_PARAM: + instoffset = autosize + a->offset + ptrsize; + if(instoffset >= -BIG && instoffset < BIG) + return C_SACON; + return C_LACON; + } + return C_GOK; + + case D_BRANCH: + return C_SBRA; + } + return C_GOK; +} + +Optab* +oplook(Prog *p) +{ + int a1, a2, a3, r; + char *c1, *c3; + Optab *o, *e; + + a1 = p->optab; + if(a1) + return optab+(a1-1); + a1 = p->from.class; + if(a1 == 0) { + a1 = aclass(&p->from) + 1; + p->from.class = a1; + } + a1--; + a3 = p->to.class; + if(a3 == 0) { + a3 = aclass(&p->to) + 1; + p->to.class = a3; + } + a3--; + a2 = C_NONE; + if(p->reg != NREG) + a2 = C_REG; + r = p->as; + o = oprange[r].start; + if(o == 0) { + a1 = opcross[repop[r]][a1][a3]; + if(a1) { + p->optab = a1+1; + return optab+a1; + } + o = oprange[r].stop; /* just generate an error */ + a1 = p->from.class - 1; + } + e = oprange[r].stop; + + c1 = xcmp[a1]; + c3 = xcmp[a3]; + for(; oa1]) + if(c3[o->a3]) { + p->optab = (o-optab)+1; + return o; + } + diag("illegal combination %A %d %d %d", + p->as, a1, a2, a3); + if(!debug['a']) + prasm(p); + o = optab; + p->optab = (o-optab)+1; + return o; +} + +int +cmp(int a, int b) +{ + + if(a == b) + return 1; + switch(a) { + case C_LCON: + if(b == C_ZCON || b == C_SCON || b == C_UCON) + return 1; + break; + case C_UCON: + if(b == C_ZCON) + return 1; + break; + case C_SCON: + if(b == C_ZCON) + return 1; + break; + case C_LACON: + if(b == C_SACON) + return 1; + break; + case C_LRCON: + if(b == C_SRCON) + return 1; + break; + case C_LBRA: + if(b == C_SBRA) + return 1; + break; + case C_LEXT: + if(b == C_SEXT) + return 1; + break; + case C_LAUTO: + if(b == C_SAUTO) + return 1; + break; + case C_ZREG: + if(b == C_REG || b == C_ZCON) + return 1; + break; + case C_LOREG: + if(b == C_ZOREG || b == C_SOREG || b == C_SAUTO || b == C_LAUTO) + return 1; + break; + case C_SOREG: + if(b == C_ZOREG || b == C_SAUTO || b == C_SEXT) + return 1; + break; + } + return 0; +} + +int +ocmp(void *a1, void *a2) +{ + Optab *p1, *p2; + int n; + + p1 = (Optab*)a1; + p2 = (Optab*)a2; + n = p1->as - p2->as; + if(n) + return n; + n = p1->a1 - p2->a1; + if(n) + return n; + n = p1->a3 - p2->a3; + if(n) + return n; + return 0; +} + +void +buildop(void) +{ + int i, n, r; + + for(i=0; i<32; i++) + for(n=0; n<32; n++) + xcmp[i][n] = cmp(n, i); + for(n=0; optab[n].as != AXXX; n++) + ; + qsort(optab, n, sizeof(optab[0]), ocmp); + for(i=0; i= 32 || x >= nelem(opcross)) { + diag("assumptions fail in buildrep"); + errorexit(); + } + repop[as] = x; + p = (opcross + x); + s = oprange[as].start; + e = oprange[as].stop; + for(o=e-1; o>=s; o--) { + n = o-optab; + for(a1=0; a1<32; a1++) { + if(!xcmp[a1][o->a1]) + continue; + for(a3=0; a3<32; a3++) + if(xcmp[a3][o->a3]) + (*p)[a1][a3] = n; + } + } + oprange[as].start = 0; +} diff --git a/utils/mkfile b/utils/mkfile index 9b8b3126..804215b3 100644 --- a/utils/mkfile +++ b/utils/mkfile @@ -45,6 +45,9 @@ NOTPLAN9=\ ka\ kc\ kl\ + ia\ + ic\ + il\ mk\ ksize\ kstrip\ -- cgit v1.2.3