/* Nonzero if this chip supports the ARM Architecture 8.2 extensions. */
int arm_arch8_2 = 0;
+/* Nonzero if this chip supports the ARM Architecture 8.3 extensions. */
+int arm_arch8_3 = 0;
+
+/* Nonzero if this chip supports the ARM Architecture 8.4 extensions. */
+int arm_arch8_4 = 0;
+
/* Nonzero if this chip supports the FP16 instructions extension of ARM
Architecture 8.2. */
int arm_fp16_inst = 0;
&& write_symbols != NO_DEBUG
&& !TARGET_APCS_FRAME
&& (TARGET_DEFAULT & MASK_APCS_FRAME))
- warning (0, "-g with -mno-apcs-frame may not give sensible debugging");
+ warning (0, "%<-g%> with %<-mno-apcs-frame%> may not give sensible "
+ "debugging");
/* iWMMXt unsupported under Thumb mode. */
if (TARGET_THUMB_P (flags) && TARGET_IWMMXT)
error ("iWMMXt unsupported under Thumb mode");
if (TARGET_HARD_TP && TARGET_THUMB1_P (flags))
- error ("can not use -mtp=cp15 with 16-bit Thumb");
+ error ("cannot use %<-mtp=cp15%> with 16-bit Thumb");
if (TARGET_THUMB_P (flags) && TARGET_VXWORKS_RTP && flag_pic)
{
/* Cannot load addresses: -mslow-flash-data forbids literal pool and
-mword-relocations forbids relocation of MOVT/MOVW. */
if (target_word_relocations)
- error ("%s incompatible with -mword-relocations", flag);
+ error ("%s incompatible with %<-mword-relocations%>", flag);
}
}
/* Thumb2 inline assembly code should always use unified syntax.
This will apply to ARM and Thumb1 eventually. */
- opts->x_inline_asm_unified = TARGET_THUMB2_P (opts->x_target_flags);
+ if (TARGET_THUMB2_P (opts->x_target_flags))
+ opts->x_inline_asm_unified = true;
#ifdef SUBTARGET_OVERRIDE_INTERNAL_OPTIONS
SUBTARGET_OVERRIDE_INTERNAL_OPTIONS;
if (!bitmap_empty_p (isa_delta))
{
if (warn_compatible)
- warning (0, "switch -mcpu=%s conflicts with -march=%s switch",
+ warning (0, "switch %<-mcpu=%s%> conflicts "
+ "with %<-march=%s%> switch",
arm_selected_cpu->common.name,
arm_selected_arch->common.name);
/* -march wins for code generation.
if (TARGET_APCS_STACK && !TARGET_APCS_FRAME)
{
- warning (0, "-mapcs-stack-check incompatible with -mno-apcs-frame");
+ warning (0, "%<-mapcs-stack-check%> incompatible with "
+ "%<-mno-apcs-frame%>");
target_flags |= MASK_APCS_FRAME;
}
target_flags |= MASK_APCS_FRAME;
if (TARGET_APCS_REENT && flag_pic)
- error ("-fpic and -mapcs-reent are incompatible");
+ error ("%<-fpic%> and %<-mapcs-reent%> are incompatible");
if (TARGET_APCS_REENT)
warning (0, "APCS reentrant code not supported. Ignored");
if (flag_pic && TARGET_SINGLE_PIC_BASE)
{
if (TARGET_VXWORKS_RTP)
- warning (0, "RTP PIC is incompatible with -msingle-pic-base");
+ warning (0, "RTP PIC is incompatible with %<-msingle-pic-base%>");
arm_pic_register = (TARGET_APCS_STACK || TARGET_AAPCS_BASED) ? 9 : 10;
}
int pic_register = decode_reg_name (arm_pic_register_string);
if (!flag_pic)
- warning (0, "-mpic-register= is useless without -fpic");
+ warning (0, "%<-mpic-register=%> is useless without %<-fpic%>");
/* Prevent the user from choosing an obviously stupid PIC register. */
else if (pic_register < 0 || call_used_regs[pic_register]
if (flag_reorder_blocks_and_partition)
{
inform (input_location,
- "-freorder-blocks-and-partition not supported on this architecture");
+ "%<-freorder-blocks-and-partition%> not supported "
+ "on this architecture");
flag_reorder_blocks_and_partition = 0;
flag_reorder_blocks = 1;
}
arm_arch8 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8);
arm_arch8_1 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_1);
arm_arch8_2 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_2);
+ arm_arch8_3 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_3);
+ arm_arch8_4 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_4);
arm_arch_thumb1 = bitmap_bit_p (arm_active_target.isa, isa_bit_thumb);
arm_arch_thumb2 = bitmap_bit_p (arm_active_target.isa, isa_bit_thumb2);
arm_arch_xscale = bitmap_bit_p (arm_active_target.isa, isa_bit_xscale);
if (TARGET_AAPCS_BASED)
{
if (TARGET_CALLER_INTERWORKING)
- error ("AAPCS does not support -mcaller-super-interworking");
+ error ("AAPCS does not support %<-mcaller-super-interworking%>");
else
if (TARGET_CALLEE_INTERWORKING)
- error ("AAPCS does not support -mcallee-super-interworking");
+ error ("AAPCS does not support %<-mcallee-super-interworking%>");
}
/* __fp16 support currently assumes the core has ldrh. */
{
arm_pcs_default = ARM_PCS_AAPCS_VFP;
if (!bitmap_bit_p (arm_active_target.isa, isa_bit_vfpv2))
- error ("-mfloat-abi=hard: selected processor lacks an FPU");
+ error ("%<-mfloat-abi=hard%>: selected processor lacks an FPU");
}
else
arm_pcs_default = ARM_PCS_AAPCS;
else
{
if (arm_float_abi == ARM_FLOAT_ABI_HARD)
- sorry ("-mfloat-abi=hard and VFP");
+ sorry ("%<-mfloat-abi=hard%> and VFP");
if (arm_abi == ARM_ABI_APCS)
arm_pcs_default = ARM_PCS_APCS;
}
}
-/* Return 1 if double word alignment is required for argument passing.
+/* Return 2 if double word alignment is required for argument passing,
+ but wasn't required before the fix for PR88469.
+ Return 1 if double word alignment is required for argument passing.
Return -1 if double word alignment used to be required for argument
passing before PR77728 ABI fix, but is not required anymore.
Return 0 if double word alignment is not required and wasn't requried
return TYPE_ALIGN (TREE_TYPE (type)) > PARM_BOUNDARY;
int ret = 0;
- /* Record/aggregate types: Use greatest member alignment of any member. */
+ int ret2 = 0;
+ /* Record/aggregate types: Use greatest member alignment of any member. */
for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
if (DECL_ALIGN (field) > PARM_BOUNDARY)
{
Make sure we can warn about that with -Wpsabi. */
ret = -1;
}
+ else if (TREE_CODE (field) == FIELD_DECL
+ && DECL_BIT_FIELD_TYPE (field)
+ && TYPE_ALIGN (DECL_BIT_FIELD_TYPE (field)) > PARM_BOUNDARY)
+ ret2 = 1;
+
+ if (ret2)
+ return 2;
return ret;
}
inform (input_location, "parameter passing for argument of type "
"%qT changed in GCC 7.1", type);
else if (res > 0)
- pcum->nregs++;
+ {
+ pcum->nregs++;
+ if (res > 1 && warn_psabi)
+ inform (input_location, "parameter passing for argument of type "
+ "%qT changed in GCC 9.1", type);
+ }
}
/* Only allow splitting an arg between regs and memory if all preceding
if (res < 0 && warn_psabi)
inform (input_location, "parameter passing for argument of type %qT "
"changed in GCC 7.1", type);
+ if (res > 1 && warn_psabi)
+ inform (input_location, "parameter passing for argument of type "
+ "%qT changed in GCC 9.1", type);
return res > 0 ? DOUBLEWORD_ALIGNMENT : PARM_BOUNDARY;
}
if (!use_cmse)
{
*no_add_attrs = true;
- warning (OPT_Wattributes, "%qE attribute ignored without -mcmse option.",
- name);
+ warning (OPT_Wattributes, "%qE attribute ignored without %<-mcmse%> "
+ "option.", name);
return NULL_TREE;
}
if (!use_cmse)
{
*no_add_attrs = true;
- warning (OPT_Wattributes, "%qE attribute ignored without -mcmse option.",
- name);
+ warning (OPT_Wattributes, "%qE attribute ignored without %<-mcmse%> "
+ "option.", name);
return NULL_TREE;
}
currently implement these if a literal pool is disabled. */
if (arm_disable_literal_pool)
sorry ("accessing thread-local storage is not currently supported "
- "with -mpure-code or -mslow-flash-data");
+ "with %<-mpure-code%> or %<-mslow-flash-data%>");
return true;
}
arm_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
{
rtx base, offset;
+ split_const (x, &base, &offset);
- if (ARM_OFFSETS_MUST_BE_WITHIN_SECTIONS_P)
+ if (SYMBOL_REF_P (base))
{
- split_const (x, &base, &offset);
- if (GET_CODE (base) == SYMBOL_REF
+ /* Function symbols cannot have an offset due to the Thumb bit. */
+ if ((SYMBOL_REF_FLAGS (base) & SYMBOL_FLAG_FUNCTION)
+ && INTVAL (offset) != 0)
+ return true;
+
+ if (ARM_OFFSETS_MUST_BE_WITHIN_SECTIONS_P
&& !offset_within_block_p (base, INTVAL (offset)))
return true;
}
/* Generate code to load VALS, which is a PARALLEL containing only
constants (for vec_init) or CONST_VECTOR, efficiently into a
register. Returns an RTX to copy into the register, or NULL_RTX
- for a PARALLEL that can not be converted into a CONST_VECTOR. */
+ for a PARALLEL that cannot be converted into a CONST_VECTOR. */
rtx
neon_make_constant (rtx vals)
return target;
else if (const_vec != NULL_RTX)
/* Load from constant pool. On Cortex-A8 this takes two cycles
- (for either double or quad vectors). We can not take advantage
+ (for either double or quad vectors). We cannot take advantage
of single-cycle VLD1 because we need a PC-relative addressing
mode. */
return const_vec;
else
/* A PARALLEL containing something not valid inside CONST_VECTOR.
- We can not construct an initializer. */
+ We cannot construct an initializer. */
return NULL_RTX;
}
return FALSE;
}
+/* Prepares the operands for the VCMLA by lane instruction such that the right
+ register number is selected. This instruction is special in that it always
+ requires a D register, however there is a choice to be made between Dn[0],
+ Dn[1], D(n+1)[0], and D(n+1)[1] depending on the mode of the registers.
+
+ The VCMLA by lane function always selects two values. For instance given D0
+ and a V2SF, the only valid index is 0 as the values in S0 and S1 will be
+ used by the instruction. However given V4SF then index 0 and 1 are valid as
+ D0[0] or D1[0] are both valid.
+
+ This function centralizes that information based on OPERANDS, OPERANDS[3]
+ will be changed from a REG into a CONST_INT RTX and OPERANDS[4] will be
+ updated to contain the right index. */
+
+rtx *
+neon_vcmla_lane_prepare_operands (rtx *operands)
+{
+ int lane = INTVAL (operands[4]);
+ machine_mode constmode = SImode;
+ machine_mode mode = GET_MODE (operands[3]);
+ int regno = REGNO (operands[3]);
+ regno = ((regno - FIRST_VFP_REGNUM) >> 1);
+ if (lane > 0 && lane >= GET_MODE_NUNITS (mode) / 4)
+ {
+ operands[3] = gen_int_mode (regno + 1, constmode);
+ operands[4]
+ = gen_int_mode (lane - GET_MODE_NUNITS (mode) / 4, constmode);
+ }
+ else
+ {
+ operands[3] = gen_int_mode (regno, constmode);
+ operands[4] = gen_int_mode (lane, constmode);
+ }
+ return operands;
+}
+
+
/* Return true if X is a register that will be eliminated later on. */
int
arm_eliminable_register (rtx x)
if (load && (REGNO (reg) == SP_REGNUM) && (REGNO (addr) != SP_REGNUM))
return false;
+ if (regno == REGNO (addr))
+ addr_reg_in_reglist = true;
+
for (; i < count; i++)
{
elt = XVECEXP (op, 0, i);
int unsorted_regs[MAX_LDM_STM_OPS];
HOST_WIDE_INT unsorted_offsets[MAX_LDM_STM_OPS];
int order[MAX_LDM_STM_OPS];
- rtx base_reg_rtx = NULL;
int base_reg = -1;
int i, ldm_case;
if (i == 0)
{
base_reg = REGNO (reg);
- base_reg_rtx = reg;
if (TARGET_THUMB1 && base_reg > LAST_LO_REGNUM)
return 0;
}
*load_offset = unsorted_offsets[order[0]];
}
- if (TARGET_THUMB1
- && !peep2_reg_dead_p (nops, base_reg_rtx))
- return 0;
-
if (unsorted_offsets[order[0]] == 0)
ldm_case = 1; /* ldmia */
else if (TARGET_ARM && unsorted_offsets[order[0]] == 4)
if (TARGET_THUMB1)
{
- gcc_assert (peep2_reg_dead_p (nops, base_reg_rtx));
gcc_assert (ldm_case == 1 || ldm_case == 5);
- write_back = TRUE;
+
+ /* Thumb-1 ldm uses writeback except if the base is loaded. */
+ write_back = true;
+ for (i = 0; i < nops; i++)
+ if (base_reg == regs[i])
+ write_back = false;
+
+ /* Ensure the base is dead if it is updated. */
+ if (write_back && !peep2_reg_dead_p (nops, base_reg_rtx))
+ return false;
}
if (ldm_case == 5)
rtx newbase = TARGET_THUMB1 ? base_reg_rtx : gen_rtx_REG (SImode, regs[0]);
emit_insn (gen_addsi3 (newbase, base_reg_rtx, GEN_INT (offset)));
offset = 0;
- if (!TARGET_THUMB1)
- base_reg_rtx = newbase;
+ base_reg_rtx = newbase;
}
for (i = 0; i < nops; i++)
*base = addr;
return true;
}
- else if (GET_CODE (addr) == PLUS || GET_CODE (addr) == MINUS)
+ else if (GET_CODE (addr) == PLUS)
{
*base = XEXP (addr, 0);
*offset = XEXP (addr, 1);
}
/* Make sure accesses are to consecutive memory locations. */
- if (gap != 4)
+ if (gap != GET_MODE_SIZE (SImode))
return false;
if (!align_ok_ldrd_strd (align[0], offset))
}
+/* Return true if parallel execution of the two word-size accesses provided
+ could be satisfied with a single LDRD/STRD instruction. Two word-size
+ accesses are represented by the OPERANDS array, where OPERANDS[0,1] are
+ register operands and OPERANDS[2,3] are the corresponding memory operands.
+ */
+bool
+valid_operands_ldrd_strd (rtx *operands, bool load)
+{
+ int nops = 2;
+ HOST_WIDE_INT offsets[2], offset, align[2];
+ rtx base = NULL_RTX;
+ rtx cur_base, cur_offset;
+ int i, gap;
+
+ /* Check that the memory references are immediate offsets from the
+ same base register. Extract the base register, the destination
+ registers, and the corresponding memory offsets. */
+ for (i = 0; i < nops; i++)
+ {
+ if (!mem_ok_for_ldrd_strd (operands[nops+i], &cur_base, &cur_offset,
+ &align[i]))
+ return false;
+
+ if (i == 0)
+ base = cur_base;
+ else if (REGNO (base) != REGNO (cur_base))
+ return false;
+
+ offsets[i] = INTVAL (cur_offset);
+ if (GET_CODE (operands[i]) == SUBREG)
+ return false;
+ }
+
+ if (offsets[0] > offsets[1])
+ return false;
+
+ gap = offsets[1] - offsets[0];
+ offset = offsets[0];
+
+ /* Make sure accesses are to consecutive memory locations. */
+ if (gap != GET_MODE_SIZE (SImode))
+ return false;
+
+ if (!align_ok_ldrd_strd (align[0], offset))
+ return false;
+
+ return operands_ok_ldrd_strd (operands[0], operands[1], base, offset,
+ false, load);
+}
\f
/* Print a symbolic form of X to the debug file, F. */
Mnode * mp;
/* If the minipool starts before the end of FIX->INSN then this FIX
- can not be placed into the current pool. Furthermore, adding the
+ cannot be placed into the current pool. Furthermore, adding the
new constant pool entry may cause the pool to start FIX_SIZE bytes
earlier. */
if (minipool_vector_head &&
if ((flag_stack_check == STATIC_BUILTIN_STACK_CHECK
|| flag_stack_clash_protection)
&& size)
- sorry ("-fstack-check=specific for Thumb-1");
+ sorry ("%<-fstack-check=specific%> for Thumb-1");
amount = offsets->outgoing_args - offsets->saved_regs;
amount -= 4 * thumb1_extra_regs_pushed (offsets, true);
inform (input_location, "parameter passing for argument of "
"type %qT changed in GCC 7.1", type);
else if (res > 0)
- nregs++;
+ {
+ nregs++;
+ if (res > 1 && warn_psabi)
+ inform (input_location,
+ "parameter passing for argument of type "
+ "%qT changed in GCC 9.1", type);
+ }
}
}
else
return count;
}
+/* Same as above, but operands are a register/memory pair in SImode.
+ Assumes operands has the base register in position 0 and memory in position
+ 2 (which is the order provided by the arm_{ldrd,strd} patterns). */
+int
+arm_count_ldrdstrd_insns (rtx *operands, bool load)
+{
+ int count;
+ rtx ops[2];
+ int regnum, memnum;
+ if (load)
+ regnum = 0, memnum = 1;
+ else
+ regnum = 1, memnum = 0;
+ ops[regnum] = gen_rtx_REG (DImode, REGNO (operands[0]));
+ ops[memnum] = adjust_address (operands[2], DImode, 0);
+ output_move_double (ops, false, &count);
+ return count;
+}
+
+
int
vfp3_const_double_for_fract_bits (rtx operand)
{