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