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) */

View file

@ -60,6 +60,7 @@ 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
@ -75,6 +76,32 @@ 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
@ -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,6 +370,7 @@ 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.
fixup ".powerpcfixup" LABEL:ro.
comment "!" LABEL:ro cost(0, 0). 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");
} }
/* /*