This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Power/GCC: Implement little-endian SPE operations
- From: "Maciej W. Rozycki" <macro at codesourcery dot com>
- To: <gcc-patches at gcc dot gnu dot org>
- Date: Mon, 7 Jul 2014 12:40:57 +0100
- Subject: [PATCH] Power/GCC: Implement little-endian SPE operations
- Authentication-results: sourceware.org; auth=none
Hi,
This change implements little-endian code generation for Signal
Processing Engine (SPE) operations.
Where possible changes are handled within the existing patterns with
suitable conditionals added to support the little-endian mode.
In some cases operand constraints are different between the two
endiannesses where an numerical entity is accessed in memory with a
partial data transfer. In these cases new patterns have been added and
the existing patterns renamed to reflect the two endiannesses handled.
Finally the paired-integer vector permute intrinsics do not correspond to
the same high-level operations and have therefore been reimplemented with
new expander patterns. The reason is number pairs in vectors are placed
in memory in the same order regardless of the endianness selected -- the
first number occupies the lower-addressed unit and the second number takes
the higher-addressed unit. When transferred into a register with a
doubleword vector load operation they appear in the register word-swapped
between endiannesses.
These intrinsics turned out not properly covered by the testsuite, a
mistake made in the process of implementing the new expanders went through
unnoticed as only compilation-time checks are made and no run-time ones
are. Therefore a new test case has been added that covers the intrinsics,
and that scores no failures with or without changes made to GCC with this
patch.
The existing patterns that used to handle these intrinsics and that can
also be pulled implicitly by the optimiser, have been renamed to reflect
the individual vector permutation operations they implement and extended
to handle the little endianness too.
This change removes several hundreds of failures seen in powerpc-eabi
GCC, G++, libstdc++ and also GDB testing for the:
-mcpu=8548 -mfloat-gprs=double -mspe=yes -mabi=spe -mlittle
multilib and does not change results for the following powerpc-eabi
multilibs:
-mcpu=603e
-mcpu=603e -msoft-float
-mcpu=8540 -mfloat-gprs=single -mspe=yes -mabi=spe
-mcpu=8540 -mfloat-gprs=single -mspe=yes -mabi=spe -msoft-float
-mcpu=8548 -mfloat-gprs=double -mspe=yes -mabi=spe
-mcpu=8548 -mfloat-gprs=double -mspe=yes -mabi=spe -msoft-float
-mcpu=7400 -maltivec -mabi=altivec
as well as the following powerpc-linux-gnu multilibs:
-mcpu=603e
-mcpu=603e -msoft-float
-mcpu=8540 -mfloat-gprs=single -mspe=yes -mabi=spe
-mcpu=8548 -mfloat-gprs=double -mspe=yes -mabi=spe
-mcpu=7400 -maltivec -mabi=altivec
-mcpu=e5500 -m64
OK to apply?
2014-07-07 Maciej W. Rozycki <macro@codesourcery.com>
gcc/
* config/rs6000/rs6000.c (output_vec_const_move): Handle
little-endian code generation.
* config/rs6000/spe.md (spe_evmergehi): Rename to...
(vec_perm00_v2si): ... this. Handle little-endian code
generation.
(spe_evmergehilo): Rename to...
(vec_perm01_v2si): ... this. Handle little-endian code
generation.
(spe_evmergelo): Rename to...
(vec_perm11_v2si): ... this. Handle little-endian code
generation.
(spe_evmergelohi): Rename to...
(vec_perm10_v2si): ... this. Handle little-endian code
generation.
(spe_evmergehi, spe_evmergehilo): New expanders.
(spe_evmergelo, spe_evmergelohi): Likewise.
(*frob_<SPE64:mode>_<DITI:mode>): Handle little-endian code
generation.
(*frob_tf_ti): Likewise.
(*frob_<mode>_di_2): Likewise.
(*frob_tf_di_8_2): Likewise.
(*frob_di_<mode>): Likewise.
(*frob_ti_tf): Likewise.
(*frob_<DITI:mode>_<SPE64:mode>_2): Likewise.
(*frob_ti_<mode>_8_2): Likewise.
(*frob_ti_tf_2): Likewise.
(mov_si<mode>_e500_subreg0): Rename to...
(mov_si<mode>_e500_subreg0_be): ... this. Restrict to the big
endianness only.
(*mov_si<mode>_e500_subreg0_le): New instruction pattern.
(*mov_si<mode>_e500_subreg0_elf_low): Rename to...
(*mov_si<mode>_e500_subreg0_elf_low_be): ... this. Restrict to
the big endianness only.
(*mov_si<mode>_e500_subreg0_elf_low_le): New instruction pattern.
(*mov_si<mode>_e500_subreg0_2): Rename to...
(*mov_si<mode>_e500_subreg0_2_be): ... this. Restrict to the
big big endianness only.
(*mov_si<mode>_e500_subreg0_2_le): New instruction pattern.
(*mov_si<mode>_e500_subreg4): Rename to...
(*mov_si<mode>_e500_subreg4_be): ... this. Restrict to the big
endianness only.
(mov_si<mode>_e500_subreg4_le): New instruction pattern.
(*mov_si<mode>_e500_subreg4_elf_low): Rename to...
(*mov_si<mode>_e500_subreg4_elf_low_be): ... this. Restrict to
the big endianness only.
(*mov_si<mode>_e500_subreg4_elf_low_le): New instruction/splitter
pattern.
(*mov_si<mode>_e500_subreg4_2): Rename to...
(*mov_si<mode>_e500_subreg4_2_be): ... this. Restrict to the big
endianness only.
(*mov_si<mode>_e500_subreg4_2_le): New instruction pattern.
(*mov_sitf_e500_subreg8): Rename to...
(*mov_sitf_e500_subreg8_be): ... this. Restrict to the big
endianness only.
(*mov_sitf_e500_subreg8_le): New instruction pattern.
(*mov_sitf_e500_subreg8_2): Rename to...
(*mov_sitf_e500_subreg8_2_be): ... this. Restrict to the big
endianness only.
(*mov_sitf_e500_subreg8_2_le): New instruction pattern.
(*mov_sitf_e500_subreg12): Rename to...
(*mov_sitf_e500_subreg12_be): ... this. Restrict to the big
endianness only.
(*mov_sitf_e500_subreg12_le): New instruction pattern.
(*mov_sitf_e500_subreg12_2): Rename to...
(*mov_sitf_e500_subreg12_2_be): ... this. Restrict to the big
endianness only.
(*mov_sitf_e500_subreg12_2_le): New instruction pattern.
gcc/testsuite/
* gcc.target/powerpc/spe-evmerge.c: New file.
Maciej
gcc-ppc-spe-le.diff
Index: gcc-fsf-trunk-quilt/gcc/config/rs6000/rs6000.c
===================================================================
--- gcc-fsf-trunk-quilt.orig/gcc/config/rs6000/rs6000.c 2014-06-11 16:35:08.917560846 +0100
+++ gcc-fsf-trunk-quilt/gcc/config/rs6000/rs6000.c 2014-06-11 16:35:25.917851800 +0100
@@ -5299,8 +5299,10 @@ output_vec_const_move (rtx *operands)
operands[2] = CONST_VECTOR_ELT (vec, 1);
if (cst == cst2)
return "li %0,%1\n\tevmergelo %0,%0,%0";
- else
+ else if (WORDS_BIG_ENDIAN)
return "li %0,%1\n\tevmergelo %0,%0,%0\n\tli %0,%2";
+ else
+ return "li %0,%2\n\tevmergelo %0,%0,%0\n\tli %0,%1";
}
/* Initialize TARGET of vector PAIRED to VALS. */
Index: gcc-fsf-trunk-quilt/gcc/config/rs6000/spe.md
===================================================================
--- gcc-fsf-trunk-quilt.orig/gcc/config/rs6000/spe.md 2014-05-16 16:01:20.197526085 +0100
+++ gcc-fsf-trunk-quilt/gcc/config/rs6000/spe.md 2014-06-11 16:35:25.917851800 +0100
@@ -438,7 +438,7 @@
[(set_attr "type" "vecload")
(set_attr "length" "4")])
-(define_insn "spe_evmergehi"
+(define_insn "vec_perm00_v2si"
[(set (match_operand:V2SI 0 "gpc_reg_operand" "=r")
(vec_select:V2SI
(vec_concat:V4SI
@@ -446,11 +446,16 @@
(match_operand:V2SI 2 "gpc_reg_operand" "r"))
(parallel [(const_int 0) (const_int 2)])))]
"TARGET_SPE"
- "evmergehi %0,%1,%2"
+{
+ if (WORDS_BIG_ENDIAN)
+ return "evmergehi %0,%1,%2";
+ else
+ return "evmergelo %0,%2,%1";
+}
[(set_attr "type" "vecsimple")
(set_attr "length" "4")])
-(define_insn "spe_evmergehilo"
+(define_insn "vec_perm01_v2si"
[(set (match_operand:V2SI 0 "gpc_reg_operand" "=r")
(vec_select:V2SI
(vec_concat:V4SI
@@ -458,11 +463,16 @@
(match_operand:V2SI 2 "gpc_reg_operand" "r"))
(parallel [(const_int 0) (const_int 3)])))]
"TARGET_SPE"
- "evmergehilo %0,%1,%2"
+{
+ if (WORDS_BIG_ENDIAN)
+ return "evmergehilo %0,%1,%2";
+ else
+ return "evmergehilo %0,%2,%1";
+}
[(set_attr "type" "vecsimple")
(set_attr "length" "4")])
-(define_insn "spe_evmergelo"
+(define_insn "vec_perm11_v2si"
[(set (match_operand:V2SI 0 "gpc_reg_operand" "=r")
(vec_select:V2SI
(vec_concat:V4SI
@@ -470,11 +480,16 @@
(match_operand:V2SI 2 "gpc_reg_operand" "r"))
(parallel [(const_int 1) (const_int 3)])))]
"TARGET_SPE"
- "evmergelo %0,%1,%2"
+{
+ if (WORDS_BIG_ENDIAN)
+ return "evmergelo %0,%1,%2";
+ else
+ return "evmergehi %0,%2,%1";
+}
[(set_attr "type" "vecsimple")
(set_attr "length" "4")])
-(define_insn "spe_evmergelohi"
+(define_insn "vec_perm10_v2si"
[(set (match_operand:V2SI 0 "gpc_reg_operand" "=r")
(vec_select:V2SI
(vec_concat:V4SI
@@ -482,7 +497,12 @@
(match_operand:V2SI 2 "gpc_reg_operand" "r"))
(parallel [(const_int 1) (const_int 2)])))]
"TARGET_SPE"
- "evmergelohi %0,%1,%2"
+{
+ if (WORDS_BIG_ENDIAN)
+ return "evmergelohi %0,%1,%2";
+ else
+ return "evmergelohi %0,%2,%1";
+}
[(set_attr "type" "vecsimple")
(set_attr "length" "4")])
@@ -499,6 +519,58 @@
FAIL;
})
+(define_expand "spe_evmergehi"
+ [(match_operand:V2SI 0 "register_operand" "")
+ (match_operand:V2SI 1 "register_operand" "")
+ (match_operand:V2SI 2 "register_operand" "")]
+ "TARGET_SPE"
+{
+ if (BYTES_BIG_ENDIAN)
+ emit_insn (gen_vec_perm00_v2si (operands[0], operands[1], operands[2]));
+ else
+ emit_insn (gen_vec_perm11_v2si (operands[0], operands[2], operands[1]));
+ DONE;
+})
+
+(define_expand "spe_evmergehilo"
+ [(match_operand:V2SI 0 "register_operand" "")
+ (match_operand:V2SI 1 "register_operand" "")
+ (match_operand:V2SI 2 "register_operand" "")]
+ "TARGET_SPE"
+{
+ if (BYTES_BIG_ENDIAN)
+ emit_insn (gen_vec_perm01_v2si (operands[0], operands[1], operands[2]));
+ else
+ emit_insn (gen_vec_perm01_v2si (operands[0], operands[2], operands[1]));
+ DONE;
+})
+
+(define_expand "spe_evmergelo"
+ [(match_operand:V2SI 0 "register_operand" "")
+ (match_operand:V2SI 1 "register_operand" "")
+ (match_operand:V2SI 2 "register_operand" "")]
+ "TARGET_SPE"
+{
+ if (BYTES_BIG_ENDIAN)
+ emit_insn (gen_vec_perm11_v2si (operands[0], operands[1], operands[2]));
+ else
+ emit_insn (gen_vec_perm00_v2si (operands[0], operands[2], operands[1]));
+ DONE;
+})
+
+(define_expand "spe_evmergelohi"
+ [(match_operand:V2SI 0 "register_operand" "")
+ (match_operand:V2SI 1 "register_operand" "")
+ (match_operand:V2SI 2 "register_operand" "")]
+ "TARGET_SPE"
+{
+ if (BYTES_BIG_ENDIAN)
+ emit_insn (gen_vec_perm10_v2si (operands[0], operands[1], operands[2]));
+ else
+ emit_insn (gen_vec_perm10_v2si (operands[0], operands[2], operands[1]));
+ DONE;
+})
+
(define_insn "spe_evnand"
[(set (match_operand:V2SI 0 "gpc_reg_operand" "=r")
(not:V2SI (and:V2SI (match_operand:V2SI 1 "gpc_reg_operand" "r")
@@ -2220,15 +2292,31 @@
(subreg:SPE64 (match_operand:DITI 1 "input_operand" "r,m") 0))]
"(TARGET_E500_DOUBLE && <SPE64:MODE>mode == DFmode)
|| (TARGET_SPE && <SPE64:MODE>mode != DFmode)"
- "@
- evmergelo %0,%1,%L1
- evldd%X1 %0,%y1")
+{
+ switch (which_alternative)
+ {
+ default:
+ gcc_unreachable ();
+ case 0:
+ if (WORDS_BIG_ENDIAN)
+ return "evmergelo %0,%1,%L1";
+ else
+ return "evmergelo %0,%L1,%1";
+ case 1:
+ return "evldd%X1 %0,%y1";
+ }
+})
(define_insn "*frob_tf_ti"
[(set (match_operand:TF 0 "gpc_reg_operand" "=r")
(subreg:TF (match_operand:TI 1 "gpc_reg_operand" "r") 0))]
"TARGET_E500_DOUBLE"
- "evmergelo %0,%1,%L1\;evmergelo %L0,%Y1,%Z1"
+{
+ if (WORDS_BIG_ENDIAN)
+ return "evmergelo %0,%1,%L1\;evmergelo %L0,%Y1,%Z1";
+ else
+ return "evmergelo %L0,%Z1,%Y1\;evmergelo %0,%L1,%1";
+}
[(set_attr "length" "8")])
(define_insn "*frob_<mode>_di_2"
@@ -2236,31 +2324,63 @@
(match_operand:DI 1 "input_operand" "r,m"))]
"(TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
|| (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode)"
- "@
- evmergelo %0,%1,%L1
- evldd%X1 %0,%y1")
+{
+ switch (which_alternative)
+ {
+ default:
+ gcc_unreachable ();
+ case 0:
+ if (WORDS_BIG_ENDIAN)
+ return "evmergelo %0,%1,%L1";
+ else
+ return "evmergelo %0,%L1,%1";
+ case 1:
+ return "evldd%X1 %0,%y1";
+ }
+})
(define_insn "*frob_tf_di_8_2"
[(set (subreg:DI (match_operand:TF 0 "nonimmediate_operand" "+&r,r") 8)
(match_operand:DI 1 "input_operand" "r,m"))]
"TARGET_E500_DOUBLE"
- "@
- evmergelo %L0,%1,%L1
- evldd%X1 %L0,%y1")
+{
+ switch (which_alternative)
+ {
+ default:
+ gcc_unreachable ();
+ case 0:
+ if (WORDS_BIG_ENDIAN)
+ return "evmergelo %L0,%1,%L1";
+ else
+ return "evmergelo %L0,%L1,%1";
+ case 1:
+ return "evldd%X1 %L0,%y1";
+ }
+})
(define_insn "*frob_di_<mode>"
[(set (match_operand:DI 0 "nonimmediate_operand" "=&r")
(subreg:DI (match_operand:SPE64TF 1 "input_operand" "r") 0))]
"(TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
|| (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode)"
- "evmergehi %0,%1,%1\;mr %L0,%1"
+{
+ if (WORDS_BIG_ENDIAN)
+ return "evmergehi %0,%1,%1\;mr %L0,%1";
+ else
+ return "evmergehi %L0,%1,%1\;mr %0,%1";
+}
[(set_attr "length" "8")])
(define_insn "*frob_ti_tf"
[(set (match_operand:TI 0 "nonimmediate_operand" "=&r")
(subreg:TI (match_operand:TF 1 "input_operand" "r") 0))]
"TARGET_E500_DOUBLE"
- "evmergehi %0,%1,%1\;mr %L0,%1\;evmergehi %Y0,%L1,%L1\;mr %Z0,%L1"
+{
+ if (WORDS_BIG_ENDIAN)
+ return "evmergehi %0,%1,%1\;mr %L0,%1\;evmergehi %Y0,%L1,%L1\;mr %Z0,%L1";
+ else
+ return "evmergehi %Z0,%L1,%L1\;mr %Y0,%L1\;evmergehi %L0,%1,%1\;mr %0,%1";
+}
[(set_attr "length" "16")])
(define_insn "*frob_<DITI:mode>_<SPE64:mode>_2"
@@ -2275,22 +2395,40 @@
default:
gcc_unreachable ();
case 0:
- return \"evmergehi %0,%1,%1\;mr %L0,%1\";
+ if (WORDS_BIG_ENDIAN)
+ return \"evmergehi %0,%1,%1\;mr %L0,%1\";
+ else
+ return \"evmergehi %L0,%1,%1\;mr %0,%1\";
case 1:
/* If the address is not offsettable we need to load the whole
doubleword into a 64-bit register and then copy the high word
to form the correct output layout. */
if (!offsettable_nonstrict_memref_p (operands[1]))
- return \"evldd%X1 %L0,%y1\;evmergehi %0,%L0,%L0\";
+ {
+ if (WORDS_BIG_ENDIAN)
+ return \"evldd%X1 %L0,%y1\;evmergehi %0,%L0,%L0\";
+ else
+ return \"evldd%X1 %0,%y1\;evmergehi %L0,%0,%0\";
+ }
/* If the low-address word is used in the address, we must load
it last. Otherwise, load it first. Note that we cannot have
auto-increment in that case since the address register is
known to be dead. */
if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
operands[1], 0))
- return \"lwz %L0,%L1\;lwz %0,%1\";
+ {
+ if (WORDS_BIG_ENDIAN)
+ return \"lwz %L0,%L1\;lwz %0,%1\";
+ else
+ return \"lwz %0,%1\;lwz %L0,%L1\";
+ }
else
- return \"lwz%U1%X1 %0,%1\;lwz %L0,%L1\";
+ {
+ if (WORDS_BIG_ENDIAN)
+ return \"lwz%U1%X1 %0,%1\;lwz %L0,%L1\";
+ else
+ return \"lwz%U1%X1 %L0,%L1\;lwz %0,%1\";
+ }
}
}"
[(set_attr "length" "8,8")])
@@ -2308,15 +2446,33 @@
default:
gcc_unreachable ();
case 0:
- return \"evmergehi %Y0,%1,%1\;mr %Z0,%1\";
+ if (WORDS_BIG_ENDIAN)
+ return \"evmergehi %Y0,%1,%1\;mr %Z0,%1\";
+ else
+ return \"evmergehi %Z0,%1,%1\;mr %Y0,%1\";
case 1:
if (!offsettable_nonstrict_memref_p (operands[1]))
- return \"evldd%X1 %Z0,%y1\;evmergehi %Y0,%Z0,%Z0\";
+ {
+ if (WORDS_BIG_ENDIAN)
+ return \"evldd%X1 %Z0,%y1\;evmergehi %Y0,%Z0,%Z0\";
+ else
+ return \"evldd%X1 %Y0,%y1\;evmergehi %Z0,%Y0,%Y0\";
+ }
if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
operands[1], 0))
- return \"lwz %Z0,%L1\;lwz %Y0,%1\";
+ {
+ if (WORDS_BIG_ENDIAN)
+ return \"lwz %Z0,%L1\;lwz %Y0,%1\";
+ else
+ return \"lwz %Y0,%1\;lwz %Z0,%L1\";
+ }
else
- return \"lwz%U1%X1 %Y0,%1\;lwz %Z0,%L1\";
+ {
+ if (WORDS_BIG_ENDIAN)
+ return \"lwz%U1%X1 %Y0,%1\;lwz %Z0,%L1\";
+ else
+ return \"lwz%U1%X1 %Z0,%L1\;lwz %Y0,%1\";
+ }
}
}"
[(set_attr "length" "8,8")])
@@ -2325,110 +2481,226 @@
[(set (subreg:TF (match_operand:TI 0 "gpc_reg_operand" "=&r") 0)
(match_operand:TF 1 "input_operand" "r"))]
"TARGET_E500_DOUBLE"
- "evmergehi %0,%1,%1\;mr %L0,%1\;evmergehi %Y0,%L1,%L1\;mr %Z0,%L1"
+{
+ if (WORDS_BIG_ENDIAN)
+ return "evmergehi %0,%1,%1\;mr %L0,%1\;evmergehi %Y0,%L1,%L1\;mr %Z0,%L1";
+ else
+ return "evmergehi %Z0,%L1,%L1\;mr %Y0,%L1\;evmergehi %L0,%1,%1\;mr %0,%1";
+}
[(set_attr "length" "16")])
-(define_insn "mov_si<mode>_e500_subreg0"
+(define_insn "mov_si<mode>_e500_subreg0_be"
[(set (subreg:SI (match_operand:SPE64TF 0 "register_operand" "+r,&r") 0)
(match_operand:SI 1 "input_operand" "r,m"))]
- "(TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
- || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode)"
+ "WORDS_BIG_ENDIAN
+ && ((TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
+ || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode))"
"@
evmergelo %0,%1,%0
evmergelohi %0,%0,%0\;lwz%U1%X1 %0,%1\;evmergelohi %0,%0,%0"
[(set_attr "length" "4,12")])
-(define_insn_and_split "*mov_si<mode>_e500_subreg0_elf_low"
+(define_insn "*mov_si<mode>_e500_subreg0_le"
+ [(set (subreg:SI (match_operand:SPE64TF 0 "register_operand" "+r,r") 0)
+ (match_operand:SI 1 "input_operand" "r,m"))]
+ "!WORDS_BIG_ENDIAN
+ && ((TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
+ || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode))"
+ "@
+ mr %0,%1
+ lwz%U1%X1 %0,%1")
+
+(define_insn_and_split "*mov_si<mode>_e500_subreg0_elf_low_be"
[(set (subreg:SI (match_operand:SPE64TF 0 "register_operand" "+r") 0)
(lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "r")
(match_operand 2 "" "")))]
- "((TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
- || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode))
- && TARGET_ELF && !TARGET_64BIT && can_create_pseudo_p ()"
+ "WORDS_BIG_ENDIAN
+ && (((TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
+ || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode))
+ && TARGET_ELF && !TARGET_64BIT && can_create_pseudo_p ())"
"#"
"&& 1"
[(pc)]
{
rtx tmp = gen_reg_rtx (SImode);
emit_insn (gen_elf_low (tmp, operands[1], operands[2]));
- emit_insn (gen_mov_si<mode>_e500_subreg0 (operands[0], tmp));
+ emit_insn (gen_mov_si<mode>_e500_subreg0_be (operands[0], tmp));
DONE;
}
[(set_attr "length" "8")])
+(define_insn "*mov_si<mode>_e500_subreg0_elf_low_le"
+ [(set (subreg:SI (match_operand:SPE64TF 0 "register_operand" "+r") 0)
+ (lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand 2 "" "")))]
+ "!WORDS_BIG_ENDIAN
+ && (((TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
+ || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode))
+ && TARGET_ELF && !TARGET_64BIT)"
+ "addic %0,%1,%K2")
+
;; ??? Could use evstwwe for memory stores in some cases, depending on
;; the offset.
-(define_insn "*mov_si<mode>_e500_subreg0_2"
+(define_insn "*mov_si<mode>_e500_subreg0_2_be"
[(set (match_operand:SI 0 "rs6000_nonimmediate_operand" "+r,m")
(subreg:SI (match_operand:SPE64TF 1 "register_operand" "+r,&r") 0))]
- "(TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
- || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode)"
+ "WORDS_BIG_ENDIAN
+ && ((TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
+ || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode))"
"@
evmergehi %0,%0,%1
evmergelohi %1,%1,%1\;stw%U0%X0 %1,%0"
[(set_attr "length" "4,8")])
-(define_insn "*mov_si<mode>_e500_subreg4"
+(define_insn "*mov_si<mode>_e500_subreg0_2_le"
+ [(set (match_operand:SI 0 "rs6000_nonimmediate_operand" "+r,m")
+ (subreg:SI (match_operand:SPE64TF 1 "register_operand" "+r,r") 0))]
+ "!WORDS_BIG_ENDIAN
+ && ((TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
+ || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode))"
+ "@
+ mr %0,%1
+ stw%U0%X0 %1,%0")
+
+(define_insn "*mov_si<mode>_e500_subreg4_be"
[(set (subreg:SI (match_operand:SPE64TF 0 "register_operand" "+r,r") 4)
(match_operand:SI 1 "input_operand" "r,m"))]
- "(TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
- || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode)"
+ "WORDS_BIG_ENDIAN
+ && ((TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
+ || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode))"
"@
mr %0,%1
lwz%U1%X1 %0,%1")
-(define_insn "*mov_si<mode>_e500_subreg4_elf_low"
+(define_insn "mov_si<mode>_e500_subreg4_le"
+ [(set (subreg:SI (match_operand:SPE64TF 0 "register_operand" "+r,&r") 4)
+ (match_operand:SI 1 "input_operand" "r,m"))]
+ "!WORDS_BIG_ENDIAN
+ && ((TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
+ || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode))"
+ "@
+ evmergelo %0,%1,%0
+ evmergelohi %0,%0,%0\;lwz%U1%X1 %0,%1\;evmergelohi %0,%0,%0"
+ [(set_attr "length" "4,12")])
+
+(define_insn "*mov_si<mode>_e500_subreg4_elf_low_be"
[(set (subreg:SI (match_operand:SPE64TF 0 "register_operand" "+r") 4)
(lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "r")
(match_operand 2 "" "")))]
- "((TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
- || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode))
- && TARGET_ELF && !TARGET_64BIT"
+ "WORDS_BIG_ENDIAN
+ && (((TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
+ || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode))
+ && TARGET_ELF && !TARGET_64BIT)"
"addic %0,%1,%K2")
-(define_insn "*mov_si<mode>_e500_subreg4_2"
+(define_insn_and_split "*mov_si<mode>_e500_subreg4_elf_low_le"
+ [(set (subreg:SI (match_operand:SPE64TF 0 "register_operand" "+r") 4)
+ (lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand 2 "" "")))]
+ "!WORDS_BIG_ENDIAN
+ && (((TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
+ || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode))
+ && TARGET_ELF && !TARGET_64BIT && can_create_pseudo_p ())"
+ "#"
+ "&& 1"
+ [(pc)]
+{
+ rtx tmp = gen_reg_rtx (SImode);
+ emit_insn (gen_elf_low (tmp, operands[1], operands[2]));
+ emit_insn (gen_mov_si<mode>_e500_subreg4_le (operands[0], tmp));
+ DONE;
+}
+ [(set_attr "length" "8")])
+
+(define_insn "*mov_si<mode>_e500_subreg4_2_be"
[(set (match_operand:SI 0 "rs6000_nonimmediate_operand" "+r,m")
(subreg:SI (match_operand:SPE64TF 1 "register_operand" "r,r") 4))]
- "(TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
- || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode)"
+ "WORDS_BIG_ENDIAN
+ && ((TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
+ || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode))"
"@
mr %0,%1
stw%U0%X0 %1,%0")
-(define_insn "*mov_sitf_e500_subreg8"
+(define_insn "*mov_si<mode>_e500_subreg4_2_le"
+ [(set (match_operand:SI 0 "rs6000_nonimmediate_operand" "+r,m")
+ (subreg:SI (match_operand:SPE64TF 1 "register_operand" "+r,&r") 4))]
+ "!WORDS_BIG_ENDIAN
+ && ((TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
+ || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode))"
+ "@
+ evmergehi %0,%0,%1
+ evmergelohi %1,%1,%1\;stw%U0%X0 %1,%0"
+ [(set_attr "length" "4,8")])
+
+(define_insn "*mov_sitf_e500_subreg8_be"
[(set (subreg:SI (match_operand:TF 0 "register_operand" "+r,&r") 8)
(match_operand:SI 1 "input_operand" "r,m"))]
- "TARGET_E500_DOUBLE"
+ "WORDS_BIG_ENDIAN && TARGET_E500_DOUBLE"
"@
evmergelo %L0,%1,%L0
evmergelohi %L0,%L0,%L0\;lwz%U1%X1 %L0,%1\;evmergelohi %L0,%L0,%L0"
[(set_attr "length" "4,12")])
-(define_insn "*mov_sitf_e500_subreg8_2"
+(define_insn "*mov_sitf_e500_subreg8_le"
+ [(set (subreg:SI (match_operand:TF 0 "register_operand" "+r,r") 8)
+ (match_operand:SI 1 "input_operand" "r,m"))]
+ "!WORDS_BIG_ENDIAN && TARGET_E500_DOUBLE"
+ "@
+ mr %L0,%1
+ lwz%U1%X1 %L0,%1")
+
+(define_insn "*mov_sitf_e500_subreg8_2_be"
[(set (match_operand:SI 0 "rs6000_nonimmediate_operand" "+r,m")
(subreg:SI (match_operand:TF 1 "register_operand" "+r,&r") 8))]
- "TARGET_E500_DOUBLE"
+ "WORDS_BIG_ENDIAN && TARGET_E500_DOUBLE"
"@
evmergehi %0,%0,%L1
evmergelohi %L1,%L1,%L1\;stw%U0%X0 %L1,%0"
[(set_attr "length" "4,8")])
-(define_insn "*mov_sitf_e500_subreg12"
+(define_insn "*mov_sitf_e500_subreg8_2_le"
+ [(set (match_operand:SI 0 "rs6000_nonimmediate_operand" "+r,m")
+ (subreg:SI (match_operand:TF 1 "register_operand" "r,r") 8))]
+ "!WORDS_BIG_ENDIAN && TARGET_E500_DOUBLE"
+ "@
+ mr %0,%L1
+ stw%U0%X0 %L1,%0")
+
+(define_insn "*mov_sitf_e500_subreg12_be"
[(set (subreg:SI (match_operand:TF 0 "register_operand" "+r,r") 12)
(match_operand:SI 1 "input_operand" "r,m"))]
- "TARGET_E500_DOUBLE"
+ "WORDS_BIG_ENDIAN && TARGET_E500_DOUBLE"
"@
mr %L0,%1
lwz%U1%X1 %L0,%1")
-(define_insn "*mov_sitf_e500_subreg12_2"
+(define_insn "*mov_sitf_e500_subreg12_le"
+ [(set (subreg:SI (match_operand:TF 0 "register_operand" "+r,&r") 12)
+ (match_operand:SI 1 "input_operand" "r,m"))]
+ "!WORDS_BIG_ENDIAN && TARGET_E500_DOUBLE"
+ "@
+ evmergelo %L0,%1,%L0
+ evmergelohi %L0,%L0,%L0\;lwz%U1%X1 %L0,%1\;evmergelohi %L0,%L0,%L0"
+ [(set_attr "length" "4,12")])
+
+(define_insn "*mov_sitf_e500_subreg12_2_be"
[(set (match_operand:SI 0 "rs6000_nonimmediate_operand" "+r,m")
(subreg:SI (match_operand:TF 1 "register_operand" "r,r") 12))]
- "TARGET_E500_DOUBLE"
+ "WORDS_BIG_ENDIAN && TARGET_E500_DOUBLE"
"@
mr %0,%L1
stw%U0%X0 %L1,%0")
+(define_insn "*mov_sitf_e500_subreg12_2_le"
+ [(set (match_operand:SI 0 "rs6000_nonimmediate_operand" "+r,m")
+ (subreg:SI (match_operand:TF 1 "register_operand" "+r,&r") 12))]
+ "!WORDS_BIG_ENDIAN && TARGET_E500_DOUBLE"
+ "@
+ evmergehi %0,%0,%L1
+ evmergelohi %L1,%L1,%L1\;stw%U0%X0 %L1,%0"
+ [(set_attr "length" "4,8")])
+
;; FIXME: Allow r=CONST0.
(define_insn "*movdf_e500_double"
[(set (match_operand:DF 0 "rs6000_nonimmediate_operand" "=r,r,m")
Index: gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/powerpc/spe-evmerge.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/powerpc/spe-evmerge.c 2014-06-11 16:35:25.917851800 +0100
@@ -0,0 +1,71 @@
+/* Verify SPE vector permute builtins. */
+/* { dg-do run { target { powerpc*-*-* && powerpc_spe } } } */
+/* Remove `-ansi' from options so that <spe.h> compiles. */
+/* { dg-options "" } */
+
+#include <spe.h>
+#include <stdlib.h>
+
+#define vector __attribute__ ((vector_size (8)))
+
+#define WORDS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+
+int
+main (void)
+{
+ vector int a = { 0x11111111, 0x22222222 };
+ vector int b = { 0x33333333, 0x44444444 };
+ vector int c;
+
+ /* c[hi] = a[hi], c[lo] = b[hi] */
+ c = __ev_mergehi (a, b);
+ if (c[0] != (WORDS_BIG_ENDIAN ? 0x11111111 : 0x44444444))
+ abort ();
+ if (c[1] != (WORDS_BIG_ENDIAN ? 0x33333333 : 0x22222222))
+ abort ();
+ /* c[hi] = a[lo], c[lo] = b[lo] */
+ c = __ev_mergelo (a, b);
+ if (c[0] != (WORDS_BIG_ENDIAN ? 0x22222222 : 0x33333333))
+ abort ();
+ if (c[1] != (WORDS_BIG_ENDIAN ? 0x44444444 : 0x11111111))
+ abort ();
+ /* c[hi] = a[lo], c[lo] = b[hi] */
+ c = __ev_mergelohi (a, b);
+ if (c[0] != (WORDS_BIG_ENDIAN ? 0x22222222 : 0x44444444))
+ abort ();
+ if (c[1] != (WORDS_BIG_ENDIAN ? 0x33333333 : 0x11111111))
+ abort ();
+ /* c[hi] = a[hi], c[lo] = b[lo] */
+ c = __ev_mergehilo (a, b);
+ if (c[0] != (WORDS_BIG_ENDIAN ? 0x11111111 : 0x33333333))
+ abort ();
+ if (c[1] != (WORDS_BIG_ENDIAN ? 0x44444444 : 0x22222222))
+ abort ();
+
+ /* c[hi] = a[hi], c[lo] = b[hi] */
+ c = __builtin_spe_evmergehi (a, b);
+ if (c[0] != (WORDS_BIG_ENDIAN ? 0x11111111 : 0x44444444))
+ abort ();
+ if (c[1] != (WORDS_BIG_ENDIAN ? 0x33333333 : 0x22222222))
+ abort ();
+ /* c[hi] = a[lo], c[lo] = b[lo] */
+ c = __builtin_spe_evmergelo (a, b);
+ if (c[0] != (WORDS_BIG_ENDIAN ? 0x22222222 : 0x33333333))
+ abort ();
+ if (c[1] != (WORDS_BIG_ENDIAN ? 0x44444444 : 0x11111111))
+ abort ();
+ /* c[hi] = a[lo], c[lo] = b[hi] */
+ c = __builtin_spe_evmergelohi (a, b);
+ if (c[0] != (WORDS_BIG_ENDIAN ? 0x22222222 : 0x44444444))
+ abort ();
+ if (c[1] != (WORDS_BIG_ENDIAN ? 0x33333333 : 0x11111111))
+ abort ();
+ /* c[hi] = a[hi], c[lo] = b[lo] */
+ c = __builtin_spe_evmergehilo (a, b);
+ if (c[0] != (WORDS_BIG_ENDIAN ? 0x11111111 : 0x33333333))
+ abort ();
+ if (c[1] != (WORDS_BIG_ENDIAN ? 0x44444444 : 0x22222222))
+ abort ();
+
+ return 0;
+}