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"}
				
