2007-11-02 18:56:58 +00:00
|
|
|
|
2017-12-23 03:32:16 +00:00
|
|
|
/* PowerPC table for ACK target optimizer */
|
2007-11-02 18:56:58 +00:00
|
|
|
|
2018-01-05 22:55:50 +00:00
|
|
|
MAXOP 5;
|
2016-10-29 21:37:11 +00:00
|
|
|
LABEL_STARTER '.';
|
2007-11-02 18:56:58 +00:00
|
|
|
|
2019-10-24 18:08:52 +00:00
|
|
|
{
|
|
|
|
int not_using_sp(const char *);
|
|
|
|
int positive(const char *);
|
|
|
|
int lift(const char *);
|
2019-10-25 19:52:09 +00:00
|
|
|
int plus(const char *, const char *, char *);
|
2019-10-24 18:08:52 +00:00
|
|
|
}
|
|
|
|
|
2007-11-02 18:56:58 +00:00
|
|
|
%%;
|
|
|
|
|
2018-01-05 22:55:50 +00:00
|
|
|
L1, L2, L3, L4, L5 { not_using_sp(VAL) };
|
In PowerPC top, don't delete addi r0, r0, 0
Also don't delete addis r0, r0, 0. These instructions are special
cases that set r0 to zero. If we delete them, then r0 keeps its old
value.
I caught this bug because osxppc protects the .text segment against
writing. (linuxppc doesn't protect it.) A program tried to set r0 to
the NULL pointer, but top deleted the instruction, so r0 kept an old
return address pointing into .text. Later the program checked that r0
wasn't NULL, tried to write to address r0, and crashed.
2017-01-26 17:44:32 +00:00
|
|
|
RNZ { strcmp(VAL, "r0") }; /* not r0 */
|
2018-02-01 17:20:31 +00:00
|
|
|
UP { positive(VAL) };
|
2007-11-02 18:56:58 +00:00
|
|
|
X, Y, Z { TRUE };
|
|
|
|
|
|
|
|
%%;
|
|
|
|
|
|
|
|
/* Whitespace is significant here! */
|
|
|
|
|
In PowerPC top, don't delete addi r0, r0, 0
Also don't delete addis r0, r0, 0. These instructions are special
cases that set r0 to zero. If we delete them, then r0 keeps its old
value.
I caught this bug because osxppc protects the .text segment against
writing. (linuxppc doesn't protect it.) A program tried to set r0 to
the NULL pointer, but top deleted the instruction, so r0 kept an old
return address pointing into .text. Later the program checked that r0
wasn't NULL, tried to write to address r0, and crashed.
2017-01-26 17:44:32 +00:00
|
|
|
addi RNZ, RNZ, 0 -> ;
|
|
|
|
addis RNZ, RNZ, 0 -> ;
|
2007-11-02 18:56:58 +00:00
|
|
|
|
2018-01-05 22:55:50 +00:00
|
|
|
addi RNZ, RNZ, X : addi RNZ, RNZ, Y { plus(X, Y, Z) }
|
|
|
|
-> addi RNZ, RNZ, Z ;
|
|
|
|
|
2018-02-01 17:20:31 +00:00
|
|
|
/* Lower "addi sp, sp, UP" by lifting other instructions, looking for
|
2018-01-05 22:55:50 +00:00
|
|
|
* chances to merge or delete _addi_ instructions, and assuming that
|
|
|
|
* the code generator uses "sp" not "r1".
|
|
|
|
*/
|
2018-02-01 17:20:31 +00:00
|
|
|
addi sp, sp, UP : ANY L1 { lift(ANY) }
|
|
|
|
-> ANY L1 : addi sp, sp, UP ;
|
|
|
|
addi sp, sp, UP : ANY L1, L2 { lift(ANY) }
|
|
|
|
-> ANY L1, L2 : addi sp, sp, UP ;
|
|
|
|
addi sp, sp, UP : ANY L1, L2, L3 { lift(ANY) }
|
|
|
|
-> ANY L1, L2, L3 : addi sp, sp, UP ;
|
|
|
|
addi sp, sp, UP : ANY L1, L2, L3, L4 { lift(ANY) }
|
|
|
|
-> ANY L1, L2, L3, L4 : addi sp, sp, UP ;
|
|
|
|
addi sp, sp, UP : ANY L1, L2, L3, L4, L5 { lift(ANY) }
|
|
|
|
-> ANY L1, L2, L3, L4, L5 : addi sp, sp, UP ;
|
|
|
|
addi sp, sp, UP : lmw Y, L1 { Y[0]=='r' && atoi(Y+1)>1 }
|
|
|
|
-> lmw Y, L1 : addi sp, sp, UP ;
|
2018-01-05 22:55:50 +00:00
|
|
|
|
|
|
|
/* Merge _addi_ when popping from the stack. */
|
|
|
|
addi sp, sp, X : lwz L1, Y(sp) { plus(X, Y, Z) && Z[0]!='-' }
|
|
|
|
-> lwz L1, Z(sp) : addi sp, sp, X ;
|
|
|
|
addi sp, sp, X : lfs L1, Y(sp) { plus(X, Y, Z) && Z[0]!='-' }
|
|
|
|
-> lfs L1, Z(sp) : addi sp, sp, X ;
|
|
|
|
addi sp, sp, X : lfd L1, Y(sp) { plus(X, Y, Z) && Z[0]!='-' }
|
|
|
|
-> lfd L1, Z(sp) : addi sp, sp, X ;
|
|
|
|
|
|
|
|
/* Lower or delete _addi_ when pushing to the stack. */
|
|
|
|
addi sp, sp, X : stwu L1, Y(sp) { plus(X, Y, Z) && Z[0]!='-' }
|
|
|
|
-> stw L1, Z(sp) : addi sp, sp, Z ;
|
|
|
|
addi sp, sp, X : stfsu L1, Y(sp) { plus(X, Y, Z) && Z[0]!='-' }
|
|
|
|
-> stfs L1, Z(sp) : addi sp, sp, Z ;
|
|
|
|
addi sp, sp, X : stfdu L1, Y(sp) { plus(X, Y, Z) && Z[0]!='-' }
|
|
|
|
-> stfd L1, Z(sp) : addi sp, sp, Z ;
|
|
|
|
addi sp, sp, 4 : stfdu L1, -8(sp) -> stfdu L1, -4(sp) ;
|
|
|
|
|
|
|
|
/* Delete _addi_ when setting the stack pointer. */
|
|
|
|
addi sp, sp, X : addi sp, L1, Y -> addi sp, L1, Y ;
|
|
|
|
addi sp, sp, X : lwz sp, L1 -> lwz sp, L1 ;
|
|
|
|
|
2017-12-23 03:32:16 +00:00
|
|
|
or X, Y, Y -> mr X, Y ;
|
|
|
|
or. X, Y, Y -> mr. X, Y ;
|
|
|
|
|
2016-10-29 21:37:11 +00:00
|
|
|
mr X, X -> ;
|
|
|
|
fmr X, X -> ;
|
|
|
|
|
2017-12-23 03:32:16 +00:00
|
|
|
add X, Y, Z : mr. X, X -> add. X, Y, Z ;
|
|
|
|
and X, Y, Z : mr. X, X -> and. X, Y, Z ;
|
|
|
|
andc X, Y, Z : mr. X, X -> andc. X, Y, Z ;
|
|
|
|
divw X, Y, Z : mr. X, X -> divw. X, Y, Z ;
|
|
|
|
divwu X, Y, Z : mr. X, X -> divwu. X, Y, Z ;
|
|
|
|
extsb X, Y, Z : mr. X, X -> extsb. X, Y, Z ;
|
|
|
|
extsh X, Y, Z : mr. X, X -> extsh. X, Y, Z ;
|
|
|
|
eqv X, Y, Z : mr. X, X -> eqv. X, Y, Z ;
|
|
|
|
mullw X, Y, Z : mr. X, X -> mullw. X, Y, Z ;
|
|
|
|
nand X, Y, Z : mr. X, X -> nand. X, Y, Z ;
|
|
|
|
nor X, Y, Z : mr. X, X -> nor. X, Y, Z ;
|
|
|
|
or X, Y, Z : mr. X, X -> or. X, Y, Z ;
|
|
|
|
orc X, Y, Z : mr. X, X -> orc. X, Y, Z ;
|
|
|
|
slw X, Y, Z : mr. X, X -> slw. X, Y, Z ;
|
|
|
|
slwi X, Y, Z : mr. X, X -> slwi. X, Y, Z ;
|
|
|
|
subf X, Y, Z : mr. X, X -> subf. X, Y, Z ;
|
|
|
|
sraw X, Y, Z : mr. X, X -> sraw. X, Y, Z ;
|
|
|
|
srawi X, Y, Z : mr. X, X -> srawi. X, Y, Z ;
|
|
|
|
srw X, Y, Z : mr. X, X -> srw. X, Y, Z ;
|
|
|
|
srwi X, Y, Z : mr. X, X -> srwi. X, Y, Z ;
|
|
|
|
xor X, Y, Z : mr. X, X -> xor. X, Y, Z ;
|
2007-11-02 18:56:58 +00:00
|
|
|
|
2016-10-29 21:37:11 +00:00
|
|
|
b X : labdef X -> labdef X ;
|
|
|
|
|
|
|
|
/* IFFALSE=4, IFTRUE=12, ALWAYS=20 */
|
|
|
|
/* LT=0, GT=1, EQ=2, OV=3 */
|
|
|
|
|
2007-11-02 18:56:58 +00:00
|
|
|
%%;
|
2018-01-05 22:55:50 +00:00
|
|
|
|
|
|
|
/* Is it a word character? 0-9A-Za-z_ */
|
|
|
|
static int isword(char c) {
|
|
|
|
return
|
|
|
|
(c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
|
|
|
|
(c >= 'a' && c <= 'z') || (c == '_');
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Does operand _s_ not use the stack pointer? */
|
|
|
|
int not_using_sp(const char *s) {
|
|
|
|
int boundary;
|
|
|
|
|
|
|
|
boundary = 1;
|
|
|
|
while (*s) {
|
|
|
|
if (boundary &&
|
|
|
|
((s[0]=='s' && s[1]=='p') || (s[0]=='r' && s[1]=='1')) &&
|
|
|
|
!isword(s[2]))
|
|
|
|
return 0;
|
|
|
|
boundary = !isword(*s);
|
|
|
|
s++;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-01 17:20:31 +00:00
|
|
|
int positive(const char *s) {
|
|
|
|
long n;
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
n = strtol(s, &end, 10);
|
|
|
|
return *s != '\0' && *end == '\0' && n > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-01-05 22:55:50 +00:00
|
|
|
/* Instructions to lift(), sorted in strcmp() order. These are from
|
|
|
|
* ../ncg/table, minus branch instructions.
|
|
|
|
*/
|
|
|
|
const char *liftables[] = {
|
|
|
|
"add", "add.", "addi",
|
|
|
|
"and", "andc", "andi.", "andis.",
|
|
|
|
"cmp", "cmpi", "cmpl", "cmpli",
|
|
|
|
"cmplw", "cmplwi", "cmpw", "cmpwi",
|
|
|
|
"divw", "divwu", "eqv", "extlwi", "extrwi", "extsb", "extsh",
|
|
|
|
"fadd", "fadds", "fcmpo", "fctiwz", "fdiv", "fdivs",
|
|
|
|
"fmr", "fmul", "fmuls", "fneg", "frsp", "fsub", "fsubs",
|
|
|
|
"lbz", "lbzx",
|
|
|
|
"lfd", "lfdu", "lfdx", "lfs", "lfsu", "lfsx",
|
|
|
|
"lha", "lhax", "lhz", "lhzx",
|
|
|
|
"li", "lis", "lwz", "lwzu", "lwzx",
|
|
|
|
"mfcr", "mfspr", "mr", "mr.", "mtspr", "mullw",
|
|
|
|
"nand", "neg", "nor", "or", "or.", "ori", "oris",
|
|
|
|
"rlwinm", "rlwnm", "rotlwi", "rotrwi",
|
|
|
|
"slw", "slwi", "sraw", "srawi", "srw", "srwi",
|
|
|
|
"stb", "stbx",
|
|
|
|
"stfd", "stfdu", "stfdx", "stfs", "stfsu", "stfsx",
|
|
|
|
"sth", "sthx", "stw", "stwx", "stwu",
|
|
|
|
"subf", "xor", "xori", "xoris",
|
|
|
|
};
|
|
|
|
|
|
|
|
static int liftcmp(const void *a, const void *b) {
|
|
|
|
return strcmp(*(const char **)a, *(const char **)b);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* May we lift instruction _s_ above "addi SP, SP, X"? */
|
|
|
|
int lift(const char *s) {
|
|
|
|
return bsearch(&s, liftables,
|
|
|
|
sizeof(liftables) / sizeof(liftables[0]),
|
2019-10-24 18:08:52 +00:00
|
|
|
sizeof(liftables[0]), liftcmp) != NULL;
|
2018-01-05 22:55:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Does it fit a signed 16-bit integer? */
|
|
|
|
static int fits16(long l) {
|
|
|
|
return l >= -32768 && l <= 32767;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Tries sum = a + b with signed 16-bit integers. */
|
2019-10-25 19:52:09 +00:00
|
|
|
int plus(const char *a, const char *b, char *sum)
|
2018-01-05 22:55:50 +00:00
|
|
|
{
|
|
|
|
long la, lb, lsum;
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
la = strtol(a, &end, 10);
|
|
|
|
if (*a == '\0' || *end != '\0' || !fits16(la))
|
|
|
|
return 0;
|
|
|
|
lb = strtol(b, &end, 10);
|
|
|
|
if (*b == '\0' || *end != '\0' || !fits16(lb))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
lsum = la + lb;
|
|
|
|
if (!fits16(lsum))
|
|
|
|
return 0;
|
|
|
|
snprintf(sum, 7, "%ld", lsum);
|
|
|
|
return 1;
|
|
|
|
}
|