summaryrefslogtreecommitdiff
path: root/sys/src/cmd/6c
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@gmx.de>2012-07-30 19:11:16 +0200
committercinap_lenrek <cinap_lenrek@gmx.de>2012-07-30 19:11:16 +0200
commit4f33c88a51587681b7be1ae57cfbc43b627c6bc4 (patch)
tree25560404dc80007e5dc268811242c9071f6a1017 /sys/src/cmd/6c
parentfcc5e75d07e5bc6cb3ddac6d9a437e7ec62d0d95 (diff)
import updated compilers from sources
Diffstat (limited to 'sys/src/cmd/6c')
-rw-r--r--sys/src/cmd/6c/6.out.h820
-rw-r--r--sys/src/cmd/6c/cgen.c1942
-rw-r--r--sys/src/cmd/6c/div.c206
-rw-r--r--sys/src/cmd/6c/enam.c669
-rw-r--r--sys/src/cmd/6c/gc.h381
-rw-r--r--sys/src/cmd/6c/list.c337
-rw-r--r--sys/src/cmd/6c/machcap.c78
-rw-r--r--sys/src/cmd/6c/mkenam15
-rw-r--r--sys/src/cmd/6c/mkfile38
-rw-r--r--sys/src/cmd/6c/mul.c428
-rw-r--r--sys/src/cmd/6c/peep.c846
-rw-r--r--sys/src/cmd/6c/reg.c1356
-rw-r--r--sys/src/cmd/6c/sgen.c435
-rw-r--r--sys/src/cmd/6c/swt.c530
-rw-r--r--sys/src/cmd/6c/sys.c106
-rw-r--r--sys/src/cmd/6c/txt.c1515
-rw-r--r--sys/src/cmd/6c/vlrt.c746
17 files changed, 10448 insertions, 0 deletions
diff --git a/sys/src/cmd/6c/6.out.h b/sys/src/cmd/6c/6.out.h
new file mode 100644
index 000000000..0766ea3d2
--- /dev/null
+++ b/sys/src/cmd/6c/6.out.h
@@ -0,0 +1,820 @@
+#define NSYM 50
+#define NSNAME 8
+#define NOPROF (1<<0)
+#define DUPOK (1<<1)
+
+/*
+ * amd64
+ */
+
+enum as
+{
+ AXXX,
+ AAAA,
+ AAAD,
+ AAAM,
+ AAAS,
+ AADCB,
+ AADCL,
+ AADCW,
+ AADDB,
+ AADDL,
+ AADDW,
+ AADJSP,
+ AANDB,
+ AANDL,
+ AANDW,
+ AARPL,
+ ABOUNDL,
+ ABOUNDW,
+ ABSFL,
+ ABSFW,
+ ABSRL,
+ ABSRW,
+ ABTL,
+ ABTW,
+ ABTCL,
+ ABTCW,
+ ABTRL,
+ ABTRW,
+ ABTSL,
+ ABTSW,
+ ABYTE,
+ ACALL,
+ ACLC,
+ ACLD,
+ ACLI,
+ ACLTS,
+ ACMC,
+ ACMPB,
+ ACMPL,
+ ACMPW,
+ ACMPSB,
+ ACMPSL,
+ ACMPSW,
+ ADAA,
+ ADAS,
+ ADATA,
+ ADECB,
+ ADECL,
+ ADECQ,
+ ADECW,
+ ADIVB,
+ ADIVL,
+ ADIVW,
+ AENTER,
+ AGLOBL,
+ AGOK,
+ AHISTORY,
+ AHLT,
+ AIDIVB,
+ AIDIVL,
+ AIDIVW,
+ AIMULB,
+ AIMULL,
+ AIMULW,
+ AINB,
+ AINL,
+ AINW,
+ AINCB,
+ AINCL,
+ AINCQ,
+ AINCW,
+ AINSB,
+ AINSL,
+ AINSW,
+ AINT,
+ AINTO,
+ AIRETL,
+ AIRETW,
+ AJCC,
+ AJCS,
+ AJCXZ,
+ AJEQ,
+ AJGE,
+ AJGT,
+ AJHI,
+ AJLE,
+ AJLS,
+ AJLT,
+ AJMI,
+ AJMP,
+ AJNE,
+ AJOC,
+ AJOS,
+ AJPC,
+ AJPL,
+ AJPS,
+ ALAHF,
+ ALARL,
+ ALARW,
+ ALEAL,
+ ALEAW,
+ ALEAVEL,
+ ALEAVEW,
+ ALOCK,
+ ALODSB,
+ ALODSL,
+ ALODSW,
+ ALONG,
+ ALOOP,
+ ALOOPEQ,
+ ALOOPNE,
+ ALSLL,
+ ALSLW,
+ AMOVB,
+ AMOVL,
+ AMOVW,
+ AMOVBLSX,
+ AMOVBLZX,
+ AMOVBQSX,
+ AMOVBQZX,
+ AMOVBWSX,
+ AMOVBWZX,
+ AMOVWLSX,
+ AMOVWLZX,
+ AMOVWQSX,
+ AMOVWQZX,
+ AMOVSB,
+ AMOVSL,
+ AMOVSW,
+ AMULB,
+ AMULL,
+ AMULW,
+ ANAME,
+ ANEGB,
+ ANEGL,
+ ANEGW,
+ ANOP,
+ ANOTB,
+ ANOTL,
+ ANOTW,
+ AORB,
+ AORL,
+ AORW,
+ AOUTB,
+ AOUTL,
+ AOUTW,
+ AOUTSB,
+ AOUTSL,
+ AOUTSW,
+ APOPAL,
+ APOPAW,
+ APOPFL,
+ APOPFW,
+ APOPL,
+ APOPW,
+ APUSHAL,
+ APUSHAW,
+ APUSHFL,
+ APUSHFW,
+ APUSHL,
+ APUSHW,
+ ARCLB,
+ ARCLL,
+ ARCLW,
+ ARCRB,
+ ARCRL,
+ ARCRW,
+ AREP,
+ AREPN,
+ ARET,
+ AROLB,
+ AROLL,
+ AROLW,
+ ARORB,
+ ARORL,
+ ARORW,
+ ASAHF,
+ ASALB,
+ ASALL,
+ ASALW,
+ ASARB,
+ ASARL,
+ ASARW,
+ ASBBB,
+ ASBBL,
+ ASBBW,
+ ASCASB,
+ ASCASL,
+ ASCASW,
+ ASETCC,
+ ASETCS,
+ ASETEQ,
+ ASETGE,
+ ASETGT,
+ ASETHI,
+ ASETLE,
+ ASETLS,
+ ASETLT,
+ ASETMI,
+ ASETNE,
+ ASETOC,
+ ASETOS,
+ ASETPC,
+ ASETPL,
+ ASETPS,
+ ACDQ,
+ ACWD,
+ ASHLB,
+ ASHLL,
+ ASHLW,
+ ASHRB,
+ ASHRL,
+ ASHRW,
+ ASTC,
+ ASTD,
+ ASTI,
+ ASTOSB,
+ ASTOSL,
+ ASTOSW,
+ ASUBB,
+ ASUBL,
+ ASUBW,
+ ASYSCALL,
+ ATESTB,
+ ATESTL,
+ ATESTW,
+ ATEXT,
+ AVERR,
+ AVERW,
+ AWAIT,
+ AWORD,
+ AXCHGB,
+ AXCHGL,
+ AXCHGW,
+ AXLAT,
+ AXORB,
+ AXORL,
+ AXORW,
+
+ AFMOVB,
+ AFMOVBP,
+ AFMOVD,
+ AFMOVDP,
+ AFMOVF,
+ AFMOVFP,
+ AFMOVL,
+ AFMOVLP,
+ AFMOVV,
+ AFMOVVP,
+ AFMOVW,
+ AFMOVWP,
+ AFMOVX,
+ AFMOVXP,
+
+ AFCOMB,
+ AFCOMBP,
+ AFCOMD,
+ AFCOMDP,
+ AFCOMDPP,
+ AFCOMF,
+ AFCOMFP,
+ AFCOML,
+ AFCOMLP,
+ AFCOMW,
+ AFCOMWP,
+ AFUCOM,
+ AFUCOMP,
+ AFUCOMPP,
+
+ AFADDDP,
+ AFADDW,
+ AFADDL,
+ AFADDF,
+ AFADDD,
+
+ AFMULDP,
+ AFMULW,
+ AFMULL,
+ AFMULF,
+ AFMULD,
+
+ AFSUBDP,
+ AFSUBW,
+ AFSUBL,
+ AFSUBF,
+ AFSUBD,
+
+ AFSUBRDP,
+ AFSUBRW,
+ AFSUBRL,
+ AFSUBRF,
+ AFSUBRD,
+
+ AFDIVDP,
+ AFDIVW,
+ AFDIVL,
+ AFDIVF,
+ AFDIVD,
+
+ AFDIVRDP,
+ AFDIVRW,
+ AFDIVRL,
+ AFDIVRF,
+ AFDIVRD,
+
+ AFXCHD,
+ AFFREE,
+
+ AFLDCW,
+ AFLDENV,
+ AFRSTOR,
+ AFSAVE,
+ AFSTCW,
+ AFSTENV,
+ AFSTSW,
+
+ AF2XM1,
+ AFABS,
+ AFCHS,
+ AFCLEX,
+ AFCOS,
+ AFDECSTP,
+ AFINCSTP,
+ AFINIT,
+ AFLD1,
+ AFLDL2E,
+ AFLDL2T,
+ AFLDLG2,
+ AFLDLN2,
+ AFLDPI,
+ AFLDZ,
+ AFNOP,
+ AFPATAN,
+ AFPREM,
+ AFPREM1,
+ AFPTAN,
+ AFRNDINT,
+ AFSCALE,
+ AFSIN,
+ AFSINCOS,
+ AFSQRT,
+ AFTST,
+ AFXAM,
+ AFXTRACT,
+ AFYL2X,
+ AFYL2XP1,
+
+ AEND,
+
+ ADYNT,
+ AINIT,
+
+ ASIGNAME,
+
+ /* extra 32-bit operations */
+ ACMPXCHGB,
+ ACMPXCHGL,
+ ACMPXCHGW,
+ ACMPXCHG8B,
+ ACPUID,
+ AINVD,
+ AINVLPG,
+ ALFENCE,
+ AMFENCE,
+ AMOVNTIL,
+ ARDMSR,
+ ARDPMC,
+ ARDTSC,
+ ARSM,
+ ASFENCE,
+ ASYSRET,
+ AWBINVD,
+ AWRMSR,
+ AXADDB,
+ AXADDL,
+ AXADDW,
+
+ /* conditional move */
+ ACMOVLCC,
+ ACMOVLCS,
+ ACMOVLEQ,
+ ACMOVLGE,
+ ACMOVLGT,
+ ACMOVLHI,
+ ACMOVLLE,
+ ACMOVLLS,
+ ACMOVLLT,
+ ACMOVLMI,
+ ACMOVLNE,
+ ACMOVLOC,
+ ACMOVLOS,
+ ACMOVLPC,
+ ACMOVLPL,
+ ACMOVLPS,
+ ACMOVQCC,
+ ACMOVQCS,
+ ACMOVQEQ,
+ ACMOVQGE,
+ ACMOVQGT,
+ ACMOVQHI,
+ ACMOVQLE,
+ ACMOVQLS,
+ ACMOVQLT,
+ ACMOVQMI,
+ ACMOVQNE,
+ ACMOVQOC,
+ ACMOVQOS,
+ ACMOVQPC,
+ ACMOVQPL,
+ ACMOVQPS,
+ ACMOVWCC,
+ ACMOVWCS,
+ ACMOVWEQ,
+ ACMOVWGE,
+ ACMOVWGT,
+ ACMOVWHI,
+ ACMOVWLE,
+ ACMOVWLS,
+ ACMOVWLT,
+ ACMOVWMI,
+ ACMOVWNE,
+ ACMOVWOC,
+ ACMOVWOS,
+ ACMOVWPC,
+ ACMOVWPL,
+ ACMOVWPS,
+
+ /* 64-bit */
+ AADCQ,
+ AADDQ,
+ AANDQ,
+ ABSFQ,
+ ABSRQ,
+ ABTCQ,
+ ABTQ,
+ ABTRQ,
+ ABTSQ,
+ ACMPQ,
+ ACMPSQ,
+ ACMPXCHGQ,
+ ACQO,
+ ADIVQ,
+ AIDIVQ,
+ AIMULQ,
+ AIRETQ,
+ ALEAQ,
+ ALEAVEQ,
+ ALODSQ,
+ AMOVQ,
+ AMOVLQSX,
+ AMOVLQZX,
+ AMOVNTIQ,
+ AMOVSQ,
+ AMULQ,
+ ANEGQ,
+ ANOTQ,
+ AORQ,
+ APOPFQ,
+ APOPQ,
+ APUSHFQ,
+ APUSHQ,
+ ARCLQ,
+ ARCRQ,
+ AROLQ,
+ ARORQ,
+ AQUAD,
+ ASALQ,
+ ASARQ,
+ ASBBQ,
+ ASCASQ,
+ ASHLQ,
+ ASHRQ,
+ ASTOSQ,
+ ASUBQ,
+ ATESTQ,
+ AXADDQ,
+ AXCHGQ,
+ AXORQ,
+
+ /* media */
+ AADDPD,
+ AADDPS,
+ AADDSD,
+ AADDSS,
+ AANDNPD,
+ AANDNPS,
+ AANDPD,
+ AANDPS,
+ ACMPPD,
+ ACMPPS,
+ ACMPSD,
+ ACMPSS,
+ ACOMISD,
+ ACOMISS,
+ ACVTPD2PL,
+ ACVTPD2PS,
+ ACVTPL2PD,
+ ACVTPL2PS,
+ ACVTPS2PD,
+ ACVTPS2PL,
+ ACVTSD2SL,
+ ACVTSD2SQ,
+ ACVTSD2SS,
+ ACVTSL2SD,
+ ACVTSL2SS,
+ ACVTSQ2SD,
+ ACVTSQ2SS,
+ ACVTSS2SD,
+ ACVTSS2SL,
+ ACVTSS2SQ,
+ ACVTTPD2PL,
+ ACVTTPS2PL,
+ ACVTTSD2SL,
+ ACVTTSD2SQ,
+ ACVTTSS2SL,
+ ACVTTSS2SQ,
+ ADIVPD,
+ ADIVPS,
+ ADIVSD,
+ ADIVSS,
+ AEMMS,
+ AFXRSTOR,
+ AFXRSTOR64,
+ AFXSAVE,
+ AFXSAVE64,
+ ALDMXCSR,
+ AMASKMOVOU,
+ AMASKMOVQ,
+ AMAXPD,
+ AMAXPS,
+ AMAXSD,
+ AMAXSS,
+ AMINPD,
+ AMINPS,
+ AMINSD,
+ AMINSS,
+ AMOVAPD,
+ AMOVAPS,
+ AMOVOU,
+ AMOVHLPS,
+ AMOVHPD,
+ AMOVHPS,
+ AMOVLHPS,
+ AMOVLPD,
+ AMOVLPS,
+ AMOVMSKPD,
+ AMOVMSKPS,
+ AMOVNTO,
+ AMOVNTPD,
+ AMOVNTPS,
+ AMOVNTQ,
+ AMOVO,
+ AMOVQOZX,
+ AMOVSD,
+ AMOVSS,
+ AMOVUPD,
+ AMOVUPS,
+ AMULPD,
+ AMULPS,
+ AMULSD,
+ AMULSS,
+ AORPD,
+ AORPS,
+ APACKSSLW,
+ APACKSSWB,
+ APACKUSWB,
+ APADDB,
+ APADDL,
+ APADDQ,
+ APADDSB,
+ APADDSW,
+ APADDUSB,
+ APADDUSW,
+ APADDW,
+ APANDB,
+ APANDL,
+ APANDSB,
+ APANDSW,
+ APANDUSB,
+ APANDUSW,
+ APANDW,
+ APAND,
+ APANDN,
+ APAVGB,
+ APAVGW,
+ APCMPEQB,
+ APCMPEQL,
+ APCMPEQW,
+ APCMPGTB,
+ APCMPGTL,
+ APCMPGTW,
+ APEXTRW,
+ APFACC,
+ APFADD,
+ APFCMPEQ,
+ APFCMPGE,
+ APFCMPGT,
+ APFMAX,
+ APFMIN,
+ APFMUL,
+ APFNACC,
+ APFPNACC,
+ APFRCP,
+ APFRCPIT1,
+ APFRCPI2T,
+ APFRSQIT1,
+ APFRSQRT,
+ APFSUB,
+ APFSUBR,
+ APINSRW,
+ APMADDWL,
+ APMAXSW,
+ APMAXUB,
+ APMINSW,
+ APMINUB,
+ APMOVMSKB,
+ APMULHRW,
+ APMULHUW,
+ APMULHW,
+ APMULLW,
+ APMULULQ,
+ APOR,
+ APSADBW,
+ APSHUFHW,
+ APSHUFL,
+ APSHUFLW,
+ APSHUFW,
+ APSLLO,
+ APSLLL,
+ APSLLQ,
+ APSLLW,
+ APSRAL,
+ APSRAW,
+ APSRLO,
+ APSRLL,
+ APSRLQ,
+ APSRLW,
+ APSUBB,
+ APSUBL,
+ APSUBQ,
+ APSUBSB,
+ APSUBSW,
+ APSUBUSB,
+ APSUBUSW,
+ APSUBW,
+ APSWAPL,
+ APUNPCKHBW,
+ APUNPCKHLQ,
+ APUNPCKHQDQ,
+ APUNPCKHWL,
+ APUNPCKLBW,
+ APUNPCKLLQ,
+ APUNPCKLQDQ,
+ APUNPCKLWL,
+ APXOR,
+ ARCPPS,
+ ARCPSS,
+ ARSQRTPS,
+ ARSQRTSS,
+ ASHUFPD,
+ ASHUFPS,
+ ASQRTPD,
+ ASQRTPS,
+ ASQRTSD,
+ ASQRTSS,
+ ASTMXCSR,
+ ASUBPD,
+ ASUBPS,
+ ASUBSD,
+ ASUBSS,
+ AUCOMISD,
+ AUCOMISS,
+ AUNPCKHPD,
+ AUNPCKHPS,
+ AUNPCKLPD,
+ AUNPCKLPS,
+ AXORPD,
+ AXORPS,
+
+ APF2IW,
+ APF2IL,
+ API2FW,
+ API2FL,
+ ARETFW,
+ ARETFL,
+ ARETFQ,
+ ASWAPGS,
+
+ AMODE,
+
+ ALAST
+};
+
+enum
+{
+
+ D_AL = 0,
+ D_CL,
+ D_DL,
+ D_BL,
+ D_SPB,
+ D_BPB,
+ D_SIB,
+ D_DIB,
+ D_R8B,
+ D_R9B,
+ D_R10B,
+ D_R11B,
+ D_R12B,
+ D_R13B,
+ D_R14B,
+ D_R15B,
+
+ D_AX = 16,
+ D_CX,
+ D_DX,
+ D_BX,
+ D_SP,
+ D_BP,
+ D_SI,
+ D_DI,
+ D_R8,
+ D_R9,
+ D_R10,
+ D_R11,
+ D_R12,
+ D_R13,
+ D_R14,
+ D_R15,
+
+ D_AH = 32,
+ D_CH,
+ D_DH,
+ D_BH,
+
+ D_F0 = 36,
+
+ D_M0 = 44,
+
+ D_X0 = 52,
+
+ D_CS = 68,
+ D_SS,
+ D_DS,
+ D_ES,
+ D_FS,
+ D_GS,
+
+ D_GDTR, /* global descriptor table register */
+ D_IDTR, /* interrupt descriptor table register */
+ D_LDTR, /* local descriptor table register */
+ D_MSW, /* machine status word */
+ D_TASK, /* task register */
+
+ D_CR = 79,
+ D_DR = 95,
+ D_TR = 103,
+
+ D_NONE = 111,
+
+ D_BRANCH = 112,
+ D_EXTERN = 113,
+ D_STATIC = 114,
+ D_AUTO = 115,
+ D_PARAM = 116,
+ D_CONST = 117,
+ D_FCONST = 118,
+ D_SCONST = 119,
+ D_ADDR = 120,
+
+ D_FILE,
+ D_FILE1,
+
+ D_INDIR, /* additive */
+
+ T_TYPE = 1<<0,
+ T_INDEX = 1<<1,
+ T_OFFSET = 1<<2,
+ T_FCONST = 1<<3,
+ T_SYM = 1<<4,
+ T_SCONST = 1<<5,
+ T_64 = 1<<6,
+
+ REGARG = D_BP, /* MIGHT CHANGE */
+ REGRET = D_AX,
+ FREGRET = D_X0,
+ REGSP = D_SP,
+ REGTMP = D_DI,
+ REGEXT = D_R15, /* compiler allocates external registers R15 down */
+ FREGMIN = D_X0+5, /* first register variable */
+ FREGEXT = D_X0+7 /* first external register */
+};
+
+/*
+ * 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/sys/src/cmd/6c/cgen.c b/sys/src/cmd/6c/cgen.c
new file mode 100644
index 000000000..5e6b10b33
--- /dev/null
+++ b/sys/src/cmd/6c/cgen.c
@@ -0,0 +1,1942 @@
+#include "gc.h"
+
+/* ,x/^(print|prtree)\(/i/\/\/ */
+int castup(Type*, Type*);
+
+void
+cgen(Node *n, Node *nn)
+{
+ Node *l, *r, *t;
+ Prog *p1;
+ Node nod, nod1, nod2, nod3, nod4;
+ int o, hardleft;
+ long v, curs;
+ vlong c;
+
+ if(debug['g']) {
+ prtree(nn, "cgen lhs");
+ prtree(n, "cgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(typesu[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(l->complex >= FNX)
+ if(r != Z && r->complex >= FNX)
+ switch(o) {
+ default:
+ if(cond(o) && typesu[l->type->etype])
+ break;
+
+ regret(&nod, r);
+ cgen(r, &nod);
+
+ regsalloc(&nod1, r);
+ gmove(&nod, &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;
+ }
+
+ hardleft = l->addable < INDEXED || l->complex >= FNX;
+ switch(o) {
+ default:
+ diag(n, "unknown op in cgen: %O", o);
+ break;
+
+ case ONEG:
+ case OCOM:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, n->type, Z, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+
+ case OAS:
+ if(l->op == OBIT)
+ goto bitas;
+ if(!hardleft) {
+ if(nn != Z || r->addable < INDEXED || hardconst(r)) {
+ 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) {
+ if(l->op == OINDEX && immconst(r)) {
+ gmove(r, l);
+ break;
+ }
+ reglcgen(&nod1, l, Z);
+ if(r->addable >= INDEXED && !hardconst(r)) {
+ 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);
+ gmove(&nod1, &nod2);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OBIT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ bitload(n, &nod, Z, Z, nn);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(r->op == OCONST) {
+ if(r->vconst == 0) {
+ cgen(l, nn);
+ break;
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ if(o == OASHL && r->vconst == 1)
+ gopcode(OADD, n->type, &nod, &nod);
+ else
+ gopcode(o, n->type, r, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+
+ /*
+ * get nod to be D_CX
+ */
+ if(nodreg(&nod, nn, D_CX)) {
+ regsalloc(&nod1, n);
+ gmove(&nod, &nod1);
+ cgen(n, &nod); /* probably a bug */
+ gmove(&nod, nn);
+ gmove(&nod1, &nod);
+ break;
+ }
+ reg[D_CX]++;
+ if(nn->op == OREGISTER && nn->reg == D_CX)
+ regalloc(&nod1, l, Z);
+ else
+ regalloc(&nod1, l, nn);
+ if(r->complex >= l->complex) {
+ cgen(r, &nod);
+ cgen(l, &nod1);
+ } else {
+ cgen(l, &nod1);
+ cgen(r, &nod);
+ }
+ gopcode(o, n->type, &nod, &nod1);
+ gmove(&nod1, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OADD:
+ case OSUB:
+ case OOR:
+ case OXOR:
+ case OAND:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(typefd[n->type->etype])
+ goto fop;
+ if(r->op == OCONST) {
+ if(r->vconst == 0 && o != OAND) {
+ cgen(l, nn);
+ break;
+ }
+ }
+ if(n->op == OADD && l->op == OASHL && l->right->op == OCONST
+ && (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) {
+ c = l->right->vconst;
+ if(c > 0 && c <= 3) {
+ if(l->left->complex >= r->complex) {
+ regalloc(&nod, l->left, nn);
+ cgen(l->left, &nod);
+ if(r->addable < INDEXED) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ genmuladd(&nod, &nod, 1 << c, &nod1);
+ regfree(&nod1);
+ }
+ else
+ genmuladd(&nod, &nod, 1 << c, r);
+ }
+ else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l->left, Z);
+ cgen(l->left, &nod1);
+ genmuladd(&nod, &nod1, 1 << c, &nod);
+ regfree(&nod1);
+ }
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+ }
+ if(r->addable >= INDEXED && !hardconst(r)) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, n->type, r, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, n->type, &nod1, &nod);
+ } else {
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ regalloc(&nod, l, Z);
+ cgen(l, &nod);
+ gopcode(o, n->type, &nod1, &nod);
+ }
+ gmove(&nod, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OLMOD:
+ case OMOD:
+ case OLMUL:
+ case OLDIV:
+ case OMUL:
+ case ODIV:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(typefd[n->type->etype])
+ goto fop;
+ if(r->op == OCONST && typechl[n->type->etype]) { /* TO DO */
+ SET(v);
+ switch(o) {
+ case ODIV:
+ case OMOD:
+ c = r->vconst;
+ if(c < 0)
+ c = -c;
+ v = log2(c);
+ if(v < 0)
+ break;
+ /* fall thru */
+ case OMUL:
+ case OLMUL:
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ switch(o) {
+ case OMUL:
+ case OLMUL:
+ mulgen(n->type, r, &nod);
+ break;
+ case ODIV:
+ sdiv2(r->vconst, v, l, &nod);
+ break;
+ case OMOD:
+ smod2(r->vconst, v, l, &nod);
+ break;
+ }
+ gmove(&nod, nn);
+ regfree(&nod);
+ goto done;
+ case OLDIV:
+ c = r->vconst;
+ if((c & 0x80000000) == 0)
+ break;
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ regalloc(&nod, l, nn);
+ zeroregm(&nod);
+ gins(ACMPL, &nod1, nodconst(c));
+ gins(ASBBL, nodconst(-1), &nod);
+ regfree(&nod1);
+ gmove(&nod, nn);
+ regfree(&nod);
+ goto done;
+ }
+ }
+
+ if(o == OMUL) {
+ if(l->addable >= INDEXED) {
+ t = l;
+ l = r;
+ r = t;
+ }
+ /* should favour AX */
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ if(r->addable < INDEXED || hardconst(r)) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(OMUL, n->type, &nod1, &nod);
+ regfree(&nod1);
+ }else
+ gopcode(OMUL, n->type, r, &nod); /* addressible */
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+
+ /*
+ * get nod to be D_AX
+ * get nod1 to be D_DX
+ */
+ if(nodreg(&nod, nn, D_AX)) {
+ regsalloc(&nod2, n);
+ gmove(&nod, &nod2);
+ v = reg[D_AX];
+ reg[D_AX] = 0;
+
+ if(isreg(l, D_AX)) {
+ nod3 = *n;
+ nod3.left = &nod2;
+ cgen(&nod3, nn);
+ } else
+ if(isreg(r, D_AX)) {
+ nod3 = *n;
+ nod3.right = &nod2;
+ cgen(&nod3, nn);
+ } else
+ cgen(n, nn);
+
+ gmove(&nod2, &nod);
+ reg[D_AX] = v;
+ break;
+ }
+ if(nodreg(&nod1, nn, D_DX)) {
+ regsalloc(&nod2, n);
+ gmove(&nod1, &nod2);
+ v = reg[D_DX];
+ reg[D_DX] = 0;
+
+ if(isreg(l, D_DX)) {
+ nod3 = *n;
+ nod3.left = &nod2;
+ cgen(&nod3, nn);
+ } else
+ if(isreg(r, D_DX)) {
+ nod3 = *n;
+ nod3.right = &nod2;
+ cgen(&nod3, nn);
+ } else
+ cgen(n, nn);
+
+ gmove(&nod2, &nod1);
+ reg[D_DX] = v;
+ break;
+ }
+ reg[D_AX]++;
+
+ if(r->op == OCONST && (o == ODIV || o == OLDIV) && immconst(r) && typechl[r->type->etype]) {
+ reg[D_DX]++;
+ if(l->addable < INDEXED) {
+ regalloc(&nod2, l, Z);
+ cgen(l, &nod2);
+ l = &nod2;
+ }
+ if(o == ODIV)
+ sdivgen(l, r, &nod, &nod1);
+ else
+ udivgen(l, r, &nod, &nod1);
+ gmove(&nod1, nn);
+ if(l == &nod2)
+ regfree(l);
+ goto freeaxdx;
+ }
+
+ if(l->complex >= r->complex) {
+ cgen(l, &nod);
+ reg[D_DX]++;
+ if(o == ODIV || o == OMOD)
+ gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
+ if(o == OLDIV || o == OLMOD)
+ zeroregm(&nod1);
+ if(r->addable < INDEXED || r->op == OCONST) {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ gopcode(o, n->type, &nod3, Z);
+ regfree(&nod3);
+ } else
+ gopcode(o, n->type, r, Z);
+ } else {
+ regsalloc(&nod3, r);
+ cgen(r, &nod3);
+ cgen(l, &nod);
+ reg[D_DX]++;
+ if(o == ODIV || o == OMOD)
+ gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
+ if(o == OLDIV || o == OLMOD)
+ zeroregm(&nod1);
+ gopcode(o, n->type, &nod3, Z);
+ }
+ if(o == OMOD || o == OLMOD)
+ gmove(&nod1, nn);
+ else
+ gmove(&nod, nn);
+ freeaxdx:
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OASLSHR:
+ case OASASHL:
+ case OASASHR:
+ if(r->op == OCONST)
+ goto asand;
+ if(l->op == OBIT)
+ goto asbitop;
+ if(typefd[n->type->etype])
+ goto asand; /* can this happen? */
+
+ /*
+ * get nod to be D_CX
+ */
+ if(nodreg(&nod, nn, D_CX)) {
+ regsalloc(&nod1, n);
+ gmove(&nod, &nod1);
+ cgen(n, &nod);
+ if(nn != Z)
+ gmove(&nod, nn);
+ gmove(&nod1, &nod);
+ break;
+ }
+ reg[D_CX]++;
+
+ if(r->complex >= l->complex) {
+ cgen(r, &nod);
+ if(hardleft)
+ reglcgen(&nod1, l, Z);
+ else
+ nod1 = *l;
+ } else {
+ if(hardleft)
+ reglcgen(&nod1, l, Z);
+ else
+ nod1 = *l;
+ cgen(r, &nod);
+ }
+
+ gopcode(o, l->type, &nod, &nod1);
+ regfree(&nod);
+ if(nn != Z)
+ gmove(&nod1, nn);
+ if(hardleft)
+ regfree(&nod1);
+ break;
+
+ case OASAND:
+ case OASADD:
+ case OASSUB:
+ case OASXOR:
+ case OASOR:
+ asand:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(typefd[l->type->etype] || typefd[r->type->etype])
+ goto asfop;
+ if(l->complex >= r->complex) {
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ if(!immconst(r)) {
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ gopcode(o, l->type, &nod1, &nod);
+ regfree(&nod1);
+ } else
+ gopcode(o, l->type, r, &nod);
+ } else {
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ gopcode(o, l->type, &nod1, &nod);
+ regfree(&nod1);
+ }
+ if(nn != Z)
+ gmove(&nod, nn);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ asfop:
+ if(l->complex >= r->complex) {
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ if(r->addable < INDEXED){
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ }else
+ nod1 = *r;
+ regalloc(&nod2, r, Z);
+ gmove(&nod, &nod2);
+ gopcode(o, r->type, &nod1, &nod2);
+ gmove(&nod2, &nod);
+ regfree(&nod2);
+ if(r->addable < INDEXED)
+ regfree(&nod1);
+ } else {
+ regalloc(&nod1, r, nn);
+ cgen(r, &nod1);
+ if(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ if(o != OASMUL && o != OASADD || !typefd[l->type->etype]) {
+ regalloc(&nod2, r, Z);
+ gmove(&nod, &nod2);
+ gopcode(o, r->type, &nod1, &nod2);
+ regfree(&nod1);
+ gmove(&nod2, &nod);
+ regfree(&nod2);
+ } else {
+ gopcode(o, r->type, &nod, &nod1);
+ gmove(&nod1, &nod);
+ regfree(&nod1);
+ }
+ }
+ if(nn != Z)
+ gmove(&nod, nn);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(typefd[n->type->etype] || typefd[r->type->etype])
+ goto asfop;
+ if(r->op == OCONST && typechl[n->type->etype]) {
+ SET(v);
+ switch(o) {
+ case OASDIV:
+ case OASMOD:
+ c = r->vconst;
+ if(c < 0)
+ c = -c;
+ v = log2(c);
+ if(v < 0)
+ break;
+ /* fall thru */
+ case OASMUL:
+ case OASLMUL:
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod, l, nn);
+ cgen(&nod2, &nod);
+ switch(o) {
+ case OASMUL:
+ case OASLMUL:
+ mulgen(n->type, r, &nod);
+ break;
+ case OASDIV:
+ sdiv2(r->vconst, v, l, &nod);
+ break;
+ case OASMOD:
+ smod2(r->vconst, v, l, &nod);
+ break;
+ }
+ havev:
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gmove(&nod, nn);
+ if(hardleft)
+ regfree(&nod2);
+ regfree(&nod);
+ goto done;
+ case OASLDIV:
+ c = r->vconst;
+ if((c & 0x80000000) == 0)
+ break;
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod1, l, nn);
+ cgen(&nod2, &nod1);
+ regalloc(&nod, l, nn);
+ zeroregm(&nod);
+ gins(ACMPL, &nod1, nodconst(c));
+ gins(ASBBL, nodconst(-1), &nod);
+ regfree(&nod1);
+ goto havev;
+ }
+ }
+
+ if(o == OASMUL) {
+ /* should favour AX */
+ regalloc(&nod, l, nn);
+ if(r->complex >= FNX) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ r = &nod1;
+ }
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ cgen(&nod2, &nod);
+ if(r->addable < INDEXED || hardconst(r)) {
+ if(r->complex < FNX) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ }
+ gopcode(OASMUL, n->type, &nod1, &nod);
+ regfree(&nod1);
+ }
+ else
+ gopcode(OASMUL, n->type, r, &nod);
+ if(r == &nod1)
+ regfree(r);
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gmove(&nod, nn);
+ regfree(&nod);
+ if(hardleft)
+ regfree(&nod2);
+ break;
+ }
+
+ /*
+ * get nod to be D_AX
+ * get nod1 to be D_DX
+ */
+ if(nodreg(&nod, nn, D_AX)) {
+ regsalloc(&nod2, n);
+ gmove(&nod, &nod2);
+ v = reg[D_AX];
+ reg[D_AX] = 0;
+
+ if(isreg(l, D_AX)) {
+ nod3 = *n;
+ nod3.left = &nod2;
+ cgen(&nod3, nn);
+ } else
+ if(isreg(r, D_AX)) {
+ nod3 = *n;
+ nod3.right = &nod2;
+ cgen(&nod3, nn);
+ } else
+ cgen(n, nn);
+
+ gmove(&nod2, &nod);
+ reg[D_AX] = v;
+ break;
+ }
+ if(nodreg(&nod1, nn, D_DX)) {
+ regsalloc(&nod2, n);
+ gmove(&nod1, &nod2);
+ v = reg[D_DX];
+ reg[D_DX] = 0;
+
+ if(isreg(l, D_DX)) {
+ nod3 = *n;
+ nod3.left = &nod2;
+ cgen(&nod3, nn);
+ } else
+ if(isreg(r, D_DX)) {
+ nod3 = *n;
+ nod3.right = &nod2;
+ cgen(&nod3, nn);
+ } else
+ cgen(n, nn);
+
+ gmove(&nod2, &nod1);
+ reg[D_DX] = v;
+ break;
+ }
+ reg[D_AX]++;
+ reg[D_DX]++;
+
+ if(l->complex >= r->complex) {
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ cgen(&nod2, &nod);
+ if(r->op == OCONST && typechl[r->type->etype]) {
+ switch(o) {
+ case OASDIV:
+ sdivgen(&nod2, r, &nod, &nod1);
+ goto divdone;
+ case OASLDIV:
+ udivgen(&nod2, r, &nod, &nod1);
+ divdone:
+ gmove(&nod1, &nod2);
+ if(nn != Z)
+ gmove(&nod1, nn);
+ goto freelxaxdx;
+ }
+ }
+ if(o == OASDIV || o == OASMOD)
+ gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
+ if(o == OASLDIV || o == OASLMOD)
+ zeroregm(&nod1);
+ if(r->addable < INDEXED || r->op == OCONST ||
+ !typeil[r->type->etype]) {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ gopcode(o, l->type, &nod3, Z);
+ regfree(&nod3);
+ } else
+ gopcode(o, n->type, r, Z);
+ } else {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ cgen(&nod2, &nod);
+ if(o == OASDIV || o == OASMOD)
+ gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
+ if(o == OASLDIV || o == OASLMOD)
+ zeroregm(&nod1);
+ gopcode(o, l->type, &nod3, Z);
+ regfree(&nod3);
+ }
+ if(o == OASMOD || o == OASLMOD) {
+ gmove(&nod1, &nod2);
+ if(nn != Z)
+ gmove(&nod1, nn);
+ } else {
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gmove(&nod, nn);
+ }
+ freelxaxdx:
+ if(hardleft)
+ regfree(&nod2);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ fop:
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ if(r->addable < INDEXED) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, n->type, &nod1, &nod);
+ regfree(&nod1);
+ } else
+ gopcode(o, n->type, r, &nod);
+ } else {
+ /* TO DO: could do better with r->addable >= INDEXED */
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, n->type, &nod1, &nod);
+ regfree(&nod1);
+ }
+ gmove(&nod, nn);
+ regfree(&nod);
+ 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);
+
+ { /* TO DO: check floating point source */
+ Node onod;
+
+ /* incredible grot ... */
+ onod = nod3;
+ onod.op = o;
+ onod.complex = 2;
+ onod.addable = 0;
+ onod.type = tfield;
+ onod.left = &nod4;
+ onod.right = &nod3;
+ cgen(&onod, Z);
+ }
+ 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);
+ gmove(&nod, &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, nn);
+ nod.op = OREGISTER;
+ gopcode(OFUNC, n->type, Z, &nod);
+ regfree(&nod);
+ } else
+ gopcode(OFUNC, n->type, Z, l);
+ if(REGARG)
+ if(o != reg[REGARG])
+ reg[REGARG]--;
+ if(nn != Z) {
+ regret(&nod, n);
+ gmove(&nod, 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);
+ gmove(&nod, 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) && nocast(n->type, nn->type)) {
+ /* both null, gen l->nn */
+ cgen(l, nn);
+ break;
+ }
+ if(ewidth[n->type->etype] < ewidth[l->type->etype]){
+ if(l->type->etype == TIND && typechlp[n->type->etype])
+ warn(n, "conversion of pointer to shorter integer");
+ }else if(0){
+ if(nocast(n->type, nn->type) || castup(n->type, nn->type)){
+ if(typefd[l->type->etype] != typefd[nn->type->etype])
+ regalloc(&nod, l, nn);
+ else
+ regalloc(&nod, nn, nn);
+ cgen(l, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+ }
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, n, &nod);
+ gmove(&nod, &nod1);
+ gmove(&nod1, nn);
+ regfree(&nod1);
+ regfree(&nod);
+ break;
+
+ case ODOT:
+ sugen(l, nodrat, l->type->width);
+ if(nn == Z)
+ break;
+ 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(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+
+ gmove(&nod, nn);
+ if(typefd[n->type->etype]) {
+ regalloc(&nod1, l, Z);
+ gmove(&nod, &nod1);
+ if(v < 0)
+ gopcode(OSUB, n->type, nodfconst(-v), &nod1);
+ else
+ gopcode(OADD, n->type, nodfconst(v), &nod1);
+ gmove(&nod1, &nod);
+ regfree(&nod1);
+ } else
+ gopcode(OADD, n->type, nodconst(v), &nod);
+ if(hardleft)
+ regfree(&nod);
+ 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(hardleft)
+ reglcgen(&nod, l, Z);
+ else
+ nod = *l;
+ if(typefd[n->type->etype]) {
+ regalloc(&nod1, l, Z);
+ gmove(&nod, &nod1);
+ if(v < 0)
+ gopcode(OSUB, n->type, nodfconst(-v), &nod1);
+ else
+ gopcode(OADD, n->type, nodfconst(v), &nod1);
+ gmove(&nod1, &nod);
+ regfree(&nod1);
+ } else
+ gopcode(OADD, n->type, nodconst(v), &nod);
+ if(nn != Z)
+ gmove(&nod, nn);
+ if(hardleft)
+ regfree(&nod);
+ break;
+
+ bitinc:
+ if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
+ bitload(l, &nod, &nod1, &nod2, Z);
+ gmove(&nod, nn);
+ gopcode(OADD, tfield, nodconst(v), &nod);
+ bitstore(l, &nod, &nod1, &nod2, Z);
+ break;
+ }
+ bitload(l, &nod, &nod1, &nod2, nn);
+ gopcode(OADD, tfield, nodconst(v), &nod);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+ }
+done:
+ 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;
+ }
+ gopcode(OADDR, n->type, n, 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;
+ }
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+ if(n->type == T)
+ gbranch(OGOTO);
+ else
+ boolgen(n, true, Z);
+}
+
+void
+boolgen(Node *n, int true, Node *nn)
+{
+ int o;
+ Prog *p1, *p2;
+ Node *l, *r, nod, nod1;
+ long curs;
+
+ if(debug['g']) {
+ prtree(nn, "boolgen lhs");
+ prtree(n, "boolgen");
+ }
+ curs = cursafe;
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ default:
+ o = ONE;
+ if(true)
+ o = OEQ;
+ /* bad, 13 is address of external that becomes constant */
+ if(n->addable >= INDEXED && n->addable != 13) {
+ if(typefd[n->type->etype]) {
+ regalloc(&nod1, n, Z);
+ gmove(nodfconst(0.0), &nod1); /* TO DO: FREGZERO */
+ gopcode(o, n->type, n, &nod1);
+ regfree(&nod1);
+ } else
+ gopcode(o, n->type, n, nodconst(0));
+ goto com;
+ }
+ regalloc(&nod, n, nn);
+ cgen(n, &nod);
+ if(typefd[n->type->etype]) {
+ regalloc(&nod1, n, Z);
+ gmove(nodfconst(0.0), &nod1); /* TO DO: FREGZERO */
+ gopcode(o, n->type, &nod, &nod1);
+ regfree(&nod1);
+ } else
+ gopcode(o, n->type, &nod, nodconst(0));
+ regfree(&nod);
+ goto com;
+
+ 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(true)
+ o = comrel[relindex(o)];
+ if(l->complex >= FNX && r->complex >= FNX) {
+ regret(&nod, r);
+ cgen(r, &nod);
+ regsalloc(&nod1, r);
+ gmove(&nod, &nod1);
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ boolgen(&nod, true, nn);
+ break;
+ }
+ if(immconst(l)) {
+ o = invrel[relindex(o)];
+ /* bad, 13 is address of external that becomes constant */
+ if(r->addable < INDEXED || r->addable == 13) {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ gopcode(o, l->type, &nod, l);
+ regfree(&nod);
+ } else
+ gopcode(o, l->type, r, l);
+ goto com;
+ }
+ if(typefd[l->type->etype])
+ o = invrel[relindex(logrel[relindex(o)])];
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ if(r->addable < INDEXED || hardconst(r) || typefd[l->type->etype]) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, l->type, &nod, &nod1);
+ regfree(&nod1);
+ } else
+ gopcode(o, l->type, &nod, r);
+ regfree(&nod);
+ goto com;
+ }
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ if(l->addable < INDEXED || l->addable == 13 || hardconst(l)) {
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ if(typechl[l->type->etype] && ewidth[l->type->etype] <= ewidth[TINT])
+ gopcode(o, types[TINT], &nod1, &nod);
+ else
+ gopcode(o, l->type, &nod1, &nod);
+ regfree(&nod1);
+ } else
+ gopcode(o, l->type, l, &nod);
+ regfree(&nod);
+
+ com:
+ if(nn != Z) {
+ p1 = p;
+ gmove(nodconst(1L), nn);
+ gbranch(OGOTO);
+ p2 = p;
+ patch(p1, pc);
+ gmove(nodconst(0L), 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;
+ int c, mt, mo;
+ vlong o0, o1;
+
+ 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:
+ goto copy;
+
+ case ODOT:
+ l = n->left;
+ sugen(l, nodrat, l->type->width);
+ if(nn == Z)
+ break;
+ 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 && side(nn)) {
+ nod1 = *n;
+ nod1.type = typ(TIND, n->type);
+ regret(&nod2, &nod1);
+ lcgen(nn, &nod2);
+ regsalloc(&nod0, &nod1);
+ cgen(&nod2, &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 = nil;
+
+ 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;
+ nod0.right = l;
+
+ /* prtree(&nod0, "hand craft"); /* */
+ 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) {
+ switch(n->op) {
+ case OASADD:
+ case OASSUB:
+ case OASAND:
+ case OASOR:
+ case OASXOR:
+
+ case OASMUL:
+ case OASLMUL:
+
+
+ case OASASHL:
+ case OASASHR:
+ case OASLSHR:
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ case OPREINC:
+ case OPREDEC:
+ break;
+
+ default:
+ return;
+ }
+ }
+
+ if(n->complex >= FNX && nn != nil && nn->complex >= FNX) {
+ t = nn->type;
+ nn->type = types[TLONG];
+ regialloc(&nod1, nn, Z);
+ lcgen(nn, &nod1);
+ regsalloc(&nod2, nn);
+ nn->type = t;
+
+ gins(AMOVL, &nod1, &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(w <= 32) {
+ c = cursafe;
+ if(n->left != Z && n->left->complex >= FNX
+ && n->right != Z && n->right->complex >= FNX) {
+ regsalloc(&nod1, n->right);
+ cgen(n->right, &nod1);
+ nod2 = *n;
+ nod2.right = &nod1;
+ cgen(&nod2, nn);
+ cursafe = c;
+ return;
+ }
+ if(w & 7) {
+ mt = TLONG;
+ mo = AMOVL;
+ } else {
+ mt = TVLONG;
+ mo = AMOVQ;
+ }
+ if(n->complex > nn->complex) {
+ t = n->type;
+ n->type = types[mt];
+ regalloc(&nod0, n, Z);
+ if(!vaddr(n, 0)) {
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+ n = &nod1;
+ }
+ else
+ n->type = t;
+
+ t = nn->type;
+ nn->type = types[mt];
+ if(!vaddr(nn, 0)) {
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+ nn = &nod2;
+ }
+ else
+ nn->type = t;
+ } else {
+ t = nn->type;
+ nn->type = types[mt];
+ regalloc(&nod0, nn, Z);
+ if(!vaddr(nn, 0)) {
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+ nn = &nod2;
+ }
+ else
+ nn->type = t;
+
+ t = n->type;
+ n->type = types[mt];
+ if(!vaddr(n, 0)) {
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+ n = &nod1;
+ }
+ else
+ n->type = t;
+ }
+ o0 = n->xoffset;
+ o1 = nn->xoffset;
+ w /= ewidth[mt];
+ while(--w >= 0) {
+ gins(mo, n, &nod0);
+ gins(mo, &nod0, nn);
+ n->xoffset += ewidth[mt];
+ nn->xoffset += ewidth[mt];
+ }
+ n->xoffset = o0;
+ nn->xoffset = o1;
+ if(nn == &nod2)
+ regfree(&nod2);
+ if(n == &nod1)
+ regfree(&nod1);
+ regfree(&nod0);
+ return;
+ }
+
+ /* botch, need to save in .safe */
+ c = 0;
+ if(n->complex > nn->complex) {
+ t = n->type;
+ n->type = types[TLONG];
+ nodreg(&nod1, n, D_SI);
+ if(reg[D_SI]) {
+ gins(APUSHQ, &nod1, Z);
+ c |= 1;
+ reg[D_SI]++;
+ }
+ lcgen(n, &nod1);
+ n->type = t;
+
+ t = nn->type;
+ nn->type = types[TLONG];
+ nodreg(&nod2, nn, D_DI);
+ if(reg[D_DI]) {
+warn(Z, "DI botch");
+ gins(APUSHQ, &nod2, Z);
+ c |= 2;
+ reg[D_DI]++;
+ }
+ lcgen(nn, &nod2);
+ nn->type = t;
+ } else {
+ t = nn->type;
+ nn->type = types[TLONG];
+ nodreg(&nod2, nn, D_DI);
+ if(reg[D_DI]) {
+warn(Z, "DI botch");
+ gins(APUSHQ, &nod2, Z);
+ c |= 2;
+ reg[D_DI]++;
+ }
+ lcgen(nn, &nod2);
+ nn->type = t;
+
+ t = n->type;
+ n->type = types[TLONG];
+ nodreg(&nod1, n, D_SI);
+ if(reg[D_SI]) {
+ gins(APUSHQ, &nod1, Z);
+ c |= 1;
+ reg[D_SI]++;
+ }
+ lcgen(n, &nod1);
+ n->type = t;
+ }
+ nodreg(&nod3, n, D_CX);
+ if(reg[D_CX]) {
+ gins(APUSHQ, &nod3, Z);
+ c |= 4;
+ reg[D_CX]++;
+ }
+ gins(AMOVL, nodconst(w/SZ_INT), &nod3);
+ gins(ACLD, Z, Z);
+ gins(AREP, Z, Z);
+ gins(AMOVSL, Z, Z);
+ if(c & 4) {
+ gins(APOPQ, Z, &nod3);
+ reg[D_CX]--;
+ }
+ if(c & 2) {
+ gins(APOPQ, Z, &nod2);
+ reg[nod2.reg]--;
+ }
+ if(c & 1) {
+ gins(APOPQ, Z, &nod1);
+ reg[nod1.reg]--;
+ }
+}
+
+/*
+ * TO DO
+ */
+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, &lregnode, Z);
+ regalloc(&t2, &lregnode, Z);
+ if(c > 0) {
+ gmove(f, &t1);
+ f->xoffset += SZ_INT;
+ }
+ if(cn != Z)
+ gmove(nodconst(cv), cn);
+ if(c > 1) {
+ gmove(f, &t2);
+ f->xoffset += SZ_INT;
+ }
+ if(c > 0) {
+ gmove(&t1, t);
+ t->xoffset += SZ_INT;
+ }
+ if(c > 2) {
+ gmove(f, &t1);
+ f->xoffset += SZ_INT;
+ }
+ if(c > 1) {
+ gmove(&t2, t);
+ t->xoffset += SZ_INT;
+ }
+ if(c > 2) {
+ gmove(&t1, t);
+ t->xoffset += SZ_INT;
+ }
+ regfree(&t1);
+ regfree(&t2);
+}
+
+/*
+ * constant is not vlong or fits as 32-bit signed immediate
+ */
+int
+immconst(Node *n)
+{
+ long v;
+
+ if(n->op != OCONST || !typechlpv[n->type->etype])
+ return 0;
+ if(typechl[n->type->etype])
+ return 1;
+ v = n->vconst;
+ return n->vconst == (vlong)v;
+}
+
+/*
+ * if a constant and vlong, doesn't fit as 32-bit signed immediate
+ */
+int
+hardconst(Node *n)
+{
+ return n->op == OCONST && !immconst(n);
+}
+
+/*
+ * casting up to t2 covers an intermediate cast to t1
+ */
+int
+castup(Type *t1, Type *t2)
+{
+ int ft;
+
+ if(!nilcast(t1, t2))
+ return 0;
+ /* known to be small to large */
+ ft = t1->etype;
+ switch(t2->etype){
+ case TINT:
+ case TLONG:
+ return ft == TLONG || ft == TINT || ft == TSHORT || ft == TCHAR;
+ case TUINT:
+ case TULONG:
+ return ft == TULONG || ft == TUINT || ft == TUSHORT || ft == TUCHAR;
+ case TVLONG:
+ return ft == TLONG || ft == TINT || ft == TSHORT;
+ case TUVLONG:
+ return ft == TULONG || ft == TUINT || ft == TUSHORT;
+ }
+ return 0;
+}
+
+void
+zeroregm(Node *n)
+{
+ gins(AMOVL, nodconst(0), n);
+}
+
+/* do we need to load the address of a vlong? */
+int
+vaddr(Node *n, int a)
+{
+ switch(n->op) {
+ case ONAME:
+ if(a)
+ return 1;
+ return !(n->class == CEXTERN || n->class == CGLOBL || n->class == CSTATIC);
+
+ case OCONST:
+ case OREGISTER:
+ case OINDREG:
+ return 1;
+ }
+ return 0;
+}
+
+long
+hi64v(Node *n)
+{
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ return (long)(n->vconst) & ~0L;
+ else
+ return (long)((uvlong)n->vconst>>32) & ~0L;
+}
+
+long
+lo64v(Node *n)
+{
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ return (long)((uvlong)n->vconst>>32) & ~0L;
+ else
+ return (long)(n->vconst) & ~0L;
+}
+
+Node *
+hi64(Node *n)
+{
+ return nodconst(hi64v(n));
+}
+
+Node *
+lo64(Node *n)
+{
+ return nodconst(lo64v(n));
+}
+
+int
+cond(int op)
+{
+ switch(op) {
+ case OANDAND:
+ case OOROR:
+ case ONOT:
+ return 1;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ return 1;
+ }
+ return 0;
+}
diff --git a/sys/src/cmd/6c/div.c b/sys/src/cmd/6c/div.c
new file mode 100644
index 000000000..cb5886789
--- /dev/null
+++ b/sys/src/cmd/6c/div.c
@@ -0,0 +1,206 @@
+#include "gc.h"
+
+/*
+ * Based on: Granlund, T.; Montgomery, P.L.
+ * "Division by Invariant Integers using Multiplication".
+ * SIGPLAN Notices, Vol. 29, June 1994, page 61.
+ */
+
+#define TN(n) ((uvlong)1 << (n))
+#define T31 TN(31)
+#define T32 TN(32)
+
+int
+multiplier(ulong d, int p, uvlong *mp)
+{
+ int l;
+ uvlong mlo, mhi, tlo, thi;
+
+ l = topbit(d - 1) + 1;
+ mlo = (((TN(l) - d) << 32) / d) + T32;
+ if(l + p == 64)
+ mhi = (((TN(l) + 1 - d) << 32) / d) + T32;
+ else
+ mhi = (TN(32 + l) + TN(32 + l - p)) / d;
+ /*assert(mlo < mhi);*/
+ while(l > 0) {
+ tlo = mlo >> 1;
+ thi = mhi >> 1;
+ if(tlo == thi)
+ break;
+ mlo = tlo;
+ mhi = thi;
+ l--;
+ }
+ *mp = mhi;
+ return l;
+}
+
+int
+sdiv(ulong d, ulong *mp, int *sp)
+{
+ int s;
+ uvlong m;
+
+ s = multiplier(d, 32 - 1, &m);
+ *mp = m;
+ *sp = s;
+ if(m >= T31)
+ return 1;
+ else
+ return 0;
+}
+
+int
+udiv(ulong d, ulong *mp, int *sp, int *pp)
+{
+ int p, s;
+ uvlong m;
+
+ s = multiplier(d, 32, &m);
+ p = 0;
+ if(m >= T32) {
+ while((d & 1) == 0) {
+ d >>= 1;
+ p++;
+ }
+ s = multiplier(d, 32 - p, &m);
+ }
+ *mp = m;
+ *pp = p;
+ if(m >= T32) {
+ /*assert(p == 0);*/
+ *sp = s - 1;
+ return 1;
+ }
+ else {
+ *sp = s;
+ return 0;
+ }
+}
+
+void
+sdivgen(Node *l, Node *r, Node *ax, Node *dx)
+{
+ int a, s;
+ ulong m;
+ vlong c;
+
+ c = r->vconst;
+ if(c < 0)
+ c = -c;
+ a = sdiv(c, &m, &s);
+//print("a=%d i=%ld s=%d m=%lux\n", a, (long)r->vconst, s, m);
+ gins(AMOVL, nodconst(m), ax);
+ gins(AIMULL, l, Z);
+ gins(AMOVL, l, ax);
+ if(a)
+ gins(AADDL, ax, dx);
+ gins(ASHRL, nodconst(31), ax);
+ gins(ASARL, nodconst(s), dx);
+ gins(AADDL, ax, dx);
+ if(r->vconst < 0)
+ gins(ANEGL, Z, dx);
+}
+
+void
+udivgen(Node *l, Node *r, Node *ax, Node *dx)
+{
+ int a, s, t;
+ ulong m;
+ Node nod;
+
+ a = udiv(r->vconst, &m, &s, &t);
+//print("a=%ud i=%ld p=%d s=%d m=%lux\n", a, (long)r->vconst, t, s, m);
+ if(t != 0) {
+ gins(AMOVL, l, ax);
+ gins(ASHRL, nodconst(t), ax);
+ gins(AMOVL, nodconst(m), dx);
+ gins(AMULL, dx, Z);
+ }
+ else if(a) {
+ if(l->op != OREGISTER) {
+ regalloc(&nod, l, Z);
+ gins(AMOVL, l, &nod);
+ l = &nod;
+ }
+ gins(AMOVL, nodconst(m), ax);
+ gins(AMULL, l, Z);
+ gins(AADDL, l, dx);
+ gins(ARCRL, nodconst(1), dx);
+ if(l == &nod)
+ regfree(l);
+ }
+ else {
+ gins(AMOVL, nodconst(m), ax);
+ gins(AMULL, l, Z);
+ }
+ if(s != 0)
+ gins(ASHRL, nodconst(s), dx);
+}
+
+void
+sext(Node *d, Node *s, Node *l)
+{
+ if(s->reg == D_AX && !nodreg(d, Z, D_DX)) {
+ reg[D_DX]++;
+ gins(ACDQ, Z, Z);
+ }
+ else {
+ regalloc(d, l, Z);
+ gins(AMOVL, s, d);
+ gins(ASARL, nodconst(31), d);
+ }
+}
+
+void
+sdiv2(long c, int v, Node *l, Node *n)
+{
+ Node nod;
+
+ if(v > 0) {
+ if(v > 1) {
+ sext(&nod, n, l);
+ gins(AANDL, nodconst((1 << v) - 1), &nod);
+ gins(AADDL, &nod, n);
+ regfree(&nod);
+ }
+ else {
+ gins(ACMPL, n, nodconst(0x80000000));
+ gins(ASBBL, nodconst(-1), n);
+ }
+ gins(ASARL, nodconst(v), n);
+ }
+ if(c < 0)
+ gins(ANEGL, Z, n);
+}
+
+void
+smod2(long c, int v, Node *l, Node *n)
+{
+ Node nod;
+
+ if(c == 1) {
+ zeroregm(n);
+ return;
+ }
+
+ sext(&nod, n, l);
+ if(v == 0) {
+ zeroregm(n);
+ gins(AXORL, &nod, n);
+ gins(ASUBL, &nod, n);
+ }
+ else if(v > 1) {
+ gins(AANDL, nodconst((1 << v) - 1), &nod);
+ gins(AADDL, &nod, n);
+ gins(AANDL, nodconst((1 << v) - 1), n);
+ gins(ASUBL, &nod, n);
+ }
+ else {
+ gins(AANDL, nodconst(1), n);
+ gins(AXORL, &nod, n);
+ gins(ASUBL, &nod, n);
+ }
+ regfree(&nod);
+}
diff --git a/sys/src/cmd/6c/enam.c b/sys/src/cmd/6c/enam.c
new file mode 100644
index 000000000..ab8068f54
--- /dev/null
+++ b/sys/src/cmd/6c/enam.c
@@ -0,0 +1,669 @@
+char* anames[] =
+{
+ "XXX",
+ "AAA",
+ "AAD",
+ "AAM",
+ "AAS",
+ "ADCB",
+ "ADCL",
+ "ADCW",
+ "ADDB",
+ "ADDL",
+ "ADDW",
+ "ADJSP",
+ "ANDB",
+ "ANDL",
+ "ANDW",
+ "ARPL",
+ "BOUNDL",
+ "BOUNDW",
+ "BSFL",
+ "BSFW",
+ "BSRL",
+ "BSRW",
+ "BTL",
+ "BTW",
+ "BTCL",
+ "BTCW",
+ "BTRL",
+ "BTRW",
+ "BTSL",
+ "BTSW",
+ "BYTE",
+ "CALL",
+ "CLC",
+ "CLD",
+ "CLI",
+ "CLTS",
+ "CMC",
+ "CMPB",
+ "CMPL",
+ "CMPW",
+ "CMPSB",
+ "CMPSL",
+ "CMPSW",
+ "DAA",
+ "DAS",
+ "DATA",
+ "DECB",
+ "DECL",
+ "DECQ",
+ "DECW",
+ "DIVB",
+ "DIVL",
+ "DIVW",
+ "ENTER",
+ "GLOBL",
+ "GOK",
+ "HISTORY",
+ "HLT",
+ "IDIVB",
+ "IDIVL",
+ "IDIVW",
+ "IMULB",
+ "IMULL",
+ "IMULW",
+ "INB",
+ "INL",
+ "INW",
+ "INCB",
+ "INCL",
+ "INCQ",
+ "INCW",
+ "INSB",
+ "INSL",
+ "INSW",
+ "INT",
+ "INTO",
+ "IRETL",
+ "IRETW",
+ "JCC",
+ "JCS",
+ "JCXZ",
+ "JEQ",
+ "JGE",
+ "JGT",
+ "JHI",
+ "JLE",
+ "JLS",
+ "JLT",
+ "JMI",
+ "JMP",
+ "JNE",
+ "JOC",
+ "JOS",
+ "JPC",
+ "JPL",
+ "JPS",
+ "LAHF",
+ "LARL",
+ "LARW",
+ "LEAL",
+ "LEAW",
+ "LEAVEL",
+ "LEAVEW",
+ "LOCK",
+ "LODSB",
+ "LODSL",
+ "LODSW",
+ "LONG",
+ "LOOP",
+ "LOOPEQ",
+ "LOOPNE",
+ "LSLL",
+ "LSLW",
+ "MOVB",
+ "MOVL",
+ "MOVW",
+ "MOVBLSX",
+ "MOVBLZX",
+ "MOVBQSX",
+ "MOVBQZX",
+ "MOVBWSX",
+ "MOVBWZX",
+ "MOVWLSX",
+ "MOVWLZX",
+ "MOVWQSX",
+ "MOVWQZX",
+ "MOVSB",
+ "MOVSL",
+ "MOVSW",
+ "MULB",
+ "MULL",
+ "MULW",
+ "NAME",
+ "NEGB",
+ "NEGL",
+ "NEGW",
+ "NOP",
+ "NOTB",
+ "NOTL",
+ "NOTW",
+ "ORB",
+ "ORL",
+ "ORW",
+ "OUTB",
+ "OUTL",
+ "OUTW",
+ "OUTSB",
+ "OUTSL",
+ "OUTSW",
+ "POPAL",
+ "POPAW",
+ "POPFL",
+ "POPFW",
+ "POPL",
+ "POPW",
+ "PUSHAL",
+ "PUSHAW",
+ "PUSHFL",
+ "PUSHFW",
+ "PUSHL",
+ "PUSHW",
+ "RCLB",
+ "RCLL",
+ "RCLW",
+ "RCRB",
+ "RCRL",
+ "RCRW",
+ "REP",
+ "REPN",
+ "RET",
+ "ROLB",
+ "ROLL",
+ "ROLW",
+ "RORB",
+ "RORL",
+ "RORW",
+ "SAHF",
+ "SALB",
+ "SALL",
+ "SALW",
+ "SARB",
+ "SARL",
+ "SARW",
+ "SBBB",
+ "SBBL",
+ "SBBW",
+ "SCASB",
+ "SCASL",
+ "SCASW",
+ "SETCC",
+ "SETCS",
+ "SETEQ",
+ "SETGE",
+ "SETGT",
+ "SETHI",
+ "SETLE",
+ "SETLS",
+ "SETLT",
+ "SETMI",
+ "SETNE",
+ "SETOC",
+ "SETOS",
+ "SETPC",
+ "SETPL",
+ "SETPS",
+ "CDQ",
+ "CWD",
+ "SHLB",
+ "SHLL",
+ "SHLW",
+ "SHRB",
+ "SHRL",
+ "SHRW",
+ "STC",
+ "STD",
+ "STI",
+ "STOSB",
+ "STOSL",
+ "STOSW",
+ "SUBB",
+ "SUBL",
+ "SUBW",
+ "SYSCALL",
+ "TESTB",
+ "TESTL",
+ "TESTW",
+ "TEXT",
+ "VERR",
+ "VERW",
+ "WAIT",
+ "WORD",
+ "XCHGB",
+ "XCHGL",
+ "XCHGW",
+ "XLAT",
+ "XORB",
+ "XORL",
+ "XORW",
+ "FMOVB",
+ "FMOVBP",
+ "FMOVD",
+ "FMOVDP",
+ "FMOVF",
+ "FMOVFP",
+ "FMOVL",
+ "FMOVLP",
+ "FMOVV",
+ "FMOVVP",
+ "FMOVW",
+ "FMOVWP",
+ "FMOVX",
+ "FMOVXP",
+ "FCOMB",
+ "FCOMBP",
+ "FCOMD",
+ "FCOMDP",
+ "FCOMDPP",
+ "FCOMF",
+ "FCOMFP",
+ "FCOML",
+ "FCOMLP",
+ "FCOMW",
+ "FCOMWP",
+ "FUCOM",
+ "FUCOMP",
+ "FUCOMPP",
+ "FADDDP",
+ "FADDW",
+ "FADDL",
+ "FADDF",
+ "FADDD",
+ "FMULDP",
+ "FMULW",
+ "FMULL",
+ "FMULF",
+ "FMULD",
+ "FSUBDP",
+ "FSUBW",
+ "FSUBL",
+ "FSUBF",
+ "FSUBD",
+ "FSUBRDP",
+ "FSUBRW",
+ "FSUBRL",
+ "FSUBRF",
+ "FSUBRD",
+ "FDIVDP",
+ "FDIVW",
+ "FDIVL",
+ "FDIVF",
+ "FDIVD",
+ "FDIVRDP",
+ "FDIVRW",
+ "FDIVRL",
+ "FDIVRF",
+ "FDIVRD",
+ "FXCHD",
+ "FFREE",
+ "FLDCW",
+ "FLDENV",
+ "FRSTOR",
+ "FSAVE",
+ "FSTCW",
+ "FSTENV",
+ "FSTSW",
+ "F2XM1",
+ "FABS",
+ "FCHS",
+ "FCLEX",
+ "FCOS",
+ "FDECSTP",
+ "FINCSTP",
+ "FINIT",
+ "FLD1",
+ "FLDL2E",
+ "FLDL2T",
+ "FLDLG2",
+ "FLDLN2",
+ "FLDPI",
+ "FLDZ",
+ "FNOP",
+ "FPATAN",
+ "FPREM",
+ "FPREM1",
+ "FPTAN",
+ "FRNDINT",
+ "FSCALE",
+ "FSIN",
+ "FSINCOS",
+ "FSQRT",
+ "FTST",
+ "FXAM",
+ "FXTRACT",
+ "FYL2X",
+ "FYL2XP1",
+ "END",
+ "DYNT",
+ "INIT",
+ "SIGNAME",
+ "CMPXCHGB",
+ "CMPXCHGL",
+ "CMPXCHGW",
+ "CMPXCHG8B",
+ "CPUID",
+ "INVD",
+ "INVLPG",
+ "LFENCE",
+ "MFENCE",
+ "MOVNTIL",
+ "RDMSR",
+ "RDPMC",
+ "RDTSC",
+ "RSM",
+ "SFENCE",
+ "SYSRET",
+ "WBINVD",
+ "WRMSR",
+ "XADDB",
+ "XADDL",
+ "XADDW",
+ "CMOVLCC",
+ "CMOVLCS",
+ "CMOVLEQ",
+ "CMOVLGE",
+ "CMOVLGT",
+ "CMOVLHI",
+ "CMOVLLE",
+ "CMOVLLS",
+ "CMOVLLT",
+ "CMOVLMI",
+ "CMOVLNE",
+ "CMOVLOC",
+ "CMOVLOS",
+ "CMOVLPC",
+ "CMOVLPL",
+ "CMOVLPS",
+ "CMOVQCC",
+ "CMOVQCS",
+ "CMOVQEQ",
+ "CMOVQGE",
+ "CMOVQGT",
+ "CMOVQHI",
+ "CMOVQLE",
+ "CMOVQLS",
+ "CMOVQLT",
+ "CMOVQMI",
+ "CMOVQNE",
+ "CMOVQOC",
+ "CMOVQOS",
+ "CMOVQPC",
+ "CMOVQPL",
+ "CMOVQPS",
+ "CMOVWCC",
+ "CMOVWCS",
+ "CMOVWEQ",
+ "CMOVWGE",
+ "CMOVWGT",
+ "CMOVWHI",
+ "CMOVWLE",
+ "CMOVWLS",
+ "CMOVWLT",
+ "CMOVWMI",
+ "CMOVWNE",
+ "CMOVWOC",
+ "CMOVWOS",
+ "CMOVWPC",
+ "CMOVWPL",
+ "CMOVWPS",
+ "ADCQ",
+ "ADDQ",
+ "ANDQ",
+ "BSFQ",
+ "BSRQ",
+ "BTCQ",
+ "BTQ",
+ "BTRQ",
+ "BTSQ",
+ "CMPQ",
+ "CMPSQ",
+ "CMPXCHGQ",
+ "CQO",
+ "DIVQ",
+ "IDIVQ",
+ "IMULQ",
+ "IRETQ",
+ "LEAQ",
+ "LEAVEQ",
+ "LODSQ",
+ "MOVQ",
+ "MOVLQSX",
+ "MOVLQZX",
+ "MOVNTIQ",
+ "MOVSQ",
+ "MULQ",
+ "NEGQ",
+ "NOTQ",
+ "ORQ",
+ "POPFQ",
+ "POPQ",
+ "PUSHFQ",
+ "PUSHQ",
+ "RCLQ",
+ "RCRQ",
+ "ROLQ",
+ "RORQ",
+ "QUAD",
+ "SALQ",
+ "SARQ",
+ "SBBQ",
+ "SCASQ",
+ "SHLQ",
+ "SHRQ",
+ "STOSQ",
+ "SUBQ",
+ "TESTQ",
+ "XADDQ",
+ "XCHGQ",
+ "XORQ",
+ "ADDPD",
+ "ADDPS",
+ "ADDSD",
+ "ADDSS",
+ "ANDNPD",
+ "ANDNPS",
+ "ANDPD",
+ "ANDPS",
+ "CMPPD",
+ "CMPPS",
+ "CMPSD",
+ "CMPSS",
+ "COMISD",
+ "COMISS",
+ "CVTPD2PL",
+ "CVTPD2PS",
+ "CVTPL2PD",
+ "CVTPL2PS",
+ "CVTPS2PD",
+ "CVTPS2PL",
+ "CVTSD2SL",
+ "CVTSD2SQ",
+ "CVTSD2SS",
+ "CVTSL2SD",
+ "CVTSL2SS",
+ "CVTSQ2SD",
+ "CVTSQ2SS",
+ "CVTSS2SD",
+ "CVTSS2SL",
+ "CVTSS2SQ",
+ "CVTTPD2PL",
+ "CVTTPS2PL",
+ "CVTTSD2SL",
+ "CVTTSD2SQ",
+ "CVTTSS2SL",
+ "CVTTSS2SQ",
+ "DIVPD",
+ "DIVPS",
+ "DIVSD",
+ "DIVSS",
+ "EMMS",
+ "FXRSTOR",
+ "FXRSTOR64",
+ "FXSAVE",
+ "FXSAVE64",
+ "LDMXCSR",
+ "MASKMOVOU",
+ "MASKMOVQ",
+ "MAXPD",
+ "MAXPS",
+ "MAXSD",
+ "MAXSS",
+ "MINPD",
+ "MINPS",
+ "MINSD",
+ "MINSS",
+ "MOVAPD",
+ "MOVAPS",
+ "MOVOU",
+ "MOVHLPS",
+ "MOVHPD",
+ "MOVHPS",
+ "MOVLHPS",
+ "MOVLPD",
+ "MOVLPS",
+ "MOVMSKPD",
+ "MOVMSKPS",
+ "MOVNTO",
+ "MOVNTPD",
+ "MOVNTPS",
+ "MOVNTQ",
+ "MOVO",
+ "MOVQOZX",
+ "MOVSD",
+ "MOVSS",
+ "MOVUPD",
+ "MOVUPS",
+ "MULPD",
+ "MULPS",
+ "MULSD",
+ "MULSS",
+ "ORPD",
+ "ORPS",
+ "PACKSSLW",
+ "PACKSSWB",
+ "PACKUSWB",
+ "PADDB",
+ "PADDL",
+ "PADDQ",
+ "PADDSB",
+ "PADDSW",
+ "PADDUSB",
+ "PADDUSW",
+ "PADDW",
+ "PANDB",
+ "PANDL",
+ "PANDSB",
+ "PANDSW",
+ "PANDUSB",
+ "PANDUSW",
+ "PANDW",
+ "PAND",
+ "PANDN",
+ "PAVGB",
+ "PAVGW",
+ "PCMPEQB",
+ "PCMPEQL",
+ "PCMPEQW",
+ "PCMPGTB",
+ "PCMPGTL",
+ "PCMPGTW",
+ "PEXTRW",
+ "PFACC",
+ "PFADD",
+ "PFCMPEQ",
+ "PFCMPGE",
+ "PFCMPGT",
+ "PFMAX",
+ "PFMIN",
+ "PFMUL",
+ "PFNACC",
+ "PFPNACC",
+ "PFRCP",
+ "PFRCPIT1",
+ "PFRCPI2T",
+ "PFRSQIT1",
+ "PFRSQRT",
+ "PFSUB",
+ "PFSUBR",
+ "PINSRW",
+ "PMADDWL",
+ "PMAXSW",
+ "PMAXUB",
+ "PMINSW",
+ "PMINUB",
+ "PMOVMSKB",
+ "PMULHRW",
+ "PMULHUW",
+ "PMULHW",
+ "PMULLW",
+ "PMULULQ",
+ "POR",
+ "PSADBW",
+ "PSHUFHW",
+ "PSHUFL",
+ "PSHUFLW",
+ "PSHUFW",
+ "PSLLO",
+ "PSLLL",
+ "PSLLQ",
+ "PSLLW",
+ "PSRAL",
+ "PSRAW",
+ "PSRLO",
+ "PSRLL",
+ "PSRLQ",
+ "PSRLW",
+ "PSUBB",
+ "PSUBL",
+ "PSUBQ",
+ "PSUBSB",
+ "PSUBSW",
+ "PSUBUSB",
+ "PSUBUSW",
+ "PSUBW",
+ "PSWAPL",
+ "PUNPCKHBW",
+ "PUNPCKHLQ",
+ "PUNPCKHQDQ",
+ "PUNPCKHWL",
+ "PUNPCKLBW",
+ "PUNPCKLLQ",
+ "PUNPCKLQDQ",
+ "PUNPCKLWL",
+ "PXOR",
+ "RCPPS",
+ "RCPSS",
+ "RSQRTPS",
+ "RSQRTSS",
+ "SHUFPD",
+ "SHUFPS",
+ "SQRTPD",
+ "SQRTPS",
+ "SQRTSD",
+ "SQRTSS",
+ "STMXCSR",
+ "SUBPD",
+ "SUBPS",
+ "SUBSD",
+ "SUBSS",
+ "UCOMISD",
+ "UCOMISS",
+ "UNPCKHPD",
+ "UNPCKHPS",
+ "UNPCKLPD",
+ "UNPCKLPS",
+ "XORPD",
+ "XORPS",
+ "PF2IW",
+ "PF2IL",
+ "PI2FW",
+ "PI2FL",
+ "RETFW",
+ "RETFL",
+ "RETFQ",
+ "SWAPGS",
+ "MODE",
+ "LAST",
+};
diff --git a/sys/src/cmd/6c/gc.h b/sys/src/cmd/6c/gc.h
new file mode 100644
index 000000000..57d3a9994
--- /dev/null
+++ b/sys/src/cmd/6c/gc.h
@@ -0,0 +1,381 @@
+#include "../cc/cc.h"
+#include "../6c/6.out.h"
+
+/*
+ * 6c/amd64
+ * Intel 386 with AMD64 extensions
+ */
+#define SZ_CHAR 1
+#define SZ_SHORT 2
+#define SZ_INT 4
+#define SZ_LONG 4
+#define SZ_IND 8
+#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 Var Var;
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+typedef struct Renv Renv;
+
+EXTERN struct
+{
+ Node* regtree;
+ Node* basetree;
+ short scale;
+ short reg;
+ short ptr;
+} idx;
+
+struct Adr
+{
+ vlong offset;
+ double dval;
+ char sval[NSNAME];
+
+ Sym* sym;
+ uchar type;
+ uchar index;
+ uchar etype;
+ uchar scale; /* doubles as width in DATA op */
+};
+#define A ((Adr*)0)
+
+#define INDEXED 9
+struct Prog
+{
+ Adr from;
+ Adr to;
+ Prog* link;
+ long lineno;
+ short as;
+};
+#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 Var
+{
+ vlong 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)
+
+struct Renv
+{
+ int safe;
+ Node base;
+ Node* saved;
+ Node* scope;
+};
+
+#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 Node* nodrat;
+EXTERN Node* nodret;
+EXTERN Node* nodsafe;
+EXTERN long nrathole;
+EXTERN long nstring;
+EXTERN Prog* p;
+EXTERN long pc;
+EXTERN Node lregnode;
+EXTERN Node qregnode;
+EXTERN char string[NSNAME];
+EXTERN Sym* symrathole;
+EXTERN Node znode;
+EXTERN Prog zprog;
+EXTERN int reg[D_NONE];
+EXTERN long exregoffset;
+EXTERN long exfregoffset;
+EXTERN uchar typechlpv[NTYPE];
+
+#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 5
+#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[];
+
+/*
+ * sgen.c
+ */
+void codgen(Node*, Node*);
+void gen(Node*);
+void noretval(int);
+void usedset(Node*, int);
+void xcom(Node*);
+void indx(Node*);
+int bcomplex(Node*, Node*);
+
+/*
+ * cgen.c
+ */
+void zeroregm(Node*);
+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);
+int needreg(Node*, int);
+int hardconst(Node*);
+int immconst(Node*);
+
+/*
+ * cgen64.c
+ */
+int vaddr(Node*, int);
+void loadpair(Node*, Node*);
+int cgen64(Node*, Node*);
+void testv(Node*, int);
+
+/*
+ * 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* nodfconst(double);
+Node* nodgconst(vlong, Type*);
+int nodreg(Node*, Node*, int);
+int isreg(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 naddr(Node*, Adr*);
+void gcmp(int, Node*, vlong);
+void gmove(Node*, Node*);
+void gins(int a, Node*, Node*);
+void gopcode(int, Type*, Node*, Node*);
+int samaddr(Node*, Node*);
+void gbranch(int);
+void patch(Prog*, long);
+int sconst(Node*);
+void gpseudo(int, Sym*, Node*);
+
+/*
+ * swt.c
+ */
+int swcmp(const void*, const void*);
+void doswit(Node*);
+void swit1(C1*, int, long, Node*);
+void casf(void);
+void bitload(Node*, Node*, Node*, Node*, Node*);
+void bitstore(Node*, Node*, Node*, Node*, Node*);
+long outstring(char*, long);
+void nullwarn(Node*, Node*);
+void sextern(Sym*, Node*, long, long);
+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 Rconv(Fmt*);
+int Xconv(Fmt*);
+int Bconv(Fmt*);
+
+/*
+ * reg.c
+ */
+Reg* rega(void);
+int rcmp(const void*, const void*);
+void regopt(Prog*);
+void addmove(Reg*, int, int, int);
+Bits mkvar(Reg*, Adr*);
+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 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 copysub(Adr*, Adr*, Adr*, int);
+int copysub1(Prog*, Adr*, Adr*, int);
+
+long RtoB(int);
+long FtoB(int);
+int BtoR(long);
+int BtoF(long);
+
+#define D_HI D_NONE
+#define D_LO D_NONE
+
+#define isregtype(t) ((t)>= D_AX && (t)<=D_R15)
+
+/*
+ * bound
+ */
+void comtarg(void);
+
+/*
+ * com64
+ */
+int cond(int);
+int com64(Node*);
+void com64init(void);
+void bool64(Node*);
+long lo64v(Node*);
+long hi64v(Node*);
+Node* lo64(Node*);
+Node* hi64(Node*);
+
+/*
+ * div/mul
+ */
+void sdivgen(Node*, Node*, Node*, Node*);
+void udivgen(Node*, Node*, Node*, Node*);
+void sdiv2(long, int, Node*, Node*);
+void smod2(long, int, Node*, Node*);
+void mulgen(Type*, Node*, Node*);
+void genmuladd(Node*, Node*, int, Node*);
+void shiftit(Type*, Node*, Node*);
+
+#pragma varargck type "A" int
+#pragma varargck type "B" Bits
+#pragma varargck type "D" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "R" int
+#pragma varargck type "S" char*
+
+#define D_X7 (D_X0+7)
+
+void fgopcode(int, Node*, Node*, int, int);
diff --git a/sys/src/cmd/6c/list.c b/sys/src/cmd/6c/list.c
new file mode 100644
index 000000000..73efdf139
--- /dev/null
+++ b/sys/src/cmd/6c/list.c
@@ -0,0 +1,337 @@
+#define EXTERN
+#include "gc.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv);
+ fmtinstall('B', Bconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('R', Rconv);
+}
+
+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, "$%lld", 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;
+
+ p = va_arg(fp->args, Prog*);
+ if(p->as == ADATA)
+ sprint(str, " %A %D/%d,%D",
+ p->as, &p->from, p->from.scale, &p->to);
+ else if(p->as == ATEXT)
+ sprint(str, " %A %D,%d,%D",
+ p->as, &p->from, p->from.scale, &p->to);
+ else
+ sprint(str, " %A %D,%D",
+ p->as, &p->from, &p->to);
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ int i;
+
+ i = va_arg(fp->args, int);
+ return fmtstrcpy(fp, anames[i]);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[40], s[20];
+ Adr *a;
+ int i;
+
+ a = va_arg(fp->args, Adr*);
+ i = a->type;
+ if(i >= D_INDIR) {
+ if(a->offset)
+ sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
+ else
+ sprint(str, "(%R)", i-D_INDIR);
+ goto brk;
+ }
+ switch(i) {
+
+ default:
+ if(a->offset)
+ sprint(str, "$%lld,%R", a->offset, i);
+ else
+ sprint(str, "%R", i);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ break;
+
+ case D_BRANCH:
+ sprint(str, "%lld(PC)", a->offset-pc);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%lld(SB)", a->sym->name,
+ a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
+ break;
+
+ case D_PARAM:
+ if(a->sym)
+ sprint(str, "%s+%lld(FP)", a->sym->name, a->offset);
+ else
+ sprint(str, "%lld(FP)", a->offset);
+ break;
+
+ case D_CONST:
+ sprint(str, "$%lld", a->offset);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$(%.17e)", a->dval);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ break;
+
+ case D_ADDR:
+ a->type = a->index;
+ a->index = D_NONE;
+ sprint(str, "$%D", a);
+ a->index = a->type;
+ a->type = D_ADDR;
+ goto conv;
+ }
+brk:
+ if(a->index != D_NONE) {
+ sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
+ strcat(str, s);
+ }
+conv:
+ return fmtstrcpy(fp, str);
+}
+
+char* regstr[] =
+{
+ "AL", /* [D_AL] */
+ "CL",
+ "DL",
+ "BL",
+ "SPB",
+ "BPB",
+ "SIB",
+ "DIB",
+ "R8B",
+ "R9B",
+ "R10B",
+ "R11B",
+ "R12B",
+ "R13B",
+ "R14B",
+ "R15B",
+
+ "AX", /* [D_AX] */
+ "CX",
+ "DX",
+ "BX",
+ "SP",
+ "BP",
+ "SI",
+ "DI",
+ "R8",
+ "R9",
+ "R10",
+ "R11",
+ "R12",
+ "R13",
+ "R14",
+ "R15",
+
+ "AH",
+ "CH",
+ "DH",
+ "BH",
+
+ "F0", /* [D_F0] */
+ "F1",
+ "F2",
+ "F3",
+ "F4",
+ "F5",
+ "F6",
+ "F7",
+
+ "M0",
+ "M1",
+ "M2",
+ "M3",
+ "M4",
+ "M5",
+ "M6",
+ "M7",
+
+ "X0",
+ "X1",
+ "X2",
+ "X3",
+ "X4",
+ "X5",
+ "X6",
+ "X7",
+ "X8",
+ "X9",
+ "X10",
+ "X11",
+ "X12",
+ "X13",
+ "X14",
+ "X15",
+
+ "CS", /* [D_CS] */
+ "SS",
+ "DS",
+ "ES",
+ "FS",
+ "GS",
+
+ "GDTR", /* [D_GDTR] */
+ "IDTR", /* [D_IDTR] */
+ "LDTR", /* [D_LDTR] */
+ "MSW", /* [D_MSW] */
+ "TASK", /* [D_TASK] */
+
+ "CR0", /* [D_CR] */
+ "CR1",
+ "CR2",
+ "CR3",
+ "CR4",
+ "CR5",
+ "CR6",
+ "CR7",
+ "CR8",
+ "CR9",
+ "CR10",
+ "CR11",
+ "CR12",
+ "CR13",
+ "CR14",
+ "CR15",
+
+ "DR0", /* [D_DR] */
+ "DR1",
+ "DR2",
+ "DR3",
+ "DR4",
+ "DR5",
+ "DR6",
+ "DR7",
+
+ "TR0", /* [D_TR] */
+ "TR1",
+ "TR2",
+ "TR3",
+ "TR4",
+ "TR5",
+ "TR6",
+ "TR7",
+
+ "NONE", /* [D_NONE] */
+};
+
+int
+Rconv(Fmt *fp)
+{
+ char str[20];
+ int r;
+
+ r = va_arg(fp->args, int);
+ if(r >= D_AL && r <= D_NONE)
+ sprint(str, "%s", regstr[r-D_AL]);
+ else
+ sprint(str, "gok(%d)", r);
+
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[30], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(double); i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ default:
+ if(c < 040 || c >= 0177)
+ break; /* not portable */
+ p[-1] = c;
+ continue;
+ 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);
+}
diff --git a/sys/src/cmd/6c/machcap.c b/sys/src/cmd/6c/machcap.c
new file mode 100644
index 000000000..68c7fa8d2
--- /dev/null
+++ b/sys/src/cmd/6c/machcap.c
@@ -0,0 +1,78 @@
+#include "gc.h"
+
+int
+machcap(Node *n)
+{
+
+ if(n == Z)
+ return 1; /* test */
+
+ switch(n->op) {
+ case OMUL:
+ case OLMUL:
+ case OASMUL:
+ case OASLMUL:
+ if(typechl[n->type->etype])
+ return 1;
+ if(typev[n->type->etype]) {
+ return 1;
+ }
+ break;
+
+ case OCOM:
+ case ONEG:
+ case OADD:
+ case OAND:
+ case OOR:
+ case OSUB:
+ case OXOR:
+ case OASHL:
+ case OLSHR:
+ case OASHR:
+ if(typechlv[n->left->type->etype])
+ return 1;
+ break;
+
+ case OCAST:
+ return 1;
+
+ case OCOND:
+ case OCOMMA:
+ case OLIST:
+ case OANDAND:
+ case OOROR:
+ case ONOT:
+ return 1;
+
+ case OASADD:
+ case OASSUB:
+ case OASAND:
+ case OASOR:
+ case OASXOR:
+ return 1;
+
+ case OASASHL:
+ case OASASHR:
+ case OASLSHR:
+ return 1;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ case OPREINC:
+ case OPREDEC:
+ return 1;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OGT:
+ case OLT:
+ case OGE:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ return 1;
+ }
+ return 0;
+}
diff --git a/sys/src/cmd/6c/mkenam b/sys/src/cmd/6c/mkenam
new file mode 100644
index 000000000..32cb1d958
--- /dev/null
+++ b/sys/src/cmd/6c/mkenam
@@ -0,0 +1,15 @@
+ed - ../6c/6.out.h <<'!'
+v/^ A/d
+,s/^ A/ "/
+g/ .*$/s///
+,s/,*$/",/
+1i
+char* anames[] =
+{
+.
+$a
+};
+.
+w enam.c
+Q
+!
diff --git a/sys/src/cmd/6c/mkfile b/sys/src/cmd/6c/mkfile
new file mode 100644
index 000000000..18dea3867
--- /dev/null
+++ b/sys/src/cmd/6c/mkfile
@@ -0,0 +1,38 @@
+</$objtype/mkfile
+
+TARG=6c
+OFILES=\
+ cgen.$O\
+ enam.$O\
+ list.$O\
+ sgen.$O\
+ swt.$O\
+ txt.$O\
+ reg.$O\
+ peep.$O\
+ pgen.$O\
+ pswt.$O\
+ machcap.$O\
+ div.$O\
+ mul.$O\
+
+HFILES=\
+ gc.h\
+ 6.out.h\
+ ../cc/cc.h\
+
+LIB=../cc/cc.a$O
+
+BIN=/$objtype/bin
+</sys/src/cmd/mkone
+
+$LIB:
+ cd ../cc
+ mk install
+ mk clean
+
+%.$O: ../cc/%.c
+ $CC $CFLAGS ../cc/$stem.c
+
+bound.$O: bound.h
+
diff --git a/sys/src/cmd/6c/mul.c b/sys/src/cmd/6c/mul.c
new file mode 100644
index 000000000..a60908c64
--- /dev/null
+++ b/sys/src/cmd/6c/mul.c
@@ -0,0 +1,428 @@
+#include "gc.h"
+
+typedef struct Malg Malg;
+typedef struct Mparam Mparam;
+
+struct Malg
+{
+ char vals[10];
+};
+
+struct Mparam
+{
+ ulong value;
+ char alg;
+ char neg;
+ char shift;
+ char arg;
+ char off;
+};
+
+static Mparam multab[32];
+static int mulptr;
+
+static Malg malgs[] =
+{
+ {0, 100},
+ {-1, 1, 100},
+ {-9, -5, -3, 3, 5, 9, 100},
+ {6, 10, 12, 18, 20, 24, 36, 40, 72, 100},
+ {-8, -4, -2, 2, 4, 8, 100},
+};
+
+/*
+ * return position of lowest 1
+ */
+int
+lowbit(ulong v)
+{
+ int s, i;
+ ulong m;
+
+ s = 0;
+ m = 0xFFFFFFFFUL;
+ for(i = 16; i > 0; i >>= 1) {
+ m >>= i;
+ if((v & m) == 0) {
+ v >>= i;
+ s += i;
+ }
+ }
+ return s;
+}
+
+void
+genmuladd(Node *d, Node *s, int m, Node *a)
+{
+ Node nod;
+
+ nod.op = OINDEX;
+ nod.left = a;
+ nod.right = s;
+ nod.scale = m;
+ nod.type = types[TIND];
+ nod.xoffset = 0;
+ xcom(&nod);
+ gopcode(OADDR, d->type, &nod, d);
+}
+
+void
+mulparam(ulong m, Mparam *mp)
+{
+ int c, i, j, n, o, q, s;
+ int bc, bi, bn, bo, bq, bs, bt;
+ char *p;
+ long u;
+ ulong t;
+
+ bc = bq = 10;
+ bi = bn = bo = bs = bt = 0;
+ for(i = 0; i < nelem(malgs); i++) {
+ for(p = malgs[i].vals, j = 0; (o = p[j]) < 100; j++)
+ for(s = 0; s < 2; s++) {
+ c = 10;
+ q = 10;
+ u = m - o;
+ if(u == 0)
+ continue;
+ if(s) {
+ o = -o;
+ if(o > 0)
+ continue;
+ u = -u;
+ }
+ n = lowbit(u);
+ t = (ulong)u >> n;
+ switch(i) {
+ case 0:
+ if(t == 1) {
+ c = s + 1;
+ q = 0;
+ break;
+ }
+ switch(t) {
+ case 3:
+ case 5:
+ case 9:
+ c = s + 1;
+ if(n)
+ c++;
+ q = 0;
+ break;
+ }
+ if(s)
+ break;
+ switch(t) {
+ case 15:
+ case 25:
+ case 27:
+ case 45:
+ case 81:
+ c = 2;
+ if(n)
+ c++;
+ q = 1;
+ break;
+ }
+ break;
+ case 1:
+ if(t == 1) {
+ c = 3;
+ q = 3;
+ break;
+ }
+ switch(t) {
+ case 3:
+ case 5:
+ case 9:
+ c = 3;
+ q = 2;
+ break;
+ }
+ break;
+ case 2:
+ if(t == 1) {
+ c = 3;
+ q = 2;
+ break;
+ }
+ break;
+ case 3:
+ if(s)
+ break;
+ if(t == 1) {
+ c = 3;
+ q = 1;
+ break;
+ }
+ break;
+ case 4:
+ if(t == 1) {
+ c = 3;
+ q = 0;
+ break;
+ }
+ break;
+ }
+ if(c < bc || (c == bc && q > bq)) {
+ bc = c;
+ bi = i;
+ bn = n;
+ bo = o;
+ bq = q;
+ bs = s;
+ bt = t;
+ }
+ }
+ }
+ mp->value = m;
+ if(bc <= 3) {
+ mp->alg = bi;
+ mp->shift = bn;
+ mp->off = bo;
+ mp->neg = bs;
+ mp->arg = bt;
+ }
+ else
+ mp->alg = -1;
+}
+
+int
+m0(int a)
+{
+ switch(a) {
+ case -2:
+ case 2:
+ return 2;
+ case -3:
+ case 3:
+ return 2;
+ case -4:
+ case 4:
+ return 4;
+ case -5:
+ case 5:
+ return 4;
+ case 6:
+ return 2;
+ case -8:
+ case 8:
+ return 8;
+ case -9:
+ case 9:
+ return 8;
+ case 10:
+ return 4;
+ case 12:
+ return 2;
+ case 15:
+ return 2;
+ case 18:
+ return 8;
+ case 20:
+ return 4;
+ case 24:
+ return 2;
+ case 25:
+ return 4;
+ case 27:
+ return 2;
+ case 36:
+ return 8;
+ case 40:
+ return 4;
+ case 45:
+ return 4;
+ case 72:
+ return 8;
+ case 81:
+ return 8;
+ }
+ diag(Z, "bad m0");
+ return 0;
+}
+
+int
+m1(int a)
+{
+ switch(a) {
+ case 15:
+ return 4;
+ case 25:
+ return 4;
+ case 27:
+ return 8;
+ case 45:
+ return 8;
+ case 81:
+ return 8;
+ }
+ diag(Z, "bad m1");
+ return 0;
+}
+
+int
+m2(int a)
+{
+ switch(a) {
+ case 6:
+ return 2;
+ case 10:
+ return 2;
+ case 12:
+ return 4;
+ case 18:
+ return 2;
+ case 20:
+ return 4;
+ case 24:
+ return 8;
+ case 36:
+ return 4;
+ case 40:
+ return 8;
+ case 72:
+ return 8;
+ }
+ diag(Z, "bad m2");
+ return 0;
+}
+
+void
+shiftit(Type *t, Node *s, Node *d)
+{
+ long c;
+
+ c = (long)s->vconst & 31;
+ switch(c) {
+ case 0:
+ break;
+ case 1:
+ gopcode(OADD, t, d, d);
+ break;
+ default:
+ gopcode(OASHL, t, s, d);
+ }
+}
+
+static int
+mulgen1(ulong v, Node *n)
+{
+ int i, o;
+ Mparam *p;
+ Node nod, nods;
+
+ for(i = 0; i < nelem(multab); i++) {
+ p = &multab[i];
+ if(p->value == v)
+ goto found;
+ }
+
+ p = &multab[mulptr];
+ if(++mulptr == nelem(multab))
+ mulptr = 0;
+
+ mulparam(v, p);
+
+found:
+// print("v=%.lx a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
+ if(p->alg < 0)
+ return 0;
+
+ nods = *nodconst(p->shift);
+
+ o = OADD;
+ if(p->alg > 0) {
+ regalloc(&nod, n, Z);
+ if(p->off < 0)
+ o = OSUB;
+ }
+
+ switch(p->alg) {
+ case 0:
+ switch(p->arg) {
+ case 1:
+ shiftit(n->type, &nods, n);
+ break;
+ case 15:
+ case 25:
+ case 27:
+ case 45:
+ case 81:
+ genmuladd(n, n, m1(p->arg), n);
+ /* fall thru */
+ case 3:
+ case 5:
+ case 9:
+ genmuladd(n, n, m0(p->arg), n);
+ shiftit(n->type, &nods, n);
+ break;
+ default:
+ goto bad;
+ }
+ if(p->neg == 1)
+ gins(ANEGL, Z, n);
+ break;
+ case 1:
+ switch(p->arg) {
+ case 1:
+ gmove(n, &nod);
+ shiftit(n->type, &nods, &nod);
+ break;
+ case 3:
+ case 5:
+ case 9:
+ genmuladd(&nod, n, m0(p->arg), n);
+ shiftit(n->type, &nods, &nod);
+ break;
+ default:
+ goto bad;
+ }
+ if(p->neg)
+ gopcode(o, n->type, &nod, n);
+ else {
+ gopcode(o, n->type, n, &nod);
+ gmove(&nod, n);
+ }
+ break;
+ case 2:
+ genmuladd(&nod, n, m0(p->off), n);
+ shiftit(n->type, &nods, n);
+ goto comop;
+ case 3:
+ genmuladd(&nod, n, m0(p->off), n);
+ shiftit(n->type, &nods, n);
+ genmuladd(n, &nod, m2(p->off), n);
+ break;
+ case 4:
+ genmuladd(&nod, n, m0(p->off), nodconst(0));
+ shiftit(n->type, &nods, n);
+ goto comop;
+ default:
+ diag(Z, "bad mul alg");
+ break;
+ comop:
+ if(p->neg) {
+ gopcode(o, n->type, n, &nod);
+ gmove(&nod, n);
+ }
+ else
+ gopcode(o, n->type, &nod, n);
+ }
+
+ if(p->alg > 0)
+ regfree(&nod);
+
+ return 1;
+
+bad:
+ diag(Z, "mulgen botch");
+ return 1;
+}
+
+void
+mulgen(Type *t, Node *r, Node *n)
+{
+ if(!mulgen1(r->vconst, n))
+ gopcode(OMUL, t, r, n);
+}
diff --git a/sys/src/cmd/6c/peep.c b/sys/src/cmd/6c/peep.c
new file mode 100644
index 000000000..2511b6c7e
--- /dev/null
+++ b/sys/src/cmd/6c/peep.c
@@ -0,0 +1,846 @@
+#include "gc.h"
+
+static int
+needc(Prog *p)
+{
+ while(p != P) {
+ switch(p->as) {
+ case AADCL:
+ case AADCQ:
+ case ASBBL:
+ case ASBBQ:
+ case ARCRL:
+ case ARCRQ:
+ return 1;
+ case AADDL:
+ case AADDQ:
+ case ASUBL:
+ case ASUBQ:
+ case AJMP:
+ case ARET:
+ case ACALL:
+ return 0;
+ default:
+ if(p->to.type == D_BRANCH)
+ return 0;
+ }
+ p = p->link;
+ }
+ return 0;
+}
+
+static Reg*
+rnops(Reg *r)
+{
+ Prog *p;
+ Reg *r1;
+
+ if(r != R)
+ for(;;){
+ p = r->prog;
+ if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
+ break;
+ r1 = uniqs(r);
+ if(r1 == R)
+ break;
+ r = r1;
+ }
+ return r;
+}
+
+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;
+ }
+ }
+
+ pc = 0; /* speculating it won't kill */
+
+loop1:
+
+ t = 0;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ case AMOVL:
+ case AMOVQ:
+ case AMOVSS:
+ case AMOVSD:
+ if(regtyp(&p->to))
+ if(regtyp(&p->from)) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ break;
+
+ case AMOVBLZX:
+ case AMOVWLZX:
+ case AMOVBLSX:
+ case AMOVWLSX:
+ if(regtyp(&p->to)) {
+ r1 = rnops(uniqs(r));
+ if(r1 != R) {
+ p1 = r1->prog;
+ if(p->as == p1->as && p->to.type == p1->from.type){
+ p1->as = AMOVL;
+ t++;
+ }
+ }
+ }
+ break;
+
+ case AMOVBQSX:
+ case AMOVBQZX:
+ case AMOVWQSX:
+ case AMOVWQZX:
+ case AMOVLQSX:
+ case AMOVLQZX:
+ if(regtyp(&p->to)) {
+ r1 = rnops(uniqs(r));
+ if(r1 != R) {
+ p1 = r1->prog;
+ if(p->as == p1->as && p->to.type == p1->from.type){
+ p1->as = AMOVQ;
+ t++;
+ }
+ }
+ }
+ break;
+
+ case AADDL:
+ case AADDQ:
+ case AADDW:
+ if(p->from.type != D_CONST || needc(p->link))
+ break;
+ if(p->from.offset == -1){
+ if(p->as == AADDQ)
+ p->as = ADECQ;
+ else if(p->as == AADDL)
+ p->as = ADECL;
+ else
+ p->as = ADECW;
+ p->from = zprog.from;
+ }
+ else if(p->from.offset == 1){
+ if(p->as == AADDQ)
+ p->as = AINCQ;
+ else if(p->as == AADDL)
+ p->as = AINCL;
+ else
+ p->as = AINCW;
+ p->from = zprog.from;
+ }
+ break;
+
+ case ASUBL:
+ case ASUBQ:
+ case ASUBW:
+ if(p->from.type != D_CONST || needc(p->link))
+ break;
+ if(p->from.offset == -1) {
+ if(p->as == ASUBQ)
+ p->as = AINCQ;
+ else if(p->as == ASUBL)
+ p->as = AINCL;
+ else
+ p->as = AINCW;
+ p->from = zprog.from;
+ }
+ else if(p->from.offset == 1){
+ if(p->as == ASUBQ)
+ p->as = ADECQ;
+ else if(p->as == ASUBL)
+ p->as = ADECL;
+ else
+ p->as = ADECW;
+ p->from = zprog.from;
+ }
+ break;
+ }
+ }
+ if(t)
+ goto loop1;
+}
+
+void
+excise(Reg *r)
+{
+ Prog *p;
+
+ p = r->prog;
+ p->as = ANOP;
+ p->from = zprog.from;
+ p->to = zprog.to;
+}
+
+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
+regtyp(Adr *a)
+{
+ int t;
+
+ t = a->type;
+ if(t >= D_AX && t <= D_R15)
+ return 1;
+ if(t >= D_X0 && t <= D_X0+15)
+ 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 ACALL:
+ return 0;
+
+ case AIMULL:
+ case AIMULQ:
+ case AIMULW:
+ if(p->to.type != D_NONE)
+ break;
+
+ case ADIVB:
+ case ADIVL:
+ case ADIVQ:
+ case ADIVW:
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVQ:
+ case AIDIVW:
+ case AIMULB:
+ case AMULB:
+ case AMULL:
+ case AMULQ:
+ case AMULW:
+
+ case AROLB:
+ case AROLL:
+ case AROLQ:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORQ:
+ case ARORW:
+ case ASALB:
+ case ASALL:
+ case ASALQ:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARQ:
+ case ASARW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLQ:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRQ:
+ case ASHRW:
+
+ case AREP:
+ case AREPN:
+
+ case ACWD:
+ case ACDQ:
+ case ACQO:
+
+ case AMOVSL:
+ case AMOVSQ:
+ return 0;
+
+ case AMOVL:
+ case AMOVQ:
+ if(p->to.type == v1->type)
+ goto gotit;
+ break;
+ }
+ if(copyau(&p->from, v2) ||
+ copyau(&p->to, v2))
+ break;
+ if(copysub(&p->from, 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);
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P'])
+ print("%P\n", r->prog);
+ }
+ t = v1->type;
+ v1->type = v2->type;
+ v2->type = 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("; %D rar; return 0\n", v2);
+ return 0;
+
+ case 3: /* set */
+ if(debug['P'])
+ print("; %D set; 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("; %D used+set and f=%d; return 0\n", v2, f);
+ else
+ print("; %D used 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("; %D used+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("; %D set 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);
+ /* SBBL; ADCL; FLD1; SAHF */
+ return 2;
+
+
+ case ANEGB:
+ case ANEGW:
+ case ANEGL:
+ case ANEGQ:
+ case ANOTB:
+ case ANOTW:
+ case ANOTL:
+ case ANOTQ:
+ if(copyas(&p->to, v))
+ return 2;
+ break;
+
+ case ALEAL: /* lhs addr, rhs store */
+ case ALEAQ:
+ if(copyas(&p->from, v))
+ return 2;
+
+
+ case ANOP: /* rhs store */
+ case AMOVL:
+ case AMOVQ:
+ case AMOVBLSX:
+ case AMOVBLZX:
+ case AMOVBQSX:
+ case AMOVBQZX:
+ case AMOVLQSX:
+ case AMOVLQZX:
+ case AMOVWLSX:
+ case AMOVWLZX:
+ case AMOVWQSX:
+ case AMOVWQZX:
+
+ case AMOVSS:
+ case AMOVSD:
+ case ACVTSD2SL:
+ case ACVTSD2SQ:
+ case ACVTSD2SS:
+ case ACVTSL2SD:
+ case ACVTSL2SS:
+ case ACVTSQ2SD:
+ case ACVTSQ2SS:
+ case ACVTSS2SD:
+ case ACVTSS2SL:
+ case ACVTSS2SQ:
+ case ACVTTSD2SL:
+ case ACVTTSD2SQ:
+ case ACVTTSS2SL:
+ case ACVTTSS2SQ:
+ if(copyas(&p->to, v)) {
+ if(s != A)
+ return copysub(&p->from, v, s, 1);
+ if(copyau(&p->from, v))
+ return 4;
+ return 3;
+ }
+ goto caseread;
+
+ case AROLB:
+ case AROLL:
+ case AROLQ:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORQ:
+ case ARORW:
+ case ASALB:
+ case ASALL:
+ case ASALQ:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARQ:
+ case ASARW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLQ:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRQ:
+ case ASHRW:
+ if(copyas(&p->to, v))
+ return 2;
+ if(copyas(&p->from, v))
+ if(p->from.type == D_CX)
+ return 2;
+ goto caseread;
+
+ case AADDB: /* rhs rar */
+ case AADDL:
+ case AADDQ:
+ case AADDW:
+ case AANDB:
+ case AANDL:
+ case AANDQ:
+ case AANDW:
+ case ADECL:
+ case ADECQ:
+ case ADECW:
+ case AINCL:
+ case AINCQ:
+ case AINCW:
+ case ASUBB:
+ case ASUBL:
+ case ASUBQ:
+ case ASUBW:
+ case AORB:
+ case AORL:
+ case AORQ:
+ case AORW:
+ case AXORB:
+ case AXORL:
+ case AXORQ:
+ case AXORW:
+ case AMOVB:
+ case AMOVW:
+
+ case AADDSD:
+ case AADDSS:
+ case ACMPSD:
+ case ACMPSS:
+ case ADIVSD:
+ case ADIVSS:
+ case AMAXSD:
+ case AMAXSS:
+ case AMINSD:
+ case AMINSS:
+ case AMULSD:
+ case AMULSS:
+ case ARCPSS:
+ case ARSQRTSS:
+ case ASQRTSD:
+ case ASQRTSS:
+ case ASUBSD:
+ case ASUBSS:
+ case AXORPD:
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+
+ case ACMPL: /* read only */
+ case ACMPW:
+ case ACMPB:
+ case ACMPQ:
+
+ case ACOMISD:
+ case ACOMISS:
+ case AUCOMISD:
+ case AUCOMISS:
+ caseread:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return copysub(&p->to, v, s, 1);
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ break;
+
+ case AJGE: /* no reference */
+ case AJNE:
+ case AJLE:
+ case AJEQ:
+ case AJHI:
+ case AJLS:
+ case AJMI:
+ case AJPL:
+ case AJGT:
+ case AJLT:
+ case AJCC:
+ case AJCS:
+
+ case AADJSP:
+ case AWAIT:
+ case ACLD:
+ break;
+
+ case AIMULL:
+ case AIMULQ:
+ case AIMULW:
+ if(p->to.type != D_NONE) {
+ if(copyas(&p->to, v))
+ return 2;
+ goto caseread;
+ }
+
+ case ADIVB:
+ case ADIVL:
+ case ADIVQ:
+ case ADIVW:
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVQ:
+ case AIDIVW:
+ case AIMULB:
+ case AMULB:
+ case AMULL:
+ case AMULQ:
+ case AMULW:
+
+ case ACWD:
+ case ACDQ:
+ case ACQO:
+ if(v->type == D_AX || v->type == D_DX)
+ return 2;
+ goto caseread;
+
+ case AMOVSL:
+ case AMOVSQ:
+ case AREP:
+ case AREPN:
+ if(v->type == D_CX || v->type == D_DI || v->type == D_SI)
+ return 2;
+ goto caseread;
+
+ 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 == REGRET || v->type == FREGRET)
+ return 2;
+ if(s != A)
+ return 1;
+ return 3;
+
+ case ACALL: /* funny */
+ if(REGEXT && v->type <= REGEXT && v->type > exregoffset)
+ return 2;
+ if(REGARG && v->type == REGARG)
+ 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(REGARG && v->type == REGARG)
+ return 3;
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Adr *a, Adr *v)
+{
+ if(a->type != v->type)
+ return 0;
+ if(regtyp(v))
+ return 1;
+ if(v->type == D_AUTO || v->type == D_PARAM)
+ if(v->offset == a->offset)
+ return 1;
+ return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Adr *a, Adr *v)
+{
+
+ if(copyas(a, v))
+ return 1;
+ if(regtyp(v)) {
+ if(a->type-D_INDIR == v->type)
+ return 1;
+ if(a->index == 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)
+{
+ int t;
+
+ if(copyas(a, v)) {
+ t = s->type;
+ if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) {
+ if(f)
+ a->type = t;
+ }
+ return 0;
+ }
+ if(regtyp(v)) {
+ t = v->type;
+ if(a->type == t+D_INDIR) {
+ if((s->type == D_BP || s->type == D_R13) && a->index != D_NONE)
+ return 1; /* can't use BP-base with index */
+ if(f)
+ a->type = s->type+D_INDIR;
+// return 0;
+ }
+ if(a->index == t) {
+ if(f)
+ a->index = s->type;
+ return 0;
+ }
+ return 0;
+ }
+ return 0;
+}
diff --git a/sys/src/cmd/6c/reg.c b/sys/src/cmd/6c/reg.c
new file mode 100644
index 000000000..32b9abf5d
--- /dev/null
+++ b/sys/src/cmd/6c/reg.c
@@ -0,0 +1,1356 @@
+#include "gc.h"
+
+Reg*
+rega(void)
+{
+ Reg *r;
+
+ r = freer;
+ if(r == R) {
+ r = alloc(sizeof(*r));
+ } else
+ freer = r->link;
+
+ *r = zreg;
+ return r;
+}
+
+int
+rcmp(const void *a1, const 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 = RtoB(D_SP) | RtoB(D_AX) | RtoB(D_X0);
+ for(z=0; z<BITS; z++) {
+ externs.b[z] = 0;
+ params.b[z] = 0;
+ consts.b[z] = 0;
+ addrs.b[z] = 0;
+ }
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+ val = 5L * 5L * 5L * 5L * 5L;
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->m = 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:
+ case AIRETL:
+ case AIRETQ:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+
+ bit = mkvar(r, &p->from);
+ if(bany(&bit))
+ switch(p->as) {
+ /*
+ * funny
+ */
+ case ALEAL:
+ case ALEAQ:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * left side read
+ */
+ default:
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+ break;
+ }
+
+ bit = mkvar(r, &p->to);
+ if(bany(&bit))
+ switch(p->as) {
+ default:
+ diag(Z, "reg: unknown op: %A", p->as);
+ break;
+
+ /*
+ * right side read
+ */
+ case ACMPB:
+ case ACMPL:
+ case ACMPQ:
+ case ACMPW:
+ case ACOMISS:
+ case ACOMISD:
+ case AUCOMISS:
+ case AUCOMISD:
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * right side write
+ */
+ case ANOP:
+ case AMOVL:
+ case AMOVQ:
+ case AMOVB:
+ case AMOVW:
+ case AMOVBLSX:
+ case AMOVBLZX:
+ case AMOVBQSX:
+ case AMOVBQZX:
+ case AMOVLQSX:
+ case AMOVLQZX:
+ case AMOVWLSX:
+ case AMOVWLZX:
+ case AMOVWQSX:
+ case AMOVWQZX:
+
+ case AMOVSS:
+ case AMOVSD:
+ case ACVTSD2SL:
+ case ACVTSD2SQ:
+ case ACVTSD2SS:
+ case ACVTSL2SD:
+ case ACVTSL2SS:
+ case ACVTSQ2SD:
+ case ACVTSQ2SS:
+ case ACVTSS2SD:
+ case ACVTSS2SL:
+ case ACVTSS2SQ:
+ case ACVTTSD2SL:
+ case ACVTTSD2SQ:
+ case ACVTTSS2SL:
+ case ACVTTSS2SQ:
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * right side read+write
+ */
+ case AADDB:
+ case AADDL:
+ case AADDQ:
+ case AADDW:
+ case AANDB:
+ case AANDL:
+ case AANDQ:
+ case AANDW:
+ case ASUBB:
+ case ASUBL:
+ case ASUBQ:
+ case ASUBW:
+ case AORB:
+ case AORL:
+ case AORQ:
+ case AORW:
+ case AXORB:
+ case AXORL:
+ case AXORQ:
+ case AXORW:
+ case ASALB:
+ case ASALL:
+ case ASALQ:
+ case ASALW:
+ case ASARB:
+ case ASARL:
+ case ASARQ:
+ case ASARW:
+ case AROLB:
+ case AROLL:
+ case AROLQ:
+ case AROLW:
+ case ARORB:
+ case ARORL:
+ case ARORQ:
+ case ARORW:
+ case ASHLB:
+ case ASHLL:
+ case ASHLQ:
+ case ASHLW:
+ case ASHRB:
+ case ASHRL:
+ case ASHRQ:
+ case ASHRW:
+ case AIMULL:
+ case AIMULQ:
+ case AIMULW:
+ case ANEGL:
+ case ANEGQ:
+ case ANOTL:
+ case ANOTQ:
+ case AADCL:
+ case AADCQ:
+ case ASBBL:
+ case ASBBQ:
+
+ case AADDSD:
+ case AADDSS:
+ case ACMPSD:
+ case ACMPSS:
+ case ADIVSD:
+ case ADIVSS:
+ case AMAXSD:
+ case AMAXSS:
+ case AMINSD:
+ case AMINSS:
+ case AMULSD:
+ case AMULSS:
+ case ARCPSS:
+ case ARSQRTSS:
+ case ASQRTSD:
+ case ASQRTSS:
+ case ASUBSD:
+ case ASUBSS:
+ case AXORPD:
+ for(z=0; z<BITS; z++) {
+ r->set.b[z] |= bit.b[z];
+ r->use2.b[z] |= bit.b[z];
+ }
+ break;
+
+ /*
+ * funny
+ */
+ case ACALL:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+ }
+
+ switch(p->as) {
+ case AIMULL:
+ case AIMULQ:
+ case AIMULW:
+ if(p->to.type != D_NONE)
+ break;
+
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVQ:
+ case AIDIVW:
+ case AIMULB:
+ case ADIVB:
+ case ADIVL:
+ case ADIVQ:
+ case ADIVW:
+ case AMULB:
+ case AMULL:
+ case AMULQ:
+ case AMULW:
+
+ case ACWD:
+ case ACDQ:
+ case ACQO:
+ r->regu |= RtoB(D_AX) | RtoB(D_DX);
+ break;
+
+ case AREP:
+ case AREPN:
+ case ALOOP:
+ case ALOOPEQ:
+ case ALOOPNE:
+ r->regu |= RtoB(D_CX);
+ break;
+
+ case AMOVSB:
+ case AMOVSL:
+ case AMOVSQ:
+ case AMOVSW:
+ case ACMPSB:
+ case ACMPSL:
+ case ACMPSQ:
+ case ACMPSW:
+ r->regu |= RtoB(D_SI) | RtoB(D_DI);
+ break;
+
+ case ASTOSB:
+ case ASTOSL:
+ case ASTOSQ:
+ case ASTOSW:
+ case ASCASB:
+ case ASCASL:
+ case ASCASQ:
+ case ASCASW:
+ r->regu |= RtoB(D_AX) | RtoB(D_DI);
+ break;
+
+ case AINSB:
+ case AINSL:
+ case AINSW:
+ case AOUTSB:
+ case AOUTSL:
+ case AOUTSW:
+ r->regu |= RtoB(D_DI) | RtoB(D_DX);
+ break;
+ }
+ }
+ if(firstr == R)
+ return;
+ initpc = pc - val;
+ npc = val;
+
+ /*
+ * pass 2
+ * turn branch references to pointers
+ * build back pointers
+ */
+ for(r = firstr; r != R; r = r->link) {
+ 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);
+ if(debug['R'] && debug['v']) {
+ print("\nlooping structure:\n");
+ for(r = firstr; r != R; r = r->link) {
+ print("%ld:%P", r->loop, r->prog);
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->use1.b[z] |
+ r->use2.b[z] |
+ r->set.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);
+ }
+ print("\n");
+ }
+ }
+
+ /*
+ * 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;
+
+
+ /*
+ * pass 5
+ * isolate regions
+ * calculate costs (paint1)
+ */
+ r = firstr;
+ if(r) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = (r->refahead.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);
+ }
+ }
+ if(debug['R'] && debug['v'])
+ print("\nprop structure:\n");
+ for(r = firstr; r != R; r = r->link)
+ r->act = zbits;
+ rgp = region;
+ nregion = 0;
+ for(r = firstr; r != R; r = r->link) {
+ if(debug['R'] && debug['v']) {
+ print("%P\t", r->prog);
+ if(bany(&r->set))
+ print("s:%B ", r->set);
+ if(bany(&r->refahead))
+ print("ra:%B ", r->refahead);
+ if(bany(&r->calahead))
+ print("ca:%B ", r->calahead);
+ print("\n");
+ }
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.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; z<BITS; z++)
+ bit.b[z] = LOAD(r) & ~(r->act.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; i<nregion; i++) {
+ bit = blsh(rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno);
+ vreg = allreg(vreg, rgp);
+ if(debug['R']) {
+ print("%L$%d %R: %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;
+ }
+}
+
+/*
+ * 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->offset = v->offset;
+ a->etype = v->etype;
+ a->type = v->name;
+
+ p1->as = AMOVL;
+ if(v->etype == TCHAR || v->etype == TUCHAR)
+ p1->as = AMOVB;
+ if(v->etype == TSHORT || v->etype == TUSHORT)
+ p1->as = AMOVW;
+ if(v->etype == TVLONG || v->etype == TUVLONG || v->etype == TIND)
+ p1->as = AMOVQ;
+ if(v->etype == TFLOAT)
+ p1->as = AMOVSS;
+ if(v->etype == TDOUBLE)
+ p1->as = AMOVSD;
+
+ p1->from.type = rn;
+ if(!f) {
+ p1->from = *a;
+ *a = zprog.from;
+ a->type = rn;
+ if(v->etype == TUCHAR)
+ p1->as = AMOVB;
+ if(v->etype == TUSHORT)
+ p1->as = AMOVW;
+ }
+ if(debug['R'])
+ print("%P\t.a%P\n", p, p1);
+}
+
+ulong
+doregbits(int r)
+{
+ ulong b;
+
+ b = 0;
+ if(r >= D_INDIR)
+ r -= D_INDIR;
+ if(r >= D_AX && r <= D_R15)
+ b |= RtoB(r);
+ else
+ if(r >= D_AL && r <= D_R15B)
+ b |= RtoB(r-D_AL+D_AX);
+ else
+ if(r >= D_AH && r <= D_BH)
+ b |= RtoB(r-D_AH+D_AX);
+ else
+ if(r >= D_X0 && r <= D_X0+15)
+ b |= FtoB(r);
+ return b;
+}
+
+Bits
+mkvar(Reg *r, Adr *a)
+{
+ Var *v;
+ int i, t, n, et, z;
+ long o;
+ Bits bit;
+ Sym *s;
+
+ /*
+ * mark registers used
+ */
+ t = a->type;
+ r->regu |= doregbits(t);
+ r->regu |= doregbits(a->index);
+
+ switch(t) {
+ default:
+ goto none;
+ case D_ADDR:
+ a->type = a->index;
+ bit = mkvar(r, a);
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ a->type = t;
+ goto none;
+ case D_EXTERN:
+ case D_STATIC:
+ case D_PARAM:
+ case D_AUTO:
+ n = t;
+ break;
+ }
+ s = a->sym;
+ if(s == S)
+ goto none;
+ if(s->name[0] == '.')
+ goto none;
+ et = a->etype;
+ o = a->offset;
+ v = var;
+ for(i=0; i<nvar; i++) {
+ if(s == v->sym)
+ if(n == v->name)
+ if(o == v->offset)
+ goto out;
+ v++;
+ }
+ 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->name = n;
+ v->etype = et;
+ 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; z<BITS; z++)
+ externs.b[z] |= bit.b[z];
+ if(n == D_PARAM)
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+ if(v->etype != et || !(typechlpfd[et] || typev[et])) /* funny punning */
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ return bit;
+
+none:
+ return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+ Reg *r1, *r2;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->p1) {
+ for(z=0; z<BITS; z++) {
+ ref.b[z] |= r1->refahead.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 ACALL:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] |= ref.b[z] | externs.b[z];
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ATEXT:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = 0;
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ARET:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = externs.b[z];
+ ref.b[z] = 0;
+ }
+ }
+ for(z=0; z<BITS; z++) {
+ ref.b[z] = (ref.b[z] & ~r1->set.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; z<BITS; z++) {
+ dif.b[z] = (dif.b[z] &
+ ~(~r1->refbehind.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; z<BITS; z++)
+ dif.b[z] &= ~(~r1->calbehind.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 TVLONG:
+ case TUVLONG:
+ 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;
+ 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
+regset(Reg *r, ulong bb)
+{
+ ulong b, set;
+ Adr v;
+ int c;
+
+ set = 0;
+ v = zprog.from;
+ while(b = bb & ~(bb-1)) {
+ v.type = b & 0xFFFF? BtoR(b): BtoF(b);
+ if(v.type == 0)
+ diag(Z, "zero v.type for %#lux", b);
+ c = copyu(r->prog, &v, A);
+ if(c == 3)
+ set |= b;
+ bb &= ~b;
+ }
+ return set;
+}
+
+ulong
+reguse(Reg *r, ulong bb)
+{
+ ulong b, set;
+ Adr v;
+ int c;
+
+ set = 0;
+ v = zprog.from;
+ while(b = bb & ~(bb-1)) {
+ v.type = b & 0xFFFF? BtoR(b): BtoF(b);
+ c = copyu(r->prog, &v, A);
+ if(c == 1 || c == 2 || c == 4)
+ set |= b;
+ bb &= ~b;
+ }
+ return set;
+}
+
+ulong
+paint2(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ ulong bb, vreg, x;
+
+ 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;
+ }
+
+ bb = vreg;
+ for(; r; r=r->s1) {
+ x = r->regu & ~bb;
+ if(x) {
+ vreg |= reguse(r, x);
+ bb |= regset(r, x);
+ }
+ }
+ 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);
+ 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->offset = 0;
+ a->type = rn;
+}
+
+long
+RtoB(int r)
+{
+
+ if(r < D_AX || r > D_R15)
+ return 0;
+ return 1L << (r-D_AX);
+}
+
+int
+BtoR(long b)
+{
+
+ b &= 0xffffL;
+ if(b == 0)
+ return 0;
+ return bitno(b) + D_AX;
+}
+
+/*
+ * bit reg
+ * 16 X5
+ * 17 X6
+ * 18 X7
+ */
+long
+FtoB(int f)
+{
+ if(f < FREGMIN || f > FREGEXT)
+ return 0;
+ return 1L << (f - FREGMIN + 16);
+}
+
+int
+BtoF(long b)
+{
+
+ b &= 0x70000L;
+ if(b == 0)
+ return 0;
+ return bitno(b) - 16 + FREGMIN;
+}
diff --git a/sys/src/cmd/6c/sgen.c b/sys/src/cmd/6c/sgen.c
new file mode 100644
index 000000000..a7d751c0f
--- /dev/null
+++ b/sys/src/cmd/6c/sgen.c
@@ -0,0 +1,435 @@
+#include "gc.h"
+
+void
+noretval(int n)
+{
+
+ if(n & 1) {
+ gins(ANOP, Z, Z);
+ p->to.type = REGRET;
+ }
+ if(n & 2) {
+ gins(ANOP, Z, Z);
+ p->to.type = FREGRET;
+ }
+}
+
+/* welcome to commute */
+static void
+commute(Node *n)
+{
+ Node *l, *r;
+
+ l = n->left;
+ r = n->right;
+ if(r->complex > l->complex) {
+ n->left = r;
+ n->right = l;
+ }
+}
+
+void
+indexshift(Node *n)
+{
+ int g;
+
+ if(!typechlpv[n->type->etype])
+ return;
+ simplifyshift(n);
+ if(n->op == OASHL && n->right->op == OCONST){
+ g = vconst(n->right);
+ if(g >= 0 && g <= 3)
+ n->addable = 7;
+ }
+}
+
+/*
+ * calculate addressability as follows
+ * NAME ==> 10/11 name+value(SB/SP)
+ * REGISTER ==> 12 register
+ * CONST ==> 20 $value
+ * *(20) ==> 21 value
+ * &(10) ==> 13 $name+value(SB)
+ * &(11) ==> 1 $name+value(SP)
+ * (13) + (20) ==> 13 fold constants
+ * (1) + (20) ==> 1 fold constants
+ * *(13) ==> 10 back to name
+ * *(1) ==> 11 back to name
+ *
+ * (20) * (X) ==> 7 multiplier in indexing
+ * (X,7) + (13,1) ==> 8 adder in indexing (addresses)
+ * (8) ==> &9(OINDEX) index, almost addressable
+ *
+ * calculate complexity (number of registers)
+ */
+void
+xcom(Node *n)
+{
+ Node *l, *r;
+ int g;
+
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ n->complex = 0;
+ n->addable = 0;
+ switch(n->op) {
+ case OCONST:
+ n->addable = 20;
+ break;
+
+ case ONAME:
+ n->addable = 10;
+ if(n->class == CPARAM || n->class == CAUTO)
+ n->addable = 11;
+ break;
+
+ case OREGISTER:
+ n->addable = 12;
+ break;
+
+ case OINDREG:
+ n->addable = 12;
+ break;
+
+ case OADDR:
+ xcom(l);
+ if(l->addable == 10)
+ n->addable = 13;
+ else
+ if(l->addable == 11)
+ n->addable = 1;
+ break;
+
+ case OADD:
+ xcom(l);
+ xcom(r);
+ if(n->type->etype != TIND)
+ break;
+
+ switch(r->addable) {
+ case 20:
+ switch(l->addable) {
+ case 1:
+ case 13:
+ commadd:
+ l->type = n->type;
+ *n = *l;
+ l = new(0, Z, Z);
+ *l = *(n->left);
+ l->xoffset += r->vconst;
+ n->left = l;
+ r = n->right;
+ goto brk;
+ }
+ break;
+
+ case 1:
+ case 13:
+ case 10:
+ case 11:
+ /* l is the base, r is the index */
+ if(l->addable != 20)
+ n->addable = 8;
+ break;
+ }
+ switch(l->addable) {
+ case 20:
+ switch(r->addable) {
+ case 13:
+ case 1:
+ r = n->left;
+ l = n->right;
+ n->left = l;
+ n->right = r;
+ goto commadd;
+ }
+ break;
+
+ case 13:
+ case 1:
+ case 10:
+ case 11:
+ /* r is the base, l is the index */
+ if(r->addable != 20)
+ n->addable = 8;
+ break;
+ }
+ if(n->addable == 8 && !side(n)) {
+ indx(n);
+ l = new1(OINDEX, idx.basetree, idx.regtree);
+ l->scale = idx.scale;
+ l->addable = 9;
+ l->complex = l->right->complex;
+ l->type = l->left->type;
+ n->op = OADDR;
+ n->left = l;
+ n->right = Z;
+ n->addable = 8;
+ break;
+ }
+ break;
+
+ case OINDEX:
+ xcom(l);
+ xcom(r);
+ n->addable = 9;
+ break;
+
+ case OIND:
+ xcom(l);
+ if(l->op == OADDR) {
+ l = l->left;
+ l->type = n->type;
+ *n = *l;
+ return;
+ }
+ switch(l->addable) {
+ case 20:
+ n->addable = 21;
+ break;
+ case 1:
+ n->addable = 11;
+ break;
+ case 13:
+ n->addable = 10;
+ break;
+ }
+ break;
+
+ case OASHL:
+ xcom(l);
+ xcom(r);
+ indexshift(n);
+ break;
+
+ case OMUL:
+ case OLMUL:
+ xcom(l);
+ xcom(r);
+ g = vlog(l);
+ if(g >= 0) {
+ n->left = r;
+ n->right = l;
+ l = r;
+ r = n->right;
+ }
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASHL;
+ r->vconst = g;
+ r->type = types[TINT];
+ indexshift(n);
+ break;
+ }
+ commute(n);
+ break;
+
+ case OASLDIV:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASLSHR;
+ r->vconst = g;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OLDIV:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OLSHR;
+ r->vconst = g;
+ r->type = types[TINT];
+ indexshift(n);
+ break;
+ }
+ break;
+
+ case OASLMOD:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASAND;
+ r->vconst--;
+ }
+ break;
+
+ case OLMOD:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OAND;
+ r->vconst--;
+ }
+ break;
+
+ case OASMUL:
+ case OASLMUL:
+ xcom(l);
+ xcom(r);
+ g = vlog(r);
+ if(g >= 0) {
+ n->op = OASASHL;
+ r->vconst = g;
+ }
+ break;
+
+ case OLSHR:
+ case OASHR:
+ xcom(l);
+ xcom(r);
+ indexshift(n);
+ break;
+
+ default:
+ if(l != Z)
+ xcom(l);
+ if(r != Z)
+ xcom(r);
+ break;
+ }
+brk:
+ 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++;
+
+ switch(n->op) {
+
+ case OFUNC:
+ n->complex = FNX;
+ break;
+
+ case OCAST:
+ if(l->type->etype == TUVLONG && typefd[n->type->etype])
+ n->complex += 2;
+ break;
+
+ case OLMOD:
+ case OMOD:
+ case OLMUL:
+ case OLDIV:
+ case OMUL:
+ case ODIV:
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ if(r->complex >= l->complex) {
+ n->complex = l->complex + 3;
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ } else {
+ n->complex = r->complex + 3;
+ if(l->complex > n->complex)
+ n->complex = l->complex;
+ }
+ break;
+
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ case OASLSHR:
+ case OASASHL:
+ case OASASHR:
+ if(r->complex >= l->complex) {
+ n->complex = l->complex + 2;
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ } else {
+ n->complex = r->complex + 2;
+ if(l->complex > n->complex)
+ n->complex = l->complex;
+ }
+ break;
+
+ case OADD:
+ case OXOR:
+ case OAND:
+ case OOR:
+ /*
+ * immediate operators, make const on right
+ */
+ if(l->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ }
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ /*
+ * compare operators, make const on left
+ */
+ if(r->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ n->op = invrel[relindex(n->op)];
+ }
+ break;
+ }
+}
+
+void
+indx(Node *n)
+{
+ Node *l, *r;
+
+ if(debug['x'])
+ prtree(n, "indx");
+
+ l = n->left;
+ r = n->right;
+ if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) {
+ n->right = l;
+ n->left = r;
+ l = r;
+ r = n->right;
+ }
+ if(l->addable != 7) {
+ idx.regtree = l;
+ idx.scale = 1;
+ } else
+ if(l->right->addable == 20) {
+ idx.regtree = l->left;
+ idx.scale = 1 << l->right->vconst;
+ } else
+ if(l->left->addable == 20) {
+ idx.regtree = l->right;
+ idx.scale = 1 << l->left->vconst;
+ } else
+ diag(n, "bad index");
+
+ idx.basetree = r;
+ if(debug['x']) {
+ print("scale = %d\n", idx.scale);
+ prtree(idx.regtree, "index");
+ prtree(idx.basetree, "base");
+ }
+}
diff --git a/sys/src/cmd/6c/swt.c b/sys/src/cmd/6c/swt.c
new file mode 100644
index 000000000..b201c9cae
--- /dev/null
+++ b/sys/src/cmd/6c/swt.c
@@ -0,0 +1,530 @@
+#include "gc.h"
+
+void
+swit1(C1 *q, int nc, long def, Node *n)
+{
+ C1 *r;
+ int i;
+ Prog *sp;
+
+ if(nc < 5) {
+ for(i=0; i<nc; i++) {
+ if(debug['W'])
+ print("case = %.8llux\n", q->val);
+ gcmp(OEQ, n, q->val);
+ patch(p, q->label);
+ q++;
+ }
+ gbranch(OGOTO);
+ patch(p, def);
+ return;
+ }
+ i = nc / 2;
+ r = q+i;
+ if(debug['W'])
+ print("case > %.8llux\n", r->val);
+ gcmp(OGT, n, r->val);
+ sp = p;
+ gbranch(OGOTO);
+ p->as = AJEQ;
+ patch(p, r->label);
+ swit1(q, i, def, n);
+
+ if(debug['W'])
+ print("case < %.8llux\n", r->val);
+ patch(sp, pc);
+ swit1(r+1, nc-i-1, def, n);
+}
+
+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);
+ gmove(n2, n3);
+ gmove(n3, 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, tfield, nodconst(v), n1);
+ } else {
+ sh = 32 - b->type->shift - b->type->nbits;
+ if(sh > 0)
+ gopcode(OASHL, tfield, nodconst(sh), n1);
+ sh += b->type->shift;
+ if(sh > 0)
+ if(typeu[b->type->etype])
+ gopcode(OLSHR, tfield, nodconst(sh), n1);
+ else
+ gopcode(OASHR, tfield, nodconst(sh), n1);
+ }
+}
+
+void
+bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ long v;
+ Node nod;
+ int sh;
+
+ regalloc(&nod, b->left, Z);
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, types[TLONG], nodconst(v), n1);
+ gmove(n1, &nod);
+ if(nn != Z)
+ gmove(n1, nn);
+ sh = b->type->shift;
+ if(sh > 0)
+ gopcode(OASHL, types[TLONG], nodconst(sh), &nod);
+ v <<= sh;
+ gopcode(OAND, types[TLONG], nodconst(~v), n3);
+ gopcode(OOR, types[TLONG], n3, &nod);
+ gmove(&nod, 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->from.scale = NSNAME;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, string, NSNAME);
+ mnstring = 0;
+ }
+ n--;
+ }
+ return r;
+}
+
+void
+sextern(Sym *s, Node *a, long o, long w)
+{
+ long e, lw;
+
+ for(e=0; e<w; e+=NSNAME) {
+ lw = NSNAME;
+ if(w-e < lw)
+ lw = w-e;
+ gpseudo(ADATA, s, nodconst(0L));
+ p->from.offset += o+e;
+ p->from.scale = 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(0 && a->op == OCONST && typev[a->type->etype]) {
+ gpseudo(ADATA, s, lo64(a));
+ p->from.offset += o;
+ p->from.scale = 4;
+ gpseudo(ADATA, s, hi64(a));
+ p->from.offset += o + 4;
+ p->from.scale = 4;
+ return;
+ }
+ gpseudo(ADATA, s, a);
+ p->from.offset += o;
+ p->from.scale = w;
+ switch(p->to.type) {
+ default:
+ p->to.index = p->to.type;
+ p->to.type = D_ADDR;
+ case D_CONST:
+ case D_FCONST:
+ case D_ADDR:
+ break;
+ }
+}
+
+void zname(Biobuf*, Sym*, int);
+void zaddr(Biobuf*, Adr*, int);
+void outhist(Biobuf*);
+
+void
+outcode(void)
+{
+ struct { Sym *sym; short type; } h[NSYM];
+ Prog *p;
+ Sym *s;
+ int f, sf, st, t, sym;
+ Biobuf b;
+
+ 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++;
+ }
+ }
+ f = open(outfile, OWRITE);
+ if(f < 0) {
+ diag(Z, "cannot open %s", outfile);
+ return;
+ }
+ Binit(&b, f, OWRITE);
+ Bseek(&b, 0L, 2);
+ outhist(&b);
+ for(sym=0; sym<NSYM; sym++) {
+ h[sym].sym = S;
+ h[sym].type = 0;
+ }
+ sym = 1;
+ for(p = firstp; p != P; p = p->link) {
+ jackpot:
+ sf = 0;
+ s = p->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = p->from.type;
+ if(t == D_ADDR)
+ t = p->from.index;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ s->sym = sym;
+ zname(&b, 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.type;
+ if(t == D_ADDR)
+ t = p->to.index;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ s->sym = sym;
+ zname(&b, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ Bputc(&b, p->as);
+ Bputc(&b, p->as>>8);
+ Bputc(&b, p->lineno);
+ Bputc(&b, p->lineno>>8);
+ Bputc(&b, p->lineno>>16);
+ Bputc(&b, p->lineno>>24);
+ zaddr(&b, &p->from, sf);
+ zaddr(&b, &p->to, st);
+ }
+ Bflush(&b);
+ close(f);
+ 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, ANAME>>8);
+ 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;
+
+ Bputc(b, pg.as);
+ Bputc(b, pg.as>>8);
+ Bputc(b, pg.lineno);
+ Bputc(b, pg.lineno>>8);
+ Bputc(b, pg.lineno>>16);
+ Bputc(b, pg.lineno>>24);
+ zaddr(b, &pg.from, 0);
+ zaddr(b, &pg.to, 0);
+ }
+}
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ char *n;
+ ulong sig;
+
+ if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
+ sig = sign(s);
+ Bputc(b, ASIGNAME);
+ Bputc(b, ASIGNAME>>8);
+ Bputc(b, sig);
+ Bputc(b, sig>>8);
+ Bputc(b, sig>>16);
+ Bputc(b, sig>>24);
+ s->sig = SIGDONE;
+ }
+ else{
+ Bputc(b, ANAME); /* as */
+ Bputc(b, ANAME>>8); /* as */
+ }
+ Bputc(b, t); /* type */
+ Bputc(b, s->sym); /* sym */
+ n = s->name;
+ while(*n) {
+ Bputc(b, *n);
+ n++;
+ }
+ Bputc(b, 0);
+}
+
+void
+zaddr(Biobuf *b, Adr *a, int s)
+{
+ long l;
+ int i, t;
+ char *n;
+ Ieee e;
+
+ t = 0;
+ if(a->index != D_NONE || a->scale != 0)
+ t |= T_INDEX;
+ if(s != 0)
+ t |= T_SYM;
+
+ switch(a->type) {
+ default:
+ t |= T_TYPE;
+ case D_NONE:
+ if(a->offset != 0) {
+ t |= T_OFFSET;
+ l = a->offset;
+ if((vlong)l != a->offset)
+ t |= T_64;
+ }
+ break;
+ case D_FCONST:
+ t |= T_FCONST;
+ break;
+ case D_SCONST:
+ t |= T_SCONST;
+ break;
+ }
+ Bputc(b, t);
+
+ if(t & T_INDEX) { /* implies index, scale */
+ Bputc(b, a->index);
+ Bputc(b, a->scale);
+ }
+ if(t & T_OFFSET) { /* implies offset */
+ l = a->offset;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ if(t & T_64) {
+ l = a->offset>>32;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ }
+ }
+ if(t & T_SYM) /* implies sym */
+ Bputc(b, s);
+ if(t & T_FCONST) {
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ l = e.h;
+ Bputc(b, l);
+ Bputc(b, l>>8);
+ Bputc(b, l>>16);
+ Bputc(b, l>>24);
+ return;
+ }
+ if(t & T_SCONST) {
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(b, *n);
+ n++;
+ }
+ return;
+ }
+ if(t & T_TYPE)
+ Bputc(b, a->type);
+}
+
+long
+align(long i, Type *t, int op)
+{
+ long o;
+ Type *v;
+ int w;
+
+ o = i;
+ w = 1;
+ switch(op) {
+ default:
+ diag(Z, "unknown align opcode %d", op);
+ break;
+
+ case Asu2: /* padding at end of a struct */
+ 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 = ewidth[v->etype];
+ 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(typesu[t->etype]) {
+ o = align(o, types[TIND], Aarg1);
+ o = align(o, types[TIND], Aarg2);
+ }
+ break;
+
+ case Aarg1: /* initial align of parameter */
+ w = ewidth[t->etype];
+ if(w <= 0 || w >= SZ_VLONG) {
+ w = SZ_VLONG;
+ break;
+ }
+ w = 1; /* little endian no adjustment */
+ break;
+
+ case Aarg2: /* width of a parameter */
+ o += t->width;
+ w = SZ_VLONG;
+ break;
+
+ case Aaut3: /* total allign of automatic */
+ o = align(o, t, Ael1);
+ o = align(o, t, Ael2);
+ break;
+ }
+ o = round(o, w);
+ if(debug['A'])
+ print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ return o;
+}
+
+long
+maxround(long max, long v)
+{
+ v += SZ_VLONG-1;
+ if(v > max)
+ max = round(v, SZ_VLONG);
+ return max;
+}
diff --git a/sys/src/cmd/6c/sys.c b/sys/src/cmd/6c/sys.c
new file mode 100644
index 000000000..abdc42b04
--- /dev/null
+++ b/sys/src/cmd/6c/sys.c
@@ -0,0 +1,106 @@
+#include <u.h>
+#include <libc.h>
+#include "/sys/src/libc/9syscall/sys.h"
+
+vlong _sysargs[6*4];
+vlong _callsys(void);
+
+/*
+ * syscalls
+ */
+
+int
+getpid(void)
+{
+ _sysargs[0] = -1;
+ return _callsys();
+}
+
+long
+pread(int fd, void *a, long n, vlong)
+{
+ _sysargs[0] = PREAD;
+ _sysargs[1] = fd;
+ _sysargs[2] = (vlong)a;
+ _sysargs[3] = n;
+ return _callsys();
+}
+
+long
+pwrite(int fd, void *a, long n, vlong)
+{
+ _sysargs[0] = PWRITE;
+ _sysargs[1] = fd;
+ _sysargs[2] = (vlong)a;
+ _sysargs[3] = n;
+ return _callsys();
+}
+
+int
+close(int fd)
+{
+ _sysargs[0] = CLOSE;
+ _sysargs[1] = fd;
+ return _callsys();
+}
+
+int
+open(char *name, int mode)
+{
+ _sysargs[0] = OPEN;
+ _sysargs[1] = (vlong)name;
+ _sysargs[2] = mode;
+ return _callsys();
+}
+
+int
+create(char *f, int mode, ulong perm)
+{
+ _sysargs[0] = CREATE;
+ _sysargs[1] = (vlong)f;
+ _sysargs[2] = mode;
+ _sysargs[3] = perm;
+ return _callsys();
+}
+
+void
+_exits(char *s)
+{
+ _sysargs[0] = EXITS;
+ _sysargs[1] = s!=nil? strlen(s): 0;
+ _callsys();
+}
+
+int
+dup(int f, int t)
+{
+ _sysargs[0] = DUP;
+ _sysargs[1] = f;
+ _sysargs[2] = t;
+ return _callsys();
+}
+
+int
+errstr(char *buf, uint n)
+{
+ _sysargs[0] = ERRSTR;
+ _sysargs[1] = (vlong)buf;
+ _sysargs[2] = n;
+ return _callsys();
+}
+
+int
+brk_(void *a)
+{
+ _sysargs[0] = BRK_;
+ _sysargs[1] = (vlong)a;
+ return _callsys();
+}
+
+void*
+sbrk(ulong n)
+{
+ _sysargs[0] = -2;
+ _sysargs[1] = n;
+ return (void*)_callsys();
+}
diff --git a/sys/src/cmd/6c/txt.c b/sys/src/cmd/6c/txt.c
new file mode 100644
index 000000000..24ac1db46
--- /dev/null
+++ b/sys/src/cmd/6c/txt.c
@@ -0,0 +1,1515 @@
+#include "gc.h"
+
+void
+ginit(void)
+{
+ int i;
+ Type *t;
+
+ thechar = '6';
+ thestring = "amd64";
+ 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[TINT];
+
+ typeword = typechlvp;
+ typeswitch = typechlv;
+ typecmplx = typesu;
+
+ /* TO DO */
+ memmove(typechlpv, typechlp, sizeof(typechlpv));
+ typechlpv[TVLONG] = 1;
+ typechlpv[TUVLONG] = 1;
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.from.type = D_NONE;
+ zprog.from.index = D_NONE;
+ zprog.from.scale = 0;
+ zprog.to = zprog.from;
+
+ lregnode.op = OREGISTER;
+ lregnode.class = CEXREG;
+ lregnode.reg = REGTMP;
+ lregnode.complex = 0;
+ lregnode.addable = 11;
+ lregnode.type = types[TLONG];
+
+ qregnode = lregnode;
+ qregnode.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(0)
+ com64init();
+
+ for(i=0; i<nelem(reg); i++) {
+ reg[i] = 1;
+ if(i >= D_AX && i <= D_R15 && i != D_SP)
+ reg[i] = 0;
+ if(i >= D_X0 && i <= D_X7)
+ reg[i] = 0;
+ }
+}
+
+void
+gclean(void)
+{
+ int i;
+ Sym *s;
+
+ reg[D_SP]--;
+ for(i=D_AX; i<=D_R15; i++)
+ if(reg[i])
+ diag(Z, "reg %R left allocated", i);
+ for(i=D_X0; i<=D_X7; i++)
+ if(reg[i])
+ diag(Z, "reg %R left allocated", i);
+ while(mnstring)
+ outstring("", 1L);
+ symstring->type->width = nstring;
+ symrathole->type->width = nrathole;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ 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;
+}
+
+int
+nareg(void)
+{
+ int i, n;
+
+ n = 0;
+ for(i=D_AX; i<=D_R15; i++)
+ if(reg[i] == 0)
+ n++;
+ return n;
+}
+
+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(typesu[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 && typechlpv[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);
+ gmove(n, tn2);
+ return;
+ }
+ regalloc(tn1, n, Z);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ regaalloc(tn2, n);
+ gmove(tn1, 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*
+nodfconst(double d)
+{
+ fconstnode.fconst = d;
+ return &fconstnode;
+}
+
+int
+isreg(Node *n, int r)
+{
+
+ if(n->op == OREGISTER)
+ if(n->reg == r)
+ return 1;
+ return 0;
+}
+
+int
+nodreg(Node *n, Node *nn, int r)
+{
+ int et;
+
+ *n = qregnode;
+ n->reg = r;
+ if(nn != Z){
+ et = nn->type->etype;
+ if(!typefd[et] && nn->type->width <= SZ_LONG && 0)
+ n->type = typeu[et]? types[TUINT]: types[TINT];
+ else
+ n->type = nn->type;
+//print("nodreg %s [%s]\n", tnames[et], tnames[n->type->etype]);
+ n->lineno = nn->lineno;
+ }
+ if(reg[r] == 0)
+ return 0;
+ if(nn != Z) {
+ if(nn->op == OREGISTER)
+ if(nn->reg == r)
+ return 0;
+ }
+ return 1;
+}
+
+void
+regret(Node *n, Node *nn)
+{
+ int r;
+
+ r = REGRET;
+ if(typefd[nn->type->etype])
+ r = FREGRET;
+ nodreg(n, nn, r);
+ reg[r]++;
+}
+
+void
+regalloc(Node *n, Node *tn, Node *o)
+{
+ int i;
+
+ switch(tn->type->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 >= D_AX && i <= D_R15)
+ goto out;
+ }
+ for(i=D_AX; i<=D_R15; i++)
+ if(reg[i] == 0)
+ goto out;
+ diag(tn, "out of fixed registers");
+ goto err;
+
+ case TFLOAT:
+ case TDOUBLE:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= D_X0 && i <= D_X7)
+ goto out;
+ }
+ for(i=D_X0; i<=D_X7; i++)
+ if(reg[i] == 0)
+ goto out;
+ diag(tn, "out of float registers");
+ goto out;
+ }
+ diag(tn, "unknown type in regalloc: %T", tn->type);
+err:
+ i = 0;
+out:
+ if(i)
+ 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: %R", i);
+}
+
+void
+regsalloc(Node *n, Node *nn)
+{
+ cursafe = align(cursafe, nn->type, Aaut3);
+ 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;
+ 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
+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 %D", n->op, a);
+ break;
+
+ case OREGISTER:
+ a->type = n->reg;
+ a->sym = S;
+ break;
+
+
+ case OIND:
+ naddr(n->left, a);
+ if(a->type >= D_AX && a->type <= D_R15)
+ a->type += D_INDIR;
+ else
+ if(a->type == D_CONST)
+ a->type = D_NONE+D_INDIR;
+ else
+ if(a->type == D_ADDR) {
+ a->type = a->index;
+ a->index = D_NONE;
+ } else
+ goto bad;
+ break;
+
+ case OINDEX:
+ a->type = idx.ptr;
+ if(n->left->op == OADDR || n->left->op == OCONST)
+ naddr(n->left, a);
+ if(a->type >= D_AX && a->type <= D_R15)
+ a->type += D_INDIR;
+ else
+ if(a->type == D_CONST)
+ a->type = D_NONE+D_INDIR;
+ else
+ if(a->type == D_ADDR) {
+ a->type = a->index;
+ a->index = D_NONE;
+ } else
+ goto bad;
+ a->index = idx.reg;
+ a->scale = n->scale;
+ a->offset += n->xoffset;
+ break;
+
+ case OINDREG:
+ a->type = n->reg+D_INDIR;
+ a->sym = S;
+ a->offset = n->xoffset;
+ break;
+
+ case ONAME:
+ a->etype = n->etype;
+ a->type = D_STATIC;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ if(n->class == CSTATIC)
+ break;
+ if(n->class == CEXTERN || n->class == CGLOBL) {
+ a->type = D_EXTERN;
+ break;
+ }
+ if(n->class == CAUTO) {
+ a->type = D_AUTO;
+ break;
+ }
+ if(n->class == CPARAM) {
+ a->type = D_PARAM;
+ break;
+ }
+ goto bad;
+
+ case OCONST:
+ if(typefd[n->type->etype]) {
+ a->type = D_FCONST;
+ a->dval = n->fconst;
+ break;
+ }
+ a->sym = S;
+ a->type = D_CONST;
+ if(typev[n->type->etype] || n->type->etype == TIND)
+ a->offset = n->vconst;
+ else
+ a->offset = convvtox(n->vconst, typeu[n->type->etype]? TULONG: TLONG);
+ break;
+
+ case OADDR:
+ naddr(n->left, a);
+ if(a->type >= D_INDIR) {
+ a->type -= D_INDIR;
+ break;
+ }
+ if(a->type == D_EXTERN || a->type == D_STATIC ||
+ a->type == D_AUTO || a->type == D_PARAM)
+ if(a->index == D_NONE) {
+ a->index = a->type;
+ a->type = D_ADDR;
+ break;
+ }
+ goto bad;
+
+ case OADD:
+ if(n->right->op == OCONST) {
+ v = n->right->vconst;
+ naddr(n->left, a);
+ } else
+ if(n->left->op == OCONST) {
+ v = n->left->vconst;
+ naddr(n->right, a);
+ } else
+ goto bad;
+ a->offset += v;
+ break;
+
+ }
+}
+
+void
+gcmp(int op, Node *n, vlong val)
+{
+ Node *cn, nod;
+
+ cn = nodgconst(val, n->type);
+ if(!immconst(cn)){
+ regalloc(&nod, n, Z);
+ gmove(cn, &nod);
+ gopcode(op, n->type, n, &nod);
+ regfree(&nod);
+ }else
+ gopcode(op, n->type, n, cn);
+}
+
+#define CASE(a,b) ((a<<8)|(b<<0))
+
+void
+gmove(Node *f, Node *t)
+{
+ int ft, tt, t64, a;
+ Node nod, nod1, nod2, nod3;
+ Prog *p1, *p2;
+
+ ft = f->type->etype;
+ tt = t->type->etype;
+ t64 = tt == TVLONG || tt == TUVLONG || tt == TIND;
+ if(debug['M'])
+ print("gop: %O %O[%s],%O[%s]\n", OAS,
+ f->op, tnames[ft], t->op, tnames[tt]);
+ if(typefd[ft] && f->op == OCONST) {
+ /* TO DO: pick up special constants, possibly preloaded */
+ if(f->fconst == 0.0){
+ regalloc(&nod, t, t);
+ gins(AXORPD, &nod, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+ }
+/*
+ * load
+ */
+ if(f->op == ONAME || f->op == OINDREG ||
+ f->op == OIND || f->op == OINDEX)
+ switch(ft) {
+ case TCHAR:
+ a = AMOVBLSX;
+ if(t64)
+ a = AMOVBQSX;
+ goto ld;
+ case TUCHAR:
+ a = AMOVBLZX;
+ if(t64)
+ a = AMOVBQZX;
+ goto ld;
+ case TSHORT:
+ a = AMOVWLSX;
+ if(t64)
+ a = AMOVWQSX;
+ goto ld;
+ case TUSHORT:
+ a = AMOVWLZX;
+ if(t64)
+ a = AMOVWQZX;
+ goto ld;
+ case TINT:
+ case TLONG:
+ if(typefd[tt]) {
+ regalloc(&nod, t, t);
+ if(tt == TDOUBLE)
+ a = ACVTSL2SD;
+ else
+ a = ACVTSL2SS;
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+ a = AMOVL;
+ if(t64)
+ a = AMOVLQSX;
+ goto ld;
+ case TUINT:
+ case TULONG:
+ a = AMOVL;
+ if(t64)
+ a = AMOVLQZX; /* could probably use plain MOVL */
+ goto ld;
+ case TVLONG:
+ if(typefd[tt]) {
+ regalloc(&nod, t, t);
+ if(tt == TDOUBLE)
+ a = ACVTSQ2SD;
+ else
+ a = ACVTSQ2SS;
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+ case TUVLONG:
+ a = AMOVQ;
+ goto ld;
+ case TIND:
+ a = AMOVQ;
+
+ ld:
+ regalloc(&nod, f, t);
+ nod.type = t64? types[TVLONG]: types[TINT];
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+ case TFLOAT:
+ a = AMOVSS;
+ goto fld;
+ case TDOUBLE:
+ a = AMOVSD;
+ fld:
+ regalloc(&nod, f, t);
+ if(tt != TDOUBLE && tt != TFLOAT){ /* TO DO: why is this here */
+ prtree(f, "odd tree");
+ nod.type = t64? types[TVLONG]: types[TINT];
+ }
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+
+/*
+ * store
+ */
+ if(t->op == ONAME || t->op == OINDREG ||
+ t->op == OIND || t->op == OINDEX)
+ switch(tt) {
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVB; goto st;
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVW; goto st;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ a = AMOVL; goto st;
+ case TVLONG:
+ case TUVLONG:
+ case TIND:
+ a = AMOVQ; goto st;
+
+ st:
+ if(f->op == OCONST) {
+ gins(a, f, t);
+ return;
+ }
+ fst:
+ regalloc(&nod, t, f);
+ gmove(f, &nod);
+ gins(a, &nod, t);
+ regfree(&nod);
+ return;
+
+ case TFLOAT:
+ a = AMOVSS;
+ goto fst;
+ case TDOUBLE:
+ a = AMOVSD;
+ goto fst;
+ }
+
+/*
+ * convert
+ */
+ switch(CASE(ft,tt)) {
+ default:
+/*
+ * integer to integer
+ ********
+ a = AGOK; break;
+
+ case CASE( TCHAR, TCHAR):
+ case CASE( TUCHAR, TCHAR):
+ case CASE( TSHORT, TCHAR):
+ case CASE( TUSHORT,TCHAR):
+ case CASE( TINT, TCHAR):
+ case CASE( TUINT, TCHAR):
+ case CASE( TLONG, TCHAR):
+ case CASE( TULONG, TCHAR):
+ case CASE( TIND, TCHAR):
+
+ case CASE( TCHAR, TUCHAR):
+ case CASE( TUCHAR, TUCHAR):
+ case CASE( TSHORT, TUCHAR):
+ case CASE( TUSHORT,TUCHAR):
+ case CASE( TINT, TUCHAR):
+ case CASE( TUINT, TUCHAR):
+ case CASE( TLONG, TUCHAR):
+ case CASE( TULONG, TUCHAR):
+ case CASE( TIND, TUCHAR):
+
+ case CASE( TSHORT, TSHORT):
+ case CASE( TUSHORT,TSHORT):
+ case CASE( TINT, TSHORT):
+ case CASE( TUINT, TSHORT):
+ case CASE( TLONG, TSHORT):
+ case CASE( TULONG, TSHORT):
+ case CASE( TIND, TSHORT):
+
+ case CASE( TSHORT, TUSHORT):
+ case CASE( TUSHORT,TUSHORT):
+ case CASE( TINT, TUSHORT):
+ case CASE( TUINT, TUSHORT):
+ case CASE( TLONG, TUSHORT):
+ case CASE( TULONG, TUSHORT):
+ case CASE( TIND, TUSHORT):
+
+ case CASE( TINT, TINT):
+ case CASE( TUINT, TINT):
+ case CASE( TLONG, TINT):
+ case CASE( TULONG, TINT):
+ case CASE( TIND, TINT):
+
+ case CASE( TINT, TUINT):
+ case CASE( TUINT, TUINT):
+ case CASE( TLONG, TUINT):
+ case CASE( TULONG, TUINT):
+ case CASE( TIND, TUINT):
+
+ case CASE( TUINT, TIND):
+ case CASE( TVLONG, TUINT):
+ case CASE( TVLONG, TULONG):
+ case CASE( TUVLONG, TUINT):
+ case CASE( TUVLONG, TULONG):
+ *****/
+ a = AMOVL;
+ break;
+
+ case CASE( TVLONG, TCHAR):
+ case CASE( TVLONG, TSHORT):
+ case CASE( TVLONG, TINT):
+ case CASE( TVLONG, TLONG):
+ case CASE( TUVLONG, TCHAR):
+ case CASE( TUVLONG, TSHORT):
+ case CASE( TUVLONG, TINT):
+ case CASE( TUVLONG, TLONG):
+ case CASE( TINT, TVLONG):
+ case CASE( TINT, TUVLONG):
+ case CASE( TLONG, TVLONG):
+ case CASE( TINT, TIND):
+ case CASE( TLONG, TIND):
+ a = AMOVLQSX;
+ if(f->op == OCONST) {
+ f->vconst &= (uvlong)0xffffffffU;
+ if(f->vconst & 0x80000000)
+ f->vconst |= (vlong)0xffffffff << 32;
+ a = AMOVQ;
+ }
+ break;
+
+ case CASE( TUINT, TIND):
+ case CASE( TUINT, TVLONG):
+ case CASE( TUINT, TUVLONG):
+ case CASE( TULONG, TVLONG):
+ case CASE( TULONG, TUVLONG):
+ case CASE( TULONG, TIND):
+ a = AMOVL; /* same effect as AMOVLQZX */
+ if(f->op == OCONST) {
+ f->vconst &= (uvlong)0xffffffffU;
+ a = AMOVQ;
+ }
+ break;
+
+ case CASE( TIND, TVLONG):
+ case CASE( TVLONG, TVLONG):
+ case CASE( TUVLONG, TVLONG):
+ case CASE( TVLONG, TUVLONG):
+ case CASE( TUVLONG, TUVLONG):
+ case CASE( TIND, TUVLONG):
+ case CASE( TVLONG, TIND):
+ case CASE( TUVLONG, TIND):
+ case CASE( TIND, TIND):
+ a = AMOVQ;
+ break;
+
+ case CASE( TSHORT, TINT):
+ case CASE( TSHORT, TUINT):
+ case CASE( TSHORT, TLONG):
+ case CASE( TSHORT, TULONG):
+ a = AMOVWLSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ if(f->vconst & 0x8000)
+ f->vconst |= 0xffff0000;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TSHORT, TVLONG):
+ case CASE( TSHORT, TUVLONG):
+ case CASE( TSHORT, TIND):
+ a = AMOVWQSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ if(f->vconst & 0x8000){
+ f->vconst |= 0xffff0000;
+ f->vconst |= (vlong)~0 << 32;
+ }
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TUSHORT,TINT):
+ case CASE( TUSHORT,TUINT):
+ case CASE( TUSHORT,TLONG):
+ case CASE( TUSHORT,TULONG):
+ a = AMOVWLZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TUSHORT,TVLONG):
+ case CASE( TUSHORT,TUVLONG):
+ case CASE( TUSHORT,TIND):
+ a = AMOVWQZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ a = AMOVL; /* MOVL also zero-extends to 64 bits */
+ }
+ break;
+
+ case CASE( TCHAR, TSHORT):
+ case CASE( TCHAR, TUSHORT):
+ case CASE( TCHAR, TINT):
+ case CASE( TCHAR, TUINT):
+ case CASE( TCHAR, TLONG):
+ case CASE( TCHAR, TULONG):
+ a = AMOVBLSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ if(f->vconst & 0x80)
+ f->vconst |= 0xffffff00;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TCHAR, TVLONG):
+ case CASE( TCHAR, TUVLONG):
+ case CASE( TCHAR, TIND):
+ a = AMOVBQSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ if(f->vconst & 0x80){
+ f->vconst |= 0xffffff00;
+ f->vconst |= (vlong)~0 << 32;
+ }
+ a = AMOVQ;
+ }
+ break;
+
+ case CASE( TUCHAR, TSHORT):
+ case CASE( TUCHAR, TUSHORT):
+ case CASE( TUCHAR, TINT):
+ case CASE( TUCHAR, TUINT):
+ case CASE( TUCHAR, TLONG):
+ case CASE( TUCHAR, TULONG):
+ a = AMOVBLZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TUCHAR, TVLONG):
+ case CASE( TUCHAR, TUVLONG):
+ case CASE( TUCHAR, TIND):
+ a = AMOVBQZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ a = AMOVL; /* zero-extends to 64-bits */
+ }
+ break;
+
+/*
+ * float to fix
+ */
+ case CASE( TFLOAT, TCHAR):
+ case CASE( TFLOAT, TUCHAR):
+ case CASE( TFLOAT, TSHORT):
+ case CASE( TFLOAT, TUSHORT):
+ case CASE( TFLOAT, TINT):
+ case CASE( TFLOAT, TUINT):
+ case CASE( TFLOAT, TLONG):
+ case CASE( TFLOAT, TULONG):
+ case CASE( TFLOAT, TVLONG):
+ case CASE( TFLOAT, TUVLONG):
+ case CASE( TFLOAT, TIND):
+
+ case CASE( TDOUBLE,TCHAR):
+ case CASE( TDOUBLE,TUCHAR):
+ case CASE( TDOUBLE,TSHORT):
+ case CASE( TDOUBLE,TUSHORT):
+ case CASE( TDOUBLE,TINT):
+ case CASE( TDOUBLE,TUINT):
+ case CASE( TDOUBLE,TLONG):
+ case CASE( TDOUBLE,TULONG):
+ case CASE( TDOUBLE,TVLONG):
+ case CASE( TDOUBLE,TUVLONG):
+ case CASE( TDOUBLE,TIND):
+ regalloc(&nod, t, Z);
+ if(ewidth[tt] == SZ_VLONG || typeu[tt] && ewidth[tt] == SZ_INT){
+ if(ft == TFLOAT)
+ a = ACVTTSS2SQ;
+ else
+ a = ACVTTSD2SQ;
+ }else{
+ if(ft == TFLOAT)
+ a = ACVTTSS2SL;
+ else
+ a = ACVTTSD2SL;
+ }
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+/*
+ * ulong to float
+ */
+ case CASE( TUVLONG, TDOUBLE):
+ case CASE( TUVLONG, TFLOAT):
+ a = ACVTSQ2SS;
+ if(tt == TDOUBLE)
+ a = ACVTSQ2SD;
+ regalloc(&nod, f, f);
+ gmove(f, &nod);
+ regalloc(&nod1, t, t);
+ gins(ACMPQ, &nod, nodconst(0));
+ gins(AJLT, Z, Z);
+ p1 = p;
+ gins(a, &nod, &nod1);
+ gins(AJMP, Z, Z);
+ p2 = p;
+ patch(p1, pc);
+ regalloc(&nod2, f, Z);
+ regalloc(&nod3, f, Z);
+ gmove(&nod, &nod2);
+ gins(ASHRQ, nodconst(1), &nod2);
+ gmove(&nod, &nod3);
+ gins(AANDL, nodconst(1), &nod3);
+ gins(AORQ, &nod3, &nod2);
+ gins(a, &nod2, &nod1);
+ gins(tt == TDOUBLE? AADDSD: AADDSS, &nod1, &nod1);
+ regfree(&nod2);
+ regfree(&nod3);
+ patch(p2, pc);
+ regfree(&nod);
+ regfree(&nod1);
+ return;
+
+ case CASE( TULONG, TDOUBLE):
+ case CASE( TUINT, TDOUBLE):
+ case CASE( TULONG, TFLOAT):
+ case CASE( TUINT, TFLOAT):
+ a = ACVTSQ2SS;
+ if(tt == TDOUBLE)
+ a = ACVTSQ2SD;
+ regalloc(&nod, f, f);
+ gins(AMOVLQZX, f, &nod);
+ regalloc(&nod1, t, t);
+ gins(a, &nod, &nod1);
+ gmove(&nod1, t);
+ regfree(&nod);
+ regfree(&nod1);
+ return;
+
+/*
+ * fix to float
+ */
+ case CASE( TCHAR, TFLOAT):
+ case CASE( TUCHAR, TFLOAT):
+ case CASE( TSHORT, TFLOAT):
+ case CASE( TUSHORT,TFLOAT):
+ case CASE( TINT, TFLOAT):
+ case CASE( TLONG, TFLOAT):
+ case CASE( TVLONG, TFLOAT):
+ case CASE( TIND, TFLOAT):
+
+ case CASE( TCHAR, TDOUBLE):
+ case CASE( TUCHAR, TDOUBLE):
+ case CASE( TSHORT, TDOUBLE):
+ case CASE( TUSHORT,TDOUBLE):
+ case CASE( TINT, TDOUBLE):
+ case CASE( TLONG, TDOUBLE):
+ case CASE( TVLONG, TDOUBLE):
+ case CASE( TIND, TDOUBLE):
+ regalloc(&nod, t, t);
+ if(ewidth[ft] == SZ_VLONG){
+ if(tt == TFLOAT)
+ a = ACVTSQ2SS;
+ else
+ a = ACVTSQ2SD;
+ }else{
+ if(tt == TFLOAT)
+ a = ACVTSL2SS;
+ else
+ a = ACVTSL2SD;
+ }
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+/*
+ * float to float
+ */
+ case CASE( TFLOAT, TFLOAT):
+ a = AMOVSS;
+ break;
+ case CASE( TDOUBLE,TFLOAT):
+ a = ACVTSD2SS;
+ break;
+ case CASE( TFLOAT, TDOUBLE):
+ a = ACVTSS2SD;
+ break;
+ case CASE( TDOUBLE,TDOUBLE):
+ a = AMOVSD;
+ break;
+ }
+ if(a == AMOVQ || a == AMOVSD || a == AMOVSS || a == AMOVL && ewidth[ft] == ewidth[tt]) /* TO DO: check AMOVL */
+ if(samaddr(f, t))
+ return;
+ gins(a, f, t);
+}
+
+void
+doindex(Node *n)
+{
+ Node nod, nod1;
+ long v;
+
+if(debug['Y'])
+prtree(n, "index");
+
+if(n->left->complex >= FNX)
+print("botch in doindex\n");
+
+ regalloc(&nod, &qregnode, Z);
+ v = constnode.vconst;
+ cgen(n->right, &nod);
+ idx.ptr = D_NONE;
+ if(n->left->op == OCONST)
+ idx.ptr = D_CONST;
+ else if(n->left->op == OREGISTER)
+ idx.ptr = n->left->reg;
+ else if(n->left->op != OADDR) {
+ reg[D_BP]++; // cant be used as a base
+ regalloc(&nod1, &qregnode, Z);
+ cgen(n->left, &nod1);
+ idx.ptr = nod1.reg;
+ regfree(&nod1);
+ reg[D_BP]--;
+ }
+ idx.reg = nod.reg;
+ regfree(&nod);
+ constnode.vconst = v;
+}
+
+void
+gins(int a, Node *f, Node *t)
+{
+
+ if(f != Z && f->op == OINDEX)
+ doindex(f);
+ if(t != Z && t->op == OINDEX)
+ doindex(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, Type *ty, Node *f, Node *t)
+{
+ int a, et;
+
+ et = TLONG;
+ if(ty != T)
+ et = ty->etype;
+ if(debug['M']) {
+ if(f != Z && f->type != T)
+ print("gop: %O %O[%s],", o, f->op, tnames[et]);
+ else
+ print("gop: %O Z,", o);
+ if(t != Z && t->type != T)
+ print("%O[%s]\n", t->op, tnames[t->type->etype]);
+ else
+ print("Z\n");
+ }
+ a = AGOK;
+ switch(o) {
+ case OCOM:
+ a = ANOTL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ANOTB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ANOTW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ANOTQ;
+ break;
+
+ case ONEG:
+ a = ANEGL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ANEGB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ANEGW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ANEGQ;
+ break;
+
+ case OADDR:
+ a = ALEAQ;
+ break;
+
+ case OASADD:
+ case OADD:
+ a = AADDL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AADDB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AADDW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AADDQ;
+ if(et == TFLOAT)
+ a = AADDSS;
+ if(et == TDOUBLE)
+ a = AADDSD;
+ break;
+
+ case OASSUB:
+ case OSUB:
+ a = ASUBL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASUBB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASUBW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ASUBQ;
+ if(et == TFLOAT)
+ a = ASUBSS;
+ if(et == TDOUBLE)
+ a = ASUBSD;
+ break;
+
+ case OASOR:
+ case OOR:
+ a = AORL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AORB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AORW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AORQ;
+ break;
+
+ case OASAND:
+ case OAND:
+ a = AANDL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AANDB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AANDW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AANDQ;
+ break;
+
+ case OASXOR:
+ case OXOR:
+ a = AXORL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AXORB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AXORW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AXORQ;
+ break;
+
+ case OASLSHR:
+ case OLSHR:
+ a = ASHRL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASHRB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASHRW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ASHRQ;
+ break;
+
+ case OASASHR:
+ case OASHR:
+ a = ASARL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASARB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASARW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ASARQ;
+ break;
+
+ case OASASHL:
+ case OASHL:
+ a = ASALL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASALB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASALW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ASALQ;
+ break;
+
+ case OFUNC:
+ a = ACALL;
+ break;
+
+ case OASMUL:
+ case OMUL:
+ if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0)
+ t = Z;
+ a = AIMULL;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AIMULQ;
+ if(et == TFLOAT)
+ a = AMULSS;
+ if(et == TDOUBLE)
+ a = AMULSD;
+ break;
+
+ case OASMOD:
+ case OMOD:
+ case OASDIV:
+ case ODIV:
+ a = AIDIVL;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AIDIVQ;
+ if(et == TFLOAT)
+ a = ADIVSS;
+ if(et == TDOUBLE)
+ a = ADIVSD;
+ break;
+
+ case OASLMUL:
+ case OLMUL:
+ a = AMULL;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AMULQ;
+ break;
+
+ case OASLMOD:
+ case OLMOD:
+ case OASLDIV:
+ case OLDIV:
+ a = ADIVL;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ADIVQ;
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHS:
+ case OHI:
+ a = ACMPL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ACMPB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ACMPW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ACMPQ;
+ if(et == TFLOAT)
+ a = AUCOMISS;
+ if(et == TDOUBLE)
+ a = AUCOMISD;
+ gins(a, f, t);
+ switch(o) {
+ case OEQ: a = AJEQ; break;
+ case ONE: a = AJNE; break;
+ case OLT: a = AJLT; break;
+ case OLE: a = AJLE; break;
+ case OGE: a = AJGE; break;
+ case OGT: a = AJGT; break;
+ case OLO: a = AJCS; break;
+ case OLS: a = AJLS; break;
+ case OHS: a = AJCC; break;
+ case OHI: a = AJHI; break;
+ }
+ gins(a, Z, Z);
+ return;
+ }
+ if(a == AGOK)
+ diag(Z, "bad in gopcode %O", o);
+ gins(a, f, t);
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+ return f->op == OREGISTER && t->op == OREGISTER && f->reg == t->reg;
+}
+
+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_EXTERN;
+ p->from.sym = s;
+ p->from.scale = (profileflg ? 0 : NOPROF);
+ if(s->class == CSTATIC)
+ p->from.type = D_STATIC;
+ naddr(n, &p->to);
+ if(a == ADATA || a == AGLOBL)
+ pc--;
+}
+
+int
+sconst(Node *n)
+{
+ long v;
+
+ if(n->op == OCONST && !typefd[n->type->etype]) {
+ v = n->vconst;
+ if(v >= -32766L && v < 32766L)
+ return 1;
+ }
+ return 0;
+}
+
+long
+exreg(Type *t)
+{
+ long o;
+
+ if(typechlpv[t->etype]) {
+ if(exregoffset <= REGEXT-4)
+ return 0;
+ o = exregoffset;
+ exregoffset--;
+ 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]*/
+ SZ_IND, /*[TIND]*/
+ 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, /*[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/sys/src/cmd/6c/vlrt.c b/sys/src/cmd/6c/vlrt.c
new file mode 100644
index 000000000..7c9f1a07b
--- /dev/null
+++ b/sys/src/cmd/6c/vlrt.c
@@ -0,0 +1,746 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ struct
+ {
+ uint lo;
+ uint hi;
+ };
+ struct
+ {
+ ushort lols;
+ ushort loms;
+ ushort hils;
+ ushort hims;
+ };
+ };
+};
+
+void abort(void);
+
+void _subv(Vlong*, Vlong, Vlong);
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ uint xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+uint _div64by32(Vlong, uint, uint*);
+void _mul64by32(Vlong*, Vlong, uint);
+
+static void
+slowdodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+ uint numlo, numhi, denhi, denlo, quohi, quolo, t;
+ int i;
+
+ numhi = num.hi;
+ numlo = num.lo;
+ denhi = den.hi;
+ denlo = den.lo;
+
+ /*
+ * get a divide by zero
+ */
+ if(denlo==0 && denhi==0) {
+ numlo = numlo / denlo;
+ }
+
+ /*
+ * set up the divisor and find the number of iterations needed
+ */
+ if(numhi >= SIGN(32)) {
+ quohi = SIGN(32);
+ quolo = 0;
+ } else {
+ quohi = numhi;
+ quolo = numlo;
+ }
+ i = 0;
+ while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+ denhi = (denhi<<1) | (denlo>>31);
+ denlo <<= 1;
+ i++;
+ }
+
+ quohi = 0;
+ quolo = 0;
+ for(; i >= 0; i--) {
+ quohi = (quohi<<1) | (quolo>>31);
+ quolo <<= 1;
+ if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+ t = numlo;
+ numlo -= denlo;
+ if(numlo > t)
+ numhi--;
+ numhi -= denhi;
+ quolo |= 1;
+ }
+ denlo = (denlo>>1) | (denhi<<31);
+ denhi >>= 1;
+ }
+
+ if(q) {
+ q->lo = quolo;
+ q->hi = quohi;
+ }
+ if(r) {
+ r->lo = numlo;
+ r->hi = numhi;
+ }
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
+{
+ uint n;
+ Vlong x, q, r;
+
+ if(den.hi > num.hi || (den.hi == num.hi && den.lo > num.lo)){
+ if(qp) {
+ qp->hi = 0;
+ qp->lo = 0;
+ }
+ if(rp) {
+ rp->hi = num.hi;
+ rp->lo = num.lo;
+ }
+ return;
+ }
+
+ if(den.hi != 0){
+ q.hi = 0;
+ n = num.hi/den.hi;
+ _mul64by32(&x, den, n);
+ if(x.hi > num.hi || (x.hi == num.hi && x.lo > num.lo))
+ slowdodiv(num, den, &q, &r);
+ else {
+ q.lo = n;
+ _subv(&r, num, x);
+ }
+ } else {
+ if(num.hi >= den.lo){
+ q.hi = n = num.hi/den.lo;
+ num.hi -= den.lo*n;
+ } else {
+ q.hi = 0;
+ }
+ q.lo = _div64by32(num, den.lo, &r.lo);
+ r.hi = 0;
+ }
+ if(qp) {
+ qp->lo = q.lo;
+ qp->hi = q.hi;
+ }
+ if(rp) {
+ rp->lo = r.lo;
+ rp->hi = r.hi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ uint t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ uint t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u.lo = 0;
+ u.hi = 0;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (uint)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, uint ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, uint ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, uint ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}