X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-spu.c;h=24969c97abd55515a8c812ca95ca7747498a152c;hb=97f50151221de0a023a8317559b1992a90f9cb8f;hp=681bc20ddced6b9837fbb3d1046fa5232d20d07d;hpb=e2785c4472a06867e3ddbd11a5609d3f1a9e0f32;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-spu.c b/gas/config/tc-spu.c index 681bc20ddc..24969c97ab 100644 --- a/gas/config/tc-spu.c +++ b/gas/config/tc-spu.c @@ -1,12 +1,12 @@ /* spu.c -- Assembler for the IBM Synergistic Processing Unit (SPU) - Copyright 2006 Free Software Foundation, Inc. + Copyright (C) 2006-2016 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) + the Free Software Foundation; either version 3, or (at your option) any later version. GAS is distributed in the hope that it will be useful, @@ -22,12 +22,11 @@ #include "as.h" #include "safe-ctype.h" #include "subsegs.h" -#include "opcode/spu.h" -#include "dwarf2dbg.h" +#include "dwarf2dbg.h" const struct spu_opcode spu_opcodes[] = { #define APUOP(TAG,MACFORMAT,OPCODE,MNEMONIC,ASMFORMAT,DEP,PIPE) \ - { MACFORMAT, (OPCODE) << (32-11), MNEMONIC, ASMFORMAT }, + { MACFORMAT, (OPCODE ## u) << (32-11), MNEMONIC, ASMFORMAT }, #define APUOPFB(TAG,MACFORMAT,OPCODE,FB,MNEMONIC,ASMFORMAT,DEP,PIPE) \ { MACFORMAT, ((OPCODE) << (32-11)) | ((FB) << (32-18)), MNEMONIC, ASMFORMAT }, #include "opcode/spu-insns.h" @@ -45,16 +44,17 @@ struct spu_insn unsigned int opcode; expressionS exp[MAX_RELOCS]; int reloc_arg[MAX_RELOCS]; - int flag[MAX_RELOCS]; + bfd_reloc_code_real_type reloc[MAX_RELOCS]; enum spu_insns tag; }; static const char *get_imm (const char *param, struct spu_insn *insn, int arg); static const char *get_reg (const char *param, struct spu_insn *insn, int arg, int accept_expr); - static int calcop (struct spu_opcode *format, const char *param, struct spu_insn *insn); +static void spu_brinfo (int); +static void spu_cons (int); extern char *myname; static struct hash_control *op_hash = NULL; @@ -83,22 +83,30 @@ const char FLT_CHARS[] = "dDfF"; const pseudo_typeS md_pseudo_table[] = { {"align", s_align_ptwo, 4}, + {"brinfo", spu_brinfo, 0}, + {"bss", s_lcomm_bytes, 1}, {"def", s_set, 0}, {"dfloat", float_cons, 'd'}, {"ffloat", float_cons, 'f'}, {"global", s_globl, 0}, {"half", cons, 2}, - {"bss", s_lcomm_bytes, 1}, - {"string", stringer, 1}, - {"word", cons, 4}, + {"int", spu_cons, 4}, + {"long", spu_cons, 4}, + {"quad", spu_cons, 8}, + {"string", stringer, 8 + 1}, + {"word", spu_cons, 4}, /* Force set to be treated as an instruction. */ {"set", NULL, 0}, {".set", s_set, 0}, - {"file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0 }, - {"loc", dwarf2_directive_loc, 0}, + /* Likewise for eqv. */ + {"eqv", NULL, 0}, + {".eqv", s_set, -1}, {0,0,0} }; +/* Bits plugged into branch instruction offset field. */ +unsigned int brinfo; + void md_begin (void) { @@ -115,7 +123,8 @@ md_begin (void) { /* hash each mnemonic and record its position */ - retval = hash_insert (op_hash, spu_opcodes[i].mnemonic, (PTR)&spu_opcodes[i]); + retval = hash_insert (op_hash, spu_opcodes[i].mnemonic, + (void *) &spu_opcodes[i]); if (retval != NULL && strcmp (retval, "exists") != 0) as_fatal (_("Can't hash instruction '%s':%s"), @@ -147,7 +156,7 @@ static int emulate_apuasm; static int use_dd2 = 1; int -md_parse_option (int c, char *arg ATTRIBUTE_UNUSED) +md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED) { switch (c) { @@ -236,17 +245,17 @@ insn_fmt_string (struct spu_opcode *format) for (i = 1; i <= format->arg[0]; i++) { int arg = format->arg[i]; - char *exp; - if (i > 1 && arg != A_P && format->arg[i-1] != A_P) + const char *exp; + if (i > 1 && arg != A_P && format->arg[i-1] != A_P) buf[len++] = ','; if (arg == A_P) exp = "("; else if (arg < A_P) exp = i == syntax_error_arg ? "REG" : "reg"; - else + else exp = i == syntax_error_arg ? "IMM" : "imm"; len += sprintf (&buf[len], "%s", exp); - if (i > 1 && format->arg[i-1] == A_P) + if (i > 1 && format->arg[i-1] == A_P) buf[len++] = ')'; } buf[len] = 0; @@ -262,7 +271,7 @@ md_assemble (char *op) struct spu_insn insn; int i; - assert (op); + gas_assert (op); /* skip over instruction to find parameters */ @@ -298,7 +307,7 @@ md_assemble (char *op) insn.exp[i].X_add_number = 0; insn.exp[i].X_op = O_illegal; insn.reloc_arg[i] = -1; - insn.flag[i] = 0; + insn.reloc[i] = BFD_RELOC_NONE; } insn.opcode = format->opcode; insn.tag = (enum spu_insns) (format - spu_opcodes); @@ -336,6 +345,16 @@ md_assemble (char *op) as_warn (_("Treating '%-*s' as a symbol."), (int)(syntax_error_param - d), d); } + if (brinfo != 0 + && (insn.tag <= M_BRASL + || (insn.tag >= M_BRZ && insn.tag <= M_BRHNZ)) + && (insn.opcode & 0x7ff80) == 0 + && (insn.reloc_arg[0] == A_R18 + || insn.reloc_arg[0] == A_S18 + || insn.reloc_arg[1] == A_R18 + || insn.reloc_arg[1] == A_S18)) + insn.opcode |= brinfo << 7; + /* grow the current frag and plop in the opcode */ thisfrag = frag_more (4); @@ -344,28 +363,29 @@ md_assemble (char *op) /* if this instruction requires labels mark it for later */ for (i = 0; i < MAX_RELOCS; i++) - if (insn.reloc_arg[i] >= 0) + if (insn.reloc_arg[i] >= 0) { fixS *fixP; - bfd_reloc_code_real_type reloc = arg_encode[insn.reloc_arg[i]].reloc; + bfd_reloc_code_real_type reloc = insn.reloc[i]; int pcrel = 0; - if (reloc == BFD_RELOC_SPU_PCREL9a + + if (reloc == BFD_RELOC_SPU_PCREL9a || reloc == BFD_RELOC_SPU_PCREL9b - || reloc == BFD_RELOC_SPU_PCREL16) + || reloc == BFD_RELOC_SPU_PCREL16) pcrel = 1; - if (insn.flag[i] & 1) - reloc = BFD_RELOC_SPU_HI16; - else if (insn.flag[i] & 2) - reloc = BFD_RELOC_SPU_LO16; fixP = fix_new_exp (frag_now, thisfrag - frag_now->fr_literal, 4, &insn.exp[i], pcrel, reloc); - fixP->tc_fix_data = insn.reloc_arg[i]; + fixP->tc_fix_data.arg_format = insn.reloc_arg[i]; + fixP->tc_fix_data.insn_tag = insn.tag; } dwarf2_emit_insn (4); + + /* .brinfo lasts exactly one instruction. */ + brinfo = 0; } static int @@ -387,7 +407,7 @@ calcop (struct spu_opcode *format, const char *param, struct spu_insn *insn) if (arg < A_P) param = get_reg (param, insn, arg, 1); else if (arg > A_P) - param = get_imm (param, insn, arg); + param = get_imm (param, insn, arg); else if (arg == A_P) { paren++; @@ -484,7 +504,7 @@ get_reg (const char *param, struct spu_insn *insn, int arg, int accept_expr) saw_prefix = 1; param++; } - + if (arg == A_H) /* Channel */ { if ((param[0] == 'c' || param[0] == 'C') @@ -582,37 +602,37 @@ get_imm (const char *param, struct spu_insn *insn, int arg) int low = 0, high = 0; int reloc_i = insn->reloc_arg[0] >= 0 ? 1 : 0; - if (strncmp (param, "%lo(", 4) == 0) + if (strncasecmp (param, "%lo(", 4) == 0) { param += 3; low = 1; as_warn (_("Using old style, %%lo(expr), please change to PPC style, expr@l.")); } - else if (strncmp (param, "%hi(", 4) == 0) + else if (strncasecmp (param, "%hi(", 4) == 0) { param += 3; high = 1; as_warn (_("Using old style, %%hi(expr), please change to PPC style, expr@h.")); } - else if (strncmp (param, "%pic(", 5) == 0) + else if (strncasecmp (param, "%pic(", 5) == 0) { /* Currently we expect %pic(expr) == expr, so do nothing here. - * i.e. for code loaded at address 0 $toc will be 0. */ + i.e. for code loaded at address 0 $toc will be 0. */ param += 4; } - + if (*param == '$') { /* Symbols can start with $, but if this symbol matches a register - * name, it's probably a mistake. The only way to avoid this - * warning is to rename the symbol. */ + name, it's probably a mistake. The only way to avoid this + warning is to rename the symbol. */ struct spu_insn tmp_insn; const char *np = get_reg (param, &tmp_insn, arg, 0); if (np) syntax_error_param = np; } - + save_ptr = input_line_pointer; input_line_pointer = (char *) param; expression (&insn->exp[reloc_i]); @@ -620,7 +640,7 @@ get_imm (const char *param, struct spu_insn *insn, int arg) input_line_pointer = save_ptr; /* Similar to ppc_elf_suffix in tc-ppc.c. We have so few cases to - * handle we do it inlined here. */ + handle we do it inlined here. */ if (param[0] == '@' && !ISALNUM (param[2]) && param[2] != '@') { if (param[1] == 'h' || param[1] == 'H') @@ -635,18 +655,18 @@ get_imm (const char *param, struct spu_insn *insn, int arg) } } - val = insn->exp[reloc_i].X_add_number; - if (insn->exp[reloc_i].X_op == O_constant) { + val = insn->exp[reloc_i].X_add_number; + if (emulate_apuasm) { - /* Convert the value to a format we expect. */ + /* Convert the value to a format we expect. */ val <<= arg_encode[arg].rshift; if (arg == A_U7A) val = 173 - val; else if (arg == A_U7B) - val = 155 - val; + val = 155 - val; } if (high) @@ -672,7 +692,7 @@ get_imm (const char *param, struct spu_insn *insn, int arg) if (arg == A_U7A) val = 173 - val; else if (arg == A_U7B) - val = 155 - val; + val = 155 - val; /* Branch hints have a split encoding. Do the bottom part. */ if (arg == A_S11 || arg == A_S11I) @@ -681,76 +701,25 @@ get_imm (const char *param, struct spu_insn *insn, int arg) insn->opcode |= (((val >> arg_encode[arg].rshift) & ((1 << arg_encode[arg].size) - 1)) << arg_encode[arg].pos); - insn->reloc_arg[reloc_i] = -1; - insn->flag[reloc_i] = 0; } else { insn->reloc_arg[reloc_i] = arg; if (high) - insn->flag[reloc_i] |= 1; - if (low) - insn->flag[reloc_i] |= 2; + insn->reloc[reloc_i] = BFD_RELOC_SPU_HI16; + else if (low) + insn->reloc[reloc_i] = BFD_RELOC_SPU_LO16; + else + insn->reloc[reloc_i] = arg_encode[arg].reloc; } return param; } -#define MAX_LITTLENUMS 6 - -/* Turn a string in input_line_pointer into a floating point constant of type - type, and store the appropriate bytes in *litP. The number of LITTLENUMS - emitted is stored in *sizeP . An error message is returned, or NULL on OK. - */ -char * +const char * md_atof (int type, char *litP, int *sizeP) { - int prec; - LITTLENUM_TYPE words[MAX_LITTLENUMS]; - LITTLENUM_TYPE *wordP; - char *t; - - switch (type) - { - case 'f': - case 'F': - case 's': - case 'S': - prec = 2; - break; - - case 'd': - case 'D': - case 'r': - case 'R': - prec = 4; - break; - - case 'x': - case 'X': - prec = 6; - break; - - case 'p': - case 'P': - prec = 6; - break; - - default: - *sizeP = 0; - return _("Bad call to MD_ATOF()"); - } - t = atof_ieee (input_line_pointer, type, words); - if (t) - input_line_pointer = t; - - *sizeP = prec * sizeof (LITTLENUM_TYPE); - for (wordP = words; prec--;) - { - md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE)); - litP += sizeof (LITTLENUM_TYPE); - } - return 0; + return ieee_md_atof (type, litP, sizeP, TRUE); } #ifndef WORKING_DOT_WORD @@ -799,6 +768,86 @@ md_create_long_jump (char *ptr, } #endif +/* Handle .brinfo ,. */ +static void +spu_brinfo (int ignore ATTRIBUTE_UNUSED) +{ + addressT priority; + addressT lrlive; + + priority = get_absolute_expression (); + SKIP_WHITESPACE (); + + lrlive = 0; + if (*input_line_pointer == ',') + { + ++input_line_pointer; + lrlive = get_absolute_expression (); + } + + if (priority > 0x1fff) + { + as_bad (_("invalid priority '%lu'"), (unsigned long) priority); + priority = 0; + } + + if (lrlive > 7) + { + as_bad (_("invalid lrlive '%lu'"), (unsigned long) lrlive); + lrlive = 0; + } + + brinfo = (lrlive << 13) | priority; + demand_empty_rest_of_line (); +} + +/* Support @ppu on symbols referenced in .int/.long/.word/.quad. */ +static void +spu_cons (int nbytes) +{ + expressionS exp; + + if (is_it_end_of_statement ()) + { + demand_empty_rest_of_line (); + return; + } + + do + { + deferred_expression (&exp); + if ((exp.X_op == O_symbol + || exp.X_op == O_constant) + && strncasecmp (input_line_pointer, "@ppu", 4) == 0) + { + char *p = frag_more (nbytes); + enum bfd_reloc_code_real reloc; + + /* Check for identifier@suffix+constant. */ + input_line_pointer += 4; + if (*input_line_pointer == '-' || *input_line_pointer == '+') + { + expressionS new_exp; + + expression (&new_exp); + if (new_exp.X_op == O_constant) + exp.X_add_number += new_exp.X_add_number; + } + + reloc = nbytes == 4 ? BFD_RELOC_SPU_PPU32 : BFD_RELOC_SPU_PPU64; + fix_new_exp (frag_now, p - frag_now->fr_literal, nbytes, + &exp, 0, reloc); + } + else + emit_expr (&exp, nbytes); + } + while (*input_line_pointer++ == ','); + + /* Put terminator back into stream. */ + input_line_pointer--; + demand_empty_rest_of_line (); +} + int md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED, segT segment_type ATTRIBUTE_UNUSED) @@ -814,12 +863,14 @@ arelent * tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) { arelent *reloc; - reloc = (arelent *) xmalloc (sizeof (arelent)); - reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + reloc = XNEW (arelent); + reloc->sym_ptr_ptr = XNEW (asymbol *); if (fixp->fx_addsy) *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); else if (fixp->fx_subsy) *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy); + else + abort (); reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); if (reloc->howto == (reloc_howto_type *) NULL) @@ -896,6 +947,7 @@ void md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) { unsigned int res; + unsigned int mask; valueT val = *valP; char *place = fixP->fx_where + fixP->fx_frag->fr_literal; @@ -934,90 +986,115 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) fixP->fx_addnumber = val; + if (fixP->fx_r_type == BFD_RELOC_SPU_PPU32 + || fixP->fx_r_type == BFD_RELOC_SPU_PPU64 + || fixP->fx_r_type == BFD_RELOC_SPU_ADD_PIC) + return; + if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0) { fixP->fx_done = 1; res = 0; - if (fixP->tc_fix_data > A_P) + mask = 0; + if (fixP->tc_fix_data.arg_format > A_P) { - int hi = arg_encode[fixP->tc_fix_data].hi; - int lo = arg_encode[fixP->tc_fix_data].lo; + int hi = arg_encode[fixP->tc_fix_data.arg_format].hi; + int lo = arg_encode[fixP->tc_fix_data.arg_format].lo; if (hi > lo && ((offsetT) val < lo || (offsetT) val > hi)) as_bad_where (fixP->fx_file, fixP->fx_line, - "Relocation doesn't fit. (relocation value = 0x%lx)", + _("Relocation doesn't fit. (relocation value = 0x%lx)"), (long) val); } switch (fixP->fx_r_type) - { - case BFD_RELOC_8: + { + case BFD_RELOC_8: md_number_to_chars (place, val, 1); return; - case BFD_RELOC_16: + case BFD_RELOC_16: md_number_to_chars (place, val, 2); return; - case BFD_RELOC_32: + case BFD_RELOC_32: + case BFD_RELOC_32_PCREL: md_number_to_chars (place, val, 4); return; - case BFD_RELOC_64: + case BFD_RELOC_64: md_number_to_chars (place, val, 8); return; - case BFD_RELOC_SPU_IMM7: - res = (val & 0x7f) << 14; - break; - - case BFD_RELOC_SPU_IMM8: - res = (val & 0xff) << 14; - break; - - case BFD_RELOC_SPU_IMM10: - res = (val & 0x3ff) << 14; - break; - - case BFD_RELOC_SPU_IMM10W: - res = (val & 0x3ff0) << 10; - break; - - case BFD_RELOC_SPU_IMM16: - res = (val & 0xffff) << 7; - break; - - case BFD_RELOC_SPU_IMM16W: - res = (val & 0x3fffc) << 5; - break; - - case BFD_RELOC_SPU_IMM18: - res = (val & 0x3ffff) << 7; - break; - - case BFD_RELOC_SPU_PCREL9a: - res = ((val & 0x1fc) >> 2) | ((val & 0x600) << 14); - break; - - case BFD_RELOC_SPU_PCREL9b: - res = ((val & 0x1fc) >> 2) | ((val & 0x600) << 5); - break; - - case BFD_RELOC_SPU_PCREL16: - res = (val & 0x3fffc) << 5; - break; - - default: - as_bad_where (fixP->fx_file, fixP->fx_line, - _("reloc %d not supported by object file format"), - (int) fixP->fx_r_type); - } - - if (res != 0) - { - place[0] |= (res >> 24) & 0xff; - place[1] |= (res >> 16) & 0xff; - place[2] |= (res >> 8) & 0xff; - place[3] |= (res) & 0xff; - } + case BFD_RELOC_SPU_IMM7: + res = val << 14; + mask = 0x7f << 14; + break; + + case BFD_RELOC_SPU_IMM8: + res = val << 14; + mask = 0xff << 14; + break; + + case BFD_RELOC_SPU_IMM10: + res = val << 14; + mask = 0x3ff << 14; + break; + + case BFD_RELOC_SPU_IMM10W: + res = val << 10; + mask = 0x3ff0 << 10; + break; + + case BFD_RELOC_SPU_IMM16: + res = val << 7; + mask = 0xffff << 7; + break; + + case BFD_RELOC_SPU_IMM16W: + res = val << 5; + mask = 0x3fffc << 5; + break; + + case BFD_RELOC_SPU_IMM18: + res = val << 7; + mask = 0x3ffff << 7; + break; + + case BFD_RELOC_SPU_PCREL9a: + res = ((val & 0x1fc) >> 2) | ((val & 0x600) << 14); + mask = (0x1fc >> 2) | (0x600 << 14); + break; + + case BFD_RELOC_SPU_PCREL9b: + res = ((val & 0x1fc) >> 2) | ((val & 0x600) << 5); + mask = (0x1fc >> 2) | (0x600 << 5); + break; + + case BFD_RELOC_SPU_PCREL16: + res = val << 5; + mask = 0x3fffc << 5; + break; + + case BFD_RELOC_SPU_HI16: + res = val >> 9; + mask = 0xffff << 7; + break; + + case BFD_RELOC_SPU_LO16: + res = val << 7; + mask = 0xffff << 7; + break; + + default: + as_bad_where (fixP->fx_file, fixP->fx_line, + _("reloc %d not supported by object file format"), + (int) fixP->fx_r_type); + } + + res &= mask; + place[0] = (place[0] & (~mask >> 24)) | ((res >> 24) & 0xff); + place[1] = (place[1] & (~mask >> 16)) | ((res >> 16) & 0xff); + place[2] = (place[2] & (~mask >> 8)) | ((res >> 8) & 0xff); + place[3] = (place[3] & ~mask) | (res & 0xff); } }