754e96ef16
A 4-byte load from a label yields a token IND_RL_W. This token emits either lis/lwz or lis/lfs, if we want a general-purpose register or a floating-point register.
2588 lines
60 KiB
Plaintext
2588 lines
60 KiB
Plaintext
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) /* comment {LABEL, n} */
|
|
|
|
|
|
#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) (lo(n) | (((0-(lo(n)>>15)) & ~0xFFFF)))
|
|
#define his(n) ((hi(n) + (lo(n)>>15)) & 0xFFFF)
|
|
|
|
|
|
|
|
PROPERTIES
|
|
|
|
GPR /* any GPR */
|
|
REG /* any allocatable GPR */
|
|
REG_PAIR(8) /* speed hack for sti 8 */
|
|
FPR(8) /* any FPR */
|
|
FREG(8) /* any allocatable FPR */
|
|
FSREG /* any allocatable single-precision 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
|
|
|
|
FPR0(8) FPR1(8) FPR2(8) FPR3(8) FPR4(8) FPR5(8) FPR6(8) FPR7(8)
|
|
FPR8(8) FPR9(8) FPR10(8) FPR11(8) FPR12(8) FPR13(8) FPR14(8) FPR15(8)
|
|
FPR16(8) FPR17(8) FPR18(8) FPR19(8) FPR20(8) FPR21(8) FPR22(8) FPR23(8)
|
|
FPR24(8) FPR25(8) FPR26(8) FPR27(8) FPR28(8) FPR29(8) FPR30(8) FPR31(8)
|
|
|
|
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, REG, 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.
|
|
|
|
/* speed hack for sti 8 */
|
|
PAIR_R9_R10=R9+R10 : REG_PAIR.
|
|
PAIR_R7_R8=R7+R8 : REG_PAIR.
|
|
PAIR_R5_R6=R5+R6 : REG_PAIR.
|
|
PAIR_R3_R4=R3+R4 : REG_PAIR.
|
|
|
|
/*
|
|
* F14 to F31 are reserved for regvar, if we ever implement
|
|
* it. Don't add them to FREG; the register allocator would
|
|
* be too slow.
|
|
*/
|
|
F31("f31") : FPR, FPR31.
|
|
F30("f30") : FPR, FPR30.
|
|
F29("f29") : FPR, FPR29.
|
|
F28("f28") : FPR, FPR28.
|
|
F27("f27") : FPR, FPR27.
|
|
F26("f26") : FPR, FPR26.
|
|
F25("f25") : FPR, FPR25.
|
|
F24("f24") : FPR, FPR24.
|
|
F23("f23") : FPR, FPR23.
|
|
F22("f22") : FPR, FPR22.
|
|
F21("f21") : FPR, FPR21.
|
|
F20("f20") : FPR, FPR20.
|
|
F19("f19") : FPR, FPR19.
|
|
F18("f18") : FPR, FPR18.
|
|
F17("f17") : FPR, FPR17.
|
|
F16("f16") : FPR, FPR16.
|
|
F15("f15") : FPR, FPR15.
|
|
F14("f14") : FPR, 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, FPR0.
|
|
|
|
FS13("f13")=F13 : FSREG.
|
|
FS12("f12")=F12 : FSREG.
|
|
FS11("f11")=F11 : FSREG.
|
|
FS10("f10")=F10 : FSREG.
|
|
FS9("f9")=F9 : FSREG.
|
|
FS8("f8")=F8 : FSREG.
|
|
FS7("f7")=F7 : FSREG.
|
|
FS6("f6")=F6 : FSREG.
|
|
FS5("f5")=F5 : FSREG.
|
|
FS4("f4")=F4 : FSREG.
|
|
FS3("f3")=F3 : FSREG.
|
|
FS2("f2")=F2 : FSREG.
|
|
FS1("f1")=F1 : FSREG.
|
|
|
|
LR("lr") : SPR.
|
|
CTR("ctr") : SPR.
|
|
CR0("cr0") : CR.
|
|
|
|
#define RSCRATCH R0
|
|
#define FSCRATCH F0
|
|
|
|
|
|
TOKENS
|
|
|
|
/* Primitives */
|
|
|
|
CONST = { INT val; } 4 val.
|
|
LABEL = { ADDR adr; } 4 adr.
|
|
LABEL_HI = { ADDR adr; } 4 "hi16[" adr "]".
|
|
LABEL_HA = { ADDR adr; } 4 "ha16[" adr "]".
|
|
LABEL_LO = { ADDR adr; } 4 "lo16[" adr "]".
|
|
LABEL_STACK = { GPR reg; ADDR adr; } 4.
|
|
LOCAL = { INT off; } 4 ">>> BUG IN LOCAL".
|
|
|
|
/* Allows us to use regvar() to refer to registers */
|
|
|
|
GPRE = { GPR reg; } 4 reg.
|
|
|
|
/* Constants on the stack */
|
|
|
|
CONST_N8000 = { INT val; } 4.
|
|
CONST_N7FFF_N0001 = { INT val; } 4.
|
|
CONST_0000_7FFF = { INT val; } 4.
|
|
CONST_8000 = { INT val; } 4.
|
|
CONST_8001_FFFF = { INT val; } 4.
|
|
CONST_HZ = { INT val; } 4.
|
|
CONST_HL = { INT val; } 4.
|
|
|
|
/* Expression partial results */
|
|
|
|
SUM_RIS = { GPR reg; INT offhi; } 4.
|
|
SUM_RC = { GPR reg; INT off; } 4.
|
|
SUM_RR = { GPR reg1; GPR reg2; } 4.
|
|
|
|
SEX_B = { GPR reg; } 4.
|
|
SEX_H = { GPR reg; } 4.
|
|
|
|
IND_RC_B = { GPR reg; INT off; } 4 off "(" reg ")".
|
|
IND_RR_B = { GPR reg1; GPR reg2; } 4.
|
|
IND_RC_H = { GPR reg; INT off; } 4 off "(" reg ")".
|
|
IND_RR_H = { GPR reg1; GPR reg2; } 4.
|
|
IND_RC_H_S = { GPR reg; INT off; } 4 off "(" reg ")".
|
|
IND_RR_H_S = { GPR reg1; GPR reg2; } 4.
|
|
IND_RC_W = { GPR reg; INT off; } 4 off "(" reg ")".
|
|
IND_RL_W = { GPR reg; ADDR adr; } 4 "lo16[" adr "](" reg ")".
|
|
IND_RR_W = { GPR reg1; GPR reg2; } 4.
|
|
IND_RC_D = { GPR reg; INT off; } 8 off "(" reg ")".
|
|
IND_RR_D = { GPR reg1; GPR reg2; } 8.
|
|
|
|
NOT_R = { GPR reg; } 4.
|
|
|
|
AND_RR = { GPR reg1; GPR reg2; } 4.
|
|
OR_RR = { GPR reg1; GPR reg2; } 4.
|
|
OR_RIS = { GPR reg; INT valhi; } 4.
|
|
OR_RC = { GPR reg; INT val; } 4.
|
|
XOR_RR = { GPR reg1; GPR reg2; } 4.
|
|
XOR_RIS = { GPR reg; INT valhi; } 4.
|
|
XOR_RC = { GPR reg; INT val; } 4.
|
|
|
|
COND_RC = { GPR reg; INT val; } 4.
|
|
COND_RR = { GPR reg1; GPR reg2; } 4.
|
|
CONDL_RC = { GPR reg; INT val; } 4.
|
|
CONDL_RR = { GPR reg1; GPR reg2; } 4.
|
|
COND_FS = { FSREG reg1; FSREG reg2; } 4.
|
|
COND_FD = { FREG reg1; FREG reg2; } 4.
|
|
|
|
XEQ = { GPR reg; } 4.
|
|
XNE = { GPR reg; } 4.
|
|
XGT = { GPR reg; } 4.
|
|
XGE = { GPR reg; } 4.
|
|
XLT = { GPR reg; } 4.
|
|
XLE = { GPR reg; } 4.
|
|
|
|
|
|
SETS
|
|
|
|
/* signed 16-bit integer */
|
|
CONST2 = CONST_N8000 + CONST_N7FFF_N0001 + CONST_0000_7FFF.
|
|
/* integer that, when negated, fits signed 16-bit */
|
|
CONST2_WHEN_NEG = CONST_N7FFF_N0001 + CONST_0000_7FFF + CONST_8000.
|
|
/* unsigned 16-bit integer */
|
|
UCONST2 = CONST_0000_7FFF + CONST_8000 + CONST_8001_FFFF.
|
|
/* any constant on stack */
|
|
CONST_STACK = CONST_N8000 + CONST_N7FFF_N0001 + CONST_0000_7FFF +
|
|
CONST_8000 + CONST_8001_FFFF + CONST_HZ + CONST_HL.
|
|
|
|
SUM_ALL = SUM_RC + SUM_RR.
|
|
|
|
SEX_ALL = SEX_B + SEX_H.
|
|
|
|
LOGICAL_ALL = NOT_R + AND_RR + OR_RR + OR_RC + XOR_RR +
|
|
XOR_RC.
|
|
|
|
/* indirect values */
|
|
IND_ALL_B = IND_RC_B + IND_RR_B.
|
|
IND_ALL_H = IND_RC_H + IND_RR_H + IND_RC_H_S + IND_RR_H_S.
|
|
IND_ALL_W = IND_RC_W + IND_RL_W + IND_RR_W.
|
|
IND_ALL_D = IND_RC_D + IND_RR_D.
|
|
IND_ALL_BHW = IND_ALL_B + IND_ALL_H + IND_ALL_W.
|
|
|
|
/* anything killed by sti (store indirect) */
|
|
MEMORY = IND_ALL_BHW + IND_ALL_D.
|
|
|
|
/* any stack token that we can easily move to GPR */
|
|
ANY_BHW = REG + CONST_STACK + LABEL + SEX_ALL +
|
|
SUM_ALL + IND_ALL_BHW + LOGICAL_ALL.
|
|
|
|
|
|
INSTRUCTIONS
|
|
|
|
/* We give time as cycles of total latency from Freescale
|
|
* Semiconductor, MPC7450 RISC Microprocessor Family Reference
|
|
* Manual, Rev. 5, section 6.6.
|
|
*
|
|
* We have only 4-byte alignment for doubles; 8-byte alignment is
|
|
* optimal. We guess the misalignment penalty by adding 1 cycle to
|
|
* the cost of loading or storing a double:
|
|
* lfd lfdu lfdx: 4 -> 5
|
|
* stfd stfdu stfdx: 3 -> 4
|
|
*/
|
|
cost(4, 1) /* space, time */
|
|
|
|
add GPR:wo, GPR:ro, GPR:ro.
|
|
addX "add." GPR:wo, GPR:ro, GPR:ro.
|
|
addi GPR:wo, GPR:ro, CONST+LABEL_LO:ro.
|
|
li GPR:wo, CONST:ro.
|
|
addis GPR:wo, GPR:ro, CONST+LABEL_HI+LABEL_HA:ro.
|
|
lis GPR:wo, CONST+LABEL_HI+LABEL_HA:ro.
|
|
and GPR:wo, GPR:ro, GPR:ro.
|
|
andc GPR:wo, GPR:ro, GPR:ro.
|
|
andiX "andi." GPR:wo:cc, GPR:ro, CONST:ro.
|
|
andisX "andis." GPR:wo:cc, GPR:ro, CONST:ro.
|
|
b LABEL:ro.
|
|
bc CONST:ro, CONST:ro, LABEL:ro.
|
|
beq LABEL:ro.
|
|
bne LABEL:ro.
|
|
bgt LABEL:ro.
|
|
bge LABEL:ro.
|
|
blt LABEL:ro.
|
|
ble LABEL:ro.
|
|
bxx LABEL:ro. /* dummy */
|
|
bcctr CONST:ro, CONST:ro, CONST:ro.
|
|
bctr.
|
|
bcctrl CONST:ro, CONST:ro, CONST:ro.
|
|
bctrl.
|
|
bclr CONST:ro, CONST:ro, CONST:ro.
|
|
bl LABEL:ro.
|
|
cmp CR:ro, CONST:ro, GPR:ro, GPR:ro kills :cc.
|
|
cmpw GPR:ro, GPR:ro kills :cc.
|
|
cmpi CR:ro, CONST:ro, GPR:ro, CONST:ro kills :cc.
|
|
cmpwi GPR:ro, CONST:ro kills :cc.
|
|
cmpl CR:ro, CONST:ro, GPR:ro, GPR:ro kills :cc.
|
|
cmplw GPR:ro, GPR:ro kills :cc.
|
|
cmpli CR:ro, CONST:ro, GPR:ro, CONST:ro kills :cc.
|
|
cmplwi GPR:ro, CONST:ro kills :cc.
|
|
divw GPR:wo, GPR:ro, GPR:ro cost(4, 23).
|
|
divwu GPR:wo, GPR:ro, GPR:ro cost(4, 23).
|
|
eqv GPR:wo, GPR:ro, GPR:ro.
|
|
extsb GPR:wo, GPR:ro.
|
|
extsh GPR:wo, GPR:ro.
|
|
fadd FREG:wo, FREG:ro, FREG:ro cost(4, 5).
|
|
fadds FSREG:wo, FSREG:ro, FSREG:ro cost(4, 5).
|
|
fcmpo CR:wo, FREG:ro, FREG:ro cost(4, 5).
|
|
fcmpo CR:wo, FSREG:ro, FSREG:ro cost(4, 5).
|
|
fdiv FREG:wo, FREG:ro, FREG:ro cost(4, 35).
|
|
fdivs FSREG:wo, FSREG:ro, FSREG:ro cost(4, 21).
|
|
fmr FPR:wo, FPR:ro cost(4, 5).
|
|
fmr FSREG:wo, FSREG:ro cost(4, 5).
|
|
fmul FREG:wo, FREG:ro, FREG:ro cost(4, 5).
|
|
fmuls FSREG:wo, FSREG:ro, FSREG:ro cost(4, 5).
|
|
fneg FREG:wo, FREG:ro cost(4, 5).
|
|
fneg FSREG:wo, FSREG:ro cost(4, 5).
|
|
frsp FSREG:wo, FREG:ro cost(4, 5).
|
|
fsub FREG:wo, FREG:ro, FREG:ro cost(4, 5).
|
|
fsubs FSREG:wo, FSREG:ro, FSREG:ro cost(4, 5).
|
|
lbz GPR:wo, IND_RC_B:ro cost(4, 3).
|
|
lbzx GPR:wo, GPR:ro, GPR:ro cost(4, 3).
|
|
lfd FPR:wo, IND_RC_D:ro cost(4, 5).
|
|
lfdu FPR:wo, IND_RC_D:ro cost(4, 5).
|
|
lfdx FPR:wo, GPR:ro, GPR:ro cost(4, 5).
|
|
lfs FSREG:wo, IND_RC_W+IND_RL_W:ro cost(4, 4).
|
|
lfsu FSREG:wo, IND_RC_W:rw cost(4, 4).
|
|
lfsx FSREG:wo, GPR:ro, GPR:ro cost(4, 4).
|
|
lha GPR:wo, IND_RC_H_S:ro cost(4, 3).
|
|
lhax GPR:wo, GPR:ro, GPR:ro cost(4, 3).
|
|
lhz GPR:wo, IND_RC_H:ro cost(4, 3).
|
|
lhzx GPR:wo, GPR:ro, GPR:ro cost(4, 3).
|
|
li32 GPR:wo, CONST:ro cost(8, 2).
|
|
lwzu GPR:wo, IND_RC_W:ro cost(4, 3).
|
|
lwzx GPR:wo, GPR:ro, GPR:ro cost(4, 3).
|
|
lwz GPR:wo, IND_RC_W+IND_RL_W:ro cost(4, 3).
|
|
nand GPR:wo, GPR:ro, GPR:ro.
|
|
neg GPR:wo, GPR:ro.
|
|
nor GPR:wo, GPR:ro, GPR:ro.
|
|
mfcr GPR:wo cost(4,2).
|
|
mullw GPR:wo, GPR:ro, GPR:ro cost(4, 4).
|
|
mfspr GPR:wo, SPR:ro cost(4, 3).
|
|
mtspr SPR:wo, GPR:ro cost(4, 2).
|
|
or GPR:wo, GPR:ro, GPR:ro.
|
|
orc GPR:wo, GPR:ro, GPR:ro.
|
|
ori GPR:wo, GPR:ro, CONST+LABEL_LO:ro.
|
|
oris GPR:wo, GPR:ro, CONST:ro.
|
|
orX "or." GPR:wo:cc, GPR:ro, GPR:ro.
|
|
rlwinm GPR:wo, GPR:ro, CONST:ro, CONST:ro, CONST:ro.
|
|
extlwi GPR:wo, GPR:ro, CONST:ro, CONST:ro.
|
|
extrwi GPR:wo, GPR:ro, CONST:ro, CONST:ro.
|
|
slw GPR:wo, GPR:ro, GPR:ro.
|
|
subf GPR:wo, GPR:ro, GPR:ro.
|
|
sraw GPR:wo, GPR:ro, GPR:ro cost(4, 2).
|
|
srawi GPR:wo, GPR:ro, CONST:ro cost(4, 2).
|
|
srw GPR:wo, GPR:ro, GPR:ro.
|
|
stb GPR:ro, IND_RC_B:rw cost(4, 3).
|
|
stbx GPR:ro, GPR:ro, GPR:ro cost(4, 3).
|
|
stfd FPR:ro, IND_RC_D:rw cost(4, 4).
|
|
stfdu FPR:ro, IND_RC_D:rw cost(4, 4).
|
|
stfdx FPR:ro, GPR:ro, GPR:ro cost(4, 4).
|
|
stfs FSREG:ro, IND_RC_W+IND_RL_W:rw cost(4, 3).
|
|
stfsu FSREG:ro, IND_RC_W:rw cost(4, 3).
|
|
stfsx FSREG:ro, GPR:ro, GPR:ro cost(4, 3).
|
|
sth GPR:ro, IND_RC_H:rw cost(4, 3).
|
|
sthx GPR:ro, GPR:ro, GPR:ro cost(4, 3).
|
|
stw GPR:ro, IND_RC_W+IND_RL_W:rw cost(4, 3).
|
|
stwx GPR:ro, GPR:ro, GPR:ro cost(4, 3).
|
|
stwu GPR+LOCAL:ro, IND_RC_W:rw cost(4, 3).
|
|
xor GPR:wo, GPR:ro, GPR:ro.
|
|
xori GPR:wo, GPR:ro, CONST:ro.
|
|
xoris GPR:wo, GPR:ro, CONST:ro.
|
|
|
|
comment "!" LABEL:ro cost(0, 0).
|
|
|
|
|
|
|
|
MOVES
|
|
|
|
from GPR to GPR
|
|
gen
|
|
COMMENT("move GPR->GPR")
|
|
or %2, %1, %1
|
|
|
|
/* Constants */
|
|
|
|
from CONST + CONST_STACK smalls(%val) to GPR
|
|
gen
|
|
COMMENT("move CONST->GPR smalls")
|
|
li %2, {CONST, %1.val}
|
|
|
|
from CONST + CONST_STACK lo(%val)==0 to GPR
|
|
gen
|
|
COMMENT("move CONST->GPR shifted")
|
|
lis %2, {CONST, hi(%1.val)}
|
|
|
|
from CONST + CONST_STACK to GPR
|
|
gen
|
|
COMMENT("move CONST->GPR")
|
|
lis %2, {CONST, hi(%1.val)}
|
|
ori %2, %2, {CONST, lo(%1.val)}
|
|
/* Can't use addi %2, %2, {CONST, los(%1.val)}
|
|
* because %2 might be R0. */
|
|
|
|
from LABEL to GPR
|
|
gen
|
|
COMMENT("move LABEL->GPR")
|
|
lis %2, {LABEL_HI, %1.adr}
|
|
ori %2, %2, {LABEL_LO, %1.adr}
|
|
|
|
from LABEL_HA to GPR
|
|
gen
|
|
lis %2, %1
|
|
|
|
from LABEL_STACK to GPR
|
|
gen
|
|
move {LABEL_HA, %1.adr}, %1.reg
|
|
addi %2, %1.reg, {LABEL_LO, %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_RIS to GPR
|
|
gen
|
|
COMMENT("move SUM_RIS->GPR")
|
|
addis %2, %1.reg, {CONST, %1.offhi}
|
|
|
|
from SUM_RC to GPR
|
|
gen
|
|
COMMENT("move SUM_RC->GPR")
|
|
addi %2, %1.reg, {CONST, %1.off}
|
|
|
|
from SUM_RR to GPR
|
|
gen
|
|
COMMENT("move SUM_RR->GPR")
|
|
add %2, %1.reg1, %1.reg2
|
|
|
|
/* Read byte */
|
|
|
|
from IND_RC_B to GPR
|
|
gen
|
|
COMMENT("move IND_RC_B->GPR")
|
|
lbz %2, %1
|
|
|
|
from IND_RR_B to GPR
|
|
gen
|
|
COMMENT("move IND_RR_B->GPR")
|
|
lbzx %2, %1.reg1, %1.reg2
|
|
|
|
/* Write byte */
|
|
|
|
from GPR to IND_RC_B
|
|
gen
|
|
COMMENT("move GPR->IND_RC_B")
|
|
stb %1, %2
|
|
|
|
from GPR to IND_RR_B
|
|
gen
|
|
COMMENT("move GPR->IND_RR_B")
|
|
stbx %1, %2.reg1, %2.reg2
|
|
|
|
/* Read halfword (short) */
|
|
|
|
from IND_RC_H to GPR
|
|
gen
|
|
COMMENT("move IND_RC_H->GPR")
|
|
lhz %2, %1
|
|
|
|
from IND_RR_H to GPR
|
|
gen
|
|
COMMENT("move IND_RR_H->GPR")
|
|
lhzx %2, %1.reg1, %1.reg2
|
|
|
|
from IND_RC_H_S to GPR
|
|
gen
|
|
COMMENT("move IND_RC_H_S->GPR")
|
|
lha %2, %1
|
|
|
|
from IND_RR_H_S to GPR
|
|
gen
|
|
COMMENT("move IND_RR_H_S->GPR")
|
|
lhax %2, %1.reg1, %1.reg2
|
|
|
|
/* Write halfword */
|
|
|
|
from GPR to IND_RC_H
|
|
gen
|
|
COMMENT("move GPR->IND_RC_H")
|
|
sth %1, %2
|
|
|
|
from GPR to IND_RR_H
|
|
gen
|
|
COMMENT("move GPR->IND_RR_H")
|
|
sthx %1, %2.reg1, %2.reg2
|
|
|
|
/* Read word */
|
|
|
|
from IND_RC_W to GPR
|
|
gen
|
|
COMMENT("move IND_RC_W->GPR")
|
|
lwz %2, %1
|
|
|
|
from IND_RL_W to GPR
|
|
gen
|
|
move {LABEL_HA, %1.adr}, %1.reg
|
|
lwz %2, %1
|
|
|
|
from IND_RR_W to GPR
|
|
gen
|
|
COMMENT("move IND_RR_W->GPR")
|
|
lwzx %2, %1.reg1, %1.reg2
|
|
|
|
from IND_RC_W to FSREG
|
|
gen
|
|
COMMENT("move IND_RC_W->FSREG")
|
|
lfs %2, %1
|
|
|
|
from IND_RL_W to FSREG
|
|
gen
|
|
move {LABEL_HA, %1.adr}, %1.reg
|
|
lfs %2, %1
|
|
|
|
from IND_RR_W to FSREG
|
|
gen
|
|
COMMENT("move IND_RR_W->FSREG")
|
|
lfsx %2, %1.reg1, %1.reg2
|
|
|
|
/* Write word */
|
|
|
|
from GPR to IND_RC_W
|
|
gen
|
|
COMMENT("move GPR->IND_RC_W")
|
|
stw %1, %2
|
|
|
|
from GPR to IND_RR_W
|
|
gen
|
|
COMMENT("move GPR->IND_RR_W")
|
|
stwx %1, %2.reg1, %2.reg2
|
|
|
|
from FSREG to IND_RC_W
|
|
gen
|
|
COMMENT("move FSREG->IND_RC_W")
|
|
stfs %1, %2
|
|
|
|
from FSREG to IND_RR_W
|
|
gen
|
|
COMMENT("move FSREG->IND_RR_W")
|
|
stfsx %1, %2.reg1, %2.reg2
|
|
|
|
/* Read double */
|
|
|
|
from IND_RC_D to FPR
|
|
gen
|
|
COMMENT("move IND_RC_D->FPR")
|
|
lfd %2, {IND_RC_D, %1.reg, %1.off}
|
|
|
|
from IND_RR_D to FPR
|
|
gen
|
|
COMMENT("move IND_RR_D->FPR")
|
|
lfdx %2, %1.reg1, %1.reg2
|
|
|
|
/* Write double */
|
|
|
|
from FPR to IND_RC_D
|
|
gen
|
|
COMMENT("move FPR->IND_RC_D")
|
|
stfd %1, {IND_RC_D, %2.reg, %2.off}
|
|
|
|
from FPR to IND_RR_D
|
|
gen
|
|
COMMENT("move FPR->IND_RR_W")
|
|
stfdx %1, %2.reg1, %2.reg2
|
|
|
|
/* 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 OR_RR to GPR
|
|
gen
|
|
COMMENT("move OR_RR->GPR")
|
|
or %2, %1.reg1, %1.reg2
|
|
|
|
from OR_RIS to GPR
|
|
gen
|
|
COMMENT("move OR_RIS->GPR")
|
|
oris %2, %1.reg, {CONST, %1.valhi}
|
|
|
|
from OR_RC to GPR
|
|
gen
|
|
COMMENT("move OR_RC->GPR")
|
|
ori %2, %1.reg, {CONST, %1.val}
|
|
|
|
from XOR_RR to GPR
|
|
gen
|
|
COMMENT("move XOR_RR->GPR")
|
|
xor %2, %1.reg1, %1.reg2
|
|
|
|
from XOR_RIS to GPR
|
|
gen
|
|
COMMENT("move XOR_RIS->GPR")
|
|
xoris %2, %1.reg, {CONST, %1.valhi}
|
|
|
|
from XOR_RC to GPR
|
|
gen
|
|
COMMENT("move XOR_RC->GPR")
|
|
xori %2, %1.reg, {CONST, %1.val}
|
|
|
|
/* Conditions */
|
|
|
|
/* Compare values, then copy cr0 to GPR. */
|
|
|
|
from COND_RC to GPR
|
|
gen
|
|
cmpwi %1.reg, {CONST, %1.val}
|
|
mfcr %2
|
|
|
|
from COND_RR to GPR
|
|
gen
|
|
cmpw %1.reg1, %1.reg2
|
|
mfcr %2
|
|
|
|
from CONDL_RC to GPR
|
|
gen
|
|
cmplwi %1.reg, {CONST, %1.val}
|
|
mfcr %2
|
|
|
|
from CONDL_RR to GPR
|
|
gen
|
|
cmplw %1.reg1, %1.reg2
|
|
mfcr %2
|
|
|
|
from COND_FS to GPR
|
|
gen
|
|
fcmpo CR0, %1.reg1, %1.reg2
|
|
mfcr %2
|
|
|
|
from COND_FD to GPR
|
|
gen
|
|
fcmpo CR0, %1.reg1, %1.reg2
|
|
mfcr %2
|
|
|
|
/* Given a copy of cr0 in %1.reg, extract a condition bit
|
|
* (lt, gt, eq) and perhaps flip it.
|
|
*/
|
|
|
|
from XEQ to GPR
|
|
gen
|
|
extrwi %2, %1.reg, {CONST, 1}, {CONST, 2}
|
|
|
|
from XNE to GPR
|
|
gen
|
|
extrwi %2, %1.reg, {CONST, 1}, {CONST, 2}
|
|
xori %2, %2, {CONST, 1}
|
|
|
|
from XGT to GPR
|
|
gen
|
|
extrwi %2, %1.reg, {CONST, 1}, {CONST, 1}
|
|
|
|
from XGE to GPR
|
|
gen
|
|
extrwi %2, %1.reg, {CONST, 1}, {CONST, 0}
|
|
xori %2, %2, {CONST, 1}
|
|
|
|
from XLT to GPR
|
|
gen
|
|
extrwi %2, %1.reg, {CONST, 1}, {CONST, 0}
|
|
|
|
from XLE to GPR
|
|
gen
|
|
extrwi %2, %1.reg, {CONST, 1}, {CONST, 1}
|
|
xori %2, %2, {CONST, 1}
|
|
|
|
/* GPRE exists solely to allow us to use regvar() (which can only be used in
|
|
an expression) as a register constant. */
|
|
|
|
from ANY_BHW to GPRE
|
|
gen
|
|
move %1, %2.reg
|
|
|
|
|
|
TESTS
|
|
|
|
to test GPR
|
|
gen
|
|
orX RSCRATCH, %1, %1
|
|
|
|
|
|
|
|
STACKINGRULES
|
|
|
|
from LOCAL to STACK
|
|
gen
|
|
COMMENT("stack LOCAL")
|
|
stwu %1, {IND_RC_W, SP, 0-4}
|
|
|
|
from REG to STACK
|
|
gen
|
|
COMMENT("stack REG")
|
|
stwu %1, {IND_RC_W, SP, 0-4}
|
|
|
|
from REG_PAIR to STACK
|
|
gen
|
|
COMMENT("stack REG_PAIR")
|
|
stwu %1.2, {IND_RC_W, SP, 0-4}
|
|
stwu %1.1, {IND_RC_W, SP, 0-4}
|
|
|
|
from CONST_STACK to STACK
|
|
gen
|
|
COMMENT("stack CONST_STACK")
|
|
move %1, RSCRATCH
|
|
stwu RSCRATCH, {IND_RC_W, SP, 0-4}
|
|
|
|
from LABEL_STACK to STACK
|
|
gen
|
|
COMMENT("stack LABEL_STACK")
|
|
move %1, RSCRATCH
|
|
stwu RSCRATCH, {IND_RC_W, SP, 0-4}
|
|
|
|
from SEX_B to STACK
|
|
gen
|
|
COMMENT("stack SEX_B")
|
|
extsb RSCRATCH, %1.reg
|
|
stwu RSCRATCH, {IND_RC_W, SP, 0-4}
|
|
|
|
from SEX_H to STACK
|
|
gen
|
|
COMMENT("stack SEX_H")
|
|
extsh RSCRATCH, %1.reg
|
|
stwu RSCRATCH, {IND_RC_W, SP, 0-4}
|
|
|
|
from SUM_ALL + LOGICAL_ALL to STACK
|
|
gen
|
|
COMMENT("stack SUM_ALL + LOGICAL_ALL")
|
|
move %1, RSCRATCH
|
|
stwu RSCRATCH, {IND_RC_W, SP, 0-4}
|
|
|
|
from IND_ALL_BHW to STACK
|
|
gen
|
|
COMMENT("stack IND_ALL_BHW")
|
|
move %1, RSCRATCH
|
|
stwu RSCRATCH, {IND_RC_W, SP, 0-4}
|
|
|
|
from IND_ALL_D to STACK
|
|
gen
|
|
COMMENT("stack IND_ALL_D")
|
|
move %1, FSCRATCH
|
|
stfdu FSCRATCH, {IND_RC_D, SP, 0-8}
|
|
|
|
from FREG to STACK
|
|
gen
|
|
COMMENT("stack FPR")
|
|
stfdu %1, {IND_RC_D, SP, 0-8}
|
|
|
|
from FSREG to STACK
|
|
gen
|
|
COMMENT("stack FSREG")
|
|
stfsu %1, {IND_RC_W, SP, 0-4}
|
|
|
|
|
|
|
|
COERCIONS
|
|
|
|
from REG
|
|
uses REG
|
|
gen
|
|
COMMENT("coerce REG->REG")
|
|
move %1, %a
|
|
yields %a
|
|
|
|
from CONST + CONST_STACK
|
|
uses REG
|
|
gen
|
|
COMMENT("coerce CONST->REG")
|
|
move %1, %a
|
|
yields %a
|
|
|
|
from LABEL
|
|
uses REG
|
|
gen
|
|
COMMENT("coerce LABEL->REG")
|
|
move %1, %a
|
|
yields %a
|
|
|
|
from STACK
|
|
uses REG
|
|
gen
|
|
COMMENT("coerce STACK->REG")
|
|
lwz %a, {IND_RC_W, SP, 0}
|
|
addi SP, SP, {CONST, 4}
|
|
yields %a
|
|
|
|
from STACK
|
|
uses REG_PAIR
|
|
gen
|
|
COMMENT("coerce STACK->REG_PAIR")
|
|
lwz %a.1, {IND_RC_W, SP, 0}
|
|
lwz %a.2, {IND_RC_W, SP, 4}
|
|
addi SP, SP, {CONST, 8}
|
|
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 + LOGICAL_ALL
|
|
uses REG
|
|
gen
|
|
move %1, %a
|
|
yields %a
|
|
|
|
from FSREG
|
|
uses FSREG
|
|
gen
|
|
fmr %a, %1
|
|
yields %a
|
|
|
|
from FREG
|
|
uses FREG
|
|
gen
|
|
fmr %a, %1
|
|
yields %a
|
|
|
|
from STACK
|
|
uses FREG
|
|
gen
|
|
COMMENT("coerce STACK->FREG")
|
|
lfd %a, {IND_RC_D, SP, 0}
|
|
addi SP, SP, {CONST, 8}
|
|
yields %a
|
|
|
|
from STACK
|
|
uses FSREG
|
|
gen
|
|
COMMENT("coerce STACK->FSREG")
|
|
lfs %a, {IND_RC_W, SP, 0}
|
|
addi SP, SP, {CONST, 4}
|
|
yields %a
|
|
|
|
from IND_ALL_BHW
|
|
uses REG
|
|
gen
|
|
move %1, %a
|
|
yields %a
|
|
|
|
from IND_ALL_W
|
|
uses FSREG
|
|
gen
|
|
move %1, %a
|
|
yields %a
|
|
|
|
/*
|
|
* from IND_RC_D to REG_PAIR is not possible, because
|
|
* %1.off+4 might overflow a signed 16-bit integer in
|
|
* move {IND_RC_W, %1.val, %1.off+4}, %a.2
|
|
*/
|
|
|
|
from IND_ALL_D
|
|
uses FREG
|
|
gen
|
|
move %1, %a
|
|
yields %a
|
|
|
|
|
|
|
|
PATTERNS
|
|
|
|
/* Intrinsics */
|
|
|
|
pat loc $1==(0-0x8000) /* Load constant */
|
|
yields {CONST_N8000, $1}
|
|
pat loc $1>=(0-0x7FFF) && $1<=(0-1)
|
|
yields {CONST_N7FFF_N0001, $1}
|
|
pat loc $1>=0 && $1<=0x7FFF
|
|
yields {CONST_0000_7FFF, $1}
|
|
pat loc $1==0x8000
|
|
yields {CONST_8000, $1}
|
|
pat loc $1>=0x8001 && $1<=0xFFFF
|
|
yields {CONST_8001_FFFF, $1}
|
|
pat loc lo($1)==0
|
|
yields {CONST_HZ, $1}
|
|
pat loc
|
|
yields {CONST_HL, $1}
|
|
|
|
pat dup $1==INT32 /* Duplicate word on top of stack */
|
|
with REG
|
|
yields %1 %1
|
|
with FSREG
|
|
yields %1 %1
|
|
|
|
pat dup $1==INT64 /* Duplicate double-word on top of stack */
|
|
with REG REG
|
|
yields %2 %1 %2 %1
|
|
with FREG
|
|
yields %1 %1
|
|
|
|
pat exg $1==INT32 /* Exchange top two words on stack */
|
|
with REG REG
|
|
yields %1 %2
|
|
|
|
pat stl lol $1==$2 /* Store then load local */
|
|
leaving
|
|
dup 4
|
|
stl $1
|
|
|
|
pat sdl ldl $1==$2 /* Store then load double local */
|
|
leaving
|
|
dup 8
|
|
sdl $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 smalls($1) /* Load address of local */
|
|
yields {SUM_RC, FP, $1}
|
|
|
|
pat lal /* Load address of local */
|
|
uses REG={SUM_RIS, FP, his($1)}
|
|
yields {SUM_RC, %a, los($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 ANY_BHW
|
|
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 */
|
|
yields {IND_RC_W, regvar($1), 0}
|
|
|
|
pat lil /* Load from indirected local */
|
|
leaving
|
|
lol $1
|
|
loi INT32
|
|
|
|
pat sil /* Save to indirected local */
|
|
leaving
|
|
lol $1
|
|
sti INT32
|
|
|
|
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 */
|
|
uses REG
|
|
yields {LABEL_STACK, %a, $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 */
|
|
kills MEMORY
|
|
uses REG={LABEL, $1}, REG
|
|
gen
|
|
lwz %b, {IND_RC_W, %a, 0}
|
|
addi %b, %b, {CONST, 1}
|
|
stw %b, {IND_RC_W, %a, 0}
|
|
|
|
pat dee /* Decrement external */
|
|
kills MEMORY
|
|
uses REG={LABEL, $1}, REG
|
|
gen
|
|
lwz %b, {IND_RC_W, %a, 0}
|
|
addi %b, %b, {CONST, 0-1}
|
|
stw %b, {IND_RC_W, %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
|
|
yields {IND_RC_B, %1, 0}
|
|
with SUM_RR
|
|
yields {IND_RR_B, %1.reg1, %1.reg2}
|
|
with SUM_RC
|
|
yields {IND_RC_B, %1.reg, %1.off}
|
|
|
|
pat loi loc loc cii $1==INT16 && $2==INT16 && $3==INT32
|
|
/* Load half-word indirect and sign extend */
|
|
with GPR
|
|
yields {IND_RC_H_S, %1, 0}
|
|
with SUM_RR
|
|
yields {IND_RR_H_S, %1.reg1, %1.reg2}
|
|
with SUM_RC
|
|
yields {IND_RC_H_S, %1.reg, %1.off}
|
|
|
|
pat loi $1==INT16 /* Load half-word indirect */
|
|
with GPR
|
|
yields {IND_RC_H, %1, 0}
|
|
with SUM_RR
|
|
yields {IND_RR_H, %1.reg1, %1.reg2}
|
|
with SUM_RC
|
|
yields {IND_RC_H, %1.reg, %1.off}
|
|
|
|
pat loi $1==INT32 /* Load word indirect */
|
|
with GPR
|
|
yields {IND_RC_W, %1, 0}
|
|
with exact LABEL_STACK
|
|
yields {IND_RL_W, %1.reg, %1.adr}
|
|
with exact SUM_RC
|
|
yields {IND_RC_W, %1.reg, %1.off}
|
|
with exact SUM_RR
|
|
yields {IND_RR_W, %1.reg1, %1.reg2}
|
|
|
|
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}
|
|
|
|
pat loi /* Load arbitrary size */
|
|
leaving
|
|
loc $1
|
|
los INT32
|
|
|
|
pat los $1==INT32 /* Load arbitrary size */
|
|
with GPR3 GPR4 STACK
|
|
kills ALL
|
|
gen
|
|
bl {LABEL, ".los"}
|
|
|
|
pat sti $1==INT8 /* Store byte indirect */
|
|
with GPR GPR
|
|
kills MEMORY
|
|
gen
|
|
stb %2, {IND_RC_B, %1, 0}
|
|
with SUM_RR GPR
|
|
kills MEMORY
|
|
gen
|
|
stbx %2, %1.reg1, %1.reg2
|
|
with SUM_RC GPR
|
|
kills MEMORY
|
|
gen
|
|
move %2, {IND_RC_B, %1.reg, %1.off}
|
|
with GPR SEX_B
|
|
kills MEMORY
|
|
gen
|
|
stb %2.reg, {IND_RC_B, %1, 0}
|
|
with SUM_RR SEX_B
|
|
kills MEMORY
|
|
gen
|
|
stbx %2.reg, %1.reg1, %1.reg2
|
|
with SUM_RC SEX_B
|
|
kills MEMORY
|
|
gen
|
|
move %2.reg, {IND_RC_B, %1.reg, %1.off}
|
|
|
|
pat sti $1==INT16 /* Store half-word indirect */
|
|
with GPR GPR
|
|
kills MEMORY
|
|
gen
|
|
sth %2, {IND_RC_H, %1, 0}
|
|
with SUM_RR GPR
|
|
kills MEMORY
|
|
gen
|
|
sthx %2, %1.reg1, %1.reg2
|
|
with SUM_RC GPR
|
|
kills MEMORY
|
|
gen
|
|
move %2, {IND_RC_H, %1.reg, %1.off}
|
|
with GPR SEX_H
|
|
kills MEMORY
|
|
gen
|
|
sth %2.reg, {IND_RC_H, %1, 0}
|
|
with SUM_RR SEX_H
|
|
kills MEMORY
|
|
gen
|
|
sthx %2.reg, %1.reg1, %1.reg2
|
|
with SUM_RC SEX_H
|
|
kills MEMORY
|
|
gen
|
|
move %2.reg, {IND_RC_H, %1.reg, %1.off}
|
|
|
|
pat sti $1==INT32 /* Store word indirect */
|
|
with REG REG+FSREG
|
|
kills MEMORY
|
|
gen
|
|
move %2, {IND_RC_W, %1, 0}
|
|
with LABEL_STACK REG
|
|
kills MEMORY
|
|
gen
|
|
move {LABEL_HA, %1.adr}, %1.reg
|
|
stw %2, {IND_RL_W, %1.reg, %1.adr}
|
|
with LABEL_STACK FSREG
|
|
kills MEMORY
|
|
gen
|
|
move {LABEL_HA, %1.adr}, %1.reg
|
|
stfs %2, {IND_RL_W, %1.reg, %1.adr}
|
|
with SUM_RR REG+FSREG
|
|
kills MEMORY
|
|
gen
|
|
move %2, {IND_RR_W, %1.reg1, %1.reg2}
|
|
with SUM_RC REG+FSREG
|
|
kills MEMORY
|
|
gen
|
|
move %2, {IND_RC_W, %1.reg, %1.off}
|
|
|
|
pat sti $1==INT64 /* Store double-word indirect */
|
|
with REG FREG
|
|
kills MEMORY
|
|
gen
|
|
move %2, {IND_RC_D, %1, 0}
|
|
with SUM_RR FREG
|
|
kills MEMORY
|
|
gen
|
|
move %2, {IND_RR_D, %1.reg1, %1.reg2}
|
|
with SUM_RC FREG
|
|
kills MEMORY
|
|
gen
|
|
move %2, {IND_RC_D, %1.reg, %1.off}
|
|
/*
|
|
* This pattern would be too slow:
|
|
* with REG REG REG
|
|
* ncg can't handle that many registers, and would
|
|
* take about 2 seconds on each sti 8. So we use
|
|
* REG_PAIR as a speed hack for sti 8.
|
|
*/
|
|
with REG REG_PAIR
|
|
kills MEMORY
|
|
gen
|
|
move %2.1, {IND_RC_W, %1, 0}
|
|
move %2.2, {IND_RC_W, %1, 4}
|
|
/*
|
|
* Next 2 patterns exist because there is no coercion
|
|
* from IND_ALL_D to REG_PAIR.
|
|
*/
|
|
with REG IND_RC_D
|
|
kills MEMORY
|
|
uses REG={SUM_RC, %2.reg, %2.off}, REG_PAIR
|
|
gen
|
|
move {IND_RC_W, %a, 0}, %b.1
|
|
move {IND_RC_W, %a, 4}, %b.2
|
|
move %b.1, {IND_RC_W, %1, 0}
|
|
move %b.2, {IND_RC_W, %1, 4}
|
|
with REG IND_RR_D
|
|
kills MEMORY
|
|
uses REG={SUM_RR, %2.reg1, %2.reg2}, REG_PAIR
|
|
gen
|
|
move {IND_RC_W, %a, 0}, %b.1
|
|
move {IND_RC_W, %a, 4}, %b.2
|
|
move %b.1, {IND_RC_W, %1, 0}
|
|
move %b.2, {IND_RC_W, %1, 4}
|
|
|
|
pat sti /* Store arbitrary size */
|
|
leaving
|
|
loc $1
|
|
sts INT32
|
|
|
|
pat sts $1==INT32 /* Store 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 CONST2 REG
|
|
yields {SUM_RC, %2, %1.val}
|
|
with REG CONST2
|
|
yields {SUM_RC, %1, %2.val}
|
|
with CONST_HZ REG
|
|
uses reusing %2, REG={SUM_RIS, %2, his(%1.val)}
|
|
yields %a
|
|
with REG CONST_HZ
|
|
uses reusing %1, REG={SUM_RIS, %1, his(%2.val)}
|
|
yields %a
|
|
with CONST_STACK-CONST2-CONST_HZ REG
|
|
uses reusing %2, REG={SUM_RIS, %2, his(%1.val)}
|
|
yields {SUM_RC, %a, los(%1.val)}
|
|
with REG CONST_STACK-CONST2-CONST_HZ
|
|
uses reusing %1, REG={SUM_RIS, %1, his(%2.val)}
|
|
yields {SUM_RC, %a, los(%2.val)}
|
|
with exact CONST_STACK LABEL_STACK
|
|
uses reusing %2.reg, REG
|
|
yields {LABEL_STACK, %a, %2.adr+%1.val}
|
|
with exact LABEL_STACK CONST_STACK
|
|
uses reusing %1.reg, REG
|
|
yields {LABEL_STACK, %a, %1.adr+%2.val}
|
|
|
|
pat sbi $1==4 /* Subtract word (second - top) */
|
|
with REG REG
|
|
uses reusing %2, REG
|
|
gen
|
|
subf %a, %1, %2
|
|
yields %a
|
|
with CONST2_WHEN_NEG REG
|
|
yields {SUM_RC, %2, 0-%1.val}
|
|
with CONST_HZ REG
|
|
uses reusing %2, REG={SUM_RIS, %2, his(0-%1.val)}
|
|
yields %a
|
|
with CONST_STACK-CONST2_WHEN_NEG-CONST_HZ REG
|
|
uses reusing %2, REG={SUM_RIS, %2, his(0-%1.val)}
|
|
yields {SUM_RC, %a, los(0-%1.val)}
|
|
with exact CONST_STACK LABEL_STACK
|
|
uses reusing %2.reg, REG
|
|
yields {LABEL_STACK, %a, %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 UCONST2
|
|
uses reusing %1, REG
|
|
gen
|
|
andiX %a, %1, {CONST, %2.val}
|
|
yields %a
|
|
with UCONST2 GPR
|
|
uses reusing %2, REG
|
|
gen
|
|
andiX %a, %2, {CONST, %1.val}
|
|
yields %a
|
|
with GPR CONST_HZ
|
|
uses reusing %1, REG
|
|
gen
|
|
andisX %a, %1, {CONST, hi(%2.val)}
|
|
yields %a
|
|
with CONST_HZ GPR
|
|
uses reusing %2, REG
|
|
gen
|
|
andisX %a, %2, {CONST, hi(%1.val)}
|
|
yields %a
|
|
|
|
pat and defined($1) /* AND set */
|
|
leaving
|
|
loc $1
|
|
cal ".and"
|
|
|
|
pat and !defined($1)
|
|
leaving
|
|
cal ".and"
|
|
|
|
pat ior $1==4 /* OR word */
|
|
with REG NOT_R
|
|
uses reusing %1, REG
|
|
gen
|
|
orc %a, %1, %2.reg
|
|
yields %a
|
|
with NOT_R REG
|
|
uses reusing %2, REG
|
|
gen
|
|
orc %a, %2, %1.reg
|
|
yields %a
|
|
with REG REG
|
|
yields {OR_RR, %1, %2}
|
|
with REG UCONST2
|
|
yields {OR_RC, %1, %2.val}
|
|
with UCONST2 REG
|
|
yields {OR_RC, %2, %1.val}
|
|
with REG CONST_HZ
|
|
uses reusing %1, REG={OR_RIS, %1, hi(%2.val)}
|
|
yields %a
|
|
with CONST_HZ REG
|
|
uses reusing %2, REG={OR_RIS, %2, hi(%1.val)}
|
|
yields %a
|
|
with REG CONST_STACK-UCONST2-CONST_HZ
|
|
uses reusing %1, REG={OR_RIS, %1, hi(%2.val)}
|
|
yields {OR_RC, %1, lo(%2.val)}
|
|
with CONST_STACK-UCONST2-CONST_HZ REG
|
|
uses reusing %2, REG={OR_RIS, %2, hi(%1.val)}
|
|
yields {OR_RC, %2, lo(%1.val)}
|
|
|
|
pat ior defined($1) /* OR set */
|
|
leaving
|
|
loc $1
|
|
cal ".ior"
|
|
|
|
/* OR set (variable), used in lang/m2/libm2/LtoUset.e */
|
|
pat ior !defined($1)
|
|
leaving
|
|
cal ".ior"
|
|
|
|
pat xor $1==4 /* XOR word */
|
|
with REG REG
|
|
yields {XOR_RR, %1, %2}
|
|
with REG UCONST2
|
|
yields {XOR_RC, %1, %2.val}
|
|
with UCONST2 REG
|
|
yields {XOR_RC, %2, %1.val}
|
|
with REG CONST_HZ
|
|
uses reusing %1, REG={XOR_RIS, %1, hi(%2.val)}
|
|
yields %a
|
|
with CONST_HZ REG
|
|
uses reusing %2, REG={XOR_RIS, %2, hi(%1.val)}
|
|
yields %a
|
|
with REG CONST_STACK-UCONST2-CONST_HZ
|
|
uses reusing %1, REG={XOR_RIS, %1, hi(%2.val)}
|
|
yields {XOR_RC, %1, lo(%2.val)}
|
|
with CONST_STACK-UCONST2-CONST_HZ REG
|
|
uses reusing %2, REG={XOR_RIS, %2, hi(%1.val)}
|
|
yields {XOR_RC, %2, lo(%1.val)}
|
|
|
|
pat xor defined($1) /* XOR set */
|
|
with STACK
|
|
kills ALL
|
|
gen
|
|
move {CONST, $1}, R3
|
|
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 */
|
|
leaving
|
|
loc $1
|
|
cal ".com"
|
|
|
|
pat com !defined($1)
|
|
leaving
|
|
cal ".com"
|
|
|
|
pat zer $1==4 /* Push zero */
|
|
leaving
|
|
loc 0
|
|
|
|
pat zer defined($1) /* Create empty set */
|
|
leaving
|
|
loc $1
|
|
cal ".zer"
|
|
|
|
pat sli $1==4 /* Shift left (second << top) */
|
|
with CONST_STACK 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_STACK 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_STACK 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
|
|
kills ALL
|
|
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 singleton set */
|
|
leaving
|
|
loc $1
|
|
cal ".set"
|
|
|
|
/* Create set (variable), used in lang/m2/libm2/LtoUset.e */
|
|
pat set !defined($1)
|
|
leaving
|
|
cal ".set"
|
|
|
|
pat inn defined($1) /* Test for set bit */
|
|
leaving
|
|
loc $1
|
|
cal ".inn"
|
|
|
|
pat inn !defined($1)
|
|
leaving
|
|
cal ".inn"
|
|
|
|
|
|
|
|
/* Boolean resolutions */
|
|
|
|
pat teq /* top = (top == 0) */
|
|
with REG
|
|
uses reusing %1, REG
|
|
gen
|
|
test %1
|
|
mfcr %a
|
|
move {XEQ, %a}, %a
|
|
yields %a
|
|
|
|
pat tne /* top = (top != 0) */
|
|
with REG
|
|
uses reusing %1, REG
|
|
gen
|
|
test %1
|
|
mfcr %a
|
|
move {XNE, %a}, %a
|
|
yields %a
|
|
|
|
pat tlt /* top = (top < 0) */
|
|
with REG
|
|
uses reusing %1, REG
|
|
gen
|
|
test %1
|
|
mfcr %a
|
|
move {XLT, %a}, %a
|
|
yields %a
|
|
|
|
pat tle /* top = (top <= 0) */
|
|
with REG
|
|
uses reusing %1, REG
|
|
gen
|
|
test %1
|
|
mfcr %a
|
|
move {XLE, %a}, %a
|
|
yields %a
|
|
|
|
pat tgt /* top = (top > 0) */
|
|
with REG
|
|
uses reusing %1, REG
|
|
gen
|
|
test %1
|
|
mfcr %a
|
|
move {XGT, %a}, %a
|
|
yields %a
|
|
|
|
pat tge /* top = (top >= 0) */
|
|
with REG
|
|
uses reusing %1, REG
|
|
gen
|
|
test %1
|
|
mfcr %a
|
|
move {XGE, %a}, %a
|
|
yields %a
|
|
|
|
pat cmi teq $1==4 /* Signed second == top */
|
|
with REG CONST2
|
|
uses reusing %1, REG={COND_RC, %1, %2.val}
|
|
gen move {XEQ, %a}, %a
|
|
yields %a
|
|
with CONST2 REG
|
|
uses reusing %1, REG={COND_RC, %2, %1.val}
|
|
gen move {XEQ, %a}, %a
|
|
yields %a
|
|
with REG REG
|
|
uses reusing %1, REG={COND_RR, %2, %1}
|
|
gen move {XEQ, %a}, %a
|
|
yields %a
|
|
|
|
pat cmi tne $1==4 /* Signed second != top */
|
|
with REG CONST2
|
|
uses reusing %1, REG={COND_RC, %1, %2.val}
|
|
gen move {XNE, %a}, %a
|
|
yields %a
|
|
with CONST2 REG
|
|
uses reusing %1, REG={COND_RC, %2, %1.val}
|
|
gen move {XNE, %a}, %a
|
|
yields %a
|
|
with REG REG
|
|
uses reusing %1, REG={COND_RR, %2, %1}
|
|
gen move {XNE, %a}, %a
|
|
yields %a
|
|
|
|
pat cmi tgt $1==4 /* Signed second > top */
|
|
with REG CONST2
|
|
uses reusing %1, REG={COND_RC, %1, %2.val}
|
|
gen move {XLT, %a}, %a
|
|
yields %a
|
|
with CONST2 REG
|
|
uses reusing %1, REG={COND_RC, %2, %1.val}
|
|
gen move {XGT, %a}, %a
|
|
yields %a
|
|
with REG REG
|
|
uses reusing %1, REG={COND_RR, %2, %1}
|
|
gen move {XGT, %a}, %a
|
|
yields %a
|
|
|
|
pat cmi tge $1==4 /* Signed second >= top */
|
|
with REG CONST2
|
|
uses reusing %1, REG={COND_RC, %1, %2.val}
|
|
gen move {XLE, %a}, %a
|
|
yields %a
|
|
with CONST2 REG
|
|
uses reusing %1, REG={COND_RC, %2, %1.val}
|
|
gen move {XGE, %a}, %a
|
|
yields %a
|
|
with REG REG
|
|
uses reusing %1, REG={COND_RR, %2, %1}
|
|
gen move {XGE, %a}, %a
|
|
yields %a
|
|
|
|
pat cmi tlt $1==4 /* Signed second < top */
|
|
with REG CONST2
|
|
uses reusing %1, REG={COND_RC, %1, %2.val}
|
|
gen move {XGT, %a}, %a
|
|
yields %a
|
|
with CONST2 REG
|
|
uses reusing %1, REG={COND_RC, %2, %1.val}
|
|
gen move {XLT, %a}, %a
|
|
yields %a
|
|
with REG REG
|
|
uses reusing %1, REG={COND_RR, %2, %1}
|
|
gen move {XLT, %a}, %a
|
|
yields %a
|
|
|
|
pat cmi tle $1==4 /* Signed second <= top */
|
|
with REG CONST2
|
|
uses reusing %1, REG={COND_RC, %1, %2.val}
|
|
gen move {XGE, %a}, %a
|
|
yields %a
|
|
with CONST2 REG
|
|
uses reusing %1, REG={COND_RC, %2, %1.val}
|
|
gen move {XLE, %a}, %a
|
|
yields %a
|
|
with REG REG
|
|
uses reusing %1, REG={COND_RR, %2, %1}
|
|
gen move {XLE, %a}, %a
|
|
yields %a
|
|
|
|
pat cmu teq $1==4 /* Unsigned second == top */
|
|
with REG UCONST2
|
|
uses reusing %1, REG={CONDL_RC, %1, %2.val}
|
|
gen move {XEQ, %a}, %a
|
|
yields %a
|
|
with UCONST2 REG
|
|
uses reusing %1, REG={CONDL_RC, %2, %1.val}
|
|
gen move {XEQ, %a}, %a
|
|
yields %a
|
|
with REG REG
|
|
uses reusing %1, REG={CONDL_RR, %2, %1}
|
|
gen move {XEQ, %a}, %a
|
|
yields %a
|
|
|
|
pat cmu tne $1==4 /* Unsigned second != top */
|
|
with REG UCONST2
|
|
uses reusing %1, REG={CONDL_RC, %1, %2.val}
|
|
gen move {XNE, %a}, %a
|
|
yields %a
|
|
with UCONST2 REG
|
|
uses reusing %1, REG={CONDL_RC, %2, %1.val}
|
|
gen move {XNE, %a}, %a
|
|
yields %a
|
|
with REG REG
|
|
uses reusing %1, REG={CONDL_RR, %2, %1}
|
|
gen move {XNE, %a}, %a
|
|
yields %a
|
|
|
|
pat cmu tgt $1==4 /* Unsigned second > top */
|
|
with REG UCONST2
|
|
uses reusing %1, REG={CONDL_RC, %1, %2.val}
|
|
gen move {XLT, %a}, %a
|
|
yields %a
|
|
with UCONST2 REG
|
|
uses reusing %1, REG={CONDL_RC, %2, %1.val}
|
|
gen move {XGT, %a}, %a
|
|
yields %a
|
|
with REG REG
|
|
uses reusing %1, REG={CONDL_RR, %2, %1}
|
|
gen move {XGT, %a}, %a
|
|
yields %a
|
|
|
|
pat cmu tge $1==4 /* Unsigned second >= top */
|
|
with REG UCONST2
|
|
uses reusing %1, REG={CONDL_RC, %1, %2.val}
|
|
gen move {XLE, %a}, %a
|
|
yields %a
|
|
with UCONST2 REG
|
|
uses reusing %1, REG={CONDL_RC, %2, %1.val}
|
|
gen move {XGE, %a}, %a
|
|
yields %a
|
|
with REG REG
|
|
uses reusing %1, REG={CONDL_RR, %2, %1}
|
|
gen move {XGE, %a}, %a
|
|
yields %a
|
|
|
|
pat cmu tlt $1==4 /* Unsigned second < top */
|
|
with REG UCONST2
|
|
uses reusing %1, REG={CONDL_RC, %1, %2.val}
|
|
gen move {XGT, %a}, %a
|
|
yields %a
|
|
with UCONST2 REG
|
|
uses reusing %1, REG={CONDL_RC, %2, %1.val}
|
|
gen move {XLT, %a}, %a
|
|
yields %a
|
|
with REG REG
|
|
uses reusing %1, REG={CONDL_RR, %2, %1}
|
|
gen move {XLT, %a}, %a
|
|
yields %a
|
|
|
|
pat cmu tle $1==4 /* Unsigned second <= top */
|
|
with REG UCONST2
|
|
uses reusing %1, REG={CONDL_RC, %1, %2.val}
|
|
gen move {XGE, %a}, %a
|
|
yields %a
|
|
with UCONST2 REG
|
|
uses reusing %1, REG={CONDL_RC, %2, %1.val}
|
|
gen move {XLE, %a}, %a
|
|
yields %a
|
|
with REG REG
|
|
uses reusing %1, REG={CONDL_RR, %2, %1}
|
|
gen move {XLE, %a}, %a
|
|
yields %a
|
|
|
|
|
|
|
|
/* Simple branches */
|
|
|
|
proc zxx example zeq
|
|
with REG STACK
|
|
gen
|
|
test %1
|
|
bxx* {LABEL, $1}
|
|
|
|
/* Pop signed int, branch if... */
|
|
pat zeq call zxx("beq") /* top == 0 */
|
|
pat zne call zxx("bne") /* top != 0 */
|
|
pat zgt call zxx("bgt") /* top > 0 */
|
|
pat zge call zxx("bge") /* top >= 0 */
|
|
pat zlt call zxx("blt") /* top < 0 */
|
|
pat zle call zxx("ble") /* top >= 0 */
|
|
|
|
/* The peephole optimizer rewrites
|
|
* cmi 4 zeq
|
|
* as beq, and does same for bne, bgt, and so on.
|
|
*/
|
|
|
|
proc bxx example beq
|
|
with REG CONST2 STACK
|
|
gen
|
|
cmpwi %1, {CONST, %2.val}
|
|
bxx[2] {LABEL, $1}
|
|
with CONST2 REG STACK
|
|
gen
|
|
cmpwi %2, {CONST, %1.val}
|
|
bxx[1] {LABEL, $1}
|
|
with REG REG STACK
|
|
gen
|
|
cmpw %2, %1
|
|
bxx[1] {LABEL, $1}
|
|
|
|
/* Pop two signed ints, branch if... */
|
|
pat beq call bxx("beq", "beq") /* second == top */
|
|
pat bne call bxx("bne", "bne") /* second != top */
|
|
pat bgt call bxx("bgt", "blt") /* second > top */
|
|
pat bge call bxx("bge", "ble") /* second >= top */
|
|
pat blt call bxx("blt", "bgt") /* second < top */
|
|
pat ble call bxx("ble", "bge") /* second >= top */
|
|
|
|
proc cmu4zxx example cmu zeq
|
|
with REG CONST2 STACK
|
|
gen
|
|
cmplwi %1, {CONST, %2.val}
|
|
bxx[2] {LABEL, $2}
|
|
with CONST2 REG STACK
|
|
gen
|
|
cmplwi %2, {CONST, %1.val}
|
|
bxx[1] {LABEL, $2}
|
|
with REG REG STACK
|
|
gen
|
|
cmplw %2, %1
|
|
bxx[1] {LABEL, $2}
|
|
|
|
/* Pop two unsigned ints, branch if... */
|
|
pat cmu zeq $1==4 call cmu4zxx("beq", "beq")
|
|
pat cmu zne $1==4 call cmu4zxx("bne", "bne")
|
|
pat cmu zgt $1==4 call cmu4zxx("bgt", "blt")
|
|
pat cmu zge $1==4 call cmu4zxx("bge", "ble")
|
|
pat cmu zlt $1==4 call cmu4zxx("blt", "bgt")
|
|
pat cmu zle $1==4 call cmu4zxx("ble", "bge")
|
|
|
|
|
|
|
|
/* Comparisons */
|
|
|
|
/* Each comparison extracts the lt and gt bits from cr0.
|
|
* extlwi %a, %a, 2, 0
|
|
* puts lt in the sign bit, so lt yields a negative result,
|
|
* gt yields positive.
|
|
* rlwinm %a, %a, 1, 31, 0
|
|
* puts gt in the sign bit, to reverse the comparison.
|
|
*/
|
|
|
|
pat cmi $1==INT32 /* Signed tristate compare */
|
|
with REG CONST2
|
|
uses reusing %1, REG={COND_RC, %1, %2.val}
|
|
gen rlwinm %a, %a, {CONST, 1}, {CONST, 31}, {CONST, 0}
|
|
yields %a
|
|
with CONST2 REG
|
|
uses reusing %2, REG={COND_RC, %2, %1.val}
|
|
gen extlwi %a, %a, {CONST, 2}, {CONST, 0}
|
|
yields %a
|
|
with REG REG
|
|
uses reusing %1, REG={COND_RR, %2, %1}
|
|
gen extlwi %a, %a, {CONST, 2}, {CONST, 0}
|
|
yields %a
|
|
|
|
pat cmu $1==INT32 /* Unsigned tristate compare */
|
|
with REG UCONST2
|
|
uses reusing %1, REG={CONDL_RC, %1, %2.val}
|
|
gen rlwinm %a, %a, {CONST, 1}, {CONST, 31}, {CONST, 0}
|
|
yields %a
|
|
with UCONST2 REG
|
|
uses reusing %2, REG={CONDL_RC, %2, %1.val}
|
|
gen extlwi %a, %a, {CONST, 2}, {CONST, 0}
|
|
yields %a
|
|
with REG REG
|
|
uses reusing %1, REG={CONDL_RR, %2, %1}
|
|
gen extlwi %a, %a, {CONST, 2}, {CONST, 0}
|
|
yields %a
|
|
|
|
pat cmp /* Compare pointers */
|
|
leaving
|
|
cmu INT32
|
|
|
|
pat cms $1==INT32 /* Compare blocks (word sized) */
|
|
leaving
|
|
cmi INT32
|
|
|
|
pat cms defined($1)
|
|
with STACK
|
|
kills ALL
|
|
gen
|
|
move {CONST, $1}, R3
|
|
bl {LABEL, ".cms"}
|
|
yields R3
|
|
|
|
|
|
|
|
/* Other branching and labelling */
|
|
|
|
pat lab topeltsize($1)==4 && !fallthrough($1)
|
|
kills ALL
|
|
gen
|
|
labeldef $1
|
|
yields R3
|
|
|
|
pat lab topeltsize($1)==4 && fallthrough($1)
|
|
with GPR3 STACK
|
|
kills ALL
|
|
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
|
|
bctrl.
|
|
|
|
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, {IND_RC_W, SP, 0-4}
|
|
stwu %2, {IND_RC_W, SP, 0-4}
|
|
stwu %1, {IND_RC_W, 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, {IND_RC_W, SP, 0-4}
|
|
stwu %3, {IND_RC_W, SP, 0-4}
|
|
stwu %2, {IND_RC_W, SP, 0-4}
|
|
bl {LABEL, "_memmove"}
|
|
addi SP, SP, {CONST, 12}
|
|
|
|
pat csa /* Array-lookup switch */
|
|
with STACK
|
|
gen
|
|
b {LABEL, ".csa"}
|
|
|
|
pat csb /* Table-lookup switch */
|
|
with STACK
|
|
gen
|
|
b {LABEL, ".csb"}
|
|
|
|
|
|
|
|
/* EM specials */
|
|
|
|
pat fil /* Set current filename */
|
|
leaving
|
|
lae $1
|
|
ste "hol0+4"
|
|
|
|
pat lin /* Set current line number */
|
|
leaving
|
|
loc $1
|
|
ste "hol0"
|
|
|
|
pat lni /* Increment line number */
|
|
leaving
|
|
ine "hol0"
|
|
|
|
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, {IND_RC_W, %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
|
|
bctr.
|
|
|
|
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 str $1==0 /* Store FP */
|
|
with GPR
|
|
gen
|
|
move %1, FP
|
|
|
|
pat str $1==1 /* Store SP */
|
|
with GPR
|
|
gen
|
|
move %1, SP
|
|
|
|
pat loc ass $1==4 && $2==4 /* Drop 4 bytes from stack */
|
|
with exact GPR
|
|
/* nop */
|
|
with STACK
|
|
gen
|
|
addi SP, SP, {CONST, 4}
|
|
|
|
pat ass $1==4 /* Adjust stack by variable amount */
|
|
with CONST2 STACK
|
|
gen
|
|
move {SUM_RC, SP, %1.val}, SP
|
|
with CONST_HZ STACK
|
|
gen
|
|
move {SUM_RC, SP, his(%1.val)}, SP
|
|
with CONST_STACK-CONST2-CONST_HZ STACK
|
|
gen
|
|
move {SUM_RC, SP, his(%1.val)}, SP
|
|
move {SUM_RC, SP, los(%1.val)}, SP
|
|
with GPR STACK
|
|
gen
|
|
move {SUM_RR, SP, %1}, SP
|
|
|
|
pat asp /* Adjust stack by constant amount */
|
|
leaving
|
|
loc $1
|
|
ass 4
|
|
|
|
pat lae rck $2==4 /* Range check */
|
|
with REG
|
|
gen
|
|
cmpwi %1, {CONST, rom($1, 1)}
|
|
blt {LABEL, ".trap_erange"}
|
|
cmpwi %1, {CONST, rom($1, 2)}
|
|
bgt {LABEL, ".trap_erange"}
|
|
yields %1
|
|
|
|
|
|
|
|
|
|
/* 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 FSREG FSREG
|
|
uses reusing %1, FSREG
|
|
gen
|
|
fadds %a, %2, %1
|
|
yields %a
|
|
|
|
pat sbf $1==INT32 /* Subtract single */
|
|
with FSREG FSREG
|
|
uses reusing %1, FSREG
|
|
gen
|
|
fsubs %a, %2, %1
|
|
yields %a
|
|
|
|
pat mlf $1==INT32 /* Multiply single */
|
|
with FSREG FSREG
|
|
uses reusing %1, FSREG
|
|
gen
|
|
fmuls %a, %2, %1
|
|
yields %a
|
|
|
|
pat dvf $1==INT32 /* Divide single */
|
|
with FSREG FSREG
|
|
uses reusing %1, FSREG
|
|
gen
|
|
fdivs %a, %2, %1
|
|
yields %a
|
|
|
|
pat ngf $1==INT32 /* Negate single */
|
|
with FSREG
|
|
uses reusing %1, FSREG
|
|
gen
|
|
fneg %a, %1
|
|
yields %a
|
|
|
|
pat cmf $1==INT32 /* Compare single */
|
|
with FSREG FSREG
|
|
uses REG={COND_FS, %2, %1}
|
|
gen extlwi %a, %a, {CONST, 2}, {CONST, 0}
|
|
yields %a
|
|
|
|
pat cmf teq $1==4 /* Single second == top */
|
|
with FSREG FSREG
|
|
uses REG={COND_FS, %2, %1}
|
|
gen move {XEQ, %a}, %a
|
|
yields %a
|
|
|
|
pat cmf tne $1==4 /* Single second == top */
|
|
with FSREG FSREG
|
|
uses REG={COND_FS, %2, %1}
|
|
gen move {XNE, %a}, %a
|
|
yields %a
|
|
|
|
pat cmf tgt $1==4 /* Single second > top */
|
|
with FSREG FSREG
|
|
uses REG={COND_FS, %2, %1}
|
|
gen move {XGT, %a}, %a
|
|
yields %a
|
|
|
|
pat cmf tge $1==4 /* Single second >= top */
|
|
with FSREG FSREG
|
|
uses REG={COND_FS, %2, %1}
|
|
gen move {XGE, %a}, %a
|
|
yields %a
|
|
|
|
pat cmf tlt $1==4 /* Single second < top */
|
|
with FSREG FSREG
|
|
uses REG={COND_FS, %2, %1}
|
|
gen move {XLT, %a}, %a
|
|
yields %a
|
|
|
|
pat cmf tle $1==4 /* Single second <= top */
|
|
with FSREG FSREG
|
|
uses REG={COND_FS, %2, %1}
|
|
gen move {XLE, %a}, %a
|
|
yields %a
|
|
|
|
proc cmf4zxx example cmf zeq
|
|
with FREG FREG STACK
|
|
uses REG
|
|
gen
|
|
fcmpo CR0, %2, %1
|
|
bxx* {LABEL, $2}
|
|
|
|
/* Pop 2 singles, branch if... */
|
|
pat cmf zeq $1==4 call cmf4zxx("beq")
|
|
pat cmf zne $1==4 call cmf4zxx("bne")
|
|
pat cmf zgt $1==4 call cmf4zxx("bgt")
|
|
pat cmf zge $1==4 call cmf4zxx("bge")
|
|
pat cmf zlt $1==4 call cmf4zxx("blt")
|
|
pat cmf zle $1==4 call cmf4zxx("ble")
|
|
|
|
pat loc loc cff $1==INT32 && $2==INT64 /* Convert single to double */
|
|
with FSREG
|
|
yields %1.1
|
|
|
|
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 FREG FREG
|
|
uses FREG
|
|
gen
|
|
fadd %a, %2, %1
|
|
yields %a
|
|
|
|
pat sbf $1==INT64 /* Subtract double */
|
|
with FREG FREG
|
|
uses FREG
|
|
gen
|
|
fsub %a, %2, %1
|
|
yields %a
|
|
|
|
pat mlf $1==INT64 /* Multiply double */
|
|
with FREG FREG
|
|
uses reusing %1, FREG
|
|
gen
|
|
fmul %a, %2, %1
|
|
yields %a
|
|
|
|
pat dvf $1==INT64 /* Divide double */
|
|
with FREG FREG
|
|
uses reusing %1, FREG
|
|
gen
|
|
fdiv %a, %2, %1
|
|
yields %a
|
|
|
|
pat ngf $1==INT64 /* Negate double */
|
|
with FREG
|
|
uses reusing %1, FREG
|
|
gen
|
|
fneg %a, %1
|
|
yields %a
|
|
|
|
pat cmf $1==INT64 /* Compare double */
|
|
with FREG FREG
|
|
uses REG={COND_FD, %2, %1}
|
|
gen extlwi %a, %a, {CONST, 2}, {CONST, 0}
|
|
yields %a
|
|
|
|
pat cmf teq $1==8 /* Double second == top */
|
|
with FREG FREG
|
|
uses REG={COND_FD, %2, %1}
|
|
gen move {XEQ, %a}, %a
|
|
yields %a
|
|
|
|
pat cmf tne $1==8 /* Single second == top */
|
|
with FREG FREG
|
|
uses REG={COND_FD, %2, %1}
|
|
gen move {XNE, %a}, %a
|
|
yields %a
|
|
|
|
pat cmf tgt $1==8 /* Double second > top */
|
|
with FREG FREG
|
|
uses REG={COND_FD, %2, %1}
|
|
gen move {XGT, %a}, %a
|
|
yields %a
|
|
|
|
pat cmf tge $1==8 /* Double second >= top */
|
|
with FREG FREG
|
|
uses REG={COND_FD, %2, %1}
|
|
gen move {XGE, %a}, %a
|
|
yields %a
|
|
|
|
pat cmf tlt $1==8 /* Double second < top */
|
|
with FREG FREG
|
|
uses REG={COND_FD, %2, %1}
|
|
gen move {XLT, %a}, %a
|
|
yields %a
|
|
|
|
pat cmf tle $1==8 /* Double second <= top */
|
|
with FREG FREG
|
|
uses REG={COND_FD, %2, %1}
|
|
gen move {XLE, %a}, %a
|
|
yields %a
|
|
|
|
proc cmf8zxx example cmf zeq
|
|
with FREG FREG STACK
|
|
uses REG
|
|
gen
|
|
fcmpo CR0, %2, %1
|
|
bxx* {LABEL, $2}
|
|
|
|
/* Pop 2 doubles, branch if... */
|
|
pat cmf zeq $1==8 call cmf8zxx("beq")
|
|
pat cmf zne $1==8 call cmf8zxx("bne")
|
|
pat cmf zgt $1==8 call cmf8zxx("bgt")
|
|
pat cmf zge $1==8 call cmf8zxx("bge")
|
|
pat cmf zlt $1==8 call cmf8zxx("blt")
|
|
pat cmf zle $1==8 call cmf8zxx("ble")
|
|
|
|
pat loc loc cff $1==INT64 && $2==INT32 /* Convert double to single */
|
|
with FREG
|
|
uses reusing %1, FSREG
|
|
gen
|
|
frsp %a, %1
|
|
yields %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 exponent, fraction */
|
|
with GPR3 GPR4
|
|
kills ALL
|
|
gen
|
|
bl {LABEL, ".fef8"}
|
|
yields R4 R3 R5
|
|
|
|
pat fif $1==INT64 /* Multiply then split integer, fraction */
|
|
with FPR1 FPR2
|
|
kills ALL
|
|
gen
|
|
bl {LABEL, ".fif8"}
|
|
yields F1 F2
|