Backport from trunk r213378.
2014-07-31 James Greenhalgh <james.greenhalgh@arm.com>
* config/aarch64/aarch64.c (aarch64_simd_vect_par_cnst_half): Vary
the generated mask based on BYTES_BIG_ENDIAN.
(aarch64_simd_check_vect_par_cnst_half): New.
* config/aarch64/aarch64-protos.h
(aarch64_simd_check_vect_par_cnst_half): New.
* config/aarch64/predicates.md (vect_par_cnst_hi_half): Refactor
the check out to aarch64_simd_check_vect_par_cnst_half.
(vect_par_cnst_lo_half): Likewise.
* config/aarch64/aarch64-simd.md
(aarch64_simd_move_hi_quad_<mode>): Always use vec_par_cnst_lo_half.
(move_hi_quad_<mode>): Always generate a low mask.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/linaro/gcc-4_9-branch@214502
138bc75d-0d04-0410-961f-
82ee72b054a4
+2014-08-26 Yvan Roux <yvan.roux@linaro.org>
+
+ Backport from trunk r213378.
+ 2014-07-31 James Greenhalgh <james.greenhalgh@arm.com>
+
+ * config/aarch64/aarch64.c (aarch64_simd_vect_par_cnst_half): Vary
+ the generated mask based on BYTES_BIG_ENDIAN.
+ (aarch64_simd_check_vect_par_cnst_half): New.
+ * config/aarch64/aarch64-protos.h
+ (aarch64_simd_check_vect_par_cnst_half): New.
+ * config/aarch64/predicates.md (vect_par_cnst_hi_half): Refactor
+ the check out to aarch64_simd_check_vect_par_cnst_half.
+ (vect_par_cnst_lo_half): Likewise.
+ * config/aarch64/aarch64-simd.md
+ (aarch64_simd_move_hi_quad_<mode>): Always use vec_par_cnst_lo_half.
+ (move_hi_quad_<mode>): Always generate a low mask.
+
2014-08-22 Yvan Roux <yvan.roux@linaro.org>
Backport from trunk r212927, r213304.
bool aarch64_pad_reg_upward (enum machine_mode, const_tree, bool);
bool aarch64_regno_ok_for_base_p (int, bool);
bool aarch64_regno_ok_for_index_p (int, bool);
+bool aarch64_simd_check_vect_par_cnst_half (rtx op, enum machine_mode mode,
+ bool high);
bool aarch64_simd_imm_scalar_p (rtx x, enum machine_mode mode);
bool aarch64_simd_imm_zero_p (rtx, enum machine_mode);
bool aarch64_simd_scalar_immediate_valid_for_move (rtx, enum machine_mode);
(match_operand:<VHALF> 1 "register_operand" "w,r")
(vec_select:<VHALF>
(match_dup 0)
- (match_operand:VQ 2 "vect_par_cnst_hi_half" ""))))]
+ (match_operand:VQ 2 "vect_par_cnst_lo_half" ""))))]
"TARGET_SIMD && BYTES_BIG_ENDIAN"
"@
ins\\t%0.d[1], %1.d[0]
(match_operand:<VHALF> 1 "register_operand" "")]
"TARGET_SIMD"
{
- rtx p = aarch64_simd_vect_par_cnst_half (<MODE>mode, BYTES_BIG_ENDIAN);
+ rtx p = aarch64_simd_vect_par_cnst_half (<MODE>mode, false);
if (BYTES_BIG_ENDIAN)
emit_insn (gen_aarch64_simd_move_hi_quad_be_<mode> (operands[0],
operands[1], p));
return aarch64_simd_valid_immediate (op_v, vmode, false, NULL);
}
-/* Construct and return a PARALLEL RTX vector. */
+/* Construct and return a PARALLEL RTX vector with elements numbering the
+ lanes of either the high (HIGH == TRUE) or low (HIGH == FALSE) half of
+ the vector - from the perspective of the architecture. This does not
+ line up with GCC's perspective on lane numbers, so we end up with
+ different masks depending on our target endian-ness. The diagram
+ below may help. We must draw the distinction when building masks
+ which select one half of the vector. An instruction selecting
+ architectural low-lanes for a big-endian target, must be described using
+ a mask selecting GCC high-lanes.
+
+ Big-Endian Little-Endian
+
+GCC 0 1 2 3 3 2 1 0
+ | x | x | x | x | | x | x | x | x |
+Architecture 3 2 1 0 3 2 1 0
+
+Low Mask: { 2, 3 } { 0, 1 }
+High Mask: { 0, 1 } { 2, 3 }
+*/
+
rtx
aarch64_simd_vect_par_cnst_half (enum machine_mode mode, bool high)
{
int nunits = GET_MODE_NUNITS (mode);
rtvec v = rtvec_alloc (nunits / 2);
- int base = high ? nunits / 2 : 0;
+ int high_base = nunits / 2;
+ int low_base = 0;
+ int base;
rtx t1;
int i;
- for (i=0; i < nunits / 2; i++)
+ if (BYTES_BIG_ENDIAN)
+ base = high ? low_base : high_base;
+ else
+ base = high ? high_base : low_base;
+
+ for (i = 0; i < nunits / 2; i++)
RTVEC_ELT (v, i) = GEN_INT (base + i);
t1 = gen_rtx_PARALLEL (mode, v);
return t1;
}
+/* Check OP for validity as a PARALLEL RTX vector with elements
+ numbering the lanes of either the high (HIGH == TRUE) or low lanes,
+ from the perspective of the architecture. See the diagram above
+ aarch64_simd_vect_par_cnst_half for more details. */
+
+bool
+aarch64_simd_check_vect_par_cnst_half (rtx op, enum machine_mode mode,
+ bool high)
+{
+ rtx ideal = aarch64_simd_vect_par_cnst_half (mode, high);
+ HOST_WIDE_INT count_op = XVECLEN (op, 0);
+ HOST_WIDE_INT count_ideal = XVECLEN (ideal, 0);
+ int i = 0;
+
+ if (!VECTOR_MODE_P (mode))
+ return false;
+
+ if (count_op != count_ideal)
+ return false;
+
+ for (i = 0; i < count_ideal; i++)
+ {
+ rtx elt_op = XVECEXP (op, 0, i);
+ rtx elt_ideal = XVECEXP (ideal, 0, i);
+
+ if (GET_CODE (elt_op) != CONST_INT
+ || INTVAL (elt_ideal) != INTVAL (elt_op))
+ return false;
+ }
+ return true;
+}
+
/* Bounds-check lanes. Ensure OPERAND lies between LOW (inclusive) and
HIGH (exclusive). */
void
(define_special_predicate "vect_par_cnst_hi_half"
(match_code "parallel")
{
- HOST_WIDE_INT count = XVECLEN (op, 0);
- int nunits = GET_MODE_NUNITS (mode);
- int i;
-
- if (count < 1
- || count != nunits / 2)
- return false;
-
- if (!VECTOR_MODE_P (mode))
- return false;
-
- for (i = 0; i < count; i++)
- {
- rtx elt = XVECEXP (op, 0, i);
- int val;
-
- if (GET_CODE (elt) != CONST_INT)
- return false;
-
- val = INTVAL (elt);
- if (val != (nunits / 2) + i)
- return false;
- }
- return true;
+ return aarch64_simd_check_vect_par_cnst_half (op, mode, true);
})
(define_special_predicate "vect_par_cnst_lo_half"
(match_code "parallel")
{
- HOST_WIDE_INT count = XVECLEN (op, 0);
- int nunits = GET_MODE_NUNITS (mode);
- int i;
-
- if (count < 1
- || count != nunits / 2)
- return false;
-
- if (!VECTOR_MODE_P (mode))
- return false;
-
- for (i = 0; i < count; i++)
- {
- rtx elt = XVECEXP (op, 0, i);
- int val;
-
- if (GET_CODE (elt) != CONST_INT)
- return false;
-
- val = INTVAL (elt);
- if (val != i)
- return false;
- }
- return true;
+ return aarch64_simd_check_vect_par_cnst_half (op, mode, false);
})
-
(define_special_predicate "aarch64_simd_lshift_imm"
(match_code "const_vector")
{