Add assembler support for fixing up arbitrary oris/addi pairs of instructions;

this should allow oris/lwz constant value loads, which will save an opcode.
This commit is contained in:
David Given 2017-01-15 00:15:01 +01:00
parent fd83b09c58
commit 8edbff9795
6 changed files with 97 additions and 43 deletions

View file

@ -84,6 +84,9 @@
%token <y_word> OP_LA %token <y_word> OP_LA
%token <y_word> OP_LI32 %token <y_word> OP_LI32
%token <y_word> OP_POWERPC_FIXUP
%token <y_word> OP_HI OP_LO
/* Other token types */ /* Other token types */
%type <y_word> c %type <y_word> c

View file

@ -102,6 +102,9 @@
0, OP_LA, 0, "la", 0, OP_LA, 0, "la",
0, OP_LA, 0, "li", 0, OP_LA, 0, "li",
0, OP_RS_RA_RA_C, 31<<26 | 444<<1, "mr", 0, OP_RS_RA_RA_C, 31<<26 | 444<<1, "mr",
0, OP_POWERPC_FIXUP, 0, ".powerpcfixup",
0, OP_HI, 0, "hi",
0, OP_LO, 0, "lo",
/* Branch processor instructions (page 20) */ /* Branch processor instructions (page 20) */
@ -270,7 +273,7 @@
0, OP_RS_RA_SH_ME6_SH_C, 30<<26 | 1<<2, "rldicr", 0, OP_RS_RA_SH_ME6_SH_C, 30<<26 | 1<<2, "rldicr",
0, OP_RS_RA_SH_MB6_SH_C, 30<<26 | 2<<2, "rldic", 0, OP_RS_RA_SH_MB6_SH_C, 30<<26 | 2<<2, "rldic",
0, OP_RS_RA_SH_MB5_ME5_C, 21<<26, "rlwinm", 0, OP_RS_RA_SH_MB5_ME5_C, 21<<26, "rlwinm",
0, OP_RS_RA_RB_MB6_C, 30<<26 | 8<<1, "rldcl", 0, OP_RS_RA_RB_MB6_C, 30<<26 | 8<<1, "rldcl",
0, OP_RS_RA_RB_ME6_C, 30<<26 | 9<<1, "rldcr", 0, OP_RS_RA_RB_ME6_C, 30<<26 | 9<<1, "rldcr",
0, OP_RS_RA_RB_MB5_ME5_C, 23<<26, "rlwnm", 0, OP_RS_RA_RB_MB5_ME5_C, 23<<26, "rlwnm",
0, OP_RS_RA_SH_MB6_SH_C, 30<<26 | 3<<2, "rldimi", 0, OP_RS_RA_SH_MB6_SH_C, 30<<26 | 3<<2, "rldimi",

View file

@ -19,9 +19,9 @@ operation
| OP_FRS_RA_D FPR ',' e16 '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); } | OP_FRS_RA_D FPR ',' e16 '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); }
| OP_FRS_RA_RB FPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); } | OP_FRS_RA_RB FPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_FRT_FRA_FRB_C c FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<11)); } | OP_FRT_FRA_FRB_C c FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<11)); }
| OP_FRT_FRA_FRC_FRB_C c FPR ',' FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($9<<11) | ($7<<6)); } | OP_FRT_FRA_FRC_FRB_C c FPR ',' FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($9<<11) | ($7<<6)); }
| OP_FRT_FRA_FRC_C c FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<6)); } | OP_FRT_FRA_FRC_C c FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<6)); }
| OP_FRT_FRB_C c FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<11)); } | OP_FRT_FRB_C c FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<11)); }
| OP_FRT_RA_D FPR ',' e16 '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); } | OP_FRT_RA_D FPR ',' e16 '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); }
| OP_FRT_RA_RB FPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); } | OP_FRT_RA_RB FPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_FRT_C c FPR { emit4($1 | $2 | ($3<<21)); } | OP_FRT_C c FPR { emit4($1 | $2 | ($3<<21)); }
@ -40,15 +40,15 @@ operation
| OP_RS_RA_D GPR ',' e16 '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); } | OP_RS_RA_D GPR ',' e16 '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); }
| OP_RS_RA_DS GPR ',' ds '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); } | OP_RS_RA_DS GPR ',' ds '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); }
| OP_RS_RA_NB GPR ',' GPR ',' nb { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); } | OP_RS_RA_NB GPR ',' GPR ',' nb { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_RS_RA_UI GPR ',' GPR ',' e16 { emit4($1 | ($4<<21) | ($2<<16) | $6); } | OP_RS_RA_UI GPR ',' GPR ',' e16 { emit4($1 | ($4<<21) | ($2<<16) | $6); }
| OP_RS_RA_UI_CC C GPR ',' GPR ',' e16 { emit4($1 | ($5<<21) | ($3<<16) | $7); } | OP_RS_RA_UI_CC C GPR ',' GPR ',' e16 { emit4($1 | ($5<<21) | ($3<<16) | $7); }
| OP_RS_RA_RB GPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); } | OP_RS_RA_RB GPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_RS_RA_RB_C c GPR ',' GPR ',' GPR { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); } | OP_RS_RA_RB_C c GPR ',' GPR ',' GPR { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); }
| OP_RS_RA_RA_C c GPR ',' GPR { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($5<<11)); } | OP_RS_RA_RA_C c GPR ',' GPR { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($5<<11)); }
| OP_RS_RA_RB_MB5_ME5_C c GPR ',' GPR ',' GPR ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); } | OP_RS_RA_RB_MB5_ME5_C c GPR ',' GPR ',' GPR ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); }
| OP_RS_RA_RB_MB6_C c GPR ',' GPR ',' GPR ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | (($9&0x1F)<<6) | (($9&0x20)>>0)); } | OP_RS_RA_RB_MB6_C c GPR ',' GPR ',' GPR ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | (($9&0x1F)<<6) | (($9&0x20)>>0)); }
| OP_RS_RA_RB_ME6_C c GPR ',' GPR ',' GPR ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | (($9&0x1F)<<6) | (($9&0x20)>>0)); } | OP_RS_RA_RB_ME6_C c GPR ',' GPR ',' GPR ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | (($9&0x1F)<<6) | (($9&0x20)>>0)); }
| OP_RS_RA_SH_MB5_ME5_C c GPR ',' GPR ',' u5 ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); } | OP_RS_RA_SH_MB5_ME5_C c GPR ',' GPR ',' u5 ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); }
| OP_RS_RA_SH_MB6_SH_C c GPR ',' GPR ',' u6 ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | (($7&0x1F)<<11) | ($9<<6) | (($7&0x20)>>4)); } | OP_RS_RA_SH_MB6_SH_C c GPR ',' GPR ',' u6 ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | (($7&0x1F)<<11) | ($9<<6) | (($7&0x20)>>4)); }
| OP_RS_RA_SH_ME6_SH_C c GPR ',' GPR ',' u6 ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | (($7&0x1F)<<11) | ($9<<6) | (($7&0x20)>>4)); } | OP_RS_RA_SH_ME6_SH_C c GPR ',' GPR ',' u6 ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | (($7&0x1F)<<11) | ($9<<6) | (($7&0x20)>>4)); }
| OP_RS_RA_SH5_C c GPR ',' GPR ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); } | OP_RS_RA_SH5_C c GPR ',' GPR ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); }
@ -60,13 +60,14 @@ operation
| OP_LIA lia { emit4($1 | $2); } | OP_LIA lia { emit4($1 | $2); }
| OP_LIL lil { emit4($1 | $2); } | OP_LIL lil { emit4($1 | $2); }
| OP_LI32 li32 /* emitted in subrule */ | OP_LI32 li32 /* emitted in subrule */
| OP_POWERPC_FIXUP powerpcfixup /* emitted in subrule */
; ;
c c
: /* nothing */ { $$ = 0; } : /* nothing */ { $$ = 0; }
| C { $$ = 1; } | C { $$ = 1; }
; ;
e16 e16
: absexp : absexp
{ {
@ -75,8 +76,34 @@ e16
serror("16-bit value out of range"); serror("16-bit value out of range");
$$ = (uint16_t) $1; $$ = (uint16_t) $1;
} }
| OP_HI expr
{
/* If this is a symbol reference, discard the symbol and keep only the
* offset part. */
quad type = $2.typ & S_TYP;
quad val = $2.val;
/* If the assembler stored a symbol for relocation later, we need to
* abandon it (because we're not going to generate a relocation). */
if (type != S_ABS)
relonami = 0;
$$ = ((quad)val) >> 16;
}
| OP_LO expr
{
quad type = $2.typ & S_TYP;
quad val = $2.val;
/* If the assembler stored a symbol for relocation later, we need to
* abandon it (because we're not going to generate a relocation). */
if (type != S_ABS)
relonami = 0;
$$ = val & 0xffff;
}
; ;
u8 u8
: absexp : absexp
{ {
@ -85,7 +112,7 @@ u8
$$ = $1; $$ = $1;
} }
; ;
u7 u7
: absexp : absexp
{ {
@ -94,7 +121,7 @@ u7
$$ = $1; $$ = $1;
} }
; ;
u6 u6
: absexp : absexp
{ {
@ -103,7 +130,7 @@ u6
$$ = $1; $$ = $1;
} }
; ;
u5 u5
: absexp : absexp
{ {
@ -112,7 +139,7 @@ u5
$$ = $1; $$ = $1;
} }
; ;
u4 u4
: absexp : absexp
{ {
@ -121,7 +148,7 @@ u4
$$ = $1; $$ = $1;
} }
; ;
u1 u1
: absexp : absexp
{ {
@ -130,7 +157,7 @@ u1
$$ = $1; $$ = $1;
} }
; ;
u2 u2
: absexp : absexp
{ {
@ -139,7 +166,7 @@ u2
$$ = $1; $$ = $1;
} }
; ;
ds ds
: e16 : e16
{ {
@ -148,26 +175,26 @@ ds
$$ = $1; $$ = $1;
} }
; ;
nb nb
: absexp : absexp
{ {
if (($1 < 1) || ($1 > 32)) if (($1 < 1) || ($1 > 32))
serror("register count must be in the range 1..32"); serror("register count must be in the range 1..32");
if ($1 == 32) if ($1 == 32)
$$ = 0; $$ = 0;
else else
$$ = $1; $$ = $1;
} }
; ;
bdl bdl
: expr : expr
{ {
int dist = $1.val - DOTVAL; int dist = $1.val - DOTVAL;
fit(fitx(dist, 25)); fit(fitx(dist, 25));
if (dist & 0x3) if (dist & 0x3)
serror("jump targets must be 4-aligned"); serror("jump targets must be 4-aligned");
@ -183,7 +210,7 @@ bda
{ {
int target = $1.val; int target = $1.val;
fit(fitx(target, 16)); fit(fitx(target, 16));
if (target & 0x3) if (target & 0x3)
serror("jump targets must be 4-aligned"); serror("jump targets must be 4-aligned");
@ -193,7 +220,7 @@ bda
$$ = target & 0xFFFD; $$ = target & 0xFFFD;
} }
; ;
li32 li32
: GPR ',' expr : GPR ',' expr
{ {
@ -215,7 +242,7 @@ lil
{ {
int dist = $1.val - DOTVAL; int dist = $1.val - DOTVAL;
fit(fitx(dist, 26)); fit(fitx(dist, 26));
if (dist & 0x3) if (dist & 0x3)
serror("jump targets must be 4-aligned"); serror("jump targets must be 4-aligned");
@ -223,13 +250,13 @@ lil
$$ = dist & 0x03FFFFFD; $$ = dist & 0x03FFFFFD;
} }
; ;
lia lia
: expr : expr
{ {
int target = $1.val; int target = $1.val;
fit(fitx(target, 26)); fit(fitx(target, 26));
if (target & 0x3) if (target & 0x3)
serror("jump targets must be 4-aligned"); serror("jump targets must be 4-aligned");
@ -248,3 +275,14 @@ spr_num
$$ = ($1 >> 5) | (($1 & 0x1f) << 5); $$ = ($1 >> 5) | (($1 & 0x1f) << 5);
} }
; ;
powerpcfixup
: expr
{
quad type = $1.typ & S_TYP;
quad val = $1.val;
if (type == S_ABS)
serror(".powerpcfixup is useless on absolute values");
newrelo($1.typ, RELOPPC | FIXUPFLAGS);
}
;

View file

@ -2,4 +2,3 @@
* $Source$ * $Source$
* $State$ * $State$
*/ */

View file

@ -169,11 +169,14 @@ TOKENS
/* Used only in instruction descriptions (to generate the correct syntax). */ /* Used only in instruction descriptions (to generate the correct syntax). */
GPRINDIRECT = { GPR reg; INT off; } 4 off "(" reg ")". GPRINDIRECT = { GPR reg; INT off; } 4 off "(" reg ")".
GPRINDIRECT_OFFSET_LO = { GPR reg; ADDR adr; } 4 "lo [" adr "](" reg ")".
CONST = { INT val; } 4 val. CONST = { INT val; } 4 val.
/* Primitives */ /* Primitives */
LABEL = { ADDR adr; } 4 adr. LABEL = { ADDR adr; } 4 adr.
LABEL_OFFSET_HI = { ADDR adr; } 4 "hi " adr.
LABEL_OFFSET_LO = { ADDR adr; } 4 "lo " adr.
LOCAL = { INT off; } 4. LOCAL = { INT off; } 4.
/* Allows us to use regvar() to refer to registers */ /* Allows us to use regvar() to refer to registers */
@ -282,7 +285,7 @@ INSTRUCTIONS
add GPR:wo, GPR:ro, GPR:ro. add GPR:wo, GPR:ro, GPR:ro.
addX "add." GPR:wo, GPR:ro, GPR:ro. addX "add." GPR:wo, GPR:ro, GPR:ro.
addi GPR:wo, GPR:ro, CONST:ro. addi GPR:wo, GPR:ro, CONST:ro.
addis GPR:wo, GPR:ro, CONST:ro. addis GPR:wo, GPR:ro, CONST+LABEL_OFFSET_HI:ro.
and GPR:wo, GPR:ro, GPR:ro. and GPR:wo, GPR:ro, GPR:ro.
andc GPR:wo, GPR:ro, GPR:ro. andc GPR:wo, GPR:ro, GPR:ro.
andiX "andi." GPR:wo:cc, GPR:ro, CONST:ro. andiX "andi." GPR:wo:cc, GPR:ro, CONST:ro.
@ -329,10 +332,9 @@ INSTRUCTIONS
lhz GPR:wo, GPRINDIRECT:ro cost(4, 3). lhz GPR:wo, GPRINDIRECT:ro cost(4, 3).
lhzx GPR:wo, GPR:ro, GPR:ro cost(4, 3). lhzx GPR:wo, GPR:ro, GPR:ro cost(4, 3).
li32 GPR:wo, CONST:ro cost(8, 2). li32 GPR:wo, CONST:ro cost(8, 2).
li32 GPR:wo, LABEL:ro cost(8, 2).
lwzu GPR:wo, GPRINDIRECT:ro cost(4, 3). lwzu GPR:wo, GPRINDIRECT:ro cost(4, 3).
lwzx GPR:wo, GPR:ro, GPR:ro cost(4, 3). lwzx GPR:wo, GPR:ro, GPR:ro cost(4, 3).
lwz GPR:wo, GPRINDIRECT:ro cost(4, 3). lwz GPR:wo, GPRINDIRECT+GPRINDIRECT_OFFSET_LO:ro cost(4, 3).
nand GPR:wo, GPR:ro, GPR:ro. nand GPR:wo, GPR:ro, GPR:ro.
neg GPR:wo, GPR:ro. neg GPR:wo, GPR:ro.
nor GPR:wo, GPR:ro, GPR:ro. nor GPR:wo, GPR:ro, GPR:ro.
@ -342,7 +344,7 @@ INSTRUCTIONS
mtspr SPR:wo, GPR:ro cost(4, 2). mtspr SPR:wo, GPR:ro cost(4, 2).
or GPR:wo, GPR:ro, GPR:ro. or GPR:wo, GPR:ro, GPR:ro.
orc GPR:wo, GPR:ro, GPR:ro. orc GPR:wo, GPR:ro, GPR:ro.
ori GPR:wo, GPR:ro, CONST:ro. ori GPR:wo, GPR:ro, CONST+LABEL_OFFSET_LO:ro.
oris GPR:wo, GPR:ro, CONST:ro. oris GPR:wo, GPR:ro, CONST:ro.
orX "or." GPR:wo:cc, GPR:ro, GPR:ro. orX "or." GPR:wo:cc, GPR:ro, GPR:ro.
rlwinm GPR:wo, GPR:ro, CONST:ro, CONST:ro, CONST:ro. rlwinm GPR:wo, GPR:ro, CONST:ro, CONST:ro, CONST:ro.
@ -368,7 +370,8 @@ INSTRUCTIONS
xori GPR:wo, GPR:ro, CONST:ro. xori GPR:wo, GPR:ro, CONST:ro.
xoris GPR:wo, GPR:ro, CONST:ro. xoris GPR:wo, GPR:ro, CONST:ro.
comment "!" LABEL:ro cost(0, 0). fixup ".powerpcfixup" LABEL:ro.
comment "!" LABEL:ro cost(0, 0).
@ -405,7 +408,9 @@ MOVES
from LABEL to GPR from LABEL to GPR
gen gen
COMMENT("move LABEL->GPR") COMMENT("move LABEL->GPR")
li32 %2, {LABEL, %1.adr} fixup {LABEL, %1.adr}
addis %2, R0, {LABEL_OFFSET_HI, %1.adr}
ori %2, %2, {LABEL_OFFSET_LO, %1.adr}
/* Sign extension */ /* Sign extension */
@ -1142,6 +1147,13 @@ PATTERNS
yields {IND_RC_H, %1.reg, %1.off} yields {IND_RC_H, %1.reg, %1.off}
pat loi $1==INT32 /* Load word indirect */ pat loi $1==INT32 /* Load word indirect */
with LABEL
uses REG
gen
fixup {LABEL, %1.adr}
addis %a, R0, {LABEL_OFFSET_HI, %1.adr}
lwz %a, {GPRINDIRECT_OFFSET_LO, %a, %1.adr}
yields %a
with GPR with GPR
yields {IND_RC_W, %1, 0} yields {IND_RC_W, %1, 0}
with SUM_RC with SUM_RC

View file

@ -119,14 +119,13 @@ static uint32_t get_powerpc_valu(char* addr, uint16_t type)
/* branch instruction */ /* branch instruction */
return opcode1 & 0x03fffffd; return opcode1 & 0x03fffffd;
} }
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) && else
((opcode2 & 0xfc000000) == 0x60000000))
{ {
/* addis / ori instruction pair */ /* If it's not a branch, we're just going to assume that the user
* knows what they're doing and this is a addis/ori pair (or
* compatible). */
return ((opcode1 & 0xffff) << 16) | (opcode2 & 0xffff); return ((opcode1 & 0xffff) << 16) | (opcode2 & 0xffff);
} }
assert(0 && "unrecognised PowerPC instruction");
} }
/* /*
@ -260,17 +259,17 @@ static void put_powerpc_valu(char* addr, uint32_t value, uint16_t type)
i |= value & 0x03fffffd; i |= value & 0x03fffffd;
write4(i, addr, type); write4(i, addr, type);
} }
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) && else
((opcode2 & 0xfc000000) == 0x60000000))
{ {
/* If it's not a branch, we're just going to assume that the user
* knows what they're doing and this is a addis/ori pair (or
* compatible). */
uint16_t hi = value >> 16; uint16_t hi = value >> 16;
uint16_t lo = value & 0xffff; uint16_t lo = value & 0xffff;
write4((opcode1 & 0xffff0000) | hi, addr+0, type); write4((opcode1 & 0xffff0000) | hi, addr+0, type);
write4((opcode2 & 0xffff0000) | lo, addr+4, type); write4((opcode2 & 0xffff0000) | lo, addr+4, type);
} }
else
assert(0 && "unrecognised PowerPC instruction");
} }
/* /*
@ -339,7 +338,7 @@ addrelo(relo, names, valu_out)
extern int hash(); extern int hash();
extern struct outname *searchname(); extern struct outname *searchname();
extern unsigned indexof(); extern unsigned indexof();
extern struct outhead outhead; extern struct outhead outhead;
name = searchname(local->on_mptr, hash(local->on_mptr)); name = searchname(local->on_mptr, hash(local->on_mptr));
if (name == (struct outname *)0) if (name == (struct outname *)0)