summaryrefslogtreecommitdiff
path: root/gcc/config/arm/neon.md
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/arm/neon.md')
-rw-r--r--gcc/config/arm/neon.md136
1 files changed, 67 insertions, 69 deletions
diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md
index e5a2b0f1c9a..62fb6daae99 100644
--- a/gcc/config/arm/neon.md
+++ b/gcc/config/arm/neon.md
@@ -4253,6 +4253,9 @@ if (BYTES_BIG_ENDIAN)
[(set_attr "type" "neon_load1_1reg<q>")]
)
+;; The lane numbers in the RTL are in GCC lane order, having been flipped
+;; in arm_expand_neon_args. The lane numbers are restored to architectural
+;; lane order here.
(define_insn "neon_vld1_lane<mode>"
[(set (match_operand:VDX 0 "s_register_operand" "=w")
(unspec:VDX [(match_operand:<V_elem> 1 "neon_struct_operand" "Um")
@@ -4261,10 +4264,9 @@ if (BYTES_BIG_ENDIAN)
UNSPEC_VLD1_LANE))]
"TARGET_NEON"
{
- HOST_WIDE_INT lane = INTVAL (operands[3]);
+ HOST_WIDE_INT lane = NEON_ENDIAN_LANE_N(<MODE>mode, INTVAL (operands[3]));
HOST_WIDE_INT max = GET_MODE_NUNITS (<MODE>mode);
- if (lane < 0 || lane >= max)
- error ("lane out of range");
+ operands[3] = GEN_INT (lane);
if (max == 1)
return "vld1.<V_sz_elem>\t%P0, %A1";
else
@@ -4273,6 +4275,8 @@ if (BYTES_BIG_ENDIAN)
[(set_attr "type" "neon_load1_one_lane<q>")]
)
+;; see comment on neon_vld1_lane for reason why the lane numbers are reversed
+;; here on big endian targets.
(define_insn "neon_vld1_lane<mode>"
[(set (match_operand:VQX 0 "s_register_operand" "=w")
(unspec:VQX [(match_operand:<V_elem> 1 "neon_struct_operand" "Um")
@@ -4281,12 +4285,11 @@ if (BYTES_BIG_ENDIAN)
UNSPEC_VLD1_LANE))]
"TARGET_NEON"
{
- HOST_WIDE_INT lane = INTVAL (operands[3]);
+ HOST_WIDE_INT lane = NEON_ENDIAN_LANE_N(<MODE>mode, INTVAL (operands[3]));
HOST_WIDE_INT max = GET_MODE_NUNITS (<MODE>mode);
+ operands[3] = GEN_INT (lane);
int regno = REGNO (operands[0]);
- if (lane < 0 || lane >= max)
- error ("lane out of range");
- else if (lane >= max / 2)
+ if (lane >= max / 2)
{
lane -= max / 2;
regno += 2;
@@ -4359,6 +4362,8 @@ if (BYTES_BIG_ENDIAN)
"vst1.<V_sz_elem>\t%h1, %A0"
[(set_attr "type" "neon_store1_1reg<q>")])
+;; see comment on neon_vld1_lane for reason why the lane numbers are reversed
+;; here on big endian targets.
(define_insn "neon_vst1_lane<mode>"
[(set (match_operand:<V_elem> 0 "neon_struct_operand" "=Um")
(unspec:<V_elem>
@@ -4367,10 +4372,9 @@ if (BYTES_BIG_ENDIAN)
UNSPEC_VST1_LANE))]
"TARGET_NEON"
{
- HOST_WIDE_INT lane = INTVAL (operands[2]);
+ HOST_WIDE_INT lane = NEON_ENDIAN_LANE_N(<MODE>mode, INTVAL (operands[2]));
HOST_WIDE_INT max = GET_MODE_NUNITS (<MODE>mode);
- if (lane < 0 || lane >= max)
- error ("lane out of range");
+ operands[2] = GEN_INT (lane);
if (max == 1)
return "vst1.<V_sz_elem>\t{%P1}, %A0";
else
@@ -4379,6 +4383,8 @@ if (BYTES_BIG_ENDIAN)
[(set_attr "type" "neon_store1_one_lane<q>")]
)
+;; see comment on neon_vld1_lane for reason why the lane numbers are reversed
+;; here on big endian targets.
(define_insn "neon_vst1_lane<mode>"
[(set (match_operand:<V_elem> 0 "neon_struct_operand" "=Um")
(unspec:<V_elem>
@@ -4387,17 +4393,15 @@ if (BYTES_BIG_ENDIAN)
UNSPEC_VST1_LANE))]
"TARGET_NEON"
{
- HOST_WIDE_INT lane = INTVAL (operands[2]);
+ HOST_WIDE_INT lane = NEON_ENDIAN_LANE_N(<MODE>mode, INTVAL (operands[2]));
HOST_WIDE_INT max = GET_MODE_NUNITS (<MODE>mode);
int regno = REGNO (operands[1]);
- if (lane < 0 || lane >= max)
- error ("lane out of range");
- else if (lane >= max / 2)
+ if (lane >= max / 2)
{
lane -= max / 2;
regno += 2;
- operands[2] = GEN_INT (lane);
}
+ operands[2] = GEN_INT (lane);
operands[1] = gen_rtx_REG (<V_HALF>mode, regno);
if (max == 2)
return "vst1.<V_sz_elem>\t{%P1}, %A0";
@@ -4448,6 +4452,8 @@ if (BYTES_BIG_ENDIAN)
"vld2.<V_sz_elem>\t%h0, %A1"
[(set_attr "type" "neon_load2_2reg_q")])
+;; see comment on neon_vld1_lane for reason why the lane numbers are reversed
+;; here on big endian targets.
(define_insn "neon_vld2_lane<mode>"
[(set (match_operand:TI 0 "s_register_operand" "=w")
(unspec:TI [(match_operand:<V_two_elem> 1 "neon_struct_operand" "Um")
@@ -4457,22 +4463,21 @@ if (BYTES_BIG_ENDIAN)
UNSPEC_VLD2_LANE))]
"TARGET_NEON"
{
- HOST_WIDE_INT lane = INTVAL (operands[3]);
- HOST_WIDE_INT max = GET_MODE_NUNITS (<MODE>mode);
+ HOST_WIDE_INT lane = NEON_ENDIAN_LANE_N(<MODE>mode, INTVAL (operands[3]));
int regno = REGNO (operands[0]);
rtx ops[4];
- if (lane < 0 || lane >= max)
- error ("lane out of range");
ops[0] = gen_rtx_REG (DImode, regno);
ops[1] = gen_rtx_REG (DImode, regno + 2);
ops[2] = operands[1];
- ops[3] = operands[3];
+ ops[3] = GEN_INT (lane);
output_asm_insn ("vld2.<V_sz_elem>\t{%P0[%c3], %P1[%c3]}, %A2", ops);
return "";
}
[(set_attr "type" "neon_load2_one_lane<q>")]
)
+;; see comment on neon_vld1_lane for reason why the lane numbers are reversed
+;; here on big endian targets.
(define_insn "neon_vld2_lane<mode>"
[(set (match_operand:OI 0 "s_register_operand" "=w")
(unspec:OI [(match_operand:<V_two_elem> 1 "neon_struct_operand" "Um")
@@ -4482,13 +4487,11 @@ if (BYTES_BIG_ENDIAN)
UNSPEC_VLD2_LANE))]
"TARGET_NEON"
{
- HOST_WIDE_INT lane = INTVAL (operands[3]);
+ HOST_WIDE_INT lane = NEON_ENDIAN_LANE_N(<MODE>mode, INTVAL (operands[3]));
HOST_WIDE_INT max = GET_MODE_NUNITS (<MODE>mode);
int regno = REGNO (operands[0]);
rtx ops[4];
- if (lane < 0 || lane >= max)
- error ("lane out of range");
- else if (lane >= max / 2)
+ if (lane >= max / 2)
{
lane -= max / 2;
regno += 2;
@@ -4563,6 +4566,8 @@ if (BYTES_BIG_ENDIAN)
[(set_attr "type" "neon_store2_4reg<q>")]
)
+;; see comment on neon_vld1_lane for reason why the lane numbers are reversed
+;; here on big endian targets.
(define_insn "neon_vst2_lane<mode>"
[(set (match_operand:<V_two_elem> 0 "neon_struct_operand" "=Um")
(unspec:<V_two_elem>
@@ -4572,22 +4577,21 @@ if (BYTES_BIG_ENDIAN)
UNSPEC_VST2_LANE))]
"TARGET_NEON"
{
- HOST_WIDE_INT lane = INTVAL (operands[2]);
- HOST_WIDE_INT max = GET_MODE_NUNITS (<MODE>mode);
+ HOST_WIDE_INT lane = NEON_ENDIAN_LANE_N(<MODE>mode, INTVAL (operands[2]));
int regno = REGNO (operands[1]);
rtx ops[4];
- if (lane < 0 || lane >= max)
- error ("lane out of range");
ops[0] = operands[0];
ops[1] = gen_rtx_REG (DImode, regno);
ops[2] = gen_rtx_REG (DImode, regno + 2);
- ops[3] = operands[2];
+ ops[3] = GEN_INT (lane);
output_asm_insn ("vst2.<V_sz_elem>\t{%P1[%c3], %P2[%c3]}, %A0", ops);
return "";
}
[(set_attr "type" "neon_store2_one_lane<q>")]
)
+;; see comment on neon_vld1_lane for reason why the lane numbers are reversed
+;; here on big endian targets.
(define_insn "neon_vst2_lane<mode>"
[(set (match_operand:<V_two_elem> 0 "neon_struct_operand" "=Um")
(unspec:<V_two_elem>
@@ -4597,13 +4601,11 @@ if (BYTES_BIG_ENDIAN)
UNSPEC_VST2_LANE))]
"TARGET_NEON"
{
- HOST_WIDE_INT lane = INTVAL (operands[2]);
+ HOST_WIDE_INT lane = NEON_ENDIAN_LANE_N(<MODE>mode, INTVAL (operands[2]));
HOST_WIDE_INT max = GET_MODE_NUNITS (<MODE>mode);
int regno = REGNO (operands[1]);
rtx ops[4];
- if (lane < 0 || lane >= max)
- error ("lane out of range");
- else if (lane >= max / 2)
+ if (lane >= max / 2)
{
lane -= max / 2;
regno += 2;
@@ -4707,6 +4709,8 @@ if (BYTES_BIG_ENDIAN)
[(set_attr "type" "neon_load3_3reg<q>")]
)
+;; see comment on neon_vld1_lane for reason why the lane numbers are reversed
+;; here on big endian targets.
(define_insn "neon_vld3_lane<mode>"
[(set (match_operand:EI 0 "s_register_operand" "=w")
(unspec:EI [(match_operand:<V_three_elem> 1 "neon_struct_operand" "Um")
@@ -4716,17 +4720,14 @@ if (BYTES_BIG_ENDIAN)
UNSPEC_VLD3_LANE))]
"TARGET_NEON"
{
- HOST_WIDE_INT lane = INTVAL (operands[3]);
- HOST_WIDE_INT max = GET_MODE_NUNITS (<MODE>mode);
+ HOST_WIDE_INT lane = NEON_ENDIAN_LANE_N (<MODE>mode, INTVAL (operands[3]));
int regno = REGNO (operands[0]);
rtx ops[5];
- if (lane < 0 || lane >= max)
- error ("lane out of range");
ops[0] = gen_rtx_REG (DImode, regno);
ops[1] = gen_rtx_REG (DImode, regno + 2);
ops[2] = gen_rtx_REG (DImode, regno + 4);
ops[3] = operands[1];
- ops[4] = operands[3];
+ ops[4] = GEN_INT (lane);
output_asm_insn ("vld3.<V_sz_elem>\t{%P0[%c4], %P1[%c4], %P2[%c4]}, %3",
ops);
return "";
@@ -4734,6 +4735,8 @@ if (BYTES_BIG_ENDIAN)
[(set_attr "type" "neon_load3_one_lane<q>")]
)
+;; see comment on neon_vld1_lane for reason why the lane numbers are reversed
+;; here on big endian targets.
(define_insn "neon_vld3_lane<mode>"
[(set (match_operand:CI 0 "s_register_operand" "=w")
(unspec:CI [(match_operand:<V_three_elem> 1 "neon_struct_operand" "Um")
@@ -4743,13 +4746,11 @@ if (BYTES_BIG_ENDIAN)
UNSPEC_VLD3_LANE))]
"TARGET_NEON"
{
- HOST_WIDE_INT lane = INTVAL (operands[3]);
+ HOST_WIDE_INT lane = NEON_ENDIAN_LANE_N(<MODE>mode, INTVAL (operands[3]));
HOST_WIDE_INT max = GET_MODE_NUNITS (<MODE>mode);
int regno = REGNO (operands[0]);
rtx ops[5];
- if (lane < 0 || lane >= max)
- error ("lane out of range");
- else if (lane >= max / 2)
+ if (lane >= max / 2)
{
lane -= max / 2;
regno += 2;
@@ -4879,6 +4880,8 @@ if (BYTES_BIG_ENDIAN)
[(set_attr "type" "neon_store3_3reg<q>")]
)
+;; see comment on neon_vld1_lane for reason why the lane numbers are reversed
+;; here on big endian targets.
(define_insn "neon_vst3_lane<mode>"
[(set (match_operand:<V_three_elem> 0 "neon_struct_operand" "=Um")
(unspec:<V_three_elem>
@@ -4888,17 +4891,14 @@ if (BYTES_BIG_ENDIAN)
UNSPEC_VST3_LANE))]
"TARGET_NEON"
{
- HOST_WIDE_INT lane = INTVAL (operands[2]);
- HOST_WIDE_INT max = GET_MODE_NUNITS (<MODE>mode);
+ HOST_WIDE_INT lane = NEON_ENDIAN_LANE_N(<MODE>mode, INTVAL (operands[2]));
int regno = REGNO (operands[1]);
rtx ops[5];
- if (lane < 0 || lane >= max)
- error ("lane out of range");
ops[0] = operands[0];
ops[1] = gen_rtx_REG (DImode, regno);
ops[2] = gen_rtx_REG (DImode, regno + 2);
ops[3] = gen_rtx_REG (DImode, regno + 4);
- ops[4] = operands[2];
+ ops[4] = GEN_INT (lane);
output_asm_insn ("vst3.<V_sz_elem>\t{%P1[%c4], %P2[%c4], %P3[%c4]}, %0",
ops);
return "";
@@ -4906,6 +4906,8 @@ if (BYTES_BIG_ENDIAN)
[(set_attr "type" "neon_store3_one_lane<q>")]
)
+;; see comment on neon_vld1_lane for reason why the lane numbers are reversed
+;; here on big endian targets.
(define_insn "neon_vst3_lane<mode>"
[(set (match_operand:<V_three_elem> 0 "neon_struct_operand" "=Um")
(unspec:<V_three_elem>
@@ -4915,13 +4917,11 @@ if (BYTES_BIG_ENDIAN)
UNSPEC_VST3_LANE))]
"TARGET_NEON"
{
- HOST_WIDE_INT lane = INTVAL (operands[2]);
+ HOST_WIDE_INT lane = NEON_ENDIAN_LANE_N(<MODE>mode, INTVAL (operands[2]));
HOST_WIDE_INT max = GET_MODE_NUNITS (<MODE>mode);
int regno = REGNO (operands[1]);
rtx ops[5];
- if (lane < 0 || lane >= max)
- error ("lane out of range");
- else if (lane >= max / 2)
+ if (lane >= max / 2)
{
lane -= max / 2;
regno += 2;
@@ -5029,6 +5029,8 @@ if (BYTES_BIG_ENDIAN)
[(set_attr "type" "neon_load4_4reg<q>")]
)
+;; see comment on neon_vld1_lane for reason why the lane numbers are reversed
+;; here on big endian targets.
(define_insn "neon_vld4_lane<mode>"
[(set (match_operand:OI 0 "s_register_operand" "=w")
(unspec:OI [(match_operand:<V_four_elem> 1 "neon_struct_operand" "Um")
@@ -5038,18 +5040,15 @@ if (BYTES_BIG_ENDIAN)
UNSPEC_VLD4_LANE))]
"TARGET_NEON"
{
- HOST_WIDE_INT lane = INTVAL (operands[3]);
- HOST_WIDE_INT max = GET_MODE_NUNITS (<MODE>mode);
+ HOST_WIDE_INT lane = NEON_ENDIAN_LANE_N(<MODE>mode, INTVAL (operands[3]));
int regno = REGNO (operands[0]);
rtx ops[6];
- if (lane < 0 || lane >= max)
- error ("lane out of range");
ops[0] = gen_rtx_REG (DImode, regno);
ops[1] = gen_rtx_REG (DImode, regno + 2);
ops[2] = gen_rtx_REG (DImode, regno + 4);
ops[3] = gen_rtx_REG (DImode, regno + 6);
ops[4] = operands[1];
- ops[5] = operands[3];
+ ops[5] = GEN_INT (lane);
output_asm_insn ("vld4.<V_sz_elem>\t{%P0[%c5], %P1[%c5], %P2[%c5], %P3[%c5]}, %A4",
ops);
return "";
@@ -5057,6 +5056,8 @@ if (BYTES_BIG_ENDIAN)
[(set_attr "type" "neon_load4_one_lane<q>")]
)
+;; see comment on neon_vld1_lane for reason why the lane numbers are reversed
+;; here on big endian targets.
(define_insn "neon_vld4_lane<mode>"
[(set (match_operand:XI 0 "s_register_operand" "=w")
(unspec:XI [(match_operand:<V_four_elem> 1 "neon_struct_operand" "Um")
@@ -5066,13 +5067,11 @@ if (BYTES_BIG_ENDIAN)
UNSPEC_VLD4_LANE))]
"TARGET_NEON"
{
- HOST_WIDE_INT lane = INTVAL (operands[3]);
+ HOST_WIDE_INT lane = NEON_ENDIAN_LANE_N(<MODE>mode, INTVAL (operands[3]));
HOST_WIDE_INT max = GET_MODE_NUNITS (<MODE>mode);
int regno = REGNO (operands[0]);
rtx ops[6];
- if (lane < 0 || lane >= max)
- error ("lane out of range");
- else if (lane >= max / 2)
+ if (lane >= max / 2)
{
lane -= max / 2;
regno += 2;
@@ -5209,6 +5208,8 @@ if (BYTES_BIG_ENDIAN)
[(set_attr "type" "neon_store4_4reg<q>")]
)
+;; see comment on neon_vld1_lane for reason why the lane numbers are reversed
+;; here on big endian targets.
(define_insn "neon_vst4_lane<mode>"
[(set (match_operand:<V_four_elem> 0 "neon_struct_operand" "=Um")
(unspec:<V_four_elem>
@@ -5218,18 +5219,15 @@ if (BYTES_BIG_ENDIAN)
UNSPEC_VST4_LANE))]
"TARGET_NEON"
{
- HOST_WIDE_INT lane = INTVAL (operands[2]);
- HOST_WIDE_INT max = GET_MODE_NUNITS (<MODE>mode);
+ HOST_WIDE_INT lane = NEON_ENDIAN_LANE_N(<MODE>mode, INTVAL (operands[2]));
int regno = REGNO (operands[1]);
rtx ops[6];
- if (lane < 0 || lane >= max)
- error ("lane out of range");
ops[0] = operands[0];
ops[1] = gen_rtx_REG (DImode, regno);
ops[2] = gen_rtx_REG (DImode, regno + 2);
ops[3] = gen_rtx_REG (DImode, regno + 4);
ops[4] = gen_rtx_REG (DImode, regno + 6);
- ops[5] = operands[2];
+ ops[5] = GEN_INT (lane);
output_asm_insn ("vst4.<V_sz_elem>\t{%P1[%c5], %P2[%c5], %P3[%c5], %P4[%c5]}, %A0",
ops);
return "";
@@ -5237,6 +5235,8 @@ if (BYTES_BIG_ENDIAN)
[(set_attr "type" "neon_store4_one_lane<q>")]
)
+;; see comment on neon_vld1_lane for reason why the lane numbers are reversed
+;; here on big endian targets.
(define_insn "neon_vst4_lane<mode>"
[(set (match_operand:<V_four_elem> 0 "neon_struct_operand" "=Um")
(unspec:<V_four_elem>
@@ -5246,13 +5246,11 @@ if (BYTES_BIG_ENDIAN)
UNSPEC_VST4_LANE))]
"TARGET_NEON"
{
- HOST_WIDE_INT lane = INTVAL (operands[2]);
+ HOST_WIDE_INT lane = NEON_ENDIAN_LANE_N(<MODE>mode, INTVAL (operands[2]));
HOST_WIDE_INT max = GET_MODE_NUNITS (<MODE>mode);
int regno = REGNO (operands[1]);
rtx ops[6];
- if (lane < 0 || lane >= max)
- error ("lane out of range");
- else if (lane >= max / 2)
+ if (lane >= max / 2)
{
lane -= max / 2;
regno += 2;