+2017-11-08 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ * simplify-rtx.c (simplify_ternary_operation, VEC_MERGE):
+ Simplify vec_merge of vec_duplicate and vec_concat.
+ * config/aarch64/constraints.md (Utq): New constraint.
+ * config/aarch64/aarch64-simd.md (load_pair_lanes<mode>): New
+ define_insn.
+
2017-11-08 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
* simplify-rtx.c (simplify_ternary_operation, VEC_MERGE):
[(set_attr "type" "neon_to_gp<q>, neon_dup<q>, neon_store1_one_lane<q>")]
)
+(define_insn "load_pair_lanes<mode>"
+ [(set (match_operand:<VDBL> 0 "register_operand" "=w")
+ (vec_concat:<VDBL>
+ (match_operand:VDC 1 "memory_operand" "Utq")
+ (match_operand:VDC 2 "memory_operand" "m")))]
+ "TARGET_SIMD && !STRICT_ALIGNMENT
+ && rtx_equal_p (XEXP (operands[2], 0),
+ plus_constant (Pmode,
+ XEXP (operands[1], 0),
+ GET_MODE_SIZE (<MODE>mode)))"
+ "ldr\\t%q0, %1"
+ [(set_attr "type" "neon_load1_1reg_q")]
+)
+
;; In this insn, operand 1 should be low, and operand 2 the high part of the
;; dest vector.
(and (match_code "mem")
(match_test "aarch64_simd_mem_operand_p (op)")))
+(define_memory_constraint "Utq"
+ "@internal
+ An address valid for loading or storing a 128-bit AdvSIMD register"
+ (and (match_code "mem")
+ (match_test "aarch64_legitimate_address_p (V2DImode, XEXP (op, 0),
+ MEM, 1)")))
+
(define_constraint "Ufc"
"A floating point constant which can be used with an\
FMOV immediate operation."
std::swap (newop0, newop1);
return simplify_gen_binary (VEC_CONCAT, mode, newop0, newop1);
}
+ /* Replace (vec_merge (vec_duplicate x) (vec_concat (y) (z)) (const_int N))
+ with (vec_concat x z) if N == 1, or (vec_concat y x) if N == 2.
+ Only applies for vectors of two elements. */
+ if (GET_CODE (op0) == VEC_DUPLICATE
+ && GET_CODE (op1) == VEC_CONCAT
+ && GET_MODE_NUNITS (GET_MODE (op0)) == 2
+ && GET_MODE_NUNITS (GET_MODE (op1)) == 2
+ && IN_RANGE (sel, 1, 2))
+ {
+ rtx newop0 = XEXP (op0, 0);
+ rtx newop1 = XEXP (op1, 2 - sel);
+ rtx otherop = XEXP (op1, sel - 1);
+ if (sel == 2)
+ std::swap (newop0, newop1);
+ /* Don't want to throw away the other part of the vec_concat if
+ it has side-effects. */
+ if (!side_effects_p (otherop))
+ return simplify_gen_binary (VEC_CONCAT, mode, newop0, newop1);
+ }
}
if (rtx_equal_p (op0, op1)
+2017-11-08 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ * gcc.target/aarch64/load_v2vec_lanes_1.c: New test.
+
2017-11-08 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
* gcc.target/aarch64/construct_lane_zero_1.c: New test.
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+typedef long long v2di __attribute__ ((vector_size (16)));
+typedef double v2df __attribute__ ((vector_size (16)));
+
+v2di
+construct_lanedi (long long *y)
+{
+ v2di x = { y[0], y[1] };
+ return x;
+}
+
+v2df
+construct_lanedf (double *y)
+{
+ v2df x = { y[0], y[1] };
+ return x;
+}
+
+/* We can use the load_pair_lanes<mode> pattern to vec_concat two DI/DF
+ values from consecutive memory into a 2-element vector by using
+ a Q-reg LDR. */
+
+/* { dg-final { scan-assembler-times "ldr\tq\[0-9\]+" 2 } } */
+/* { dg-final { scan-assembler-not "ins\t" } } */