cbe5d8640b
Use f14 to f31 as register variables for 8-byte double-precison.
There are no regvars for 4-byte double precision, because all
regvar(reg_float) must have the same size. I expect more programs to
prefer 8-byte double precision.
Teach mach/powerpc/ncg/mach.c to emit stfd and lfd instructions to
save and restore 8-byte regvars. Delay emitting the function prolog
until f_regsave(), so we can use one addi to make stack space for both
local vars and saved registers. Be more careful with types in mach.c;
don't assume that int and long and full are the same.
In ncg table, add f14 to f31 as register variables, and some rules to
use them. Add rules to put the result of fadd, fsub, fmul, fdiv, fneg
in a regvar. Without such rules, the result would go in a scratch
FREG, and we would need fmr to move it to the regvar. Also add a rule
for pat sdl inreg($1)==reg_float with STACK, so we can unstack the
value directly into the regvar, again without a scratch FREG and fmr.
Edit util/ego/descr/powerpc.descr to tell ego about the new float
regvars. This might not be working right; ego usually decides against
using any float regvars, so ack -O1 (not running ego) uses the
regvars, but ack -O4 (running ego) doesn't use the regvars.
Beware that ack -mosxppc runs ego using powerpc.descr but -mlinuxppc
and -mqemuppc run ego without a config file (since 8ef7c31
). I am
testing powerpc.descr with a local edit to plat/linuxppc/descr to run
ego with powerpc.descr there, but I did not commit my local edit.
2368 lines
55 KiB
Plaintext
2368 lines
55 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 */
|
|
SL_OFFSET = 8 /* Offset of static link */
|
|
|
|
#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 */
|
|
FPR(8) /* any FPR */
|
|
FREG(8) /* any allocatable FPR */
|
|
FSREG /* any allocatable single-precision FPR */
|
|
SPR /* any SPR */
|
|
CR /* any CR */
|
|
|
|
|
|
REGISTERS
|
|
|
|
/* Reverse order to encourage ncg to allocate them from r31 down */
|
|
|
|
r31, r30, r29, r28, r27, r26,
|
|
r25, r24, r23, r22, r21, r20,
|
|
r19, r18, r17, r16, r15, r14,
|
|
r13 : GPR, REG regvar(reg_any).
|
|
|
|
r12, r11, r10, r9, r8, r7,
|
|
r6, r5, r4, r3 : GPR, REG.
|
|
|
|
fp, sp, r0 : GPR.
|
|
|
|
f31, f30, f29, f28, f27, f26,
|
|
f25, f24, f23, f22, f21, f20,
|
|
f19, f18, f17, f16, f15, f14 : FPR, FREG regvar(reg_float).
|
|
|
|
f13, f12, f11, f10, f9, f8
|
|
f7, f6, f5, f4, f3, f2, f1 : FPR, FREG.
|
|
|
|
f0 : FPR.
|
|
|
|
fs13("f13")=f13, fs12("f12")=f12,
|
|
fs11("f11")=f11, fs10("f10")=f10,
|
|
fs9("f9")=f9, fs8("f8")=f8,
|
|
fs7("f7")=f7, fs6("f6")=f6,
|
|
fs5("f5")=f5, fs4("f4")=f4,
|
|
fs3("f3")=f3, fs2("f2")=f2,
|
|
fs1("f1")=f1 : FSREG.
|
|
|
|
lr, ctr : SPR.
|
|
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 "]".
|
|
LOCAL = { INT off; } 4 ">>> BUG IN LOCAL".
|
|
DLOCAL = { INT off; } 8 ">>> BUG IN DLOCAL".
|
|
|
|
/* 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. /* reg + (offhi << 16) */
|
|
SUM_RC = { GPR reg; INT off; } 4. /* reg + off */
|
|
SUM_RL = { GPR reg; ADDR adr; } 4. /* reg + lo16[adr] */
|
|
SUM_RR = { GPR reg1; GPR reg2; } 4. /* reg1 + reg2 */
|
|
|
|
SEX_B = { GPR reg; } 4.
|
|
SEX_H = { GPR reg; } 4.
|
|
|
|
IND_RC_B = { GPR reg; INT off; } 4 off "(" reg ")".
|
|
IND_RL_B = { GPR reg; ADDR adr; } 4 "lo16[" adr "](" reg ")".
|
|
IND_RR_B = { GPR reg1; GPR reg2; } 4.
|
|
IND_RC_H = { GPR reg; INT off; } 4 off "(" reg ")".
|
|
IND_RL_H = { GPR reg; ADDR adr; } 4 "lo16[" adr "](" reg ")".
|
|
IND_RR_H = { GPR reg1; GPR reg2; } 4.
|
|
IND_RC_H_S = { GPR reg; INT off; } 4 off "(" reg ")".
|
|
IND_RL_H_S = { GPR reg; ADDR adr; } 4 "lo16[" adr "](" 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_RL_D = { GPR reg; ADDR adr; } 8 "lo16[" adr "](" 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_RL + SUM_RR.
|
|
|
|
SEX_ALL = SEX_B + SEX_H.
|
|
|
|
LOGICAL_ALL = NOT_R + AND_RR + OR_RR + OR_RC + XOR_RR +
|
|
XOR_RC.
|
|
|
|
IND_ALL_B = IND_RC_B + IND_RL_B + IND_RR_B.
|
|
IND_ALL_H = IND_RC_H + IND_RL_H + IND_RR_H +
|
|
IND_RC_H_S + IND_RL_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_RL_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 + 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.
|
|
bdnz 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+DLOCAL: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).
|
|
fctiwz FREG:wo, FREG:ro.
|
|
fdiv FREG+DLOCAL:wo, FREG:ro, FREG:ro cost(4, 35).
|
|
fdivs FSREG:wo, FSREG:ro, FSREG:ro cost(4, 21).
|
|
fmr FPR+DLOCAL:wo, FPR:ro cost(4, 5).
|
|
fmr FSREG:wo, FSREG:ro cost(4, 5).
|
|
fmul FREG+DLOCAL:wo, FREG:ro, FREG:ro cost(4, 5).
|
|
fmuls FSREG:wo, FSREG:ro, FSREG:ro cost(4, 5).
|
|
fneg FREG+DLOCAL:wo, FREG:ro cost(4, 5).
|
|
fneg FSREG:wo, FSREG:ro cost(4, 5).
|
|
frsp FSREG:wo, FREG:ro cost(4, 5).
|
|
fsub FREG+DLOCAL:wo, FREG:ro, FREG:ro cost(4, 5).
|
|
fsubs FSREG:wo, FSREG:ro, FSREG:ro cost(4, 5).
|
|
lbz GPR:wo, IND_RC_B+IND_RL_B:ro cost(4, 3).
|
|
lbzx GPR:wo, GPR:ro, GPR:ro cost(4, 3).
|
|
lfd FPR+DLOCAL:wo, IND_RC_D+IND_RL_D:ro cost(4, 5).
|
|
lfdu FPR:wo, IND_RC_D:ro cost(4, 5).
|
|
lfdx FPR+DLOCAL: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+IND_RL_H_S:ro cost(4, 3).
|
|
lhax GPR:wo, GPR:ro, GPR:ro cost(4, 3).
|
|
lhz GPR:wo, IND_RC_H+IND_RL_H:ro cost(4, 3).
|
|
lhzx GPR:wo, GPR:ro, GPR:ro cost(4, 3).
|
|
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.
|
|
mr GPR:wo, GPR:ro.
|
|
orX "or." GPR:wo:cc, GPR:ro, GPR:ro.
|
|
orX_readonly "or." GPR:ro:cc, 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.
|
|
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.
|
|
srwi GPR:wo, GPR: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+IND_RL_B:rw cost(4, 3).
|
|
stbx GPR:ro, GPR:ro, GPR:ro cost(4, 3).
|
|
stfd FPR:ro, IND_RC_D+IND_RL_D:rw cost(4, 4).
|
|
stfdu FPR+DLOCAL: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+IND_RL_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 mr %2, %1
|
|
|
|
from FPR to FPR+DLOCAL
|
|
gen fmr %2, %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
|
|
|
|
/* Sign extension */
|
|
|
|
from SEX_B to GPR
|
|
gen extsb %2, %1.reg
|
|
|
|
from SEX_H to GPR
|
|
gen extsh %2, %1.reg
|
|
|
|
/* Register + something */
|
|
|
|
from SUM_RIS to GPR
|
|
gen addis %2, %1.reg, {CONST, %1.offhi}
|
|
|
|
from SUM_RC to GPR
|
|
gen addi %2, %1.reg, {CONST, %1.off}
|
|
|
|
from SUM_RL to GPR
|
|
gen addi %2, %1.reg, {LABEL_LO, %1.adr}
|
|
|
|
from SUM_RR to GPR
|
|
gen add %2, %1.reg1, %1.reg2
|
|
|
|
/* Read byte */
|
|
|
|
from IND_RC_B+IND_RL_B to GPR
|
|
gen lbz %2, %1
|
|
|
|
from IND_RR_B to GPR
|
|
gen lbzx %2, %1.reg1, %1.reg2
|
|
|
|
/* Write byte */
|
|
|
|
from GPR to IND_RC_B+IND_RL_B
|
|
gen stb %1, %2
|
|
|
|
from GPR to IND_RR_B
|
|
gen stbx %1, %2.reg1, %2.reg2
|
|
|
|
/* Read halfword (short) */
|
|
|
|
from IND_RC_H+IND_RL_H to GPR
|
|
gen lhz %2, %1
|
|
|
|
from IND_RR_H to GPR
|
|
gen lhzx %2, %1.reg1, %1.reg2
|
|
|
|
from IND_RC_H_S+IND_RL_H_S to GPR
|
|
gen lha %2, %1
|
|
|
|
from IND_RR_H_S to GPR
|
|
gen lhax %2, %1.reg1, %1.reg2
|
|
|
|
/* Write halfword */
|
|
|
|
from GPR to IND_RC_H+IND_RL_H
|
|
gen sth %1, %2
|
|
|
|
from GPR to IND_RR_H
|
|
gen sthx %1, %2.reg1, %2.reg2
|
|
|
|
/* Read word */
|
|
|
|
from IND_RC_W+IND_RL_W to GPR
|
|
gen lwz %2, %1
|
|
|
|
from IND_RR_W to GPR
|
|
gen lwzx %2, %1.reg1, %1.reg2
|
|
|
|
from IND_RC_W+IND_RL_W to FSREG
|
|
gen lfs %2, %1
|
|
|
|
from IND_RR_W to FSREG
|
|
gen lfsx %2, %1.reg1, %1.reg2
|
|
|
|
/* Write word */
|
|
|
|
from GPR to IND_RC_W+IND_RL_W
|
|
gen stw %1, %2
|
|
|
|
from GPR to IND_RR_W
|
|
gen stwx %1, %2.reg1, %2.reg2
|
|
|
|
from FSREG to IND_RC_W+IND_RL_W
|
|
gen stfs %1, %2
|
|
|
|
from FSREG to IND_RR_W
|
|
gen stfsx %1, %2.reg1, %2.reg2
|
|
|
|
/* Read double */
|
|
|
|
from IND_RC_D+IND_RL_D to FPR+DLOCAL
|
|
gen lfd %2, %1
|
|
|
|
from IND_RR_D to FPR+DLOCAL
|
|
gen lfdx %2, %1.reg1, %1.reg2
|
|
|
|
/* Write double */
|
|
|
|
from FPR to IND_RC_D+IND_RL_D
|
|
gen stfd %1, %2
|
|
|
|
from FPR to IND_RR_D
|
|
gen stfdx %1, %2.reg1, %2.reg2
|
|
|
|
/* Logicals */
|
|
|
|
from NOT_R to GPR
|
|
gen nor %2, %1.reg, %1.reg
|
|
|
|
from AND_RR to GPR
|
|
gen and %2, %1.reg1, %1.reg2
|
|
|
|
from OR_RR to GPR
|
|
gen or %2, %1.reg1, %1.reg2
|
|
|
|
from OR_RIS to GPR
|
|
gen oris %2, %1.reg, {CONST, %1.valhi}
|
|
|
|
from OR_RC to GPR
|
|
gen ori %2, %1.reg, {CONST, %1.val}
|
|
|
|
from XOR_RR to GPR
|
|
gen xor %2, %1.reg1, %1.reg2
|
|
|
|
from XOR_RIS to GPR
|
|
gen xoris %2, %1.reg, {CONST, %1.valhi}
|
|
|
|
from XOR_RC to GPR
|
|
gen 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
|
|
|
|
/* Given orX %1, %1, %1, ncgg says, "Instruction destroys %1,
|
|
* not allowed here". We use orX_readonly to trick ncgg.
|
|
*
|
|
* Using "or." and not "mr." because mach/powerpc/top/table
|
|
* was optimizing "or." and not "mr.".
|
|
*/
|
|
to test GPR
|
|
gen
|
|
orX_readonly %1, %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 ANY_BHW-REG to STACK
|
|
gen
|
|
COMMENT("stack ANY_BHW-REG")
|
|
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+DLOCAL to STACK
|
|
gen
|
|
COMMENT("stack FREG+DLOCAL")
|
|
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 ANY_BHW
|
|
uses REG
|
|
gen
|
|
COMMENT("coerce ANY_BHW->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 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_W
|
|
uses FSREG
|
|
gen
|
|
move %1, %a
|
|
yields %a
|
|
|
|
/*
|
|
* from IND_RC_D to REG REG 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
|
|
*/
|
|
|
|
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 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 REG
|
|
yields {SEX_B, %1}
|
|
|
|
pat loc loc cii $1==2 && $2==4 /* signed char -> signed short */
|
|
with REG
|
|
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)}
|
|
|
|
/* Load word from local */
|
|
pat lol inreg($1)==reg_any
|
|
yields {LOCAL, $1}
|
|
pat lol
|
|
leaving
|
|
lal $1
|
|
loi 4
|
|
|
|
/* Load double-word from local */
|
|
pat ldl inreg($1)==reg_float
|
|
yields {DLOCAL, $1}
|
|
pat ldl
|
|
leaving
|
|
lal $1
|
|
loi 8
|
|
|
|
/* Store word to local */
|
|
pat stl inreg($1)==reg_any
|
|
with ANY_BHW
|
|
kills regvar($1), LOCAL %off==$1
|
|
gen move %1, {GPRE, regvar($1)}
|
|
pat stl
|
|
leaving
|
|
lal $1
|
|
sti 4
|
|
|
|
/* Store double-word to local */
|
|
pat sdl inreg($1)==reg_float
|
|
with exact FREG+IND_ALL_D
|
|
gen move %1, {DLOCAL, $1}
|
|
with STACK
|
|
gen
|
|
lfd {DLOCAL, $1}, {IND_RC_D, sp, 0}
|
|
addi sp, sp, {CONST, 8}
|
|
pat sdl
|
|
leaving
|
|
lal $1
|
|
sti 8
|
|
|
|
/* Load indirect from local */
|
|
pat lil inreg($1)==reg_any
|
|
yields {IND_RC_W, regvar($1), 0}
|
|
pat lil
|
|
leaving
|
|
lol $1
|
|
loi 4
|
|
|
|
pat sil /* Save to indirected local */
|
|
leaving
|
|
lol $1
|
|
sti 4
|
|
|
|
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={LABEL_HA, $1}
|
|
yields {SUM_RL, %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 */
|
|
leaving
|
|
loe $1
|
|
inc
|
|
ste $1
|
|
|
|
pat dee /* Decrement external */
|
|
leaving
|
|
loe $1
|
|
dec
|
|
ste $1
|
|
|
|
|
|
/* 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 REG
|
|
yields {IND_RC_B, %1, 0}
|
|
with exact SUM_RC
|
|
yields {IND_RC_B, %1.reg, %1.off}
|
|
with exact SUM_RL
|
|
yields {IND_RL_B, %1.reg, %1.adr}
|
|
with exact SUM_RR
|
|
yields {IND_RR_B, %1.reg1, %1.reg2}
|
|
|
|
pat loi loc loc cii $1==INT16 && $2==INT16 && $3==INT32
|
|
/* Load half-word indirect and sign extend */
|
|
with REG
|
|
yields {IND_RC_H_S, %1, 0}
|
|
with exact SUM_RC
|
|
yields {IND_RC_H_S, %1.reg, %1.off}
|
|
with exact SUM_RL
|
|
yields {IND_RL_H_S, %1.reg, %1.adr}
|
|
with exact SUM_RR
|
|
yields {IND_RR_H_S, %1.reg1, %1.reg2}
|
|
|
|
pat loi $1==INT16 /* Load half-word indirect */
|
|
with REG
|
|
yields {IND_RC_H, %1, 0}
|
|
with exact SUM_RC
|
|
yields {IND_RC_H, %1.reg, %1.off}
|
|
with exact SUM_RL
|
|
yields {IND_RL_H, %1.reg, %1.adr}
|
|
with exact SUM_RR
|
|
yields {IND_RR_H, %1.reg1, %1.reg2}
|
|
|
|
pat loi $1==INT32 /* Load word indirect */
|
|
with REG
|
|
yields {IND_RC_W, %1, 0}
|
|
with exact SUM_RC
|
|
yields {IND_RC_W, %1.reg, %1.off}
|
|
with exact SUM_RL
|
|
yields {IND_RL_W, %1.reg, %1.adr}
|
|
with exact SUM_RR
|
|
yields {IND_RR_W, %1.reg1, %1.reg2}
|
|
|
|
pat loi $1==INT64 /* Load double-word indirect */
|
|
with REG
|
|
yields {IND_RC_D, %1, 0}
|
|
with exact SUM_RC
|
|
yields {IND_RC_D, %1.reg, %1.off}
|
|
with exact SUM_RL
|
|
yields {IND_RL_D, %1.reg, %1.adr}
|
|
with exact SUM_RR
|
|
yields {IND_RR_D, %1.reg1, %1.reg2}
|
|
|
|
pat loi /* Load arbitrary size */
|
|
leaving
|
|
loc $1
|
|
los 4
|
|
|
|
pat los $1==4 /* Load arbitrary size */
|
|
with REG STACK
|
|
kills ALL
|
|
gen
|
|
move %1, r3
|
|
bl {LABEL, ".los4"}
|
|
|
|
pat sti $1==INT8 /* Store byte indirect */
|
|
with REG REG
|
|
kills MEMORY
|
|
gen move %2, {IND_RC_B, %1, 0}
|
|
with SUM_RC REG
|
|
kills MEMORY
|
|
gen move %2, {IND_RC_B, %1.reg, %1.off}
|
|
with SUM_RL REG
|
|
kills MEMORY
|
|
gen move %2, {IND_RL_B, %1.reg, %1.adr}
|
|
with SUM_RR REG
|
|
kills MEMORY
|
|
gen move %2, {IND_RR_B, %1.reg1, %1.reg2}
|
|
|
|
pat sti $1==INT16 /* Store half-word indirect */
|
|
with REG REG
|
|
kills MEMORY
|
|
gen move %2, {IND_RC_H, %1, 0}
|
|
with SUM_RC REG
|
|
kills MEMORY
|
|
gen move %2, {IND_RC_H, %1.reg, %1.off}
|
|
with SUM_RL REG
|
|
kills MEMORY
|
|
gen move %2, {IND_RL_H, %1.reg, %1.adr}
|
|
with SUM_RR REG
|
|
kills MEMORY
|
|
gen move %2, {IND_RR_H, %1.reg1, %1.reg2}
|
|
|
|
pat sti $1==INT32 /* Store word indirect */
|
|
with REG REG+FSREG
|
|
kills MEMORY
|
|
gen move %2, {IND_RC_W, %1, 0}
|
|
with SUM_RC REG+FSREG
|
|
kills MEMORY
|
|
gen move %2, {IND_RC_W, %1.reg, %1.off}
|
|
with SUM_RL REG+FSREG
|
|
kills MEMORY
|
|
gen move %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}
|
|
|
|
pat sti $1==INT64 /* Store double-word indirect */
|
|
with REG FREG
|
|
kills MEMORY
|
|
gen move %2, {IND_RC_D, %1, 0}
|
|
with SUM_RC FREG
|
|
kills MEMORY
|
|
gen move %2, {IND_RC_D, %1.reg, %1.off}
|
|
with SUM_RL FREG
|
|
kills MEMORY
|
|
gen move %2, {IND_RL_D, %1.reg, %1.adr}
|
|
with SUM_RR FREG
|
|
kills MEMORY
|
|
gen move %2, {IND_RR_D, %1.reg1, %1.reg2}
|
|
with REG REG REG
|
|
kills MEMORY
|
|
gen
|
|
move %2, {IND_RC_W, %1, 0}
|
|
move %3, {IND_RC_W, %1, 4}
|
|
/*
|
|
* Next 2 patterns exist because there is no coercion
|
|
* from IND_ALL_D to REG REG.
|
|
*/
|
|
with REG IND_RC_D
|
|
kills MEMORY
|
|
uses REG={SUM_RC, %2.reg, %2.off}, REG, REG
|
|
gen
|
|
move {IND_RC_W, %a, 0}, %b
|
|
move {IND_RC_W, %a, 4}, %c
|
|
move %b, {IND_RC_W, %1, 0}
|
|
move %c, {IND_RC_W, %1, 4}
|
|
with REG IND_RR_D
|
|
kills MEMORY
|
|
uses REG={SUM_RR, %2.reg1, %2.reg2}, REG, REG
|
|
gen
|
|
move {IND_RC_W, %a, 0}, %b
|
|
move {IND_RC_W, %a, 4}, %c
|
|
move %b, {IND_RC_W, %1, 0}
|
|
move %c, {IND_RC_W, %1, 4}
|
|
|
|
pat sti /* Store arbitrary size */
|
|
leaving
|
|
loc $1
|
|
sts 4
|
|
|
|
pat sts $1==4 /* Store arbitrary size */
|
|
with REG STACK
|
|
kills ALL
|
|
gen
|
|
move %1, r3
|
|
bl {LABEL, ".sts4"}
|
|
|
|
|
|
/* 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 mlu /* Multiply unsigned */
|
|
leaving
|
|
mli $1
|
|
|
|
pat slu /* Shift left unsigned */
|
|
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)}
|
|
|
|
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)}
|
|
|
|
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 REG NOT_R
|
|
uses reusing %1, REG
|
|
gen
|
|
andc %a, %1, %2.reg
|
|
yields %a
|
|
with NOT_R REG
|
|
uses reusing %1, REG
|
|
gen
|
|
andc %a, %2, %1.reg
|
|
yields %a
|
|
with REG REG
|
|
yields {AND_RR, %1, %2}
|
|
with REG UCONST2
|
|
uses reusing %1, REG
|
|
gen
|
|
andiX %a, %1, {CONST, %2.val}
|
|
yields %a
|
|
with UCONST2 REG
|
|
uses reusing %2, REG
|
|
gen
|
|
andiX %a, %2, {CONST, %1.val}
|
|
yields %a
|
|
with REG CONST_HZ
|
|
uses reusing %1, REG
|
|
gen
|
|
andisX %a, %1, {CONST, hi(%2.val)}
|
|
yields %a
|
|
with CONST_HZ REG
|
|
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 */
|
|
leaving
|
|
loc $1
|
|
cal ".xor"
|
|
|
|
pat xor !defined($1)
|
|
leaving
|
|
cal ".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 REG
|
|
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 REG
|
|
uses reusing %2, REG
|
|
gen
|
|
rlwinm %a, %2, {CONST, (%1.val & 0x1F)}, {CONST, 0}, {CONST, 31-(%1.val & 0x1F)}
|
|
yields %a
|
|
with REG REG
|
|
uses reusing %2, REG
|
|
gen
|
|
slw %a, %2, %1
|
|
yields %a
|
|
|
|
pat sri $1==4 /* Shift right signed (second >> top) */
|
|
with CONST_STACK REG
|
|
uses reusing %2, REG
|
|
gen
|
|
srawi %a, %2, {CONST, %1.val & 0x1F}
|
|
yields %a
|
|
with REG REG
|
|
uses reusing %2, REG
|
|
gen
|
|
sraw %a, %2, %1
|
|
yields %a
|
|
|
|
pat sru $1==4 /* Shift right unsigned (second >> top) */
|
|
with CONST_STACK REG
|
|
uses reusing %2, REG
|
|
gen
|
|
rlwinm %a, %2, {CONST, 32-(%1.val & 0x1F)}, {CONST, (%1.val & 0x1F)}, {CONST, 31}
|
|
yields %a
|
|
with REG REG
|
|
uses reusing %2, REG
|
|
gen
|
|
srw %a, %2, %1
|
|
yields %a
|
|
|
|
|
|
/* Arrays */
|
|
|
|
pat aar $1==4 /* Address of array element */
|
|
leaving
|
|
cal ".aar4"
|
|
|
|
pat lar $1==4 /* Load from array */
|
|
with STACK
|
|
kills ALL
|
|
gen
|
|
bl {LABEL, ".aar4"}
|
|
/* pass r3 = size from .aar4 to .los4 */
|
|
bl {LABEL, ".los4"}
|
|
|
|
pat lae lar $2==4 && nicesize(rom($1, 3))
|
|
leaving
|
|
lae $1
|
|
aar 4
|
|
loi rom($1, 3)
|
|
|
|
pat sar $1==4 /* Store to array */
|
|
with STACK
|
|
kills ALL
|
|
gen
|
|
bl {LABEL, ".aar4"}
|
|
/* pass r3 = size from .aar4 to .sts4 */
|
|
bl {LABEL, ".sts4"}
|
|
|
|
pat lae sar $2==4 && nicesize(rom($1, 3))
|
|
leaving
|
|
lae $1
|
|
aar 4
|
|
sti rom($1, 3)
|
|
|
|
|
|
/* 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)
|
|
leaving
|
|
loc $1
|
|
cal ".cms"
|
|
|
|
pat cms !defined($1)
|
|
leaving
|
|
cal ".cms"
|
|
|
|
|
|
/* 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 REG STACK
|
|
kills ALL
|
|
gen
|
|
move %1, r3
|
|
labeldef $1
|
|
yields r3
|
|
|
|
pat lab topeltsize($1)!=4
|
|
with STACK
|
|
kills ALL
|
|
gen
|
|
labeldef $1
|
|
|
|
pat bra topeltsize($1)==4 /* Unconditional jump with TOS GPRister */
|
|
with REG STACK
|
|
gen
|
|
move %1, r3
|
|
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 REG 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 REG
|
|
gen
|
|
move %1, r3
|
|
return
|
|
b {LABEL, ".ret"}
|
|
|
|
pat ret $1==INT64 /* Return from procedure, double-word */
|
|
with REG REG
|
|
gen
|
|
move %1, r3
|
|
move %2, r4
|
|
return
|
|
b {LABEL, ".ret"}
|
|
|
|
pat blm /* Block move constant length */
|
|
leaving
|
|
loc $1
|
|
bls
|
|
|
|
pat bls /* Block move variable length */
|
|
with REG REG REG
|
|
uses reusing %1, REG, REG={CONST_0000_7FFF, 0}
|
|
gen
|
|
/* Wrong if size is zero */
|
|
srwi %1, %1, {CONST, 2}
|
|
mtspr ctr, %1
|
|
1:
|
|
lwzx %a, %3, %b
|
|
stwx %a, %2, %b
|
|
addi %b, %b, {CONST, 4}
|
|
bdnz {LABEL, "1b"}
|
|
|
|
pat csa /* Array-lookup switch */
|
|
with STACK
|
|
kills ALL
|
|
gen
|
|
b {LABEL, ".csa"}
|
|
|
|
pat csb /* Table-lookup switch */
|
|
with STACK
|
|
kills ALL
|
|
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 REG
|
|
kills ALL
|
|
gen
|
|
move %1, r3
|
|
bl {LABEL, ".trap"}
|
|
|
|
pat sig /* Set trap handler */
|
|
leaving
|
|
ste ".trppc"
|
|
|
|
pat rtt /* Return from trap */
|
|
leaving
|
|
ret 0
|
|
|
|
/*
|
|
* Lexical local base: lxl 0 yields our fp, lxl n yields the
|
|
* fp of the nth statically enclosing procedure.
|
|
*/
|
|
pat lxl $1==0
|
|
leaving
|
|
lor 0
|
|
pat lxl $1==1
|
|
yields {IND_RC_W, fp, SL_OFFSET}
|
|
pat lxl $1==2
|
|
uses REG={IND_RC_W, fp, SL_OFFSET}
|
|
yields {IND_RC_W, %a, SL_OFFSET}
|
|
pat lxl $1==3
|
|
uses REG={IND_RC_W, fp, SL_OFFSET}, reusing %a, REG
|
|
gen move {IND_RC_W, %a, SL_OFFSET}, %b
|
|
yields {IND_RC_W, %b, SL_OFFSET}
|
|
pat lxl $1>=4 && $1<=0x8000
|
|
uses REG={IND_RC_W, fp, SL_OFFSET},
|
|
REG={CONST_0000_7FFF, $1-1}
|
|
gen
|
|
mtspr ctr, %b
|
|
1:
|
|
lwz %a, {IND_RC_W, %a, SL_OFFSET}
|
|
bdnz {LABEL, "1b"}
|
|
yields %a
|
|
|
|
pat dch /* Dynamic chain: LB -> caller's LB */
|
|
with REG
|
|
yields {IND_RC_W, %1, FP_OFFSET}
|
|
|
|
pat lpb /* LB -> argument base */
|
|
leaving
|
|
adp EM_BSIZE
|
|
|
|
pat lxa /* Lexical argument base */
|
|
leaving
|
|
lxl $1
|
|
lpb
|
|
|
|
pat gto /* longjmp */
|
|
with STACK
|
|
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 local base */
|
|
uses REG
|
|
gen
|
|
move fp, %a
|
|
yields %a
|
|
|
|
pat lor $1==1 /* Load stack pointer */
|
|
uses REG
|
|
gen
|
|
move sp, %a
|
|
yields %a
|
|
|
|
pat str $1==0 /* Store local base */
|
|
with REG
|
|
gen
|
|
move %1, fp
|
|
|
|
pat str $1==1 /* Store stack pointer */
|
|
with REG
|
|
gen
|
|
move %1, sp
|
|
|
|
pat loc ass $1==4 && $2==4 /* Drop 4 bytes from stack */
|
|
with exact REG
|
|
/* 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 REG 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
|
|
kills ALL
|
|
gen
|
|
cmpwi %1, {CONST, rom($1, 1)}
|
|
blt {LABEL, ".trap_erange"}
|
|
cmpwi %1, {CONST, rom($1, 2)}
|
|
bgt {LABEL, ".trap_erange"}
|
|
yields %1
|
|
|
|
|
|
/* Single-precision floating-point */
|
|
|
|
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
|
|
|
|
/* Convert single to signed int */
|
|
pat loc loc cfi $1==4 && $2==4
|
|
leaving
|
|
loc 4
|
|
loc 8
|
|
cff
|
|
loc 8
|
|
loc 4
|
|
cfi
|
|
|
|
/* Convert single to unsigned int */
|
|
pat loc loc cfu $1==4 && $2==4
|
|
leaving
|
|
loc 4
|
|
loc 8
|
|
cff
|
|
loc 8
|
|
loc 4
|
|
cfu
|
|
|
|
/* Convert signed int to single */
|
|
pat loc loc cif $1==4 && $2==4
|
|
leaving
|
|
loc 4
|
|
loc 8
|
|
cif
|
|
loc 8
|
|
loc 4
|
|
cff
|
|
|
|
/* Convert unsigned int to single */
|
|
pat loc loc cuf $1==4 && $2==4
|
|
leaving
|
|
loc 4
|
|
loc 8
|
|
cuf
|
|
loc 8
|
|
loc 4
|
|
cff
|
|
|
|
|
|
/* Double-precision floating-point */
|
|
|
|
pat zrf $1==INT64 /* Push zero */
|
|
leaving
|
|
lde ".fd_00000000"
|
|
|
|
pat adf $1==8 /* Add double */
|
|
with FREG FREG
|
|
uses reusing %1, FREG
|
|
gen
|
|
fadd %a, %2, %1
|
|
yields %a
|
|
pat adf sdl $1==8 && inreg($2)==reg_float
|
|
with FREG FREG
|
|
gen fadd {DLOCAL, $2}, %2, %1
|
|
|
|
pat sbf $1==8 /* Subtract double */
|
|
with FREG FREG
|
|
uses reusing %1, FREG
|
|
gen
|
|
fsub %a, %2, %1
|
|
yields %a
|
|
pat sbf sdl $1==8 && inreg($2)==reg_float
|
|
with FREG FREG
|
|
gen fsub {DLOCAL, $2}, %2, %1
|
|
|
|
pat mlf $1==8 /* Multiply double */
|
|
with FREG FREG
|
|
uses reusing %1, FREG
|
|
gen
|
|
fmul %a, %2, %1
|
|
yields %a
|
|
pat mlf sdl $1==8 && inreg($2)==reg_float
|
|
with FREG FREG
|
|
gen fmul {DLOCAL, $2}, %2, %1
|
|
|
|
pat dvf $1==8 /* Divide double */
|
|
with FREG FREG
|
|
uses reusing %1, FREG
|
|
gen
|
|
fdiv %a, %2, %1
|
|
yields %a
|
|
pat dvf sdl $1==8 && inreg($2)==reg_float
|
|
with FREG FREG
|
|
gen fdiv {DLOCAL, $2}, %2, %1
|
|
|
|
pat ngf $1==8 /* Negate double */
|
|
with FREG
|
|
uses reusing %1, FREG
|
|
gen
|
|
fneg %a, %1
|
|
yields %a
|
|
pat ngf sdl $1==8 && inreg($2)==reg_float
|
|
with FREG
|
|
gen fneg {DLOCAL, $2}, %1
|
|
|
|
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
|
|
|
|
/* Convert double to signed int */
|
|
pat loc loc cfi $1==8 && $2==4
|
|
with FREG STACK
|
|
uses reusing %1, FREG
|
|
gen
|
|
fctiwz %a, %1
|
|
stfdu %a, {IND_RC_D, sp, 0-8}
|
|
addi sp, sp, {CONST, 4}
|
|
|
|
/* Convert double to unsigned int */
|
|
pat loc loc cfu $1==8 && $2==4
|
|
leaving
|
|
cal ".cfu8"
|
|
|
|
/*
|
|
* To convert integer to IEEE double, we pack the integer in
|
|
* the low bits of the magic double
|
|
* 1 << 52 == 0x 4330 0000 0000 0000
|
|
*
|
|
* For signed integer i, we flip its sign bit, then compute
|
|
* ((1 << 52) + i) - ((1 << 52) + (1 << 31))
|
|
*/
|
|
pat loc loc cif $1==4 && $2==8
|
|
with REG
|
|
uses reusing %1, REG={XOR_RIS, %1, 0x8000},
|
|
REG={CONST_HZ, 0x43300000},
|
|
REG={CONST_HZ, 0x80000000},
|
|
FREG, FREG
|
|
gen
|
|
stwu %b, {IND_RC_W, sp, 0-8}
|
|
stw %a, {IND_RC_W, sp, 4}
|
|
lfd %d, {IND_RC_D, sp, 0}
|
|
stw %c, {IND_RC_W, sp, 4}
|
|
lfd %e, {IND_RC_D, sp, 0}
|
|
fsub %d, %d, %e
|
|
addi sp, sp, {CONST, 8}
|
|
yields %d
|
|
|
|
/*
|
|
* To convert unsigned integer u to IEEE double, we compute
|
|
* ((1 << 52) + u) - (1 << 52)
|
|
*/
|
|
pat loc loc cuf $1==4 && $2==8
|
|
with REG
|
|
uses REG={CONST_HZ, 0x43300000},
|
|
REG={CONST_0000_7FFF, 0},
|
|
FREG, FREG
|
|
gen
|
|
stwu %a, {IND_RC_W, sp, 0-8}
|
|
stw %1, {IND_RC_W, sp, 4}
|
|
lfd %c, {IND_RC_D, sp, 0}
|
|
stw %b, {IND_RC_W, sp, 4}
|
|
lfd %d, {IND_RC_D, sp, 0}
|
|
fsub %c, %c, %d
|
|
addi sp, sp, {CONST, 8}
|
|
yields %c
|
|
|
|
pat fef $1==8 /* Split fraction, exponent */
|
|
leaving
|
|
cal ".fef8"
|
|
|
|
/* Multiply two doubles, then split fraction, integer */
|
|
pat fif $1==8
|
|
leaving
|
|
cal ".fif8"
|