.reg improvements.

This commit is contained in:
Alan Modra
2000-09-05 03:45:18 +00:00
parent 904a31bffc
commit ecacdc7a62
3 changed files with 444 additions and 434 deletions

View File

@ -1,5 +1,29 @@
2000-09-05 Alan Modra <alan@linuxcare.com.au>
* config/tc-hppa.c (fudge_reg_expressions): New
(hppa_force_reg_syms_absolute): New.
(pa_equ): Allow reg_section expressions.
* config/tc-hppa.c (md_optimize_expr): Define.
(hppa_force_reg_syms_absolute): Prototype.
* config/tc-hppa.c (pa_11_fp_reg_struct): Delete.
(pa_parse_number): Pass in arg to select fp reg parsing.
Return 1 to indicate format checks pass. If strict, then only
accept a register or register symbol. Return value in...
(pa_number): New static for pa_parse_number.
(FP_REG_BASE): Define.
(FP_REG_RSEL): Define.
(pre_defined_registers): Apply FP_REG_BASE and FP_REG_RSEL as
appropriate. White space changes.
(need_pa11_opcode): Don't bother passing any params, get them from
globals instead.
(pa_ip): Modify all calls to pa_parse_number and need_pa11_opcode.
Remove extraneous check in case 'Q'.
(pa_equ): Modify call to pa_parse_number to do strict parsing. If
reg, set section of resulting symbol to reg_section.
(pa_parse_space_stmt): Modify call to pa_parse_number.
(pa_space): Likewise.
* config/tc-hppa.c: (md_apply_fix): Handle vtable relocs.
(hppa_force_relocation): Handle vtable relocs.
(pa_vtable_entry): New.

View File

@ -249,23 +249,7 @@ struct pa_it
| 14 or 30L | 30 or 30R |
+--------------+--------------+
| 15 or 31L | 31 or 31R |
+--------------+--------------+
The following is a version of pa_parse_number that
handles the L/R notation and returns the correct
value to put into the instruction register field.
The correct value to put into the instruction is
encoded in the structure 'pa_11_fp_reg_struct'. */
struct pa_11_fp_reg_struct
{
/* The register number. */
char number_part;
/* L/R selector. */
char l_r_select;
};
+--------------+--------------+ */
/* Additional information needed to build argument relocation stubs. */
struct call_desc
@ -526,9 +510,8 @@ static void pa_proc PARAMS ((int));
static void pa_procend PARAMS ((int));
static void pa_param PARAMS ((int));
static void pa_undefine_label PARAMS ((void));
static int need_pa11_opcode PARAMS ((struct pa_it *,
struct pa_11_fp_reg_struct *));
static int pa_parse_number PARAMS ((char **, struct pa_11_fp_reg_struct *));
static int need_pa11_opcode PARAMS ((void));
static int pa_parse_number PARAMS ((char **, int));
static label_symbol_struct *pa_get_label PARAMS ((void));
#ifdef OBJ_SOM
static int log2 PARAMS ((int));
@ -763,6 +746,15 @@ static int hppa_field_selector;
strict syntax checking should be enabled for that instruction. */
static int strict = 0;
/* pa_parse_number returns values in `pa_number'. Mostly
pa_parse_number is used to return a register number, with floating
point registers being numbered from FP_REG_BASE upwards.
The bit specified with FP_REG_RSEL is set if the floating point
register has a `r' suffix. */
#define FP_REG_BASE 64
#define FP_REG_RSEL 128
static int pa_number;
#ifdef OBJ_SOM
/* A dummy bfd symbol so that all relocations have symbols of some kind. */
static symbolS *dummy_symbol;
@ -831,102 +823,102 @@ static const struct pd_reg pre_defined_registers[] =
{"%dp", 27},
{"%eiem", 15},
{"%eirr", 23},
{"%fr0", 0},
{"%fr0l", 0},
{"%fr0r", 0},
{"%fr1", 1},
{"%fr10", 10},
{"%fr10l", 10},
{"%fr10r", 10},
{"%fr11", 11},
{"%fr11l", 11},
{"%fr11r", 11},
{"%fr12", 12},
{"%fr12l", 12},
{"%fr12r", 12},
{"%fr13", 13},
{"%fr13l", 13},
{"%fr13r", 13},
{"%fr14", 14},
{"%fr14l", 14},
{"%fr14r", 14},
{"%fr15", 15},
{"%fr15l", 15},
{"%fr15r", 15},
{"%fr16", 16},
{"%fr16l", 16},
{"%fr16r", 16},
{"%fr17", 17},
{"%fr17l", 17},
{"%fr17r", 17},
{"%fr18", 18},
{"%fr18l", 18},
{"%fr18r", 18},
{"%fr19", 19},
{"%fr19l", 19},
{"%fr19r", 19},
{"%fr1l", 1},
{"%fr1r", 1},
{"%fr2", 2},
{"%fr20", 20},
{"%fr20l", 20},
{"%fr20r", 20},
{"%fr21", 21},
{"%fr21l", 21},
{"%fr21r", 21},
{"%fr22", 22},
{"%fr22l", 22},
{"%fr22r", 22},
{"%fr23", 23},
{"%fr23l", 23},
{"%fr23r", 23},
{"%fr24", 24},
{"%fr24l", 24},
{"%fr24r", 24},
{"%fr25", 25},
{"%fr25l", 25},
{"%fr25r", 25},
{"%fr26", 26},
{"%fr26l", 26},
{"%fr26r", 26},
{"%fr27", 27},
{"%fr27l", 27},
{"%fr27r", 27},
{"%fr28", 28},
{"%fr28l", 28},
{"%fr28r", 28},
{"%fr29", 29},
{"%fr29l", 29},
{"%fr29r", 29},
{"%fr2l", 2},
{"%fr2r", 2},
{"%fr3", 3},
{"%fr30", 30},
{"%fr30l", 30},
{"%fr30r", 30},
{"%fr31", 31},
{"%fr31l", 31},
{"%fr31r", 31},
{"%fr3l", 3},
{"%fr3r", 3},
{"%fr4", 4},
{"%fr4l", 4},
{"%fr4r", 4},
{"%fr5", 5},
{"%fr5l", 5},
{"%fr5r", 5},
{"%fr6", 6},
{"%fr6l", 6},
{"%fr6r", 6},
{"%fr7", 7},
{"%fr7l", 7},
{"%fr7r", 7},
{"%fr8", 8},
{"%fr8l", 8},
{"%fr8r", 8},
{"%fr9", 9},
{"%fr9l", 9},
{"%fr9r", 9},
{"%fr0", 0 + FP_REG_BASE},
{"%fr0l", 0 + FP_REG_BASE},
{"%fr0r", 0 + FP_REG_BASE + FP_REG_RSEL},
{"%fr1", 1 + FP_REG_BASE},
{"%fr10", 10 + FP_REG_BASE},
{"%fr10l", 10 + FP_REG_BASE},
{"%fr10r", 10 + FP_REG_BASE + FP_REG_RSEL},
{"%fr11", 11 + FP_REG_BASE},
{"%fr11l", 11 + FP_REG_BASE},
{"%fr11r", 11 + FP_REG_BASE + FP_REG_RSEL},
{"%fr12", 12 + FP_REG_BASE},
{"%fr12l", 12 + FP_REG_BASE},
{"%fr12r", 12 + FP_REG_BASE + FP_REG_RSEL},
{"%fr13", 13 + FP_REG_BASE},
{"%fr13l", 13 + FP_REG_BASE},
{"%fr13r", 13 + FP_REG_BASE + FP_REG_RSEL},
{"%fr14", 14 + FP_REG_BASE},
{"%fr14l", 14 + FP_REG_BASE},
{"%fr14r", 14 + FP_REG_BASE + FP_REG_RSEL},
{"%fr15", 15 + FP_REG_BASE},
{"%fr15l", 15 + FP_REG_BASE},
{"%fr15r", 15 + FP_REG_BASE + FP_REG_RSEL},
{"%fr16", 16 + FP_REG_BASE},
{"%fr16l", 16 + FP_REG_BASE},
{"%fr16r", 16 + FP_REG_BASE + FP_REG_RSEL},
{"%fr17", 17 + FP_REG_BASE},
{"%fr17l", 17 + FP_REG_BASE},
{"%fr17r", 17 + FP_REG_BASE + FP_REG_RSEL},
{"%fr18", 18 + FP_REG_BASE},
{"%fr18l", 18 + FP_REG_BASE},
{"%fr18r", 18 + FP_REG_BASE + FP_REG_RSEL},
{"%fr19", 19 + FP_REG_BASE},
{"%fr19l", 19 + FP_REG_BASE},
{"%fr19r", 19 + FP_REG_BASE + FP_REG_RSEL},
{"%fr1l", 1 + FP_REG_BASE},
{"%fr1r", 1 + FP_REG_BASE + FP_REG_RSEL},
{"%fr2", 2 + FP_REG_BASE},
{"%fr20", 20 + FP_REG_BASE},
{"%fr20l", 20 + FP_REG_BASE},
{"%fr20r", 20 + FP_REG_BASE + FP_REG_RSEL},
{"%fr21", 21 + FP_REG_BASE},
{"%fr21l", 21 + FP_REG_BASE},
{"%fr21r", 21 + FP_REG_BASE + FP_REG_RSEL},
{"%fr22", 22 + FP_REG_BASE},
{"%fr22l", 22 + FP_REG_BASE},
{"%fr22r", 22 + FP_REG_BASE + FP_REG_RSEL},
{"%fr23", 23 + FP_REG_BASE},
{"%fr23l", 23 + FP_REG_BASE},
{"%fr23r", 23 + FP_REG_BASE + FP_REG_RSEL},
{"%fr24", 24 + FP_REG_BASE},
{"%fr24l", 24 + FP_REG_BASE},
{"%fr24r", 24 + FP_REG_BASE + FP_REG_RSEL},
{"%fr25", 25 + FP_REG_BASE},
{"%fr25l", 25 + FP_REG_BASE},
{"%fr25r", 25 + FP_REG_BASE + FP_REG_RSEL},
{"%fr26", 26 + FP_REG_BASE},
{"%fr26l", 26 + FP_REG_BASE},
{"%fr26r", 26 + FP_REG_BASE + FP_REG_RSEL},
{"%fr27", 27 + FP_REG_BASE},
{"%fr27l", 27 + FP_REG_BASE},
{"%fr27r", 27 + FP_REG_BASE + FP_REG_RSEL},
{"%fr28", 28 + FP_REG_BASE},
{"%fr28l", 28 + FP_REG_BASE},
{"%fr28r", 28 + FP_REG_BASE + FP_REG_RSEL},
{"%fr29", 29 + FP_REG_BASE},
{"%fr29l", 29 + FP_REG_BASE},
{"%fr29r", 29 + FP_REG_BASE + FP_REG_RSEL},
{"%fr2l", 2 + FP_REG_BASE},
{"%fr2r", 2 + FP_REG_BASE + FP_REG_RSEL},
{"%fr3", 3 + FP_REG_BASE},
{"%fr30", 30 + FP_REG_BASE},
{"%fr30l", 30 + FP_REG_BASE},
{"%fr30r", 30 + FP_REG_BASE + FP_REG_RSEL},
{"%fr31", 31 + FP_REG_BASE},
{"%fr31l", 31 + FP_REG_BASE},
{"%fr31r", 31 + FP_REG_BASE + FP_REG_RSEL},
{"%fr3l", 3 + FP_REG_BASE},
{"%fr3r", 3 + FP_REG_BASE + FP_REG_RSEL},
{"%fr4", 4 + FP_REG_BASE},
{"%fr4l", 4 + FP_REG_BASE},
{"%fr4r", 4 + FP_REG_BASE + FP_REG_RSEL},
{"%fr5", 5 + FP_REG_BASE},
{"%fr5l", 5 + FP_REG_BASE},
{"%fr5r", 5 + FP_REG_BASE + FP_REG_RSEL},
{"%fr6", 6 + FP_REG_BASE},
{"%fr6l", 6 + FP_REG_BASE},
{"%fr6r", 6 + FP_REG_BASE + FP_REG_RSEL},
{"%fr7", 7 + FP_REG_BASE},
{"%fr7l", 7 + FP_REG_BASE},
{"%fr7r", 7 + FP_REG_BASE + FP_REG_RSEL},
{"%fr8", 8 + FP_REG_BASE},
{"%fr8l", 8 + FP_REG_BASE},
{"%fr8r", 8 + FP_REG_BASE + FP_REG_RSEL},
{"%fr9", 9 + FP_REG_BASE},
{"%fr9l", 9 + FP_REG_BASE},
{"%fr9r", 9 + FP_REG_BASE + FP_REG_RSEL},
{"%hta", 25},
{"%iir", 19},
{"%ior", 21},
@ -1651,10 +1643,9 @@ pa_ip (str)
/* Handle a 5 bit register or control register field at 10. */
case 'b':
case '^':
/* This should be more strict. Small steps. */
if (strict && *s != '%')
if (!pa_parse_number (&s, 0))
break;
num = pa_parse_number (&s, 0);
num = pa_number;
CHECK_FIELD (num, 31, 0, 0);
INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
@ -1679,28 +1670,25 @@ pa_ip (str)
/* Handle a 5 bit register field at 15. */
case 'x':
/* This should be more strict. Small steps. */
if (strict && *s != '%')
if (!pa_parse_number (&s, 0))
break;
num = pa_parse_number (&s, 0);
num = pa_number;
CHECK_FIELD (num, 31, 0, 0);
INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
/* Handle a 5 bit register field at 31. */
case 't':
/* This should be more strict. Small steps. */
if (strict && *s != '%')
if (!pa_parse_number (&s, 0))
break;
num = pa_parse_number (&s, 0);
num = pa_number;
CHECK_FIELD (num, 31, 0, 0);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
/* Handle a 5 bit register field at 10 and 15. */
case 'a':
/* This should be more strict. Small steps. */
if (strict && *s != '%')
if (!pa_parse_number (&s, 0))
break;
num = pa_parse_number (&s, 0);
num = pa_number;
CHECK_FIELD (num, 31, 0, 0);
opcode |= num << 16;
INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
@ -1767,19 +1755,17 @@ pa_ip (str)
/* Handle a 2 bit space identifier at 17. */
case 's':
/* This should be more strict. Small steps. */
if (strict && *s != '%')
if (!pa_parse_number (&s, 0))
break;
num = pa_parse_number (&s, 0);
num = pa_number;
CHECK_FIELD (num, 3, 0, 1);
INSERT_FIELD_AND_CONTINUE (opcode, num, 14);
/* Handle a 3 bit space identifier at 18. */
case 'S':
/* This should be more strict. Small steps. */
if (strict && *s != '%')
if (!pa_parse_number (&s, 0))
break;
num = pa_parse_number (&s, 0);
num = pa_number;
CHECK_FIELD (num, 7, 0, 1);
opcode |= re_assemble_3 (num);
continue;
@ -3444,8 +3430,6 @@ pa_ip (str)
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
if (the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 31, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
@ -3669,49 +3653,43 @@ pa_ip (str)
{
/* Float target register. */
case 't':
/* This should be more strict. Small steps. */
if (strict && *s != '%')
if (!pa_parse_number (&s, 3))
break;
num = pa_parse_number (&s, 0);
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
/* Float target register with L/R selection. */
case 'T':
{
struct pa_11_fp_reg_struct result;
/* This should be more strict. Small steps. */
if (strict && *s != '%')
if (!pa_parse_number (&s, 1))
break;
pa_parse_number (&s, &result);
CHECK_FIELD (result.number_part, 31, 0, 0);
opcode |= result.number_part;
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
opcode |= num;
/* 0x30 opcodes are FP arithmetic operation opcodes
and need to be turned into 0x38 opcodes. This
is not necessary for loads/stores. */
if (need_pa11_opcode (&the_insn, &result)
if (need_pa11_opcode ()
&& ((opcode & 0xfc000000) == 0x30000000))
opcode |= 1 << 27;
INSERT_FIELD_AND_CONTINUE (opcode, result.l_r_select & 1, 6);
opcode |= (pa_number & FP_REG_RSEL ? 1 << 6 : 0);
continue;
}
/* Float operand 1. */
case 'a':
{
struct pa_11_fp_reg_struct result;
/* This should be more strict. Small steps. */
if (strict && *s != '%')
if (!pa_parse_number (&s, 1))
break;
pa_parse_number (&s, &result);
CHECK_FIELD (result.number_part, 31, 0, 0);
opcode |= result.number_part << 21;
if (need_pa11_opcode (&the_insn, &result))
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
opcode |= num << 21;
if (need_pa11_opcode ())
{
opcode |= (result.l_r_select & 1) << 7;
opcode |= (pa_number & FP_REG_RSEL ? 1 << 7 : 0);
opcode |= 1 << 27;
}
continue;
@ -3721,32 +3699,26 @@ pa_ip (str)
case 'X':
case 'A':
{
struct pa_11_fp_reg_struct result;
/* This should be more strict. Small steps. */
if (strict && *s != '%')
if (!pa_parse_number (&s, 1))
break;
pa_parse_number (&s, &result);
CHECK_FIELD (result.number_part, 31, 0, 0);
opcode |= result.number_part << 21;
opcode |= (result.l_r_select & 1) << 7;
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
opcode |= num << 21;
opcode |= (pa_number & FP_REG_RSEL ? 1 << 7 : 0);
continue;
}
/* Float operand 2. */
case 'b':
{
struct pa_11_fp_reg_struct result;
/* This should be more strict. Small steps. */
if (strict && *s != '%')
if (!pa_parse_number (&s, 1))
break;
pa_parse_number (&s, &result);
CHECK_FIELD (result.number_part, 31, 0, 0);
opcode |= (result.number_part & 0x1f) << 16;
if (need_pa11_opcode (&the_insn, &result))
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
opcode |= num << 16;
if (need_pa11_opcode ())
{
opcode |= (result.l_r_select & 1) << 12;
opcode |= (pa_number & FP_REG_RSEL ? 1 << 12 : 0);
opcode |= 1 << 27;
}
continue;
@ -3755,174 +3727,149 @@ pa_ip (str)
/* Float operand 2 with L/R selection. */
case 'B':
{
struct pa_11_fp_reg_struct result;
/* This should be more strict. Small steps. */
if (strict && *s != '%')
if (!pa_parse_number (&s, 1))
break;
pa_parse_number (&s, &result);
CHECK_FIELD (result.number_part, 31, 0, 0);
opcode |= (result.number_part & 0x1f) << 16;
opcode |= (result.l_r_select & 1) << 12;
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
opcode |= num << 16;
opcode |= (pa_number & FP_REG_RSEL ? 1 << 12 : 0);
continue;
}
/* Float operand 3 for fmpyfadd, fmpynfadd. */
case 'C':
{
struct pa_11_fp_reg_struct result;
/* This should be more strict. Small steps. */
if (strict && *s != '%')
if (!pa_parse_number (&s, 1))
break;
pa_parse_number (&s, &result);
CHECK_FIELD (result.number_part, 31, 0, 0);
opcode |= (result.number_part & 0x1c) << 11;
opcode |= (result.number_part & 0x3) << 9;
opcode |= (result.l_r_select & 1) << 8;
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
opcode |= (num & 0x1c) << 11;
opcode |= (num & 0x03) << 9;
opcode |= (pa_number & FP_REG_RSEL ? 1 << 8 : 0);
continue;
}
/* Float mult operand 1 for fmpyadd, fmpysub */
case 'i':
{
struct pa_11_fp_reg_struct result;
/* This should be more strict. Small steps. */
if (strict && *s != '%')
if (!pa_parse_number (&s, 1))
break;
pa_parse_number (&s, &result);
CHECK_FIELD (result.number_part, 31, 0, 0);
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
if (the_insn.fpof1 == SGL)
{
if (result.number_part < 16)
if (num < 16)
{
as_bad (_("Invalid register for single precision fmpyadd or fmpysub"));
break;
}
result.number_part &= 0xF;
result.number_part |= (result.l_r_select & 1) << 4;
num &= 0xF;
num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
}
INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 21);
INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
}
/* Float mult operand 2 for fmpyadd, fmpysub */
case 'j':
{
struct pa_11_fp_reg_struct result;
/* This should be more strict. Small steps. */
if (strict && *s != '%')
if (!pa_parse_number (&s, 1))
break;
pa_parse_number (&s, &result);
CHECK_FIELD (result.number_part, 31, 0, 0);
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
if (the_insn.fpof1 == SGL)
{
if (result.number_part < 16)
if (num < 16)
{
as_bad (_("Invalid register for single precision fmpyadd or fmpysub"));
break;
}
result.number_part &= 0xF;
result.number_part |= (result.l_r_select & 1) << 4;
num &= 0xF;
num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
}
INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 16);
INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
}
/* Float mult target for fmpyadd, fmpysub */
case 'k':
{
struct pa_11_fp_reg_struct result;
/* This should be more strict. Small steps. */
if (strict && *s != '%')
if (!pa_parse_number (&s, 1))
break;
pa_parse_number (&s, &result);
CHECK_FIELD (result.number_part, 31, 0, 0);
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
if (the_insn.fpof1 == SGL)
{
if (result.number_part < 16)
if (num < 16)
{
as_bad (_("Invalid register for single precision fmpyadd or fmpysub"));
break;
}
result.number_part &= 0xF;
result.number_part |= (result.l_r_select & 1) << 4;
num &= 0xF;
num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
}
INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 0);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
}
/* Float add operand 1 for fmpyadd, fmpysub */
case 'l':
{
struct pa_11_fp_reg_struct result;
/* This should be more strict. Small steps. */
if (strict && *s != '%')
if (!pa_parse_number (&s, 1))
break;
pa_parse_number (&s, &result);
CHECK_FIELD (result.number_part, 31, 0, 0);
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
if (the_insn.fpof1 == SGL)
{
if (result.number_part < 16)
if (num < 16)
{
as_bad (_("Invalid register for single precision fmpyadd or fmpysub"));
break;
}
result.number_part &= 0xF;
result.number_part |= (result.l_r_select & 1) << 4;
num &= 0xF;
num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
}
INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 6);
INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
}
/* Float add target for fmpyadd, fmpysub */
case 'm':
{
struct pa_11_fp_reg_struct result;
/* This should be more strict. Small steps. */
if (strict && *s != '%')
if (!pa_parse_number (&s, 1))
break;
pa_parse_number (&s, &result);
CHECK_FIELD (result.number_part, 31, 0, 0);
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
if (the_insn.fpof1 == SGL)
{
if (result.number_part < 16)
if (num < 16)
{
as_bad (_("Invalid register for single precision fmpyadd or fmpysub"));
break;
}
result.number_part &= 0xF;
result.number_part |= (result.l_r_select & 1) << 4;
num &= 0xF;
num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
}
INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 11);
INSERT_FIELD_AND_CONTINUE (opcode, num, 11);
}
/* Handle L/R register halves like 'x'. */
case 'E':
case 'e':
{
struct pa_11_fp_reg_struct result;
if (strict && *s != '%')
if (!pa_parse_number (&s, 1))
break;
pa_parse_number (&s, &result);
CHECK_FIELD (result.number_part, 31, 0, 0);
opcode |= (result.number_part & 0x1f) << 16;
if (need_pa11_opcode (&the_insn, &result))
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
opcode |= num << 16;
if (need_pa11_opcode ())
{
opcode |= (result.l_r_select & 1) << 1;
opcode |= (pa_number & FP_REG_RSEL ? 1 << 1 : 0);
}
continue;
}
/* Float target register (PA 2.0 wide). */
case 'x':
/* This should be more strict. Small steps. */
if (strict && *s != '%')
if (!pa_parse_number (&s, 3))
break;
num = pa_parse_number (&s, 0);
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
@ -4622,19 +4569,21 @@ is_end_of_statement ()
the most common will be a hex or decimal constant, but it could be
a pre-defined register (Yuk!), or an absolute symbol.
Return a number or -1 for failure.
Return 1 on success or 0 on failure. If STRICT, then a missing
register prefix will cause a failure. The number itself is
returned in `pa_number'.
When parsing PA-89 FP register numbers RESULT will be
the address of a structure to return information about
L/R half of FP registers, store results there as appropriate.
IS_FLOAT indicates that a PA-89 FP register number should be
parsed; A `l' or `r' suffix is checked for if but 2 of IS_FLOAT is
not set.
pa_parse_number can not handle negative constants and will fail
horribly if it is passed such a constant. */
static int
pa_parse_number (s, result)
pa_parse_number (s, is_float)
char **s;
struct pa_11_fp_reg_struct *result;
int is_float;
{
int num;
char *name;
@ -4642,23 +4591,18 @@ pa_parse_number (s, result)
symbolS *sym;
int status;
char *p = *s;
boolean have_prefix;
/* Skip whitespace before the number. */
while (*p == ' ' || *p == '\t')
p = p + 1;
/* Store info in RESULT if requested by caller. */
if (result)
{
result->number_part = -1;
result->l_r_select = -1;
}
num = -1;
if (isdigit (*p))
pa_number = -1;
have_prefix = 0;
num = 0;
if (!strict && isdigit (*p))
{
/* Looks like a number. */
num = 0;
if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X'))
{
@ -4686,29 +4630,30 @@ pa_parse_number (s, result)
}
}
/* Store info in RESULT if requested by the caller. */
if (result)
{
result->number_part = num;
pa_number = num;
/* Check for a `l' or `r' suffix. */
if (is_float)
{
pa_number += FP_REG_BASE;
if (! (is_float & 2))
{
if (IS_R_SELECT (p))
{
result->l_r_select = 1;
pa_number += FP_REG_RSEL;
++p;
}
else if (IS_L_SELECT (p))
{
result->l_r_select = 0;
++p;
}
else
result->l_r_select = 0;
}
}
}
else if (*p == '%')
{
/* The number might be a predefined register. */
num = 0;
have_prefix = 1;
name = p;
p++;
c = *p;
@ -4764,23 +4709,12 @@ pa_parse_number (s, result)
*p = c;
}
/* Store info in RESULT if requested by caller. */
if (result)
{
result->number_part = num;
if (IS_R_SELECT (p - 1))
result->l_r_select = 1;
else if (IS_L_SELECT (p - 1))
result->l_r_select = 0;
else
result->l_r_select = 0;
}
pa_number = num;
}
else
{
/* And finally, it could be a symbol in the absolute section which
is effectively a constant. */
num = 0;
is effectively a constant, or a register alias symbol. */
name = p;
c = *p;
while (is_part_of_name (c))
@ -4791,16 +4725,23 @@ pa_parse_number (s, result)
*p = 0;
if ((sym = symbol_find (name)) != NULL)
{
if (S_GET_SEGMENT (sym) == &bfd_abs_section)
if (S_GET_SEGMENT (sym) == reg_section)
{
num = S_GET_VALUE (sym);
else
/* Well, we don't really have one, but we do have a
register, so... */
have_prefix = true;
}
else if (S_GET_SEGMENT (sym) == &bfd_abs_section)
num = S_GET_VALUE (sym);
else if (!strict)
{
if (print_errors)
as_bad (_("Non-absolute symbol: '%s'."), name);
num = -1;
}
}
else
else if (!strict)
{
/* There is where we'd come for an undefined symbol
or for an empty string. For an empty string we
@ -4817,21 +4758,15 @@ pa_parse_number (s, result)
}
*p = c;
/* Store info in RESULT if requested by caller. */
if (result)
{
result->number_part = num;
if (IS_R_SELECT (p - 1))
result->l_r_select = 1;
else if (IS_L_SELECT (p - 1))
result->l_r_select = 0;
else
result->l_r_select = 0;
}
pa_number = num;
}
if (!strict || have_prefix)
{
*s = p;
return num;
return 1;
}
return 0;
}
#define REG_NAME_CNT (sizeof(pre_defined_registers) / sizeof(struct pd_reg))
@ -4870,11 +4805,10 @@ reg_name_search (name)
a new PA-1.1 opcode. */
static int
need_pa11_opcode (insn, result)
struct pa_it *insn;
struct pa_11_fp_reg_struct *result;
need_pa11_opcode ()
{
if (result->l_r_select == 1 && !(insn->fpof1 == DBL && insn->fpof2 == DBL))
if ((pa_number & FP_REG_RSEL) != 0
&& !(the_insn.fpof1 == DBL && the_insn.fpof2 == DBL))
{
/* If this instruction is specific to a particular architecture,
then set a new architecture. */
@ -5186,7 +5120,7 @@ pa_get_absolute_expression (insn, strp)
The PA assembly syntax is ambigious in a variety of ways. Consider
this string "4 %r5" Is that the number 4 followed by the register
r5, or is that 4 MOD 5?
r5, or is that 4 MOD r5?
If we get a modulo expresion When looking for an absolute, we try
again cutting off the input string at the first whitespace character. */
@ -6465,6 +6399,27 @@ pa_entry (unused)
#endif
}
/* Silly nonsense for pa_equ. The only half-sensible use for this is
being able to subtract two register symbols that specify a range of
registers, to get the size of the range. */
static int fudge_reg_expressions;
int
hppa_force_reg_syms_absolute (resultP, op, rightP)
expressionS *resultP;
operatorT op ATTRIBUTE_UNUSED;
expressionS *rightP;
{
if (fudge_reg_expressions
&& rightP->X_op == O_register
&& resultP->X_op == O_register)
{
rightP->X_op = O_constant;
resultP->X_op = O_constant;
}
return 0; /* Continue normal expr handling. */
}
/* Handle a .EQU pseudo-op. */
static void
@ -6478,10 +6433,32 @@ pa_equ (reg)
{
symbol = label_symbol->lss_label;
if (reg)
S_SET_VALUE (symbol, pa_parse_number (&input_line_pointer, 0));
{
strict = 1;
if (!pa_parse_number (&input_line_pointer, 0))
as_bad (_(".REG expression must be a register"));
S_SET_VALUE (symbol, pa_number);
S_SET_SEGMENT (symbol, reg_section);
}
else
S_SET_VALUE (symbol, (unsigned int) get_absolute_expression ());
S_SET_SEGMENT (symbol, bfd_abs_section_ptr);
{
expressionS exp;
segT seg;
fudge_reg_expressions = 1;
seg = expression (&exp);
fudge_reg_expressions = 0;
if (exp.X_op != O_constant
&& exp.X_op != O_register)
{
if (exp.X_op != O_absent)
as_bad (_("bad or irreducible absolute expression; zero assumed"));
exp.X_add_number = 0;
seg = absolute_section;
}
S_SET_VALUE (symbol, (unsigned int) exp.X_add_number);
S_SET_SEGMENT (symbol, seg);
}
}
else
{
@ -7135,7 +7112,7 @@ pa_parse_space_stmt (space_name, create_flag)
{
char *name, *ptemp, c;
char loadable, defined, private, sort;
int spnum, temp;
int spnum;
asection *seg = NULL;
sd_chain_struct *space;
@ -7169,10 +7146,11 @@ pa_parse_space_stmt (space_name, create_flag)
/* First see if the space was specified as a number rather than
as a name. According to the PA assembly manual the rest of
the line should be ignored. */
temp = pa_parse_number (&ptemp, 0);
if (temp >= 0)
strict = 0;
pa_parse_number (&ptemp, 0);
if (pa_number >= 0)
{
spnum = temp;
spnum = pa_number;
input_line_pointer = ptemp;
}
else
@ -7254,7 +7232,6 @@ pa_space (unused)
int unused ATTRIBUTE_UNUSED;
{
char *name, c, *space_name, *save_s;
int temp;
sd_chain_struct *sd_chain;
if (within_procedure)
@ -7332,9 +7309,11 @@ pa_space (unused)
/* It could be a space specified by number. */
print_errors = 0;
save_s = input_line_pointer;
if ((temp = pa_parse_number (&input_line_pointer, 0)) >= 0)
strict = 0;
pa_parse_number (&input_line_pointer, 0);
if (pa_number >= 0)
{
if ((sd_chain = pa_find_space_by_number (temp)))
if ((sd_chain = pa_find_space_by_number (pa_number)))
{
current_space = sd_chain;

View File

@ -176,6 +176,13 @@ void pa_end_of_source PARAMS ((void));
#define md_operand(x)
/* Allow register expressions to be treated as absolute expressions.
A silly fudge required for backwards compatibility. */
#define md_optimize_expr hppa_force_reg_syms_absolute
int hppa_force_reg_syms_absolute
PARAMS ((expressionS *, operatorT, expressionS *));
#define TC_FIX_TYPE PTR
#define TC_INIT_FIX_DATA(FIXP) ((FIXP)->tc_fix_data = NULL)