--- /dev/null
--- /dev/null
++/*
++ * $Source$
++ * $State$
++ */
++
++/* Integer registers */
++
++0, GPR, 0, "r0",
++0, GPR, 1, "r1",
++0, GPR, 1, "sp",
++0, GPR, 2, "r2",
++0, GPR, 2, "fp",
++0, GPR, 3, "r3",
++0, GPR, 4, "r4",
++0, GPR, 5, "r5",
++0, GPR, 6, "r6",
++0, GPR, 7, "r7",
++0, GPR, 8, "r8",
++0, GPR, 9, "r9",
++0, GPR, 10, "r10",
++0, GPR, 11, "r11",
++0, GPR, 12, "r12",
++0, GPR, 13, "r13",
++0, GPR, 14, "r14",
++0, GPR, 15, "r15",
++0, GPR, 16, "r16",
++0, GPR, 17, "r17",
++0, GPR, 18, "r18",
++0, GPR, 19, "r19",
++0, GPR, 20, "r20",
++0, GPR, 21, "r21",
++0, GPR, 22, "r22",
++0, GPR, 23, "r23",
++0, GPR, 24, "r24",
++0, GPR, 25, "r25",
++0, GPR, 26, "r26",
++0, GPR, 27, "r27",
++0, GPR, 28, "r28",
++0, GPR, 29, "r29",
++0, GPR, 30, "r30",
++0, GPR, 31, "r31",
++
++/* Floating-point registers */
++
++0, FPR, 0, "f0",
++0, FPR, 1, "f1",
++0, FPR, 2, "f2",
++0, FPR, 3, "f3",
++0, FPR, 4, "f4",
++0, FPR, 5, "f5",
++0, FPR, 6, "f6",
++0, FPR, 7, "f7",
++0, FPR, 8, "f8",
++0, FPR, 9, "f9",
++0, FPR, 10, "f10",
++0, FPR, 11, "f11",
++0, FPR, 12, "f12",
++0, FPR, 13, "f13",
++0, FPR, 14, "f14",
++0, FPR, 15, "f15",
++0, FPR, 16, "f16",
++0, FPR, 17, "f17",
++0, FPR, 18, "f18",
++0, FPR, 19, "f19",
++0, FPR, 20, "f20",
++0, FPR, 21, "f21",
++0, FPR, 22, "f22",
++0, FPR, 23, "f23",
++0, FPR, 24, "f24",
++0, FPR, 25, "f25",
++0, FPR, 26, "f26",
++0, FPR, 27, "f27",
++0, FPR, 28, "f28",
++0, FPR, 29, "f29",
++0, FPR, 30, "f30",
++0, FPR, 31, "f31",
++
++/* Special registers */
++
++0, SPR, 32, "xer",
++0, SPR, 256, "lr",
++0, SPR, 288, "ctr",
++
++/* Condition registers */
++
++0, CR, 0, "cr0",
++0, CR, 1, "cr1",
++0, CR, 2, "cr2",
++0, CR, 3, "cr3",
++0, CR, 4, "cr4",
++0, CR, 5, "cr5",
++0, CR, 6, "cr6",
++0, CR, 7, "cr7",
++
++/* Condition code flag */
++
++0, C, 0, ".",
++
++/* Special instructions */
++
++0, OP_la, 0, "la",
++
++/* Branch processor instructions (page 20) */
++
++0, OP_LIL, 18<<26 | 0<<1 | 0<<0, "b",
++0, OP_LIA, 18<<26 | 1<<1 | 0<<0, "ba",
++0, OP_LIL, 18<<26 | 0<<1 | 1<<0, "bl",
++0, OP_LIA, 18<<26 | 1<<1 | 1<<0, "bla",
++0, OP_BO_BI_BDL, 16<<26 | 0<<1 | 0<<0, "bc",
++0, OP_BO_BI_BDA, 16<<26 | 1<<1 | 0<<0, "bca",
++0, OP_BO_BI_BDL, 16<<26 | 0<<1 | 1<<0, "bcl",
++0, OP_BO_BI_BDA, 16<<26 | 1<<1 | 1<<0, "bcla",
++0, OP_BO_BI_BH, 19<<26 | 16<<1 | 0<<0, "bclr",
++0, OP_BO_BI_BH, 19<<26 | 16<<1 | 1<<0, "bclrl",
++0, OP_BO_BI_BH, 19<<26 | 528<<1 | 0<<0, "bcctr",
++0, OP_BO_BI_BH, 19<<26 | 528<<1 | 1<<0, "bcctrl",
++0, OP_LEV, 17<<26 | 1<<1, "sc",
++0, OP_BT_BA_BB, 19<<26 | 257<<1, "crand",
++0, OP_BT_BA_BB, 19<<26 | 449<<1, "cror",
++0, OP_BT_BA_BB, 19<<26 | 193<<1, "crxor",
++0, OP_BT_BA_BB, 19<<26 | 225<<1, "crnand",
++0, OP_BT_BA_BB, 19<<26 | 33<<1, "crnor",
++0, OP_BT_BA_BB, 19<<26 | 289<<1, "crneqv",
++0, OP_BT_BA_BB, 19<<26 | 129<<1, "crandc",
++0, OP_BT_BA_BB, 19<<26 | 417<<1, "crorc",
++0, OP_BF_BFA, 19<<26 | 0<<1, "mcrf",
++
++/* Fixed point instructions (page 29) */
++
++0, OP_RT_RA_D, 34<<26, "lbz",
++0, OP_RT_RA_RB, 31<<26 | 87<<1, "lbzx",
++0, OP_RT_RA_D, 35<<26, "lbzu",
++0, OP_RT_RA_RB, 31<<26 | 119<<1, "lbzux",
++0, OP_RT_RA_D, 40<<26, "lhz",
++0, OP_RT_RA_RB, 31<<26 | 279<<1, "lhzx",
++0, OP_RT_RA_D, 41<<26, "lhzu",
++0, OP_RT_RA_RB, 31<<26 | 311<<1, "lhzux",
++0, OP_RT_RA_D, 42<<26, "lha",
++0, OP_RT_RA_RB, 31<<26 | 343<<1, "lhax",
++0, OP_RT_RA_D, 43<<26, "lhau",
++0, OP_RT_RA_RB, 31<<26 | 375<<1, "lhaux",
++0, OP_RT_RA_D, 32<<26, "lwz",
++0, OP_RT_RA_RB, 31<<26 | 23<<1, "lwzx",
++0, OP_RT_RA_D, 33<<26, "lwzu",
++0, OP_RT_RA_RB, 31<<26 | 55<<1, "lwzux",
++0, OP_RT_RA_DS, 58<<26 | 2<<0, "lwa",
++0, OP_RT_RA_RB, 31<<26 | 341<<1, "lwax",
++0, OP_RT_RA_RB, 31<<26 | 363<<1, "lwaux",
++0, OP_RT_RA_DS, 58<<26, "ld",
++0, OP_RT_RA_RB, 31<<26 | 21<<1, "ldx",
++0, OP_RT_RA_DS, 58<<26 | 1<<0, "ldu",
++0, OP_RT_RA_RB, 31<<26 | 53<<1, "ldux",
++
++0, OP_RS_RA_D, 38<<26, "stb",
++0, OP_RS_RA_RB, 31<<26 | 215<<1, "stbx",
++0, OP_RS_RA_D, 39<<26, "stbu",
++0, OP_RS_RA_RB, 31<<26 | 247<<1, "stbux",
++0, OP_RS_RA_D, 44<<26, "sth",
++0, OP_RS_RA_RB, 31<<26 | 407<<1, "sthx",
++0, OP_RS_RA_D, 45<<26, "sthu",
++0, OP_RS_RA_RB, 31<<26 | 439<<1, "sthux",
++0, OP_RS_RA_D, 36<<26, "stw",
++0, OP_RS_RA_RB, 31<<26 | 151<<1, "stwx",
++0, OP_RS_RA_D, 37<<26, "stwu",
++0, OP_RS_RA_RB, 31<<26 | 183<<1, "stwux",
++0, OP_RS_RA_DS, 62<<26, "std",
++0, OP_RS_RA_RB, 31<<26 | 149<<1, "stdx",
++0, OP_RS_RA_DS, 62<<26 | 1<<0, "stdu",
++0, OP_RS_RA_RB, 31<<26 | 181<<1, "stdux",
++
++/* page 42 */
++0, OP_RT_RA_RB, 31<<26 | 790<<1, "lhbrx",
++0, OP_RT_RA_RB, 31<<26 | 534<<1, "lwbrx",
++0, OP_RS_RA_RB, 31<<26 | 918<<1, "sthbrx",
++0, OP_RS_RA_RB, 31<<26 | 662<<1, "stwbrx",
++
++/* page 44 */
++0, OP_RT_RA_D, 46<<26, "lmw",
++0, OP_RS_RA_D, 47<<26, "stmw",
++
++/* page 45 */
++0, OP_RT_RA_NB, 31<<26 | 597<<1, "lswi",
++0, OP_RT_RA_RB, 31<<26 | 533<<1, "lswx",
++0, OP_RS_RA_NB, 31<<26 | 725<<1, "stswi",
++0, OP_RS_RA_RB, 31<<26 | 661<<1, "stswx",
++
++/* page 49 */
++0, OP_RT_RA_SI, 14<<26, "addi",
++0, OP_RT_RA_SI, 15<<26, "addis",
++0, OP_RT_RA_RB_C, 31<<26 | 0<<10 | 266<<1, "add",
++0, OP_RT_RA_RB_C, 31<<26 | 1<<10 | 266<<1, "addo",
++0, OP_RT_RA_RB_C, 31<<26 | 0<<10 | 40<<1, "subf",
++0, OP_RT_RA_RB_C, 31<<26 | 1<<10 | 40<<1, "subfo",
++0, OP_RT_RA_SI_addic, 12<<26, "addic", /* special case C */
++0, OP_RT_RA_SI, 8<<26, "subfic",
++0, OP_RT_RA_RB_C, 31<<26 | 0<<10 | 138<<1, "adde",
++0, OP_RT_RA_RB_C, 31<<26 | 1<<10 | 138<<1, "addeo",
++0, OP_RT_RA_RB_C, 31<<26 | 0<<10 | 136<<1, "subfe",
++0, OP_RT_RA_RB_C, 31<<26 | 1<<10 | 136<<1, "subfeo",
++0, OP_RT_RA_C, 31<<26 | 0<<10 | 234<<1, "addme",
++0, OP_RT_RA_C, 31<<26 | 1<<10 | 234<<1, "addmeo",
++0, OP_RT_RA_C, 31<<26 | 0<<10 | 232<<1, "subfme",
++0, OP_RT_RA_C, 31<<26 | 1<<10 | 232<<1, "subfmeo",
++0, OP_RT_RA_C, 31<<26 | 0<<10 | 202<<1, "addze",
++0, OP_RT_RA_C, 31<<26 | 1<<10 | 202<<1, "addzeo",
++0, OP_RT_RA_C, 31<<26 | 0<<10 | 200<<1, "subfze",
++0, OP_RT_RA_C, 31<<26 | 1<<10 | 200<<1, "subfzeo",
++0, OP_RT_RA_C, 31<<26 | 0<<10 | 104<<1, "neg",
++0, OP_RT_RA_C, 31<<26 | 1<<10 | 104<<1, "nego",
++
++/* page 54 */
++0, OP_RT_RA_SI, 7<<26, "mulli",
++0, OP_RT_RA_RB_C, 31<<26 | 0<<10 | 233<<1, "mulld",
++0, OP_RT_RA_RB_C, 31<<26 | 1<<10 | 233<<1, "mulldo",
++0, OP_RT_RA_RB_C, 31<<26 | 0<<10 | 235<<1, "mullw",
++0, OP_RT_RA_RB_C, 31<<26 | 1<<10 | 235<<1, "mullwo",
++0, OP_RT_RA_RB_C, 31<<26 | 73<<1, "mulhd",
++0, OP_RT_RA_RB_C, 31<<26 | 75<<1, "mulhw",
++0, OP_RT_RA_RB_C, 31<<26 | 9<<1, "mulhdu",
++0, OP_RT_RA_RB_C, 31<<26 | 11<<1, "mulhwu",
++
++/* page 56 */
++0, OP_RT_RA_RB_C, 31<<26 | 0<<10 | 489<<1, "divd",
++0, OP_RT_RA_RB_C, 31<<26 | 1<<10 | 489<<1, "divdo",
++0, OP_RT_RA_RB_C, 31<<26 | 0<<10 | 491<<1, "divw",
++0, OP_RT_RA_RB_C, 31<<26 | 1<<10 | 491<<1, "divwo",
++0, OP_RT_RA_RB_C, 31<<26 | 0<<10 | 457<<1, "divdu",
++0, OP_RT_RA_RB_C, 31<<26 | 1<<10 | 457<<1, "divduo",
++0, OP_RT_RA_RB_C, 31<<26 | 0<<10 | 459<<1, "divwu",
++0, OP_RT_RA_RB_C, 31<<26 | 1<<10 | 459<<1, "divwuo",
++
++/* page 58 */
++0, OP_BF_L_RA_SI, 11<<26, "cmpi",
++0, OP_BF_L_RA_RB, 31<<26 | 0<<1, "cmp",
++0, OP_BF_L_RA_UI, 10<<26, "cmpli",
++0, OP_BF_L_RA_RB, 31<<26 | 32<<1, "cmpl",
++
++/* page 60 */
++0, OP_TO_RA_SI, 2<<26, "tdi",
++0, OP_TO_RA_SI, 3<<26, "twi",
++0, OP_TO_RA_RB, 31<<26 | 68<<1, "td",
++0, OP_TO_RA_RB, 31<<26 | 4<<1, "tw",
++
++/* page 62 */
++0, OP_RS_RA_UI_CC, 28<<26, "andi", /* C compulsory */
++0, OP_RS_RA_UI_CC, 29<<26, "andis", /* C compulsory */
++0, OP_RS_RA_UI, 24<<26, "ori",
++0, OP_RS_RA_UI, 25<<26, "oris",
++0, OP_RS_RA_UI, 26<<26, "xori",
++0, OP_RS_RA_UI, 27<<26, "xoris",
++0, OP_RS_RA_RB_C, 31<<26 | 28<<1, "and",
++0, OP_RS_RA_RB_C, 31<<26 | 444<<1, "or",
++0, OP_RS_RA_RB_C, 31<<26 | 316<<1, "xor",
++0, OP_RS_RA_RB_C, 31<<26 | 476<<1, "nand",
++0, OP_RS_RA_RB_C, 31<<26 | 124<<1, "nor",
++0, OP_RS_RA_RB_C, 31<<26 | 284<<1, "eqv",
++0, OP_RS_RA_RB_C, 31<<26 | 60<<1, "andc",
++0, OP_RS_RA_RB_C, 31<<26 | 412<<1, "orc",
++0, OP_RS_RA_C, 31<<26 | 954<<1, "extsb",
++0, OP_RS_RA_C, 31<<26 | 922<<1, "extsh",
++0, OP_RS_RA_C, 31<<26 | 986<<1, "extsw",
++0, OP_RS_RA_C, 31<<26 | 58<<1, "cntlzd",
++0, OP_RS_RA_C, 31<<26 | 26<<1, "cntlzw",
++
++/* page 69 */
++0, OP_RS_RA_SH_MB6_SH_C, 30<<26 | 0<<2, "rldicl",
++0, OP_RS_RA_SH_ME6_SH_C, 30<<26 | 1<<2, "rldicr",
++0, OP_RS_RA_SH_MB6_SH_C, 30<<26 | 2<<2, "rldic",
++0, OP_RS_RA_SH_MB5_ME5_C, 21<<26, "rlwinm",
++0, OP_RS_RA_RB_MB6_C, 30<<26 | 8<<1, "rldcl",
++0, OP_RS_RA_RB_ME6_C, 30<<26 | 9<<1, "rldcr",
++0, OP_RS_RA_RB_MB5_ME5_C, 23<<26, "rlwnm",
++0, OP_RS_RA_SH_MB6_SH_C, 30<<26 | 3<<2, "rldimi",
++0, OP_RS_RA_SH_MB5_ME5_C, 20<<26, "rlwimi",
++
++/* page 74 */
++0, OP_RS_RA_RB_C, 31<<26 | 27<<1, "sld",
++0, OP_RS_RA_RB_C, 31<<26 | 24<<1, "slw",
++0, OP_RS_RA_RB_C, 31<<26 | 539<<1, "srd",
++0, OP_RS_RA_RB_C, 31<<26 | 536<<1, "srw",
++0, OP_RS_RA_SH6_C, 31<<26 | 413<<2, "sradi",
++0, OP_RS_RA_SH5_C, 31<<26 | 824<<1, "srawi",
++0, OP_RS_RA_RB_C, 31<<26 | 794<<1, "srad",
++0, OP_RS_RA_RB_C, 31<<26 | 792<<1, "sraw",
++
++/* page 78 */
++0, OP_RS_SPR, 31<<26 | 467<<1, "mtspr",
++0, OP_RT_SPR, 31<<26 | 339<<1, "mfspr",
++0, OP_RS_FXM, 31<<26 | 0<<21 | 144<<1, "mtcrf",
++0, OP_RT, 31<<26 | 0<<21 | 19<<1, "mfcr",
++
++/* Floating point instructions (page 83) */
++
++0, OP_FRT_RA_D, 48<<26, "lfs",
++0, OP_FRT_RA_RB, 31<<26 | 535<<1, "lfsx",
++0, OP_FRT_RA_D, 49<<26, "lfsu",
++0, OP_FRT_RA_RB, 31<<26 | 567<<1, "lfsux",
++0, OP_FRT_RA_D, 50<<26, "lfd",
++0, OP_FRT_RA_RB, 31<<26 | 599<<1, "lfdx",
++0, OP_FRT_RA_D, 51<<26, "lfdu",
++0, OP_FRT_RA_RB, 31<<26 | 631<<1, "lfdux",
++0, OP_FRS_RA_D, 52<<26, "stfs",
++0, OP_FRS_RA_RB, 31<<26 | 663<<1, "stfsx",
++0, OP_FRS_RA_D, 53<<26, "stfsu",
++0, OP_FRS_RA_RB, 31<<26 | 695<<1, "stfsux",
++0, OP_FRS_RA_D, 54<<26, "stfd",
++0, OP_FRS_RA_RB, 31<<26 | 727<<1, "stfdx",
++0, OP_FRS_RA_D, 55<<26, "stfdu",
++0, OP_FRS_RA_RB, 31<<26 | 759<<1, "stfdux",
++0, OP_FRS_RA_RB, 31<<26 | 983<<1, "stfiwx",
++
++0, OP_FRT_FRB_C, 63<<26 | 72<<1, "fmr",
++0, OP_FRT_FRB_C, 63<<26 | 40<<1, "fneg",
++0, OP_FRT_FRB_C, 63<<26 | 264<<1, "fabs",
++0, OP_FRT_FRB_C, 63<<26 | 136<<1, "fnabs",
++
++0, OP_FRT_FRA_FRB_C, 63<<26 | 21<<1, "fadd",
++0, OP_FRT_FRA_FRB_C, 59<<26 | 21<<1, "fadds",
++0, OP_FRT_FRA_FRB_C, 63<<26 | 20<<1, "fsub",
++0, OP_FRT_FRA_FRB_C, 59<<26 | 20<<1, "fsubs",
++0, OP_FRT_FRA_FRC_C, 63<<26 | 25<<1, "fmul",
++0, OP_FRT_FRA_FRC_C, 59<<26 | 25<<1, "fmuls",
++0, OP_FRT_FRA_FRB_C, 63<<26 | 18<<1, "fdiv",
++0, OP_FRT_FRA_FRB_C, 59<<26 | 18<<1, "fdivs",
++
++0, OP_FRT_FRA_FRC_FRB_C, 63<<26 | 29<<1, "fmadd",
++0, OP_FRT_FRA_FRC_FRB_C, 59<<26 | 29<<1, "fmadds",
++0, OP_FRT_FRA_FRC_FRB_C, 63<<26 | 28<<1, "fmsub",
++0, OP_FRT_FRA_FRC_FRB_C, 59<<26 | 28<<1, "fmsubs",
++0, OP_FRT_FRA_FRC_FRB_C, 63<<26 | 31<<1, "fnmadd",
++0, OP_FRT_FRA_FRC_FRB_C, 59<<26 | 31<<1, "fnmadds",
++0, OP_FRT_FRA_FRC_FRB_C, 63<<26 | 30<<1, "fnmsub",
++0, OP_FRT_FRA_FRC_FRB_C, 59<<26 | 30<<1, "fnmsubs",
++
++0, OP_FRT_FRB_C, 63<<26 | 12<<1, "frsp",
++0, OP_FRT_FRB_C, 63<<26 | 814<<1, "fctid",
++0, OP_FRT_FRB_C, 63<<26 | 815<<1, "fctidz",
++0, OP_FRT_FRB_C, 63<<26 | 14<<1, "fctiw",
++0, OP_FRT_FRB_C, 63<<26 | 15<<1, "fctiwz",
++0, OP_FRT_FRB_C, 63<<26 | 846<<1, "fcfid",
++
++0, OP_BF_FRA_FRB, 63<<26 | 0<<1, "fcmpu",
++0, OP_BF_FRA_FRB, 63<<26 | 32<<1, "fcmpo",
++
++0, OP_FRT_C, 63<<26 | 583<<1, "mffs",
++0, OP_BF_BFA, 63<<26 | 64<<1, "mcrfs",
++0, OP_BF_U_C, 63<<26 | 134<<1, "mtfsfi",
++0, OP_FLM_FRB_C, 63<<26 | 711<<1, "mtfsf",
++0, OP_BT_C, 63<<26 | 70<<1, "mtfsb0",
++0, OP_BT_C, 63<<26 | 38<<1, "mtfsb1",
++
++0, OP_FRT_FRB_C, 63<<26 | 22<<1, "fsqrt",
++0, OP_FRT_FRB_C, 59<<26 | 22<<1, "fsqrts",
++0, OP_FRT_FRB_C, 59<<26 | 24<<1, "fres",
++0, OP_FRT_FRB_C, 63<<26 | 26<<1, "frsqrte",
++0, OP_FRT_FRA_FRC_FRB_C, 63<<26 | 23<<1, "fsel",
++
++/* page 98 */
--- /dev/null
--- /dev/null
++EM_WSIZE = 4
++EM_PSIZE = 4
++EM_BSIZE = 8 /* two words saved in call frame */
++
++INT8 = 1 /* Size of values */
++INT16 = 2
++INT32 = 4
++INT64 = 8
++
++FP_OFFSET = 0 /* Offset of saved FP relative to our FP */
++PC_OFFSET = 4 /* Offset of saved PC relative to our FP */
++
++#define COMMENT(n) /* noop */
++
++
++#define nicesize(x) ((x)==INT8 || (x)==INT16 || (x)==INT32 || (x)==INT64)
++
++#define smalls(n) sfit(n, 16)
++#define smallu(n) ufit(n, 16)
++
++#define lo(n) (n & 0xFFFF)
++#define hi(n) ((n>>16) & 0xFFFF)
++
++/* Use these for instructions that treat the low half as signed --- his()
++ * includes a modifier to produce the correct value when the low half gets
++ * sign extended. Er, do make sure you load the low half second. */
++#define los(n) (n & 0xFFFF)
++#define his(n) ((hi(n) - (lo(n)>>15)) & 0xFFFF)
++
++#define IFFALSE {CONST, 4}
++#define IFTRUE {CONST, 12}
++#define ALWAYS {CONST, 20}
++#define DCTRZ {CONST, 34}
++
++#define LT {CONST, 0}
++#define GT {CONST, 1}
++#define EQ {CONST, 2}
++
++
++
++PROPERTIES
++
++ GPR /* any GPR */
++ REG /* any allocatable GPR */
++ FPR /* any FPR */
++ FREG /* any allocatable FPR */
++ SPR /* any SPR */
++ CR /* any CR */
++
++ GPR0 GPRSP GPRFP GPR3 GPR4 GPR5 GPR6 GPR7
++ GPR8 GPR9 GPR10 GPR11 GPR12 GPR13 GPR14 GPR15
++ GPR16 GPR17 GPR18 GPR19 GPR20 GPR21 GPR22 GPR23
++ GPR24 GPR25 GPR26 GPR27 GPR28 GPR29 GPR30 GPR31
++
++ CR0 CR1
++
++ FPR0 FPR1 FPR2 FPR3 FPR4 FPR5 FPR6 FPR7
++ FPR8 FPR9 FPR10 FPR11 FPR12 FPR13 FPR14 FPR15
++ FPR16 FPR17 FPR18 FPR19 FPR20 FPR21 FPR22 FPR23
++ FPR24 FPR25 FPR26 FPR27 FPR28 FPR29 FPR30 FPR31
++
++REGISTERS
++
++ /* Reverse order to encourage ncg to allocate them from r31 down */
++
++ R31("r31") : GPR, REG, GPR31 regvar.
++ R30("r30") : GPR, REG, GPR30 regvar.
++ R29("r29") : GPR, REG, GPR29 regvar.
++ R28("r28") : GPR, REG, GPR28 regvar.
++ R27("r27") : GPR, REG, GPR27 regvar.
++ R26("r26") : GPR, REG, GPR26 regvar.
++ R25("r25") : GPR, REG, GPR25 regvar.
++ R24("r24") : GPR, REG, GPR24 regvar.
++ R23("r23") : GPR, REG, GPR23 regvar.
++ R22("r22") : GPR, REG, GPR22 regvar.
++ R21("r21") : GPR, REG, GPR21 regvar.
++ R20("r20") : GPR, REG, GPR20 regvar.
++ R19("r19") : GPR, REG, GPR19 regvar.
++ R18("r18") : GPR, REG, GPR18 regvar.
++ R17("r17") : GPR, REG, GPR17 regvar.
++ R16("r16") : GPR, REG, GPR16 regvar.
++ R15("r15") : GPR, REG, GPR15 regvar.
++ R14("r14") : GPR, REG, GPR14 regvar.
++ R13("r13") : GPR, REG, GPR13 regvar.
++ R12("r12") : GPR, REG, GPR12.
++ R11("r11") : GPR, GPR11.
++ R10("r10") : GPR, REG, GPR10.
++ R9("r9") : GPR, REG, GPR9.
++ R8("r8") : GPR, REG, GPR8.
++ R7("r7") : GPR, REG, GPR7.
++ R6("r6") : GPR, REG, GPR6.
++ R5("r5") : GPR, REG, GPR5.
++ R4("r4") : GPR, REG, GPR4.
++ R3("r3") : GPR, REG, GPR3.
++ FP("fp") : GPR, GPRFP.
++ SP("sp") : GPR, GPRSP.
++ R0("r0") : GPR, GPR0.
++
++ F31("f31") : FPR, FREG, FPR31.
++ F30("f30") : FPR, FREG, FPR30.
++ F29("f29") : FPR, FREG, FPR29.
++ F28("f28") : FPR, FREG, FPR28.
++ F27("f27") : FPR, FREG, FPR27.
++ F26("f26") : FPR, FREG, FPR26.
++ F25("f25") : FPR, FREG, FPR25.
++ F24("f24") : FPR, FREG, FPR24.
++ F23("f23") : FPR, FREG, FPR23.
++ F22("f22") : FPR, FREG, FPR22.
++ F21("f21") : FPR, FREG, FPR21.
++ F20("f20") : FPR, FREG, FPR20.
++ F19("f19") : FPR, FREG, FPR19.
++ F18("f18") : FPR, FREG, FPR18.
++ F17("f17") : FPR, FREG, FPR17.
++ F16("f16") : FPR, FREG, FPR16.
++ F15("f15") : FPR, FREG, FPR15.
++ F14("f14") : FPR, FREG, FPR14.
++ F13("f13") : FPR, FREG, FPR13.
++ F12("f12") : FPR, FREG, FPR12.
++ F11("f11") : FPR, FREG, FPR11.
++ F10("f10") : FPR, FREG, FPR10.
++ F9("f9") : FPR, FREG, FPR9.
++ F8("f8") : FPR, FREG, FPR8.
++ F7("f7") : FPR, FREG, FPR7.
++ F6("f6") : FPR, FREG, FPR6.
++ F5("f5") : FPR, FREG, FPR5.
++ F4("f4") : FPR, FREG, FPR4.
++ F3("f3") : FPR, FREG, FPR3.
++ F2("f2") : FPR, FREG, FPR2.
++ F1("f1") : FPR, FREG, FPR1.
++ F0("f0") : FPR, FREG, FPR0.
++
++ LR("lr") : SPR.
++ CTR("ctr") : SPR.
++ C0("cr0") : CR, CR0.
++
++#define SCRATCH R11
++#define FSCRATCH F0
++
++
++TOKENS
++
++/* Used only in instruction descriptions (to generate the correct syntax). */
++
++ GPRINDIRECT = { GPR reg; INT off; } 4 off "(" reg ")".
++ GPRINDIRECTLO = { GPR reg; ADDR adr; } 4 ">" adr "(" reg ")". /* Warning! Do not use on labels. */
++ HILABEL = { ADDR adr; } 4 "<" adr.
++ LOLABEL = { ADDR adr; } 4 ">" adr.
++
++/* Primitives */
++
++ LABEL = { ADDR adr; } 4 adr.
++ CONST = { INT val; } 4 val.
++ LOCAL = { INT off; } 4.
++
++/* Allows us to use regvar() to refer to registers */
++
++ GPRE = { GPR reg; } 4 reg.
++
++/* Expression partial results */
++
++ SUM_RC = { GPR reg; INT off; } 4.
++ SUM_RR = { GPR reg1; GPR reg2; } 4.
++
++ TRISTATE_RC_S = { GPR reg; INT val; } 4.
++ TRISTATE_RC_U = { GPR reg; INT val; } 4.
++ TRISTATE_RR_S = { GPR reg1; GPR reg2; } 4.
++ TRISTATE_RR_U = { GPR reg1; GPR reg2; } 4.
++
++ TRISTATE_FF = { FPR reg1; FPR reg2; } 4.
++
++ SEX_B = { GPR reg; } 4.
++ SEX_H = { GPR reg; } 4.
++
++ IND_RC_B = { GPR reg; INT off; } 4.
++ IND_RC_H = { GPR reg; INT off; } 4.
++ IND_RC_H_S = { GPR reg; INT off; } 4.
++ IND_RC_W = { GPR reg; INT off; } 4.
++ IND_RR_W = { GPR reg1; GPR reg2; } 4.
++ IND_LABEL_W = { ADDR adr; } 4.
++ IND_RC_D = { GPR reg; INT off; } 8.
++ IND_RR_D = { GPR reg1; GPR reg2; } 8.
++ IND_LABEL_D = { ADDR adr; } 8.
++
++ NOT_R = { GPR reg; } 4.
++
++ AND_RR = { GPR reg1; GPR reg2; } 4.
++ AND_RC = { GPR reg; INT val; } 4.
++ OR_RR = { GPR reg1; GPR reg2; } 4.
++ OR_RC = { GPR reg; INT val; } 4.
++ XOR_RR = { GPR reg1; GPR reg2; } 4.
++ XOR_RC = { GPR reg; INT val; } 4.
++
++/* Floats */
++
++ FD = { FPR reg; } 8 reg.
++ FS = { FPR reg; } 4 reg.
++
++/* Comments */
++
++ LABELI = { ADDR msg; INT num; } 4 msg " " num.
++
++
++
++
++SETS
++
++ TOKEN = LABEL + CONST + LOCAL.
++ GPRI = GPR + GPRE.
++
++ SUM_ALL = SUM_RC + SUM_RR.
++
++ TRISTATE_ALL = TRISTATE_RC_S + TRISTATE_RC_U + TRISTATE_RR_S +
++ TRISTATE_RR_U + TRISTATE_FF.
++
++ SEX_ALL = SEX_B + SEX_H.
++
++ LOGICAL_ALL = NOT_R + AND_RR + AND_RC + OR_RR + OR_RC + XOR_RR +
++ XOR_RC.
++
++ IND_ALL_W = IND_RC_W + IND_RR_W + IND_LABEL_W.
++
++ IND_ALL_D = IND_RC_D + IND_RR_D + IND_LABEL_D.
++
++ OP_ALL_W = SUM_ALL + TRISTATE_ALL + SEX_ALL + LOGICAL_ALL +
++ IND_ALL_W.
++
++
++INSTRUCTIONS
++
++ add GPRI:wo, GPRI:ro, GPRI:ro.
++ addX "add." GPRI:wo, GPRI:ro, GPRI:ro.
++ addi GPRI:wo, GPRI:ro, CONST:ro.
++ addis GPRI:wo, GPRI:ro, CONST+HILABEL:ro.
++ and GPRI:wo, GPRI:ro, GPRI:ro.
++ andc GPRI:wo, GPRI:ro, GPRI:ro.
++ andiX "andi." GPRI:wo, GPRI:ro, CONST:ro kills :cc.
++ andisX "andis." GPRI:wo, GPRI:ro, CONST:ro kills :cc.
++ b LABEL:ro.
++ bc CONST:ro, CONST:ro, LABEL:ro.
++ bcctr CONST:ro, CONST:ro, CONST:ro.
++ bcctrl CONST:ro, CONST:ro, CONST:ro.
++ bclr CONST:ro, CONST:ro, CONST:ro.
++ bl LABEL:ro.
++ cmp CR:ro, CONST:ro, GPRI:ro, GPR:ro kills :cc.
++ cmpi CR:ro, CONST:ro, GPRI:ro, CONST:ro kills :cc.
++ cmpl CR:ro, CONST:ro, GPRI:ro, GPR:ro kills :cc.
++ cmpli CR:ro, CONST:ro, GPRI:ro, CONST:ro kills :cc.
++ divw GPRI:wo, GPRI:ro, GPRI:ro.
++ divwu GPRI:wo, GPRI:ro, GPRI:ro.
++ eqv GPRI:wo, GPRI:ro, GPRI:ro.
++ extsb GPRI:wo, GPRI:ro.
++ extsh GPRI:wo, GPRI:ro.
++ fadd FD:wo, FD:ro, FD:ro.
++ fadds FS:wo, FS:ro, FS:ro.
++ fcmpo CR:wo, FD:ro, FD:ro.
++ fdiv FD:wo, FD:ro, FD:ro.
++ fdivs FS:wo, FS:ro, FS:ro.
++ fneg FS+FD:wo, FS+FD:ro.
++ fmul FD:wo, FD:ro, FD:ro.
++ fmuls FS:wo, FS:ro, FS:ro.
++ frsp FS:wo, FD:ro.
++ fsub FD:wo, FD:ro, FD:ro.
++ fsubs FS:wo, FS:ro, FS:ro.
++ fmr FS+FD:wo, FS+FD:ro.
++ lbzx GPRI:wo, GPR:ro, GPR:ro.
++ lbz GPRI:wo, GPRINDIRECT+GPRINDIRECTLO:ro.
++ lfd FD:wo, GPRINDIRECT+GPRINDIRECTLO:ro.
++ lfdu FD:wo, GPRINDIRECT+GPRINDIRECTLO:ro.
++ lfdx FD:wo, GPR:ro, GPR:ro.
++ lfs FS:wo, GPRINDIRECT+GPRINDIRECTLO:ro.
++ lfsu FS:wo, GPRINDIRECT+GPRINDIRECTLO:rw.
++ lfsx FS:wo, GPR:ro, GPR:ro.
++ lhzx GPRI:wo, GPR:ro, GPR:ro.
++ lhax GPRI:wo, GPR:ro, GPR:ro.
++ lha GPRI:wo, GPRINDIRECT+GPRINDIRECTLO:ro.
++ lhz GPRI:wo, GPRINDIRECT+GPRINDIRECTLO:ro.
++ lwzu GPRI:wo, GPRINDIRECT+GPRINDIRECTLO:ro.
++ lwzx GPRI:wo, GPR:ro, GPR:ro.
++ lwz GPRI:wo, GPRINDIRECT+GPRINDIRECTLO:ro.
++ nand GPRI:wo, GPRI:ro, GPRI:ro.
++ neg GPRI:wo, GPRI:ro.
++ nor GPRI:wo, GPRI:ro, GPRI:ro.
++ mfcr GPRI:wo.
++ mullw GPRI:wo, GPRI:ro, GPRI:ro.
++ mfspr GPRI:wo, SPR:ro.
++ mtspr SPR:wo, GPRI:ro.
++ or GPRI:wo, GPRI:ro, GPRI:ro.
++ orc GPRI:wo, GPRI:ro, GPRI:ro.
++ ori GPRI:wo, GPRI:ro, CONST+LOLABEL:ro.
++ orX "or." GPRI:wo, GPRI:ro, GPRI:ro kills :cc.
++ rlwinm GPRI:wo, GPRI:ro, CONST:ro, CONST:ro, CONST:ro.
++ slw GPRI:wo, GPRI:ro, GPRI:ro.
++ subf GPRI:wo, GPRI:ro, GPRI:ro.
++ sraw GPRI:wo, GPRI:ro, GPRI:ro.
++ srawi GPRI:wo, GPRI:ro, CONST:ro.
++ srw GPRI:wo, GPRI:ro, GPRI:ro.
++ stb GPRI:ro, GPRINDIRECT+GPRINDIRECTLO:rw.
++ stbx GPRI:ro, GPR:ro, GPR:ro.
++ stfd FD:ro, GPRINDIRECT+GPRINDIRECTLO:rw.
++ stfdu FD:ro, GPRINDIRECT+GPRINDIRECTLO:rw.
++ stfdx FD:ro, GPR:ro, GPR:ro.
++ stfs FS:ro, GPRINDIRECT+GPRINDIRECTLO:rw.
++ stfsu FS:ro, GPRINDIRECT+GPRINDIRECTLO:rw.
++ stfsx FS:ro, GPR:ro, GPR:ro.
++ sth GPRI:ro, GPRINDIRECT+GPRINDIRECTLO:rw.
++ sthx GPRI:ro, GPR:ro, GPR:ro.
++ stw GPRI:ro, GPRINDIRECT+GPRINDIRECTLO:rw.
++ stwx GPRI:ro, GPR:ro, GPR:ro.
++ stwu GPRI:ro, GPRINDIRECT+GPRINDIRECTLO:rw.
++ xor GPRI:wo, GPRI:ro, GPRI:ro.
++ xori GPRI:wo, GPRI:ro, CONST:ro.
++
++ gpr_gpr_gpr GPRI:wo, GPRI:ro, GPRI:ro.
++ gpr_gpr_si GPRI:wo, GPRI:ro, CONST:ro.
++ gpr_ro_gprindirect GPRI:ro, GPRINDIRECT:rw.
++ gpr_ro_gpr_gpr GPRI:ro, GPRI:ro, GPRI:ro.
++ gpr_wo_gprindirect GPRI:wo, GPRINDIRECT:ro.
++ gpr_wo_gpr_gpr GPRI:wo, GPRI:ro, GPRI:ro.
++
++ invalid "invalid".
++ comment "!" LABEL+LABELI:ro.
++
++
++
++MOVES
++
++ from GPR to GPR
++ gen
++ COMMENT("move GPR->GPR")
++ or %2, %1, %1
++
++/* GPRE exists solely to allow us to use regvar() (which can only be used in
++ an expression) as a register constant. */
++
++ from GPR to GPRE
++ gen
++ COMMENT("move GPR->GPRE")
++ or %2, %1, %1
++
++/* Constants */
++
++ from CONST smalls(%val) to GPR
++ gen
++ COMMENT("move CONST->GPRE")
++ addi %2, R0, {CONST, lo(%1.val)}
++
++ from CONST to GPR
++ gen
++ COMMENT("move CONST->GPRE")
++ addis %2, R0, {CONST, hi(%1.val)}
++ ori %2, %2, {CONST, lo(%1.val)}
++
++ from LABEL to GPR
++ gen
++ COMMENT("move LABEL->GPR")
++ addis %2, R0, {HILABEL, %1.adr}
++ ori %2, %2, {LOLABEL, %1.adr}
++
++/* Sign extension */
++
++ from SEX_B to GPR
++ gen
++ COMMENT("move SEX_B->GPR")
++ extsb %2, %1.reg
++
++ from SEX_H to GPR
++ gen
++ COMMENT("move SEX_H->GPR")
++ extsh %2, %1.reg
++
++/* Register + something */
++
++ from SUM_RC smalls(%off) to GPR
++ gen
++ COMMENT("move SUM_RC->GPR smalls")
++ addi %2, %1.reg, {CONST, lo(%1.off)}
++
++ from SUM_RC to GPR
++ gen
++ COMMENT("move SUM_RC->GPR large")
++ addi %2, %1.reg, {CONST, los(%1.off)}
++ addis %2, %2, {CONST, his(%1.off)}
++
++ from SUM_RR to GPR
++ gen
++ COMMENT("move SUM_RR->GPR")
++ add %2, %1.reg1, %1.reg2
++
++ from SUM_RR to GPR
++ gen
++ COMMENT("move SUM_RR->GPRE")
++ add %2, %1.reg1, %1.reg2
++
++/* Read/write byte */
++
++ from IND_RC_B smalls(%off) to GPR
++ gen
++ COMMENT("move IND_RC_B->GPR small")
++ lbz %2, {GPRINDIRECT, %1.reg, %1.off}
++
++ from IND_RC_B to GPR
++ gen
++ COMMENT("move IND_RC_B->GPR large")
++ addis SCRATCH, %1.reg, {CONST, his(%1.off)}
++ lbz %2, {GPRINDIRECT, SCRATCH, los(%1.off)}
++
++ from GPR to IND_RC_B smalls(%off)
++ gen
++ COMMENT("move GPR->IND_RC_B small")
++ stb %1, {GPRINDIRECT, %2.reg, %2.off}
++
++ from GPR to IND_RC_B
++ gen
++ COMMENT("move GPR->IND_RC_B large")
++ addis SCRATCH, %2.reg, {CONST, his(%2.off)}
++ stb %1, {GPRINDIRECT, SCRATCH, los(%2.off)}
++
++/* Read/write short */
++
++ from IND_RC_H smalls(%off) to GPR
++ gen
++ COMMENT("move IND_RC_H->GPR small")
++ lhz %2, {GPRINDIRECT, %1.reg, %1.off}
++
++ from IND_RC_H to GPR
++ gen
++ COMMENT("move IND_RC_H->GPR large")
++ addis SCRATCH, %1.reg, {CONST, his(%1.off)}
++ lhz %2, {GPRINDIRECT, SCRATCH, los(%1.off)}
++
++ from IND_RC_H_S smalls(%off) to GPR
++ gen
++ COMMENT("move IND_RC_H_S->GPR small")
++ lha %2, {GPRINDIRECT, %1.reg, %1.off}
++
++ from IND_RC_H_S to GPR
++ gen
++ COMMENT("move IND_RC_H_S->GPR large")
++ addis SCRATCH, %1.reg, {CONST, his(%1.off)}
++ lha %2, {GPRINDIRECT, SCRATCH, los(%1.off)}
++
++ from GPR to IND_RC_H smalls(%off)
++ gen
++ COMMENT("move GPR->IND_RC_H small")
++ sth %1, {GPRINDIRECT, %2.reg, %2.off}
++
++ from GPR to IND_RC_H
++ gen
++ COMMENT("move GPR->IND_RC_H large")
++ addis SCRATCH, %2.reg, {CONST, his(%2.off)}
++ sth %1, {GPRINDIRECT, SCRATCH, los(%2.off)}
++
++/* Read word */
++
++ from IND_RC_W smalls(%off) to GPR
++ gen
++ COMMENT("move IND_RC_W->GPR small")
++ lwz %2, {GPRINDIRECT, %1.reg, %1.off}
++
++ from IND_RC_W to GPR
++ gen
++ COMMENT("move IND_RC_W->GPR large")
++ addis %2, %1.reg, {CONST, his(%1.off)}
++ lwz %2, {GPRINDIRECT, %2, los(%1.off)}
++
++ from IND_RR_W to GPR
++ gen
++ COMMENT("move IND_RR_W->GPR")
++ lwzx %2, %1.reg1, %1.reg2
++
++ from IND_LABEL_W to GPR
++ gen
++ COMMENT("move IND_LABEL_W->GPR")
++ move {LABEL, %1.adr}, SCRATCH
++ lwz %2, {GPRINDIRECT, SCRATCH, 0}
++
++ from IND_RC_W smalls(%off) to FS
++ gen
++ COMMENT("move IND_RC_W->FS small")
++ lfs %2, {GPRINDIRECT, %1.reg, %1.off}
++
++ from IND_RC_W to FS
++ gen
++ COMMENT("move IND_RC_W->FS large")
++ addis SCRATCH, %1.reg, {CONST, his(%1.off)}
++ lfs %2, {GPRINDIRECT, SCRATCH, los(%1.off)}
++
++ from IND_RR_W to FS
++ gen
++ COMMENT("move IND_RR_W->FS")
++ lfsx %2, %1.reg1, %1.reg2
++
++ from IND_LABEL_W to FS
++ gen
++ COMMENT("move IND_LABEL_W->FS")
++ move {LABEL, %1.adr}, SCRATCH
++ lfs %2, {GPRINDIRECT, SCRATCH, 0}
++
++/* Write word */
++
++ from GPR to IND_RC_W smalls(%off)
++ gen
++ COMMENT("move GPR->IND_RC_W small")
++ stw %1, {GPRINDIRECT, %2.reg, %2.off}
++
++ from GPR to IND_RC_W
++ gen
++ COMMENT("move GPR->IND_RC_W large")
++ addis SCRATCH, %2.reg, {CONST, his(%2.off)}
++ stw %1, {GPRINDIRECT, SCRATCH, los(%2.off)}
++
++ from GPR to IND_RR_W
++ gen
++ COMMENT("move GPR->IND_RR_W")
++ stwx %1, %2.reg1, %2.reg2
++
++ from GPR to IND_LABEL_W
++ gen
++ COMMENT("move GPR->IND_LABEL_D")
++ move {LABEL, %2.adr}, SCRATCH
++ stw %1, {GPRINDIRECT, SCRATCH, 0}
++
++ from FS to IND_RC_W smalls(%off)
++ gen
++ COMMENT("move FS->IND_RC_W small")
++ stfs %1, {GPRINDIRECT, %2.reg, %2.off}
++
++ from FS to IND_RC_W
++ gen
++ COMMENT("move FS->IND_RC_W large")
++ addis SCRATCH, %2.reg, {CONST, his(%2.off)}
++ stfs %1, {GPRINDIRECT, SCRATCH, los(%2.off)}
++
++ from FS to IND_RR_W
++ gen
++ COMMENT("move FS->IND_RR_W")
++ stfsx %1, %2.reg1, %2.reg2
++
++ from FS to IND_LABEL_W
++ gen
++ COMMENT("move FS->IND_LABEL_D")
++ move {LABEL, %2.adr}, SCRATCH
++ stfs %1, {GPRINDIRECT, SCRATCH, 0}
++
++/* Read double */
++
++ from IND_RC_D smalls(%off) to FD
++ gen
++ COMMENT("move IND_RC_D->FD small")
++ lfd %2, {GPRINDIRECT, %1.reg, %1.off}
++
++ from IND_RC_D to FD
++ gen
++ COMMENT("move IND_RC_D->FD large")
++ addis SCRATCH, %1.reg, {CONST, his(%1.off)}
++ lfd %2, {GPRINDIRECT, SCRATCH, los(%1.off)}
++
++ from IND_RR_D to FD
++ gen
++ COMMENT("move IND_RR_D->FD")
++ lfdx %2, %1.reg1, %1.reg2
++
++ from IND_LABEL_D to FD
++ gen
++ COMMENT("move IND_LABEL_D->FD")
++ move {LABEL, %1.adr}, SCRATCH
++ lfd %2, {GPRINDIRECT, SCRATCH, 0}
++
++/* Write double */
++
++ from FD to IND_RC_D smalls(%off)
++ gen
++ COMMENT("move FD->IND_RC_D small")
++ stfd %1, {GPRINDIRECT, %2.reg, %2.off}
++
++ from FD to IND_RC_D
++ gen
++ COMMENT("move FD->IND_RC_D large")
++ addis SCRATCH, %2.reg, {CONST, his(%2.off)}
++ stfd %1, {GPRINDIRECT, SCRATCH, los(%2.off)}
++
++ from FD to IND_RR_D
++ gen
++ COMMENT("move FD->IND_RR_W")
++ stfdx %1, %2.reg1, %2.reg2
++
++ from FD to IND_LABEL_D
++ gen
++ COMMENT("move FD->IND_LABEL_D")
++ move {LABEL, %2.adr}, SCRATCH
++ stfd %1, {GPRINDIRECT, SCRATCH, 0}
++
++/* Extract condition code field (actually produces (CC&3)<<2) */
++
++ from CR0 to GPR
++ gen
++ COMMENT("move CR0->GPR")
++ mfcr %2
++ rlwinm %2, %2, {CONST, 4}, {CONST, 32-4}, {CONST, 31-2}
++
++/* Comparisons */
++
++ from TRISTATE_RR_S to CR0
++ gen
++ cmp %2, {CONST, 0}, %1.reg1, %1.reg2
++
++ from TRISTATE_RR_U to CR0
++ gen
++ cmpl %2, {CONST, 0}, %1.reg1, %1.reg2
++
++ from TRISTATE_RC_S to CR0
++ gen
++ COMMENT("move TRISTATE_RC_S->CR0 large")
++ move {CONST, %1.val}, SCRATCH
++ cmp %2, {CONST, 0}, %1.reg, SCRATCH
++
++ from TRISTATE_RC_U smallu(%val) to CR0
++ gen
++ COMMENT("move TRISTATE_RC_U->CR0 small")
++ cmpli %2, {CONST, 0}, %1.reg, {CONST, %1.val}
++
++ from TRISTATE_RC_U to CR0
++ gen
++ COMMENT("move TRISTATE_RC_U->CR0")
++ move {CONST, %1.val}, SCRATCH
++ cmpl %2, {CONST, 0}, %1.reg, SCRATCH
++
++ from TRISTATE_FF to CR0
++ gen
++ COMMENT("move TRISTATE_FF->CR0")
++ fcmpo %2, {FD, %1.reg1}, {FD, %1.reg2}
++
++ from GPR to CR0
++ gen
++ COMMENT("move GPR->CR0")
++ orX SCRATCH, %1, %1 /* alas, can't call test */
++
++ from TRISTATE_RR_S + TRISTATE_RC_S + TRISTATE_FF to GPR
++ gen
++ COMMENT("move TRISTATE_R*_S->GPR")
++ move %1, C0
++ move C0, SCRATCH
++ move {LABEL, ".tristate_s_table"}, %2
++ lwzx %2, %2, SCRATCH
++
++ from TRISTATE_RR_U + TRISTATE_RC_U to GPR
++ gen
++ COMMENT("move TRISTATE_R*_U->GPR")
++ move %1, C0
++ move C0, SCRATCH
++ move {LABEL, ".tristate_u_table"}, %2
++ lwzx %2, %2, SCRATCH
++
++/* Logicals */
++
++ from NOT_R to GPR
++ gen
++ COMMENT("move NOT_R->GPR")
++ nor %2, %1.reg, %1.reg
++
++ from AND_RR to GPR
++ gen
++ COMMENT("move AND_RR->GPR")
++ and %2, %1.reg1, %1.reg2
++
++ from AND_RC smallu(%val) to GPR
++ gen
++ COMMENT("move AND_RC->GPR small")
++ andiX %2, %1.reg, {CONST, %1.val}
++
++ from AND_RC to GPR
++ gen
++ COMMENT("move AND_RC->GPR")
++ move {CONST, %1.val}, SCRATCH
++ and %2, %1.reg, SCRATCH
++
++ from OR_RR to GPR
++ gen
++ COMMENT("move OR_RR->GPR")
++ or %2, %1.reg1, %1.reg2
++
++ from OR_RC smallu(%val) to GPR
++ gen
++ COMMENT("move OR_RC->GPR small")
++ ori %2, %1.reg, {CONST, %1.val}
++
++ from OR_RC to GPR
++ gen
++ COMMENT("move OR_RC->GPR")
++ move {CONST, %1.val}, SCRATCH
++ or %2, %1.reg, SCRATCH
++
++ from XOR_RR to GPR
++ gen
++ COMMENT("move XOR_RR->GPR")
++ xor %2, %1.reg1, %1.reg2
++
++ from XOR_RC smallu(%val) to GPR
++ gen
++ COMMENT("move XOR_RC->GPR small")
++ xori %2, %1.reg, {CONST, %1.val}
++
++ from XOR_RC to GPR
++ gen
++ COMMENT("move XOR_RC->GPR")
++ move {CONST, %1.val}, SCRATCH
++ xor %2, %1.reg, SCRATCH
++
++/* Miscellaneous */
++
++ from OP_ALL_W + LABEL + CONST to GPRE
++ gen
++ move %1, %2.reg
++
++
++TESTS
++
++ to test GPR
++ gen
++ orX SCRATCH, %1, %1
++
++
++
++STACKINGRULES
++
++ from GPR to STACK
++ gen
++ COMMENT("stack GPR")
++ stwu %1, {GPRINDIRECT, SP, 0-4}
++
++ from CONST to STACK
++ uses REG
++ gen
++ COMMENT("stack CONST")
++ move %1, %a
++ stwu %a, {GPRINDIRECT, SP, 0-4}
++
++ from LABEL to STACK
++ uses REG
++ gen
++ COMMENT("stack LABEL")
++ move %1, {GPRE, %a}
++ stwu %a, {GPRINDIRECT, SP, 0-4}
++
++ from SEX_B to STACK
++ gen
++ COMMENT("stack SEX_B")
++ extsb SCRATCH, %1.reg
++ stwu SCRATCH, {GPRINDIRECT, SP, 0-4}
++
++ from SEX_H to STACK
++ gen
++ COMMENT("stack SEX_H")
++ extsh SCRATCH, %1.reg
++ stwu SCRATCH, {GPRINDIRECT, SP, 0-4}
++
++ from SUM_ALL + TRISTATE_ALL + LOGICAL_ALL to STACK
++ gen
++ move %1, {GPRE, SCRATCH}
++ stwu SCRATCH, {GPRINDIRECT, SP, 0-4}
++
++ from IND_ALL_W to STACK
++ gen
++ move %1, SCRATCH
++ stwu SCRATCH, {GPRINDIRECT, SP, 0-4}
++
++ from IND_ALL_D to STACK
++ gen
++ move %1, {FD, FSCRATCH}
++ stfdu {FD, FSCRATCH}, {GPRINDIRECT, SP, 0-8}
++
++ from FD to STACK
++ gen
++ COMMENT("stack FD")
++ stfdu %1, {GPRINDIRECT, SP, 0-8}
++
++ from FS to STACK
++ gen
++ COMMENT("stack FS")
++ stfsu %1, {GPRINDIRECT, SP, 0-4}
++
++ from TOKEN to STACK
++ gen
++ invalid.
++
++
++
++COERCIONS
++
++ from REG
++ uses REG
++ gen
++ COMMENT("coerce REG->REG")
++ move %1, %a
++ yields %a
++
++ from CONST
++ uses REG
++ gen
++ COMMENT("coerce CONST->REG")
++ move %1, %a
++ yields %a
++
++ from LABEL
++ uses REG
++ gen
++ COMMENT("coerce LABEL->REG")
++ move %1, {GPRE, %a}
++ yields %a
++
++ from STACK
++ uses REG
++ gen
++ COMMENT("coerce STACK->REG")
++ lwz %a, {GPRINDIRECT, SP, 0}
++ addi SP, SP, {CONST, 4}
++ yields %a
++
++ from SEX_B
++ uses REG
++ gen
++ COMMENT("coerce SEX_B->REG")
++ extsb %a, %1.reg
++ yields %a
++
++ from SEX_H
++ uses REG
++ gen
++ COMMENT("coerce SEX_H->REG")
++ extsh %a, %1.reg
++ yields %a
++
++ from SUM_ALL + TRISTATE_ALL + LOGICAL_ALL
++ uses REG
++ gen
++ move %1, {GPRE, %a}
++ yields %a
++
++ from FS
++ uses FREG
++ gen
++ fmr {FS, %a}, %1
++ yields {FS, %a}
++
++ from FD
++ uses FREG
++ gen
++ fmr {FD, %a}, %1
++ yields {FD, %a}
++
++ from STACK
++ uses FREG
++ gen
++ COMMENT("coerce STACK->FD")
++ lfd {FD, %a}, {GPRINDIRECT, SP, 0}
++ addi SP, SP, {CONST, 8}
++ yields {FD, %a}
++
++ from STACK
++ uses FREG
++ gen
++ COMMENT("coerce STACK->FS")
++ lfs {FS, %a}, {GPRINDIRECT, SP, 0}
++ addi SP, SP, {CONST, 4}
++ yields {FS, %a}
++
++ from IND_ALL_W
++ uses REG
++ gen
++ move %1, %a
++ yields %a
++
++ from IND_ALL_W
++ uses FREG
++ gen
++ move %1, {FS, %a}
++ yields {FS, %a}
++
++ from IND_ALL_D
++ uses FREG
++ gen
++ move %1, {FD, %a}
++ yields {FD, %a}
++
++
++
++
++PATTERNS
++
++/* Intrinsics */
++
++ pat loc /* Load constant */
++ yields {CONST, $1}
++
++ pat dup $1==INT32 /* Duplicate word on top of stack */
++ with GPR
++ yields %1 %1
++
++ pat dup $1==INT64 /* Duplicate double-word on top of stack */
++ with GPR GPR
++ yields %2 %1 %2 %1
++
++ pat exg $1==INT32 /* Exchange top two words on stack */
++ with GPR GPR
++ yields %1 %2
++
++ pat stl lol $1==$2 /* Store then load local */
++ leaving
++ dup 4
++ stl $1
++
++ pat lal sti lal loi $1==$3 && $2==$4 /* Store then load local, of a different size */
++ leaving
++ dup INT32
++ lal $1
++ sti $2
++
++ pat ste loe $1==$2 /* Store then load external */
++ leaving
++ dup 4
++ ste $1
++
++
++/* Type conversions */
++
++ pat loc loc cii loc loc cii $1==$4 && $2==$5 /* madness, generated by the C compiler */
++ leaving
++ loc $1
++ loc $2
++ cii
++
++ pat loc loc cii loc loc cii $2==INT32 && $5==INT32 && $4<$2 /* madness, generated by the C compiler */
++ leaving
++ loc $4
++ loc $5
++ cii
++
++ pat loc loc ciu /* signed X -> unsigned X */
++ leaving
++ loc $1
++ loc $2
++ cuu
++
++ pat loc loc cuu $1==$2 /* unsigned X -> unsigned X */
++ /* nop */
++
++ pat loc loc cii $1==$2 /* signed X -> signed X */
++ /* nop */
++
++ pat loc loc cui $1==$2 /* unsigned X -> signed X */
++ /* nop */
++
++ pat loc loc cui $1==INT8 && $2==INT32 /* unsigned char -> signed int */
++ /* nop */
++
++ pat loc loc cui $1==INT16 && $2==INT32 /* unsigned short -> signed int */
++ /* nop */
++
++ pat loc loc cii $1==INT8 && $2==INT32 /* signed char -> signed int */
++ with GPR
++ yields {SEX_B, %1}
++
++ pat loc loc cii $1==2 && $2==4 /* signed char -> signed short */
++ with GPR
++ yields {SEX_H, %1}
++
++
++
++
++
++/* Local variables */
++
++ pat lal /* Load address of local */
++ yields {SUM_RC, FP, $1}
++
++ pat lol inreg($1)>0 /* Load from local */
++ yields {LOCAL, $1}
++
++ pat lol /* Load from local */
++ leaving
++ lal $1
++ loi INT32
++
++ pat ldl /* Load double-word from local */
++ leaving
++ lal $1
++ loi INT32*2
++
++ pat stl inreg($1)>0 /* Store to local */
++ with CONST + LABEL + GPR + OP_ALL_W
++ kills regvar($1), LOCAL %off==$1
++ gen
++ move %1, {GPRE, regvar($1)}
++
++ pat stl /* Store to local */
++ leaving
++ lal $1
++ sti INT32
++
++ pat sdl /* Store double-word to local */
++ leaving
++ lal $1
++ sti INT32*2
++
++ pat lil inreg($1)>0 /* Load from indirected local */
++ uses REG
++ gen
++ lwz %a, {GPRINDIRECT, regvar($1), 0}
++ yields %a
++
++ pat lil /* Load from indirected local */
++ leaving
++ lol $1
++ loi INT32
++
++ pat sil /* Save to indirected local */
++ leaving
++ lol $1
++ sti INT32
++
++ pat stl lol $1==$2 /* Save then load (generated by C compiler) */
++ leaving
++ dup 4
++ stl $1
++
++ pat zrl /* Zero local */
++ leaving
++ loc 0
++ stl $1
++
++ pat inl /* Increment local */
++ leaving
++ lol $1
++ loc 1
++ adi 4
++ stl $1
++
++ pat del /* Decrement local */
++ leaving
++ lol $1
++ loc 1
++ sbi 4
++ stl $1
++
++
++/* Global variables */
++
++ pat lpi /* Load address of external function */
++ leaving
++ lae $1
++
++ pat lae /* Load address of external */
++ yields {LABEL, $1}
++
++ pat loe /* Load word external */
++ leaving
++ lae $1
++ loi INT32
++
++ pat ste /* Store word external */
++ leaving
++ lae $1
++ sti INT32
++
++ pat lde /* Load double-word external */
++ leaving
++ lae $1
++ loi INT64
++
++ pat sde /* Store double-word external */
++ leaving
++ lae $1
++ sti INT64
++
++ pat zre /* Zero external */
++ leaving
++ loc 0
++ ste $1
++
++ pat ine /* Increment external */
++ uses REG={LABEL, $1}, REG
++ gen
++ lwz %b, {GPRINDIRECT, %a, 0}
++ addi %b, %b, {CONST, 1}
++ stw %b, {GPRINDIRECT, %a, 0}
++
++ pat dee /* Decrement external */
++ uses REG={LABEL, $1}, REG
++ gen
++ lwz %b, {GPRINDIRECT, %a, 0}
++ addi %b, %b, {CONST, 0-1}
++ stw %b, {GPRINDIRECT, %a, 0}
++
++
++
++/* Structures */
++
++ pat lof /* Load word offsetted */
++ leaving
++ adp $1
++ loi INT32
++
++ pat ldf /* Load double-word offsetted */
++ leaving
++ adp $1
++ loi INT64
++
++ pat stf /* Store word offsetted */
++ leaving
++ adp $1
++ sti INT32
++
++ pat sdf /* Store double-word offsetted */
++ leaving
++ adp $1
++ sti INT64
++
++
++
++/* Loads and stores */
++
++ pat loi $1==INT8 /* Load byte indirect */
++ with GPR
++ uses REG
++ gen
++ lbz %a, {GPRINDIRECT, %1, 0}
++ yields %a
++ with SUM_RR
++ uses reusing %1, REG
++ gen
++ lbzx %a, %1.reg1, %1.reg2
++ yields %a
++ with SUM_RC
++ uses REG
++ gen
++ move {IND_RC_B, %1.reg, %1.off}, %a
++ yields %a
++
++ pat loi loc loc cii $1==INT16 && $2==INT16 && $3==INT32 /* Load half-word indirect and sign extend */
++ with GPR
++ uses REG
++ gen
++ lha %a, {GPRINDIRECT, %1, 0}
++ yields %a
++ with SUM_RR
++ uses reusing %1, REG
++ gen
++ lhax %a, %1.reg1, %1.reg2
++ yields %a
++ with SUM_RC
++ uses REG
++ gen
++ move {IND_RC_H_S, %1.reg, %1.off}, %a
++ yields %a
++
++ pat loi $1==INT16 /* Load half-word indirect */
++ with GPR
++ uses REG
++ gen
++ lhz %a, {GPRINDIRECT, %1, 0}
++ yields %a
++ with SUM_RR
++ uses reusing %1, REG
++ gen
++ lhzx %a, %1.reg1, %1.reg2
++ yields %a
++ with SUM_RC
++ uses REG
++ gen
++ move {IND_RC_H, %1.reg, %1.off}, %a
++ yields %a
++
++ pat loi $1==INT32 /* Load word indirect */
++ with GPR
++ yields {IND_RC_W, %1, 0}
++ with SUM_RC
++ yields {IND_RC_W, %1.reg, %1.off}
++ with SUM_RR
++ yields {IND_RR_W, %1.reg1, %1.reg2}
++ with LABEL
++ yields {IND_LABEL_W, %1.adr}
++
++ pat loi $1==INT64 /* Load double-word indirect */
++ with GPR
++ yields {IND_RC_D, %1, 0}
++ with SUM_RC
++ yields {IND_RC_D, %1.reg, %1.off}
++ with SUM_RR
++ yields {IND_RR_D, %1.reg1, %1.reg2}
++ with LABEL
++ yields {IND_LABEL_D, %1.adr}
++
++ pat loi /* Load arbitrary size */
++ leaving
++ loc $1
++ los INT32
++
++ pat los /* Load arbitrary size */
++ with GPR3 GPR4 STACK
++ kills ALL
++ gen
++ bl {LABEL, ".los"}
++
++ pat sti $1==INT8 /* Store byte indirect */
++ with GPR GPR
++ gen
++ stb %2, {GPRINDIRECT, %1, 0}
++ with SUM_RR GPR
++ gen
++ stbx %2, %1.reg1, %1.reg2
++ with SUM_RC GPR
++ gen
++ move %2, {IND_RC_B, %1.reg, %1.off}
++ with GPR SEX_B
++ gen
++ stb %2.reg, {GPRINDIRECT, %1, 0}
++ with SUM_RR SEX_B
++ gen
++ stbx %2.reg, %1.reg1, %1.reg2
++ with SUM_RC SEX_B
++ gen
++ move %2.reg, {IND_RC_B, %1.reg, %1.off}
++
++ pat sti $1==INT16 /* Store half-word indirect */
++ with GPR GPR
++ gen
++ sth %2, {GPRINDIRECT, %1, 0}
++ with SUM_RR GPR
++ gen
++ sthx %2, %1.reg1, %1.reg2
++ with SUM_RC GPR
++ gen
++ move %2, {IND_RC_H, %1.reg, %1.off}
++ with GPR SEX_H
++ gen
++ sth %2.reg, {GPRINDIRECT, %1, 0}
++ with SUM_RR SEX_H
++ gen
++ sthx %2.reg, %1.reg1, %1.reg2
++ with SUM_RC SEX_H
++ gen
++ move %2.reg, {IND_RC_H, %1.reg, %1.off}
++
++ pat sti $1==INT32 /* Store word indirect */
++ with GPR GPR+FS
++ gen
++ move %2, {IND_RC_W, %1, 0}
++ with SUM_RR GPR+FS
++ gen
++ move %2, {IND_RR_W, %1.reg1, %1.reg2}
++ with SUM_RC GPR+FS
++ gen
++ move %2, {IND_RC_W, %1.reg, %1.off}
++ with LABEL GPR+FS
++ gen
++ move %2, {IND_LABEL_W, %1.adr}
++
++ pat sti $1==INT64 /* Store double-word indirect */
++ with GPR FD
++ gen
++ move %2, {IND_RC_D, %1, 0}
++ with SUM_RR FD
++ gen
++ move %2, {IND_RR_D, %1.reg1, %1.reg2}
++ with SUM_RC FD
++ gen
++ move %2, {IND_RC_D, %1.reg, %1.off}
++ with GPR GPR GPR
++ gen
++ stw %2, {GPRINDIRECT, %1, 0}
++ stw %3, {GPRINDIRECT, %1, 4}
++ with SUM_RC GPR GPR
++ gen
++ move %2, {IND_RC_W, %1.reg, %1.off}
++ move %3, {IND_RC_W, %1.reg, %1.off+4}
++ with LABEL FD
++ gen
++ move %2, {IND_LABEL_D, %1.adr}
++
++
++ pat sti /* Store arbitrary size */
++ leaving
++ loc $1
++ sts INT32
++
++ pat sts /* Load arbitrary size */
++ with GPR3 GPR4 STACK
++ kills ALL
++ gen
++ bl {LABEL, ".sts"}
++
++
++
++/* Arithmetic wrappers */
++
++ pat ads $1==4 /* Add var to pointer */
++ leaving adi $1
++
++ pat sbs $1==4 /* Subtract var from pointer */
++ leaving sbi $1
++
++ pat adp /* Add constant to pointer */
++ leaving
++ loc $1
++ adi 4
++
++ pat adu /* Add unsigned */
++ leaving
++ adi $1
++
++ pat sbu /* Subtract unsigned */
++ leaving
++ sbi $1
++
++ pat inc /* Add 1 */
++ leaving
++ loc 1
++ adi 4
++
++ pat dec /* Subtract 1 */
++ leaving
++ loc 1
++ sbi 4
++
++ pat loc mlu $2==2 /* Unsigned multiply by constant */
++ leaving
++ loc $1
++ mli 4
++
++ pat mlu /* Unsigned multiply by var */
++ leaving
++ mli $1
++
++ pat loc slu /* Shift left unsigned by constant amount */
++ leaving
++ loc $1
++ sli $2
++
++ pat slu /* Shift left unsigned by variable amount */
++ leaving
++ sli $1
++
++
++
++/* Word arithmetic */
++
++ pat adi $1==4 /* Add word (second + top) */
++ with REG REG
++ yields {SUM_RR, %1, %2}
++ with CONST REG
++ yields {SUM_RC, %2, %1.val}
++ with REG CONST
++ yields {SUM_RC, %1, %2.val}
++ with CONST SUM_RC
++ yields {SUM_RC, %2.reg, %2.off+%1.val}
++ with CONST LABEL
++ yields {LABEL, %2.adr+%1.val}
++
++ pat sbi $1==4 /* Subtract word (second - top) */
++ with REG REG
++ uses reusing %2, REG
++ gen
++ subf %a, %1, %2
++ yields %a
++ with CONST REG
++ yields {SUM_RC, %2, 0-%1.val}
++ with CONST SUM_RC
++ yields {SUM_RC, %2.reg, %2.off-%1.val}
++ with CONST LABEL
++ yields {LABEL, %2.adr+(0-%1.val)}
++
++ pat ngi $1==4 /* Negate word */
++ with REG
++ uses reusing %1, REG
++ gen
++ neg %a, %1
++ yields %a
++
++ pat mli $1==4 /* Multiply word (second * top) */
++ with REG REG
++ uses reusing %2, REG
++ gen
++ mullw %a, %2, %1
++ yields %a
++
++ pat dvi $1==4 /* Divide word (second / top) */
++ with REG REG
++ uses reusing %2, REG
++ gen
++ divw %a, %2, %1
++ yields %a
++
++ pat dvu $1==4 /* Divide unsigned word (second / top) */
++ with REG REG
++ uses reusing %2, REG
++ gen
++ divwu %a, %2, %1
++ yields %a
++
++ pat rmi $1==4 /* Remainder word (second % top) */
++ with REG REG
++ uses REG
++ gen
++ divw %a, %2, %1
++ mullw %a, %a, %1
++ subf %a, %a, %2
++ yields %a
++
++ pat rmu $1==4 /* Remainder unsigned word (second % top) */
++ with REG REG
++ uses REG
++ gen
++ divwu %a, %2, %1
++ mullw %a, %a, %1
++ subf %a, %a, %2
++ yields %a
++
++ pat and $1==4 /* AND word */
++ with GPR NOT_R
++ uses reusing %1, REG
++ gen
++ andc %a, %1, %2.reg
++ yields %a
++ with NOT_R GPR
++ uses reusing %1, REG
++ gen
++ andc %a, %2, %1.reg
++ yields %a
++ with GPR GPR
++ yields {AND_RR, %1, %2}
++ with GPR CONST
++ yields {AND_RC, %1, %2.val}
++ with CONST GPR
++ yields {AND_RC, %2, %1.val}
++
++ pat and !defined($1) /* AND set */
++ with STACK
++ gen
++ bl {LABEL, ".and"}
++
++ pat ior $1==4 /* OR word */
++ with GPR NOT_R
++ uses reusing %1, REG
++ gen
++ orc %a, %1, %2.reg
++ yields %a
++ with NOT_R GPR
++ uses reusing %2, REG
++ gen
++ orc %a, %2, %1.reg
++ yields %a
++ with GPR GPR
++ yields {OR_RR, %1, %2}
++ with GPR CONST
++ yields {OR_RC, %1, %2.val}
++ with CONST GPR
++ yields {OR_RC, %2, %1.val}
++
++ pat ior !defined($1) /* OR set */
++ with STACK
++ gen
++ bl {LABEL, ".ior"}
++
++ pat xor $1==4 /* XOR word */
++ with GPR GPR
++ yields {XOR_RR, %1, %2}
++ with GPR CONST
++ yields {XOR_RC, %1, %2.val}
++ with CONST GPR
++ yields {XOR_RC, %2, %1.val}
++
++ pat xor !defined($1) /* XOR set */
++ with STACK
++ gen
++ bl {LABEL, ".xor"}
++
++ pat com $1==INT32 /* NOT word */
++ with AND_RR
++ uses REG
++ gen
++ nand %a, %1.reg1, %1.reg2
++ yields %a
++ with OR_RR
++ uses REG
++ gen
++ nor %a, %1.reg1, %1.reg2
++ yields %a
++ with XOR_RR
++ uses REG
++ gen
++ eqv %a, %1.reg1, %1.reg2
++ yields %a
++ with GPR
++ yields {NOT_R, %1}
++
++ pat com !defined($1) /* NOT set */
++ with STACK
++ gen
++ bl {LABEL, ".com"}
++
++ pat sli $1==4 /* Shift left (second << top) */
++ with CONST GPR
++ uses reusing %2, REG
++ gen
++ rlwinm %a, %2, {CONST, (%1.val & 0x1F)}, {CONST, 0}, {CONST, 31-(%1.val & 0x1F)}
++ yields %a
++ with GPR GPR
++ uses reusing %2, REG
++ gen
++ slw %a, %2, %1
++ yields %a
++
++ pat sri $1==4 /* Shift right signed (second >> top) */
++ with CONST GPR
++ uses reusing %2, REG
++ gen
++ srawi %a, %2, {CONST, %1.val & 0x1F}
++ yields %a
++ with GPR GPR
++ uses reusing %2, REG
++ gen
++ sraw %a, %2, %1
++ yields %a
++
++ pat sru $1==4 /* Shift right unsigned (second >> top) */
++ with CONST GPR
++ uses reusing %2, REG
++ gen
++ rlwinm %a, %2, {CONST, 32-(%1.val & 0x1F)}, {CONST, (%1.val & 0x1F)}, {CONST, 31}
++ yields %a
++ with GPR GPR
++ uses reusing %2, REG
++ gen
++ srw %a, %2, %1
++ yields %a
++
++
++
++/* Arrays */
++
++ pat aar $1==INT32 /* Index array */
++ with GPR3 GPR4 GPR5
++ gen
++ bl {LABEL, ".aar4"}
++ yields R3
++
++ pat lae lar $2==INT32 && nicesize(rom($1, 3)) /* Load array */
++ leaving
++ lae $1
++ aar INT32
++ loi rom($1, 3)
++
++ pat lar $1==INT32 /* Load array */
++ with GPR3 GPR4 GPR5 STACK
++ kills ALL
++ gen
++ bl {LABEL, ".lar4"}
++
++ pat lae sar $2==INT32 && nicesize(rom($1, 3)) /* Store array */
++ leaving
++ lae $1
++ aar INT32
++ sti rom($1, 3)
++
++ pat sar $1==INT32 /* Store array */
++ with GPR3 GPR4 GPR5 STACK
++ kills ALL
++ gen
++ bl {LABEL, ".sar4"}
++
++
++
++
++/* Sets */
++
++ pat set defined($1) /* Create word with set bit */
++ leaving
++ loc 1
++ exg INT32
++ sli INT32
++
++ pat set !defined($1) /* Create structure with set bit (variable) */
++ with GPR3 GPR4 STACK
++ gen
++ bl {LABEL, ".set"}
++
++ pat inn defined($1) /* Test for set bit */
++ leaving
++ set INT32
++ and INT32
++
++ pat inn !defined($1) /* Test for set bit (variable) */
++ with GPR3 STACK
++ gen
++ bl {LABEL, ".inn"}
++
++
++
++/* Boolean resolutions */
++
++ pat teq /* top = (top == 0) */
++ with TRISTATE_ALL + GPR
++ uses reusing %1, REG
++ gen
++ move %1, C0
++ move C0, SCRATCH
++ move {LABEL, ".teq_table"}, %a
++ lwzx %a, %a, SCRATCH
++ yields %a
++
++ pat tne /* top = (top != 0) */
++ with TRISTATE_ALL + GPR
++ uses reusing %1, REG
++ gen
++ move %1, C0
++ move C0, SCRATCH
++ move {LABEL, ".tne_table"}, %a
++ lwzx %a, %a, SCRATCH
++ yields %a
++
++ pat tlt /* top = (top < 0) */
++ with TRISTATE_ALL + GPR
++ uses reusing %1, REG
++ gen
++ move %1, C0
++ move C0, SCRATCH
++ move {LABEL, ".tlt_table"}, %a
++ lwzx %a, %a, SCRATCH
++ yields %a
++
++ pat tle /* top = (top <= 0) */
++ with TRISTATE_ALL + GPR
++ uses reusing %1, REG
++ gen
++ move %1, C0
++ move C0, SCRATCH
++ move {LABEL, ".tle_table"}, %a
++ lwzx %a, %a, SCRATCH
++ yields %a
++
++ pat tgt /* top = (top > 0) */
++ with TRISTATE_ALL + GPR
++ uses reusing %1, REG
++ gen
++ move %1, C0
++ move C0, SCRATCH
++ move {LABEL, ".tgt_table"}, %a
++ lwzx %a, %a, SCRATCH
++ yields %a
++
++ pat tge /* top = (top >= 0) */
++ with TRISTATE_ALL + GPR
++ uses reusing %1, REG
++ gen
++ move %1, C0
++ move C0, SCRATCH
++ move {LABEL, ".tge_table"}, %a
++ lwzx %a, %a, SCRATCH
++ yields %a
++
++
++
++
++/* Simple branches */
++
++ pat zeq /* Branch if signed top == 0 */
++ with TRISTATE_ALL+GPR STACK
++ gen
++ move %1, C0
++ bc IFTRUE, EQ, {LABEL, $1}
++
++ pat beq
++ leaving
++ cmi INT32
++ zeq $1
++
++ pat zne /* Branch if signed top != 0 */
++ with TRISTATE_ALL+GPR STACK
++ gen
++ move %1, C0
++ bc IFFALSE, EQ, {LABEL, $1}
++
++ pat bne
++ leaving
++ cmi INT32
++ zne $1
++
++ pat zgt /* Branch if signed top > 0 */
++ with TRISTATE_ALL+GPR STACK
++ gen
++ move %1, C0
++ bc IFTRUE, GT, {LABEL, $1}
++
++ pat bgt
++ leaving
++ cmi INT32
++ zgt $1
++
++ pat zge /* Branch if signed top >= 0 */
++ with TRISTATE_ALL+GPR STACK
++ gen
++ move %1, C0
++ bc IFFALSE, LT, {LABEL, $1}
++
++ pat bge
++ leaving
++ cmi INT32
++ zge $1
++
++ pat zlt /* Branch if signed top < 0 */
++ with TRISTATE_ALL+GPR STACK
++ gen
++ move %1, C0
++ bc IFTRUE, LT, {LABEL, $1}
++
++ pat blt
++ leaving
++ cmi INT32
++ zlt $1
++
++ pat zle /* Branch if signed top >= 0 */
++ with TRISTATE_ALL+GPR STACK
++ gen
++ move %1, C0
++ bc IFFALSE, GT, {LABEL, $1}
++
++ pat ble
++ leaving
++ cmi INT32
++ zle $1
++
++
++/* Compare and jump */
++
++ pat cmi /* Signed tristate compare */
++ with CONST GPR
++ yields {TRISTATE_RC_S, %2, %1.val}
++ with GPR GPR
++ yields {TRISTATE_RR_S, %2, %1}
++
++ pat cmu /* Unsigned tristate compare */
++ with CONST GPR
++ yields {TRISTATE_RC_U, %2, %1.val}
++ with GPR GPR
++ yields {TRISTATE_RR_U, %2, %1}
++
++ pat cmp /* Compare pointers */
++ leaving
++ cmu INT32
++
++ pat cms $1==INT32 /* Compare blocks (word sized) */
++ leaving
++ cmi INT32
++
++
++
++
++/* Other branching and labelling */
++
++ pat lab topeltsize($1)==4 && !fallthrough($1)
++ gen
++ labeldef $1
++ yields R3
++
++ pat lab topeltsize($1)==4 && fallthrough($1)
++ with GPR3
++ gen
++ labeldef $1
++ yields %1
++
++ pat lab topeltsize($1)!=4
++ with STACK
++ kills ALL
++ gen
++ labeldef $1
++
++ pat bra topeltsize($1)==4 /* Unconditional jump with TOS GPRister */
++ with GPR3 STACK
++ gen
++ b {LABEL, $1}
++
++ pat bra topeltsize($1)!=4 /* Unconditional jump without TOS GPRister */
++ with STACK
++ gen
++ b {LABEL, $1}
++
++
++
++/* Miscellaneous */
++
++ pat cal /* Call procedure */
++ with STACK
++ kills ALL
++ gen
++ bl {LABEL, $1}
++
++ pat cai /* Call procedure indirect */
++ with GPR STACK
++ kills ALL
++ gen
++ mtspr CTR, %1
++ bcctrl ALWAYS, {CONST, 0}, {CONST, 0}
++
++ pat lfr $1==INT32 /* Load function result, word */
++ yields R3
++
++ pat lfr $1==INT64 /* Load function result, double-word */
++ yields R4 R3
++
++ pat ret $1==0 /* Return from procedure */
++ gen
++ return
++ b {LABEL, ".ret"}
++
++ pat ret $1==INT32 /* Return from procedure, word */
++ with GPR3
++ gen
++ return
++ b {LABEL, ".ret"}
++
++ pat ret $1==INT64 /* Return from procedure, double-word */
++ with GPR3 GPR4
++ gen
++ return
++ b {LABEL, ".ret"}
++
++ pat blm /* Block move constant length */
++ with GPR GPR STACK
++ uses REG
++ gen
++ move {CONST, $1}, %a
++ stwu %a, {GPRINDIRECT, SP, 0-4}
++ stwu %2, {GPRINDIRECT, SP, 0-4}
++ stwu %1, {GPRINDIRECT, SP, 0-4}
++ bl {LABEL, "_memmove"}
++ addi SP, SP, {CONST, 12}
++
++ pat bls /* Block move variable length */
++ with GPR GPR GPR STACK
++ gen
++ stwu %1, {GPRINDIRECT, SP, 0-4}
++ stwu %3, {GPRINDIRECT, SP, 0-4}
++ stwu %2, {GPRINDIRECT, SP, 0-4}
++ bl {LABEL, "_memmove"}
++ addi SP, SP, {CONST, 12}
++
++ pat csa /* Array-lookup switch */
++ with GPR3 GPR4 STACK
++ gen
++ b {LABEL, ".csa"}
++
++ pat csb /* Table-lookup switch */
++ with GPR3 GPR4 STACK
++ gen
++ b {LABEL, ".csb"}
++
++
++
++/* EM specials */
++
++ pat fil /* Set current filename */
++ leaving
++ lae $1
++ ste ".filename"
++
++ pat lin /* Set current line number */
++ leaving
++ loc $1
++ ste ".linenumber"
++
++ pat lni /* Increment line number */
++ leaving
++ ine ".linenumber"
++
++ pat lim /* Load EM trap ignore mask */
++ leaving
++ lde ".ignmask"
++
++ pat sim /* Store EM trap ignore mask */
++ leaving
++ ste ".ignmask"
++
++ pat trp /* Raise EM trap */
++ with GPR3
++ gen
++ bl {LABEL, ".trap"}
++
++ pat sig /* Set trap handler */
++ leaving
++ ste ".trppc"
++
++ pat rtt /* Return from trap */
++ leaving
++ ret 0
++
++ pat lxl $1==0 /* Load FP */
++ leaving
++ lor 0
++
++ pat lxl $1==1 /* Load caller's FP */
++ leaving
++ lxl 0
++ dch
++
++ pat dch /* FP -> caller FP */
++ with GPR
++ uses reusing %1, REG
++ gen
++ lwz %a, {GPRINDIRECT, %1, FP_OFFSET}
++ yields %a
++
++ pat lpb /* Convert FP to argument address */
++ leaving
++ adp EM_BSIZE
++
++ pat lxa /* Load caller's SP */
++ leaving
++ lxl $1
++ lpb
++
++ pat gto /* longjmp */
++ uses REG
++ gen
++ move {LABEL, $1}, %a
++ move {IND_RC_W, %a, 8}, FP
++ move {IND_RC_W, %a, 4}, SP
++ move {IND_RC_W, %a, 0}, %a
++ mtspr CTR, %a
++ bcctr ALWAYS, {CONST, 0}, {CONST, 0}
++
++#if 0
++
++ pat gto /* longjmp */
++ with STACK
++ gen
++ ld {LABEL, $1+2}
++ wspec {CONST, 1}
++ ld {LABEL, $1+4}
++ wspec {CONST, 0}
++ ld {LABEL, $1+0}
++ wspec {CONST, 2}
++
++ pat str $1==1 /* Store special GPRister */
++ with GPR0
++ gen
++ wspec {CONST, $1}
++
++#endif
++
++ pat lor $1==0 /* Load FP */
++ uses REG
++ gen
++ move FP, %a
++ yields %a
++
++ pat lor $1==1 /* Load SP */
++ uses REG
++ gen
++ move SP, %a
++ yields %a
++
++ pat lor $1==2 /* Load HP */
++ leaving
++ loe ".reghp"
++
++ pat str $1==0 /* Store FP */
++ with GPR
++ gen
++ move %1, FP
++
++ pat str $1==1 /* Store SP */
++ with GPR
++ gen
++ move %1, SP
++
++ pat str $1==2 /* Store HP */
++ leaving
++ ste ".reghp"
++
++ pat ass /* Adjust stack by variable amount */
++ with CONST
++ gen
++ move {SUM_RC, SP, %1.val}, {GPRE, SP}
++ with GPR
++ gen
++ move {SUM_RR, SP, %1}, {GPRE, SP}
++
++ pat asp /* Adjust stack by constant amount */
++ leaving
++ loc $1
++ ass
++
++
++
++/* Floating point support */
++
++ /* All very cheap and nasty --- this needs to be properly integrated into
++ * the code generator. ncg doesn't like having separate FPU registers. */
++
++ /* Single-precision */
++
++ pat zrf $1==INT32 /* Push zero */
++ leaving
++ loe ".fs_00000000"
++
++ pat adf $1==INT32 /* Add single */
++ with FS FS
++ uses reusing %1, FREG
++ gen
++ fadds {FS, %a}, %2, %1
++ yields {FS, %a}
++
++ pat sbf $1==INT32 /* Subtract single */
++ with FS FS
++ uses reusing %1, FREG
++ gen
++ fsubs {FS, %a}, %2, %1
++ yields {FS, %a}
++
++ pat mlf $1==INT32 /* Multiply single */
++ with FS FS
++ uses reusing %1, FREG
++ gen
++ fmuls {FS, %a}, %2, %1
++ yields {FS, %a}
++
++ pat dvf $1==INT32 /* Divide single */
++ with FS FS
++ uses reusing %1, FREG
++ gen
++ fdivs {FS, %a}, %2, %1
++ yields {FS, %a}
++
++ pat ngf $1==INT32 /* Negate single */
++ with FS
++ uses reusing %1, FREG
++ gen
++ fneg {FS, %a}, %1
++ yields {FS, %a}
++
++ pat cmf $1==INT32 /* Compare single */
++ with FS FS
++ yields {TRISTATE_FF, %2.reg, %1.reg}
++
++ pat loc loc cff $1==INT32 && $2==INT64 /* Convert single to double */
++ with FS
++ yields {FD, %1.reg}
++
++ pat loc loc cfu $1==INT32 && $2==INT32 /* Convert single to unsigned int */
++ with STACK
++ gen
++ bl {LABEL, ".cfu4"}
++
++ pat loc loc cfi $1==INT32 && $2==INT32 /* Convert single to signed int */
++ with STACK
++ gen
++ bl {LABEL, ".cfi4"}
++
++ pat loc loc cif $1==INT32 && $2==INT32 /* Convert integer to single */
++ with STACK
++ gen
++ bl {LABEL, ".cif4"}
++
++ pat loc loc cuf $1==INT32 && $2==INT32 /* Convert unsigned int to single */
++ with STACK
++ gen
++ bl {LABEL, ".cuf4"}
++
++ pat fef $1==INT32 /* Split single */
++ with STACK
++ gen
++ bl {LABEL, ".fef4"}
++
++ /* Double-precision */
++
++ pat zrf $1==INT64 /* Push zero */
++ leaving
++ lde ".fd_00000000"
++
++ pat adf $1==INT64 /* Add double */
++ with FD FD
++ uses FREG
++ gen
++ fadd {FD, %a}, %2, %1
++ yields {FD, %a}
++
++ pat sbf $1==INT64 /* Subtract double */
++ with FD FD
++ uses FREG
++ gen
++ fsub {FD, %a}, %2, %1
++ yields {FD, %a}
++
++ pat mlf $1==INT64 /* Multiply double */
++ with FD FD
++ uses reusing %1, FREG
++ gen
++ fmul {FD, %a}, %2, %1
++ yields {FD, %a}
++
++ pat dvf $1==INT64 /* Divide double */
++ with FD FD
++ uses reusing %1, FREG
++ gen
++ fdiv {FD, %a}, %2, %1
++ yields {FD, %a}
++
++ pat ngf $1==INT64 /* Negate double */
++ with FD
++ uses reusing %1, FREG
++ gen
++ fneg {FD, %a}, %1
++ yields {FD, %a}
++
++ pat cmf $1==INT64 /* Compare double */
++ with FD FD
++ yields {TRISTATE_FF, %2.reg, %1.reg}
++
++ pat loc loc cff $1==INT64 && $2==INT32 /* Convert double to single */
++ with FD
++ uses reusing %1, FREG
++ gen
++ frsp {FS, %a}, %1
++ yields {FS, %a}
++
++ pat loc loc cfu $1==INT64 && $2==INT32 /* Convert double to unsigned int */
++ with STACK
++ gen
++ bl {LABEL, ".cfu8"}
++
++ pat loc loc cfi $1==INT64 && $2==INT32 /* Convert double to signed int */
++ with STACK
++ gen
++ bl {LABEL, ".cfi8"}
++
++ pat loc loc cif $1==INT32 && $2==INT64 /* Convert integer to double */
++ with STACK
++ kills ALL
++ gen
++ bl {LABEL, ".cif8"}
++
++ pat loc loc cuf $1==INT32 && $2==INT64 /* Convert unsigned int to double */
++ with STACK
++ gen
++ bl {LABEL, ".cuf8"}
++
++ pat fef $1==INT64 /* Split double */
++ with FD
++ gen
++ addi SP, SP, {CONST, 0-8}
++ stfd %1, {GPRINDIRECT, SP, 0}
++ stwu SP, {GPRINDIRECT, SP, 0-4}
++ bl {LABEL, "___fef8"}
++ stw R3, {GPRINDIRECT, SP, 0}
++
++ pat fif $1==INT64 /* Multiply and split double (?) */
++ with STACK
++ gen
++ bl {LABEL, ".fif8"}
++
++