Handle Alpha load-immediate-FP pseudo-instructions:

* config/alpha-opcode.h (ldif, ldig, ldis, ldit): New patterns.
* config/tc-alpha.c (lit8_sec, lit4_sec, lit8_sym, lit4_sym): New variables.
(create_literal_section): New function.
(create_lita_section): Now a macro.
(get_lit8_offset, get_lit4_offset): New functions.
(maybe_set_gp): New function.
(select_gp_value): Call it.
(load_expression): Preserve addend if symbol is a section symbol.
(alpha_ip): Handle new operand type `F' for floating-point constants; store
them in .lit{4,8} sections.
(alpha_ip, case 'G'): Emit LITUSE relocations for symbol exprs.
This commit is contained in:
Ken Raeburn
1994-03-09 02:44:00 +00:00
parent 055a75ef75
commit 40cd35fffd
2 changed files with 137 additions and 30 deletions

View File

@ -394,6 +394,10 @@ static const struct alpha_opcode alpha_opcodes[] =
{ "sts", 0x98000000, 1, "e,P" }, /* regbase macro */ { "sts", 0x98000000, 1, "e,P" }, /* regbase macro */
{ "stt", 0x9c000000, 1, "e,l(2)" }, { "stt", 0x9c000000, 1, "e,l(2)" },
{ "stt", 0x9c000000, 1, "e,P" }, /* regbase macro */ { "stt", 0x9c000000, 1, "e,P" }, /* regbase macro */
{ "ldif", 0x80000000, 1, "e,F" },
{ "ldig", 0x84000000, 1, "e,F" },
{ "ldis", 0x88000000, 1, "e,F" },
{ "ldit", 0x8c000000, 1, "e,F" },
{ "fbeq", 0xc4000000, 1, "e,L" }, /* 6o+5a+21d */ { "fbeq", 0xc4000000, 1, "e,L" }, /* 6o+5a+21d */
{ "fbne", 0xd4000000, 1, "e,L" }, { "fbne", 0xd4000000, 1, "e,L" },

View File

@ -70,10 +70,11 @@ int md_long_jump_size = 4;
/* handle of the OPCODE hash table */ /* handle of the OPCODE hash table */
static struct hash_control *op_hash; static struct hash_control *op_hash;
/* sections we'll want to keep track of */ /* Sections and symbols we'll want to keep track of. */
static segT lita_sec, rdata, sdata; static segT lita_sec, rdata, sdata, lit8_sec, lit4_sec;
static symbolS *lit8_sym, *lit4_sym;
/* setting for ".set [no]{at,macro}" */ /* Setting for ".set [no]{at,macro}". */
static int at_ok = 1, macro_ok = 1; static int at_ok = 1, macro_ok = 1;
/* Keep track of global pointer. */ /* Keep track of global pointer. */
@ -431,17 +432,54 @@ s_gprel32 ()
} }
static void static void
create_lita_section () create_literal_section (secp, name)
segT *secp;
const char *name;
{ {
segT current_section = now_seg; segT current_section = now_seg;
int current_subsec = now_subseg; int current_subsec = now_subseg;
segT new_sec;
lita_sec = subseg_new (".lita", 0); *secp = new_sec = subseg_new (name, 0);
subseg_set (current_section, current_subsec); subseg_set (current_section, current_subsec);
bfd_set_section_flags (stdoutput, lita_sec, bfd_set_section_alignment (stdoutput, new_sec, 3);
bfd_set_section_flags (stdoutput, new_sec,
SEC_RELOC | SEC_ALLOC | SEC_LOAD | SEC_READONLY SEC_RELOC | SEC_ALLOC | SEC_LOAD | SEC_READONLY
| SEC_DATA); | SEC_DATA);
bfd_set_section_alignment (stdoutput, lita_sec, 3); }
#define create_lita_section() create_literal_section (&lita_sec, ".lita")
static valueT
get_lit8_offset (val)
bfd_vma val;
{
valueT retval;
if (lit8_sec == 0)
{
create_literal_section (&lit8_sec, ".lit8");
lit8_sym = section_symbol (lit8_sec);
}
retval = add_to_literal_pool ((symbolS *) 0, val, lit8_sec, 8);
if (retval >= 0xfff0)
as_fatal ("overflow in fp literal (.lit8) table");
return retval;
}
static valueT
get_lit4_offset (val)
bfd_vma val;
{
valueT retval;
if (lit4_sec == 0)
{
create_literal_section (&lit4_sec, ".lit4");
lit4_sym = section_symbol (lit4_sec);
}
retval = add_to_literal_pool ((symbolS *) 0, val, lit4_sec, 4);
if (retval >= 0xfff0)
as_fatal ("overflow in fp literal (.lit4) table");
return retval;
} }
/* This function is called once, at assembler startup time. It should /* This function is called once, at assembler startup time. It should
@ -510,7 +548,6 @@ md_begin ()
} }
if (lose) if (lose)
as_fatal ("Broken assembler. No assembly attempted."); as_fatal ("Broken assembler. No assembly attempted.");
@ -578,31 +615,34 @@ md_assemble (str)
} }
} }
static inline void
maybe_set_gp (sec)
asection *sec;
{
bfd_vma vma;
if (!sec)
return;
vma = bfd_get_section_vma (foo, sec);
if (vma && vma < alpha_gp_value)
alpha_gp_value = vma;
}
static void static void
select_gp_value () select_gp_value ()
{ {
bfd_vma lita_vma, sdata_vma;
if (alpha_gp_value != 0) if (alpha_gp_value != 0)
abort (); abort ();
if (lita_sec) /* Get minus-one in whatever width... */
lita_vma = bfd_get_section_vma (abfd, lita_sec); alpha_gp_value = 0; alpha_gp_value--;
else
lita_vma = 0;
#if 0
if (sdata)
sdata_vma = bfd_get_section_vma (abfd, sdata);
else
#endif
sdata = 0;
if (lita_vma == 0 /* Select the smallest VMA of these existing sections. */
/* Who knows which order they'll get laid out in? */ maybe_set_gp (lita_sec);
|| (sdata_vma != 0 && sdata_vma < lita_vma)) /* maybe_set_gp (sdata); Was disabled before -- should we use it? */
alpha_gp_value = sdata_vma; #if 0
else maybe_set_gp (lit8_sec);
alpha_gp_value = lita_vma; maybe_set_gp (lit4_sec);
#endif
alpha_gp_value += GP_ADJUSTMENT; alpha_gp_value += GP_ADJUSTMENT;
@ -747,8 +787,15 @@ load_expression (reg, insn)
valueT addend; valueT addend;
int num_insns = 1; int num_insns = 1;
addend = insn->reloc[0].exp.X_add_number; if (insn->reloc[0].exp.X_add_symbol->bsym->flags & BSF_SECTION_SYM)
insn->reloc[0].exp.X_add_number = 0; {
addend = 0;
}
else
{
addend = insn->reloc[0].exp.X_add_number;
insn->reloc[0].exp.X_add_number = 0;
}
load_symbol_address (reg, insn); load_symbol_address (reg, insn);
if (addend) if (addend)
{ {
@ -1165,6 +1212,60 @@ alpha_ip (str, insns)
} }
continue; continue;
case 'F':
{
int format, length, mode, i, size;
char temp[20 /*MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT*/];
char *err;
static const char formats[4] = "FGfd";
bfd_vma bits, offset;
char *old_input_line_pointer = input_line_pointer;
input_line_pointer = s;
SKIP_WHITESPACE ();
memset (temp, 0, sizeof (temp));
mode = (opcode >> 26) & 3;
format = formats[mode];
err = md_atof (format, temp, &length);
if (err)
{
as_bad ("Bad floating literal: %s", err);
bits = 0;
}
else
{
/* Generate little-endian number from byte sequence. */
bits = 0;
for (i = length - 1; i >= 0; i--)
bits += ((bfd_vma)(temp[i] & 0xff)) << (i * 8);
}
switch (length)
{
case 8:
offset = get_lit8_offset (bits) - 0x8000;
insns[0].reloc[0].exp.X_add_symbol = lit8_sym;
insns[0].reloc[0].exp.X_add_number = 0x8000;
break;
case 4:
offset = get_lit4_offset (bits) - 0x8000;
insns[0].reloc[0].exp.X_add_symbol = lit4_sym;
insns[0].reloc[0].exp.X_add_number = 0x8000;
break;
default:
abort ();
}
insns[0].reloc[0].exp.X_op = O_symbol;
offset &= 0xffff;
num_gen = load_expression (AT, &insns[0]);
insns[num_gen].reloc[0].code = BFD_RELOC_ALPHA_LITUSE;
insns[num_gen].reloc[0].exp = lituse_basereg;
insns[num_gen++].opcode = opcode | (AT << SB) | offset;
opcode = insns[0].opcode;
s = input_line_pointer;
input_line_pointer = old_input_line_pointer;
}
continue;
/* The following two.. take advantage of the fact that /* The following two.. take advantage of the fact that
opcode already contains most of what we need to know. opcode already contains most of what we need to know.
We just prepend to the instr an "ldah We just prepend to the instr an "ldah
@ -1246,8 +1347,10 @@ alpha_ip (str, insns)
{ {
struct alpha_it *i; struct alpha_it *i;
i = &insns[num_gen++]; i = &insns[num_gen++];
i->reloc[0].code = BFD_RELOC_NONE;
i->opcode = old_opcode | (tmp_reg << SB); i->opcode = old_opcode | (tmp_reg << SB);
i->reloc[0].code = BFD_RELOC_ALPHA_LITUSE;
i->reloc[0].exp = lituse_basereg;
} }
} }
else else
@ -1271,7 +1374,7 @@ alpha_ip (str, insns)
continue; continue;
/* Same failure modes as above, actually most of the /* Same failure modes as above, actually most of the
same code shared. */ same code shared. */
case 'B': /* Builtins */ case 'B': /* Builtins */
args++; args++;
switch (*args) switch (*args)