X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-arm.c;h=f325dcf1f1161d105b098b1463f09dfe0833a99b;hb=886e1c739b5441aca92a9725c932d0d446097a32;hp=f52cf7fac27f6e3fc43e36863438aec3f7e3bc2a;hpb=4070243b5c1f66a36dd43a7b722e991ac9fc40e1;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index f52cf7fac2..f325dcf1f1 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -1,5 +1,5 @@ /* tc-arm.c -- Assemble for the ARM - Copyright (C) 1994-2017 Free Software Foundation, Inc. + Copyright (C) 1994-2019 Free Software Foundation, Inc. Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) Modified by David Taylor (dtaylor@armltd.co.uk) Cirrus coprocessor mods by Aldy Hernandez (aldyh@redhat.com) @@ -75,6 +75,9 @@ static struct unsigned sp_restored:1; } unwind; +/* Whether --fdpic was given. */ +static int arm_fdpic; + #endif /* OBJ_ELF */ /* Results from operand parsing worker functions. */ @@ -123,7 +126,12 @@ enum arm_float_abi #define streq(a, b) (strcmp (a, b) == 0) +/* Current set of feature bits available (CPU+FPU). Different from + selected_cpu + selected_fpu in case of autodetection since the CPU + feature bits are then all set. */ static arm_feature_set cpu_variant; +/* Feature bits used in each execution state. Used to set build attribute + (in particular Tag_*_ISA_use) in CPU autodetection mode. */ static arm_feature_set arm_arch_used; static arm_feature_set thumb_arch_used; @@ -143,17 +151,24 @@ bfd_boolean codecomposer_syntax = FALSE; /* Variables that we set while parsing command-line options. Once all options have been read we re-process these values to set the real assembly flags. */ + +/* CPU and FPU feature bits set for legacy CPU and FPU options (eg. -marm1 + instead of -mcpu=arm1). */ static const arm_feature_set *legacy_cpu = NULL; static const arm_feature_set *legacy_fpu = NULL; +/* CPU, extension and FPU feature bits selected by -mcpu. */ static const arm_feature_set *mcpu_cpu_opt = NULL; -static arm_feature_set *dyn_mcpu_ext_opt = NULL; +static arm_feature_set *mcpu_ext_opt = NULL; static const arm_feature_set *mcpu_fpu_opt = NULL; + +/* CPU, extension and FPU feature bits selected by -march. */ static const arm_feature_set *march_cpu_opt = NULL; -static arm_feature_set *dyn_march_ext_opt = NULL; +static arm_feature_set *march_ext_opt = NULL; static const arm_feature_set *march_fpu_opt = NULL; + +/* Feature bits selected by -mfpu. */ static const arm_feature_set *mfpu_opt = NULL; -static const arm_feature_set *object_arch = NULL; /* Constants for known architecture features. */ static const arm_feature_set fpu_default = FPU_DEFAULT; @@ -189,6 +204,9 @@ static const arm_feature_set arm_ext_v5j = ARM_FEATURE_CORE_LOW (ARM_EXT_V5J); static const arm_feature_set arm_ext_v6 = ARM_FEATURE_CORE_LOW (ARM_EXT_V6); static const arm_feature_set arm_ext_v6k = ARM_FEATURE_CORE_LOW (ARM_EXT_V6K); static const arm_feature_set arm_ext_v6t2 = ARM_FEATURE_CORE_LOW (ARM_EXT_V6T2); +/* Only for compatability of hint instructions. */ +static const arm_feature_set arm_ext_v6k_v6t2 = + ARM_FEATURE_CORE_LOW (ARM_EXT_V6K | ARM_EXT_V6T2); static const arm_feature_set arm_ext_v6_notm = ARM_FEATURE_CORE_LOW (ARM_EXT_V6_NOTM); static const arm_feature_set arm_ext_v6_dsp = @@ -217,6 +235,8 @@ static const arm_feature_set arm_ext_pan = ARM_FEATURE_CORE_HIGH (ARM_EXT2_PAN); static const arm_feature_set arm_ext_v8m = ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M); static const arm_feature_set arm_ext_v8m_main = ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M_MAIN); +static const arm_feature_set arm_ext_v8_1m_main = +ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN); /* Instructions in ARMv8-M only found in M profile architectures. */ static const arm_feature_set arm_ext_v8m_m_only = ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M | ARM_EXT2_V8M_MAIN); @@ -235,8 +255,16 @@ static const arm_feature_set arm_ext_ras = /* FP16 instructions. */ static const arm_feature_set arm_ext_fp16 = ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST); +static const arm_feature_set arm_ext_fp16_fml = + ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_FML); +static const arm_feature_set arm_ext_v8_2 = + ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_2A); static const arm_feature_set arm_ext_v8_3 = ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_3A); +static const arm_feature_set arm_ext_sb = + ARM_FEATURE_CORE_HIGH (ARM_EXT2_SB); +static const arm_feature_set arm_ext_predres = + ARM_FEATURE_CORE_HIGH (ARM_EXT2_PREDRES); static const arm_feature_set arm_arch_any = ARM_ANY; #ifdef OBJ_ELF @@ -274,6 +302,10 @@ static const arm_feature_set fpu_neon_ext_v1 = ARM_FEATURE_COPROC (FPU_NEON_EXT_V1); static const arm_feature_set fpu_vfp_v3_or_neon_ext = ARM_FEATURE_COPROC (FPU_NEON_EXT_V1 | FPU_VFP_EXT_V3); +static const arm_feature_set mve_ext = + ARM_FEATURE_COPROC (FPU_MVE); +static const arm_feature_set mve_fp_ext = + ARM_FEATURE_COPROC (FPU_MVE_FP); #ifdef OBJ_ELF static const arm_feature_set fpu_vfp_fp16 = ARM_FEATURE_COPROC (FPU_VFP_EXT_FP16); @@ -298,8 +330,20 @@ static const arm_feature_set fpu_neon_ext_dotprod = ARM_FEATURE_COPROC (FPU_NEON_EXT_DOTPROD); static int mfloat_abi_opt = -1; -/* Record user cpu selection for object attributes. */ +/* Architecture feature bits selected by the last -mcpu/-march or .cpu/.arch + directive. */ +static arm_feature_set selected_arch = ARM_ARCH_NONE; +/* Extension feature bits selected by the last -mcpu/-march or .arch_extension + directive. */ +static arm_feature_set selected_ext = ARM_ARCH_NONE; +/* Feature bits selected by the last -mcpu/-march or by the combination of the + last .cpu/.arch directive .arch_extension directives since that + directive. */ static arm_feature_set selected_cpu = ARM_ARCH_NONE; +/* FPU feature bits selected by the last -mfpu or .fpu directive. */ +static arm_feature_set selected_fpu = FPU_NONE; +/* Feature bits selected by the last .object_arch directive. */ +static arm_feature_set selected_object_arch = ARM_ARCH_NONE; /* Must be long enough to hold any of the names in arm_cpus. */ static char selected_cpu_name[20]; @@ -409,20 +453,25 @@ struct neon_type unsigned elems; }; -enum it_instruction_type +enum pred_instruction_type { - OUTSIDE_IT_INSN, + OUTSIDE_PRED_INSN, + INSIDE_VPT_INSN, INSIDE_IT_INSN, INSIDE_IT_LAST_INSN, IF_INSIDE_IT_LAST_INSN, /* Either outside or inside; if inside, should be the last one. */ NEUTRAL_IT_INSN, /* This could be either inside or outside, i.e. BKPT and NOP. */ - IT_INSN /* The IT insn has been parsed. */ + IT_INSN, /* The IT insn has been parsed. */ + VPT_INSN, /* The VPT/VPST insn has been parsed. */ + MVE_OUTSIDE_PRED_INSN /* Instruction to indicate a MVE instruction without + a predication code. */ }; /* The maximum number of operands we need. */ #define ARM_IT_MAX_OPERANDS 6 +#define ARM_IT_MAX_RELOCS 3 struct arm_it { @@ -447,9 +496,9 @@ struct arm_it bfd_reloc_code_real_type type; expressionS exp; int pc_rel; - } reloc; + } relocs[ARM_IT_MAX_RELOCS]; - enum it_instruction_type it_insn_type; + enum pred_instruction_type pred_insn_type; struct { @@ -466,7 +515,7 @@ struct arm_it instructions. This allows us to disambiguate ARM <-> vector insns. */ unsigned regisimm : 1; /* 64-bit immediate, reg forms high 32 bits. */ unsigned isvec : 1; /* Is a single, double or quad VFP/Neon reg. */ - unsigned isquad : 1; /* Operand is Neon quad-precision register. */ + unsigned isquad : 1; /* Operand is SIMD quad register. */ unsigned issingle : 1; /* Operand is VFP single-precision register. */ unsigned hasreloc : 1; /* Operand has relocation suffix. */ unsigned writeback : 1; /* Operand has trailing ! */ @@ -487,9 +536,6 @@ const char * fp_const[] = "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0", 0 }; -/* Number of littlenums required to hold an extended precision number. */ -#define MAX_LITTLENUMS 6 - LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS]; #define FAIL (-1) @@ -540,7 +586,7 @@ struct asm_barrier_opt struct reloc_entry { - const char * name; + const char * name; bfd_reloc_code_real_type reloc; }; @@ -567,7 +613,8 @@ struct neon_typed_alias }; /* ARM register categories. This includes coprocessor numbers and various - architecture extensions' registers. */ + architecture extensions' registers. Each entry should have an error message + in reg_expected_msgs below. */ enum arm_reg_type { REG_TYPE_RN, @@ -579,6 +626,7 @@ enum arm_reg_type REG_TYPE_NQ, REG_TYPE_VFSD, REG_TYPE_NDQ, + REG_TYPE_NSD, REG_TYPE_NSDQ, REG_TYPE_VFC, REG_TYPE_MVF, @@ -586,12 +634,13 @@ enum arm_reg_type REG_TYPE_MVFX, REG_TYPE_MVDX, REG_TYPE_MVAX, + REG_TYPE_MQ, REG_TYPE_DSPSC, REG_TYPE_MMXWR, REG_TYPE_MMXWC, REG_TYPE_MMXWCG, REG_TYPE_XSCALE, - REG_TYPE_RNB + REG_TYPE_RNB, }; /* Structure for a hash table entry for a register. @@ -610,27 +659,31 @@ struct reg_entry /* Diagnostics used when we don't get a register of the expected type. */ const char * const reg_expected_msgs[] = { - N_("ARM register expected"), - N_("bad or missing co-processor number"), - N_("co-processor register expected"), - N_("FPA register expected"), - N_("VFP single precision register expected"), - N_("VFP/Neon double precision register expected"), - N_("Neon quad precision register expected"), - N_("VFP single or double precision register expected"), - N_("Neon double or quad precision register expected"), - N_("VFP single, double or Neon quad precision register expected"), - N_("VFP system register expected"), - N_("Maverick MVF register expected"), - N_("Maverick MVD register expected"), - N_("Maverick MVFX register expected"), - N_("Maverick MVDX register expected"), - N_("Maverick MVAX register expected"), - N_("Maverick DSPSC register expected"), - N_("iWMMXt data register expected"), - N_("iWMMXt control register expected"), - N_("iWMMXt scalar register expected"), - N_("XScale accumulator register expected"), + [REG_TYPE_RN] = N_("ARM register expected"), + [REG_TYPE_CP] = N_("bad or missing co-processor number"), + [REG_TYPE_CN] = N_("co-processor register expected"), + [REG_TYPE_FN] = N_("FPA register expected"), + [REG_TYPE_VFS] = N_("VFP single precision register expected"), + [REG_TYPE_VFD] = N_("VFP/Neon double precision register expected"), + [REG_TYPE_NQ] = N_("Neon quad precision register expected"), + [REG_TYPE_VFSD] = N_("VFP single or double precision register expected"), + [REG_TYPE_NDQ] = N_("Neon double or quad precision register expected"), + [REG_TYPE_NSD] = N_("Neon single or double precision register expected"), + [REG_TYPE_NSDQ] = N_("VFP single, double or Neon quad precision register" + " expected"), + [REG_TYPE_VFC] = N_("VFP system register expected"), + [REG_TYPE_MVF] = N_("Maverick MVF register expected"), + [REG_TYPE_MVD] = N_("Maverick MVD register expected"), + [REG_TYPE_MVFX] = N_("Maverick MVFX register expected"), + [REG_TYPE_MVDX] = N_("Maverick MVDX register expected"), + [REG_TYPE_MVAX] = N_("Maverick MVAX register expected"), + [REG_TYPE_DSPSC] = N_("Maverick DSPSC register expected"), + [REG_TYPE_MMXWR] = N_("iWMMXt data register expected"), + [REG_TYPE_MMXWC] = N_("iWMMXt control register expected"), + [REG_TYPE_MMXWCG] = N_("iWMMXt scalar register expected"), + [REG_TYPE_XSCALE] = N_("XScale accumulator register expected"), + [REG_TYPE_MQ] = N_("MVE vector register expected"), + [REG_TYPE_RNB] = N_("") }; /* Some well known registers that we refer to directly elsewhere. */ @@ -655,7 +708,7 @@ struct asm_opcode unsigned int tag : 4; /* Basic instruction code. */ - unsigned int avalue : 28; + unsigned int avalue; /* Thumb-format instruction code. */ unsigned int tvalue; @@ -669,6 +722,9 @@ struct asm_opcode /* Function to call to encode instruction in Thumb format. */ void (* tencode) (void); + + /* Indicates whether this instruction may be vector predicated. */ + unsigned int mayBeVecPred : 1; }; /* Defines for various bits that we will want to toggle. */ @@ -791,19 +847,27 @@ struct asm_opcode #define THUMB_LOAD_BIT 0x0800 #define THUMB2_LOAD_BIT 0x00100000 +#define BAD_SYNTAX _("syntax error") #define BAD_ARGS _("bad arguments to instruction") #define BAD_SP _("r13 not allowed here") #define BAD_PC _("r15 not allowed here") +#define BAD_ODD _("Odd register not allowed here") +#define BAD_EVEN _("Even register not allowed here") #define BAD_COND _("instruction cannot be conditional") #define BAD_OVERLAP _("registers may not be the same") #define BAD_HIREG _("lo register required") #define BAD_THUMB32 _("instruction not supported in Thumb16 mode") #define BAD_ADDR_MODE _("instruction does not accept this addressing mode"); #define BAD_BRANCH _("branch must be last instruction in IT block") +#define BAD_BRANCH_OFF _("branch out of range or not a multiple of 2") #define BAD_NOT_IT _("instruction not allowed in IT block") +#define BAD_NOT_VPT _("instruction missing MVE vector predication code") #define BAD_FPU _("selected FPU does not support instruction") #define BAD_OUT_IT _("thumb conditional instruction should be in IT block") +#define BAD_OUT_VPT \ + _("vector predicated instruction should be in VPT/VPST block") #define BAD_IT_COND _("incorrect condition in IT block") +#define BAD_VPT_COND _("incorrect condition in VPT/VPST block") #define BAD_IT_IT _("IT falling in the range of a previous IT block") #define MISSING_FNSTART _("missing .fnstart before unwinding directive") #define BAD_PC_ADDRESSING \ @@ -814,9 +878,24 @@ struct asm_opcode #define BAD_FP16 _("selected processor does not support fp16 instruction") #define UNPRED_REG(R) _("using " R " results in unpredictable behaviour") #define THUMB1_RELOC_ONLY _("relocation valid in thumb1 code only") +#define MVE_NOT_IT _("Warning: instruction is UNPREDICTABLE in an IT " \ + "block") +#define MVE_NOT_VPT _("Warning: instruction is UNPREDICTABLE in a VPT " \ + "block") +#define MVE_BAD_PC _("Warning: instruction is UNPREDICTABLE with PC" \ + " operand") +#define MVE_BAD_SP _("Warning: instruction is UNPREDICTABLE with SP" \ + " operand") +#define BAD_SIMD_TYPE _("bad type in SIMD instruction") +#define BAD_MVE_AUTO \ + _("GAS auto-detection mode and -march=all is deprecated for MVE, please" \ + " use a valid -march or -mcpu option.") +#define BAD_MVE_SRCDEST _("Warning: 32-bit element size and same destination "\ + "and source operands makes instruction UNPREDICTABLE") static struct hash_control * arm_ops_hsh; static struct hash_control * arm_cond_hsh; +static struct hash_control * arm_vcond_hsh; static struct hash_control * arm_shift_hsh; static struct hash_control * arm_psr_hsh; static struct hash_control * arm_v7m_psr_hsh; @@ -868,15 +947,15 @@ typedef enum asmfunc_states static asmfunc_states asmfunc_state = OUTSIDE_ASMFUNC; #ifdef OBJ_ELF -# define now_it seg_info (now_seg)->tc_segment_info_data.current_it +# define now_pred seg_info (now_seg)->tc_segment_info_data.current_pred #else -static struct current_it now_it; +static struct current_pred now_pred; #endif static inline int -now_it_compatible (int cond) +now_pred_compatible (int cond) { - return (cond & ~1) == (now_it.cc & ~1); + return (cond & ~1) == (now_pred.cc & ~1); } static inline int @@ -885,39 +964,39 @@ conditional_insn (void) return inst.cond != COND_ALWAYS; } -static int in_it_block (void); +static int in_pred_block (void); -static int handle_it_state (void); +static int handle_pred_state (void); static void force_automatic_it_block_close (void); static void it_fsm_post_encode (void); -#define set_it_insn_type(type) \ +#define set_pred_insn_type(type) \ do \ { \ - inst.it_insn_type = type; \ - if (handle_it_state () == FAIL) \ + inst.pred_insn_type = type; \ + if (handle_pred_state () == FAIL) \ return; \ } \ while (0) -#define set_it_insn_type_nonvoid(type, failret) \ +#define set_pred_insn_type_nonvoid(type, failret) \ do \ { \ - inst.it_insn_type = type; \ - if (handle_it_state () == FAIL) \ + inst.pred_insn_type = type; \ + if (handle_pred_state () == FAIL) \ return failret; \ } \ while(0) -#define set_it_insn_type_last() \ +#define set_pred_insn_type_last() \ do \ { \ if (inst.cond == COND_ALWAYS) \ - set_it_insn_type (IF_INSIDE_IT_LAST_INSN); \ + set_pred_insn_type (IF_INSIDE_IT_LAST_INSN); \ else \ - set_it_insn_type (INSIDE_IT_LAST_INSN); \ + set_pred_insn_type (INSIDE_IT_LAST_INSN); \ } \ while (0) @@ -977,11 +1056,11 @@ skip_past_char (char ** str, char c) /* Return TRUE if anything in the expression is a bignum. */ -static int +static bfd_boolean walk_no_bignums (symbolS * sp) { if (symbol_get_value_expression (sp)->X_op == O_big) - return 1; + return TRUE; if (symbol_get_value_expression (sp)->X_add_symbol) { @@ -990,10 +1069,10 @@ walk_no_bignums (symbolS * sp) && walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol))); } - return 0; + return FALSE; } -static int in_my_get_expression = 0; +static bfd_boolean in_my_get_expression = FALSE; /* Third argument to my_get_expression. */ #define GE_NO_PREFIX 0 @@ -1007,7 +1086,6 @@ static int my_get_expression (expressionS * ep, char ** str, int prefix_mode) { char * save_in; - segT seg; /* In unified syntax, all prefixes are optional. */ if (unified_syntax) @@ -1030,16 +1108,17 @@ my_get_expression (expressionS * ep, char ** str, int prefix_mode) if (is_immediate_prefix (**str)) (*str)++; break; - default: abort (); + default: + abort (); } memset (ep, 0, sizeof (expressionS)); save_in = input_line_pointer; input_line_pointer = *str; - in_my_get_expression = 1; - seg = expression (ep); - in_my_get_expression = 0; + in_my_get_expression = TRUE; + expression (ep); + in_my_get_expression = FALSE; if (ep->X_op == O_illegal || ep->X_op == O_absent) { @@ -1052,22 +1131,6 @@ my_get_expression (expressionS * ep, char ** str, int prefix_mode) return 1; } -#ifdef OBJ_AOUT - if (seg != absolute_section - && seg != text_section - && seg != data_section - && seg != bss_section - && seg != undefined_section) - { - inst.error = _("bad segment"); - *str = input_line_pointer; - input_line_pointer = save_in; - return 1; - } -#else - (void) seg; -#endif - /* Get rid of any bignums now, so that we don't generate an error for which we can't establish a line number later on. Big numbers are never valid in instructions, which is where this routine is always called. */ @@ -1086,7 +1149,7 @@ my_get_expression (expressionS * ep, char ** str, int prefix_mode) *str = input_line_pointer; input_line_pointer = save_in; - return 0; + return SUCCESS; } /* Turn a string in input_line_pointer into a floating point constant @@ -1181,6 +1244,7 @@ md_atof (int type, char * litP, int * sizeP) /* We handle all bad expressions here, so that we can report the faulty instruction in the error message. */ + void md_operand (expressionS * exp) { @@ -1190,10 +1254,11 @@ md_operand (expressionS * exp) /* Immediate values. */ +#ifdef OBJ_ELF /* Generic immediate-value read function for use in directives. Accepts anything that 'expression' can fold to a constant. *val receives the number. */ -#ifdef OBJ_ELF + static int immediate_for_directive (int *val) { @@ -1463,6 +1528,41 @@ parse_neon_operand_type (struct neon_type_el *vectype, char **ccp) #define NEON_ALL_LANES 15 #define NEON_INTERLEAVE_LANES 14 +/* Record a use of the given feature. */ +static void +record_feature_use (const arm_feature_set *feature) +{ + if (thumb_mode) + ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used, *feature); + else + ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used, *feature); +} + +/* If the given feature available in the selected CPU, mark it as used. + Returns TRUE iff feature is available. */ +static bfd_boolean +mark_feature_used (const arm_feature_set *feature) +{ + + /* Do not support the use of MVE only instructions when in auto-detection or + -march=all. */ + if (((feature == &mve_ext) || (feature == &mve_fp_ext)) + && ARM_CPU_IS_ANY (cpu_variant)) + { + first_error (BAD_MVE_AUTO); + return FALSE; + } + /* Ensure the option is valid on the current architecture. */ + if (!ARM_CPU_HAS_FEATURE (cpu_variant, *feature)) + return FALSE; + + /* Add the appropriate architecture feature for the barrier option used. + */ + record_feature_use (feature); + + return TRUE; +} + /* Parse either a register or a scalar, with an optional type. Return the register number, and optionally fill in the actual type of the register when multiple alternatives were given (NEON_TYPE_NDQ) in *RTYPE, and @@ -1503,10 +1603,32 @@ parse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type, || (type == REG_TYPE_NSDQ && (reg->type == REG_TYPE_VFS || reg->type == REG_TYPE_VFD || reg->type == REG_TYPE_NQ)) + || (type == REG_TYPE_NSD + && (reg->type == REG_TYPE_VFS || reg->type == REG_TYPE_VFD)) || (type == REG_TYPE_MMXWC && (reg->type == REG_TYPE_MMXWCG))) type = (enum arm_reg_type) reg->type; + if (type == REG_TYPE_MQ) + { + if (!ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext)) + return FAIL; + + if (!reg || reg->type != REG_TYPE_NQ) + return FAIL; + + if (reg->number > 14 && !mark_feature_used (&fpu_vfp_ext_d32)) + { + first_error (_("expected MVE register [q0..q7]")); + return FAIL; + } + type = REG_TYPE_NQ; + } + else if (ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext) + && (type == REG_TYPE_NQ)) + return FAIL; + + if (type != reg->type) return FAIL; @@ -1526,7 +1648,9 @@ parse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type, if (skip_past_char (&str, '[') == SUCCESS) { - if (type != REG_TYPE_VFD) + if (type != REG_TYPE_VFD + && !(type == REG_TYPE_VFS + && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8_2))) { first_error (_("only D registers may be indexed")); return FAIL; @@ -1572,7 +1696,7 @@ parse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type, return reg->number; } -/* Like arm_reg_parse, but allow allow the following extra features: +/* Like arm_reg_parse, but also allow the following extra features: - If RTYPE is non-zero, return the (possibly restricted) type of the register (e.g. Neon double or quad reg when either has been requested). - If this is a Neon vector type with additional type information, fill @@ -1622,8 +1746,12 @@ parse_scalar (char **ccp, int elsize, struct neon_type_el *type) int reg; char *str = *ccp; struct neon_typed_alias atype; + enum arm_reg_type reg_type = REG_TYPE_VFD; - reg = parse_typed_reg_or_scalar (&str, REG_TYPE_VFD, NULL, &atype); + if (elsize == 4) + reg_type = REG_TYPE_VFS; + + reg = parse_typed_reg_or_scalar (&str, reg_type, NULL, &atype); if (reg == FAIL || (atype.defined & NTA_HASINDEX) == 0) return FAIL; @@ -1647,14 +1775,29 @@ parse_scalar (char **ccp, int elsize, struct neon_type_el *type) return reg * 16 + atype.index; } +/* Types of registers in a list. */ + +enum reg_list_els +{ + REGLIST_RN, + REGLIST_CLRM, + REGLIST_VFP_S, + REGLIST_VFP_S_VPR, + REGLIST_VFP_D, + REGLIST_VFP_D_VPR, + REGLIST_NEON_D +}; + /* Parse an ARM register list. Returns the bitmask, or FAIL. */ static long -parse_reg_list (char ** strp) +parse_reg_list (char ** strp, enum reg_list_els etype) { - char * str = * strp; - long range = 0; - int another_range; + char *str = *strp; + long range = 0; + int another_range; + + gas_assert (etype == REGLIST_RN || etype == REGLIST_CLRM); /* We come back here if we get ranges concatenated by '+' or '|'. */ do @@ -1672,11 +1815,35 @@ parse_reg_list (char ** strp) do { int reg; + const char apsr_str[] = "apsr"; + int apsr_str_len = strlen (apsr_str); - if ((reg = arm_reg_parse (&str, REG_TYPE_RN)) == FAIL) + reg = arm_reg_parse (&str, REGLIST_RN); + if (etype == REGLIST_CLRM) { - first_error (_(reg_expected_msgs[REG_TYPE_RN])); - return FAIL; + if (reg == REG_SP || reg == REG_PC) + reg = FAIL; + else if (reg == FAIL + && !strncasecmp (str, apsr_str, apsr_str_len) + && !ISALPHA (*(str + apsr_str_len))) + { + reg = 15; + str += apsr_str_len; + } + + if (reg == FAIL) + { + first_error (_("r0-r12, lr or APSR expected")); + return FAIL; + } + } + else /* etype == REGLIST_RN. */ + { + if (reg == FAIL) + { + first_error (_(reg_expected_msgs[REGLIST_RN])); + return FAIL; + } } if (in_range) @@ -1720,7 +1887,7 @@ parse_reg_list (char ** strp) return FAIL; } } - else + else if (etype == REGLIST_RN) { expressionS exp; @@ -1751,15 +1918,15 @@ parse_reg_list (char ** strp) } else { - if (inst.reloc.type != 0) + if (inst.relocs[0].type != 0) { inst.error = _("expression too complex"); return FAIL; } - memcpy (&inst.reloc.exp, &exp, sizeof (expressionS)); - inst.reloc.type = BFD_RELOC_ARM_MULTI; - inst.reloc.pc_rel = 0; + memcpy (&inst.relocs[0].exp, &exp, sizeof (expressionS)); + inst.relocs[0].type = BFD_RELOC_ARM_MULTI; + inst.relocs[0].pc_rel = 0; } } @@ -1775,15 +1942,6 @@ parse_reg_list (char ** strp) return range; } -/* Types of registers in a list. */ - -enum reg_list_els -{ - REGLIST_VFP_S, - REGLIST_VFP_D, - REGLIST_NEON_D -}; - /* Parse a VFP register list. If the string is invalid return FAIL. Otherwise return the number of registers, and set PBASE to the first register. Parses registers of type ETYPE. @@ -1800,7 +1958,8 @@ enum reg_list_els bug. */ static int -parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype) +parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype, + bfd_boolean *partial_match) { char *str = *ccp; int base_reg; @@ -1811,6 +1970,9 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype) int warned = 0; unsigned long mask = 0; int i; + bfd_boolean vpr_seen = FALSE; + bfd_boolean expect_vpr = + (etype == REGLIST_VFP_S_VPR) || (etype == REGLIST_VFP_D_VPR); if (skip_past_char (&str, '{') == FAIL) { @@ -1821,20 +1983,25 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype) switch (etype) { case REGLIST_VFP_S: + case REGLIST_VFP_S_VPR: regtype = REG_TYPE_VFS; max_regs = 32; break; case REGLIST_VFP_D: + case REGLIST_VFP_D_VPR: regtype = REG_TYPE_VFD; break; case REGLIST_NEON_D: regtype = REG_TYPE_NDQ; break; + + default: + gas_assert (0); } - if (etype != REGLIST_VFP_S) + if (etype != REGLIST_VFP_S && etype != REGLIST_VFP_S_VPR) { /* VFPv3 allows 32 D registers, except for the VFPv3-D16 variant. */ if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_d32)) @@ -1852,19 +2019,54 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype) } base_reg = max_regs; + *partial_match = FALSE; do { int setmask = 1, addregs = 1; + const char vpr_str[] = "vpr"; + int vpr_str_len = strlen (vpr_str); new_base = arm_typed_reg_parse (&str, regtype, ®type, NULL); - if (new_base == FAIL) + if (expect_vpr) + { + if (new_base == FAIL + && !strncasecmp (str, vpr_str, vpr_str_len) + && !ISALPHA (*(str + vpr_str_len)) + && !vpr_seen) + { + vpr_seen = TRUE; + str += vpr_str_len; + if (count == 0) + base_reg = 0; /* Canonicalize VPR only on d0 with 0 regs. */ + } + else if (vpr_seen) + { + first_error (_("VPR expected last")); + return FAIL; + } + else if (new_base == FAIL) + { + if (regtype == REG_TYPE_VFS) + first_error (_("VFP single precision register or VPR " + "expected")); + else /* regtype == REG_TYPE_VFD. */ + first_error (_("VFP/Neon double precision register or VPR " + "expected")); + return FAIL; + } + } + else if (new_base == FAIL) { first_error (_(reg_expected_msgs[regtype])); return FAIL; } + *partial_match = TRUE; + if (vpr_seen) + continue; + if (new_base >= max_regs) { first_error (_("register out of range in list")); @@ -1887,7 +2089,7 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype) return FAIL; } - if ((mask >> new_base) != 0 && ! warned) + if ((mask >> new_base) != 0 && ! warned && !vpr_seen) { as_tsktsk (_("register list not in ascending order")); warned = 1; @@ -1942,11 +2144,17 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype) str++; /* Sanity check -- should have raised a parse error above. */ - if (count == 0 || count > max_regs) + if ((!vpr_seen && count == 0) || count > max_regs) abort (); *pbase = base_reg; + if (expect_vpr && !vpr_seen) + { + first_error (_("VPR expected last")); + return FAIL; + } + /* Final test -- the registers must be consecutive. */ mask >>= base_reg; for (i = 0; i < count; i++) @@ -3209,7 +3417,7 @@ add_to_lit_pool (unsigned int nbytes) { imm1 = inst.operands[1].imm; imm2 = (inst.operands[1].regisimm ? inst.operands[1].reg - : inst.reloc.exp.X_unsigned ? 0 + : inst.relocs[0].exp.X_unsigned ? 0 : ((bfd_int64_t) inst.operands[1].imm) >> 32); if (target_big_endian) { @@ -3225,23 +3433,23 @@ add_to_lit_pool (unsigned int nbytes) { if (nbytes == 4) { - if ((pool->literals[entry].X_op == inst.reloc.exp.X_op) - && (inst.reloc.exp.X_op == O_constant) + if ((pool->literals[entry].X_op == inst.relocs[0].exp.X_op) + && (inst.relocs[0].exp.X_op == O_constant) && (pool->literals[entry].X_add_number - == inst.reloc.exp.X_add_number) + == inst.relocs[0].exp.X_add_number) && (pool->literals[entry].X_md == nbytes) && (pool->literals[entry].X_unsigned - == inst.reloc.exp.X_unsigned)) + == inst.relocs[0].exp.X_unsigned)) break; - if ((pool->literals[entry].X_op == inst.reloc.exp.X_op) - && (inst.reloc.exp.X_op == O_symbol) + if ((pool->literals[entry].X_op == inst.relocs[0].exp.X_op) + && (inst.relocs[0].exp.X_op == O_symbol) && (pool->literals[entry].X_add_number - == inst.reloc.exp.X_add_number) + == inst.relocs[0].exp.X_add_number) && (pool->literals[entry].X_add_symbol - == inst.reloc.exp.X_add_symbol) + == inst.relocs[0].exp.X_add_symbol) && (pool->literals[entry].X_op_symbol - == inst.reloc.exp.X_op_symbol) + == inst.relocs[0].exp.X_op_symbol) && (pool->literals[entry].X_md == nbytes)) break; } @@ -3251,11 +3459,11 @@ add_to_lit_pool (unsigned int nbytes) && (pool->literals[entry].X_op == O_constant) && (pool->literals[entry].X_add_number == (offsetT) imm1) && (pool->literals[entry].X_unsigned - == inst.reloc.exp.X_unsigned) + == inst.relocs[0].exp.X_unsigned) && (pool->literals[entry + 1].X_op == O_constant) && (pool->literals[entry + 1].X_add_number == (offsetT) imm2) && (pool->literals[entry + 1].X_unsigned - == inst.reloc.exp.X_unsigned)) + == inst.relocs[0].exp.X_unsigned)) break; padding_slot_p = ((pool->literals[entry].X_md >> 8) == PADDING_SLOT); @@ -3287,8 +3495,8 @@ add_to_lit_pool (unsigned int nbytes) We also check to make sure the literal operand is a constant number. */ - if (!(inst.reloc.exp.X_op == O_constant - || inst.reloc.exp.X_op == O_big)) + if (!(inst.relocs[0].exp.X_op == O_constant + || inst.relocs[0].exp.X_op == O_big)) { inst.error = _("invalid type for literal pool"); return FAIL; @@ -3301,7 +3509,7 @@ add_to_lit_pool (unsigned int nbytes) return FAIL; } - pool->literals[entry] = inst.reloc.exp; + pool->literals[entry] = inst.relocs[0].exp; pool->literals[entry].X_op = O_constant; pool->literals[entry].X_add_number = 0; pool->literals[entry++].X_md = (PADDING_SLOT << 8) | 4; @@ -3314,22 +3522,22 @@ add_to_lit_pool (unsigned int nbytes) return FAIL; } - pool->literals[entry] = inst.reloc.exp; + pool->literals[entry] = inst.relocs[0].exp; pool->literals[entry].X_op = O_constant; pool->literals[entry].X_add_number = imm1; - pool->literals[entry].X_unsigned = inst.reloc.exp.X_unsigned; + pool->literals[entry].X_unsigned = inst.relocs[0].exp.X_unsigned; pool->literals[entry++].X_md = 4; - pool->literals[entry] = inst.reloc.exp; + pool->literals[entry] = inst.relocs[0].exp; pool->literals[entry].X_op = O_constant; pool->literals[entry].X_add_number = imm2; - pool->literals[entry].X_unsigned = inst.reloc.exp.X_unsigned; + pool->literals[entry].X_unsigned = inst.relocs[0].exp.X_unsigned; pool->literals[entry].X_md = 4; pool->alignment = 3; pool->next_free_entry += 1; } else { - pool->literals[entry] = inst.reloc.exp; + pool->literals[entry] = inst.relocs[0].exp; pool->literals[entry].X_md = 4; } @@ -3345,13 +3553,13 @@ add_to_lit_pool (unsigned int nbytes) } else if (padding_slot_p) { - pool->literals[entry] = inst.reloc.exp; + pool->literals[entry] = inst.relocs[0].exp; pool->literals[entry].X_md = nbytes; } - inst.reloc.exp.X_op = O_symbol; - inst.reloc.exp.X_add_number = pool_size; - inst.reloc.exp.X_add_symbol = pool->symbol; + inst.relocs[0].exp.X_op = O_symbol; + inst.relocs[0].exp.X_add_number = pool_size; + inst.relocs[0].exp.X_add_symbol = pool->symbol; return SUCCESS; } @@ -3552,7 +3760,9 @@ s_arm_elf_cons (int nbytes) } if (size > nbytes) - as_bad (_("%s relocations do not fit in %d bytes"), + as_bad (ngettext ("%s relocations do not fit in %d byte", + "%s relocations do not fit in %d bytes", + nbytes), howto->name, nbytes); else { @@ -3638,10 +3848,10 @@ emit_insn (expressionS *exp, int nbytes) } else { - if (now_it.state == AUTOMATIC_IT_BLOCK) - set_it_insn_type_nonvoid (OUTSIDE_IT_INSN, 0); + if (now_pred.state == AUTOMATIC_PRED_BLOCK) + set_pred_insn_type_nonvoid (OUTSIDE_PRED_INSN, 0); else - set_it_insn_type_nonvoid (NEUTRAL_IT_INSN, 0); + set_pred_insn_type_nonvoid (NEUTRAL_IT_INSN, 0); if (thumb_mode && (size > THUMB_SIZE) && !target_big_endian) emit_thumb32_expr (exp); @@ -3945,7 +4155,7 @@ s_arm_unwind_save_core (void) long range; int n; - range = parse_reg_list (&input_line_pointer); + range = parse_reg_list (&input_line_pointer, REGLIST_RN); if (range == FAIL) { as_bad (_("expected register list")); @@ -4072,8 +4282,10 @@ s_arm_unwind_save_vfp_armv6 (void) valueT op; int num_vfpv3_regs = 0; int num_regs_below_16; + bfd_boolean partial_match; - count = parse_vfp_reg_list (&input_line_pointer, &start, REGLIST_VFP_D); + count = parse_vfp_reg_list (&input_line_pointer, &start, REGLIST_VFP_D, + &partial_match); if (count == FAIL) { as_bad (_("expected register list")); @@ -4120,8 +4332,10 @@ s_arm_unwind_save_vfp (void) int count; unsigned int reg; valueT op; + bfd_boolean partial_match; - count = parse_vfp_reg_list (&input_line_pointer, ®, REGLIST_VFP_D); + count = parse_vfp_reg_list (&input_line_pointer, ®, REGLIST_VFP_D, + &partial_match); if (count == FAIL) { as_bad (_("expected register list")); @@ -4619,7 +4833,7 @@ s_arm_eabi_attribute (int ignored ATTRIBUTE_UNUSED) { int tag = obj_elf_vendor_attribute (OBJ_ATTR_PROC); - if (tag < NUM_KNOWN_OBJ_ATTRIBUTES) + if (tag >= 0 && tag < NUM_KNOWN_OBJ_ATTRIBUTES) attributes_set_explicitly[tag] = 1; } @@ -4736,7 +4950,7 @@ const pseudo_typeS md_pseudo_table[] = {"4byte", cons, 4}, {"8byte", cons, 8}, /* These are used for dwarf2. */ - { "file", (void (*) (int)) dwarf2_directive_file, 0 }, + { "file", dwarf2_directive_file, 0 }, { "loc", dwarf2_directive_loc, 0 }, { "loc_mark_labels", dwarf2_directive_loc_mark_labels, 0 }, #endif @@ -4769,6 +4983,7 @@ parse_immediate (char **str, int *val, int min, int max, bfd_boolean prefix_opt) { expressionS exp; + my_get_expression (&exp, str, prefix_opt ? GE_OPT_PREFIX : GE_IMM_PREFIX); if (exp.X_op != O_constant) { @@ -5169,7 +5384,7 @@ parse_shift (char **str, int i, enum parse_shift_mode mode) inst.operands[i].imm = reg; inst.operands[i].immisreg = 1; } - else if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX)) + else if (my_get_expression (&inst.relocs[0].exp, &p, GE_IMM_PREFIX)) return FAIL; } inst.operands[i].shift_kind = shift; @@ -5201,8 +5416,8 @@ parse_shifter_operand (char **str, int i) inst.operands[i].isreg = 1; /* parse_shift will override this if appropriate */ - inst.reloc.exp.X_op = O_constant; - inst.reloc.exp.X_add_number = 0; + inst.relocs[0].exp.X_op = O_constant; + inst.relocs[0].exp.X_add_number = 0; if (skip_past_comma (str) == FAIL) return SUCCESS; @@ -5211,7 +5426,7 @@ parse_shifter_operand (char **str, int i) return parse_shift (str, i, NO_SHIFT_RESTRICT); } - if (my_get_expression (&inst.reloc.exp, str, GE_IMM_PREFIX)) + if (my_get_expression (&inst.relocs[0].exp, str, GE_IMM_PREFIX)) return FAIL; if (skip_past_comma (str) == SUCCESS) @@ -5220,7 +5435,7 @@ parse_shifter_operand (char **str, int i) if (my_get_expression (&exp, str, GE_NO_PREFIX)) return FAIL; - if (exp.X_op != O_constant || inst.reloc.exp.X_op != O_constant) + if (exp.X_op != O_constant || inst.relocs[0].exp.X_op != O_constant) { inst.error = _("constant expression expected"); return FAIL; @@ -5232,19 +5447,20 @@ parse_shifter_operand (char **str, int i) inst.error = _("invalid rotation"); return FAIL; } - if (inst.reloc.exp.X_add_number < 0 || inst.reloc.exp.X_add_number > 255) + if (inst.relocs[0].exp.X_add_number < 0 + || inst.relocs[0].exp.X_add_number > 255) { inst.error = _("invalid constant"); return FAIL; } /* Encode as specified. */ - inst.operands[i].imm = inst.reloc.exp.X_add_number | value << 7; + inst.operands[i].imm = inst.relocs[0].exp.X_add_number | value << 7; return SUCCESS; } - inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE; - inst.reloc.pc_rel = 0; + inst.relocs[0].type = BFD_RELOC_ARM_IMMEDIATE; + inst.relocs[0].pc_rel = 0; return SUCCESS; } @@ -5415,12 +5631,12 @@ parse_shifter_operand_group_reloc (char **str, int i) /* We now have the group relocation table entry corresponding to the name in the assembler source. Next, we parse the expression. */ - if (my_get_expression (&inst.reloc.exp, str, GE_NO_PREFIX)) + if (my_get_expression (&inst.relocs[0].exp, str, GE_NO_PREFIX)) return PARSE_OPERAND_FAIL_NO_BACKTRACK; /* Record the relocation type (always the ALU variant here). */ - inst.reloc.type = (bfd_reloc_code_real_type) entry->alu_code; - gas_assert (inst.reloc.type != 0); + inst.relocs[0].type = (bfd_reloc_code_real_type) entry->alu_code; + gas_assert (inst.relocs[0].type != 0); return PARSE_OPERAND_SUCCESS; } @@ -5459,23 +5675,23 @@ parse_neon_alignment (char **str, int i) } /* Parse all forms of an ARM address expression. Information is written - to inst.operands[i] and/or inst.reloc. + to inst.operands[i] and/or inst.relocs[0]. Preindexed addressing (.preind=1): - [Rn, #offset] .reg=Rn .reloc.exp=offset + [Rn, #offset] .reg=Rn .relocs[0].exp=offset [Rn, +/-Rm] .reg=Rn .imm=Rm .immisreg=1 .negative=0/1 [Rn, +/-Rm, shift] .reg=Rn .imm=Rm .immisreg=1 .negative=0/1 - .shift_kind=shift .reloc.exp=shift_imm + .shift_kind=shift .relocs[0].exp=shift_imm These three may have a trailing ! which causes .writeback to be set also. Postindexed addressing (.postind=1, .writeback=1): - [Rn], #offset .reg=Rn .reloc.exp=offset + [Rn], #offset .reg=Rn .relocs[0].exp=offset [Rn], +/-Rm .reg=Rn .imm=Rm .immisreg=1 .negative=0/1 [Rn], +/-Rm, shift .reg=Rn .imm=Rm .immisreg=1 .negative=0/1 - .shift_kind=shift .reloc.exp=shift_imm + .shift_kind=shift .relocs[0].exp=shift_imm Unindexed addressing (.preind=0, .postind=0): @@ -5484,11 +5700,11 @@ parse_neon_alignment (char **str, int i) Other: [Rn]{!} shorthand for [Rn,#0]{!} - =immediate .isreg=0 .reloc.exp=immediate - label .reg=PC .reloc.pc_rel=1 .reloc.exp=label + =immediate .isreg=0 .relocs[0].exp=immediate + label .reg=PC .relocs[0].pc_rel=1 .relocs[0].exp=label It is the caller's responsibility to check for addressing modes not - supported by the instruction, and to set inst.reloc.type. */ + supported by the instruction, and to set inst.relocs[0].type. */ static parse_operand_result parse_address_main (char **str, int i, int group_relocations, @@ -5502,15 +5718,15 @@ parse_address_main (char **str, int i, int group_relocations, if (skip_past_char (&p, '=') == FAIL) { /* Bare address - translate to PC-relative offset. */ - inst.reloc.pc_rel = 1; + inst.relocs[0].pc_rel = 1; inst.operands[i].reg = REG_PC; inst.operands[i].isreg = 1; inst.operands[i].preind = 1; - if (my_get_expression (&inst.reloc.exp, &p, GE_OPT_PREFIX_BIG)) + if (my_get_expression (&inst.relocs[0].exp, &p, GE_OPT_PREFIX_BIG)) return PARSE_OPERAND_FAIL; } - else if (parse_big_immediate (&p, i, &inst.reloc.exp, + else if (parse_big_immediate (&p, i, &inst.relocs[0].exp, /*allow_symbol_p=*/TRUE)) return PARSE_OPERAND_FAIL; @@ -5585,29 +5801,32 @@ parse_address_main (char **str, int i, int group_relocations, /* We now have the group relocation table entry corresponding to the name in the assembler source. Next, we parse the expression. */ - if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX)) + if (my_get_expression (&inst.relocs[0].exp, &p, GE_NO_PREFIX)) return PARSE_OPERAND_FAIL_NO_BACKTRACK; /* Record the relocation type. */ switch (group_type) { case GROUP_LDR: - inst.reloc.type = (bfd_reloc_code_real_type) entry->ldr_code; + inst.relocs[0].type + = (bfd_reloc_code_real_type) entry->ldr_code; break; case GROUP_LDRS: - inst.reloc.type = (bfd_reloc_code_real_type) entry->ldrs_code; + inst.relocs[0].type + = (bfd_reloc_code_real_type) entry->ldrs_code; break; case GROUP_LDC: - inst.reloc.type = (bfd_reloc_code_real_type) entry->ldc_code; + inst.relocs[0].type + = (bfd_reloc_code_real_type) entry->ldc_code; break; default: gas_assert (0); } - if (inst.reloc.type == 0) + if (inst.relocs[0].type == 0) { inst.error = _("this group relocation is not allowed on this instruction"); return PARSE_OPERAND_FAIL_NO_BACKTRACK; @@ -5616,11 +5835,12 @@ parse_address_main (char **str, int i, int group_relocations, else { char *q = p; - if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX)) + + if (my_get_expression (&inst.relocs[0].exp, &p, GE_IMM_PREFIX)) return PARSE_OPERAND_FAIL; /* If the offset is 0, find out if it's a +0 or -0. */ - if (inst.reloc.exp.X_op == O_constant - && inst.reloc.exp.X_add_number == 0) + if (inst.relocs[0].exp.X_op == O_constant + && inst.relocs[0].exp.X_add_number == 0) { skip_whitespace (q); if (*q == '#') @@ -5706,16 +5926,17 @@ parse_address_main (char **str, int i, int group_relocations, else { char *q = p; + if (inst.operands[i].negative) { inst.operands[i].negative = 0; p--; } - if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX)) + if (my_get_expression (&inst.relocs[0].exp, &p, GE_IMM_PREFIX)) return PARSE_OPERAND_FAIL; /* If the offset is 0, find out if it's a +0 or -0. */ - if (inst.reloc.exp.X_op == O_constant - && inst.reloc.exp.X_add_number == 0) + if (inst.relocs[0].exp.X_op == O_constant + && inst.relocs[0].exp.X_add_number == 0) { skip_whitespace (q); if (*q == '#') @@ -5735,8 +5956,8 @@ parse_address_main (char **str, int i, int group_relocations, if (inst.operands[i].preind == 0 && inst.operands[i].postind == 0) { inst.operands[i].preind = 1; - inst.reloc.exp.X_op = O_constant; - inst.reloc.exp.X_add_number = 0; + inst.relocs[0].exp.X_op = O_constant; + inst.relocs[0].exp.X_add_number = 0; } *str = p; return PARSE_OPERAND_SUCCESS; @@ -5764,28 +5985,28 @@ parse_half (char **str) p = *str; skip_past_char (&p, '#'); if (strncasecmp (p, ":lower16:", 9) == 0) - inst.reloc.type = BFD_RELOC_ARM_MOVW; + inst.relocs[0].type = BFD_RELOC_ARM_MOVW; else if (strncasecmp (p, ":upper16:", 9) == 0) - inst.reloc.type = BFD_RELOC_ARM_MOVT; + inst.relocs[0].type = BFD_RELOC_ARM_MOVT; - if (inst.reloc.type != BFD_RELOC_UNUSED) + if (inst.relocs[0].type != BFD_RELOC_UNUSED) { p += 9; skip_whitespace (p); } - if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX)) + if (my_get_expression (&inst.relocs[0].exp, &p, GE_NO_PREFIX)) return FAIL; - if (inst.reloc.type == BFD_RELOC_UNUSED) + if (inst.relocs[0].type == BFD_RELOC_UNUSED) { - if (inst.reloc.exp.X_op != O_constant) + if (inst.relocs[0].exp.X_op != O_constant) { inst.error = _("constant expression expected"); return FAIL; } - if (inst.reloc.exp.X_add_number < 0 - || inst.reloc.exp.X_add_number > 0xffff) + if (inst.relocs[0].exp.X_add_number < 0 + || inst.relocs[0].exp.X_add_number > 0xffff) { inst.error = _("immediate value out of range"); return FAIL; @@ -5994,6 +6215,39 @@ check_suffix: return FAIL; } +static int +parse_sys_vldr_vstr (char **str) +{ + unsigned i; + int val = FAIL; + struct { + const char *name; + int regl; + int regh; + } sysregs[] = { + {"FPSCR", 0x1, 0x0}, + {"FPSCR_nzcvqc", 0x2, 0x0}, + {"VPR", 0x4, 0x1}, + {"P0", 0x5, 0x1}, + {"FPCXTNS", 0x6, 0x1}, + {"FPCXTS", 0x7, 0x1} + }; + char *op_end = strchr (*str, ','); + size_t op_strlen = op_end - *str; + + for (i = 0; i < sizeof (sysregs) / sizeof (sysregs[0]); i++) + { + if (!strncmp (*str, sysregs[i].name, op_strlen)) + { + val = sysregs[i].regl | (sysregs[i].regh << 3); + *str = op_end; + break; + } + } + + return val; +} + /* Parse the flags argument to CPSI[ED]. Returns FAIL on error, or a value suitable for splatting into the AIF field of the instruction. */ @@ -6125,32 +6379,6 @@ parse_cond (char **str) return c->value; } -/* Record a use of the given feature. */ -static void -record_feature_use (const arm_feature_set *feature) -{ - if (thumb_mode) - ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used, *feature); - else - ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used, *feature); -} - -/* If the given feature available in the selected CPU, mark it as used. - Returns TRUE iff feature is available. */ -static bfd_boolean -mark_feature_used (const arm_feature_set *feature) -{ - /* Ensure the option is valid on the current architecture. */ - if (!ARM_CPU_HAS_FEATURE (cpu_variant, *feature)) - return FALSE; - - /* Add the appropriate architecture feature for the barrier option used. - */ - record_feature_use (feature); - - return TRUE; -} - /* Parse an option for a barrier instruction. Returns the encoding for the option, or FAIL. */ static int @@ -6213,7 +6441,7 @@ parse_tb (char **str) { if (parse_shift (&p, 0, SHIFT_LSL_IMMEDIATE) == FAIL) return FAIL; - if (inst.reloc.exp.X_add_number != 1) + if (inst.relocs[0].exp.X_add_number != 1) { inst.error = _("invalid shift"); return FAIL; @@ -6476,9 +6704,15 @@ enum operand_parse_code OP_RVS, /* VFP single precision register */ OP_RVD, /* VFP double precision register (0..15) */ OP_RND, /* Neon double precision register (0..31) */ + OP_RNDMQ, /* Neon double precision (0..31) or MVE vector register. */ + OP_RNDMQR, /* Neon double precision (0..31), MVE vector or ARM register. + */ OP_RNQ, /* Neon quad precision register */ + OP_RNQMQ, /* Neon quad or MVE vector register. */ OP_RVSD, /* VFP single or double precision register */ + OP_RNSD, /* Neon single or double precision register */ OP_RNDQ, /* Neon double or quad precision register */ + OP_RNDQMQ, /* Neon double, quad or MVE vector register. */ OP_RNSDQ, /* Neon single, double or quad precision register */ OP_RNSC, /* Neon scalar D[X] */ OP_RVC, /* VFP control register */ @@ -6493,24 +6727,42 @@ enum operand_parse_code OP_RIWG, /* iWMMXt wCG register */ OP_RXA, /* XScale accumulator register */ + OP_RNSDQMQ, /* Neon single, double or quad register or MVE vector register + */ + OP_RNSDQMQR, /* Neon single, double or quad register, MVE vector register or + GPR (no SP/SP) */ + OP_RMQ, /* MVE vector register. */ + + /* New operands for Armv8.1-M Mainline. */ + OP_LR, /* ARM LR register */ + OP_RRe, /* ARM register, only even numbered. */ + OP_RRo, /* ARM register, only odd numbered, not r13 or r15. */ + OP_RRnpcsp_I32, /* ARM register (no BadReg) or literal 1 .. 32 */ + OP_REGLST, /* ARM register list */ + OP_CLRMLST, /* CLRM register list */ OP_VRSLST, /* VFP single-precision register list */ OP_VRDLST, /* VFP double-precision register list */ OP_VRSDLST, /* VFP single or double-precision register list (& quad) */ OP_NRDLST, /* Neon double-precision register list (d0-d31, qN aliases) */ OP_NSTRLST, /* Neon element/structure list */ + OP_VRSDVLST, /* VFP single or double-precision register list and VPR */ OP_RNDQ_I0, /* Neon D or Q reg, or immediate zero. */ OP_RVSD_I0, /* VFP S or D reg, or immediate zero. */ OP_RSVD_FI0, /* VFP S or D reg, or floating point immediate zero. */ OP_RR_RNSC, /* ARM reg or Neon scalar. */ + OP_RNSD_RNSC, /* Neon S or D reg, or Neon scalar. */ OP_RNSDQ_RNSC, /* Vector S, D or Q reg, or Neon scalar. */ + OP_RNSDQ_RNSC_MQ, /* Vector S, D or Q reg, Neon scalar or MVE vector register. + */ OP_RNDQ_RNSC, /* Neon D or Q reg, or Neon scalar. */ OP_RND_RNSC, /* Neon D reg, or Neon scalar. */ OP_VMOV, /* Neon VMOV operands. */ OP_RNDQ_Ibig, /* Neon D or Q reg, or big immediate for logic and VMVN. */ OP_RNDQ_I63b, /* Neon D or Q reg, or immediate for shift. */ OP_RIWR_I32z, /* iWMMXt wR register, or immediate 0 .. 32 for iWMMXt2. */ + OP_VLDR, /* VLDR operand. */ OP_I0, /* immediate zero */ OP_I7, /* immediate value 0 .. 7 */ @@ -6541,6 +6793,7 @@ enum operand_parse_code OP_EXP, /* arbitrary expression */ OP_EXPi, /* same, with optional immediate prefix */ OP_EXPr, /* same, with optional relocation suffix */ + OP_EXPs, /* same, with optional non-first operand relocation suffix */ OP_HALF, /* 0 .. 65535 or low/high reloc. */ OP_IROT1, /* VCADD rotate immediate: 90, 270. */ OP_IROT2, /* VCMLA rotate immediate: 0, 90, 180, 270. */ @@ -6570,13 +6823,17 @@ enum operand_parse_code OP_oI255c, /* curly-brace enclosed, 0 .. 255 */ OP_oRR, /* ARM register */ + OP_oLR, /* ARM LR register */ OP_oRRnpc, /* ARM register, not the PC */ OP_oRRnpcsp, /* ARM register, neither the PC nor the SP (a.k.a. BadReg) */ OP_oRRw, /* ARM register, not r15, optional trailing ! */ OP_oRND, /* Optional Neon double precision register */ OP_oRNQ, /* Optional Neon quad precision register */ + OP_oRNDQMQ, /* Optional Neon double, quad or MVE vector register. */ OP_oRNDQ, /* Optional Neon double or quad precision register */ OP_oRNSDQ, /* Optional single, double or quad precision vector register */ + OP_oRNSDQMQ, /* Optional single, double or quad register or MVE vector + register. */ OP_oSHll, /* LSL immediate */ OP_oSHar, /* ASR immediate */ OP_oSHllar, /* LSL or ASR immediate */ @@ -6605,6 +6862,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) enum arm_reg_type rtype; parse_operand_result result; unsigned int op_parse_code; + bfd_boolean partial_match; #define po_char_or_fail(chr) \ do \ @@ -6738,6 +6996,10 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) case OP_RRnpc: case OP_RRnpcsp: case OP_oRR: + case OP_RRe: + case OP_RRo: + case OP_LR: + case OP_oLR: case OP_RR: po_reg_or_fail (REG_TYPE_RN); break; case OP_RCP: po_reg_or_fail (REG_TYPE_CP); break; case OP_RCN: po_reg_or_fail (REG_TYPE_CN); break; @@ -6745,6 +7007,14 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) case OP_RVS: po_reg_or_fail (REG_TYPE_VFS); break; case OP_RVD: po_reg_or_fail (REG_TYPE_VFD); break; case OP_oRND: + case OP_RNDMQR: + po_reg_or_goto (REG_TYPE_RN, try_rndmq); + break; + try_rndmq: + case OP_RNDMQ: + po_reg_or_goto (REG_TYPE_MQ, try_rnd); + break; + try_rnd: case OP_RND: po_reg_or_fail (REG_TYPE_VFD); break; case OP_RVC: po_reg_or_goto (REG_TYPE_VFC, coproc_reg); @@ -6764,13 +7034,37 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) case OP_RIWG: po_reg_or_fail (REG_TYPE_MMXWCG); break; case OP_RXA: po_reg_or_fail (REG_TYPE_XSCALE); break; case OP_oRNQ: + case OP_RNQMQ: + po_reg_or_goto (REG_TYPE_MQ, try_nq); + break; + try_nq: case OP_RNQ: po_reg_or_fail (REG_TYPE_NQ); break; + case OP_RNSD: po_reg_or_fail (REG_TYPE_NSD); break; + case OP_oRNDQMQ: + case OP_RNDQMQ: + po_reg_or_goto (REG_TYPE_MQ, try_rndq); + break; + try_rndq: case OP_oRNDQ: case OP_RNDQ: po_reg_or_fail (REG_TYPE_NDQ); break; case OP_RVSD: po_reg_or_fail (REG_TYPE_VFSD); break; case OP_oRNSDQ: case OP_RNSDQ: po_reg_or_fail (REG_TYPE_NSDQ); break; - + case OP_RNSDQMQR: + po_reg_or_goto (REG_TYPE_RN, try_mq); + break; + try_mq: + case OP_oRNSDQMQ: + case OP_RNSDQMQ: + po_reg_or_goto (REG_TYPE_MQ, try_nsdq2); + break; + try_nsdq2: + po_reg_or_fail (REG_TYPE_NSDQ); + inst.error = 0; + break; + case OP_RMQ: + po_reg_or_fail (REG_TYPE_MQ); + break; /* Neon scalar. Using an element size of 8 means that some invalid scalars are accepted here, so deal with those in later code. */ case OP_RNSC: po_scalar_or_goto (8, failure); break; @@ -6813,6 +7107,10 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) } break; + case OP_RNSDQ_RNSC_MQ: + po_reg_or_goto (REG_TYPE_MQ, try_rnsdq_rnsc); + break; + try_rnsdq_rnsc: case OP_RNSDQ_RNSC: { po_scalar_or_goto (8, try_nsdq); @@ -6822,6 +7120,18 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) } break; + case OP_RNSD_RNSC: + { + po_scalar_or_goto (8, try_s_scalar); + break; + try_s_scalar: + po_scalar_or_goto (4, try_nsd); + break; + try_nsd: + po_reg_or_fail (REG_TYPE_NSD); + } + break; + case OP_RNDQ_RNSC: { po_scalar_or_goto (8, try_ndq); @@ -6936,19 +7246,19 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) /* Expressions */ case OP_EXPi: EXPi: - po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str, + po_misc_or_fail (my_get_expression (&inst.relocs[0].exp, &str, GE_OPT_PREFIX)); break; case OP_EXP: - po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str, + po_misc_or_fail (my_get_expression (&inst.relocs[0].exp, &str, GE_NO_PREFIX)); break; case OP_EXPr: EXPr: - po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str, + po_misc_or_fail (my_get_expression (&inst.relocs[0].exp, &str, GE_NO_PREFIX)); - if (inst.reloc.exp.X_op == O_symbol) + if (inst.relocs[0].exp.X_op == O_symbol) { val = parse_reloc (&str); if (val == -1) @@ -6964,6 +7274,20 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) } break; + case OP_EXPs: + po_misc_or_fail (my_get_expression (&inst.relocs[i].exp, &str, + GE_NO_PREFIX)); + if (inst.relocs[i].exp.X_op == O_symbol) + { + inst.operands[i].hasreloc = 1; + } + else if (inst.relocs[i].exp.X_op == O_constant) + { + inst.operands[i].imm = inst.relocs[i].exp.X_add_number; + inst.operands[i].hasreloc = 0; + } + break; + /* Operand for MOVW or MOVT. */ case OP_HALF: po_misc_or_fail (parse_half (&str)); @@ -7052,6 +7376,13 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) val = parse_psr (&str, op_parse_code == OP_wPSR); break; + case OP_VLDR: + po_reg_or_goto (REG_TYPE_VFSD, try_sysreg); + break; + try_sysreg: + val = parse_sys_vldr_vstr (&str); + break; + case OP_APSR_RR: po_reg_or_goto (REG_TYPE_RN, try_apsr); break; @@ -7087,7 +7418,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) /* Register lists. */ case OP_REGLST: - val = parse_reg_list (&str); + val = parse_reg_list (&str, REGLIST_RN); if (*str == '^') { inst.operands[i].writeback = 1; @@ -7095,30 +7426,48 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) } break; + case OP_CLRMLST: + val = parse_reg_list (&str, REGLIST_CLRM); + break; + case OP_VRSLST: - val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_S); + val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_S, + &partial_match); break; case OP_VRDLST: - val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_D); + val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_D, + &partial_match); break; case OP_VRSDLST: /* Allow Q registers too. */ val = parse_vfp_reg_list (&str, &inst.operands[i].reg, - REGLIST_NEON_D); + REGLIST_NEON_D, &partial_match); if (val == FAIL) { inst.error = NULL; val = parse_vfp_reg_list (&str, &inst.operands[i].reg, - REGLIST_VFP_S); + REGLIST_VFP_S, &partial_match); + inst.operands[i].issingle = 1; + } + break; + + case OP_VRSDVLST: + val = parse_vfp_reg_list (&str, &inst.operands[i].reg, + REGLIST_VFP_D_VPR, &partial_match); + if (val == FAIL && !partial_match) + { + inst.error = NULL; + val = parse_vfp_reg_list (&str, &inst.operands[i].reg, + REGLIST_VFP_S_VPR, &partial_match); inst.operands[i].issingle = 1; } break; case OP_NRDLST: val = parse_vfp_reg_list (&str, &inst.operands[i].reg, - REGLIST_NEON_D); + REGLIST_NEON_D, &partial_match); break; case OP_NSTRLST: @@ -7210,6 +7559,10 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) inst.error = BAD_PC; break; + case OP_VLDR: + if (inst.operands[i].isreg) + break; + /* fall through. */ case OP_CPSF: case OP_ENDI: case OP_oROR: @@ -7218,9 +7571,11 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) case OP_COND: case OP_oBARRIER_I15: case OP_REGLST: + case OP_CLRMLST: case OP_VRSLST: case OP_VRDLST: case OP_VRSDLST: + case OP_VRSDVLST: case OP_NRDLST: case OP_NSTRLST: if (val == FAIL) @@ -7228,6 +7583,30 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) inst.operands[i].imm = val; break; + case OP_LR: + case OP_oLR: + if (inst.operands[i].reg != REG_LR) + inst.error = _("operand must be LR register"); + break; + + case OP_RRe: + if (inst.operands[i].isreg + && (inst.operands[i].reg & 0x00000001) != 0) + inst.error = BAD_ODD; + break; + + case OP_RRo: + if (inst.operands[i].isreg) + { + if ((inst.operands[i].reg & 0x00000001) != 1) + inst.error = BAD_EVEN; + else if (inst.operands[i].reg == REG_SP) + as_tsktsk (MVE_BAD_SP); + else if (inst.operands[i].reg == REG_PC) + inst.error = BAD_PC; + } + break; + default: break; } @@ -7245,7 +7624,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) /* The parse routine should already have set inst.error, but set a default here just in case. */ if (!inst.error) - inst.error = _("syntax error"); + inst.error = BAD_SYNTAX; return FAIL; } @@ -7257,7 +7636,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) && upat[i+1] == OP_stop) { if (!inst.error) - inst.error = _("syntax error"); + inst.error = BAD_SYNTAX; return FAIL; } @@ -7338,7 +7717,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) static void do_scalar_fp16_v82_encode (void) { - if (inst.cond != COND_ALWAYS) + if (inst.cond < COND_ALWAYS) as_warn (_("ARMv8.2 scalar fp16 instruction cannot be conditional," " the behaviour is UNPREDICTABLE")); constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_fp16), @@ -7484,7 +7863,7 @@ encode_arm_shift (int i) inst.instruction |= inst.operands[i].imm << 8; } else - inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM; + inst.relocs[0].type = BFD_RELOC_ARM_SHIFT_IMM; } } @@ -7499,7 +7878,7 @@ encode_arm_shifter_operand (int i) else { inst.instruction |= INST_IMMEDIATE; - if (inst.reloc.type != BFD_RELOC_ARM_IMMEDIATE) + if (inst.relocs[0].type != BFD_RELOC_ARM_IMMEDIATE) inst.instruction |= inst.operands[i].imm; } } @@ -7574,13 +7953,13 @@ encode_arm_addr_mode_2 (int i, bfd_boolean is_t) else { inst.instruction |= inst.operands[i].shift_kind << 5; - inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM; + inst.relocs[0].type = BFD_RELOC_ARM_SHIFT_IMM; } } } - else /* immediate offset in inst.reloc */ + else /* immediate offset in inst.relocs[0] */ { - if (is_pc && !inst.reloc.pc_rel) + if (is_pc && !inst.relocs[0].pc_rel) { const bfd_boolean is_load = ((inst.instruction & LOAD_BIT) != 0); @@ -7597,12 +7976,12 @@ encode_arm_addr_mode_2 (int i, bfd_boolean is_t) as_tsktsk (_("use of PC in this instruction is deprecated")); } - if (inst.reloc.type == BFD_RELOC_UNUSED) + if (inst.relocs[0].type == BFD_RELOC_UNUSED) { /* Prefer + for zero encoded value. */ if (!inst.operands[i].negative) inst.instruction |= INDEX_UP; - inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM; + inst.relocs[0].type = BFD_RELOC_ARM_OFFSET_IMM; } } } @@ -7634,19 +8013,19 @@ encode_arm_addr_mode_3 (int i, bfd_boolean is_t) if (!inst.operands[i].negative) inst.instruction |= INDEX_UP; } - else /* immediate offset in inst.reloc */ + else /* immediate offset in inst.relocs[0] */ { - constraint ((inst.operands[i].reg == REG_PC && !inst.reloc.pc_rel + constraint ((inst.operands[i].reg == REG_PC && !inst.relocs[0].pc_rel && inst.operands[i].writeback), BAD_PC_WRITEBACK); inst.instruction |= HWOFFSET_IMM; - if (inst.reloc.type == BFD_RELOC_UNUSED) + if (inst.relocs[0].type == BFD_RELOC_UNUSED) { /* Prefer + for zero encoded value. */ if (!inst.operands[i].negative) inst.instruction |= INDEX_UP; - inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8; + inst.relocs[0].type = BFD_RELOC_ARM_OFFSET_IMM8; } } } @@ -7899,7 +8278,7 @@ enum lit_type static void do_vfp_nsyn_opcode (const char *); -/* inst.reloc.exp describes an "=expr" load pseudo-operation. +/* inst.relocs[0].exp describes an "=expr" load pseudo-operation. Determine whether it can be performed with a move instruction; if it can, convert inst.instruction to that move instruction and return TRUE; if it can't, convert inst.instruction to a literal-pool @@ -7926,28 +8305,28 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3) return TRUE; } - if (inst.reloc.exp.X_op != O_constant - && inst.reloc.exp.X_op != O_symbol - && inst.reloc.exp.X_op != O_big) + if (inst.relocs[0].exp.X_op != O_constant + && inst.relocs[0].exp.X_op != O_symbol + && inst.relocs[0].exp.X_op != O_big) { inst.error = _("constant expression expected"); return TRUE; } - if (inst.reloc.exp.X_op == O_constant - || inst.reloc.exp.X_op == O_big) + if (inst.relocs[0].exp.X_op == O_constant + || inst.relocs[0].exp.X_op == O_big) { #if defined BFD_HOST_64_BIT bfd_int64_t v; #else offsetT v; #endif - if (inst.reloc.exp.X_op == O_big) + if (inst.relocs[0].exp.X_op == O_big) { LITTLENUM_TYPE w[X_PRECISION]; LITTLENUM_TYPE * l; - if (inst.reloc.exp.X_add_number == -1) + if (inst.relocs[0].exp.X_add_number == -1) { gen_to_words (w, X_PRECISION, E_PRECISION); l = w; @@ -7971,7 +8350,7 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3) #endif } else - v = inst.reloc.exp.X_add_number; + v = inst.relocs[0].exp.X_add_number; if (!inst.operands[i].issingle) { @@ -8060,7 +8439,7 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3) unsigned immlo = inst.operands[1].imm; unsigned immhi = inst.operands[1].regisimm ? inst.operands[1].reg - : inst.reloc.exp.X_unsigned + : inst.relocs[0].exp.X_unsigned ? 0 : ((bfd_int64_t)((int) immlo)) >> 32; int cmode = neon_cmode_for_move_imm (immlo, immhi, FALSE, &immbits, @@ -8135,8 +8514,8 @@ move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3) inst.operands[1].reg = REG_PC; inst.operands[1].isreg = 1; inst.operands[1].preind = 1; - inst.reloc.pc_rel = 1; - inst.reloc.type = (thumb_p + inst.relocs[0].pc_rel = 1; + inst.relocs[0].type = (thumb_p ? BFD_RELOC_ARM_THUMB_OFFSET : (mode_3 ? BFD_RELOC_ARM_HWLITERAL @@ -8203,15 +8582,15 @@ encode_arm_cp_address (int i, int wb_ok, int unind_ok, int reloc_override) } if (reloc_override) - inst.reloc.type = (bfd_reloc_code_real_type) reloc_override; - else if ((inst.reloc.type < BFD_RELOC_ARM_ALU_PC_G0_NC - || inst.reloc.type > BFD_RELOC_ARM_LDC_SB_G2) - && inst.reloc.type != BFD_RELOC_ARM_LDR_PC_G0) + inst.relocs[0].type = (bfd_reloc_code_real_type) reloc_override; + else if ((inst.relocs[0].type < BFD_RELOC_ARM_ALU_PC_G0_NC + || inst.relocs[0].type > BFD_RELOC_ARM_LDC_SB_G2) + && inst.relocs[0].type != BFD_RELOC_ARM_LDR_PC_G0) { if (thumb_mode) - inst.reloc.type = BFD_RELOC_ARM_T32_CP_OFF_IMM; + inst.relocs[0].type = BFD_RELOC_ARM_T32_CP_OFF_IMM; else - inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM; + inst.relocs[0].type = BFD_RELOC_ARM_CP_OFF_IMM; } /* Prefer + for zero encoded value. */ @@ -8330,9 +8709,9 @@ static void do_rm_rd_rn (void) { constraint ((inst.operands[2].reg == REG_PC), BAD_PC); - constraint (((inst.reloc.exp.X_op != O_constant - && inst.reloc.exp.X_op != O_illegal) - || inst.reloc.exp.X_add_number != 0), + constraint (((inst.relocs[0].exp.X_op != O_constant + && inst.relocs[0].exp.X_op != O_illegal) + || inst.relocs[0].exp.X_add_number != 0), BAD_ADDR_MODE); inst.instruction |= inst.operands[0].reg; inst.instruction |= inst.operands[1].reg << 12; @@ -8366,15 +8745,16 @@ do_adr (void) /* Frag hacking will turn this into a sub instruction if the offset turns out to be negative. */ - inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE; - inst.reloc.pc_rel = 1; - inst.reloc.exp.X_add_number -= 8; + inst.relocs[0].type = BFD_RELOC_ARM_IMMEDIATE; + inst.relocs[0].pc_rel = 1; + inst.relocs[0].exp.X_add_number -= 8; - if (inst.reloc.exp.X_op == O_symbol - && inst.reloc.exp.X_add_symbol != NULL - && S_IS_DEFINED (inst.reloc.exp.X_add_symbol) - && THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol)) - inst.reloc.exp.X_add_number += 1; + if (support_interwork + && inst.relocs[0].exp.X_op == O_symbol + && inst.relocs[0].exp.X_add_symbol != NULL + && S_IS_DEFINED (inst.relocs[0].exp.X_add_symbol) + && THUMB_IS_FUNC (inst.relocs[0].exp.X_add_symbol)) + inst.relocs[0].exp.X_add_number |= 1; } /* This is a pseudo-op of the form "adrl rd, label" to be converted @@ -8389,23 +8769,24 @@ do_adrl (void) /* Frag hacking will turn this into a sub instruction if the offset turns out to be negative. */ - inst.reloc.type = BFD_RELOC_ARM_ADRL_IMMEDIATE; - inst.reloc.pc_rel = 1; + inst.relocs[0].type = BFD_RELOC_ARM_ADRL_IMMEDIATE; + inst.relocs[0].pc_rel = 1; inst.size = INSN_SIZE * 2; - inst.reloc.exp.X_add_number -= 8; + inst.relocs[0].exp.X_add_number -= 8; - if (inst.reloc.exp.X_op == O_symbol - && inst.reloc.exp.X_add_symbol != NULL - && S_IS_DEFINED (inst.reloc.exp.X_add_symbol) - && THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol)) - inst.reloc.exp.X_add_number += 1; + if (support_interwork + && inst.relocs[0].exp.X_op == O_symbol + && inst.relocs[0].exp.X_add_symbol != NULL + && S_IS_DEFINED (inst.relocs[0].exp.X_add_symbol) + && THUMB_IS_FUNC (inst.relocs[0].exp.X_add_symbol)) + inst.relocs[0].exp.X_add_number |= 1; } static void do_arit (void) { - constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC - && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC , + constraint (inst.relocs[0].type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC + && inst.relocs[0].type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC , THUMB1_RELOC_ONLY); if (!inst.operands[1].present) inst.operands[1].reg = inst.operands[0].reg; @@ -8490,13 +8871,13 @@ encode_branch (int default_reloc) constraint (inst.operands[0].imm != BFD_RELOC_ARM_PLT32 && inst.operands[0].imm != BFD_RELOC_ARM_TLS_CALL, _("the only valid suffixes here are '(plt)' and '(tlscall)'")); - inst.reloc.type = inst.operands[0].imm == BFD_RELOC_ARM_PLT32 + inst.relocs[0].type = inst.operands[0].imm == BFD_RELOC_ARM_PLT32 ? BFD_RELOC_ARM_PLT32 : thumb_mode ? BFD_RELOC_ARM_THM_TLS_CALL : BFD_RELOC_ARM_TLS_CALL; } else - inst.reloc.type = (bfd_reloc_code_real_type) default_reloc; - inst.reloc.pc_rel = 1; + inst.relocs[0].type = (bfd_reloc_code_real_type) default_reloc; + inst.relocs[0].pc_rel = 1; } static void @@ -8570,7 +8951,8 @@ do_bx (void) /* Output R_ARM_V4BX relocations if is an EABI object that looks like it is for ARMv4t or earlier. */ want_reloc = !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5); - if (object_arch && !ARM_CPU_HAS_FEATURE (*object_arch, arm_ext_v5)) + if (!ARM_FEATURE_ZERO (selected_object_arch) + && !ARM_CPU_HAS_FEATURE (selected_object_arch, arm_ext_v5)) want_reloc = TRUE; #ifdef OBJ_ELF @@ -8579,7 +8961,7 @@ do_bx (void) want_reloc = FALSE; if (want_reloc) - inst.reloc.type = BFD_RELOC_ARM_V4BX; + inst.relocs[0].type = BFD_RELOC_ARM_V4BX; } @@ -8808,9 +9190,9 @@ do_it (void) inst.size = 0; if (unified_syntax) { - set_it_insn_type (IT_INSN); - now_it.mask = (inst.instruction & 0xf) | 0x10; - now_it.cc = inst.operands[0].imm; + set_pred_insn_type (IT_INSN); + now_pred.mask = (inst.instruction & 0xf) | 0x10; + now_pred.cc = inst.operands[0].imm; } } @@ -8868,6 +9250,11 @@ encode_ldmstm(int from_push_pop_mnem) { int is_push = (inst.instruction & A_PUSH_POP_OP_MASK) == A1_OPCODE_PUSH; + if (is_push && one_reg == 13 /* SP */) + /* PR 22483: The A2 encoding cannot be used when + pushing the stack pointer as this is UNPREDICTABLE. */ + return; + inst.instruction &= A_COND_MASK; inst.instruction |= is_push ? A2_OPCODE_PUSH : A2_OPCODE_POP; inst.instruction |= one_reg << 12; @@ -8943,15 +9330,15 @@ do_ldrex (void) || (inst.operands[1].reg == REG_PC), BAD_ADDR_MODE); - constraint (inst.reloc.exp.X_op != O_constant - || inst.reloc.exp.X_add_number != 0, + constraint (inst.relocs[0].exp.X_op != O_constant + || inst.relocs[0].exp.X_add_number != 0, _("offset must be zero in ARM encoding")); constraint ((inst.operands[1].reg == REG_PC), BAD_PC); inst.instruction |= inst.operands[0].reg << 12; inst.instruction |= inst.operands[1].reg << 16; - inst.reloc.type = BFD_RELOC_UNUSED; + inst.relocs[0].type = BFD_RELOC_UNUSED; } static void @@ -8978,7 +9365,7 @@ check_ldr_r15_aligned (void) constraint (!(inst.operands[1].immisreg) && (inst.operands[0].reg == REG_PC && inst.operands[1].reg == REG_PC - && (inst.reloc.exp.X_add_number & 0x3)), + && (inst.relocs[0].exp.X_add_number & 0x3)), _("ldr to register 15 must be 4-byte aligned")); } @@ -9000,8 +9387,8 @@ do_ldstt (void) reject [Rn,...]. */ if (inst.operands[1].preind) { - constraint (inst.reloc.exp.X_op != O_constant - || inst.reloc.exp.X_add_number != 0, + constraint (inst.relocs[0].exp.X_op != O_constant + || inst.relocs[0].exp.X_add_number != 0, _("this instruction requires a post-indexed address")); inst.operands[1].preind = 0; @@ -9032,8 +9419,8 @@ do_ldsttv4 (void) reject [Rn,...]. */ if (inst.operands[1].preind) { - constraint (inst.reloc.exp.X_op != O_constant - || inst.reloc.exp.X_add_number != 0, + constraint (inst.relocs[0].exp.X_op != O_constant + || inst.relocs[0].exp.X_add_number != 0, _("this instruction requires a post-indexed address")); inst.operands[1].preind = 0; @@ -9072,8 +9459,8 @@ do_mlas (void) static void do_mov (void) { - constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC - && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC , + constraint (inst.relocs[0].type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC + && inst.relocs[0].type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC , THUMB1_RELOC_ONLY); inst.instruction |= inst.operands[0].reg << 12; encode_arm_shifter_operand (1); @@ -9087,14 +9474,14 @@ do_mov16 (void) bfd_boolean top; top = (inst.instruction & 0x00400000) != 0; - constraint (top && inst.reloc.type == BFD_RELOC_ARM_MOVW, + constraint (top && inst.relocs[0].type == BFD_RELOC_ARM_MOVW, _(":lower16: not allowed in this instruction")); - constraint (!top && inst.reloc.type == BFD_RELOC_ARM_MOVT, + constraint (!top && inst.relocs[0].type == BFD_RELOC_ARM_MOVT, _(":upper16: not allowed in this instruction")); inst.instruction |= inst.operands[0].reg << 12; - if (inst.reloc.type == BFD_RELOC_UNUSED) + if (inst.relocs[0].type == BFD_RELOC_UNUSED) { - imm = inst.reloc.exp.X_add_number; + imm = inst.relocs[0].exp.X_add_number; /* The value is in two pieces: 0:11, 16:19. */ inst.instruction |= (imm & 0x00000fff); inst.instruction |= (imm & 0x0000f000) << 4; @@ -9198,7 +9585,7 @@ do_mrs (void) if (inst.operands[1].isreg) { br = inst.operands[1].reg; - if (((br & 0x200) == 0) && ((br & 0xf0000) != 0xf000)) + if (((br & 0x200) == 0) && ((br & 0xf0000) != 0xf0000)) as_bad (_("bad register for mrs")); } else @@ -9229,8 +9616,8 @@ do_msr (void) else { inst.instruction |= INST_IMMEDIATE; - inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE; - inst.reloc.pc_rel = 0; + inst.relocs[0].type = BFD_RELOC_ARM_IMMEDIATE; + inst.relocs[0].pc_rel = 0; } } @@ -9470,28 +9857,28 @@ do_shift (void) _("extraneous shift as part of operand to shift insn")); } else - inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM; + inst.relocs[0].type = BFD_RELOC_ARM_SHIFT_IMM; } static void do_smc (void) { - inst.reloc.type = BFD_RELOC_ARM_SMC; - inst.reloc.pc_rel = 0; + inst.relocs[0].type = BFD_RELOC_ARM_SMC; + inst.relocs[0].pc_rel = 0; } static void do_hvc (void) { - inst.reloc.type = BFD_RELOC_ARM_HVC; - inst.reloc.pc_rel = 0; + inst.relocs[0].type = BFD_RELOC_ARM_HVC; + inst.relocs[0].pc_rel = 0; } static void do_swi (void) { - inst.reloc.type = BFD_RELOC_ARM_SWI; - inst.reloc.pc_rel = 0; + inst.relocs[0].type = BFD_RELOC_ARM_SWI; + inst.relocs[0].pc_rel = 0; } static void @@ -9593,14 +9980,14 @@ do_strex (void) constraint (inst.operands[0].reg == inst.operands[1].reg || inst.operands[0].reg == inst.operands[2].reg, BAD_OVERLAP); - constraint (inst.reloc.exp.X_op != O_constant - || inst.reloc.exp.X_add_number != 0, + constraint (inst.relocs[0].exp.X_op != O_constant + || inst.relocs[0].exp.X_add_number != 0, _("offset must be zero in ARM encoding")); inst.instruction |= inst.operands[0].reg << 12; inst.instruction |= inst.operands[1].reg; inst.instruction |= inst.operands[2].reg << 16; - inst.reloc.type = BFD_RELOC_UNUSED; + inst.relocs[0].type = BFD_RELOC_UNUSED; } static void @@ -9987,15 +10374,15 @@ do_fpa_ldmstm (void) [Rn]{!}. The instruction does not really support stacking or unstacking, so we have to emulate these by setting appropriate bits and offsets. */ - constraint (inst.reloc.exp.X_op != O_constant - || inst.reloc.exp.X_add_number != 0, + constraint (inst.relocs[0].exp.X_op != O_constant + || inst.relocs[0].exp.X_add_number != 0, _("this instruction does not support indexing")); if ((inst.instruction & PRE_INDEX) || inst.operands[2].writeback) - inst.reloc.exp.X_add_number = 12 * inst.operands[1].imm; + inst.relocs[0].exp.X_add_number = 12 * inst.operands[1].imm; if (!(inst.instruction & INDEX_UP)) - inst.reloc.exp.X_add_number = -inst.reloc.exp.X_add_number; + inst.relocs[0].exp.X_add_number = -inst.relocs[0].exp.X_add_number; if (!(inst.instruction & PRE_INDEX) && inst.operands[2].writeback) { @@ -10115,7 +10502,7 @@ do_iwmmxt_wldstd (void) if (inst.operands[1].writeback) inst.instruction |= WRITE_BACK; inst.instruction |= inst.operands[1].reg << 16; - inst.instruction |= inst.reloc.exp.X_add_number << 4; + inst.instruction |= inst.relocs[0].exp.X_add_number << 4; inst.instruction |= inst.operands[1].imm; } else @@ -10287,7 +10674,7 @@ do_xsc_mra (void) static void encode_thumb32_shifted_operand (int i) { - unsigned int value = inst.reloc.exp.X_add_number; + unsigned int value = inst.relocs[0].exp.X_add_number; unsigned int shift = inst.operands[i].shift_kind; constraint (inst.operands[i].immisreg, @@ -10297,7 +10684,7 @@ encode_thumb32_shifted_operand (int i) inst.instruction |= SHIFT_ROR << 4; else { - constraint (inst.reloc.exp.X_op != O_constant, + constraint (inst.relocs[0].exp.X_op != O_constant, _("expression too complex")); constraint (value > 32 @@ -10349,14 +10736,14 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d) inst.instruction |= inst.operands[i].imm; if (inst.operands[i].shifted) { - constraint (inst.reloc.exp.X_op != O_constant, + constraint (inst.relocs[0].exp.X_op != O_constant, _("expression too complex")); - constraint (inst.reloc.exp.X_add_number < 0 - || inst.reloc.exp.X_add_number > 3, + constraint (inst.relocs[0].exp.X_add_number < 0 + || inst.relocs[0].exp.X_add_number > 3, _("shift out of range")); - inst.instruction |= inst.reloc.exp.X_add_number << 4; + inst.instruction |= inst.relocs[0].exp.X_add_number << 4; } - inst.reloc.type = BFD_RELOC_UNUSED; + inst.relocs[0].type = BFD_RELOC_UNUSED; } else if (inst.operands[i].preind) { @@ -10378,7 +10765,7 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d) if (inst.operands[i].writeback) inst.instruction |= 0x00000100; } - inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM; + inst.relocs[0].type = BFD_RELOC_ARM_T32_OFFSET_IMM; } else if (inst.operands[i].postind) { @@ -10390,7 +10777,7 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d) inst.instruction |= 0x00200000; else inst.instruction |= 0x00000900; - inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM; + inst.relocs[0].type = BFD_RELOC_ARM_T32_OFFSET_IMM; } else /* unindexed - only for coprocessor */ inst.error = _("instruction does not accept unindexed addressing"); @@ -10418,6 +10805,11 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d) X(_asrs, 1000, fa50f000), \ X(_b, e000, f000b000), \ X(_bcond, d000, f0008000), \ + X(_bf, 0000, f040e001), \ + X(_bfcsel,0000, f000e001), \ + X(_bfx, 0000, f060e001), \ + X(_bfl, 0000, f000c001), \ + X(_bflx, 0000, f070e001), \ X(_bic, 4380, ea200000), \ X(_bics, 4380, ea300000), \ X(_cmn, 42c0, eb100f00), \ @@ -10426,6 +10818,7 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d) X(_cpsid, b670, f3af8600), \ X(_cpy, 4600, ea4f0000), \ X(_dec_sp,80dd, f1ad0d00), \ + X(_dls, 0000, f040e001), \ X(_eor, 4040, ea800000), \ X(_eors, 4040, ea900000), \ X(_inc_sp,00dd, f10d0d00), \ @@ -10438,6 +10831,7 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d) X(_ldr_pc,4800, f85f0000), \ X(_ldr_pc2,4800, f85f0000), \ X(_ldr_sp,9800, f85d0000), \ + X(_le, 0000, f00fc001), \ X(_lsl, 0000, fa00f000), \ X(_lsls, 0000, fa10f000), \ X(_lsr, 0800, fa20f000), \ @@ -10479,6 +10873,7 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d) X(_yield, bf10, f3af8001), \ X(_wfe, bf20, f3af8002), \ X(_wfi, bf30, f3af8003), \ + X(_wls, 0000, f040c001), \ X(_sev, bf40, f3af8004), \ X(_sevl, bf50, f3af8005), \ X(_udf, de00, f7f0a000) @@ -10522,7 +10917,7 @@ do_t_add_sub_w (void) reject_bad_reg (Rd); inst.instruction |= (Rn << 16) | (Rd << 8); - inst.reloc.type = BFD_RELOC_ARM_T32_IMM12; + inst.relocs[0].type = BFD_RELOC_ARM_T32_IMM12; } /* Parse an add or subtract instruction. We get here with inst.instruction @@ -10539,7 +10934,7 @@ do_t_add_sub (void) : inst.operands[0].reg); /* Rd, foo -> Rd, Rd, foo */ if (Rd == REG_PC) - set_it_insn_type_last (); + set_pred_insn_type_last (); if (unified_syntax) { @@ -10550,9 +10945,9 @@ do_t_add_sub (void) flags = (inst.instruction == T_MNEM_adds || inst.instruction == T_MNEM_subs); if (flags) - narrow = !in_it_block (); + narrow = !in_pred_block (); else - narrow = in_it_block (); + narrow = in_pred_block (); if (!inst.operands[2].isreg) { int add; @@ -10584,11 +10979,12 @@ do_t_add_sub (void) { inst.instruction = THUMB_OP16(opcode); inst.instruction |= (Rd << 4) | Rs; - if (inst.reloc.type < BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC - || inst.reloc.type > BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC) + if (inst.relocs[0].type < BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC + || (inst.relocs[0].type + > BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC)) { if (inst.size_req == 2) - inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD; + inst.relocs[0].type = BFD_RELOC_ARM_THUMB_ADD; else inst.relax = opcode; } @@ -10599,29 +10995,31 @@ do_t_add_sub (void) if (inst.size_req == 4 || (inst.size_req != 2 && !opcode)) { - constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC - && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC , + constraint ((inst.relocs[0].type + >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC) + && (inst.relocs[0].type + <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC) , THUMB1_RELOC_ONLY); if (Rd == REG_PC) { constraint (add, BAD_PC); constraint (Rs != REG_LR || inst.instruction != T_MNEM_subs, _("only SUBS PC, LR, #const allowed")); - constraint (inst.reloc.exp.X_op != O_constant, + constraint (inst.relocs[0].exp.X_op != O_constant, _("expression too complex")); - constraint (inst.reloc.exp.X_add_number < 0 - || inst.reloc.exp.X_add_number > 0xff, + constraint (inst.relocs[0].exp.X_add_number < 0 + || inst.relocs[0].exp.X_add_number > 0xff, _("immediate value out of range")); inst.instruction = T2_SUBS_PC_LR - | inst.reloc.exp.X_add_number; - inst.reloc.type = BFD_RELOC_UNUSED; + | inst.relocs[0].exp.X_add_number; + inst.relocs[0].type = BFD_RELOC_UNUSED; return; } else if (Rs == REG_PC) { /* Always use addw/subw. */ inst.instruction = add ? 0xf20f0000 : 0xf2af0000; - inst.reloc.type = BFD_RELOC_ARM_T32_IMM12; + inst.relocs[0].type = BFD_RELOC_ARM_T32_IMM12; } else { @@ -10629,9 +11027,9 @@ do_t_add_sub (void) inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000; if (flags) - inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE; + inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE; else - inst.reloc.type = BFD_RELOC_ARM_T32_ADD_IMM; + inst.relocs[0].type = BFD_RELOC_ARM_T32_ADD_IMM; } inst.instruction |= Rd << 8; inst.instruction |= Rs << 16; @@ -10639,7 +11037,7 @@ do_t_add_sub (void) } else { - unsigned int value = inst.reloc.exp.X_add_number; + unsigned int value = inst.relocs[0].exp.X_add_number; unsigned int shift = inst.operands[2].shift_kind; Rn = inst.operands[2].reg; @@ -10715,7 +11113,7 @@ do_t_add_sub (void) inst.instruction = (inst.instruction == T_MNEM_add ? 0x0000 : 0x8000); inst.instruction |= (Rd << 4) | Rs; - inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD; + inst.relocs[0].type = BFD_RELOC_ARM_THUMB_ADD; return; } @@ -10766,24 +11164,24 @@ do_t_adr (void) /* Generate a 32-bit opcode. */ inst.instruction = THUMB_OP32 (inst.instruction); inst.instruction |= Rd << 8; - inst.reloc.type = BFD_RELOC_ARM_T32_ADD_PC12; - inst.reloc.pc_rel = 1; + inst.relocs[0].type = BFD_RELOC_ARM_T32_ADD_PC12; + inst.relocs[0].pc_rel = 1; } else { /* Generate a 16-bit opcode. */ inst.instruction = THUMB_OP16 (inst.instruction); - inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD; - inst.reloc.exp.X_add_number -= 4; /* PC relative adjust. */ - inst.reloc.pc_rel = 1; + inst.relocs[0].type = BFD_RELOC_ARM_THUMB_ADD; + inst.relocs[0].exp.X_add_number -= 4; /* PC relative adjust. */ + inst.relocs[0].pc_rel = 1; inst.instruction |= Rd << 4; } - if (inst.reloc.exp.X_op == O_symbol - && inst.reloc.exp.X_add_symbol != NULL - && S_IS_DEFINED (inst.reloc.exp.X_add_symbol) - && THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol)) - inst.reloc.exp.X_add_number += 1; + if (inst.relocs[0].exp.X_op == O_symbol + && inst.relocs[0].exp.X_add_symbol != NULL + && S_IS_DEFINED (inst.relocs[0].exp.X_add_symbol) + && THUMB_IS_FUNC (inst.relocs[0].exp.X_add_symbol)) + inst.relocs[0].exp.X_add_number += 1; } /* Arithmetic instructions for which there is just one 16-bit @@ -10818,7 +11216,7 @@ do_t_arit3 (void) inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000; inst.instruction |= Rd << 8; inst.instruction |= Rs << 16; - inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE; + inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE; } else { @@ -10826,9 +11224,9 @@ do_t_arit3 (void) /* See if we can do this with a 16-bit instruction. */ if (THUMB_SETS_FLAGS (inst.instruction)) - narrow = !in_it_block (); + narrow = !in_pred_block (); else - narrow = in_it_block (); + narrow = in_pred_block (); if (Rd > 7 || Rn > 7 || Rs > 7) narrow = FALSE; @@ -10906,7 +11304,7 @@ do_t_arit3c (void) inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000; inst.instruction |= Rd << 8; inst.instruction |= Rs << 16; - inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE; + inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE; } else { @@ -10914,9 +11312,9 @@ do_t_arit3c (void) /* See if we can do this with a 16-bit instruction. */ if (THUMB_SETS_FLAGS (inst.instruction)) - narrow = !in_it_block (); + narrow = !in_pred_block (); else - narrow = in_it_block (); + narrow = in_pred_block (); if (Rd > 7 || Rn > 7 || Rs > 7) narrow = FALSE; @@ -11055,7 +11453,7 @@ do_t_bfx (void) static void do_t_blx (void) { - set_it_insn_type_last (); + set_pred_insn_type_last (); if (inst.operands[0].isreg) { @@ -11079,9 +11477,9 @@ do_t_branch (void) bfd_reloc_code_real_type reloc; cond = inst.cond; - set_it_insn_type (IF_INSIDE_IT_LAST_INSN); + set_pred_insn_type (IF_INSIDE_IT_LAST_INSN); - if (in_it_block ()) + if (in_pred_block ()) { /* Conditional branches inside IT blocks are encoded as unconditional branches. */ @@ -11099,7 +11497,7 @@ do_t_branch (void) && (inst.size_req == 4 || (inst.size_req != 2 && (inst.operands[0].hasreloc - || inst.reloc.exp.X_op == O_constant)))) + || inst.relocs[0].exp.X_op == O_constant)))) { inst.instruction = THUMB_OP32(opcode); if (cond == COND_ALWAYS) @@ -11129,8 +11527,8 @@ do_t_branch (void) if (unified_syntax && inst.size_req != 2) inst.relax = opcode; } - inst.reloc.type = reloc; - inst.reloc.pc_rel = 1; + inst.relocs[0].type = reloc; + inst.relocs[0].pc_rel = 1; } /* Actually do the work for Thumb state bkpt and hlt. The only difference @@ -11148,7 +11546,7 @@ do_t_bkpt_hlt1 (int range) inst.instruction |= inst.operands[0].imm; } - set_it_insn_type (NEUTRAL_IT_INSN); + set_pred_insn_type (NEUTRAL_IT_INSN); } static void @@ -11166,7 +11564,7 @@ do_t_bkpt (void) static void do_t_branch23 (void) { - set_it_insn_type_last (); + set_pred_insn_type_last (); encode_branch (BFD_RELOC_THUMB_PCREL_BRANCH23); /* md_apply_fix blows up with 'bl foo(PLT)' where foo is defined in @@ -11174,27 +11572,27 @@ do_t_branch23 (void) the branch encoding is now needed to deal with TLSCALL relocs. So if we see a PLT reloc now, put it back to how it used to be to keep the preexisting behaviour. */ - if (inst.reloc.type == BFD_RELOC_ARM_PLT32) - inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23; + if (inst.relocs[0].type == BFD_RELOC_ARM_PLT32) + inst.relocs[0].type = BFD_RELOC_THUMB_PCREL_BRANCH23; #if defined(OBJ_COFF) /* If the destination of the branch is a defined symbol which does not have the THUMB_FUNC attribute, then we must be calling a function which has the (interfacearm) attribute. We look for the Thumb entry point to that function and change the branch to refer to that function instead. */ - if ( inst.reloc.exp.X_op == O_symbol - && inst.reloc.exp.X_add_symbol != NULL - && S_IS_DEFINED (inst.reloc.exp.X_add_symbol) - && ! THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol)) - inst.reloc.exp.X_add_symbol = - find_real_start (inst.reloc.exp.X_add_symbol); + if ( inst.relocs[0].exp.X_op == O_symbol + && inst.relocs[0].exp.X_add_symbol != NULL + && S_IS_DEFINED (inst.relocs[0].exp.X_add_symbol) + && ! THUMB_IS_FUNC (inst.relocs[0].exp.X_add_symbol)) + inst.relocs[0].exp.X_add_symbol + = find_real_start (inst.relocs[0].exp.X_add_symbol); #endif } static void do_t_bx (void) { - set_it_insn_type_last (); + set_pred_insn_type_last (); inst.instruction |= inst.operands[0].reg << 3; /* ??? FIXME: Should add a hacky reloc here if reg is REG_PC. The reloc should cause the alignment to be checked once it is known. This is @@ -11206,7 +11604,7 @@ do_t_bxj (void) { int Rm; - set_it_insn_type_last (); + set_pred_insn_type_last (); Rm = inst.operands[0].reg; reject_bad_reg (Rm); inst.instruction |= Rm << 16; @@ -11229,17 +11627,23 @@ do_t_clz (void) inst.instruction |= Rm; } +static void +do_t_csdb (void) +{ + set_pred_insn_type (OUTSIDE_PRED_INSN); +} + static void do_t_cps (void) { - set_it_insn_type (OUTSIDE_IT_INSN); + set_pred_insn_type (OUTSIDE_PRED_INSN); inst.instruction |= inst.operands[0].imm; } static void do_t_cpsi (void) { - set_it_insn_type (OUTSIDE_IT_INSN); + set_pred_insn_type (OUTSIDE_PRED_INSN); if (unified_syntax && (inst.operands[1].present || inst.size_req == 4) && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6_notm)) @@ -11286,11 +11690,11 @@ do_t_cpy (void) static void do_t_cbz (void) { - set_it_insn_type (OUTSIDE_IT_INSN); + set_pred_insn_type (OUTSIDE_PRED_INSN); constraint (inst.operands[0].reg > 7, BAD_HIREG); inst.instruction |= inst.operands[0].reg; - inst.reloc.pc_rel = 1; - inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH7; + inst.relocs[0].pc_rel = 1; + inst.relocs[0].type = BFD_RELOC_THUMB_PCREL_BRANCH7; } static void @@ -11332,10 +11736,11 @@ do_t_it (void) { unsigned int cond = inst.operands[0].imm; - set_it_insn_type (IT_INSN); - now_it.mask = (inst.instruction & 0xf) | 0x10; - now_it.cc = cond; - now_it.warn_deprecated = FALSE; + set_pred_insn_type (IT_INSN); + now_pred.mask = (inst.instruction & 0xf) | 0x10; + now_pred.cc = cond; + now_pred.warn_deprecated = FALSE; + now_pred.type = SCALAR_PRED; /* If the condition is a negative condition, invert the mask. */ if ((cond & 0x1) == 0x0) @@ -11345,22 +11750,22 @@ do_t_it (void) if ((mask & 0x7) == 0) { /* No conversion needed. */ - now_it.block_length = 1; + now_pred.block_length = 1; } else if ((mask & 0x3) == 0) { mask ^= 0x8; - now_it.block_length = 2; + now_pred.block_length = 2; } else if ((mask & 0x1) == 0) { mask ^= 0xC; - now_it.block_length = 3; + now_pred.block_length = 3; } else { mask ^= 0xE; - now_it.block_length = 4; + now_pred.block_length = 4; } inst.instruction &= 0xfff0; @@ -11370,18 +11775,33 @@ do_t_it (void) inst.instruction |= cond << 4; } +static void +do_mve_vpt (void) +{ + /* We are dealing with a vector predicated block. */ + set_pred_insn_type (VPT_INSN); + now_pred.cc = 0; + now_pred.mask = ((inst.instruction & 0x00400000) >> 19) + | ((inst.instruction & 0xe000) >> 13); + now_pred.warn_deprecated = FALSE; + now_pred.type = VECTOR_PRED; +} + /* Helper function used for both push/pop and ldm/stm. */ static void -encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback) +encode_thumb2_multi (bfd_boolean do_io, int base, unsigned mask, + bfd_boolean writeback) { - bfd_boolean load; + bfd_boolean load, store; - load = (inst.instruction & (1 << 20)) != 0; + gas_assert (base != -1 || !do_io); + load = do_io && ((inst.instruction & (1 << 20)) != 0); + store = do_io && !load; if (mask & (1 << 13)) inst.error = _("SP not allowed in register list"); - if ((mask & (1 << base)) != 0 + if (do_io && (mask & (1 << base)) != 0 && writeback) inst.error = _("having the base register in the register list when " "using write back is UNPREDICTABLE"); @@ -11393,16 +11813,16 @@ encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback) if (mask & (1 << 14)) inst.error = _("LR and PC should not both be in register list"); else - set_it_insn_type_last (); + set_pred_insn_type_last (); } } - else + else if (store) { if (mask & (1 << 15)) inst.error = _("PC not allowed in register list"); } - if ((mask & (mask - 1)) == 0) + if (do_io && ((mask & (mask - 1)) == 0)) { /* Single register transfers implemented as str/ldr. */ if (writeback) @@ -11431,14 +11851,15 @@ encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback) inst.instruction |= WRITE_BACK; inst.instruction |= mask; - inst.instruction |= base << 16; + if (do_io) + inst.instruction |= base << 16; } static void do_t_ldmstm (void) { /* This really doesn't seem worth it. */ - constraint (inst.reloc.type != BFD_RELOC_UNUSED, + constraint (inst.relocs[0].type != BFD_RELOC_UNUSED, _("expression too complex")); constraint (inst.operands[1].writeback, _("Thumb load/store multiple does not support {reglist}^")); @@ -11526,8 +11947,9 @@ do_t_ldmstm (void) if (inst.instruction < 0xffff) inst.instruction = THUMB_OP32 (inst.instruction); - encode_thumb2_ldmstm (inst.operands[0].reg, inst.operands[1].imm, - inst.operands[0].writeback); + encode_thumb2_multi (TRUE /* do_io */, inst.operands[0].reg, + inst.operands[1].imm, + inst.operands[0].writeback); } } else @@ -11575,7 +11997,7 @@ do_t_ldrex (void) inst.instruction |= inst.operands[0].reg << 12; inst.instruction |= inst.operands[1].reg << 16; - inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8; + inst.relocs[0].type = BFD_RELOC_ARM_T32_OFFSET_U8; } static void @@ -11605,7 +12027,7 @@ do_t_ldst (void) if (inst.operands[0].isreg && !inst.operands[0].preind && inst.operands[0].reg == REG_PC) - set_it_insn_type_last (); + set_pred_insn_type_last (); opcode = inst.instruction; if (unified_syntax) @@ -11645,7 +12067,7 @@ do_t_ldst (void) { if (Rn == REG_PC) { - if (inst.reloc.pc_rel) + if (inst.relocs[0].pc_rel) opcode = T_MNEM_ldr_pc2; else opcode = T_MNEM_ldr_pc; @@ -11666,7 +12088,7 @@ do_t_ldst (void) } inst.instruction |= THUMB_OP16 (opcode); if (inst.size_req == 2) - inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET; + inst.relocs[0].type = BFD_RELOC_ARM_THUMB_OFFSET; else inst.relax = opcode; return; @@ -11745,7 +12167,7 @@ do_t_ldst (void) inst.instruction = T_OPCODE_STR_SP; inst.instruction |= inst.operands[0].reg << 8; - inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET; + inst.relocs[0].type = BFD_RELOC_ARM_THUMB_OFFSET; return; } @@ -11755,7 +12177,7 @@ do_t_ldst (void) /* Immediate offset. */ inst.instruction |= inst.operands[0].reg; inst.instruction |= inst.operands[1].reg << 3; - inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET; + inst.relocs[0].type = BFD_RELOC_ARM_THUMB_OFFSET; return; } @@ -11864,7 +12286,7 @@ do_t_mov_cmp (void) Rm = inst.operands[1].reg; if (Rn == REG_PC) - set_it_insn_type_last (); + set_pred_insn_type_last (); if (unified_syntax) { @@ -11876,7 +12298,7 @@ do_t_mov_cmp (void) low_regs = (Rn <= 7 && Rm <= 7); opcode = inst.instruction; - if (in_it_block ()) + if (in_pred_block ()) narrow = opcode != T_MNEM_movs; else narrow = opcode != T_MNEM_movs || low_regs; @@ -11947,31 +12369,33 @@ do_t_mov_cmp (void) if (!inst.operands[1].isreg) { /* Immediate operand. */ - if (!in_it_block () && opcode == T_MNEM_mov) + if (!in_pred_block () && opcode == T_MNEM_mov) narrow = 0; if (low_regs && narrow) { inst.instruction = THUMB_OP16 (opcode); inst.instruction |= Rn << 8; - if (inst.reloc.type < BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC - || inst.reloc.type > BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC) + if (inst.relocs[0].type < BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC + || inst.relocs[0].type > BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC) { if (inst.size_req == 2) - inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM; + inst.relocs[0].type = BFD_RELOC_ARM_THUMB_IMM; else inst.relax = opcode; } } else { - constraint (inst.reloc.type >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC - && inst.reloc.type <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC , + constraint ((inst.relocs[0].type + >= BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC) + && (inst.relocs[0].type + <= BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC) , THUMB1_RELOC_ONLY); inst.instruction = THUMB_OP32 (inst.instruction); inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000; inst.instruction |= Rn << r0off; - inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE; + inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE; } } else if (inst.operands[1].shifted && inst.operands[1].immisreg @@ -11981,7 +12405,7 @@ do_t_mov_cmp (void) /* Register shifts are encoded as separate shift instructions. */ bfd_boolean flags = (inst.instruction == T_MNEM_movs); - if (in_it_block ()) + if (in_pred_block ()) narrow = !flags; else narrow = flags; @@ -12037,7 +12461,7 @@ do_t_mov_cmp (void) && (inst.instruction == T_MNEM_mov || inst.instruction == T_MNEM_movs)) { - if (in_it_block ()) + if (in_pred_block ()) narrow = (inst.instruction == T_MNEM_mov); else narrow = (inst.instruction == T_MNEM_movs); @@ -12058,7 +12482,7 @@ do_t_mov_cmp (void) { inst.instruction |= Rn; inst.instruction |= Rm << 3; - inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT; + inst.relocs[0].type = BFD_RELOC_ARM_THUMB_SHIFT; } else { @@ -12149,7 +12573,7 @@ do_t_mov_cmp (void) constraint (Rn > 7, _("only lo regs allowed with immediate")); inst.instruction |= Rn << 8; - inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM; + inst.relocs[0].type = BFD_RELOC_ARM_THUMB_IMM; } } @@ -12161,24 +12585,24 @@ do_t_mov16 (void) bfd_boolean top; top = (inst.instruction & 0x00800000) != 0; - if (inst.reloc.type == BFD_RELOC_ARM_MOVW) + if (inst.relocs[0].type == BFD_RELOC_ARM_MOVW) { constraint (top, _(":lower16: not allowed in this instruction")); - inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVW; + inst.relocs[0].type = BFD_RELOC_ARM_THUMB_MOVW; } - else if (inst.reloc.type == BFD_RELOC_ARM_MOVT) + else if (inst.relocs[0].type == BFD_RELOC_ARM_MOVT) { constraint (!top, _(":upper16: not allowed in this instruction")); - inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVT; + inst.relocs[0].type = BFD_RELOC_ARM_THUMB_MOVT; } Rd = inst.operands[0].reg; reject_bad_reg (Rd); inst.instruction |= Rd << 8; - if (inst.reloc.type == BFD_RELOC_UNUSED) + if (inst.relocs[0].type == BFD_RELOC_UNUSED) { - imm = inst.reloc.exp.X_add_number; + imm = inst.relocs[0].exp.X_add_number; inst.instruction |= (imm & 0xf000) << 4; inst.instruction |= (imm & 0x0800) << 15; inst.instruction |= (imm & 0x0700) << 4; @@ -12216,9 +12640,9 @@ do_t_mvn_tst (void) || inst.instruction == T_MNEM_tst) narrow = TRUE; else if (THUMB_SETS_FLAGS (inst.instruction)) - narrow = !in_it_block (); + narrow = !in_pred_block (); else - narrow = in_it_block (); + narrow = in_pred_block (); if (!inst.operands[1].isreg) { @@ -12228,7 +12652,7 @@ do_t_mvn_tst (void) inst.instruction = THUMB_OP32 (inst.instruction); inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000; inst.instruction |= Rn << r0off; - inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE; + inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE; } else { @@ -12383,9 +12807,9 @@ do_t_mul (void) || Rm > 7) narrow = FALSE; else if (inst.instruction == T_MNEM_muls) - narrow = !in_it_block (); + narrow = !in_pred_block (); else - narrow = in_it_block (); + narrow = in_pred_block (); } else { @@ -12451,7 +12875,7 @@ do_t_mull (void) static void do_t_nop (void) { - set_it_insn_type (NEUTRAL_IT_INSN); + set_pred_insn_type (NEUTRAL_IT_INSN); if (unified_syntax) { @@ -12489,9 +12913,9 @@ do_t_neg (void) bfd_boolean narrow; if (THUMB_SETS_FLAGS (inst.instruction)) - narrow = !in_it_block (); + narrow = !in_pred_block (); else - narrow = in_it_block (); + narrow = in_pred_block (); if (inst.operands[0].reg > 7 || inst.operands[1].reg > 7) narrow = FALSE; if (inst.size_req == 4) @@ -12540,7 +12964,7 @@ do_t_orn (void) if (!inst.operands[2].isreg) { inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000; - inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE; + inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE; } else { @@ -12574,8 +12998,8 @@ do_t_pkhbt (void) inst.instruction |= Rm; if (inst.operands[3].present) { - unsigned int val = inst.reloc.exp.X_add_number; - constraint (inst.reloc.exp.X_op != O_constant, + unsigned int val = inst.relocs[0].exp.X_add_number; + constraint (inst.relocs[0].exp.X_op != O_constant, _("expression too complex")); inst.instruction |= (val & 0x1c) << 10; inst.instruction |= (val & 0x03) << 6; @@ -12615,7 +13039,7 @@ do_t_push_pop (void) constraint (inst.operands[0].writeback, _("push/pop do not support {reglist}^")); - constraint (inst.reloc.type != BFD_RELOC_UNUSED, + constraint (inst.relocs[0].type != BFD_RELOC_UNUSED, _("expression too complex")); mask = inst.operands[0].imm; @@ -12632,8 +13056,20 @@ do_t_push_pop (void) else if (unified_syntax) { inst.instruction = THUMB_OP32 (inst.instruction); - encode_thumb2_ldmstm (13, mask, TRUE); + encode_thumb2_multi (TRUE /* do_io */, 13, mask, TRUE); + } + else + { + inst.error = _("invalid register list to push/pop instruction"); + return; } +} + +static void +do_t_clrm (void) +{ + if (unified_syntax) + encode_thumb2_multi (FALSE /* do_io */, -1, inst.operands[0].imm, FALSE); else { inst.error = _("invalid register list to push/pop instruction"); @@ -12641,6 +13077,24 @@ do_t_push_pop (void) } } +static void +do_t_vscclrm (void) +{ + if (inst.operands[0].issingle) + { + inst.instruction |= (inst.operands[0].reg & 0x1) << 22; + inst.instruction |= (inst.operands[0].reg & 0x1e) << 11; + inst.instruction |= inst.operands[0].imm; + } + else + { + inst.instruction |= (inst.operands[0].reg & 0x10) << 18; + inst.instruction |= (inst.operands[0].reg & 0xf) << 12; + inst.instruction |= 1 << 8; + inst.instruction |= inst.operands[0].imm << 1; + } +} + static void do_t_rbit (void) { @@ -12723,9 +13177,9 @@ do_t_rsb (void) bfd_boolean narrow; if ((inst.instruction & 0x00100000) != 0) - narrow = !in_it_block (); + narrow = !in_pred_block (); else - narrow = in_it_block (); + narrow = in_pred_block (); if (Rd > 7 || Rs > 7) narrow = FALSE; @@ -12733,15 +13187,15 @@ do_t_rsb (void) if (inst.size_req == 4 || !unified_syntax) narrow = FALSE; - if (inst.reloc.exp.X_op != O_constant - || inst.reloc.exp.X_add_number != 0) + if (inst.relocs[0].exp.X_op != O_constant + || inst.relocs[0].exp.X_add_number != 0) narrow = FALSE; /* Turn rsb #0 into 16-bit neg. We should probably do this via relaxation, but it doesn't seem worth the hassle. */ if (narrow) { - inst.reloc.type = BFD_RELOC_UNUSED; + inst.relocs[0].type = BFD_RELOC_UNUSED; inst.instruction = THUMB_OP16 (T_MNEM_negs); inst.instruction |= Rs << 3; inst.instruction |= Rd; @@ -12749,7 +13203,7 @@ do_t_rsb (void) else { inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000; - inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE; + inst.relocs[0].type = BFD_RELOC_ARM_T32_IMMEDIATE; } } else @@ -12763,7 +13217,7 @@ do_t_setend (void) && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8)) as_tsktsk (_("setend use is deprecated for ARMv8")); - set_it_insn_type (OUTSIDE_IT_INSN); + set_pred_insn_type (OUTSIDE_PRED_INSN); if (inst.operands[0].imm) inst.instruction |= 0x8; } @@ -12793,9 +13247,9 @@ do_t_shift (void) } if (THUMB_SETS_FLAGS (inst.instruction)) - narrow = !in_it_block (); + narrow = !in_pred_block (); else - narrow = in_it_block (); + narrow = in_pred_block (); if (inst.operands[0].reg > 7 || inst.operands[1].reg > 7) narrow = FALSE; if (!inst.operands[2].isreg && shift_kind == SHIFT_ROR) @@ -12833,7 +13287,7 @@ do_t_shift (void) inst.instruction |= inst.operands[0].reg << 8; encode_thumb32_shifted_operand (1); /* Prevent the incorrect generation of an ARM_IMMEDIATE fixup. */ - inst.reloc.type = BFD_RELOC_UNUSED; + inst.relocs[0].type = BFD_RELOC_UNUSED; } } else @@ -12865,7 +13319,7 @@ do_t_shift (void) case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_I; break; default: abort (); } - inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT; + inst.relocs[0].type = BFD_RELOC_ARM_THUMB_SHIFT; inst.instruction |= inst.operands[0].reg; inst.instruction |= inst.operands[1].reg << 3; } @@ -12909,7 +13363,7 @@ do_t_shift (void) case T_MNEM_ror: inst.error = _("ror #imm not supported"); return; default: abort (); } - inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT; + inst.relocs[0].type = BFD_RELOC_ARM_THUMB_SHIFT; inst.instruction |= inst.operands[0].reg; inst.instruction |= inst.operands[1].reg << 3; } @@ -12955,25 +13409,25 @@ do_t_simd2 (void) static void do_t_smc (void) { - unsigned int value = inst.reloc.exp.X_add_number; + unsigned int value = inst.relocs[0].exp.X_add_number; constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7a), _("SMC is not permitted on this architecture")); - constraint (inst.reloc.exp.X_op != O_constant, + constraint (inst.relocs[0].exp.X_op != O_constant, _("expression too complex")); - inst.reloc.type = BFD_RELOC_UNUSED; + inst.relocs[0].type = BFD_RELOC_UNUSED; inst.instruction |= (value & 0xf000) >> 12; inst.instruction |= (value & 0x0ff0); inst.instruction |= (value & 0x000f) << 16; /* PR gas/15623: SMC instructions must be last in an IT block. */ - set_it_insn_type_last (); + set_pred_insn_type_last (); } static void do_t_hvc (void) { - unsigned int value = inst.reloc.exp.X_add_number; + unsigned int value = inst.relocs[0].exp.X_add_number; - inst.reloc.type = BFD_RELOC_UNUSED; + inst.relocs[0].type = BFD_RELOC_UNUSED; inst.instruction |= (value & 0x0fff); inst.instruction |= (value & 0xf000) << 4; } @@ -12995,11 +13449,11 @@ do_t_ssat_usat (int bias) if (inst.operands[3].present) { - offsetT shift_amount = inst.reloc.exp.X_add_number; + offsetT shift_amount = inst.relocs[0].exp.X_add_number; - inst.reloc.type = BFD_RELOC_UNUSED; + inst.relocs[0].type = BFD_RELOC_UNUSED; - constraint (inst.reloc.exp.X_op != O_constant, + constraint (inst.relocs[0].exp.X_op != O_constant, _("expression too complex")); if (shift_amount != 0) @@ -13052,7 +13506,7 @@ do_t_strex (void) inst.instruction |= inst.operands[0].reg << 8; inst.instruction |= inst.operands[1].reg << 12; inst.instruction |= inst.operands[2].reg << 16; - inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8; + inst.relocs[0].type = BFD_RELOC_ARM_T32_OFFSET_U8; } static void @@ -13130,7 +13584,7 @@ do_t_sxth (void) static void do_t_swi (void) { - inst.reloc.type = BFD_RELOC_ARM_SWI; + inst.relocs[0].type = BFD_RELOC_ARM_SWI; } static void @@ -13140,7 +13594,7 @@ do_t_tb (void) int half; half = (inst.instruction & 0x10) != 0; - set_it_insn_type_last (); + set_pred_insn_type_last (); constraint (inst.operands[0].immisreg, _("instruction requires register index")); @@ -13176,7 +13630,7 @@ do_t_udf (void) inst.instruction |= inst.operands[0].imm; } - set_it_insn_type (NEUTRAL_IT_INSN); + set_pred_insn_type (NEUTRAL_IT_INSN); } @@ -13202,30 +13656,233 @@ do_t_usat16 (void) inst.instruction |= Rn << 16; } -/* Neon instruction encoder helpers. */ - -/* Encodings for the different types for various Neon opcodes. */ - -/* An "invalid" code for the following tables. */ -#define N_INV -1u - -struct neon_tab_entry +/* Checking the range of the branch offset (VAL) with NBITS bits + and IS_SIGNED signedness. Also checks the LSB to be 0. */ +static int +v8_1_branch_value_check (int val, int nbits, int is_signed) { - unsigned integer; - unsigned float_or_poly; - unsigned scalar_or_imm; + gas_assert (nbits > 0 && nbits <= 32); + if (is_signed) + { + int cmp = (1 << (nbits - 1)); + if ((val < -cmp) || (val >= cmp) || (val & 0x01)) + return FAIL; + } + else + { + if ((val <= 0) || (val >= (1 << nbits)) || (val & 0x1)) + return FAIL; + } + return SUCCESS; +} + +/* For branches in Armv8.1-M Mainline. */ +static void +do_t_branch_future (void) +{ + unsigned long insn = inst.instruction; + + inst.instruction = THUMB_OP32 (inst.instruction); + if (inst.operands[0].hasreloc == 0) + { + if (v8_1_branch_value_check (inst.operands[0].imm, 5, FALSE) == FAIL) + as_bad (BAD_BRANCH_OFF); + + inst.instruction |= ((inst.operands[0].imm & 0x1f) >> 1) << 23; + } + else + { + inst.relocs[0].type = BFD_RELOC_THUMB_PCREL_BRANCH5; + inst.relocs[0].pc_rel = 1; + } + + switch (insn) + { + case T_MNEM_bf: + if (inst.operands[1].hasreloc == 0) + { + int val = inst.operands[1].imm; + if (v8_1_branch_value_check (inst.operands[1].imm, 17, TRUE) == FAIL) + as_bad (BAD_BRANCH_OFF); + + int immA = (val & 0x0001f000) >> 12; + int immB = (val & 0x00000ffc) >> 2; + int immC = (val & 0x00000002) >> 1; + inst.instruction |= (immA << 16) | (immB << 1) | (immC << 11); + } + else + { + inst.relocs[1].type = BFD_RELOC_ARM_THUMB_BF17; + inst.relocs[1].pc_rel = 1; + } + break; + + case T_MNEM_bfl: + if (inst.operands[1].hasreloc == 0) + { + int val = inst.operands[1].imm; + if (v8_1_branch_value_check (inst.operands[1].imm, 19, TRUE) == FAIL) + as_bad (BAD_BRANCH_OFF); + + int immA = (val & 0x0007f000) >> 12; + int immB = (val & 0x00000ffc) >> 2; + int immC = (val & 0x00000002) >> 1; + inst.instruction |= (immA << 16) | (immB << 1) | (immC << 11); + } + else + { + inst.relocs[1].type = BFD_RELOC_ARM_THUMB_BF19; + inst.relocs[1].pc_rel = 1; + } + break; + + case T_MNEM_bfcsel: + /* Operand 1. */ + if (inst.operands[1].hasreloc == 0) + { + int val = inst.operands[1].imm; + int immA = (val & 0x00001000) >> 12; + int immB = (val & 0x00000ffc) >> 2; + int immC = (val & 0x00000002) >> 1; + inst.instruction |= (immA << 16) | (immB << 1) | (immC << 11); + } + else + { + inst.relocs[1].type = BFD_RELOC_ARM_THUMB_BF13; + inst.relocs[1].pc_rel = 1; + } + + /* Operand 2. */ + if (inst.operands[2].hasreloc == 0) + { + constraint ((inst.operands[0].hasreloc != 0), BAD_ARGS); + int val2 = inst.operands[2].imm; + int val0 = inst.operands[0].imm & 0x1f; + int diff = val2 - val0; + if (diff == 4) + inst.instruction |= 1 << 17; /* T bit. */ + else if (diff != 2) + as_bad (_("out of range label-relative fixup value")); + } + else + { + constraint ((inst.operands[0].hasreloc == 0), BAD_ARGS); + inst.relocs[2].type = BFD_RELOC_THUMB_PCREL_BFCSEL; + inst.relocs[2].pc_rel = 1; + } + + /* Operand 3. */ + constraint (inst.cond != COND_ALWAYS, BAD_COND); + inst.instruction |= (inst.operands[3].imm & 0xf) << 18; + break; + + case T_MNEM_bfx: + case T_MNEM_bflx: + inst.instruction |= inst.operands[1].reg << 16; + break; + + default: abort (); + } +} + +/* Helper function for do_t_loloop to handle relocations. */ +static void +v8_1_loop_reloc (int is_le) +{ + if (inst.relocs[0].exp.X_op == O_constant) + { + int value = inst.relocs[0].exp.X_add_number; + value = (is_le) ? -value : value; + + if (v8_1_branch_value_check (value, 12, FALSE) == FAIL) + as_bad (BAD_BRANCH_OFF); + + int imml, immh; + + immh = (value & 0x00000ffc) >> 2; + imml = (value & 0x00000002) >> 1; + + inst.instruction |= (imml << 11) | (immh << 1); + } + else + { + inst.relocs[0].type = BFD_RELOC_ARM_THUMB_LOOP12; + inst.relocs[0].pc_rel = 1; + } +} + +/* To handle the Scalar Low Overhead Loop instructions + in Armv8.1-M Mainline. */ +static void +do_t_loloop (void) +{ + unsigned long insn = inst.instruction; + + set_pred_insn_type (OUTSIDE_PRED_INSN); + inst.instruction = THUMB_OP32 (inst.instruction); + + switch (insn) + { + case T_MNEM_le: + /* le