URL
https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk
Subversion Repositories open8_urisc
Compare Revisions
- This comparison shows the changes necessary to convert path
/open8_urisc/trunk/gnu/binutils/gas/config
- from Rev 16 to Rev 148
- ↔ Reverse comparison
Rev 16 → Rev 148
/tc-tilegx.c
0,0 → 1,1844
/* tc-tilegx.c -- Assemble for a Tile-Gx chip. |
Copyright 2011 Free Software Foundation, Inc. |
|
This file is part of GAS, the GNU Assembler. |
|
This program 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 3 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
|
#include "as.h" |
#include "struc-symbol.h" |
#include "subsegs.h" |
|
#include "elf/tilegx.h" |
#include "opcode/tilegx.h" |
|
#include "dwarf2dbg.h" |
#include "dw2gencfi.h" |
|
#include "safe-ctype.h" |
|
|
/* Special registers. */ |
#define TREG_IDN0 57 |
#define TREG_IDN1 58 |
#define TREG_UDN0 59 |
#define TREG_UDN1 60 |
#define TREG_UDN2 61 |
#define TREG_UDN3 62 |
#define TREG_ZERO 63 |
|
|
/* Generic assembler global variables which must be defined by all |
targets. */ |
|
/* The dwarf2 data alignment, adjusted for 32 or 64 bit. */ |
int tilegx_cie_data_alignment; |
|
/* Characters which always start a comment. */ |
const char comment_chars[] = "#"; |
|
/* Characters which start a comment at the beginning of a line. */ |
const char line_comment_chars[] = "#"; |
|
/* Characters which may be used to separate multiple commands on a |
single line. */ |
const char line_separator_chars[] = ";"; |
|
/* Characters which are used to indicate an exponent in a floating |
point number. */ |
const char EXP_CHARS[] = "eE"; |
|
/* Characters which mean that a number is a floating point constant, |
as in 0d1.0. */ |
const char FLT_CHARS[] = "rRsSfFdDxXpP"; |
|
/* Either 32 or 64. */ |
static int tilegx_arch_size = 64; |
|
|
const char * |
tilegx_target_format (void) |
{ |
return tilegx_arch_size == 64 ? "elf64-tilegx" : "elf32-tilegx"; |
} |
|
|
#define OPTION_32 (OPTION_MD_BASE + 0) |
#define OPTION_64 (OPTION_MD_BASE + 1) |
|
const char *md_shortopts = "VQ:"; |
|
struct option md_longopts[] = |
{ |
{"32", no_argument, NULL, OPTION_32}, |
{"64", no_argument, NULL, OPTION_64}, |
{NULL, no_argument, NULL, 0} |
}; |
|
size_t md_longopts_size = sizeof (md_longopts); |
|
int |
md_parse_option (int c, char *arg ATTRIBUTE_UNUSED) |
{ |
switch (c) |
{ |
/* -Qy, -Qn: SVR4 arguments controlling whether a .comment section |
should be emitted or not. FIXME: Not implemented. */ |
case 'Q': |
break; |
|
/* -V: SVR4 argument to print version ID. */ |
case 'V': |
print_version_id (); |
break; |
|
case OPTION_32: |
tilegx_arch_size = 32; |
break; |
|
case OPTION_64: |
tilegx_arch_size = 64; |
break; |
|
default: |
return 0; |
} |
|
return 1; |
} |
|
void |
md_show_usage (FILE *stream) |
{ |
fprintf (stream, _("\ |
-Q ignored\n\ |
-V print assembler version number\n\ |
--32/--64 generate 32bit/64bit code\n")); |
} |
|
|
/* Extra expression types. */ |
|
#define O_hw0 O_md1 |
#define O_hw1 O_md2 |
#define O_hw2 O_md3 |
#define O_hw3 O_md4 |
#define O_hw0_last O_md5 |
#define O_hw1_last O_md6 |
#define O_hw2_last O_md7 |
#define O_hw0_got O_md8 |
#define O_hw1_got O_md9 |
#define O_hw2_got O_md10 |
#define O_hw3_got O_md11 |
#define O_hw0_last_got O_md12 |
#define O_hw1_last_got O_md13 |
#define O_hw2_last_got O_md14 |
#define O_plt O_md15 |
#define O_hw0_tls_gd O_md16 |
#define O_hw1_tls_gd O_md17 |
#define O_hw2_tls_gd O_md18 |
#define O_hw3_tls_gd O_md19 |
#define O_hw0_last_tls_gd O_md20 |
#define O_hw1_last_tls_gd O_md21 |
#define O_hw2_last_tls_gd O_md22 |
#define O_hw0_tls_ie O_md23 |
#define O_hw1_tls_ie O_md24 |
#define O_hw2_tls_ie O_md25 |
#define O_hw3_tls_ie O_md26 |
#define O_hw0_last_tls_ie O_md27 |
#define O_hw1_last_tls_ie O_md28 |
#define O_hw2_last_tls_ie O_md29 |
|
static struct hash_control *special_operator_hash; |
|
/* Hash tables for instruction mnemonic lookup. */ |
static struct hash_control *op_hash; |
|
/* Hash table for spr lookup. */ |
static struct hash_control *spr_hash; |
|
/* True temporarily while parsing an SPR expression. This changes the |
* namespace to include SPR names. */ |
static int parsing_spr; |
|
/* Are we currently inside `{ ... }'? */ |
static int inside_bundle; |
|
struct tilegx_instruction |
{ |
const struct tilegx_opcode *opcode; |
tilegx_pipeline pipe; |
expressionS operand_values[TILEGX_MAX_OPERANDS]; |
}; |
|
/* This keeps track of the current bundle being built up. */ |
static struct tilegx_instruction current_bundle[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE]; |
|
/* Index in current_bundle for the next instruction to parse. */ |
static int current_bundle_index; |
|
/* Allow 'r63' in addition to 'zero', etc. Normally we disallow this as |
'zero' is not a real register, so using it accidentally would be a |
nasty bug. For other registers, such as 'sp', code using multiple names |
for the same physical register is excessively confusing. |
|
The '.require_canonical_reg_names' pseudo-op turns this error on, |
and the '.no_require_canonical_reg_names' pseudo-op turns this off. |
By default the error is on. */ |
static int require_canonical_reg_names; |
|
/* Allow bundles that do undefined or suspicious things like write |
two different values to the same register at the same time. |
|
The '.no_allow_suspicious_bundles' pseudo-op turns this error on, |
and the '.allow_suspicious_bundles' pseudo-op turns this off. */ |
static int allow_suspicious_bundles; |
|
|
/* A hash table of main processor registers, mapping each register name |
to its index. |
|
Furthermore, if the register number is greater than the number |
of registers for that processor, the user used an illegal alias |
for that register (e.g. r63 instead of zero), so we should generate |
a warning. The attempted register number can be found by clearing |
NONCANONICAL_REG_NAME_FLAG. */ |
static struct hash_control *main_reg_hash; |
|
|
/* We cannot unambiguously store a 0 in a hash table and look it up, |
so we OR in this flag to every canonical register. */ |
#define CANONICAL_REG_NAME_FLAG 0x1000 |
|
/* By default we disallow register aliases like r63, but we record |
them in the hash table in case the .no_require_canonical_reg_names |
directive is used. Noncanonical names have this value added to them. */ |
#define NONCANONICAL_REG_NAME_FLAG 0x2000 |
|
/* Discards flags for register hash table entries and returns the |
reg number. */ |
#define EXTRACT_REGNO(p) ((p) & 63) |
|
/* This function is called once, at assembler startup time. It should |
set up all the tables, etc., that the MD part of the assembler will |
need. */ |
|
void |
md_begin (void) |
{ |
const struct tilegx_opcode *op; |
int i; |
|
/* Guarantee text section is aligned. */ |
bfd_set_section_alignment (stdoutput, text_section, |
TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES); |
|
require_canonical_reg_names = 1; |
allow_suspicious_bundles = 0; |
current_bundle_index = 0; |
inside_bundle = 0; |
|
tilegx_cie_data_alignment = (tilegx_arch_size == 64 ? -8 : -4); |
|
/* Initialize special operator hash table. */ |
special_operator_hash = hash_new (); |
#define INSERT_SPECIAL_OP(name) \ |
hash_insert (special_operator_hash, #name, (void *)O_##name) |
|
INSERT_SPECIAL_OP (hw0); |
INSERT_SPECIAL_OP (hw1); |
INSERT_SPECIAL_OP (hw2); |
INSERT_SPECIAL_OP (hw3); |
INSERT_SPECIAL_OP (hw0_last); |
INSERT_SPECIAL_OP (hw1_last); |
INSERT_SPECIAL_OP (hw2_last); |
/* hw3_last is a convenience alias for the equivalent hw3. */ |
hash_insert (special_operator_hash, "hw3_last", (void*)O_hw3); |
INSERT_SPECIAL_OP (hw0_got); |
INSERT_SPECIAL_OP (hw1_got); |
INSERT_SPECIAL_OP (hw2_got); |
INSERT_SPECIAL_OP (hw3_got); |
INSERT_SPECIAL_OP (hw0_last_got); |
INSERT_SPECIAL_OP (hw1_last_got); |
INSERT_SPECIAL_OP (hw2_last_got); |
INSERT_SPECIAL_OP(plt); |
INSERT_SPECIAL_OP (hw0_tls_gd); |
INSERT_SPECIAL_OP (hw1_tls_gd); |
INSERT_SPECIAL_OP (hw2_tls_gd); |
INSERT_SPECIAL_OP (hw3_tls_gd); |
INSERT_SPECIAL_OP (hw0_last_tls_gd); |
INSERT_SPECIAL_OP (hw1_last_tls_gd); |
INSERT_SPECIAL_OP (hw2_last_tls_gd); |
INSERT_SPECIAL_OP (hw0_tls_ie); |
INSERT_SPECIAL_OP (hw1_tls_ie); |
INSERT_SPECIAL_OP (hw2_tls_ie); |
INSERT_SPECIAL_OP (hw3_tls_ie); |
INSERT_SPECIAL_OP (hw0_last_tls_ie); |
INSERT_SPECIAL_OP (hw1_last_tls_ie); |
INSERT_SPECIAL_OP (hw2_last_tls_ie); |
#undef INSERT_SPECIAL_OP |
|
/* Initialize op_hash hash table. */ |
op_hash = hash_new (); |
for (op = &tilegx_opcodes[0]; op->name != NULL; op++) |
{ |
const char *hash_err = hash_insert (op_hash, op->name, (void *)op); |
if (hash_err != NULL) |
as_fatal (_("Internal Error: Can't hash %s: %s"), op->name, hash_err); |
} |
|
/* Initialize the spr hash table. */ |
parsing_spr = 0; |
spr_hash = hash_new (); |
for (i = 0; i < tilegx_num_sprs; i++) |
hash_insert (spr_hash, tilegx_sprs[i].name, |
(void *) &tilegx_sprs[i]); |
|
/* Set up the main_reg_hash table. We use this instead of |
creating a symbol in the register section to avoid ambiguities |
with labels that have the same names as registers. */ |
main_reg_hash = hash_new (); |
for (i = 0; i < TILEGX_NUM_REGISTERS; i++) |
{ |
char buf[64]; |
|
hash_insert (main_reg_hash, tilegx_register_names[i], |
(void *) (long) (i | CANONICAL_REG_NAME_FLAG)); |
|
/* See if we should insert a noncanonical alias, like r63. */ |
sprintf (buf, "r%d", i); |
if (strcmp (buf, tilegx_register_names[i]) != 0) |
hash_insert (main_reg_hash, xstrdup (buf), |
(void *) (long) (i | NONCANONICAL_REG_NAME_FLAG)); |
} |
} |
|
#define BUNDLE_TEMPLATE_MASK(p0, p1, p2) \ |
((p0) | ((p1) << 8) | ((p2) << 16)) |
#define BUNDLE_TEMPLATE(p0, p1, p2) \ |
{ { (p0), (p1), (p2) }, \ |
BUNDLE_TEMPLATE_MASK(1 << (p0), 1 << (p1), (1 << (p2))) \ |
} |
|
#define NO_PIPELINE TILEGX_NUM_PIPELINE_ENCODINGS |
|
struct bundle_template |
{ |
tilegx_pipeline pipe[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE]; |
unsigned int pipe_mask; |
}; |
|
static const struct bundle_template bundle_templates[] = |
{ |
/* In Y format we must always have something in Y2, since it has |
no fnop, so this conveys that Y2 must always be used. */ |
BUNDLE_TEMPLATE(TILEGX_PIPELINE_Y0, TILEGX_PIPELINE_Y2, NO_PIPELINE), |
BUNDLE_TEMPLATE(TILEGX_PIPELINE_Y1, TILEGX_PIPELINE_Y2, NO_PIPELINE), |
BUNDLE_TEMPLATE(TILEGX_PIPELINE_Y2, TILEGX_PIPELINE_Y0, NO_PIPELINE), |
BUNDLE_TEMPLATE(TILEGX_PIPELINE_Y2, TILEGX_PIPELINE_Y1, NO_PIPELINE), |
|
/* Y format has three instructions. */ |
BUNDLE_TEMPLATE(TILEGX_PIPELINE_Y0,TILEGX_PIPELINE_Y1,TILEGX_PIPELINE_Y2), |
BUNDLE_TEMPLATE(TILEGX_PIPELINE_Y0,TILEGX_PIPELINE_Y2,TILEGX_PIPELINE_Y1), |
BUNDLE_TEMPLATE(TILEGX_PIPELINE_Y1,TILEGX_PIPELINE_Y0,TILEGX_PIPELINE_Y2), |
BUNDLE_TEMPLATE(TILEGX_PIPELINE_Y1,TILEGX_PIPELINE_Y2,TILEGX_PIPELINE_Y0), |
BUNDLE_TEMPLATE(TILEGX_PIPELINE_Y2,TILEGX_PIPELINE_Y0,TILEGX_PIPELINE_Y1), |
BUNDLE_TEMPLATE(TILEGX_PIPELINE_Y2,TILEGX_PIPELINE_Y1,TILEGX_PIPELINE_Y0), |
|
/* X format has only two instructions. */ |
BUNDLE_TEMPLATE(TILEGX_PIPELINE_X0, TILEGX_PIPELINE_X1, NO_PIPELINE), |
BUNDLE_TEMPLATE(TILEGX_PIPELINE_X1, TILEGX_PIPELINE_X0, NO_PIPELINE) |
}; |
|
|
static void |
prepend_nop_to_bundle (tilegx_mnemonic mnemonic) |
{ |
memmove (¤t_bundle[1], ¤t_bundle[0], |
current_bundle_index * sizeof current_bundle[0]); |
current_bundle[0].opcode = &tilegx_opcodes[mnemonic]; |
++current_bundle_index; |
} |
|
static tilegx_bundle_bits |
insert_operand (tilegx_bundle_bits bits, |
const struct tilegx_operand *operand, |
int operand_value, |
char *file, |
unsigned lineno) |
{ |
/* Range-check the immediate. */ |
int num_bits = operand->num_bits; |
|
operand_value >>= operand->rightshift; |
|
if (bfd_check_overflow (operand->is_signed |
? complain_overflow_signed |
: complain_overflow_unsigned, |
num_bits, |
0, |
bfd_arch_bits_per_address (stdoutput), |
operand_value) |
!= bfd_reloc_ok) |
{ |
offsetT min, max; |
if (operand->is_signed) |
{ |
min = -(1 << (num_bits - 1)); |
max = (1 << (num_bits - 1)) - 1; |
} |
else |
{ |
min = 0; |
max = (1 << num_bits) - 1; |
} |
as_bad_value_out_of_range (_("operand"), operand_value, min, max, |
file, lineno); |
} |
|
/* Write out the bits for the immediate. */ |
return bits | operand->insert (operand_value); |
} |
|
|
static int |
apply_special_operator (operatorT op, offsetT num, char *file, unsigned lineno) |
{ |
int ret; |
int check_shift = -1; |
|
switch (op) |
{ |
case O_hw0_last_tls_gd: |
case O_hw0_last_tls_ie: |
case O_hw0_last: |
check_shift = 0; |
/* Fall through. */ |
case O_hw0_tls_gd: |
case O_hw0_tls_ie: |
case O_hw0: |
ret = (signed short)num; |
break; |
|
case O_hw1_last_tls_gd: |
case O_hw1_last_tls_ie: |
case O_hw1_last: |
check_shift = 16; |
/* Fall through. */ |
case O_hw1_tls_gd: |
case O_hw1_tls_ie: |
case O_hw1: |
ret = (signed short)(num >> 16); |
break; |
|
case O_hw2_last_tls_gd: |
case O_hw2_last_tls_ie: |
case O_hw2_last: |
check_shift = 32; |
/* Fall through. */ |
case O_hw2_tls_gd: |
case O_hw2_tls_ie: |
case O_hw2: |
ret = (signed short)(num >> 32); |
break; |
|
case O_hw3_tls_gd: |
case O_hw3_tls_ie: |
case O_hw3: |
ret = (signed short)(num >> 48); |
break; |
|
default: |
abort (); |
break; |
} |
|
if (check_shift >= 0 && ret != (num >> check_shift)) |
{ |
as_bad_value_out_of_range (_("operand"), num, |
~0ULL << (check_shift + 16 - 1), |
~0ULL >> (64 - (check_shift + 16 - 1)), |
file, lineno); |
} |
|
return ret; |
} |
|
static tilegx_bundle_bits |
emit_tilegx_instruction (tilegx_bundle_bits bits, |
int num_operands, |
const unsigned char *operands, |
expressionS *operand_values, |
char *bundle_start) |
{ |
int i; |
|
for (i = 0; i < num_operands; i++) |
{ |
const struct tilegx_operand *operand = |
&tilegx_operands[operands[i]]; |
expressionS *operand_exp = &operand_values[i]; |
int is_pc_relative = operand->is_pc_relative; |
|
if (operand_exp->X_op == O_register |
|| (operand_exp->X_op == O_constant && !is_pc_relative)) |
{ |
/* We know what the bits are right now, so insert them. */ |
bits = insert_operand (bits, operand, operand_exp->X_add_number, |
NULL, 0); |
} |
else |
{ |
bfd_reloc_code_real_type reloc = operand->default_reloc; |
expressionS subexp; |
int die = 0, use_subexp = 0, require_symbol = 0; |
fixS *fixP; |
|
/* Take an expression like hw0(x) and turn it into x with |
a different reloc type. */ |
switch (operand_exp->X_op) |
{ |
#define HANDLE_OP16(suffix) \ |
switch (reloc) \ |
{ \ |
case BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST: \ |
reloc = BFD_RELOC_TILEGX_IMM16_X0_##suffix; \ |
break; \ |
case BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST: \ |
reloc = BFD_RELOC_TILEGX_IMM16_X1_##suffix; \ |
break; \ |
default: \ |
die = 1; \ |
break; \ |
} \ |
use_subexp = 1 |
|
case O_hw0: |
HANDLE_OP16 (HW0); |
break; |
|
case O_hw1: |
HANDLE_OP16 (HW1); |
break; |
|
case O_hw2: |
HANDLE_OP16 (HW2); |
break; |
|
case O_hw3: |
HANDLE_OP16 (HW3); |
break; |
|
case O_hw0_last: |
HANDLE_OP16 (HW0_LAST); |
break; |
|
case O_hw1_last: |
HANDLE_OP16 (HW1_LAST); |
break; |
|
case O_hw2_last: |
HANDLE_OP16 (HW2_LAST); |
break; |
|
case O_hw0_got: |
HANDLE_OP16 (HW0_GOT); |
require_symbol = 1; |
break; |
|
case O_hw1_got: |
HANDLE_OP16 (HW1_GOT); |
require_symbol = 1; |
break; |
|
case O_hw2_got: |
HANDLE_OP16 (HW2_GOT); |
require_symbol = 1; |
break; |
|
case O_hw3_got: |
HANDLE_OP16 (HW3_GOT); |
require_symbol = 1; |
break; |
|
case O_hw0_last_got: |
HANDLE_OP16 (HW0_LAST_GOT); |
require_symbol = 1; |
break; |
|
case O_hw1_last_got: |
HANDLE_OP16 (HW1_LAST_GOT); |
require_symbol = 1; |
break; |
|
case O_hw2_last_got: |
HANDLE_OP16 (HW2_LAST_GOT); |
require_symbol = 1; |
break; |
|
case O_hw0_tls_gd: |
HANDLE_OP16 (HW0_TLS_GD); |
require_symbol = 1; |
break; |
|
case O_hw1_tls_gd: |
HANDLE_OP16 (HW1_TLS_GD); |
require_symbol = 1; |
break; |
|
case O_hw2_tls_gd: |
HANDLE_OP16 (HW2_TLS_GD); |
require_symbol = 1; |
break; |
|
case O_hw3_tls_gd: |
HANDLE_OP16 (HW3_TLS_GD); |
require_symbol = 1; |
break; |
|
case O_hw0_last_tls_gd: |
HANDLE_OP16 (HW0_LAST_TLS_GD); |
require_symbol = 1; |
break; |
|
case O_hw1_last_tls_gd: |
HANDLE_OP16 (HW1_LAST_TLS_GD); |
require_symbol = 1; |
break; |
|
case O_hw2_last_tls_gd: |
HANDLE_OP16 (HW2_LAST_TLS_GD); |
require_symbol = 1; |
break; |
|
case O_hw0_tls_ie: |
HANDLE_OP16 (HW0_TLS_IE); |
require_symbol = 1; |
break; |
|
case O_hw1_tls_ie: |
HANDLE_OP16 (HW1_TLS_IE); |
require_symbol = 1; |
break; |
|
case O_hw2_tls_ie: |
HANDLE_OP16 (HW2_TLS_IE); |
require_symbol = 1; |
break; |
|
case O_hw3_tls_ie: |
HANDLE_OP16 (HW3_TLS_IE); |
require_symbol = 1; |
break; |
|
case O_hw0_last_tls_ie: |
HANDLE_OP16 (HW0_LAST_TLS_IE); |
require_symbol = 1; |
break; |
|
case O_hw1_last_tls_ie: |
HANDLE_OP16 (HW1_LAST_TLS_IE); |
require_symbol = 1; |
break; |
|
case O_hw2_last_tls_ie: |
HANDLE_OP16 (HW2_LAST_TLS_IE); |
require_symbol = 1; |
break; |
|
#undef HANDLE_OP16 |
|
case O_plt: |
switch (reloc) |
{ |
case BFD_RELOC_TILEGX_JUMPOFF_X1: |
reloc = BFD_RELOC_TILEGX_JUMPOFF_X1_PLT; |
break; |
default: |
die = 1; |
break; |
} |
use_subexp = 1; |
require_symbol = 1; |
break; |
|
default: |
/* Do nothing. */ |
break; |
} |
|
if (die) |
{ |
as_bad (_("Invalid operator for operand.")); |
} |
else if (use_subexp) |
{ |
/* Now that we've changed the reloc, change ha16(x) into x, |
etc. */ |
|
if (operand_exp->X_add_symbol->sy_value.X_md) |
{ |
if (require_symbol) |
{ |
as_bad (_("Operator may only be applied to symbols.")); |
} |
|
/* HACK: We used X_md to mark this symbol as a fake wrapper |
around a real expression. To unwrap it, we just grab its |
value here. */ |
operand_exp = &operand_exp->X_add_symbol->sy_value; |
} |
else |
{ |
/* The value of this expression is an actual symbol, so |
turn that into an expression. */ |
memset (&subexp, 0, sizeof subexp); |
subexp.X_op = O_symbol; |
subexp.X_add_symbol = operand_exp->X_add_symbol; |
operand_exp = &subexp; |
} |
} |
|
/* Create a fixup to handle this later. */ |
fixP = fix_new_exp (frag_now, |
bundle_start - frag_now->fr_literal, |
(operand->num_bits + 7) >> 3, |
operand_exp, |
is_pc_relative, |
reloc); |
fixP->tc_fix_data = operand; |
|
/* Don't do overflow checking if we are applying a function like |
ha16. */ |
fixP->fx_no_overflow |= use_subexp; |
} |
} |
return bits; |
} |
|
|
/* Detects and complains if two instructions in current_bundle write |
to the same register, either implicitly or explicitly, or if a |
read-only register is written. */ |
static void |
check_illegal_reg_writes (void) |
{ |
BFD_HOST_U_64_BIT all_regs_written = 0; |
int j; |
|
for (j = 0; j < current_bundle_index; j++) |
{ |
const struct tilegx_instruction *instr = ¤t_bundle[j]; |
int k; |
BFD_HOST_U_64_BIT regs = |
((BFD_HOST_U_64_BIT)1) << instr->opcode->implicitly_written_register; |
BFD_HOST_U_64_BIT conflict; |
|
for (k = 0; k < instr->opcode->num_operands; k++) |
{ |
const struct tilegx_operand *operand = |
&tilegx_operands[instr->opcode->operands[instr->pipe][k]]; |
|
if (operand->is_dest_reg) |
{ |
int regno = instr->operand_values[k].X_add_number; |
BFD_HOST_U_64_BIT mask = ((BFD_HOST_U_64_BIT)1) << regno; |
|
if ((mask & ( (((BFD_HOST_U_64_BIT)1) << TREG_IDN1) |
| (((BFD_HOST_U_64_BIT)1) << TREG_UDN1) |
| (((BFD_HOST_U_64_BIT)1) << TREG_UDN2) |
| (((BFD_HOST_U_64_BIT)1) << TREG_UDN3))) != 0 |
&& !allow_suspicious_bundles) |
{ |
as_bad (_("Writes to register '%s' are not allowed."), |
tilegx_register_names[regno]); |
} |
|
regs |= mask; |
} |
} |
|
/* Writing to the zero register doesn't count. */ |
regs &= ~(((BFD_HOST_U_64_BIT)1) << TREG_ZERO); |
|
conflict = all_regs_written & regs; |
if (conflict != 0 && !allow_suspicious_bundles) |
{ |
/* Find which register caused the conflict. */ |
const char *conflicting_reg_name = "???"; |
int i; |
|
for (i = 0; i < TILEGX_NUM_REGISTERS; i++) |
{ |
if (((conflict >> i) & 1) != 0) |
{ |
conflicting_reg_name = tilegx_register_names[i]; |
break; |
} |
} |
|
as_bad (_("Two instructions in the same bundle both write " |
"to register %s, which is not allowed."), |
conflicting_reg_name); |
} |
|
all_regs_written |= regs; |
} |
} |
|
|
static void |
tilegx_flush_bundle (void) |
{ |
unsigned i; |
int j; |
addressT addr_mod; |
unsigned compatible_pipes; |
const struct bundle_template *match; |
char *f; |
|
inside_bundle = 0; |
|
switch (current_bundle_index) |
{ |
case 0: |
/* No instructions. */ |
return; |
case 1: |
if (current_bundle[0].opcode->can_bundle) |
{ |
/* Simplify later logic by adding an explicit fnop. */ |
prepend_nop_to_bundle (TILEGX_OPC_FNOP); |
} |
else |
{ |
/* This instruction cannot be bundled with anything else. |
Prepend an explicit 'nop', rather than an 'fnop', because |
fnops can be replaced by later binary-processing tools while |
nops cannot. */ |
prepend_nop_to_bundle (TILEGX_OPC_NOP); |
} |
break; |
default: |
if (!allow_suspicious_bundles) |
{ |
/* Make sure all instructions can be bundled with other |
instructions. */ |
const struct tilegx_opcode *cannot_bundle = NULL; |
bfd_boolean seen_non_nop = FALSE; |
|
for (j = 0; j < current_bundle_index; j++) |
{ |
const struct tilegx_opcode *op = current_bundle[j].opcode; |
|
if (!op->can_bundle && cannot_bundle == NULL) |
cannot_bundle = op; |
else if (op->mnemonic != TILEGX_OPC_NOP |
&& op->mnemonic != TILEGX_OPC_INFO |
&& op->mnemonic != TILEGX_OPC_INFOL) |
seen_non_nop = TRUE; |
} |
|
if (cannot_bundle != NULL && seen_non_nop) |
{ |
current_bundle_index = 0; |
as_bad (_("'%s' may not be bundled with other instructions."), |
cannot_bundle->name); |
return; |
} |
} |
break; |
} |
|
compatible_pipes = |
BUNDLE_TEMPLATE_MASK(current_bundle[0].opcode->pipes, |
current_bundle[1].opcode->pipes, |
(current_bundle_index == 3 |
? current_bundle[2].opcode->pipes |
: (1 << NO_PIPELINE))); |
|
/* Find a template that works, if any. */ |
match = NULL; |
for (i = 0; i < sizeof bundle_templates / sizeof bundle_templates[0]; i++) |
{ |
const struct bundle_template *b = &bundle_templates[i]; |
if ((b->pipe_mask & compatible_pipes) == b->pipe_mask) |
{ |
match = b; |
break; |
} |
} |
|
if (match == NULL) |
{ |
current_bundle_index = 0; |
as_bad (_("Invalid combination of instructions for bundle.")); |
return; |
} |
|
/* If the section seems to have no alignment set yet, go ahead and |
make it large enough to hold code. */ |
if (bfd_get_section_alignment (stdoutput, now_seg) == 0) |
bfd_set_section_alignment (stdoutput, now_seg, |
TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES); |
|
for (j = 0; j < current_bundle_index; j++) |
current_bundle[j].pipe = match->pipe[j]; |
|
if (current_bundle_index == 2 && !tilegx_is_x_pipeline (match->pipe[0])) |
{ |
/* We are in Y mode with only two instructions, so add an FNOP. */ |
prepend_nop_to_bundle (TILEGX_OPC_FNOP); |
|
/* Figure out what pipe the fnop must be in via arithmetic. |
* p0 + p1 + p2 must sum to the sum of TILEGX_PIPELINE_Y[012]. */ |
current_bundle[0].pipe = |
(tilegx_pipeline)((TILEGX_PIPELINE_Y0 |
+ TILEGX_PIPELINE_Y1 |
+ TILEGX_PIPELINE_Y2) - |
(current_bundle[1].pipe + current_bundle[2].pipe)); |
} |
|
check_illegal_reg_writes (); |
|
f = frag_more (TILEGX_BUNDLE_SIZE_IN_BYTES); |
|
/* Check to see if this bundle is at an offset that is a multiple of 8-bytes |
from the start of the frag. */ |
addr_mod = frag_now_fix () & (TILEGX_BUNDLE_ALIGNMENT_IN_BYTES - 1); |
if (frag_now->has_code && frag_now->insn_addr != addr_mod) |
as_bad (_("instruction address is not a multiple of 8")); |
frag_now->insn_addr = addr_mod; |
frag_now->has_code = 1; |
|
tilegx_bundle_bits bits = 0; |
for (j = 0; j < current_bundle_index; j++) |
{ |
struct tilegx_instruction *instr = ¤t_bundle[j]; |
tilegx_pipeline pipeline = instr->pipe; |
const struct tilegx_opcode *opcode = instr->opcode; |
|
bits |= emit_tilegx_instruction (opcode->fixed_bit_values[pipeline], |
opcode->num_operands, |
&opcode->operands[pipeline][0], |
instr->operand_values, |
f); |
} |
|
number_to_chars_littleendian (f, bits, 8); |
current_bundle_index = 0; |
|
/* Emit DWARF2 debugging information. */ |
dwarf2_emit_insn (TILEGX_BUNDLE_SIZE_IN_BYTES); |
} |
|
|
/* Extend the expression parser to handle hw0(label), etc. |
as well as SPR names when in the context of parsing an SPR. */ |
|
int |
tilegx_parse_name (char *name, expressionS *e, char *nextcharP) |
{ |
operatorT op = O_illegal; |
|
if (parsing_spr) |
{ |
void* val = hash_find (spr_hash, name); |
if (val == NULL) |
return 0; |
|
memset (e, 0, sizeof *e); |
e->X_op = O_constant; |
e->X_add_number = ((const struct tilegx_spr *)val)->number; |
return 1; |
} |
|
if (*nextcharP != '(') |
{ |
/* hw0, etc. not followed by a paren is just a label with that name. */ |
return 0; |
} |
else |
{ |
/* Look up the operator in our table. */ |
void* val = hash_find (special_operator_hash, name); |
if (val == 0) |
return 0; |
op = (operatorT)(long)val; |
} |
|
/* Restore old '(' and skip it. */ |
*input_line_pointer = '('; |
++input_line_pointer; |
|
expression (e); |
|
if (*input_line_pointer != ')') |
{ |
as_bad (_("Missing ')'")); |
*nextcharP = *input_line_pointer; |
return 0; |
} |
/* Skip ')'. */ |
++input_line_pointer; |
|
if (e->X_op == O_register || e->X_op == O_absent) |
{ |
as_bad (_("Invalid expression.")); |
e->X_op = O_constant; |
e->X_add_number = 0; |
} |
else |
{ |
/* Wrap subexpression with a unary operator. */ |
symbolS *sym = make_expr_symbol (e); |
|
if (sym != e->X_add_symbol) |
{ |
/* HACK: mark this symbol as a temporary wrapper around a proper |
expression, so we can unwrap it later once we have communicated |
the relocation type. */ |
sym->sy_value.X_md = 1; |
} |
|
memset (e, 0, sizeof *e); |
e->X_op = op; |
e->X_add_symbol = sym; |
e->X_add_number = 0; |
} |
|
*nextcharP = *input_line_pointer; |
return 1; |
} |
|
|
/* Parses an expression which must be a register name. */ |
|
static void |
parse_reg_expression (expressionS* expression) |
{ |
/* Zero everything to make sure we don't miss any flags. */ |
memset (expression, 0, sizeof *expression); |
|
char* regname = input_line_pointer; |
char terminating_char = get_symbol_end (); |
|
void* pval = hash_find (main_reg_hash, regname); |
|
if (pval == NULL) |
{ |
as_bad (_("Expected register, got '%s'."), regname); |
} |
|
int regno_and_flags = (int)(size_t)pval; |
int regno = EXTRACT_REGNO(regno_and_flags); |
|
if ((regno_and_flags & NONCANONICAL_REG_NAME_FLAG) |
&& require_canonical_reg_names) |
{ |
as_warn (_("Found use of non-canonical register name %s; " |
"use %s instead."), |
regname, |
tilegx_register_names[regno]); |
} |
|
/* Restore the old character following the register name. */ |
*input_line_pointer = terminating_char; |
|
/* Fill in the expression fields to indicate it's a register. */ |
expression->X_op = O_register; |
expression->X_add_number = regno; |
} |
|
|
/* Parses and type-checks comma-separated operands in input_line_pointer. */ |
|
static void |
parse_operands (const char *opcode_name, |
const unsigned char *operands, |
int num_operands, |
expressionS *operand_values) |
{ |
int i; |
|
memset (operand_values, 0, num_operands * sizeof operand_values[0]); |
|
SKIP_WHITESPACE (); |
for (i = 0; i < num_operands; i++) |
{ |
tilegx_operand_type type = tilegx_operands[operands[i]].type; |
|
SKIP_WHITESPACE (); |
|
if (type == TILEGX_OP_TYPE_REGISTER) |
{ |
parse_reg_expression (&operand_values[i]); |
} |
else if (*input_line_pointer == '}') |
{ |
operand_values[i].X_op = O_absent; |
} |
else if (type == TILEGX_OP_TYPE_SPR) |
{ |
/* Modify the expression parser to add SPRs to the namespace. */ |
parsing_spr = 1; |
expression (&operand_values[i]); |
parsing_spr = 0; |
} |
else |
{ |
expression (&operand_values[i]); |
} |
|
SKIP_WHITESPACE (); |
|
if (i + 1 < num_operands) |
{ |
int separator = (unsigned char)*input_line_pointer++; |
|
if (is_end_of_line[separator] || (separator == '}')) |
{ |
as_bad (_("Too few operands to '%s'."), opcode_name); |
return; |
} |
else if (separator != ',') |
{ |
as_bad (_("Unexpected character '%c' after operand %d to %s."), |
(char)separator, i + 1, opcode_name); |
return; |
} |
} |
|
/* Arbitrarily use the first valid pipe to get the operand type, |
since they are all the same. */ |
switch (tilegx_operands[operands[i]].type) |
{ |
case TILEGX_OP_TYPE_REGISTER: |
/* Handled in parse_reg_expression already. */ |
break; |
case TILEGX_OP_TYPE_SPR: |
/* Fall through */ |
case TILEGX_OP_TYPE_IMMEDIATE: |
/* Fall through */ |
case TILEGX_OP_TYPE_ADDRESS: |
if ( operand_values[i].X_op == O_register |
|| operand_values[i].X_op == O_illegal |
|| operand_values[i].X_op == O_absent) |
as_bad (_("Expected immediate expression")); |
break; |
default: |
abort(); |
} |
} |
|
if (!is_end_of_line[(unsigned char)*input_line_pointer]) |
{ |
switch (*input_line_pointer) |
{ |
case '}': |
if (!inside_bundle) |
as_bad (_("Found '}' when not bundling.")); |
++input_line_pointer; |
inside_bundle = 0; |
demand_empty_rest_of_line (); |
break; |
|
case ',': |
as_bad (_("Too many operands")); |
break; |
|
default: |
/* Use default error for unrecognized garbage. */ |
demand_empty_rest_of_line (); |
break; |
} |
} |
} |
|
|
/* This is the guts of the machine-dependent assembler. STR points to a |
machine dependent instruction. This function is supposed to emit the |
frags/bytes it assembles to. */ |
|
void |
md_assemble (char *str) |
{ |
char old_char; |
size_t opname_len; |
char *old_input_line_pointer; |
const struct tilegx_opcode *op; |
int first_pipe; |
|
/* Split off the opcode and look it up. */ |
opname_len = strcspn (str, " {}"); |
old_char = str[opname_len]; |
str[opname_len] = '\0'; |
|
op = hash_find(op_hash, str); |
str[opname_len] = old_char; |
if (op == NULL) |
{ |
as_bad (_("Unknown opcode `%.*s'."), (int)opname_len, str); |
return; |
} |
|
/* Prepare to parse the operands. */ |
old_input_line_pointer = input_line_pointer; |
input_line_pointer = str + opname_len; |
SKIP_WHITESPACE (); |
|
if (current_bundle_index == TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE) |
{ |
as_bad (_("Too many instructions for bundle.")); |
tilegx_flush_bundle (); |
} |
|
/* Make sure we have room for the upcoming bundle before we |
create any fixups. Otherwise if we have to switch to a new |
frag the fixup dot_value fields will be wrong. */ |
frag_grow (TILEGX_BUNDLE_SIZE_IN_BYTES); |
|
/* Find a valid pipe for this opcode. */ |
for (first_pipe = 0; (op->pipes & (1 << first_pipe)) == 0; first_pipe++) |
; |
|
/* Call the function that assembles this instruction. */ |
current_bundle[current_bundle_index].opcode = op; |
parse_operands (op->name, |
&op->operands[first_pipe][0], |
op->num_operands, |
current_bundle[current_bundle_index].operand_values); |
++current_bundle_index; |
|
/* Restore the saved value of input_line_pointer. */ |
input_line_pointer = old_input_line_pointer; |
|
/* If we weren't inside curly braces, go ahead and emit |
this lone instruction as a bundle right now. */ |
if (!inside_bundle) |
tilegx_flush_bundle (); |
} |
|
|
static void |
s_require_canonical_reg_names (int require) |
{ |
demand_empty_rest_of_line (); |
require_canonical_reg_names = require; |
} |
|
static void |
s_allow_suspicious_bundles (int allow) |
{ |
demand_empty_rest_of_line (); |
allow_suspicious_bundles = allow; |
} |
|
const pseudo_typeS md_pseudo_table[] = |
{ |
{"align", s_align_bytes, 0}, /* Defaulting is invalid (0). */ |
{"word", cons, 4}, |
{"require_canonical_reg_names", s_require_canonical_reg_names, 1 }, |
{"no_require_canonical_reg_names", s_require_canonical_reg_names, 0 }, |
{"allow_suspicious_bundles", s_allow_suspicious_bundles, 1 }, |
{"no_allow_suspicious_bundles", s_allow_suspicious_bundles, 0 }, |
{ NULL, 0, 0 } |
}; |
|
/* Equal to MAX_PRECISION in atof-ieee.c */ |
#define MAX_LITTLENUMS 6 |
|
/* Turn the string pointed to by litP into a floating point constant |
of type TYPE, and emit the appropriate bytes. The number of |
LITTLENUMS emitted is stored in *SIZEP. An error message is |
returned, or NULL on OK. */ |
|
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': |
prec = 2; |
break; |
|
case 'd': |
case 'D': |
prec = 4; |
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); |
/* This loops outputs the LITTLENUMs in REVERSE order; in accord with |
the bigendian 386. */ |
for (wordP = words + prec - 1; prec--;) |
{ |
md_number_to_chars (litP, (valueT) (*wordP--), sizeof (LITTLENUM_TYPE)); |
litP += sizeof (LITTLENUM_TYPE); |
} |
return 0; |
} |
|
|
/* We have no need to default values of symbols. */ |
|
symbolS * |
md_undefined_symbol (char *name ATTRIBUTE_UNUSED) |
{ |
return NULL; |
} |
|
|
void |
tilegx_cons_fix_new (fragS *frag, |
int where, |
int nbytes, |
expressionS *exp) |
{ |
expressionS subexp; |
bfd_reloc_code_real_type reloc = BFD_RELOC_NONE; |
int no_overflow = 0; |
fixS *fixP; |
|
/* See if it's one of our special functions. */ |
switch (exp->X_op) |
{ |
case O_hw0: |
reloc = BFD_RELOC_TILEGX_HW0; |
no_overflow = 1; |
break; |
case O_hw1: |
reloc = BFD_RELOC_TILEGX_HW1; |
no_overflow = 1; |
break; |
case O_hw2: |
reloc = BFD_RELOC_TILEGX_HW2; |
no_overflow = 1; |
break; |
case O_hw3: |
reloc = BFD_RELOC_TILEGX_HW3; |
no_overflow = 1; |
break; |
case O_hw0_last: |
reloc = BFD_RELOC_TILEGX_HW0_LAST; |
break; |
case O_hw1_last: |
reloc = BFD_RELOC_TILEGX_HW1_LAST; |
break; |
case O_hw2_last: |
reloc = BFD_RELOC_TILEGX_HW2_LAST; |
break; |
|
default: |
/* Do nothing. */ |
break; |
} |
|
if (reloc != BFD_RELOC_NONE) |
{ |
if (nbytes != 2) |
{ |
as_bad (_("This operator only produces two byte values.")); |
nbytes = 2; |
} |
|
memset (&subexp, 0, sizeof subexp); |
subexp.X_op = O_symbol; |
subexp.X_add_symbol = exp->X_add_symbol; |
exp = &subexp; |
} |
else |
{ |
switch (nbytes) |
{ |
case 1: |
reloc = BFD_RELOC_8; |
break; |
case 2: |
reloc = BFD_RELOC_16; |
break; |
case 4: |
reloc = BFD_RELOC_32; |
break; |
case 8: |
reloc = BFD_RELOC_64; |
break; |
default: |
as_bad (_("unsupported BFD relocation size %d"), nbytes); |
reloc = BFD_RELOC_64; |
break; |
} |
} |
|
fixP = fix_new_exp (frag, where, nbytes, exp, 0, reloc); |
fixP->tc_fix_data = NULL; |
fixP->fx_no_overflow |= no_overflow; |
} |
|
|
void |
md_apply_fix (fixS *fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED) |
{ |
const struct tilegx_operand *operand; |
valueT value = *valP; |
operatorT special; |
char *p; |
|
/* Leave these for the linker. */ |
if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT |
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) |
return; |
|
if (fixP->fx_subsy != (symbolS *) NULL) |
{ |
/* We can't actually support subtracting a symbol. */ |
as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex")); |
} |
|
/* Correct relocation types for pc-relativeness. */ |
switch (fixP->fx_r_type) |
{ |
#define FIX_PCREL(rtype) \ |
case rtype: \ |
if (fixP->fx_pcrel) \ |
fixP->fx_r_type = rtype##_PCREL; \ |
break; \ |
\ |
case rtype##_PCREL: \ |
if (!fixP->fx_pcrel) \ |
fixP->fx_r_type = rtype; \ |
break |
|
FIX_PCREL (BFD_RELOC_8); |
FIX_PCREL (BFD_RELOC_16); |
FIX_PCREL (BFD_RELOC_32); |
FIX_PCREL (BFD_RELOC_64); |
FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X0_HW0); |
FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X1_HW0); |
FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X0_HW1); |
FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X1_HW1); |
FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X0_HW2); |
FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X1_HW2); |
FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X0_HW3); |
FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X1_HW3); |
FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST); |
FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST); |
FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST); |
FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST); |
FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST); |
FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST); |
|
#undef FIX_PCREL |
|
default: |
/* Do nothing */ |
break; |
} |
|
if (fixP->fx_addsy != NULL) |
{ |
#ifdef OBJ_ELF |
switch (fixP->fx_r_type) |
{ |
case BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_IE: |
case BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_IE: |
case BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_IE: |
case BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_IE: |
case BFD_RELOC_TILEGX_IMM16_X0_HW1_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X1_HW1_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X0_HW1_TLS_IE: |
case BFD_RELOC_TILEGX_IMM16_X1_HW1_TLS_IE: |
case BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_IE: |
case BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_IE: |
case BFD_RELOC_TILEGX_IMM16_X0_HW2_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X1_HW2_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X0_HW2_TLS_IE: |
case BFD_RELOC_TILEGX_IMM16_X1_HW2_TLS_IE: |
case BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_TLS_IE: |
case BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_TLS_IE: |
case BFD_RELOC_TILEGX_IMM16_X0_HW3_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X1_HW3_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X0_HW3_TLS_IE: |
case BFD_RELOC_TILEGX_IMM16_X1_HW3_TLS_IE: |
case BFD_RELOC_TILEGX_TLS_DTPMOD64: |
case BFD_RELOC_TILEGX_TLS_DTPOFF64: |
case BFD_RELOC_TILEGX_TLS_TPOFF64: |
case BFD_RELOC_TILEGX_TLS_DTPMOD32: |
case BFD_RELOC_TILEGX_TLS_DTPOFF32: |
case BFD_RELOC_TILEGX_TLS_TPOFF32: |
S_SET_THREAD_LOCAL (fixP->fx_addsy); |
break; |
|
default: |
/* Do nothing */ |
break; |
} |
#endif |
return; |
} |
|
/* Apply hw0, etc. */ |
special = O_illegal; |
switch (fixP->fx_r_type) |
{ |
case BFD_RELOC_TILEGX_HW0: |
case BFD_RELOC_TILEGX_IMM16_X0_HW0: |
case BFD_RELOC_TILEGX_IMM16_X1_HW0: |
case BFD_RELOC_TILEGX_IMM16_X0_HW0_PCREL: |
case BFD_RELOC_TILEGX_IMM16_X1_HW0_PCREL: |
case BFD_RELOC_TILEGX_IMM16_X0_HW0_GOT: |
case BFD_RELOC_TILEGX_IMM16_X1_HW0_GOT: |
case BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_IE: |
case BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_IE: |
special = O_hw0; |
break; |
|
case BFD_RELOC_TILEGX_HW0_LAST: |
case BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST: |
case BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST: |
case BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_PCREL: |
case BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_PCREL: |
case BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_GOT: |
case BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_GOT: |
case BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_IE: |
case BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_IE: |
special = O_hw0_last; |
break; |
|
case BFD_RELOC_TILEGX_HW1: |
case BFD_RELOC_TILEGX_IMM16_X0_HW1: |
case BFD_RELOC_TILEGX_IMM16_X1_HW1: |
case BFD_RELOC_TILEGX_IMM16_X0_HW1_PCREL: |
case BFD_RELOC_TILEGX_IMM16_X1_HW1_PCREL: |
case BFD_RELOC_TILEGX_IMM16_X0_HW1_GOT: |
case BFD_RELOC_TILEGX_IMM16_X1_HW1_GOT: |
case BFD_RELOC_TILEGX_IMM16_X0_HW1_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X1_HW1_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X0_HW1_TLS_IE: |
case BFD_RELOC_TILEGX_IMM16_X1_HW1_TLS_IE: |
special = O_hw1; |
break; |
|
case BFD_RELOC_TILEGX_HW1_LAST: |
case BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST: |
case BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST: |
case BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_PCREL: |
case BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_PCREL: |
case BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_GOT: |
case BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_GOT: |
case BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_IE: |
case BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_IE: |
special = O_hw1_last; |
break; |
|
case BFD_RELOC_TILEGX_HW2: |
case BFD_RELOC_TILEGX_IMM16_X0_HW2: |
case BFD_RELOC_TILEGX_IMM16_X1_HW2: |
case BFD_RELOC_TILEGX_IMM16_X0_HW2_PCREL: |
case BFD_RELOC_TILEGX_IMM16_X1_HW2_PCREL: |
case BFD_RELOC_TILEGX_IMM16_X0_HW2_GOT: |
case BFD_RELOC_TILEGX_IMM16_X1_HW2_GOT: |
case BFD_RELOC_TILEGX_IMM16_X0_HW2_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X1_HW2_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X0_HW2_TLS_IE: |
case BFD_RELOC_TILEGX_IMM16_X1_HW2_TLS_IE: |
special = O_hw2; |
break; |
|
case BFD_RELOC_TILEGX_HW2_LAST: |
case BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST: |
case BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST: |
case BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_PCREL: |
case BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_PCREL: |
case BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_GOT: |
case BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_GOT: |
case BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_TLS_IE: |
case BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_TLS_IE: |
special = O_hw2_last; |
break; |
|
case BFD_RELOC_TILEGX_HW3: |
case BFD_RELOC_TILEGX_IMM16_X0_HW3: |
case BFD_RELOC_TILEGX_IMM16_X1_HW3: |
case BFD_RELOC_TILEGX_IMM16_X0_HW3_PCREL: |
case BFD_RELOC_TILEGX_IMM16_X1_HW3_PCREL: |
case BFD_RELOC_TILEGX_IMM16_X0_HW3_GOT: |
case BFD_RELOC_TILEGX_IMM16_X1_HW3_GOT: |
case BFD_RELOC_TILEGX_IMM16_X0_HW3_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X1_HW3_TLS_GD: |
case BFD_RELOC_TILEGX_IMM16_X0_HW3_TLS_IE: |
case BFD_RELOC_TILEGX_IMM16_X1_HW3_TLS_IE: |
special = O_hw3; |
break; |
|
default: |
/* Do nothing */ |
break; |
} |
|
if (special != O_illegal) |
{ |
*valP = value = apply_special_operator (special, value, |
fixP->fx_file, fixP->fx_line); |
} |
|
p = fixP->fx_frag->fr_literal + fixP->fx_where; |
|
operand = fixP->tc_fix_data; |
if (operand != NULL) |
{ |
/* It's an instruction operand. */ |
tilegx_bundle_bits bits = |
insert_operand (0, operand, value, fixP->fx_file, fixP->fx_line); |
|
/* Note that we might either be writing out bits for a bundle |
or a static network instruction, which are different sizes, so it's |
important to stop touching memory once we run out of bits. |
ORing in values is OK since we know the existing bits for |
this operand are zero. */ |
for (; bits != 0; bits >>= 8) |
*p++ |= (char)bits; |
} |
else |
{ |
/* Some other kind of relocation. */ |
switch (fixP->fx_r_type) |
{ |
case BFD_RELOC_8: |
case BFD_RELOC_8_PCREL: |
md_number_to_chars (p, value, 1); |
break; |
|
case BFD_RELOC_16: |
case BFD_RELOC_16_PCREL: |
md_number_to_chars (p, value, 2); |
break; |
|
case BFD_RELOC_32: |
case BFD_RELOC_32_PCREL: |
md_number_to_chars (p, value, 4); |
break; |
|
case BFD_RELOC_64: |
case BFD_RELOC_64_PCREL: |
md_number_to_chars (p, value, 8); |
break; |
|
default: |
/* Leave it for the linker. */ |
return; |
} |
} |
|
fixP->fx_done = 1; |
} |
|
|
/* Generate the BFD reloc to be stuck in the object file from the |
fixup used internally in the assembler. */ |
|
arelent * |
tc_gen_reloc (asection *sec ATTRIBUTE_UNUSED, fixS *fixp) |
{ |
arelent *reloc; |
|
reloc = (arelent *) xmalloc (sizeof (arelent)); |
reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); |
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); |
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; |
|
/* Make sure none of our internal relocations make it this far. |
They'd better have been fully resolved by this point. */ |
gas_assert ((int) fixp->fx_r_type > 0); |
|
reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); |
if (reloc->howto == NULL) |
{ |
as_bad_where (fixp->fx_file, fixp->fx_line, |
_("cannot represent `%s' relocation in object file"), |
bfd_get_reloc_code_name (fixp->fx_r_type)); |
return NULL; |
} |
|
if (!fixp->fx_pcrel != !reloc->howto->pc_relative) |
{ |
as_fatal (_("internal error? cannot generate `%s' relocation (%d, %d)"), |
bfd_get_reloc_code_name (fixp->fx_r_type), |
fixp->fx_pcrel, reloc->howto->pc_relative); |
} |
gas_assert (!fixp->fx_pcrel == !reloc->howto->pc_relative); |
|
reloc->addend = fixp->fx_offset; |
|
return reloc; |
} |
|
|
/* The location from which a PC relative jump should be calculated, |
given a PC relative reloc. */ |
|
long |
md_pcrel_from (fixS *fixP) |
{ |
return fixP->fx_frag->fr_address + fixP->fx_where; |
} |
|
|
/* Return 1 if it's OK to adjust a reloc by replacing the symbol with |
a section symbol plus some offset. */ |
int |
tilegx_fix_adjustable (fixS *fix) |
{ |
/* Prevent all adjustments to global symbols */ |
if (S_IS_EXTERNAL (fix->fx_addsy) || S_IS_WEAK (fix->fx_addsy)) |
return 0; |
|
return 1; |
} |
|
|
int |
tilegx_unrecognized_line (int ch) |
{ |
switch (ch) |
{ |
case '{': |
if (inside_bundle) |
{ |
as_bad (_("Found '{' when already bundling.")); |
} |
else |
{ |
inside_bundle = 1; |
current_bundle_index = 0; |
} |
return 1; |
|
case '}': |
if (!inside_bundle) |
{ |
as_bad (_("Found '}' when not bundling.")); |
} |
else |
{ |
tilegx_flush_bundle (); |
} |
|
/* Allow '{' to follow on the same line. We also allow ";;", but that |
happens automatically because ';' is an end of line marker. */ |
SKIP_WHITESPACE (); |
if (input_line_pointer[0] == '{') |
{ |
input_line_pointer++; |
return tilegx_unrecognized_line ('{'); |
} |
|
demand_empty_rest_of_line (); |
return 1; |
|
default: |
break; |
} |
|
/* Not a valid line. */ |
return 0; |
} |
|
|
/* This is called from HANDLE_ALIGN in write.c. Fill in the contents |
of an rs_align_code fragment. */ |
|
void |
tilegx_handle_align (fragS *fragp) |
{ |
addressT bytes, fix; |
char *p; |
|
if (fragp->fr_type != rs_align_code) |
return; |
|
bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix; |
p = fragp->fr_literal + fragp->fr_fix; |
fix = 0; |
|
/* Determine the bits for NOP. */ |
const struct tilegx_opcode *nop_opcode = |
&tilegx_opcodes[TILEGX_OPC_NOP]; |
tilegx_bundle_bits nop = |
( nop_opcode->fixed_bit_values[TILEGX_PIPELINE_X0] |
| nop_opcode->fixed_bit_values[TILEGX_PIPELINE_X1]); |
|
if ((bytes & (TILEGX_BUNDLE_SIZE_IN_BYTES - 1)) != 0) |
{ |
fix = bytes & (TILEGX_BUNDLE_SIZE_IN_BYTES - 1); |
memset (p, 0, fix); |
p += fix; |
bytes -= fix; |
} |
|
number_to_chars_littleendian (p, nop, 8); |
fragp->fr_fix += fix; |
fragp->fr_var = TILEGX_BUNDLE_SIZE_IN_BYTES; |
} |
|
/* Standard calling conventions leave the CFA at SP on entry. */ |
void |
tilegx_cfi_frame_initial_instructions (void) |
{ |
cfi_add_CFA_def_cfa_register (54); |
} |
|
int |
tc_tilegx_regname_to_dw2regnum (char *regname) |
{ |
int i; |
for (i = 0; i < TILEGX_NUM_REGISTERS; i++) |
{ |
if (!strcmp (regname, tilegx_register_names[i])) |
return i; |
} |
|
return -1; |
} |
/tc-tilegx.h
0,0 → 1,93
/* tc-tilegx.h - Macros and type defines for a TILE-Gx chip. |
Copyright 2011 Free Software Foundation, Inc. |
|
This file is part of GAS, the GNU Assembler. |
|
This program 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 3 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
|
#ifndef TC_TILEGX |
|
#include "opcode/tilegx.h" |
|
#define TC_TILEGX |
|
#define TARGET_BYTES_BIG_ENDIAN 0 |
|
#define WORKING_DOT_WORD |
|
#define TARGET_ARCH bfd_arch_tilegx |
|
extern const char * tilegx_target_format (void); |
#define TARGET_FORMAT tilegx_target_format () |
|
#define DWARF2_LINE_MIN_INSN_LENGTH 8 |
|
#define md_number_to_chars number_to_chars_littleendian |
|
#define DIFF_EXPR_OK /* foo-. gets turned into PC relative relocs */ |
|
#define HANDLE_ALIGN(fragp) tilegx_handle_align (fragp) |
extern void tilegx_handle_align (struct frag *); |
|
#define MAX_MEM_FOR_RS_ALIGN_CODE (7 + 8) |
|
struct tilegx_operand; |
#define TC_FIX_TYPE const struct tilegx_operand * |
|
/* Initialize the TC_FIX_TYPE field. */ |
#define TC_INIT_FIX_DATA(FIX) \ |
FIX->tc_fix_data = 0 |
|
extern void tilegx_cons_fix_new (struct frag *, int, |
int, struct expressionS *); |
#define TC_CONS_FIX_NEW(FRAG, WHERE, NBYTES, EXP) \ |
tilegx_cons_fix_new (FRAG, WHERE, NBYTES, EXP) |
|
extern int tilegx_parse_name (char *, expressionS *, char *); |
#define md_parse_name(name, e, m, nextP) tilegx_parse_name (name, e, nextP) |
|
extern int tilegx_fix_adjustable (struct fix *); |
#define tc_fix_adjustable(FIX) tilegx_fix_adjustable (FIX) |
|
extern int tilegx_unrecognized_line (int); |
#define tc_unrecognized_line(ch) tilegx_unrecognized_line (ch) |
|
/* Values passed to md_apply_fix3 don't include the symbol value. */ |
#define MD_APPLY_SYM_VALUE(FIX) 0 |
|
#define md_convert_frag(b,s,f) \ |
as_fatal ("tilegx convert_frag called") |
#define md_estimate_size_before_relax(f,s) \ |
(as_fatal ("tilegx estimate_size_before_relax called"),1) |
#define md_operand(x) |
|
#define md_section_align(seg,size) (size) |
|
/* We want .cfi_* pseudo-ops for generating unwind info. */ |
#define TARGET_USE_CFIPOP 1 |
|
#define tc_cfi_frame_initial_instructions tilegx_cfi_frame_initial_instructions |
extern void tilegx_cfi_frame_initial_instructions (void); |
|
#define tc_regname_to_dw2regnum tc_tilegx_regname_to_dw2regnum |
extern int tc_tilegx_regname_to_dw2regnum (char *); |
|
extern int tilegx_cie_data_alignment; |
|
#define DWARF2_DEFAULT_RETURN_COLUMN 55 |
#define DWARF2_CIE_DATA_ALIGNMENT tilegx_cie_data_alignment |
|
#endif /* TC_TILEGX */ |
/tc-i386.c
218,7 → 218,9
old_gcc_only, |
unsupported_with_intel_mnemonic, |
unsupported_syntax, |
unsupported |
unsupported, |
invalid_vsib_address, |
unsupported_vector_index_register |
}; |
|
struct _i386_insn |
679,6 → 681,8
CPU_ANY_SSE_FLAGS, 0, 1 }, |
{ STRING_COMMA_LEN (".avx"), PROCESSOR_UNKNOWN, |
CPU_AVX_FLAGS, 0, 0 }, |
{ STRING_COMMA_LEN (".avx2"), PROCESSOR_UNKNOWN, |
CPU_AVX2_FLAGS, 0, 0 }, |
{ STRING_COMMA_LEN (".noavx"), PROCESSOR_UNKNOWN, |
CPU_ANY_AVX_FLAGS, 0, 1 }, |
{ STRING_COMMA_LEN (".vmx"), PROCESSOR_UNKNOWN, |
701,6 → 705,8
CPU_RDRND_FLAGS, 0, 0 }, |
{ STRING_COMMA_LEN (".f16c"), PROCESSOR_UNKNOWN, |
CPU_F16C_FLAGS, 0, 0 }, |
{ STRING_COMMA_LEN (".bmi2"), PROCESSOR_UNKNOWN, |
CPU_BMI2_FLAGS, 0, 0 }, |
{ STRING_COMMA_LEN (".fma"), PROCESSOR_UNKNOWN, |
CPU_FMA_FLAGS, 0, 0 }, |
{ STRING_COMMA_LEN (".fma4"), PROCESSOR_UNKNOWN, |
713,6 → 719,10
CPU_MOVBE_FLAGS, 0, 0 }, |
{ STRING_COMMA_LEN (".ept"), PROCESSOR_UNKNOWN, |
CPU_EPT_FLAGS, 0, 0 }, |
{ STRING_COMMA_LEN (".lzcnt"), PROCESSOR_UNKNOWN, |
CPU_LZCNT_FLAGS, 0, 0 }, |
{ STRING_COMMA_LEN (".invpcid"), PROCESSOR_UNKNOWN, |
CPU_INVPCID_FLAGS, 0, 0 }, |
{ STRING_COMMA_LEN (".clflush"), PROCESSOR_UNKNOWN, |
CPU_CLFLUSH_FLAGS, 0, 0 }, |
{ STRING_COMMA_LEN (".nop"), PROCESSOR_UNKNOWN, |
3834,6 → 3844,38
} |
} |
|
/* Check if operands are valid for the instruction. */ |
|
static int |
check_VecOperands (const insn_template *t) |
{ |
/* Without VSIB byte, we can't have a vector register for index. */ |
if (!t->opcode_modifier.vecsib |
&& i.index_reg |
&& (i.index_reg->reg_type.bitfield.regxmm |
|| i.index_reg->reg_type.bitfield.regymm)) |
{ |
i.error = unsupported_vector_index_register; |
return 1; |
} |
|
/* For VSIB byte, we need a vector register for index and no PC |
relative addressing is allowed. */ |
if (t->opcode_modifier.vecsib |
&& (!i.index_reg |
|| !((t->opcode_modifier.vecsib == VecSIB128 |
&& i.index_reg->reg_type.bitfield.regxmm) |
|| (t->opcode_modifier.vecsib == VecSIB256 |
&& i.index_reg->reg_type.bitfield.regymm)) |
|| (i.base_reg && i.base_reg->reg_num == RegRip))) |
{ |
i.error = invalid_vsib_address; |
return 1; |
} |
|
return 0; |
} |
|
/* Check if operands are valid for the instruction. Update VEX |
operand types. */ |
|
4170,6 → 4212,10
continue; |
} |
|
/* Check if vector operands are valid. */ |
if (check_VecOperands (t)) |
continue; |
|
/* Check if VEX operands are valid. */ |
if (VEX_check_operands (t)) |
continue; |
4216,6 → 4262,12
case unsupported: |
err_msg = _("unsupported"); |
break; |
case invalid_vsib_address: |
err_msg = _("invalid VSIB address"); |
break; |
case unsupported_vector_index_register: |
err_msg = _("unsupported vector index register"); |
break; |
} |
as_bad (_("%s for `%s'"), err_msg, |
current_templates->start->name); |
5412,6 → 5464,37
break; |
gas_assert (op < i.operands); |
|
if (i.tm.opcode_modifier.vecsib) |
{ |
if (i.index_reg->reg_num == RegEiz |
|| i.index_reg->reg_num == RegRiz) |
abort (); |
|
i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; |
if (!i.base_reg) |
{ |
i.sib.base = NO_BASE_REGISTER; |
i.sib.scale = i.log2_scale_factor; |
i.types[op].bitfield.disp8 = 0; |
i.types[op].bitfield.disp16 = 0; |
i.types[op].bitfield.disp64 = 0; |
if (flag_code != CODE_64BIT) |
{ |
/* Must be 32 bit */ |
i.types[op].bitfield.disp32 = 1; |
i.types[op].bitfield.disp32s = 0; |
} |
else |
{ |
i.types[op].bitfield.disp32 = 0; |
i.types[op].bitfield.disp32s = 1; |
} |
} |
i.sib.index = i.index_reg->reg_num; |
if ((i.index_reg->reg_flags & RegRex) != 0) |
i.rex |= REX_X; |
} |
|
default_seg = &ds; |
|
if (i.base_reg == 0) |
5418,9 → 5501,16
{ |
i.rm.mode = 0; |
if (!i.disp_operands) |
fake_zero_displacement = 1; |
{ |
fake_zero_displacement = 1; |
/* Instructions with VSIB byte need 32bit displacement |
if there is no base register. */ |
if (i.tm.opcode_modifier.vecsib) |
i.types[op].bitfield.disp32 = 1; |
} |
if (i.index_reg == 0) |
{ |
gas_assert (!i.tm.opcode_modifier.vecsib); |
/* Operand is just <disp> */ |
if (flag_code == CODE_64BIT) |
{ |
5446,8 → 5536,9
i.types[op] = disp32; |
} |
} |
else /* !i.base_reg && i.index_reg */ |
else if (!i.tm.opcode_modifier.vecsib) |
{ |
/* !i.base_reg && i.index_reg */ |
if (i.index_reg->reg_num == RegEiz |
|| i.index_reg->reg_num == RegRiz) |
i.sib.index = NO_INDEX_REGISTER; |
5478,6 → 5569,7
else if (i.base_reg->reg_num == RegRip || |
i.base_reg->reg_num == RegEip) |
{ |
gas_assert (!i.tm.opcode_modifier.vecsib); |
i.rm.regmem = NO_BASE_REGISTER; |
i.types[op].bitfield.disp8 = 0; |
i.types[op].bitfield.disp16 = 0; |
5490,6 → 5582,7
} |
else if (i.base_reg->reg_type.bitfield.reg16) |
{ |
gas_assert (!i.tm.opcode_modifier.vecsib); |
switch (i.base_reg->reg_num) |
{ |
case 3: /* (%bx) */ |
5533,7 → 5626,8
i.types[op].bitfield.disp32 = 1; |
} |
|
i.rm.regmem = i.base_reg->reg_num; |
if (!i.tm.opcode_modifier.vecsib) |
i.rm.regmem = i.base_reg->reg_num; |
if ((i.base_reg->reg_flags & RegRex) != 0) |
i.rex |= REX_B; |
i.sib.base = i.base_reg->reg_num; |
5555,6 → 5649,7
i.sib.scale = i.log2_scale_factor; |
if (i.index_reg == 0) |
{ |
gas_assert (!i.tm.opcode_modifier.vecsib); |
/* <disp>(%esp) becomes two byte modrm with no index |
register. We've already stored the code for esp |
in i.rm.regmem ie. ESCAPE_TO_TWO_BYTE_ADDRESSING. |
5562,7 → 5657,7
extra modrm byte. */ |
i.sib.index = NO_INDEX_REGISTER; |
} |
else |
else if (!i.tm.opcode_modifier.vecsib) |
{ |
if (i.index_reg->reg_num == RegEiz |
|| i.index_reg->reg_num == RegRiz) |
7124,6 → 7219,8
|| i.base_reg->reg_num != |
(i.prefix[ADDR_PREFIX] == 0 ? RegRip : RegEip))) |
|| (i.index_reg |
&& !(i.index_reg->reg_type.bitfield.regxmm |
|| i.index_reg->reg_type.bitfield.regymm) |
&& (!i.index_reg->reg_type.bitfield.baseindex |
|| (i.prefix[ADDR_PREFIX] == 0 |
&& i.index_reg->reg_num != RegRiz |
7157,6 → 7254,8
if ((i.base_reg |
&& !i.base_reg->reg_type.bitfield.reg32) |
|| (i.index_reg |
&& !i.index_reg->reg_type.bitfield.regxmm |
&& !i.index_reg->reg_type.bitfield.regymm |
&& ((!i.index_reg->reg_type.bitfield.reg32 |
&& i.index_reg->reg_num != RegEiz) |
|| !i.index_reg->reg_type.bitfield.baseindex))) |
/tc-cr16.c
522,7 → 522,6
tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS * fixP) |
{ |
arelent * reloc; |
bfd_reloc_code_real_type code; |
|
/* If symbols are local and resolved, then no relocation needed. */ |
if ( ((fixP->fx_addsy) |
582,7 → 581,6
&& GOT_symbol |
&& fixP->fx_addsy == GOT_symbol) |
{ |
code = BFD_RELOC_CR16_GOT_REGREL20; |
reloc->addend = fixP->fx_offset = reloc->address; |
} |
else if ((fixP->fx_r_type == BFD_RELOC_CR16_GOTC_REGREL20) |
589,7 → 587,6
&& GOT_symbol |
&& fixP->fx_addsy == GOT_symbol) |
{ |
code = BFD_RELOC_CR16_GOTC_REGREL20; |
reloc->addend = fixP->fx_offset = reloc->address; |
} |
#endif |
1549,28 → 1546,25
|
/* Cinv instruction requires special handling. */ |
|
static int |
static void |
check_cinv_options (char * operand) |
{ |
char *p = operand; |
int i_used = 0, u_used = 0, d_used = 0; |
|
while (*++p != ']') |
{ |
if (*p == ',' || *p == ' ') |
continue; |
|
else if (*p == 'i') |
i_used = 1; |
else if (*p == 'u') |
u_used = 1; |
else if (*p == 'd') |
d_used = 1; |
else |
as_bad (_("Illegal `cinv' parameter: `%c'"), *p); |
switch (*p) |
{ |
case ',': |
case ' ': |
case 'i': |
case 'u': |
case 'd': |
break; |
default: |
as_bad (_("Illegal `cinv' parameter: `%c'"), *p); |
} |
} |
|
return 0; |
} |
|
/* Retrieve the opcode image of a given register pair. |
2504,7 → 2498,6
{ |
ins cr16_ins; |
char *param, param1[32]; |
char c; |
|
/* Reset global variables for a new instruction. */ |
reset_vars (op); |
2512,7 → 2505,6
/* Strip the mnemonic. */ |
for (param = op; *param != 0 && !ISSPACE (*param); param++) |
; |
c = *param; |
*param++ = '\0'; |
|
/* bCC instuctions and adjust the mnemonic by adding extra white spaces. */ |
/tc-tilepro.c
0,0 → 1,1645
/* tc-tilepro.c -- Assemble for a TILEPro chip. |
Copyright 2011 Free Software Foundation, Inc. |
|
This file is part of GAS, the GNU Assembler. |
|
This program 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 3 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
|
#include "as.h" |
#include "struc-symbol.h" |
#include "subsegs.h" |
|
#include "elf/tilepro.h" |
#include "opcode/tilepro.h" |
|
#include "dwarf2dbg.h" |
#include "dw2gencfi.h" |
|
#include "safe-ctype.h" |
|
|
/* Special registers. */ |
#define TREG_IDN0 57 |
#define TREG_IDN1 58 |
#define TREG_UDN0 59 |
#define TREG_UDN1 60 |
#define TREG_UDN2 61 |
#define TREG_UDN3 62 |
#define TREG_ZERO 63 |
|
|
/* Generic assembler global variables which must be defined by all |
targets. */ |
|
/* Characters which always start a comment. */ |
const char comment_chars[] = "#"; |
|
/* Characters which start a comment at the beginning of a line. */ |
const char line_comment_chars[] = "#"; |
|
/* Characters which may be used to separate multiple commands on a |
single line. */ |
const char line_separator_chars[] = ";"; |
|
/* Characters which are used to indicate an exponent in a floating |
point number. */ |
const char EXP_CHARS[] = "eE"; |
|
/* Characters which mean that a number is a floating point constant, |
as in 0d1.0. */ |
const char FLT_CHARS[] = "rRsSfFdDxXpP"; |
|
const char *md_shortopts = "VQ:"; |
|
struct option md_longopts[] = |
{ |
{NULL, no_argument, NULL, 0} |
}; |
|
size_t md_longopts_size = sizeof (md_longopts); |
|
int |
md_parse_option (int c, char *arg ATTRIBUTE_UNUSED) |
{ |
switch (c) |
{ |
/* -Qy, -Qn: SVR4 arguments controlling whether a .comment section |
should be emitted or not. FIXME: Not implemented. */ |
case 'Q': |
break; |
|
/* -V: SVR4 argument to print version ID. */ |
case 'V': |
print_version_id (); |
break; |
|
default: |
return 0; |
} |
|
return 1; |
} |
|
void |
md_show_usage (FILE *stream) |
{ |
fprintf (stream, _("\ |
-Q ignored\n\ |
-V print assembler version number\n")); |
} |
|
/* Extra expression types. */ |
|
#define O_lo16 O_md1 |
#define O_hi16 O_md2 |
#define O_ha16 O_md3 |
#define O_got O_md4 |
#define O_got_lo16 O_md5 |
#define O_got_hi16 O_md6 |
#define O_got_ha16 O_md7 |
#define O_plt O_md8 |
#define O_tls_gd O_md9 |
#define O_tls_gd_lo16 O_md10 |
#define O_tls_gd_hi16 O_md11 |
#define O_tls_gd_ha16 O_md12 |
#define O_tls_ie O_md13 |
#define O_tls_ie_lo16 O_md14 |
#define O_tls_ie_hi16 O_md15 |
#define O_tls_ie_ha16 O_md16 |
|
static struct hash_control *special_operator_hash; |
|
/* Hash tables for instruction mnemonic lookup. */ |
static struct hash_control *op_hash; |
|
/* Hash table for spr lookup. */ |
static struct hash_control *spr_hash; |
|
/* True temporarily while parsing an SPR expression. This changes the |
* namespace to include SPR names. */ |
static int parsing_spr; |
|
/* Are we currently inside `{ ... }'? */ |
static int inside_bundle; |
|
struct tilepro_instruction |
{ |
const struct tilepro_opcode *opcode; |
tilepro_pipeline pipe; |
expressionS operand_values[TILEPRO_MAX_OPERANDS]; |
}; |
|
/* This keeps track of the current bundle being built up. */ |
static struct tilepro_instruction |
current_bundle[TILEPRO_MAX_INSTRUCTIONS_PER_BUNDLE]; |
|
/* Index in current_bundle for the next instruction to parse. */ |
static int current_bundle_index; |
|
/* Allow 'r63' in addition to 'zero', etc. Normally we disallow this as |
'zero' is not a real register, so using it accidentally would be a |
nasty bug. For other registers, such as 'sp', code using multiple names |
for the same physical register is excessively confusing. |
|
The '.require_canonical_reg_names' pseudo-op turns this error on, |
and the '.no_require_canonical_reg_names' pseudo-op turns this off. |
By default the error is on. */ |
static int require_canonical_reg_names; |
|
/* Allow bundles that do undefined or suspicious things like write |
two different values to the same register at the same time. |
|
The '.no_allow_suspicious_bundles' pseudo-op turns this error on, |
and the '.allow_suspicious_bundles' pseudo-op turns this off. */ |
static int allow_suspicious_bundles; |
|
|
/* A hash table of main processor registers, mapping each register name |
to its index. |
|
Furthermore, if the register number is greater than the number |
of registers for that processor, the user used an illegal alias |
for that register (e.g. r63 instead of zero), so we should generate |
a warning. The attempted register number can be found by clearing |
NONCANONICAL_REG_NAME_FLAG. */ |
static struct hash_control *main_reg_hash; |
|
|
/* We cannot unambiguously store a 0 in a hash table and look it up, |
so we OR in this flag to every canonical register. */ |
#define CANONICAL_REG_NAME_FLAG 0x1000 |
|
/* By default we disallow register aliases like r63, but we record |
them in the hash table in case the .no_require_canonical_reg_names |
directive is used. Noncanonical names have this value added to them. */ |
#define NONCANONICAL_REG_NAME_FLAG 0x2000 |
|
/* Discards flags for register hash table entries and returns the |
reg number. */ |
#define EXTRACT_REGNO(p) ((p) & 63) |
|
/* This function is called once, at assembler startup time. It should |
set up all the tables, etc., that the MD part of the assembler will |
need. */ |
void |
md_begin (void) |
{ |
const struct tilepro_opcode *op; |
int i; |
|
/* Guarantee text section is aligned. */ |
bfd_set_section_alignment (stdoutput, text_section, |
TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES); |
|
require_canonical_reg_names = 1; |
allow_suspicious_bundles = 0; |
current_bundle_index = 0; |
inside_bundle = 0; |
|
/* Initialize special operator hash table. */ |
special_operator_hash = hash_new (); |
#define INSERT_SPECIAL_OP(name) \ |
hash_insert (special_operator_hash, #name, (void *)O_##name) |
|
INSERT_SPECIAL_OP(lo16); |
INSERT_SPECIAL_OP(hi16); |
INSERT_SPECIAL_OP(ha16); |
INSERT_SPECIAL_OP(got); |
INSERT_SPECIAL_OP(got_lo16); |
INSERT_SPECIAL_OP(got_hi16); |
INSERT_SPECIAL_OP(got_ha16); |
INSERT_SPECIAL_OP(plt); |
INSERT_SPECIAL_OP(tls_gd); |
INSERT_SPECIAL_OP(tls_gd_lo16); |
INSERT_SPECIAL_OP(tls_gd_hi16); |
INSERT_SPECIAL_OP(tls_gd_ha16); |
INSERT_SPECIAL_OP(tls_ie); |
INSERT_SPECIAL_OP(tls_ie_lo16); |
INSERT_SPECIAL_OP(tls_ie_hi16); |
INSERT_SPECIAL_OP(tls_ie_ha16); |
#undef INSERT_SPECIAL_OP |
|
/* Initialize op_hash hash table. */ |
op_hash = hash_new (); |
for (op = &tilepro_opcodes[0]; op->name != NULL; op++) |
{ |
const char *hash_err = hash_insert (op_hash, op->name, (void *)op); |
if (hash_err != NULL) |
{ |
as_fatal (_("Internal Error: Can't hash %s: %s"), |
op->name, hash_err); |
} |
} |
|
/* Initialize the spr hash table. */ |
parsing_spr = 0; |
spr_hash = hash_new (); |
for (i = 0; i < tilepro_num_sprs; i++) |
hash_insert (spr_hash, tilepro_sprs[i].name, |
(void *) &tilepro_sprs[i]); |
|
/* Set up the main_reg_hash table. We use this instead of |
* creating a symbol in the register section to avoid ambiguities |
* with labels that have the same names as registers. */ |
main_reg_hash = hash_new (); |
for (i = 0; i < TILEPRO_NUM_REGISTERS; i++) |
{ |
char buf[64]; |
|
hash_insert (main_reg_hash, tilepro_register_names[i], |
(void *) (long)(i | CANONICAL_REG_NAME_FLAG)); |
|
/* See if we should insert a noncanonical alias, like r63. */ |
sprintf (buf, "r%d", i); |
if (strcmp (buf, tilepro_register_names[i]) != 0) |
hash_insert (main_reg_hash, xstrdup (buf), |
(void *) (long)(i | NONCANONICAL_REG_NAME_FLAG)); |
} |
|
/* Insert obsolete backwards-compatibility register names. */ |
hash_insert (main_reg_hash, "io0", |
(void *) (long) (TREG_IDN0 | CANONICAL_REG_NAME_FLAG)); |
hash_insert (main_reg_hash, "io1", |
(void *) (long) (TREG_IDN1 | CANONICAL_REG_NAME_FLAG)); |
hash_insert (main_reg_hash, "us0", |
(void *) (long) (TREG_UDN0 | CANONICAL_REG_NAME_FLAG)); |
hash_insert (main_reg_hash, "us1", |
(void *) (long) (TREG_UDN1 | CANONICAL_REG_NAME_FLAG)); |
hash_insert (main_reg_hash, "us2", |
(void *) (long) (TREG_UDN2 | CANONICAL_REG_NAME_FLAG)); |
hash_insert (main_reg_hash, "us3", |
(void *) (long) (TREG_UDN3 | CANONICAL_REG_NAME_FLAG)); |
|
} |
|
|
#define BUNDLE_TEMPLATE_MASK(p0, p1, p2) \ |
((p0) | ((p1) << 8) | ((p2) << 16)) |
#define BUNDLE_TEMPLATE(p0, p1, p2) \ |
{ { (p0), (p1), (p2) }, \ |
BUNDLE_TEMPLATE_MASK(1 << (p0), 1 << (p1), (1 << (p2))) \ |
} |
|
#define NO_PIPELINE TILEPRO_NUM_PIPELINE_ENCODINGS |
|
struct bundle_template |
{ |
tilepro_pipeline pipe[TILEPRO_MAX_INSTRUCTIONS_PER_BUNDLE]; |
unsigned int pipe_mask; |
}; |
|
static const struct bundle_template bundle_templates[] = |
{ |
/* In Y format we must always have something in Y2, since it has |
* no fnop, so this conveys that Y2 must always be used. */ |
BUNDLE_TEMPLATE(TILEPRO_PIPELINE_Y0, TILEPRO_PIPELINE_Y2, NO_PIPELINE), |
BUNDLE_TEMPLATE(TILEPRO_PIPELINE_Y1, TILEPRO_PIPELINE_Y2, NO_PIPELINE), |
BUNDLE_TEMPLATE(TILEPRO_PIPELINE_Y2, TILEPRO_PIPELINE_Y0, NO_PIPELINE), |
BUNDLE_TEMPLATE(TILEPRO_PIPELINE_Y2, TILEPRO_PIPELINE_Y1, NO_PIPELINE), |
|
/* Y format has three instructions. */ |
BUNDLE_TEMPLATE(TILEPRO_PIPELINE_Y0, TILEPRO_PIPELINE_Y1, TILEPRO_PIPELINE_Y2), |
BUNDLE_TEMPLATE(TILEPRO_PIPELINE_Y0, TILEPRO_PIPELINE_Y2, TILEPRO_PIPELINE_Y1), |
BUNDLE_TEMPLATE(TILEPRO_PIPELINE_Y1, TILEPRO_PIPELINE_Y0, TILEPRO_PIPELINE_Y2), |
BUNDLE_TEMPLATE(TILEPRO_PIPELINE_Y1, TILEPRO_PIPELINE_Y2, TILEPRO_PIPELINE_Y0), |
BUNDLE_TEMPLATE(TILEPRO_PIPELINE_Y2, TILEPRO_PIPELINE_Y0, TILEPRO_PIPELINE_Y1), |
BUNDLE_TEMPLATE(TILEPRO_PIPELINE_Y2, TILEPRO_PIPELINE_Y1, TILEPRO_PIPELINE_Y0), |
|
/* X format has only two instructions. */ |
BUNDLE_TEMPLATE(TILEPRO_PIPELINE_X0, TILEPRO_PIPELINE_X1, NO_PIPELINE), |
BUNDLE_TEMPLATE(TILEPRO_PIPELINE_X1, TILEPRO_PIPELINE_X0, NO_PIPELINE) |
}; |
|
|
static void |
prepend_nop_to_bundle (tilepro_mnemonic mnemonic) |
{ |
memmove (¤t_bundle[1], ¤t_bundle[0], |
current_bundle_index * sizeof current_bundle[0]); |
current_bundle[0].opcode = &tilepro_opcodes[mnemonic]; |
++current_bundle_index; |
} |
|
|
static tilepro_bundle_bits |
insert_operand (tilepro_bundle_bits bits, |
const struct tilepro_operand *operand, |
int operand_value, |
char *file, |
unsigned lineno) |
{ |
/* Range-check the immediate. */ |
int num_bits = operand->num_bits; |
|
operand_value >>= operand->rightshift; |
|
if (bfd_check_overflow (operand->is_signed |
? complain_overflow_signed |
: complain_overflow_unsigned, |
num_bits, |
0, |
bfd_arch_bits_per_address (stdoutput), |
operand_value) |
!= bfd_reloc_ok) |
{ |
offsetT min, max; |
if (operand->is_signed) |
{ |
min = -(1 << (num_bits - 1)); |
max = (1 << (num_bits - 1)) - 1; |
} |
else |
{ |
min = 0; |
max = (1 << num_bits) - 1; |
} |
as_bad_value_out_of_range (_("operand"), operand_value, min, max, |
file, lineno); |
} |
|
/* Write out the bits for the immediate. */ |
return bits | operand->insert (operand_value); |
} |
|
|
static int |
apply_special_operator (operatorT op, int num) |
{ |
switch (op) |
{ |
case O_lo16: |
case O_got: |
case O_got_lo16: |
case O_tls_gd: |
case O_tls_gd_lo16: |
case O_tls_ie: |
case O_tls_ie_lo16: |
return (signed short)num; |
|
case O_hi16: |
case O_got_hi16: |
case O_tls_gd_hi16: |
case O_tls_ie_hi16: |
return (signed short)(num >> 16); |
|
case O_ha16: |
case O_got_ha16: |
case O_tls_gd_ha16: |
case O_tls_ie_ha16: |
return (signed short)((num + 0x8000) >> 16); |
|
default: |
abort (); |
} |
} |
|
|
static tilepro_bundle_bits |
emit_tilepro_instruction (tilepro_bundle_bits bits, |
int num_operands, |
const unsigned char *operands, |
expressionS *operand_values, |
char *bundle_start) |
{ |
int i; |
|
for (i = 0; i < num_operands; i++) |
{ |
const struct tilepro_operand *operand = |
&tilepro_operands[operands[i]]; |
expressionS *operand_exp = &operand_values[i]; |
int is_pc_relative = operand->is_pc_relative; |
|
if (operand_exp->X_op == O_register |
|| (operand_exp->X_op == O_constant && !is_pc_relative)) |
{ |
/* We know what the bits are right now, so insert them. */ |
bits = insert_operand (bits, operand, operand_exp->X_add_number, |
NULL, 0); |
} |
else |
{ |
bfd_reloc_code_real_type reloc = operand->default_reloc; |
expressionS subexp; |
int die = 0, use_subexp = 0, require_symbol = 0; |
fixS *fixP; |
|
/* Take an expression like hi16(x) and turn it into x with |
a different reloc type. */ |
switch (operand_exp->X_op) |
{ |
#define HANDLE_OP16(suffix) \ |
switch (reloc) \ |
{ \ |
case BFD_RELOC_TILEPRO_IMM16_X0: \ |
reloc = BFD_RELOC_TILEPRO_IMM16_X0_##suffix; \ |
break; \ |
case BFD_RELOC_TILEPRO_IMM16_X1: \ |
reloc = BFD_RELOC_TILEPRO_IMM16_X1_##suffix; \ |
break; \ |
default: \ |
die = 1; \ |
break; \ |
} \ |
use_subexp = 1 |
|
case O_lo16: |
HANDLE_OP16 (LO); |
break; |
|
case O_hi16: |
HANDLE_OP16 (HI); |
break; |
|
case O_ha16: |
HANDLE_OP16 (HA); |
break; |
|
case O_got: |
HANDLE_OP16 (GOT); |
require_symbol = 1; |
break; |
|
case O_got_lo16: |
HANDLE_OP16 (GOT_LO); |
require_symbol = 1; |
break; |
|
case O_got_hi16: |
HANDLE_OP16 (GOT_HI); |
require_symbol = 1; |
break; |
|
case O_got_ha16: |
HANDLE_OP16 (GOT_HA); |
require_symbol = 1; |
break; |
|
case O_tls_gd: |
HANDLE_OP16 (TLS_GD); |
require_symbol = 1; |
break; |
|
case O_tls_gd_lo16: |
HANDLE_OP16 (TLS_GD_LO); |
require_symbol = 1; |
break; |
|
case O_tls_gd_hi16: |
HANDLE_OP16 (TLS_GD_HI); |
require_symbol = 1; |
break; |
|
case O_tls_gd_ha16: |
HANDLE_OP16 (TLS_GD_HA); |
require_symbol = 1; |
break; |
|
case O_tls_ie: |
HANDLE_OP16 (TLS_IE); |
require_symbol = 1; |
break; |
|
case O_tls_ie_lo16: |
HANDLE_OP16 (TLS_IE_LO); |
require_symbol = 1; |
break; |
|
case O_tls_ie_hi16: |
HANDLE_OP16 (TLS_IE_HI); |
require_symbol = 1; |
break; |
|
case O_tls_ie_ha16: |
HANDLE_OP16 (TLS_IE_HA); |
require_symbol = 1; |
break; |
|
#undef HANDLE_OP16 |
|
case O_plt: |
switch (reloc) |
{ |
case BFD_RELOC_TILEPRO_JOFFLONG_X1: |
reloc = BFD_RELOC_TILEPRO_JOFFLONG_X1_PLT; |
break; |
default: |
die = 1; |
break; |
} |
use_subexp = 1; |
require_symbol = 1; |
break; |
|
default: |
/* Do nothing. */ |
break; |
} |
|
if (die) |
{ |
as_bad (_("Invalid operator for operand.")); |
} |
else if (use_subexp) |
{ |
/* Now that we've changed the reloc, change ha16(x) into x, |
etc. */ |
|
if (operand_exp->X_add_symbol->sy_value.X_md) |
{ |
if (require_symbol) |
{ |
as_bad (_("Operator may only be applied to symbols.")); |
} |
|
/* HACK: We used X_md to mark this symbol as a fake wrapper |
around a real expression. To unwrap it, we just grab its |
value here. */ |
operand_exp = &operand_exp->X_add_symbol->sy_value; |
} |
else |
{ |
/* The value of this expression is an actual symbol, so |
turn that into an expression. */ |
memset (&subexp, 0, sizeof subexp); |
subexp.X_op = O_symbol; |
subexp.X_add_symbol = operand_exp->X_add_symbol; |
operand_exp = &subexp; |
} |
} |
|
/* Create a fixup to handle this later. */ |
fixP = fix_new_exp (frag_now, |
bundle_start - frag_now->fr_literal, |
(operand->num_bits + 7) >> 3, |
operand_exp, |
is_pc_relative, |
reloc); |
fixP->tc_fix_data = operand; |
|
/* Don't do overflow checking if we are applying a function like |
ha16. */ |
fixP->fx_no_overflow |= use_subexp; |
} |
} |
return bits; |
} |
|
|
/* Detects and complains if two instructions in current_bundle write |
to the same register, either implicitly or explicitly, or if a |
read-only register is written. */ |
static void |
check_illegal_reg_writes (void) |
{ |
BFD_HOST_U_64_BIT all_regs_written = 0; |
int j; |
|
for (j = 0; j < current_bundle_index; j++) |
{ |
const struct tilepro_instruction *instr = ¤t_bundle[j]; |
int k; |
BFD_HOST_U_64_BIT regs = |
((BFD_HOST_U_64_BIT)1) << instr->opcode->implicitly_written_register; |
BFD_HOST_U_64_BIT conflict; |
|
for (k = 0; k < instr->opcode->num_operands; k++) |
{ |
const struct tilepro_operand *operand = |
&tilepro_operands[instr->opcode->operands[instr->pipe][k]]; |
|
if (operand->is_dest_reg) |
{ |
int regno = instr->operand_values[k].X_add_number; |
BFD_HOST_U_64_BIT mask = ((BFD_HOST_U_64_BIT)1) << regno; |
|
if ((mask & ( (((BFD_HOST_U_64_BIT)1) << TREG_IDN1) |
| (((BFD_HOST_U_64_BIT)1) << TREG_UDN1) |
| (((BFD_HOST_U_64_BIT)1) << TREG_UDN2) |
| (((BFD_HOST_U_64_BIT)1) << TREG_UDN3))) != 0 |
&& !allow_suspicious_bundles) |
{ |
as_bad (_("Writes to register '%s' are not allowed."), |
tilepro_register_names[regno]); |
} |
|
regs |= mask; |
} |
} |
|
/* Writing to the zero register doesn't count. */ |
regs &= ~(((BFD_HOST_U_64_BIT)1) << TREG_ZERO); |
|
conflict = all_regs_written & regs; |
if (conflict != 0 && !allow_suspicious_bundles) |
{ |
/* Find which register caused the conflict. */ |
const char *conflicting_reg_name = "???"; |
int i; |
|
for (i = 0; i < TILEPRO_NUM_REGISTERS; i++) |
{ |
if (((conflict >> i) & 1) != 0) |
{ |
conflicting_reg_name = tilepro_register_names[i]; |
break; |
} |
} |
|
as_bad (_("Two instructions in the same bundle both write " |
"to register %s, which is not allowed."), |
conflicting_reg_name); |
} |
|
all_regs_written |= regs; |
} |
} |
|
|
static void |
tilepro_flush_bundle (void) |
{ |
unsigned i; |
int j, addr_mod; |
unsigned compatible_pipes; |
const struct bundle_template *match; |
char *f; |
|
inside_bundle = 0; |
|
switch (current_bundle_index) |
{ |
case 0: |
/* No instructions. */ |
return; |
case 1: |
if (current_bundle[0].opcode->can_bundle) |
{ |
/* Simplify later logic by adding an explicit fnop. */ |
prepend_nop_to_bundle (TILEPRO_OPC_FNOP); |
} |
else |
{ |
/* This instruction cannot be bundled with anything else. |
Prepend an explicit 'nop', rather than an 'fnop', because |
fnops can be replaced by later binary-processing tools |
while nops cannot. */ |
prepend_nop_to_bundle (TILEPRO_OPC_NOP); |
} |
break; |
default: |
if (!allow_suspicious_bundles) |
{ |
/* Make sure all instructions can be bundled with other |
instructions. */ |
const struct tilepro_opcode *cannot_bundle = NULL; |
bfd_boolean seen_non_nop = FALSE; |
|
for (j = 0; j < current_bundle_index; j++) |
{ |
const struct tilepro_opcode *op = current_bundle[j].opcode; |
|
if (!op->can_bundle && cannot_bundle == NULL) |
cannot_bundle = op; |
else if (op->mnemonic != TILEPRO_OPC_NOP |
&& op->mnemonic != TILEPRO_OPC_INFO |
&& op->mnemonic != TILEPRO_OPC_INFOL) |
seen_non_nop = TRUE; |
} |
|
if (cannot_bundle != NULL && seen_non_nop) |
{ |
current_bundle_index = 0; |
as_bad (_("'%s' may not be bundled with other instructions."), |
cannot_bundle->name); |
return; |
} |
} |
break; |
} |
|
compatible_pipes = |
BUNDLE_TEMPLATE_MASK(current_bundle[0].opcode->pipes, |
current_bundle[1].opcode->pipes, |
(current_bundle_index == 3 |
? current_bundle[2].opcode->pipes |
: (1 << NO_PIPELINE))); |
|
/* Find a template that works, if any. */ |
match = NULL; |
for (i = 0; i < sizeof bundle_templates / sizeof bundle_templates[0]; i++) |
{ |
const struct bundle_template *b = &bundle_templates[i]; |
if ((b->pipe_mask & compatible_pipes) == b->pipe_mask) |
{ |
match = b; |
break; |
} |
} |
|
if (match == NULL) |
{ |
current_bundle_index = 0; |
as_bad (_("Invalid combination of instructions for bundle.")); |
return; |
} |
|
/* If the section seems to have no alignment set yet, go ahead and |
make it large enough to hold code. */ |
if (bfd_get_section_alignment (stdoutput, now_seg) == 0) |
bfd_set_section_alignment (stdoutput, now_seg, |
TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES); |
|
for (j = 0; j < current_bundle_index; j++) |
current_bundle[j].pipe = match->pipe[j]; |
|
if (current_bundle_index == 2 && !tilepro_is_x_pipeline(match->pipe[0])) |
{ |
/* We are in Y mode with only two instructions, so add an FNOP. */ |
prepend_nop_to_bundle (TILEPRO_OPC_FNOP); |
|
/* Figure out what pipe the fnop must be in via arithmetic. |
* p0 + p1 + p2 must sum to the sum of TILEPRO_PIPELINE_Y[012]. */ |
current_bundle[0].pipe = |
(tilepro_pipeline)((TILEPRO_PIPELINE_Y0 |
+ TILEPRO_PIPELINE_Y1 |
+ TILEPRO_PIPELINE_Y2) - |
(current_bundle[1].pipe + current_bundle[2].pipe)); |
} |
|
check_illegal_reg_writes (); |
|
f = frag_more (TILEPRO_BUNDLE_SIZE_IN_BYTES); |
|
/* Check to see if this bundle is at an offset that is a multiple of 8-bytes |
from the start of the frag. */ |
addr_mod = frag_now_fix () & (TILEPRO_BUNDLE_ALIGNMENT_IN_BYTES - 1); |
if (frag_now->has_code && frag_now->insn_addr != addr_mod) |
as_bad (_("instruction address is not a multiple of 8")); |
frag_now->insn_addr = addr_mod; |
frag_now->has_code = 1; |
|
tilepro_bundle_bits bits = 0; |
for (j = 0; j < current_bundle_index; j++) |
{ |
struct tilepro_instruction *instr = ¤t_bundle[j]; |
tilepro_pipeline pipeline = instr->pipe; |
const struct tilepro_opcode *opcode = instr->opcode; |
|
bits |= emit_tilepro_instruction (opcode->fixed_bit_values[pipeline], |
opcode->num_operands, |
&opcode->operands[pipeline][0], |
instr->operand_values, |
f); |
} |
|
number_to_chars_littleendian (f, (unsigned int)bits, 4); |
number_to_chars_littleendian (f + 4, (unsigned int)(bits >> 32), 4); |
current_bundle_index = 0; |
|
/* Emit DWARF2 debugging information. */ |
dwarf2_emit_insn (TILEPRO_BUNDLE_SIZE_IN_BYTES); |
} |
|
|
/* Extend the expression parser to handle hi16(label), etc. |
as well as SPR names when in the context of parsing an SPR. */ |
int |
tilepro_parse_name (char *name, expressionS *e, char *nextcharP) |
{ |
operatorT op = O_illegal; |
|
if (parsing_spr) |
{ |
void *val = hash_find (spr_hash, name); |
if (val == NULL) |
return 0; |
|
memset (e, 0, sizeof *e); |
e->X_op = O_constant; |
e->X_add_number = ((const struct tilepro_spr *)val)->number; |
return 1; |
} |
|
if (*nextcharP != '(') |
{ |
/* hi16, etc. not followed by a paren is just a label with that |
name. */ |
return 0; |
} |
else |
{ |
/* Look up the operator in our table. */ |
void *val = hash_find (special_operator_hash, name); |
if (val == 0) |
return 0; |
op = (operatorT)(long)val; |
} |
|
/* Restore old '(' and skip it. */ |
*input_line_pointer = '('; |
++input_line_pointer; |
|
expression (e); |
|
if (*input_line_pointer != ')') |
{ |
as_bad (_("Missing ')'")); |
*nextcharP = *input_line_pointer; |
return 0; |
} |
/* Skip ')'. */ |
++input_line_pointer; |
|
if (e->X_op == O_register || e->X_op == O_absent) |
{ |
as_bad (_("Invalid expression.")); |
e->X_op = O_constant; |
e->X_add_number = 0; |
} |
else |
{ |
/* Wrap subexpression with a unary operator. */ |
symbolS *sym = make_expr_symbol (e); |
|
if (sym != e->X_add_symbol) |
{ |
/* HACK: mark this symbol as a temporary wrapper around a proper |
expression, so we can unwrap it later once we have communicated |
the relocation type. */ |
sym->sy_value.X_md = 1; |
} |
|
memset (e, 0, sizeof *e); |
e->X_op = op; |
e->X_add_symbol = sym; |
e->X_add_number = 0; |
} |
|
*nextcharP = *input_line_pointer; |
return 1; |
} |
|
|
/* Parses an expression which must be a register name. */ |
|
static void |
parse_reg_expression (expressionS* expression) |
{ |
/* Zero everything to make sure we don't miss any flags. */ |
memset (expression, 0, sizeof *expression); |
|
char* regname = input_line_pointer; |
char terminating_char = get_symbol_end (); |
|
void* pval = hash_find (main_reg_hash, regname); |
|
if (pval == NULL) |
as_bad (_("Expected register, got '%s'."), regname); |
|
int regno_and_flags = (int)(size_t)pval; |
int regno = EXTRACT_REGNO(regno_and_flags); |
|
if ((regno_and_flags & NONCANONICAL_REG_NAME_FLAG) |
&& require_canonical_reg_names) |
as_warn (_("Found use of non-canonical register name %s; " |
"use %s instead."), |
regname, tilepro_register_names[regno]); |
|
/* Restore the old character following the register name. */ |
*input_line_pointer = terminating_char; |
|
/* Fill in the expression fields to indicate it's a register. */ |
expression->X_op = O_register; |
expression->X_add_number = regno; |
} |
|
|
/* Parses and type-checks comma-separated operands in input_line_pointer. */ |
static void |
parse_operands (const char *opcode_name, |
const unsigned char *operands, |
int num_operands, |
expressionS *operand_values) |
{ |
int i; |
|
memset (operand_values, 0, num_operands * sizeof operand_values[0]); |
|
SKIP_WHITESPACE (); |
for (i = 0; i < num_operands; i++) |
{ |
tilepro_operand_type type = tilepro_operands[operands[i]].type; |
|
SKIP_WHITESPACE (); |
|
if (type == TILEPRO_OP_TYPE_REGISTER) |
{ |
parse_reg_expression (&operand_values[i]); |
} |
else if (*input_line_pointer == '}') |
{ |
operand_values[i].X_op = O_absent; |
} |
else if (type == TILEPRO_OP_TYPE_SPR) |
{ |
/* Modify the expression parser to add SPRs to the namespace. */ |
parsing_spr = 1; |
expression (&operand_values[i]); |
parsing_spr = 0; |
} |
else |
{ |
expression (&operand_values[i]); |
} |
|
SKIP_WHITESPACE (); |
|
if (i + 1 < num_operands) |
{ |
int separator = (unsigned char)*input_line_pointer++; |
|
if (is_end_of_line[separator] || (separator == '}')) |
{ |
as_bad (_("Too few operands to '%s'."), opcode_name); |
return; |
} |
else if (separator != ',') |
{ |
as_bad (_("Unexpected character '%c' after operand %d to %s."), |
(char)separator, i + 1, opcode_name); |
return; |
} |
} |
|
/* Arbitrarily use the first valid pipe to get the operand type, |
since they are all the same. */ |
switch (tilepro_operands[operands[i]].type) |
{ |
case TILEPRO_OP_TYPE_REGISTER: |
/* Handled in parse_reg_expression already. */ |
break; |
case TILEPRO_OP_TYPE_SPR: |
/* Fall through */ |
case TILEPRO_OP_TYPE_IMMEDIATE: |
/* Fall through */ |
case TILEPRO_OP_TYPE_ADDRESS: |
if ( operand_values[i].X_op == O_register |
|| operand_values[i].X_op == O_illegal |
|| operand_values[i].X_op == O_absent) |
as_bad (_("Expected immediate expression")); |
break; |
default: |
abort (); |
} |
} |
|
if (!is_end_of_line[(unsigned char)*input_line_pointer]) |
{ |
switch (*input_line_pointer) |
{ |
case '}': |
if (!inside_bundle) |
as_bad (_("Found '}' when not bundling.")); |
++input_line_pointer; |
inside_bundle = 0; |
demand_empty_rest_of_line (); |
break; |
|
case ',': |
as_bad (_("Too many operands")); |
break; |
|
default: |
/* Use default error for unrecognized garbage. */ |
demand_empty_rest_of_line (); |
break; |
} |
} |
} |
|
|
/* This is the guts of the machine-dependent assembler. STR points to a |
machine dependent instruction. This function is supposed to emit |
the frags/bytes it assembles to. */ |
void |
md_assemble (char *str) |
{ |
char old_char; |
size_t opname_len; |
char *old_input_line_pointer; |
const struct tilepro_opcode *op; |
int first_pipe; |
|
/* Split off the opcode and look it up. */ |
opname_len = strcspn (str, " {}"); |
old_char = str[opname_len]; |
str[opname_len] = '\0'; |
|
op = hash_find(op_hash, str); |
str[opname_len] = old_char; |
if (op == NULL) |
{ |
as_bad (_("Unknown opcode `%.*s'."), (int)opname_len, str); |
return; |
} |
|
/* Prepare to parse the operands. */ |
old_input_line_pointer = input_line_pointer; |
input_line_pointer = str + opname_len; |
SKIP_WHITESPACE (); |
|
if (current_bundle_index == TILEPRO_MAX_INSTRUCTIONS_PER_BUNDLE) |
{ |
as_bad (_("Too many instructions for bundle.")); |
tilepro_flush_bundle (); |
} |
|
/* Make sure we have room for the upcoming bundle before we |
create any fixups. Otherwise if we have to switch to a new |
frag the fixup dot_value fields will be wrong. */ |
frag_grow (TILEPRO_BUNDLE_SIZE_IN_BYTES); |
|
/* Find a valid pipe for this opcode. */ |
for (first_pipe = 0; (op->pipes & (1 << first_pipe)) == 0; first_pipe++) |
; |
|
/* Call the function that assembles this instruction. */ |
current_bundle[current_bundle_index].opcode = op; |
parse_operands (op->name, |
&op->operands[first_pipe][0], |
op->num_operands, |
current_bundle[current_bundle_index].operand_values); |
++current_bundle_index; |
|
/* Restore the saved value of input_line_pointer. */ |
input_line_pointer = old_input_line_pointer; |
|
/* If we weren't inside curly braces, go ahead and emit |
this lone instruction as a bundle right now. */ |
if (!inside_bundle) |
tilepro_flush_bundle (); |
} |
|
static void |
s_require_canonical_reg_names (int require) |
{ |
demand_empty_rest_of_line (); |
require_canonical_reg_names = require; |
} |
|
static void |
s_allow_suspicious_bundles (int allow) |
{ |
demand_empty_rest_of_line (); |
allow_suspicious_bundles = allow; |
} |
|
const pseudo_typeS md_pseudo_table[] = |
{ |
{"align", s_align_bytes, 0}, /* Defaulting is invalid (0). */ |
{"word", cons, 4}, |
{"require_canonical_reg_names", s_require_canonical_reg_names, 1 }, |
{"no_require_canonical_reg_names", s_require_canonical_reg_names, 0 }, |
{"allow_suspicious_bundles", s_allow_suspicious_bundles, 1 }, |
{"no_allow_suspicious_bundles", s_allow_suspicious_bundles, 0 }, |
{ NULL, 0, 0 } |
}; |
|
/* Equal to MAX_PRECISION in atof-ieee.c */ |
#define MAX_LITTLENUMS 6 |
|
/* Turn the string pointed to by litP into a floating point constant |
of type TYPE, and emit the appropriate bytes. The number of |
LITTLENUMS emitted is stored in *SIZEP. An error message is |
returned, or NULL on OK. */ |
|
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': |
prec = 2; |
break; |
|
case 'd': |
case 'D': |
prec = 4; |
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); |
/* This loops outputs the LITTLENUMs in REVERSE order; in accord with |
the bigendian 386. */ |
for (wordP = words + prec - 1; prec--;) |
{ |
md_number_to_chars (litP, (valueT) (*wordP--), sizeof (LITTLENUM_TYPE)); |
litP += sizeof (LITTLENUM_TYPE); |
} |
return 0; |
} |
|
|
/* We have no need to default values of symbols. */ |
|
symbolS * |
md_undefined_symbol (char *name ATTRIBUTE_UNUSED) |
{ |
return NULL; |
} |
|
|
void |
tilepro_cons_fix_new (fragS *frag, |
int where, |
int nbytes, |
expressionS *exp) |
{ |
expressionS subexp; |
bfd_reloc_code_real_type reloc = BFD_RELOC_NONE; |
int no_overflow = 0; |
fixS *fixP; |
|
/* See if it's one of our special functions. */ |
switch (exp->X_op) |
{ |
case O_lo16: |
reloc = BFD_RELOC_LO16; |
no_overflow = 1; |
break; |
case O_hi16: |
reloc = BFD_RELOC_HI16; |
no_overflow = 1; |
break; |
case O_ha16: |
reloc = BFD_RELOC_HI16_S; |
no_overflow = 1; |
break; |
|
default: |
/* Do nothing. */ |
break; |
} |
|
if (reloc != BFD_RELOC_NONE) |
{ |
if (nbytes != 2) |
{ |
as_bad (_("This operator only produces two byte values.")); |
nbytes = 2; |
} |
|
memset (&subexp, 0, sizeof subexp); |
subexp.X_op = O_symbol; |
subexp.X_add_symbol = exp->X_add_symbol; |
exp = &subexp; |
} |
else |
{ |
switch (nbytes) |
{ |
case 1: |
reloc = BFD_RELOC_8; |
break; |
case 2: |
reloc = BFD_RELOC_16; |
break; |
case 4: |
reloc = BFD_RELOC_32; |
break; |
case 8: |
reloc = BFD_RELOC_64; |
break; |
default: |
as_bad (_("unsupported BFD relocation size %d"), nbytes); |
reloc = BFD_RELOC_32; |
break; |
} |
} |
|
fixP = fix_new_exp (frag, where, nbytes, exp, 0, reloc); |
fixP->tc_fix_data = NULL; |
fixP->fx_no_overflow |= no_overflow; |
} |
|
|
void |
md_apply_fix (fixS *fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED) |
{ |
const struct tilepro_operand *operand; |
valueT value = *valP; |
char *p; |
|
/* Leave these for the linker. */ |
if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT |
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) |
return; |
|
if (fixP->fx_subsy != (symbolS *) NULL) |
{ |
/* We can't actually support subtracting a symbol. */ |
as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex")); |
} |
|
/* Correct relocation types for pc-relativeness. */ |
switch (fixP->fx_r_type) |
{ |
#define FIX_PCREL(rtype) \ |
case rtype: \ |
if (fixP->fx_pcrel) \ |
fixP->fx_r_type = rtype##_PCREL; \ |
break; \ |
\ |
case rtype##_PCREL: \ |
if (!fixP->fx_pcrel) \ |
fixP->fx_r_type = rtype; \ |
break |
|
FIX_PCREL (BFD_RELOC_8); |
FIX_PCREL (BFD_RELOC_16); |
FIX_PCREL (BFD_RELOC_32); |
FIX_PCREL (BFD_RELOC_TILEPRO_IMM16_X0); |
FIX_PCREL (BFD_RELOC_TILEPRO_IMM16_X1); |
FIX_PCREL (BFD_RELOC_TILEPRO_IMM16_X0_LO); |
FIX_PCREL (BFD_RELOC_TILEPRO_IMM16_X1_LO); |
FIX_PCREL (BFD_RELOC_TILEPRO_IMM16_X0_HI); |
FIX_PCREL (BFD_RELOC_TILEPRO_IMM16_X1_HI); |
FIX_PCREL (BFD_RELOC_TILEPRO_IMM16_X0_HA); |
FIX_PCREL (BFD_RELOC_TILEPRO_IMM16_X1_HA); |
|
#undef FIX_PCREL |
|
default: |
/* Do nothing */ |
break; |
} |
|
if (fixP->fx_addsy != NULL) |
{ |
#ifdef OBJ_ELF |
switch (fixP->fx_r_type) |
{ |
case BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD: |
case BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD: |
case BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE: |
case BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE: |
case BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_LO: |
case BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_LO: |
case BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_LO: |
case BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_LO: |
case BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_HI: |
case BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_HI: |
case BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_HI: |
case BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_HI: |
case BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_HA: |
case BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_HA: |
case BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_HA: |
case BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_HA: |
case BFD_RELOC_TILEPRO_TLS_DTPMOD32: |
case BFD_RELOC_TILEPRO_TLS_DTPOFF32: |
case BFD_RELOC_TILEPRO_TLS_TPOFF32: |
S_SET_THREAD_LOCAL (fixP->fx_addsy); |
break; |
|
default: |
/* Do nothing */ |
break; |
} |
#endif |
return; |
} |
|
/* Apply lo16, hi16, ha16, etc. munging. */ |
switch (fixP->fx_r_type) |
{ |
case BFD_RELOC_TILEPRO_IMM16_X0_GOT: |
case BFD_RELOC_TILEPRO_IMM16_X1_GOT: |
*valP = value = apply_special_operator (O_got, value); |
break; |
|
case BFD_RELOC_TILEPRO_IMM16_X0_GOT_LO: |
case BFD_RELOC_TILEPRO_IMM16_X1_GOT_LO: |
*valP = value = apply_special_operator (O_got_lo16, value); |
break; |
|
case BFD_RELOC_TILEPRO_IMM16_X0_GOT_HI: |
case BFD_RELOC_TILEPRO_IMM16_X1_GOT_HI: |
*valP = value = apply_special_operator (O_got_hi16, value); |
break; |
|
case BFD_RELOC_TILEPRO_IMM16_X0_GOT_HA: |
case BFD_RELOC_TILEPRO_IMM16_X1_GOT_HA: |
*valP = value = apply_special_operator (O_got_ha16, value); |
break; |
|
case BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD: |
case BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD: |
*valP = value = apply_special_operator (O_tls_gd, value); |
break; |
|
case BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE: |
case BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE: |
*valP = value = apply_special_operator (O_tls_ie, value); |
break; |
|
case BFD_RELOC_LO16: |
case BFD_RELOC_TILEPRO_IMM16_X0_LO: |
case BFD_RELOC_TILEPRO_IMM16_X1_LO: |
case BFD_RELOC_TILEPRO_IMM16_X0_LO_PCREL: |
case BFD_RELOC_TILEPRO_IMM16_X1_LO_PCREL: |
*valP = value = apply_special_operator (O_lo16, value); |
break; |
|
case BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_LO: |
case BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_LO: |
*valP = value = apply_special_operator (O_tls_gd_lo16, value); |
break; |
|
case BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_LO: |
case BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_LO: |
*valP = value = apply_special_operator (O_tls_ie_lo16, value); |
break; |
|
case BFD_RELOC_HI16: |
case BFD_RELOC_TILEPRO_IMM16_X0_HI: |
case BFD_RELOC_TILEPRO_IMM16_X1_HI: |
case BFD_RELOC_TILEPRO_IMM16_X0_HI_PCREL: |
case BFD_RELOC_TILEPRO_IMM16_X1_HI_PCREL: |
*valP = value = apply_special_operator (O_hi16, value); |
break; |
|
case BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_HI: |
case BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_HI: |
*valP = value = apply_special_operator (O_tls_gd_hi16, value); |
break; |
|
case BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_HI: |
case BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_HI: |
*valP = value = apply_special_operator (O_tls_ie_hi16, value); |
break; |
|
case BFD_RELOC_HI16_S: |
case BFD_RELOC_TILEPRO_IMM16_X0_HA: |
case BFD_RELOC_TILEPRO_IMM16_X1_HA: |
case BFD_RELOC_TILEPRO_IMM16_X0_HA_PCREL: |
case BFD_RELOC_TILEPRO_IMM16_X1_HA_PCREL: |
*valP = value = apply_special_operator (O_ha16, value); |
break; |
|
case BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_HA: |
case BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_HA: |
*valP = value = apply_special_operator (O_tls_gd_ha16, value); |
break; |
|
case BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_HA: |
case BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_HA: |
*valP = value = apply_special_operator (O_tls_ie_ha16, value); |
break; |
|
default: |
/* Do nothing */ |
break; |
} |
|
p = fixP->fx_frag->fr_literal + fixP->fx_where; |
|
operand = fixP->tc_fix_data; |
if (operand != NULL) |
{ |
/* It's an instruction operand. */ |
tilepro_bundle_bits bits = |
insert_operand (0, operand, value, fixP->fx_file, fixP->fx_line); |
|
/* Note that we might either be writing out bits for a bundle or a |
static network instruction, which are different sizes, so it's |
important to stop touching memory once we run out of bits. ORing in |
values is OK since we know the existing bits for this operand are |
zero. */ |
for (; bits != 0; bits >>= 8) |
*p++ |= (char)bits; |
} |
else |
{ |
/* Some other kind of relocation. */ |
switch (fixP->fx_r_type) |
{ |
case BFD_RELOC_8: |
case BFD_RELOC_8_PCREL: |
md_number_to_chars (p, value, 1); |
break; |
|
case BFD_RELOC_16: |
case BFD_RELOC_16_PCREL: |
md_number_to_chars (p, value, 2); |
break; |
|
case BFD_RELOC_32: |
case BFD_RELOC_32_PCREL: |
md_number_to_chars (p, value, 4); |
break; |
|
default: |
/* Leave it for the linker. */ |
return; |
} |
} |
|
fixP->fx_done = 1; |
} |
|
|
/* Generate the BFD reloc to be stuck in the object file from the |
fixup used internally in the assembler. */ |
|
arelent * |
tc_gen_reloc (asection *sec ATTRIBUTE_UNUSED, fixS *fixp) |
{ |
arelent *reloc; |
|
reloc = (arelent *) xmalloc (sizeof (arelent)); |
reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); |
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); |
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; |
|
/* Make sure none of our internal relocations make it this far. |
They'd better have been fully resolved by this point. */ |
gas_assert ((int) fixp->fx_r_type > 0); |
|
reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); |
if (reloc->howto == NULL) |
{ |
as_bad_where (fixp->fx_file, fixp->fx_line, |
_("cannot represent `%s' relocation in object file"), |
bfd_get_reloc_code_name (fixp->fx_r_type)); |
return NULL; |
} |
|
if (!fixp->fx_pcrel != !reloc->howto->pc_relative) |
{ |
as_fatal (_("internal error? cannot generate `%s' relocation (%d, %d)"), |
bfd_get_reloc_code_name (fixp->fx_r_type), |
fixp->fx_pcrel, reloc->howto->pc_relative); |
} |
gas_assert (!fixp->fx_pcrel == !reloc->howto->pc_relative); |
|
reloc->addend = fixp->fx_offset; |
|
return reloc; |
} |
|
|
/* The location from which a PC relative jump should be calculated, |
given a PC relative reloc. */ |
|
long |
md_pcrel_from (fixS *fixP) |
{ |
return fixP->fx_frag->fr_address + fixP->fx_where; |
} |
|
|
/* Return 1 if it's OK to adjust a reloc by replacing the symbol with |
a section symbol plus some offset. */ |
int |
tilepro_fix_adjustable (fixS *fix) |
{ |
/* Prevent all adjustments to global symbols */ |
if (S_IS_EXTERNAL (fix->fx_addsy) || S_IS_WEAK (fix->fx_addsy)) |
return 0; |
|
return 1; |
} |
|
|
int |
tilepro_unrecognized_line (int ch) |
{ |
switch (ch) |
{ |
case '{': |
if (inside_bundle) |
{ |
as_bad (_("Found '{' when already bundling.")); |
} |
else |
{ |
inside_bundle = 1; |
current_bundle_index = 0; |
} |
return 1; |
|
case '}': |
if (!inside_bundle) |
{ |
as_bad (_("Found '}' when not bundling.")); |
} |
else |
{ |
tilepro_flush_bundle (); |
} |
|
/* Allow '{' to follow on the same line. We also allow ";;", but that |
happens automatically because ';' is an end of line marker. */ |
SKIP_WHITESPACE (); |
if (input_line_pointer[0] == '{') |
{ |
input_line_pointer++; |
return tilepro_unrecognized_line ('{'); |
} |
|
demand_empty_rest_of_line (); |
return 1; |
|
default: |
break; |
} |
|
/* Not a valid line. */ |
return 0; |
} |
|
|
/* This is called from HANDLE_ALIGN in write.c. Fill in the contents |
of an rs_align_code fragment. */ |
|
void |
tilepro_handle_align (fragS *fragp) |
{ |
int bytes, fix; |
char *p; |
|
if (fragp->fr_type != rs_align_code) |
return; |
|
bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix; |
p = fragp->fr_literal + fragp->fr_fix; |
fix = 0; |
|
/* Determine the bits for NOP. */ |
const struct tilepro_opcode *nop_opcode = |
&tilepro_opcodes[TILEPRO_OPC_NOP]; |
tilepro_bundle_bits nop = |
( nop_opcode->fixed_bit_values[TILEPRO_PIPELINE_X0] |
| nop_opcode->fixed_bit_values[TILEPRO_PIPELINE_X1]); |
|
if ((bytes & (TILEPRO_BUNDLE_SIZE_IN_BYTES - 1)) != 0) |
{ |
fix = bytes & (TILEPRO_BUNDLE_SIZE_IN_BYTES - 1); |
memset (p, 0, fix); |
p += fix; |
bytes -= fix; |
} |
|
number_to_chars_littleendian (p, (unsigned int)nop, 4); |
number_to_chars_littleendian (p + 4, (unsigned int)(nop >> 32), 4); |
fragp->fr_fix += fix; |
fragp->fr_var = TILEPRO_BUNDLE_SIZE_IN_BYTES; |
} |
|
/* Standard calling conventions leave the CFA at SP on entry. */ |
void |
tilepro_cfi_frame_initial_instructions (void) |
{ |
cfi_add_CFA_def_cfa_register (54); |
} |
|
int |
tc_tilepro_regname_to_dw2regnum (char *regname) |
{ |
int i; |
|
for (i = 0; i < TILEPRO_NUM_REGISTERS; i++) |
{ |
if (!strcmp (regname, tilepro_register_names[i])) |
return i; |
} |
|
return -1; |
} |
/tc-tilepro.h
0,0 → 1,93
/* tc-tile.h - Macros and type defines for a TILEPro chip. |
Copyright 2011 Free Software Foundation, Inc. |
|
This file is part of GAS, the GNU Assembler. |
|
This program 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 3 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
MA 02110-1301, USA. */ |
|
#ifndef TC_TILEPRO |
|
#include "opcode/tilepro.h" |
|
#define TC_TILEPRO |
|
#define TARGET_BYTES_BIG_ENDIAN 0 |
|
#define WORKING_DOT_WORD |
|
#define TARGET_ARCH bfd_arch_tilepro |
|
#define TARGET_FORMAT "elf32-tilepro" |
|
|
#define DWARF2_LINE_MIN_INSN_LENGTH 8 |
|
#define md_number_to_chars number_to_chars_littleendian |
|
#define DIFF_EXPR_OK /* foo-. gets turned into PC relative relocs */ |
|
#define HANDLE_ALIGN(fragp) tilepro_handle_align (fragp) |
extern void tilepro_handle_align (struct frag *); |
|
#define MAX_MEM_FOR_RS_ALIGN_CODE (7 + 8) |
|
struct tilepro_operand; |
#define TC_FIX_TYPE const struct tilepro_operand * |
|
/* Initialize the TC_FIX_TYPE field. */ |
#define TC_INIT_FIX_DATA(FIX) \ |
FIX->tc_fix_data = 0 |
|
extern void tilepro_cons_fix_new (struct frag *, int, |
int, struct expressionS *); |
|
#define TC_CONS_FIX_NEW(FRAG, WHERE, NBYTES, EXP) \ |
tilepro_cons_fix_new (FRAG, WHERE, NBYTES, EXP) |
|
extern int tilepro_parse_name (char *, expressionS *, char *); |
#define md_parse_name(name, e, m, nextP) tilepro_parse_name (name, e, nextP) |
|
extern int tilepro_fix_adjustable (struct fix *); |
#define tc_fix_adjustable(FIX) tilepro_fix_adjustable (FIX) |
|
extern int tilepro_unrecognized_line (int); |
#define tc_unrecognized_line(ch) tilepro_unrecognized_line (ch) |
|
/* Values passed to md_apply_fix3 don't include the symbol value. */ |
#define MD_APPLY_SYM_VALUE(FIX) 0 |
|
#define md_convert_frag(b,s,f) \ |
as_fatal ("tilepro convert_frag called") |
#define md_estimate_size_before_relax(f,s) \ |
(as_fatal ("tilepro estimate_size_before_relax called"),1) |
#define md_operand(x) |
|
#define md_section_align(seg,size) (size) |
|
/* We want .cfi_* pseudo-ops for generating unwind info. */ |
#define TARGET_USE_CFIPOP 1 |
|
#define tc_cfi_frame_initial_instructions \ |
tilepro_cfi_frame_initial_instructions |
extern void tilepro_cfi_frame_initial_instructions (void); |
|
#define tc_regname_to_dw2regnum tc_tilepro_regname_to_dw2regnum |
extern int tc_tilepro_regname_to_dw2regnum (char *); |
|
#define DWARF2_DEFAULT_RETURN_COLUMN 55 |
#define DWARF2_CIE_DATA_ALIGNMENT (-4) |
|
#endif /* TC_TILEPRO */ |
/tc-score7.c
1,5 → 1,5
/* tc-score7.c -- Assembler for Score7 |
Copyright 2009 Free Software Foundation, Inc. |
Copyright 2009, 2011 Free Software Foundation, Inc. |
Contributed by: |
Brain.lin (brain.lin@sunplusct.com) |
Mei Ligang (ligang@sunnorth.com.cn) |
1260,12 → 1260,12
s7_my_get_expression (expressionS * ep, char **str) |
{ |
char *save_in; |
segT seg; |
|
save_in = input_line_pointer; |
input_line_pointer = *str; |
s7_in_my_get_expression = 1; |
seg = expression (ep); |
|
(void) expression (ep); |
s7_in_my_get_expression = 0; |
|
if (ep->X_op == O_illegal) |
3096,7 → 3096,6
int conflict_reg; |
int value; |
char * temp; |
char *strbak; |
char *dataptr; |
int reg; |
int ldst_idx = 0; |
3103,7 → 3102,6
|
int hex_p = 0; |
|
strbak = str; |
s7_skip_whitespace (str); |
|
if (((conflict_reg = s7_reg_required_here (&str, 20, s7_REG_TYPE_SCORE)) == (int) s7_FAIL) |
5244,8 → 5242,6
{ |
int grows = 0; |
int relaxable_p = 0; |
int r_old; |
int r_new; |
int frag_addr = fragp->fr_address + fragp->insn_addr; |
|
addressT symbol_address = 0; |
5259,8 → 5255,6
so in relax stage , it may be wrong to calculate the symbol's offset when the frag's section |
is different from the symbol's. */ |
|
r_old = s7_RELAX_OLD (fragp->fr_subtype); |
r_new = s7_RELAX_NEW (fragp->fr_subtype); |
relaxable_p = s7_RELAX_OPT (fragp->fr_subtype); |
|
s = fragp->fr_symbol; |
5648,7 → 5642,6
/* Generate a .pdr section. */ |
segT saved_seg = now_seg; |
subsegT saved_subseg = now_subseg; |
valueT dot; |
expressionS exp; |
char *fragp; |
|
5699,7 → 5692,7
|
else |
{ |
dot = frag_now_fix (); |
(void) frag_now_fix (); |
gas_assert (s7_pdr_seg); |
subseg_set (s7_pdr_seg, 0); |
/* Write the symbol. */ |
6376,7 → 6369,6
{ |
int grows = 0; |
int insn_size; |
int insn_relax_size; |
int do_relax_p = 0; /* Indicate doing relaxation for this frag. */ |
int relaxable_p = 0; |
bfd_boolean word_align_p = FALSE; |
6396,15 → 6388,9
|
/* Get instruction size and relax size after the last relaxation. */ |
if (fragp->fr_opcode) |
{ |
insn_size = s7_RELAX_NEW (fragp->fr_subtype); |
insn_relax_size = s7_RELAX_OLD (fragp->fr_subtype); |
} |
insn_size = s7_RELAX_NEW (fragp->fr_subtype); |
else |
{ |
insn_size = s7_RELAX_OLD (fragp->fr_subtype); |
insn_relax_size = s7_RELAX_NEW (fragp->fr_subtype); |
} |
insn_size = s7_RELAX_OLD (fragp->fr_subtype); |
|
/* Handle specially for s7_GP instruction. for, s7_judge_size_before_relax() has already determine |
whether the s7_GP instruction should do relax. */ |
6891,9 → 6877,6
arelent *reloc; |
bfd_reloc_code_real_type code; |
char *type; |
fragS *f; |
symbolS *s; |
expressionS e; |
|
reloc = retval[0] = xmalloc (sizeof (arelent)); |
retval[1] = NULL; |
6932,10 → 6915,6
*retval[1]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); |
retval[1]->address = (reloc->address + s7_RELAX_RELOC2 (fixp->fx_frag->fr_subtype)); |
|
f = fixp->fx_frag; |
s = f->fr_symbol; |
e = s->sy_value; |
|
retval[1]->addend = 0; |
retval[1]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_LO16); |
gas_assert (retval[1]->howto != NULL); |
/tc-score.c
1,5 → 1,5
/* tc-score.c -- Assembler for Score |
Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc. |
Copyright 2006, 2007, 2008, 2009, 2011 Free Software Foundation, Inc. |
Contributed by: |
Brain.lin (brain.lin@sunplusct.com) |
Mei Ligang (ligang@sunnorth.com.cn) |
130,8 → 130,8
static void s3_do16_rdi5 (char *); |
static void s3_do16_xi5 (char *); |
static void s3_do16_ldst_insn (char *); |
static void s3_do16_slli_srli(char *); |
static void s3_do16_ldiu(char *); |
static void s3_do16_slli_srli (char *); |
static void s3_do16_ldiu (char *); |
static void s3_do16_push_pop (char *); |
static void s3_do16_rpush (char *); |
static void s3_do16_rpop (char *); |
531,9 → 531,9
{_IMM16_pic, 16, {0, (1 << 16) - 1}}, /* ( 0 ~ 65535) */ |
{_SIMM5, 5, {-(1 << 4), (1 << 4) - 1}}, /* ( -16 ~ 15 ) */ |
{_SIMM6, 6, {-(1 << 5), (1 << 5) - 1}}, /* ( -32 ~ 31 ) */ |
{_IMM32, 32, {0, 0xfffffff}}, |
{_SIMM32, 32, {-0x80000000, 0x7fffffff}}, |
{_IMM11, 11, {0, (1 << 11) - 1}}, |
{_IMM32, 32, {0, 0xfffffff}}, |
{_SIMM32, 32, {-0x80000000, 0x7fffffff}}, |
{_IMM11, 11, {0, (1 << 11) - 1}}, |
}; |
|
struct s3_asm_opcode |
557,7 → 557,7
void (*parms) (char *); |
}; |
|
static const struct s3_asm_opcode s3_score_ldst_insns[] = |
static const struct s3_asm_opcode s3_score_ldst_insns[] = |
{ |
{"lw", 0x20000000, 0x3e000000, 0x1000, Rd_rvalueRs_SI15, s3_do_ldst_insn}, |
{"lw", 0x06000000, 0x3e000007, 0x8000, Rd_rvalueRs_preSI12, s3_do_ldst_insn}, |
585,7 → 585,7
{"sb", 0x0e000007, 0x3e000007, 0x8000, Rd_lvalueRs_postSI12, s3_do_ldst_insn}, |
}; |
|
static const struct s3_asm_opcode s3_score_insns[] = |
static const struct s3_asm_opcode s3_score_insns[] = |
{ |
{"abs", 0x3800000a, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_dsp3}, |
{"abs.s", 0x3800004b, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_dsp3}, |
691,7 → 691,7
{"brccl", 0x00000409, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs}, |
{"brgtul", 0x00000809, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs}, |
{"brleul", 0x00000c09, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs}, |
{"breql", 0x00001009, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs}, |
{"breql", 0x00001009, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs}, |
{"brnel", 0x00001409, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs}, |
{"brgtl", 0x00001809, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs}, |
{"brlel", 0x00001c09, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs}, |
749,8 → 749,8
/* s3_inst.relax */ |
{"ldi", 0x020c0000, 0x3e0e0000, 0x6400, Rd_SI16, s3_do_rdsi16}, |
{"ldis", 0x0a0c0000, 0x3e0e0000, 0x8000, Rd_I16, s3_do_ldis}, |
|
/* ldi <-> ldiu!. */ |
|
/* ldi <-> ldiu!. */ |
{"ldiu!", 0x6400, 0x7c00, 0x8000, Rd_I5, s3_do16_ldiu}, |
|
/*ltbb! , ltbh! ltbw! */ |
954,9 → 954,9
{"li", 0x020c0000, 0x3e0e0000, 0x8000, Insn_Type_SYN, s3_do_macro_li_rdi32}, |
|
/* la reg, imm32 -->(1) ldi reg, simm16 |
(2) ldis reg, %HI(imm32) |
ori reg, %LO(imm32) |
|
(2) ldis reg, %HI(imm32) |
ori reg, %LO(imm32) |
|
la reg, symbol -->(1) lis reg, %HI(imm32) |
ori reg, %LO(imm32) */ |
{"la", 0x020c0000, 0x3e0e0000, 0x8000, Insn_Type_SYN, s3_do_macro_la_rdi32}, |
1143,7 → 1143,7
{ |
/* Check mulr, mulur rd is even number. */ |
if (((s3_inst.instruction & 0x3e0003ff) == 0x00000340 |
|| (s3_inst.instruction & 0x3e0003ff) == 0x00000342) |
|| (s3_inst.instruction & 0x3e0003ff) == 0x00000342) |
&& (reg % 2)) |
{ |
s3_inst.error = _("rd must be even number."); |
1176,7 → 1176,7
if (symbol_get_value_expression (sp)->X_add_symbol) |
return (s3_walk_no_bignums (symbol_get_value_expression (sp)->X_add_symbol) |
|| (symbol_get_value_expression (sp)->X_op_symbol |
&& s3_walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol))); |
&& s3_walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol))); |
|
return 0; |
} |
1185,12 → 1185,11
s3_my_get_expression (expressionS * ep, char **str) |
{ |
char *save_in; |
segT seg; |
|
save_in = input_line_pointer; |
input_line_pointer = *str; |
s3_in_my_get_expression = 1; |
seg = expression (ep); |
(void) expression (ep); |
s3_in_my_get_expression = 0; |
|
if (ep->X_op == O_illegal) |
1305,18 → 1304,12
|
case _IMM5_MULTI_LOAD: |
if (val >= 2 && val <= 32) |
{ |
{ |
if (val == 32) |
{ |
val = 0; |
} |
val = 0; |
return val; |
} |
else |
{ |
return (int) s3_FAIL; |
} |
break; |
} |
return (int) s3_FAIL; |
|
case _IMM32: |
if (val >= 0 && val <= 0xffffffff) |
1393,10 → 1386,10
} |
dataptr = (char *)data_exp; |
|
if ((dataptr != NULL) |
if ((dataptr != NULL) |
&& (((strstr (dataptr, "0x")) != NULL) |
|| ((strstr (dataptr, "0X")) != NULL))) |
{ |
{ |
hex_p = 1; |
if ((data_type != _SIMM16_LA) |
&& (data_type != _VALUE_HI16) |
1431,9 → 1424,9
&& (s3_inst.type != Rd_lvalueRs_SI15) |
&& (s3_inst.type != Insn_internal) |
&& (((*dataptr >= 'a') && (*dataptr <= 'z')) |
|| ((*dataptr == '0') && (*(dataptr + 1) == 'x') && (*(dataptr + 2) != '0')) |
|| ((*dataptr == '+') && (*(dataptr + 1) != '0')) |
|| ((*dataptr == '-') && (*(dataptr + 1) != '0')))) |
|| ((*dataptr == '0') && (*(dataptr + 1) == 'x') && (*(dataptr + 2) != '0')) |
|| ((*dataptr == '+') && (*(dataptr + 1) != '0')) |
|| ((*dataptr == '-') && (*(dataptr + 1) != '0')))) |
{ |
s3_inst.error = s3_BAD_ARGS; |
return (int) s3_FAIL; |
1600,7 → 1593,9
else if ((s3_inst.instruction & 0x02040001) == 0x02040001) |
{ |
/* imm <=0x3f (5 bit<<1)*/ |
if (((s3_inst.instruction & 0x1ffe0)==0)||(((s3_inst.instruction & 0x1ffe0) == 0x1ffe0)&&(s3_inst.instruction & 0x003e) !=0)) |
if (((s3_inst.instruction & 0x1ffe0) == 0) |
|| (((s3_inst.instruction & 0x1ffe0) == 0x1ffe0) |
&& (s3_inst.instruction & 0x003e) != 0)) |
{ |
s3_inst.relax_inst |= (s3_inst.instruction >> 1) & 0x1f; |
s3_inst.relax_inst |= (((s3_inst.instruction >> 20) & 0x1f) << 5); |
1613,11 → 1608,13
} |
} |
/* addi */ |
else if (((s3_inst.instruction & 0x2000000) == 0x02000000)&& (s3_inst.relax_inst!=0x8000)) |
else if (((s3_inst.instruction & 0x2000000) == 0x02000000) && (s3_inst.relax_inst!=0x8000)) |
{ |
/* rd : 0-16 ; imm <=0x7f (6 bit<<1)*/ |
if ((((s3_inst.instruction >> 20) & 0x10) != 0x10) && |
(((s3_inst.instruction & 0x1ffc0)==0)||(((s3_inst.instruction & 0x1ffc0) == 0x1ffc0)&&(s3_inst.instruction & 0x007e) !=0))) |
if ((((s3_inst.instruction >> 20) & 0x10) != 0x10) |
&& (((s3_inst.instruction & 0x1ffc0) == 0) |
|| (((s3_inst.instruction & 0x1ffc0) == 0x1ffc0) |
&& (s3_inst.instruction & 0x007e) != 0))) |
{ |
s3_inst.relax_inst |= (s3_inst.instruction >> 1) & 0x3f; |
s3_inst.relax_inst |= (((s3_inst.instruction >> 20) & 0xf) << 6); |
1626,7 → 1623,6
else |
{ |
s3_inst.relax_inst =0x8000; |
|
} |
} |
|
1702,7 → 1698,7
/* Handle bitclr.c/bitset.c/bittgl.c/slli.c/srai.c/srli.c/roli.c/rori.c/rolic.c. |
0~((2^14)-1) */ |
static void |
s3_do_rdrsi5 (char *str) |
s3_do_rdrsi5 (char *str) |
{ |
s3_skip_whitespace (str); |
|
1796,7 → 1792,7
/* rd : 0-16 ;imm =0 -> can transform to addi!*/ |
if ((((s3_inst.instruction >> 20) & 0x10) != 0x10) && ((s3_inst.instruction & 0x1ffff)==0)) |
{ |
s3_inst.relax_inst =0x5c00; /* addi! */ |
s3_inst.relax_inst =0x5c00; /* addi! */ |
s3_inst.relax_inst |= (s3_inst.instruction >> 1) & 0x3f; |
s3_inst.relax_inst |= (((s3_inst.instruction >> 20) & 0xf) << 6); |
s3_inst.relax_size = 2; |
1915,7 → 1911,7
|
if (s3_inst.relax_inst != 0x8000) |
{ |
s3_inst.relax_inst |= ((s3_inst.instruction >> 15) & 0x1f) ; |
s3_inst.relax_inst |= ((s3_inst.instruction >> 15) & 0x1f); |
s3_inst.relax_size = 2; |
} |
} |
1937,8 → 1933,7
{ |
/* mv! rd : 5bit , ra : 5bit */ |
s3_inst.relax_inst |= ((s3_inst.instruction >> 15) & 0x1f) | (((s3_inst.instruction >> 20) & 0x1f) << 5); |
s3_inst.relax_size = 2; |
|
s3_inst.relax_size = 2; |
} |
else if ((((s3_inst.instruction >> 15) & 0x10) == 0x0) && (((s3_inst.instruction >> 20) & 0x10) == 0)) |
{ |
2219,7 → 2214,7
|
static int |
s3_check_dependency (char *pre_insn, char *pre_reg, |
char *cur_insn, char *cur_reg, int *warn_or_error) |
char *cur_insn, char *cur_reg, int *warn_or_error) |
{ |
int bubbles = 0; |
unsigned int i; |
2277,7 → 2272,7
|
p = frag_var (rs_machine_dependent, relax_size + s3_RELAX_PAD_BYTE, 0, |
s3_RELAX_ENCODE (one_inst.size, one_inst.relax_size, |
one_inst.type, 0, 0, relaxable_p), |
one_inst.type, 0, 0, relaxable_p), |
NULL, 0, NULL); |
|
if (relaxable_p) |
2337,7 → 2332,7
strcpy (pre_insn, s3_dependency_vector[i].name); |
|
bubbles = s3_check_dependency (pre_insn, s3_dependency_vector[i].reg, |
cur_insn, s3_dependency_vector[0].reg, &warn_or_error); |
cur_insn, s3_dependency_vector[0].reg, &warn_or_error); |
remainder_bubbles = bubbles - i + 1; |
|
if (remainder_bubbles > 0) |
2385,9 → 2380,9
if (warn_or_error) |
{ |
as_bad (_("data dependency: %s %s -- %s %s (%d/%d bubble)"), |
s3_dependency_vector[i].name, s3_dependency_vector[i].reg, |
s3_dependency_vector[0].name, s3_dependency_vector[0].reg, |
remainder_bubbles, bubbles); |
s3_dependency_vector[i].name, s3_dependency_vector[i].reg, |
s3_dependency_vector[0].name, s3_dependency_vector[0].reg, |
remainder_bubbles, bubbles); |
} |
else |
{ |
2509,8 → 2504,8
m_code_middle = m_code & 0x3fff8000; |
m_code_low = m_code & 0x00007fff; |
result = pb_high | (m_code_high << 2) | |
pb_middle | (m_code_middle << 1) | |
pb_low | m_code_low; |
pb_middle | (m_code_middle << 1) | |
pb_low | m_code_low; |
} |
else if (i_class == INSN_CLASS_32 || i_class == INSN_CLASS_SYN) |
{ |
2563,7 → 2558,7
if (pce_p) |
{ |
backup_inst1.instruction = ((backup_inst1.instruction & 0x7FFF) << 15) |
| (inst2->instruction & 0x7FFF); |
| (inst2->instruction & 0x7FFF); |
backup_inst1.instruction = s3_adjust_paritybit (backup_inst1.instruction, INSN_CLASS_PCE); |
backup_inst1.relax_inst = 0x8000; |
backup_inst1.size = s3_INSN_SIZE; |
2573,7 → 2568,7
else |
{ |
backup_inst1.instruction = s3_adjust_paritybit (backup_inst1.instruction, |
s3_GET_INSN_CLASS (backup_inst1.type)); |
s3_GET_INSN_CLASS (backup_inst1.type)); |
} |
|
if (backup_inst1.relax_size != 0) |
2617,19 → 2612,19
{ |
if (inst1->reloc.type != BFD_RELOC_NONE) |
s3_fix_new_score (frag_now, p - frag_now->fr_literal, |
inst1->size, &inst1->reloc.exp, |
inst1->reloc.pc_rel, inst1->reloc.type); |
inst1->size, &inst1->reloc.exp, |
inst1->reloc.pc_rel, inst1->reloc.type); |
|
if (inst2->reloc.type != BFD_RELOC_NONE) |
s3_fix_new_score (frag_now, p - frag_now->fr_literal + 2, |
inst2->size, &inst2->reloc.exp, inst2->reloc.pc_rel, inst2->reloc.type); |
inst2->size, &inst2->reloc.exp, inst2->reloc.pc_rel, inst2->reloc.type); |
} |
else |
{ |
if (backup_inst1.reloc.type != BFD_RELOC_NONE) |
s3_fix_new_score (frag_now, p - frag_now->fr_literal, |
backup_inst1.size, &backup_inst1.reloc.exp, |
backup_inst1.reloc.pc_rel, backup_inst1.reloc.type); |
backup_inst1.size, &backup_inst1.reloc.exp, |
backup_inst1.reloc.pc_rel, backup_inst1.reloc.type); |
} |
|
/* relax_size may be 2, 4, 12 or 0, 0 indicates no relaxation. */ |
2638,7 → 2633,7
|
p = frag_var (rs_machine_dependent, relax_size + s3_RELAX_PAD_BYTE, 0, |
s3_RELAX_ENCODE (backup_inst1.size, backup_inst1.relax_size, |
backup_inst1.type, 0, 0, relaxable_p), |
backup_inst1.type, 0, 0, relaxable_p), |
backup_inst1.reloc.exp.X_add_symbol, 0, NULL); |
|
if (relaxable_p) |
2940,12 → 2935,10
int conflict_reg; |
int value; |
char * temp; |
char *strbak; |
char *dataptr; |
int reg; |
int ldst_idx = 0; |
|
strbak = str; |
s3_skip_whitespace (str); |
|
if (((conflict_reg = s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE)) == (int) s3_FAIL) |
3075,9 → 3068,9
|
/* lw/lh/lbu/sw/sh/sb, offset = 0, relax to 16 bit instruction. */ |
/* if ((ldst_idx == INSN_LBU) |
|| (ldst_idx == INSN_LH) |
|| (ldst_idx == INSN_LW) |
|| (ldst_idx == INSN_SB) || (ldst_idx == INSN_SH) || (ldst_idx == INSN_SW))*/ |
|| (ldst_idx == INSN_LH) |
|| (ldst_idx == INSN_LW) |
|| (ldst_idx == INSN_SB) || (ldst_idx == INSN_SH) || (ldst_idx == INSN_SW))*/ |
if ( (ldst_idx == INSN_LW)|| (ldst_idx == INSN_SW)) |
{ |
/* ra only 3 bit , rd only 4 bit for lw! and sw! */ |
3410,8 → 3403,7
static void |
s3_do16_ldst_insn (char *str) |
{ |
int conflict_reg=0; |
char * temp; |
int conflict_reg = 0; |
s3_skip_whitespace (str); |
|
if ((s3_reglow_required_here (&str, 8) == (int) s3_FAIL) || (s3_skip_past_comma (&str) == (int) s3_FAIL)) |
3428,12 → 3420,12
if (conflict_reg&0x8) |
{ |
sprintf (s3_err_msg, _("invalid register number: %d is not in [r0--r7]"),conflict_reg); |
s3_inst.error=s3_err_msg; |
return ; |
s3_inst.error = s3_err_msg; |
return; |
} |
|
s3_skip_whitespace (str); |
temp = str + 1; /* The latter will process decimal/hex expression. */ |
|
if (*str == ']') |
{ |
str++; |
3464,33 → 3456,32
data_type = _IMM5_RSHIFT_2; |
value = s3_validate_immediate (s3_inst.reloc.exp.X_add_number, data_type, 0); |
if (value == (int) s3_FAIL) |
{ |
if (data_type < 30) |
sprintf (s3_err_msg, |
_("invalid constant: %d bit expression not in range %d..%d"), |
s3_score_df_range[data_type].bits, |
s3_score_df_range[data_type].range[0], s3_score_df_range[data_type].range[1]); |
{ |
if (data_type < 30) |
sprintf (s3_err_msg, |
_("invalid constant: %d bit expression not in range %d..%d"), |
s3_score_df_range[data_type].bits, |
s3_score_df_range[data_type].range[0], s3_score_df_range[data_type].range[1]); |
s3_inst.error = s3_err_msg; |
return; |
} |
if (value &0x3) |
if (value & 0x3) |
{ |
sprintf (s3_err_msg, _("invalid constant: %d is not word align integer"),value); |
s3_inst.error=s3_err_msg; |
return ; |
s3_inst.error = s3_err_msg; |
return; |
} |
|
value >>=2; |
value >>= 2; |
s3_inst.instruction |= value; |
} |
} |
|
} |
else |
{ |
sprintf (s3_err_msg, _("missing [")); |
s3_inst.error=s3_err_msg; |
return ; |
s3_inst.error = s3_err_msg; |
return; |
} |
} |
|
3648,7 → 3639,7
return; |
} |
|
static void |
static void |
s3_do_mbitclr (char *str) |
{ |
int val; |
3657,7 → 3648,7
if (*str != '[') |
{ |
sprintf (s3_err_msg, _("missing [")); |
s3_inst.error=s3_err_msg; |
s3_inst.error = s3_err_msg; |
return; |
} |
str++; |
3678,7 → 3669,7
if (*str != ']') |
{ |
sprintf (s3_err_msg, _("missing ]")); |
s3_inst.error=s3_err_msg; |
s3_inst.error = s3_err_msg; |
return; |
} |
str++; |
3689,11 → 3680,11
|
/* Set imm11 to opcode. */ |
s3_inst.instruction |= (val & 0x1) |
| (((val >> 1 ) & 0x7) << 7) |
| (((val >> 4 ) & 0x1f) << 20); |
| (((val >> 1 ) & 0x7) << 7) |
| (((val >> 4 ) & 0x1f) << 20); |
} |
|
static void |
static void |
s3_do_mbitset (char *str) |
{ |
int val; |
3702,7 → 3693,7
if (*str != '[') |
{ |
sprintf (s3_err_msg, _("missing [")); |
s3_inst.error=s3_err_msg; |
s3_inst.error = s3_err_msg; |
return; |
} |
str++; |
3723,7 → 3714,7
if (*str != ']') |
{ |
sprintf (s3_err_msg, _("missing ]")); |
s3_inst.error=s3_err_msg; |
s3_inst.error = s3_err_msg; |
return; |
} |
str++; |
3734,8 → 3725,8
|
/* Set imm11 to opcode. */ |
s3_inst.instruction |= (val & 0x1) |
| (((val >> 1 ) & 0x7) << 7) |
| (((val >> 4 ) & 0x1f) << 20); |
| (((val >> 1 ) & 0x7) << 7) |
| (((val >> 4 ) & 0x1f) << 20); |
} |
|
static void |
3746,7 → 3737,7
if ((s3_reglow_required_here (&str, 5) == (int) s3_FAIL) |
|| (s3_skip_past_comma (&str) == (int) s3_FAIL) |
|| s3_data_op2 (&str, 0, _IMM5) == (int) s3_FAIL |
|| s3_end_of_line (str) == (int) s3_FAIL) |
|| s3_end_of_line (str) == (int) s3_FAIL) |
return; |
} |
|
3758,7 → 3749,7
if ((s3_reg_required_here (&str, 5,s3_REG_TYPE_SCORE) == (int) s3_FAIL) |
|| (s3_skip_past_comma (&str) == (int) s3_FAIL) |
|| s3_data_op2 (&str, 0, _IMM5) == (int) s3_FAIL |
|| s3_end_of_line (str) == (int) s3_FAIL) |
|| s3_end_of_line (str) == (int) s3_FAIL) |
return; |
} |
|
3767,7 → 3758,7
{ |
s3_skip_whitespace (str); |
if ((s3_reg_required_here (&str, 0, s3_REG_TYPE_SCORE)) == (int) s3_FAIL |
|| s3_end_of_line (str) == (int) s3_FAIL) |
|| s3_end_of_line (str) == (int) s3_FAIL) |
return; |
} |
|
3780,17 → 3771,17
if ((reg = (s3_reg_required_here (&str, 5, s3_REG_TYPE_SCORE))) == (int) s3_FAIL |
|| s3_skip_past_comma (&str) == (int) s3_FAIL |
|| s3_data_op2 (&str, 0, _IMM5_MULTI_LOAD) == (int) s3_FAIL |
|| s3_end_of_line (str) == (int) s3_FAIL) |
|| s3_end_of_line (str) == (int) s3_FAIL) |
return; |
|
/* 0: indicate 32. |
1: invalide value. |
2: to 31: normal value. */ |
val = s3_inst.instruction & 0x1f; |
val = s3_inst.instruction & 0x1f; |
if (val == 1) |
{ |
s3_inst.error = _("imm5 should >= 2"); |
return; |
s3_inst.error = _("imm5 should >= 2"); |
return; |
} |
if (reg >= 32) |
{ |
3808,7 → 3799,7
if ((reg = (s3_reg_required_here (&str, 5, s3_REG_TYPE_SCORE))) == (int) s3_FAIL |
|| s3_skip_past_comma (&str) == (int) s3_FAIL |
|| s3_data_op2 (&str, 0, _IMM5_MULTI_LOAD) == (int) s3_FAIL |
|| s3_end_of_line (str) == (int) s3_FAIL) |
|| s3_end_of_line (str) == (int) s3_FAIL) |
return; |
|
/* 0: indicate 32. |
3826,7 → 3817,7
s3_inst.error = _("reg should <= 31"); |
return; |
} |
else |
else |
{ |
if ((reg + val) <= 32) |
reg = reg + val - 1; |
3984,8 → 3975,8
|
static void |
s3_build_relax_frag (struct s3_score_it fix_insts[s3_RELAX_INST_NUM], int fix_num ATTRIBUTE_UNUSED, |
struct s3_score_it var_insts[s3_RELAX_INST_NUM], int var_num, |
symbolS *add_symbol) |
struct s3_score_it var_insts[s3_RELAX_INST_NUM], int var_num, |
symbolS *add_symbol) |
{ |
int i; |
char *p; |
4004,7 → 3995,7
{ |
inst_main.relax_size += var_insts[i].size; |
var_insts[i].instruction = s3_adjust_paritybit (var_insts[i].instruction, |
s3_GET_INSN_CLASS (var_insts[i].type)); |
s3_GET_INSN_CLASS (var_insts[i].type)); |
} |
|
/* Check data dependency. */ |
4027,7 → 4018,7
|
if (inst_main.reloc.type != BFD_RELOC_NONE) |
fixp = s3_fix_new_score (frag_now, p - frag_now->fr_literal, inst_main.size, |
&inst_main.reloc.exp, inst_main.reloc.pc_rel, inst_main.reloc.type); |
&inst_main.reloc.exp, inst_main.reloc.pc_rel, inst_main.reloc.type); |
|
frag_now->tc_frag_data.fixp = fixp; |
cur_fixp = frag_now->tc_frag_data.fixp; |
4045,8 → 4036,8
if (var_insts[i].reloc.type != BFD_RELOC_NONE) |
{ |
fixp = s3_fix_new_score (frag_now, where, var_insts[i].size, |
&var_insts[i].reloc.exp, var_insts[i].reloc.pc_rel, |
var_insts[i].reloc.type); |
&var_insts[i].reloc.exp, var_insts[i].reloc.pc_rel, |
var_insts[i].reloc.type); |
if (fixp) |
{ |
if (cur_fixp) |
4065,7 → 4056,7
|
p = frag_var (rs_machine_dependent, inst_main.relax_size + s3_RELAX_PAD_BYTE, 0, |
s3_RELAX_ENCODE (inst_main.size, inst_main.relax_size, inst_main.type, |
0, inst_main.size, 0), add_symbol, 0, NULL); |
0, inst_main.size, 0), add_symbol, 0, NULL); |
|
/* Write fr_var part. |
no calling s3_gen_insn_frag, no fixS will be generated. */ |
4100,11 → 4091,11
fix_num = 1; |
var_num = 2; |
|
/* For an external symbol, only one insn is generated; |
/* For an external symbol, only one insn is generated; |
For a local symbol, two insns are generated. */ |
/* Fix part |
For an external symbol: lw rD, <sym>($gp) |
(BFD_RELOC_SCORE_GOT15 or BFD_RELOC_SCORE_CALL15) */ |
(BFD_RELOC_SCORE_GOT15 or BFD_RELOC_SCORE_CALL15) */ |
sprintf (tmp, "lw_pic r%d, %s", reg_rd, add_symbol->bsym->name); |
if (s3_append_insn (tmp, FALSE) == (int) s3_FAIL) |
return; |
4213,8 → 4204,8
if (s3_append_insn (tmp, TRUE) == (int) s3_FAIL) |
return; |
|
/* Set bwarn as -1, so macro instruction itself will not be generated frag. */ |
s3_inst.bwarn = -1; |
/* Set bwarn as -1, so macro instruction itself will not be generated frag. */ |
s3_inst.bwarn = -1; |
} |
|
s3_nor1 = r1_bak; |
4488,6 → 4479,7
|
s3_nor1 = r1_bak; |
} |
|
/* Handle bcmpeq / bcmpne */ |
static void |
s3_do_macro_bcmp (char *str) |
4495,29 → 4487,29
int reg_a , reg_b; |
char keep_data[s3_MAX_LITERAL_POOL_SIZE]; |
char* ptemp; |
int i=0; |
int i = 0; |
struct s3_score_it inst_expand[2]; |
struct s3_score_it inst_main; |
|
|
memset (inst_expand, 0, sizeof inst_expand); |
s3_skip_whitespace (str); |
if (( reg_a = s3_reg_required_here (&str, 15, s3_REG_TYPE_SCORE)) == (int) s3_FAIL |
|| s3_skip_past_comma (&str) == (int) s3_FAIL |
||(reg_b = s3_reg_required_here (&str, 10, s3_REG_TYPE_SCORE)) == (int) s3_FAIL |
|| s3_skip_past_comma (&str) == (int) s3_FAIL) |
return; |
ptemp =str; |
while(*ptemp!=0) |
{ |
keep_data[i]=*ptemp; |
i++; |
ptemp++; |
} |
keep_data[i]=0; |
if (s3_my_get_expression (&s3_inst.reloc.exp, &str) == (int) s3_FAIL |
||reg_b ==0 |
return; |
ptemp = str; |
while (*ptemp != 0) |
{ |
keep_data[i] = *ptemp; |
i++; |
ptemp++; |
} |
keep_data[i] = 0; |
if (s3_my_get_expression (&s3_inst.reloc.exp, &str) == (int) s3_FAIL |
||reg_b == 0 |
|| s3_end_of_line (str) == (int) s3_FAIL) |
return ; |
return; |
else if (s3_inst.reloc.exp.X_add_symbol == 0) |
{ |
s3_inst.error = _("lacking label "); |
4525,19 → 4517,21
} |
else |
{ |
char append_str[s3_MAX_LITERAL_POOL_SIZE]; |
char append_str[s3_MAX_LITERAL_POOL_SIZE]; |
s3_SET_INSN_ERROR (NULL); |
|
|
s3_inst.reloc.type = BFD_RELOC_SCORE_BCMP; |
s3_inst.reloc.pc_rel = 1; |
bfd_signed_vma val = s3_inst.reloc.exp.X_add_number; |
|
/* Branch 32 offset field : 20 bit, 16 bit branch offset field : 8 bit. */ |
s3_inst.instruction |= ((s3_inst.reloc.exp.X_add_number>>1) & 0x1) | ((s3_inst.reloc.exp.X_add_number>>2) & 0x7)<<7 |((s3_inst.reloc.exp.X_add_number>>5) & 0x1f)<<20; |
s3_inst.instruction |= ((s3_inst.reloc.exp.X_add_number >> 1) & 0x1) |
| ((s3_inst.reloc.exp.X_add_number >> 2) & 0x7) << 7 |
| ((s3_inst.reloc.exp.X_add_number >> 5) & 0x1f) << 20; |
|
/* Check and set offset. */ |
if (((val & 0xfffffe00) != 0) |
&& ((val & 0xfffffe00) != 0xfffffe00)) |
&& ((val & 0xfffffe00) != 0xfffffe00)) |
{ |
/* support bcmp --> cmp!+beq (bne) */ |
if (s3_score_pic == s3_NO_PIC) |
4551,33 → 4545,33
sprintf (&append_str[1], "bne %s", keep_data); |
if (s3_append_insn (&append_str[1], TRUE) == (int) s3_FAIL) |
return; |
} |
else |
{ |
gas_assert (s3_inst.reloc.exp.X_add_symbol); |
} |
/* Set bwarn as -1, so macro instruction itself will not be generated frag. */ |
s3_inst.bwarn = -1; |
return; |
} |
else |
{ |
gas_assert (s3_inst.reloc.exp.X_add_symbol); |
} |
/* Set bwarn as -1, so macro instruction itself will not be generated frag. */ |
s3_inst.bwarn = -1; |
return; |
} |
else |
{ |
val >>= 1; |
s3_inst.instruction |= (val & 0x1) |
| (((val >> 1) & 0x7) << 7) |
| (((val >> 4) & 0x1f) << 20); |
| (((val >> 1) & 0x7) << 7) |
| (((val >> 4) & 0x1f) << 20); |
} |
|
/* Backup s3_inst. */ |
memcpy (&inst_main, &s3_inst, sizeof (struct s3_score_it)); |
|
if (s3_score_pic == s3_NO_PIC) |
if (s3_score_pic == s3_NO_PIC) |
{ |
sprintf (&append_str[0], "cmp! r%d, r%d", reg_a, reg_b); |
if (s3_append_insn (&append_str[0], FALSE) == (int) s3_FAIL) |
return; |
memcpy (&inst_expand[0], &s3_inst, sizeof (struct s3_score_it)); |
|
|
if ((inst_main.instruction & 0x3e00007e) == 0x0000004c) |
sprintf (&append_str[1], "beq %s", keep_data); |
else |
4597,17 → 4591,17
inst_main.instruction = s3_adjust_paritybit (inst_main.instruction, s3_GET_INSN_CLASS (inst_main.type)); |
|
for (i = 0; i < 2; i++) |
inst_expand[i].instruction = s3_adjust_paritybit (inst_expand[i].instruction, |
inst_expand[i].instruction = s3_adjust_paritybit (inst_expand[i].instruction, |
s3_GET_INSN_CLASS (inst_expand[i].type)); |
/* Check data dependency. */ |
s3_handle_dependency (&inst_main); |
/* Start a new frag if frag_now is not empty. */ |
if (frag_now_fix () != 0) |
{ |
if (!frag_now->tc_frag_data.is_insn) |
frag_wane (frag_now); |
frag_new (0); |
} |
{ |
if (!frag_now->tc_frag_data.is_insn) |
frag_wane (frag_now); |
frag_new (0); |
} |
frag_grow (20); |
|
/* Write fr_fix part. */ |
4616,10 → 4610,10
s3_md_number_to_chars (p, inst_main.instruction, inst_main.size); |
|
if (inst_main.reloc.type != BFD_RELOC_NONE) |
{ |
s3_fix_new_score (frag_now, p - frag_now->fr_literal, inst_main.size, |
&inst_main.reloc.exp, inst_main.reloc.pc_rel, inst_main.reloc.type); |
} |
{ |
s3_fix_new_score (frag_now, p - frag_now->fr_literal, inst_main.size, |
&inst_main.reloc.exp, inst_main.reloc.pc_rel, inst_main.reloc.type); |
} |
#ifdef OBJ_ELF |
dwarf2_emit_insn (inst_main.size); |
#endif |
4639,7 → 4633,7
|
/* Set bwarn as -1, so macro instruction itself will not be generated frag. */ |
s3_inst.bwarn = -1; |
} |
} |
} |
|
/* Handle bcmpeqz / bcmpnez */ |
4646,29 → 4640,31
static void |
s3_do_macro_bcmpz (char *str) |
{ |
int reg_a ; |
int reg_a; |
char keep_data[s3_MAX_LITERAL_POOL_SIZE]; |
char* ptemp; |
int i=0; |
int i = 0; |
struct s3_score_it inst_expand[2]; |
struct s3_score_it inst_main; |
|
memset (inst_expand, 0, sizeof inst_expand); |
s3_skip_whitespace (str); |
if (( reg_a = s3_reg_required_here (&str, 15, s3_REG_TYPE_SCORE)) == (int) s3_FAIL |
|| s3_skip_past_comma (&str) == (int) s3_FAIL ) |
|| s3_skip_past_comma (&str) == (int) s3_FAIL) |
return; |
ptemp =str; |
while(*ptemp!=0) |
{ |
keep_data[i]=*ptemp; |
i++; |
ptemp++; |
} |
keep_data[i]=0; |
if ( s3_my_get_expression (&s3_inst.reloc.exp, &str) == (int) s3_FAIL |
ptemp = str; |
while (*ptemp != 0) |
{ |
keep_data[i] = *ptemp; |
i++; |
ptemp++; |
} |
|
keep_data[i] = 0; |
|
if (s3_my_get_expression (&s3_inst.reloc.exp, &str) == (int) s3_FAIL |
|| s3_end_of_line (str) == (int) s3_FAIL) |
return ; |
|
return; |
else if (s3_inst.reloc.exp.X_add_symbol == 0) |
{ |
s3_inst.error = _("lacking label "); |
4676,18 → 4672,18
} |
else |
{ |
char append_str[s3_MAX_LITERAL_POOL_SIZE]; |
char append_str[s3_MAX_LITERAL_POOL_SIZE]; |
s3_SET_INSN_ERROR (NULL); |
s3_inst.reloc.type = BFD_RELOC_SCORE_BCMP; |
s3_inst.reloc.pc_rel = 1; |
s3_inst.reloc.pc_rel = 1; |
bfd_signed_vma val = s3_inst.reloc.exp.X_add_number; |
|
/* Branch 32 offset field : 20 bit, 16 bit branch offset field : 8 bit. */ |
s3_inst.instruction |= ((s3_inst.reloc.exp.X_add_number>>1) & 0x1) | ((s3_inst.reloc.exp.X_add_number>>2) & 0x7)<<7 |((s3_inst.reloc.exp.X_add_number>>5) & 0x1f)<<20; |
s3_inst.instruction |= ((s3_inst.reloc.exp.X_add_number>>1) & 0x1) | ((s3_inst.reloc.exp.X_add_number>>2) & 0x7)<<7 |((s3_inst.reloc.exp.X_add_number>>5) & 0x1f)<<20; |
|
/* Check and set offset. */ |
if (((val & 0xfffffe00) != 0) |
&& ((val & 0xfffffe00) != 0xfffffe00)) |
&& ((val & 0xfffffe00) != 0xfffffe00)) |
{ |
if (s3_score_pic == s3_NO_PIC) |
{ |
4713,14 → 4709,14
{ |
val >>= 1; |
s3_inst.instruction |= (val & 0x1) |
| (((val >> 1) & 0x7) << 7) |
| (((val >> 4) & 0x1f) << 20); |
| (((val >> 1) & 0x7) << 7) |
| (((val >> 4) & 0x1f) << 20); |
} |
|
/* Backup s3_inst. */ |
memcpy (&inst_main, &s3_inst, sizeof (struct s3_score_it)); |
|
if (s3_score_pic == s3_NO_PIC) |
|
if (s3_score_pic == s3_NO_PIC) |
{ |
sprintf (&append_str[0], "cmpi! r%d, 0", reg_a); |
if (s3_append_insn (&append_str[0], FALSE) == (int) s3_FAIL) |
4745,16 → 4741,17
inst_main.instruction = s3_adjust_paritybit (inst_main.instruction, s3_GET_INSN_CLASS (inst_main.type)); |
|
for (i = 0; i < 2; i++) |
inst_expand[i].instruction = s3_adjust_paritybit (inst_expand[i].instruction , s3_GET_INSN_CLASS (inst_expand[i].type)); |
inst_expand[i].instruction = s3_adjust_paritybit (inst_expand[i].instruction , |
s3_GET_INSN_CLASS (inst_expand[i].type)); |
/* Check data dependency. */ |
s3_handle_dependency (&inst_main); |
/* Start a new frag if frag_now is not empty. */ |
if (frag_now_fix () != 0) |
{ |
if (!frag_now->tc_frag_data.is_insn) |
frag_wane (frag_now); |
frag_new (0); |
} |
{ |
if (!frag_now->tc_frag_data.is_insn) |
frag_wane (frag_now); |
frag_new (0); |
} |
frag_grow (20); |
|
/* Write fr_fix part. */ |
4763,10 → 4760,10
s3_md_number_to_chars (p, inst_main.instruction, inst_main.size); |
|
if (inst_main.reloc.type != BFD_RELOC_NONE) |
{ |
s3_fix_new_score (frag_now, p - frag_now->fr_literal, inst_main.size, |
&inst_main.reloc.exp, inst_main.reloc.pc_rel, inst_main.reloc.type); |
} |
{ |
s3_fix_new_score (frag_now, p - frag_now->fr_literal, inst_main.size, |
&inst_main.reloc.exp, inst_main.reloc.pc_rel, inst_main.reloc.type); |
} |
#ifdef OBJ_ELF |
dwarf2_emit_insn (inst_main.size); |
#endif |
4786,7 → 4783,7
|
/* Set bwarn as -1, so macro instruction itself will not be generated frag. */ |
s3_inst.bwarn = -1; |
} |
} |
} |
|
static int |
4819,12 → 4816,12
return 1; |
} |
else if ((!S_IS_DEFINED (sym) || S_IS_COMMON (sym)) && (0 |
/* We must defer this decision until after the whole file has been read, |
since there might be a .extern after the first use of this symbol. */ |
|| (before_relaxing |
&& S_GET_VALUE (sym) == 0) |
|| (S_GET_VALUE (sym) != 0 |
&& S_GET_VALUE (sym) <= s3_g_switch_value))) |
/* We must defer this decision until after the whole file has been read, |
since there might be a .extern after the first use of this symbol. */ |
|| (before_relaxing |
&& S_GET_VALUE (sym) == 0) |
|| (S_GET_VALUE (sym) != 0 |
&& S_GET_VALUE (sym) <= s3_g_switch_value))) |
{ |
return 0; |
} |
4866,7 → 4863,7
For a local symbol, three insns are generated. */ |
/* Fix part |
For an external symbol: lw rD, <sym>($gp) |
(BFD_RELOC_SCORE_GOT15) */ |
(BFD_RELOC_SCORE_GOT15) */ |
sprintf (tmp, "lw_pic r1, %s", add_symbol->bsym->name); |
if (s3_append_insn (tmp, FALSE) == (int) s3_FAIL) |
return; |
4999,8 → 4996,8
else |
{ |
if ((s3_inst.reloc.exp.X_add_number <= 0x3fff) |
&& (s3_inst.reloc.exp.X_add_number >= -0x4000) |
&& (!s3_nopic_need_relax (s3_inst.reloc.exp.X_add_symbol, 1))) |
&& (s3_inst.reloc.exp.X_add_number >= -0x4000) |
&& (!s3_nopic_need_relax (s3_inst.reloc.exp.X_add_symbol, 1))) |
{ |
int ldst_idx = 0; |
|
5045,9 → 5042,9
/* Adjust instruction opcode and to be relaxed instruction opcode. */ |
inst_main.instruction = s3_adjust_paritybit (inst_main.instruction, s3_GET_INSN_CLASS (inst_main.type)); |
|
/* relax lw rd, label -> ldis rs, imm16 |
ori rd, imm16 |
lw rd, [rs, imm15] or lw! rd, [rs, imm5]. */ |
/* relax lw rd, label -> ldis rs, imm16 |
ori rd, imm16 |
lw rd, [rs, imm15] or lw! rd, [rs, imm5]. */ |
if (inst_expand[2].relax_size == 0) |
inst_main.relax_size = inst_expand[0].size + inst_expand[1].size + inst_expand[2].size; |
else |
5056,7 → 5053,7
inst_main.type = Insn_GP; |
|
for (i = 0; i < 3; i++) |
inst_expand[i].instruction = s3_adjust_paritybit (inst_expand[i].instruction, |
inst_expand[i].instruction = s3_adjust_paritybit (inst_expand[i].instruction, |
s3_GET_INSN_CLASS (inst_expand[i].type)); |
|
/* Check data dependency. */ |
5079,7 → 5076,7
if (inst_main.reloc.type != BFD_RELOC_NONE) |
{ |
s3_fix_new_score (frag_now, p - frag_now->fr_literal, inst_main.size, |
&inst_main.reloc.exp, inst_main.reloc.pc_rel, inst_main.reloc.type); |
&inst_main.reloc.exp, inst_main.reloc.pc_rel, inst_main.reloc.type); |
} |
|
#ifdef OBJ_ELF |
5099,9 → 5096,9
s3_md_number_to_chars (p, inst_expand[1].instruction, inst_expand[1].size); |
p += inst_expand[1].size; |
|
/* relax lw rd, label -> ldis rs, imm16 |
ori rd, imm16 |
lw rd, [rs, imm15] or lw! rd, [rs, imm5]. */ |
/* relax lw rd, label -> ldis rs, imm16 |
ori rd, imm16 |
lw rd, [rs, imm15] or lw! rd, [rs, imm5]. */ |
if (inst_expand[2].relax_size == 0) |
s3_md_number_to_chars (p, inst_expand[2].instruction, inst_expand[2].size); |
else |
5202,7 → 5199,7
} |
|
if (!(s3_inst.reloc.exp.X_add_number >= -16777216 |
&& s3_inst.reloc.exp.X_add_number <= 16777215)) |
&& s3_inst.reloc.exp.X_add_number <= 16777215)) |
{ |
s3_inst.error = _("invalid constant: 25 bit expression not in range [-16777216, 16777215]"); |
return; |
5229,7 → 5226,7
return; |
} |
else if (!(s3_inst.reloc.exp.X_add_number >= -524288 |
&& s3_inst.reloc.exp.X_add_number <= 524287)) |
&& s3_inst.reloc.exp.X_add_number <= 524287)) |
{ |
s3_inst.error = _("invalid constant: 20 bit expression not in range -2^19..2^19"); |
return; |
5258,7 → 5255,7
s3_do16_branch (char *str) |
{ |
if ((s3_my_get_expression (&s3_inst.reloc.exp, &str) == (int) s3_FAIL |
|| s3_end_of_line (str) == (int) s3_FAIL)) |
|| s3_end_of_line (str) == (int) s3_FAIL)) |
{ |
; |
} |
5267,7 → 5264,7
s3_inst.error = _("lacking label"); |
} |
else if (!(s3_inst.reloc.exp.X_add_number >= -512 |
&& s3_inst.reloc.exp.X_add_number <= 511)) |
&& s3_inst.reloc.exp.X_add_number <= 511)) |
{ |
s3_inst.error = _("invalid constant: 10 bit expression not in range [-2^9, 2^9-1]"); |
} |
5311,8 → 5308,8
linkonce = TRUE; |
|
/* The GNU toolchain uses an extension for ELF: a section |
beginning with the magic string .gnu.linkonce is a linkonce |
section. */ |
beginning with the magic string .gnu.linkonce is a linkonce |
section. */ |
if (strncmp (segment_name (symsec), ".gnu.linkonce", |
sizeof ".gnu.linkonce" - 1) == 0) |
linkonce = TRUE; |
5320,9 → 5317,9
|
/* This must duplicate the test in adjust_reloc_syms. */ |
return (symsec != &bfd_und_section |
&& symsec != &bfd_abs_section |
&& symsec != &bfd_abs_section |
&& ! bfd_is_com_section (symsec) |
&& !linkonce |
&& !linkonce |
#ifdef OBJ_ELF |
/* A global or weak symbol is treated as external. */ |
&& (OUTPUT_FLAVOR != bfd_target_elf_flavour |
5362,8 → 5359,8
return; |
|
if ( ((pec_part_1.size == s3_INSN_SIZE) && (s3_inst.size == s3_INSN_SIZE)) |
|| ((pec_part_1.size == s3_INSN_SIZE) && (s3_inst.size == s3_INSN16_SIZE)) |
|| ((pec_part_1.size == s3_INSN16_SIZE) && (s3_inst.size == s3_INSN_SIZE))) |
|| ((pec_part_1.size == s3_INSN_SIZE) && (s3_inst.size == s3_INSN16_SIZE)) |
|| ((pec_part_1.size == s3_INSN16_SIZE) && (s3_inst.size == s3_INSN_SIZE))) |
{ |
s3_inst.error = _("pce instruction error (16 bit || 16 bit)'"); |
sprintf (s3_inst.str, insnstr); |
5380,7 → 5377,7
{ |
int rd = 0; |
|
/* Check 3d. */ |
/* Check 3d. */ |
if (s3_score3d == 0) |
{ |
s3_inst.error = _("score3d instruction."); |
5404,7 → 5401,7
static void |
s3_do16_dsp2 (char *str) |
{ |
/* Check 3d. */ |
/* Check 3d. */ |
if (s3_score3d == 0) |
{ |
s3_inst.error = _("score3d instruction."); |
5431,7 → 5428,7
static void |
s3_do_dsp (char *str) |
{ |
/* Check 3d. */ |
/* Check 3d. */ |
if (s3_score3d == 0) |
{ |
s3_inst.error = _("score3d instruction."); |
5460,7 → 5457,7
{ |
int reg; |
|
/* Check 3d. */ |
/* Check 3d. */ |
if (s3_score3d == 0) |
{ |
s3_inst.error = _("score3d instruction."); |
5482,7 → 5479,7
{ |
/* Check mulr, mulur rd is even number. */ |
if (((s3_inst.instruction & 0x3e0003ff) == 0x00000340 |
|| (s3_inst.instruction & 0x3e0003ff) == 0x00000342) |
|| (s3_inst.instruction & 0x3e0003ff) == 0x00000342) |
&& (reg % 2)) |
{ |
s3_inst.error = _("rd must be even number."); |
5509,7 → 5506,7
static void |
s3_do_dsp3 (char *str) |
{ |
/* Check 3d. */ |
/* Check 3d. */ |
if (s3_score3d == 0) |
{ |
s3_inst.error = _("score3d instruction."); |
5791,7 → 5788,6
/* Generate a .pdr section. */ |
segT saved_seg = now_seg; |
subsegT saved_subseg = now_subseg; |
valueT dot; |
expressionS exp; |
char *fragp; |
|
5842,7 → 5838,7
|
else |
{ |
dot = frag_now_fix (); |
(void) frag_now_fix (); |
gas_assert (s3_pdr_seg); |
subseg_set (s3_pdr_seg, 0); |
/* Write the symbol. */ |
6069,18 → 6065,18
} |
|
#ifndef TC_IMPLICIT_LCOMM_ALIGNMENT |
#define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR) \ |
do \ |
{ \ |
if ((SIZE) >= 8) \ |
(P2VAR) = 3; \ |
else if ((SIZE) >= 4) \ |
(P2VAR) = 2; \ |
else if ((SIZE) >= 2) \ |
(P2VAR) = 1; \ |
else \ |
(P2VAR) = 0; \ |
} \ |
#define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR) \ |
do \ |
{ \ |
if ((SIZE) >= 8) \ |
(P2VAR) = 3; \ |
else if ((SIZE) >= 4) \ |
(P2VAR) = 2; \ |
else if ((SIZE) >= 2) \ |
(P2VAR) = 1; \ |
else \ |
(P2VAR) = 0; \ |
} \ |
while (0) |
#endif |
|
6223,16 → 6219,16
*p = c; |
|
if ( |
#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT) \ |
#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT) \ |
|| defined (OBJ_BOUT) || defined (OBJ_MAYBE_BOUT)) |
#ifdef BFD_ASSEMBLER |
(OUTPUT_FLAVOR != bfd_target_aout_flavour |
|| (S_GET_OTHER (symbolP) == 0 && S_GET_DESC (symbolP) == 0)) && |
(OUTPUT_FLAVOR != bfd_target_aout_flavour |
|| (S_GET_OTHER (symbolP) == 0 && S_GET_DESC (symbolP) == 0)) && |
#else |
(S_GET_OTHER (symbolP) == 0 && S_GET_DESC (symbolP) == 0) && |
(S_GET_OTHER (symbolP) == 0 && S_GET_DESC (symbolP) == 0) && |
#endif |
#endif |
(S_GET_SEGMENT (symbolP) == bss_seg || (!S_IS_DEFINED (symbolP) && S_GET_VALUE (symbolP) == 0))) |
(S_GET_SEGMENT (symbolP) == bss_seg || (!S_IS_DEFINED (symbolP) && S_GET_VALUE (symbolP) == 0))) |
{ |
char *pfrag; |
|
6323,7 → 6319,7
struct s3_asm_opcode *new_opcode; |
char *template_name; |
new_opcode = (struct s3_asm_opcode *) |
obstack_alloc (&insn_obstack, sizeof (struct s3_asm_opcode)); |
obstack_alloc (&insn_obstack, sizeof (struct s3_asm_opcode)); |
template_name = (char *) obstack_alloc (& insn_obstack, len + 1); |
|
strcpy (template_name, insn->template_name); |
6352,8 → 6348,8
struct s3_insn_to_dependency *new_i2n; |
|
new_i2n = (struct s3_insn_to_dependency *) |
obstack_alloc (&dependency_obstack, |
sizeof (struct s3_insn_to_dependency)); |
obstack_alloc (&dependency_obstack, |
sizeof (struct s3_insn_to_dependency)); |
new_i2n->insn_name = (char *) obstack_alloc (&dependency_obstack, |
len + 1); |
|
6459,7 → 6455,7
{ |
if (score3) |
return s3_s_score_cprestore (ignore); |
else |
else |
return s7_s_score_cprestore (ignore); |
} |
|
6468,7 → 6464,7
{ |
if (score3) |
return s3_s_score_gpword (ignore); |
else |
else |
return s7_s_score_gpword (ignore); |
} |
|
6477,7 → 6473,7
{ |
if (score3) |
return s3_s_score_cpadd (ignore); |
else |
else |
return s7_s_score_cpadd (ignore); |
} |
|
6486,7 → 6482,7
{ |
if (score3) |
return s3_s_score_lcomm (bytes_p); |
else |
else |
return s7_s_score_lcomm (bytes_p); |
} |
|
6574,21 → 6570,21
if (target_big_endian) |
{ |
while (n--) |
{ |
{ |
result <<= 8; |
result |= (*where++ & 255); |
} |
result |= (*where++ & 255); |
} |
} |
else |
{ |
while (n--) |
{ |
{ |
result <<= 8; |
result |= (where[n] & 255); |
} |
result |= (where[n] & 255); |
} |
} |
|
return result; |
return result; |
} |
|
static void |
6643,7 → 6639,7
static void |
s3_md_number_to_chars (char *buf, valueT val, int n) |
{ |
if (!target_big_endian && n >= 4) |
if (!target_big_endian && n >= 4) |
s3_number_to_chars_littleendian (buf, val, n); |
else |
md_number_to_chars (buf, val, n); |
6743,7 → 6739,7
|| fixp->fx_r_type == BFD_RELOC_SCORE_JMP |
|| fixp->fx_r_type == BFD_RELOC_SCORE_BRANCH |
|| fixp->fx_r_type == BFD_RELOC_SCORE16_JMP |
|| fixp->fx_r_type == BFD_RELOC_SCORE16_BRANCH |
|| fixp->fx_r_type == BFD_RELOC_SCORE16_BRANCH |
|| fixp->fx_r_type == BFD_RELOC_SCORE_BCMP) |
{ |
retval = 1; |
6759,7 → 6755,7
return 1; |
} |
else if (OUTPUT_FLAVOR == bfd_target_elf_flavour |
&& (S_IS_EXTERNAL (fixP->fx_addsy) || S_IS_WEAK (fixP->fx_addsy))) |
&& (S_IS_EXTERNAL (fixP->fx_addsy) || S_IS_WEAK (fixP->fx_addsy))) |
{ |
return 0; |
} |
6869,7 → 6865,7
|
value = offset + symbol_address - frag_addr; |
|
if (relaxable_p |
if (relaxable_p |
&& (!((value & 0xfffffe00) == 0 || (value & 0xfffffe00) == 0xfffffe00)) |
&& fragp->fr_fix == 2 |
&& (s->bsym != NULL) |
6911,8 → 6907,8
|
inst_value = s3_md_chars_to_number (fragp->fr_literal, s3_INSN_SIZE); |
offset = (inst_value & 0x1) |
| (((inst_value >> 7) & 0x7) << 1) |
| (((inst_value >> 21) & 0x1f) << 4); |
| (((inst_value >> 7) & 0x7) << 1) |
| (((inst_value >> 21) & 0x1f) << 4); |
offset <<= 1; |
if ((offset & 0x200) == 0x200) |
offset |= 0xfffffe00; |
6919,31 → 6915,30
|
value = offset + symbol_address - frag_addr; |
/* change the order of judging rule is because |
1.not defined symbol or common sysbol or external symbol will change |
bcmp to cmp!+beq/bne ,here need to record fragp->fr_opcode |
2.if the flow is as before : it will results to recursive loop |
1.not defined symbol or common sysbol or external symbol will change |
bcmp to cmp!+beq/bne ,here need to record fragp->fr_opcode |
2.if the flow is as before : it will results to recursive loop |
*/ |
if (fragp->fr_fix == 6) |
{ |
{ |
/* Have already relaxed! Just return 0 to terminate the loop. */ |
return 0; |
} |
/* need to translate when extern or not defind or common sysbol */ |
else if ((relaxable_p |
&& (!((value & 0xfffffe00) == 0 || (value & 0xfffffe00) == 0xfffffe00)) |
&& fragp->fr_fix == 4 |
&& (s->bsym != NULL)) |
|| !S_IS_DEFINED (s) |
||S_IS_COMMON (s) |
||S_IS_EXTERNAL (s)) |
else if ((relaxable_p |
&& (!((value & 0xfffffe00) == 0 || (value & 0xfffffe00) == 0xfffffe00)) |
&& fragp->fr_fix == 4 |
&& (s->bsym != NULL)) |
|| !S_IS_DEFINED (s) |
||S_IS_COMMON (s) |
||S_IS_EXTERNAL (s)) |
{ |
fragp->fr_opcode = fragp->fr_literal + s3_RELAX_RELOC1 (fragp->fr_subtype); |
fragp->fr_fix = 6; |
return 2; |
} |
|
else |
{ |
{ |
/* Never relax. Modify fr_opcode to NULL to verify it's value in |
md_apply_fix. */ |
fragp->fr_opcode = NULL; |
6971,7 → 6966,7
static int |
s3_relax_gp_and_pic_inst32 (void) |
{ |
/* md_estimate_size_before_relax has already relaxed s3_GP and s3_PIC |
/* md_estimate_size_before_relax has already relaxed s3_GP and s3_PIC |
instructions. We don't change relax size here. */ |
return 0; |
} |
6986,11 → 6981,11
if ((fragp->fr_address) % 2 != 0) |
{ |
if ((fragp->fr_address + fragp->insn_addr) % 2 != 0) |
{ |
{ |
fragp->insn_addr = 1; |
grows += 1; |
adjust_align_p = 1; |
} |
} |
} |
|
switch (s3_RELAX_TYPE (fragp->fr_subtype)) |
7167,9 → 7162,9
value = fixP->fx_offset; |
value >>= 2; |
content = (content & ~0x7f7fff7f80LL) |
| (((value & 0xff) >> 0) << 7) |
| (((value & 0x7fff00) >> 8) << 16) |
| (((value & 0x3f800000) >> 23) << 32); |
| (((value & 0xff) >> 0) << 7) |
| (((value & 0x7fff00) >> 8) << 16) |
| (((value & 0x3f800000) >> 23) << 32); |
s3_md_number_to_chars (buf, content, s3_INSN48_SIZE); |
break; |
} |
7179,9 → 7174,9
content = s3_md_chars_to_number (buf, s3_INSN48_SIZE); |
value = fixP->fx_offset; |
content = (content & ~0x7f7fff7fe0LL) |
| ((value & 0x3ff) << 5) |
| (((value >> 10) & 0x7fff) << 16) |
| (((value >> 25) & 0x7f) << 32); |
| ((value & 0x3ff) << 5) |
| (((value >> 10) & 0x7fff) << 16) |
| (((value >> 25) & 0x7f) << 32); |
s3_md_number_to_chars (buf, content, s3_INSN48_SIZE); |
break; |
} |
7231,7 → 7226,7
content = (content & 0xfc01) | (value & 0xffe); |
s3_md_number_to_chars (buf, content, s3_INSN16_SIZE); |
break; |
case BFD_RELOC_SCORE16_BRANCH: |
case BFD_RELOC_SCORE16_BRANCH: |
content = s3_md_chars_to_number (buf, s3_INSN_SIZE); |
/* Don't check c-bit. */ |
if (fixP->fx_frag->fr_opcode != 0) |
7276,7 → 7271,7
break; |
} |
|
break; |
break; |
|
case BFD_RELOC_SCORE_BCMP: |
if (fixP->fx_frag->fr_opcode != 0) |
7289,7 → 7284,7
else |
fixP->fx_done = 1; |
|
/* NOTE!!! |
/* NOTE!!! |
bcmp -> cmp! and branch, so value -= 2. */ |
value -= 2; |
|
7321,7 → 7316,7
if ((value & 0xfffffe00) != 0 && (value & 0xfffffe00) != 0xfffffe00) |
{ |
as_bad_where (fixP->fx_file, fixP->fx_line, |
_(" branch relocation truncate (0x%x) [-2^9 ~ 2^9]"), (unsigned int)value); |
_(" branch relocation truncate (0x%x) [-2^9 ~ 2^9]"), (unsigned int)value); |
return; |
} |
|
7328,9 → 7323,9
value >>= 1; |
content &= ~0x03e00381; |
content = content |
| (value & 0x1) |
| (((value & 0xe) >> 1) << 7) |
| (((value & 0x1f0) >> 4) << 21); |
| (value & 0x1) |
| (((value & 0xe) >> 1) << 7) |
| (((value & 0x1f0) >> 4) << 21); |
|
s3_md_number_to_chars (buf, content, s3_INSN_SIZE); |
break; |
7405,9 → 7400,6
arelent *reloc; |
bfd_reloc_code_real_type code; |
char *type; |
fragS *f; |
symbolS *s; |
expressionS e; |
|
reloc = retval[0] = xmalloc (sizeof (arelent)); |
retval[1] = NULL; |
7446,10 → 7438,6
*retval[1]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); |
retval[1]->address = (reloc->address + s3_RELAX_RELOC2 (fixp->fx_frag->fr_subtype)); |
|
f = fixp->fx_frag; |
s = f->fr_symbol; |
e = s->sy_value; |
|
retval[1]->addend = 0; |
retval[1]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_LO16); |
gas_assert (retval[1]->howto != NULL); |
7631,7 → 7619,7
{ |
if (score3) |
return s3_relax_frag (sec, fragp, stretch); |
else |
else |
return s7_relax_frag (sec, fragp, stretch); |
} |
|
/tc-arm.c
7798,10 → 7798,10
do_ldrd (void) |
{ |
constraint (inst.operands[0].reg % 2 != 0, |
_("first destination register must be even")); |
_("first transfer register must be even")); |
constraint (inst.operands[1].present |
&& inst.operands[1].reg != inst.operands[0].reg + 1, |
_("can only load two consecutive registers")); |
_("can only transfer two consecutive registers")); |
constraint (inst.operands[0].reg == REG_LR, _("r14 not allowed here")); |
constraint (!inst.operands[2].isreg, _("'[' expected")); |
|
7808,25 → 7808,24
if (!inst.operands[1].present) |
inst.operands[1].reg = inst.operands[0].reg + 1; |
|
if (inst.instruction & LOAD_BIT) |
{ |
/* encode_arm_addr_mode_3 will diagnose overlap between the base |
register and the first register written; we have to diagnose |
overlap between the base and the second register written here. */ |
/* encode_arm_addr_mode_3 will diagnose overlap between the base |
register and the first register written; we have to diagnose |
overlap between the base and the second register written here. */ |
|
if (inst.operands[2].reg == inst.operands[1].reg |
&& (inst.operands[2].writeback || inst.operands[2].postind)) |
as_warn (_("base register written back, and overlaps " |
"second destination register")); |
if (inst.operands[2].reg == inst.operands[1].reg |
&& (inst.operands[2].writeback || inst.operands[2].postind)) |
as_warn (_("base register written back, and overlaps " |
"second transfer register")); |
|
if (!(inst.instruction & V4_STR_BIT)) |
{ |
/* For an index-register load, the index register must not overlap the |
destination (even if not write-back). */ |
else if (inst.operands[2].immisreg |
&& ((unsigned) inst.operands[2].imm == inst.operands[0].reg |
|| (unsigned) inst.operands[2].imm == inst.operands[1].reg)) |
as_warn (_("index register overlaps destination register")); |
destination (even if not write-back). */ |
if (inst.operands[2].immisreg |
&& ((unsigned) inst.operands[2].imm == inst.operands[0].reg |
|| (unsigned) inst.operands[2].imm == inst.operands[1].reg)) |
as_warn (_("index register overlaps transfer register")); |
} |
|
inst.instruction |= inst.operands[0].reg << 12; |
encode_arm_addr_mode_3 (2, /*is_t=*/FALSE); |
} |
8344,6 → 8343,9
{ |
inst.instruction |= inst.operands[2].reg << 8; |
inst.instruction |= SHIFT_BY_REG; |
/* PR 12854: Error on extraneous shifts. */ |
constraint (inst.operands[2].shifted, |
_("extraneous shift as part of operand to shift insn")); |
} |
else |
inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM; |
11536,6 → 11538,10
inst.instruction |= inst.operands[0].reg << 8; |
inst.instruction |= inst.operands[1].reg << 16; |
inst.instruction |= inst.operands[2].reg; |
|
/* PR 12854: Error on extraneous shifts. */ |
constraint (inst.operands[2].shifted, |
_("extraneous shift as part of operand to shift insn")); |
} |
else |
{ |
11564,6 → 11570,10
|
inst.instruction |= inst.operands[0].reg; |
inst.instruction |= inst.operands[2].reg << 3; |
|
/* PR 12854: Error on extraneous shifts. */ |
constraint (inst.operands[2].shifted, |
_("extraneous shift as part of operand to shift insn")); |
} |
else |
{ |
11603,6 → 11613,10
|
inst.instruction |= inst.operands[0].reg; |
inst.instruction |= inst.operands[2].reg << 3; |
|
/* PR 12854: Error on extraneous shifts. */ |
constraint (inst.operands[2].shifted, |
_("extraneous shift as part of operand to shift insn")); |
} |
else |
{ |