this should allow oris/lwz constant value loads, which will save an opcode.
%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
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) */
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_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_MB5_ME5_C, 23<<26, "rlwnm",
0, OP_RS_RA_SH_MB6_SH_C, 30<<26 | 3<<2, "rldimi",
| 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_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_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_RB FPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_FRT_C c FPR { emit4($1 | $2 | ($3<<21)); }
| 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_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_CC C GPR ',' GPR ',' e16 { emit4($1 | ($5<<21) | ($3<<16) | $7); }
+ | 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_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_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_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_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_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
: /* nothing */ { $$ = 0; }
| C { $$ = 1; }
;
-
+
e16
: absexp
{
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
: absexp
{
$$ = $1;
}
;
-
+
u7
: absexp
{
$$ = $1;
}
;
-
+
u6
: absexp
{
$$ = $1;
}
;
-
+
u5
: absexp
{
$$ = $1;
}
;
-
+
u4
: absexp
{
$$ = $1;
}
;
-
+
u1
: absexp
{
$$ = $1;
}
;
-
+
u2
: absexp
{
$$ = $1;
}
;
-
+
ds
: e16
{
$$ = $1;
}
;
-
+
nb
: absexp
{
if (($1 < 1) || ($1 > 32))
serror("register count must be in the range 1..32");
-
+
if ($1 == 32)
$$ = 0;
else
- $$ = $1;
+ $$ = $1;
}
;
-
+
bdl
: expr
{
int dist = $1.val - DOTVAL;
fit(fitx(dist, 25));
-
+
if (dist & 0x3)
serror("jump targets must be 4-aligned");
{
int target = $1.val;
fit(fitx(target, 16));
-
+
if (target & 0x3)
serror("jump targets must be 4-aligned");
$$ = target & 0xFFFD;
}
;
-
+
li32
: GPR ',' expr
{
{
int dist = $1.val - DOTVAL;
fit(fitx(dist, 26));
-
+
if (dist & 0x3)
serror("jump targets must be 4-aligned");
$$ = dist & 0x03FFFFFD;
}
;
-
+
lia
: expr
{
int target = $1.val;
fit(fitx(target, 26));
-
+
if (target & 0x3)
serror("jump targets must be 4-aligned");
$$ = ($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);
+ }
+ ;
* $Source$
* $State$
*/
-
/* 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 */
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.
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.
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.
xori 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).
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 */
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
/* 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");
}
/*
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");
}
/*
extern int hash();
extern struct outname *searchname();
extern unsigned indexof();
- extern struct outhead outhead;
+ extern struct outhead outhead;
name = searchname(local->on_mptr, hash(local->on_mptr));
if (name == (struct outname *)0)