ack/mach/powerpc/as/mach4.c
George Koehler 1bf58cf51c Add RELOLIS for PowerPC lis with ha16 or hi16.
The new relocation type RELOLIS handles these instructions:

    lis RT, ha16[expr] == addis RT, r0, ha16[expr]
    lis RT, hi16[expr] == addis RT, r0, hi16[expr]

RELOLIS stores a 32-bit value in the program text.  In this value, the
high bit is a ha16 flag, the next 5 bits are the target register RT,
and the low bits are a signed 26-bit offset.  The linker replaces this
value with the lis instruction.

The old RELOPPC relocated a ha16/lo16 or hi16/lo16 pair.  The new
RELOLIS relocates only a ha16 or hi16, so it is no longer necessary to
have a matching lo16 in the next instruction.  The disadvantage is
that RELOLIS has only a signed 26-bit offset, not a 32-bit offset.

Switch the assembler to use RELOLIS for ha16 or hi16 and RELO2 for
lo16.  The li32 instruction still uses the old RELOPPC relocation.

This is not the same as my RELOPPC change from my recent mail to
tack-devel (https://sourceforge.net/p/tack/mailman/message/35651528/).
This commit is on a different branch.  Here I am throwing away my
RELOPPC change and instead trying RELOLIS.
2017-02-08 11:46:31 -05:00

422 lines
14 KiB
C

/*
* $Source$
* $State$
*/
operation
: OP { emit4($1); }
| OP_BDA bda { emit4($1 | $2); }
| OP_BDL bdl { emit4($1 | $2); }
| OP_BF_BFA CR ',' CR { emit4($1 | ($2<<23) | ($4<<18)); }
| OP_BF_FRA_FRB CR ',' FPR ',' FPR { emit4($1 | ($2<<23) | ($4<<16) | ($6<<11)); }
| OP_BF_L_RA_RB CR ',' u1 ',' GPR ',' GPR { emit4($1 | ($2<<23) | ($4<<21) | ($6<<16) | ($8<<11)); }
| OP_BF_L_RA_SI CR ',' u1 ',' GPR ',' e16 { emit_hl($1 | ($2<<23) | ($4<<21) | ($6<<16) | $8); }
| OP_BF_L_RA_UI CR ',' u1 ',' GPR ',' e16 { emit_hl($1 | ($2<<23) | ($4<<21) | ($6<<16) | $8); }
| OP_BF_RA_RB cr_opt GPR ',' GPR { emit4($1 | ($2<<23) | ($3<<16) | ($5<<11)); }
| OP_BF_RA_SI cr_opt GPR ',' e16 { emit_hl($1 | ($2<<23) | ($3<<16) | $5); }
| OP_BF_RA_UI cr_opt GPR ',' e16 { emit_hl($1 | ($2<<23) | ($3<<16) | $5); }
| OP_BF_U_C c CR ',' u4 { emit4($1 | $2 | ($3<<23) | ($5<<12)); }
| OP_BH { emit4($1); }
| OP_BH u2 { emit4($1 | ($2<<11)); }
| OP_BI_BDA u5 ',' bda { emit4($1 | ($2<<16) | $4); }
| OP_BI_BDL u5 ',' bdl { emit4($1 | ($2<<16) | $4); }
| OP_BI_BH u5 opt_bh { emit4($1 | ($2<<16) | $3); }
| OP_BICR_BDA cr_opt bda { emit4($1 | ($2<<18) | $3); }
| OP_BICR_BDL cr_opt bdl { emit4($1 | ($2<<18) | $3); }
| OP_BICR_BH { emit4($1); }
| OP_BICR_BH CR opt_bh { emit4($1 | ($2<<18) | $3); }
| OP_BO_BI_BDA u5 ',' u5 ',' bda { emit4($1 | ($2<<21) | ($4<<16) | $6); }
| OP_BO_BI_BDL u5 ',' u5 ',' bdl { emit4($1 | ($2<<21) | ($4<<16) | $6); }
| OP_BO_BI_BH u5 ',' u5 opt_bh { emit4($1 | ($2<<21) | ($4<<16) | $5); }
| OP_BT_BA_BA u5 ',' u5 { emit4($1 | ($2<<21) | ($4<<16) | ($4<<11)); }
| OP_BT_BA_BB u5 ',' u5 ',' u5 { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_BT_BT_BT u5 { emit4($1 | ($2<<21) | ($2<<16) | ($2<<11)); }
| OP_BT_C c u5 { emit4($1 | $2 | ($3<<21)); }
| OP_FLM_FRB_C c u8 ',' FPR { emit4($1 | $2 | ($3<<17) | ($5<<11)); }
| OP_FRS_RA_D FPR ',' e16 '(' GPR ')' { emit_hl($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_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_RA_D FPR ',' e16 '(' GPR ')' { emit_hl($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_RA_RS_C c GPR ',' GPR { emit4($1 | $2 | ($5<<21) | ($3<<16)); }
| OP_RA_RS_RB_C c GPR ',' GPR ',' GPR
{ emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); }
| OP_RA_RS_RB_MB5_ME5_C c GPR ',' GPR ',' GPR ',' u5 ',' u5
{ emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) |
($9<<6) | ($11<<1)); }
| OP_RA_RS_RB_MB6_C c GPR ',' GPR ',' GPR ',' u6
{ emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | MB6($9)); }
| OP_RA_RS_SH5_C c GPR ',' GPR ',' u5
{ emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); }
| OP_RA_RS_SH5_MB5_ME5_C c GPR ',' GPR ',' u5 ',' u5 ',' u5
{ emit4($1 | $2 | ($5<<21) | ($3<<16) |
($7<<11) | ($9<<6) | ($11<<1)); }
| OP_RA_RS_SH6_C c GPR ',' GPR ',' u6
{ emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6($7)); }
| OP_RA_RS_SH6_MB6_C c GPR ',' GPR ',' u6 ',' u6
{ emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6($7) | MB6($9)); }
| OP_RA_RS_UI GPR ',' GPR ',' e16 { emit_hl($1 | ($4<<21) | ($2<<16) | $6); }
| OP_RA_RS_UI_CC C GPR ',' GPR ',' e16 { emit_hl($1 | ($5<<21) | ($3<<16) | $7); }
| OP_RT GPR { emit4($1 | ($2<<21)); }
| OP_RT_RA_C c GPR ',' GPR { emit4($1 | $2 | ($3<<21) | ($5<<16)); }
| OP_RT_RA_D GPR ',' e16 '(' GPR ')' { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
| OP_RT_RA_DS GPR ',' ds '(' GPR ')' { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
| OP_RT_RA_NB GPR ',' GPR ',' nb { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_RT_RA_RB GPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_RT_RA_RB_C c GPR ',' GPR ',' GPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<11)); }
| OP_RT_RA_SI GPR ',' GPR ',' e16 { emit_hl($1 | ($2<<21) | ($4<<16) | $6); }
| OP_RT_RA_SI_addic c GPR ',' GPR ',' e16 { emit_hl($1 | ($2<<26) | ($3<<21) | ($5<<16) | $7); }
| OP_RT_RA_SI_subi GPR ',' GPR ',' negate16 { emit4($1 | ($2<<21) | ($4<<16) | $6); }
| OP_RT_RA_SI_subic c GPR ',' GPR ',' negate16 { emit4($1 | ($2<<26) | ($3<<21) | ($5<<16) | $7); }
| OP_RT_RB_RA_C c GPR ',' GPR ',' GPR { emit4($1 | $2 | ($3<<21) | ($7<<16) | ($5<<11)); }
| OP_RT_SI GPR ',' e16 { emit_hl($1 | ($2<<21) | $4); }
| OP_RT_SPR GPR ',' spr_num { emit4($1 | ($2<<21) | ($4<<11)); }
| OP_RS_FXM u7 ',' GPR { emit4($1 | ($4<<21) | ($2<<12)); }
| OP_RS_RA_D GPR ',' e16 '(' GPR ')' { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
| OP_RS_RA_DS GPR ',' ds '(' GPR ')' { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
| OP_RS_RA_NB GPR ',' GPR ',' nb { 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_RA_C c GPR ',' GPR { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($5<<11)); }
| OP_RS_SPR spr_num ',' GPR { emit4($1 | ($4<<21) | ($2<<11)); }
| OP_TO_RA_RB u5 ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_TO_RA_SI u5 ',' GPR ',' e16 { emit_hl($1 | ($2<<21) | ($4<<16) | $6); }
| OP_TOX_RA_RB GPR ',' GPR { emit4($1 | ($2<<16) | ($4<<11)); }
| OP_TOX_RA_SI GPR ',' e16 { emit_hl($1 | ($2<<16) | $4); }
| OP_LEV { emit4($1); }
| OP_LEV u7 { emit4($1 | ($2<<5)); }
| OP_LIA lia { emit4($1 | $2); }
| OP_LIL lil { emit4($1 | $2); }
| OP_LI32 li32 /* emitted in subrule */
| OP_clrlsldi c GPR ',' GPR ',' u6 ',' u6
{
word_t mb = ($7 - $9) & 0x3f;
fit($9 <= $7);
emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6($9) | MB6(mb));
}
| OP_clrldi c GPR ',' GPR ',' u6
{
emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6(0) | MB6($7));
}
| OP_clrrdi c GPR ',' GPR ',' u6
{
word_t me = 63 - $7;
emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6(0) | MB6(me));
}
| OP_extldi c GPR ',' GPR ',' u6 ',' u6
{
word_t me = ($7 - 1) & 0x3f;
fit($7 > 0);
emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6($9) | MB6(me));
}
| OP_extrdi c GPR ',' GPR ',' u6 ',' u6
{
word_t sh = ($9 + $7) & 0x3f;
word_t mb = (64 - $7) & 0x3f;
fit($7 > 0);
emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6(sh) | MB6(mb));
}
| OP_rotrdi c GPR ',' GPR ',' u6
{
word_t sh = (64 - $7) & 0x3f;
emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6(sh) | MB6(0));
}
| OP_sldi c GPR ',' GPR ',' u6
{
word_t me = 63 - $7;
emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6($7) | MB6(me));
}
| OP_srdi c GPR ',' GPR ',' u6
{
word_t sh = (64 - $7) & 0x3f;
emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6(sh) | MB6($7));
}
| OP_clrlslwi c GPR ',' GPR ',' u5 ',' u5
{
word_t mb = ($7 - $9) & 0x1f;
word_t me = 31 - $9;
fit($9 <= $7);
emit4($1 | $2 | ($5<<21) | ($3<<16) |
($9<<11) | (mb<<6) | (me<<1));
}
| OP_clrlwi c GPR ',' GPR ',' u5
{
emit4($1 | $2 | ($5<<21) | ($3<<16) |
(0<<11) | ($7<<6) | (31<<1));
}
| OP_clrrwi c GPR ',' GPR ',' u5
{
word_t me = 31 - $7;
emit4($1 | $2 | ($5<<21) | ($3<<16) |
(0<<11) | (0<<6) | (me<<1));
}
| OP_extlwi c GPR ',' GPR ',' u5 ',' u5
{
word_t me = ($7 - 1) & 0x1f;
fit($7 > 0);
emit4($1 | $2 | ($5<<21) | ($3<<16) |
($9<<11) | (0<<6) | (me<<1));
}
| OP_extrwi c GPR ',' GPR ',' u5 ',' u5
{
word_t sh = ($9 + $7) & 0x1f;
word_t mb = (32 - $7) & 0x1f;
fit($7 > 0);
emit4($1 | $2 | ($5<<21) | ($3<<16) |
(sh<<11) | (mb<<6) | (31<<1));
}
| OP_inslwi c GPR ',' GPR ',' u5 ',' u5
{
word_t sh = (32 - $9) & 0x1f;
word_t me = ($9 + $7 - 1) & 0x1f;
fit($7 > 0);
emit4($1 | $2 | ($5<<21) | ($3<<16) |
(sh<<11) | ($9<<6) | (me<<1));
}
| OP_insrwi c GPR ',' GPR ',' u5 ',' u5
{
word_t sh = (32 - $9 - $7) & 0x1f;
word_t me = ($9 + $7 - 1) & 0x1f;
fit($7 > 0);
emit4($1 | $2 | ($5<<21) | ($3<<16) |
(sh<<11) | ($9<<6) | (me<<1));
}
| OP_rotrwi c GPR ',' GPR ',' u5
{
word_t sh = (32 - $7) & 0x1f;
emit4($1 | $2 | ($5<<21) | ($3<<16) |
(sh<<11) | (0<<6) | (31<<1));
}
| OP_slwi c GPR ',' GPR ',' u5
{
word_t me = 31 - $7;
emit4($1 | $2 | ($5<<21) | ($3<<16) |
($7<<11) | (0<<6) | (me<<1));
}
| OP_srwi c GPR ',' GPR ',' u5
{
word_t sh = (32 - $7) & 0x1f;
emit4($1 | $2 | ($5<<21) | ($3<<16) |
(sh<<11) | ($7<<6) | (31<<1));
}
;
c
: /* nothing */ { $$ = 0; }
| C { $$ = 1; }
;
e16
: absexp
{
/* Allow signed or unsigned 16-bit values. */
if (($1 < -0x8000) || ($1 > 0xffff))
serror("16-bit value out of range");
$$ = (uint16_t) $1;
no_hl();
}
| OP_HI ASC_LPAR expr ASC_RPAR { $$ = eval_hl(&$3, OP_HI); }
| OP_HA ASC_LPAR expr ASC_RPAR { $$ = eval_hl(&$3, OP_HA); }
| OP_LO ASC_LPAR expr ASC_RPAR { $$ = eval_hl(&$3, OP_LO); }
;
negate16
: absexp
{
/* To encode subi, we negate the immediate value, then
* it must fit as signed 16-bit. */
$$ = -$1;
fit(fitx($$, 16));
$$ = (uint16_t) $$;
}
;
u8
: absexp
{
if (($1 < 0) || ($1 > 0xFF))
serror("8-bit unsigned value out of range");
$$ = $1;
}
;
u7
: absexp
{
if (($1 < 0) || ($1 > 0x7F))
serror("7-bit unsigned value out of range");
$$ = $1;
}
;
u6
: absexp
{
if (($1 < 0) || ($1 > 0x3F))
serror("6-bit unsigned value out of range");
$$ = $1;
}
;
u5
: absexp
{
if (($1 < 0) || ($1 > 0x1F))
serror("5-bit unsigned value out of range");
$$ = $1;
}
;
u4
: absexp
{
if (($1 < 0) || ($1 > 0xF))
serror("4-bit unsigned value out of range");
$$ = $1;
}
;
u1
: absexp
{
if (($1 < 0) || ($1 > 1))
serror("1-bit unsigned value out of range");
$$ = $1;
}
;
u2
: absexp
{
if (($1 < 0) || ($1 > 0x3))
serror("2-bit unsigned value out of range");
$$ = $1;
}
;
/* Optional comma, branch hint. */
opt_bh
: /* nothing */ { $$ = 0; }
| ',' u2 { $$ = ($2<<11); }
/*
* Optional condition register, comma. This checks if the token is a
* CR register name. This wouldn't work if we allowed CR as a number.
*/
cr_opt
: /* nothing */ { $$ = 0; }
| CR ',' { $$ = $1; }
ds
: e16
{
if ($1 & 3)
serror("value must be 4-aligned");
$$ = $1;
}
;
nb
: absexp
{
if (($1 < 1) || ($1 > 32))
serror("register count must be in the range 1..32");
if ($1 == 32)
$$ = 0;
else
$$ = $1;
}
;
bdl
: expr
{
int dist = $1.val - DOTVAL;
fit(fitx(dist, 25));
if (dist & 0x3)
serror("jump targets must be 4-aligned");
DOTVAL += 2;
newrelo($1.typ, RELO2 | RELPC | FIXUPFLAGS);
DOTVAL -= 2;
$$ = dist & 0xFFFD;
}
;
bda
: expr
{
int target = $1.val;
fit(fitx(target, 16));
if (target & 0x3)
serror("jump targets must be 4-aligned");
DOTVAL += 2;
newrelo($1.typ, RELO2 | FIXUPFLAGS);
DOTVAL -= 2;
$$ = target & 0xFFFD;
}
;
li32
: GPR ',' expr
{
word_t type = $3.typ & S_TYP;
word_t val = $3.val;
if ((type == S_ABS) && (val <= 0xffff))
emit4((14<<26) | ($1<<21) | (0<<16) | val); /* addi */
else
{
newrelo($3.typ, RELOPPC | FIXUPFLAGS);
emit4((15<<26) | ($1<<21) | (0<<16) | (val >> 16)); /* addis */
emit4((24<<26) | ($1<<21) | ($1<<16) | (val & 0xffff)); /* ori */
}
}
;
lil
: expr
{
int dist = $1.val - DOTVAL;
fit(fitx(dist, 26));
if (dist & 0x3)
serror("jump targets must be 4-aligned");
newrelo($1.typ, RELOPPC | RELPC | FIXUPFLAGS);
$$ = dist & 0x03FFFFFD;
}
;
lia
: expr
{
int target = $1.val;
fit(fitx(target, 26));
if (target & 0x3)
serror("jump targets must be 4-aligned");
newrelo($1.typ, RELOPPC | FIXUPFLAGS);
$$ = target & 0x03FFFFFD;
}
;
spr_num
: SPR { $$ = $1; }
| absexp
{
if (($1 < 0) || ($1 > 0x3ff))
serror("spr number out of range");
/* mfspr, mtspr swap the low and high 5 bits */
$$ = ($1 >> 5) | (($1 & 0x1f) << 5);
}
;