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:
parent
fd83b09c58
commit
8edbff9795
|
@ -84,6 +84,9 @@
|
|||
%token <y_word> OP_LA
|
||||
%token <y_word> OP_LI32
|
||||
|
||||
%token <y_word> OP_POWERPC_FIXUP
|
||||
%token <y_word> OP_HI OP_LO
|
||||
|
||||
/* Other token types */
|
||||
|
||||
%type <y_word> c
|
||||
|
|
|
@ -102,6 +102,9 @@
|
|||
0, OP_LA, 0, "la",
|
||||
0, OP_LA, 0, "li",
|
||||
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) */
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ operation
|
|||
| OP_LIA lia { emit4($1 | $2); }
|
||||
| OP_LIL lil { emit4($1 | $2); }
|
||||
| OP_LI32 li32 /* emitted in subrule */
|
||||
| OP_POWERPC_FIXUP powerpcfixup /* emitted in subrule */
|
||||
;
|
||||
|
||||
c
|
||||
|
@ -75,6 +76,32 @@ e16
|
|||
serror("16-bit value out of range");
|
||||
$$ = (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
|
||||
|
@ -248,3 +275,14 @@ spr_num
|
|||
$$ = ($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);
|
||||
}
|
||||
;
|
||||
|
|
|
@ -2,4 +2,3 @@
|
|||
* $Source$
|
||||
* $State$
|
||||
*/
|
||||
|
||||
|
|
|
@ -169,11 +169,14 @@ TOKENS
|
|||
/* Used only in instruction descriptions (to generate the correct syntax). */
|
||||
|
||||
GPRINDIRECT = { GPR reg; INT off; } 4 off "(" reg ")".
|
||||
GPRINDIRECT_OFFSET_LO = { GPR reg; ADDR adr; } 4 "lo [" adr "](" reg ")".
|
||||
CONST = { INT val; } 4 val.
|
||||
|
||||
/* Primitives */
|
||||
|
||||
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.
|
||||
|
||||
/* Allows us to use regvar() to refer to registers */
|
||||
|
@ -282,7 +285,7 @@ INSTRUCTIONS
|
|||
add GPR:wo, GPR:ro, GPR:ro.
|
||||
addX "add." GPR:wo, GPR:ro, GPR: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.
|
||||
andc GPR:wo, GPR:ro, GPR:ro.
|
||||
andiX "andi." GPR:wo:cc, GPR:ro, CONST:ro.
|
||||
|
@ -329,10 +332,9 @@ INSTRUCTIONS
|
|||
lhz GPR:wo, GPRINDIRECT: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, LABEL:ro cost(8, 2).
|
||||
lwzu GPR:wo, GPRINDIRECT: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.
|
||||
neg GPR:wo, GPR:ro.
|
||||
nor GPR:wo, GPR:ro, GPR:ro.
|
||||
|
@ -342,7 +344,7 @@ INSTRUCTIONS
|
|||
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:ro.
|
||||
ori GPR:wo, GPR:ro, CONST+LABEL_OFFSET_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.
|
||||
|
@ -368,6 +370,7 @@ INSTRUCTIONS
|
|||
xori GPR:wo, GPR:ro, CONST:ro.
|
||||
xoris GPR:wo, GPR:ro, CONST:ro.
|
||||
|
||||
fixup ".powerpcfixup" LABEL:ro.
|
||||
comment "!" LABEL:ro cost(0, 0).
|
||||
|
||||
|
||||
|
@ -405,7 +408,9 @@ MOVES
|
|||
from LABEL to GPR
|
||||
gen
|
||||
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 */
|
||||
|
||||
|
@ -1142,6 +1147,13 @@ PATTERNS
|
|||
yields {IND_RC_H, %1.reg, %1.off}
|
||||
|
||||
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
|
||||
yields {IND_RC_W, %1, 0}
|
||||
with SUM_RC
|
||||
|
|
|
@ -119,14 +119,13 @@ static uint32_t get_powerpc_valu(char* addr, uint16_t type)
|
|||
/* branch instruction */
|
||||
return opcode1 & 0x03fffffd;
|
||||
}
|
||||
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) &&
|
||||
((opcode2 & 0xfc000000) == 0x60000000))
|
||||
else
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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;
|
||||
write4(i, addr, type);
|
||||
}
|
||||
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) &&
|
||||
((opcode2 & 0xfc000000) == 0x60000000))
|
||||
else
|
||||
{
|
||||
/* 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 lo = value & 0xffff;
|
||||
|
||||
write4((opcode1 & 0xffff0000) | hi, addr+0, type);
|
||||
write4((opcode2 & 0xffff0000) | lo, addr+4, type);
|
||||
}
|
||||
else
|
||||
assert(0 && "unrecognised PowerPC instruction");
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue