--- /dev/null
+/*
+ * VideoCore IV code generator for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+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
+