summaryrefslogtreecommitdiff
path: root/gcc/config/tilegx/tilegx.md
diff options
context:
space:
mode:
authorWalter Lee <walt@tilera.com>2014-02-24 15:08:00 +0000
committerWalter Lee <walt@gcc.gnu.org>2014-02-24 15:08:00 +0000
commit341c653c704e398070219534cd9fed97e56661b3 (patch)
tree53162bb2cdbb19111069e925e278cefd4d970326 /gcc/config/tilegx/tilegx.md
parentc97d7285d9b949ac05ad04f0d76112579c50e240 (diff)
downloadgcc-341c653c704e398070219534cd9fed97e56661b3.tar.gz
TILE-Gx big endian support.
/: * configure.ac (tilepro-*-*) Change to tilepro*-*-*. (tilegx-*-*): Change to tilegx*-*-*. * configure: Regenerate. contrib/: * config-list.mk (LIST): Add tilegxbe-linux-gnu. libcpp/: * configure.ac: Change "tilepro" triplet to "tilepro*". * configure: Regenerate. libgcc/: * config.host: Support "tilegx*" and "tilepro*" triplets. * config/tilegx/sfp-machine32.h (__BYTE_ORDER): Handle big endian. * config/tilegx/sfp-machine64.h (__BYTE_ORDER): Handle big endian. gcc/: * config.gcc (tilepro-*-*): Change to tilepro*-*-*. (tilegx-*-linux*): Change to tilegx*-*-linux*; Support tilegxbe triplet. * common/config/tilegx/tilegx-common.c (TARGET_DEFAULT_TARGET_FLAGS): Define. * config/tilegx/linux.h (ASM_SPEC): Add endian_spec. (LINK_SPEC): Ditto. * config/tilegx/sync.md (atomic_test_and_set): Handle big endian. * config/tilegx/tilegx.c (tilegx_return_in_msb): New. (tilegx_gimplify_va_arg_expr): Handle big endian. (tilegx_expand_unaligned_load): Ditto. (tilegx_expand_unaligned_store): Ditto. (TARGET_RETURN_IN_MSB): New. * config/tilegx/tilegx.h (TARGET_DEFAULT): New. (TARGET_ENDIAN_DEFAULT): New. (TARGET_BIG_ENDIAN): Handle big endian. (BYTES_BIG_ENDIAN): Ditto. (WORDS_BIG_ENDIAN): Ditto. (FLOAT_WORDS_BIG_ENDIAN): Ditto. (ENDIAN_SPEC): New. (EXTRA_SPECS): New. * config/tilegx/tilegx.md (extv): Handle big endian. (extzv): Ditto. (insn_st<n>): Ditto. (insn_st<n>_add<bitsuffix>): Ditto. (insn_stnt<n>): Ditto. (insn_stnt<n>_add<bitsuffix>):Ditto. (vec_interleave_highv8qi): Handle big endian. (vec_interleave_highv8qi_be): New. (vec_interleave_highv8qi_le): New. (insn_v1int_h): Handle big endian. (vec_interleave_lowv8qi): Handle big endian. (vec_interleave_lowv8qi_be): New. (vec_interleave_lowv8qi_le): New. (insn_v1int_l): Handle big endian. (vec_interleave_highv4hi): Handle big endian. (vec_interleave_highv4hi_be): New. (vec_interleave_highv4hi_le): New. (insn_v2int_h): Handle big endian. (vec_interleave_lowv4hi): Handle big endian. (vec_interleave_lowv4hi_be): New. (vec_interleave_lowv4hi_le): New. (insn_v2int_l): Handle big endian. (vec_interleave_highv2si): Handle big endian. (vec_interleave_highv2si_be): New. (vec_interleave_highv2si_le): New. (insn_v4int_h): Handle big endian. (vec_interleave_lowv2si): Handle big endian. (vec_interleave_lowv2si_be): New. (vec_interleave_lowv2si_le): New. (insn_v4int_l): Handle big endian. * config/tilegx/tilegx.opt (mbig-endian): New option. (mlittle-endian): New option. * doc/install.texi: Document tilegxbe-linux. * doc/invoke.texi: Document -mbig-endian and -mlittle-endian. From-SVN: r208069
Diffstat (limited to 'gcc/config/tilegx/tilegx.md')
-rw-r--r--gcc/config/tilegx/tilegx.md281
1 files changed, 243 insertions, 38 deletions
diff --git a/gcc/config/tilegx/tilegx.md b/gcc/config/tilegx/tilegx.md
index c8c7af682a8..94946bb9b56 100644
--- a/gcc/config/tilegx/tilegx.md
+++ b/gcc/config/tilegx/tilegx.md
@@ -824,6 +824,12 @@
bit_width = INTVAL (operands[2]);
bit_offset = INTVAL (operands[3]);
+ /* NOTE: bit_offset is relative to the mode of operand
+ 1 (QImode). It will be negative in big-endian mode
+ here. Convert that back to the real offset. */
+ if (BYTES_BIG_ENDIAN)
+ bit_offset = GET_MODE_BITSIZE (QImode) - bit_width - bit_offset;
+
/* Reject bitfields that can be done with a normal load. */
if (MEM_ALIGN (operands[1]) >= bit_offset + bit_width)
FAIL;
@@ -860,6 +866,12 @@
if (GET_MODE (operands[1]) != QImode)
FAIL;
+ /* NOTE: bit_offset is relative to the mode of operand
+ 1 (QImode). It will be negative in big-endian mode
+ here. */
+ if (BYTES_BIG_ENDIAN)
+ bit_offset = GET_MODE_BITSIZE (QImode) - bit_width - bit_offset;
+
/* Reject bitfields that can be done with a normal load. */
if (MEM_ALIGN (operands[1]) >= bit_offset + bit_width)
FAIL;
@@ -3983,7 +3995,9 @@
(match_operand:DI 1 "reg_or_0_operand" ""))]
""
{
- operands[1] = simplify_gen_subreg (<MODE>mode, operands[1], DImode, 0);
+ operands[1] = simplify_gen_subreg (<MODE>mode, operands[1], DImode,
+ BYTES_BIG_ENDIAN
+ ? UNITS_PER_WORD - <n> : 0);
})
(define_expand "insn_st<I124MODE:n>_add<I48MODE:bitsuffix>"
@@ -3996,7 +4010,9 @@
""
{
operands[1] = simplify_gen_subreg (<I124MODE:MODE>mode, operands[1],
- DImode, 0);
+ DImode,
+ BYTES_BIG_ENDIAN
+ ? UNITS_PER_WORD - <I124MODE:n> : 0);
})
(define_insn "*insn_st<I124MODE:n>_add<I48MODE:bitsuffix>"
@@ -4035,7 +4051,9 @@
(match_operand:DI 1 "reg_or_0_operand" ""))]
""
{
- operands[1] = simplify_gen_subreg (<MODE>mode, operands[1], DImode, 0);
+ operands[1] = simplify_gen_subreg (<MODE>mode, operands[1], DImode,
+ BYTES_BIG_ENDIAN
+ ? UNITS_PER_WORD - <n> : 0);
})
(define_insn "*insn_stnt<n>"
@@ -4056,7 +4074,9 @@
""
{
operands[1] = simplify_gen_subreg (<I124MODE:MODE>mode, operands[1],
- DImode, 0);
+ DImode,
+ BYTES_BIG_ENDIAN
+ ? UNITS_PER_WORD - <n> : 0);
})
(define_insn "*insn_stnt<I124MODE:n>_add<I48MODE:bitsuffix>"
@@ -4412,11 +4432,46 @@
DONE;
})
+;; Byte ordering of these vectors is endian dependent. gcc concats
+;; right-to-left for little endian, and left-to-right for big endian.
+;; So we need different patterns that depend on endianness. Our
+;; instructions concat and interleave the way a big-endian target would
+;; work in gcc, so for little endian, we need to reverse the source
+;; operands.
+
;; insn_v1int_h
;; {B7,B6,B5,B4,B3,B2,B1,B0} {A7,A6,A5,A4,A3,A2,A1,A0}
;; => {A7,A6,A5,A4,A3,A2,A1,A0,B7,B6,B5,B4,B3,B2,B1,B0}
;; => {A7,B7,A6,B6,A5,B5,A4,B4}
-(define_insn "vec_interleave_highv8qi"
+(define_expand "vec_interleave_highv8qi"
+ [(match_operand:V8QI 0 "register_operand" "")
+ (match_operand:V8QI 1 "reg_or_0_operand" "")
+ (match_operand:V8QI 2 "reg_or_0_operand" "")]
+ ""
+{
+ if (BYTES_BIG_ENDIAN)
+ emit_insn (gen_vec_interleave_highv8qi_be (operands[0], operands[1],
+ operands[2]));
+ else
+ emit_insn (gen_vec_interleave_highv8qi_le (operands[0], operands[1],
+ operands[2]));
+ DONE;
+})
+
+(define_insn "vec_interleave_highv8qi_be"
+ [(set (match_operand:V8QI 0 "register_operand" "=r")
+ (vec_select:V8QI
+ (vec_concat:V16QI (match_operand:V8QI 1 "reg_or_0_operand" "rO")
+ (match_operand:V8QI 2 "reg_or_0_operand" "rO"))
+ (parallel [(const_int 0) (const_int 8)
+ (const_int 1) (const_int 9)
+ (const_int 2) (const_int 10)
+ (const_int 3) (const_int 11)])))]
+ "BYTES_BIG_ENDIAN"
+ "v1int_h\t%0, %r1, %r2"
+ [(set_attr "type" "X01")])
+
+(define_insn "vec_interleave_highv8qi_le"
[(set (match_operand:V8QI 0 "register_operand" "=r")
(vec_select:V8QI
(vec_concat:V16QI (match_operand:V8QI 1 "reg_or_0_operand" "rO")
@@ -4425,7 +4480,7 @@
(const_int 5) (const_int 13)
(const_int 6) (const_int 14)
(const_int 7) (const_int 15)])))]
- ""
+ "!BYTES_BIG_ENDIAN"
"v1int_h\t%0, %r2, %r1"
[(set_attr "type" "X01")])
@@ -4435,11 +4490,14 @@
(match_operand:DI 2 "reg_or_0_operand" "")]
""
{
- /* Our instruction interleaves opposite of the way vec_interleave
- works, so we need to reverse the source operands. */
+ /* For little endian, our instruction interleaves opposite of the
+ way vec_interleave works, so we need to reverse the source
+ operands. */
+ rtx opnd1 = BYTES_BIG_ENDIAN ? operands[1] : operands[2];
+ rtx opnd2 = BYTES_BIG_ENDIAN ? operands[2] : operands[1];
tilegx_expand_builtin_vector_binop (gen_vec_interleave_highv8qi, V8QImode,
- operands[0], V8QImode, operands[2],
- operands[1], true);
+ operands[0], V8QImode, opnd1, opnd2,
+ true);
DONE;
})
@@ -4447,7 +4505,35 @@
;; {B7,B6,B5,B4,B3,B2,B1,B0} {A7,A6,A5,A4,A3,A2,A1,A0}
;; => {A7,A6,A5,A4,A3,A2,A1,A0,B7,B6,B5,B4,B3,B2,B1,B0}
;; => {A3,B3,A2,B2,A1,B1,A0,B0}
-(define_insn "vec_interleave_lowv8qi"
+(define_expand "vec_interleave_lowv8qi"
+ [(match_operand:V8QI 0 "register_operand" "")
+ (match_operand:V8QI 1 "reg_or_0_operand" "")
+ (match_operand:V8QI 2 "reg_or_0_operand" "")]
+ ""
+{
+ if (BYTES_BIG_ENDIAN)
+ emit_insn (gen_vec_interleave_lowv8qi_be (operands[0], operands[1],
+ operands[2]));
+ else
+ emit_insn (gen_vec_interleave_lowv8qi_le (operands[0], operands[1],
+ operands[2]));
+ DONE;
+})
+
+(define_insn "vec_interleave_lowv8qi_be"
+ [(set (match_operand:V8QI 0 "register_operand" "=r")
+ (vec_select:V8QI
+ (vec_concat:V16QI (match_operand:V8QI 1 "reg_or_0_operand" "rO")
+ (match_operand:V8QI 2 "reg_or_0_operand" "rO"))
+ (parallel [(const_int 4) (const_int 12)
+ (const_int 5) (const_int 13)
+ (const_int 6) (const_int 14)
+ (const_int 7) (const_int 15)])))]
+ "BYTES_BIG_ENDIAN"
+ "v1int_l\t%0, %r1, %r2"
+ [(set_attr "type" "X01")])
+
+(define_insn "vec_interleave_lowv8qi_le"
[(set (match_operand:V8QI 0 "register_operand" "=r")
(vec_select:V8QI
(vec_concat:V16QI (match_operand:V8QI 1 "reg_or_0_operand" "rO")
@@ -4456,7 +4542,7 @@
(const_int 1) (const_int 9)
(const_int 2) (const_int 10)
(const_int 3) (const_int 11)])))]
- ""
+ "!BYTES_BIG_ENDIAN"
"v1int_l\t%0, %r2, %r1"
[(set_attr "type" "X01")])
@@ -4466,11 +4552,14 @@
(match_operand:DI 2 "reg_or_0_operand" "")]
""
{
- /* Our instruction interleaves opposite of the way vec_interleave
- works, so we need to reverse the source operands. */
+ /* For little endian, our instruction interleaves opposite of the
+ way vec_interleave works, so we need to reverse the source
+ operands. */
+ rtx opnd1 = BYTES_BIG_ENDIAN ? operands[1] : operands[2];
+ rtx opnd2 = BYTES_BIG_ENDIAN ? operands[2] : operands[1];
tilegx_expand_builtin_vector_binop (gen_vec_interleave_lowv8qi, V8QImode,
- operands[0], V8QImode, operands[2],
- operands[1], true);
+ operands[0], V8QImode, opnd1, opnd2,
+ true);
DONE;
})
@@ -4478,14 +4567,40 @@
;; {B3,B2,B1,B0} {A3,A2,A1,A0}
;; => {A3,A2,A1,A0,B3,B2,B1,B0}
;; => {A3,B3,A2,B2}
-(define_insn "vec_interleave_highv4hi"
+(define_expand "vec_interleave_highv4hi"
+ [(match_operand:V4HI 0 "register_operand" "")
+ (match_operand:V4HI 1 "reg_or_0_operand" "")
+ (match_operand:V4HI 2 "reg_or_0_operand" "")]
+ ""
+{
+ if (BYTES_BIG_ENDIAN)
+ emit_insn (gen_vec_interleave_highv4hi_be (operands[0], operands[1],
+ operands[2]));
+ else
+ emit_insn (gen_vec_interleave_highv4hi_le (operands[0], operands[1],
+ operands[2]));
+ DONE;
+})
+
+(define_insn "vec_interleave_highv4hi_be"
+ [(set (match_operand:V4HI 0 "register_operand" "=r")
+ (vec_select:V4HI
+ (vec_concat:V8HI (match_operand:V4HI 1 "reg_or_0_operand" "rO")
+ (match_operand:V4HI 2 "reg_or_0_operand" "rO"))
+ (parallel [(const_int 0) (const_int 4)
+ (const_int 1) (const_int 5)])))]
+ "BYTES_BIG_ENDIAN"
+ "v2int_h\t%0, %r1, %r2"
+ [(set_attr "type" "X01")])
+
+(define_insn "vec_interleave_highv4hi_le"
[(set (match_operand:V4HI 0 "register_operand" "=r")
(vec_select:V4HI
(vec_concat:V8HI (match_operand:V4HI 1 "reg_or_0_operand" "rO")
(match_operand:V4HI 2 "reg_or_0_operand" "rO"))
(parallel [(const_int 2) (const_int 6)
(const_int 3) (const_int 7)])))]
- ""
+ "!BYTES_BIG_ENDIAN"
"v2int_h\t%0, %r2, %r1"
[(set_attr "type" "X01")])
@@ -4495,11 +4610,14 @@
(match_operand:DI 2 "reg_or_0_operand" "")]
""
{
- /* Our instruction interleaves opposite of the way vec_interleave
- works, so we need to reverse the source operands. */
+ /* For little endian, our instruction interleaves opposite of the
+ way vec_interleave works, so we need to reverse the source
+ operands. */
+ rtx opnd1 = BYTES_BIG_ENDIAN ? operands[1] : operands[2];
+ rtx opnd2 = BYTES_BIG_ENDIAN ? operands[2] : operands[1];
tilegx_expand_builtin_vector_binop (gen_vec_interleave_highv4hi, V4HImode,
- operands[0], V4HImode, operands[2],
- operands[1], true);
+ operands[0], V4HImode, opnd1, opnd2,
+ true);
DONE;
})
@@ -4507,14 +4625,40 @@
;; {B3,B2,B1,B0} {A3,A2,A1,A0}
;; => {A3,A2,A1,A0,B3,B2,B1,B0}
;; => {A1,B1,A0,B0}
-(define_insn "vec_interleave_lowv4hi"
+(define_expand "vec_interleave_lowv4hi"
+ [(match_operand:V4HI 0 "register_operand" "")
+ (match_operand:V4HI 1 "reg_or_0_operand" "")
+ (match_operand:V4HI 2 "reg_or_0_operand" "")]
+ ""
+{
+ if (BYTES_BIG_ENDIAN)
+ emit_insn (gen_vec_interleave_lowv4hi_be (operands[0], operands[1],
+ operands[2]));
+ else
+ emit_insn (gen_vec_interleave_lowv4hi_le (operands[0], operands[1],
+ operands[2]));
+ DONE;
+})
+
+(define_insn "vec_interleave_lowv4hi_be"
+ [(set (match_operand:V4HI 0 "register_operand" "=r")
+ (vec_select:V4HI
+ (vec_concat:V8HI (match_operand:V4HI 1 "reg_or_0_operand" "rO")
+ (match_operand:V4HI 2 "reg_or_0_operand" "rO"))
+ (parallel [(const_int 2) (const_int 6)
+ (const_int 3) (const_int 7)])))]
+ "BYTES_BIG_ENDIAN"
+ "v2int_l\t%0, %r1, %r2"
+ [(set_attr "type" "X01")])
+
+(define_insn "vec_interleave_lowv4hi_le"
[(set (match_operand:V4HI 0 "register_operand" "=r")
(vec_select:V4HI
(vec_concat:V8HI (match_operand:V4HI 1 "reg_or_0_operand" "rO")
(match_operand:V4HI 2 "reg_or_0_operand" "rO"))
(parallel [(const_int 0) (const_int 4)
(const_int 1) (const_int 5)])))]
- ""
+ "!BYTES_BIG_ENDIAN"
"v2int_l\t%0, %r2, %r1"
[(set_attr "type" "X01")])
@@ -4524,9 +4668,14 @@
(match_operand:DI 2 "reg_or_0_operand" "")]
""
{
+ /* For little endian, our instruction interleaves opposite of the
+ way vec_interleave works, so we need to reverse the source
+ operands. */
+ rtx opnd1 = BYTES_BIG_ENDIAN ? operands[1] : operands[2];
+ rtx opnd2 = BYTES_BIG_ENDIAN ? operands[2] : operands[1];
tilegx_expand_builtin_vector_binop (gen_vec_interleave_lowv4hi, V4HImode,
- operands[0], V4HImode, operands[2],
- operands[1], true);
+ operands[0], V4HImode, opnd1, opnd2,
+ true);
DONE;
})
@@ -4534,13 +4683,38 @@
;; {B1,B0} {A1,A0}
;; => {A1,A0,B1,B0}
;; => {A1,B1}
-(define_insn "vec_interleave_highv2si"
+(define_expand "vec_interleave_highv2si"
+ [(match_operand:V2SI 0 "register_operand" "")
+ (match_operand:V2SI 1 "reg_or_0_operand" "")
+ (match_operand:V2SI 2 "reg_or_0_operand" "")]
+ ""
+{
+ if (BYTES_BIG_ENDIAN)
+ emit_insn (gen_vec_interleave_highv2si_be (operands[0], operands[1],
+ operands[2]));
+ else
+ emit_insn (gen_vec_interleave_highv2si_le (operands[0], operands[1],
+ operands[2]));
+ DONE;
+})
+
+(define_insn "vec_interleave_highv2si_be"
+ [(set (match_operand:V2SI 0 "register_operand" "=r")
+ (vec_select:V2SI
+ (vec_concat:V4SI (match_operand:V2SI 1 "reg_or_0_operand" "rO")
+ (match_operand:V2SI 2 "reg_or_0_operand" "rO"))
+ (parallel [(const_int 0) (const_int 2)])))]
+ "BYTES_BIG_ENDIAN"
+ "v4int_h\t%0, %r1, %r2"
+ [(set_attr "type" "X01")])
+
+(define_insn "vec_interleave_highv2si_le"
[(set (match_operand:V2SI 0 "register_operand" "=r")
(vec_select:V2SI
(vec_concat:V4SI (match_operand:V2SI 1 "reg_or_0_operand" "rO")
(match_operand:V2SI 2 "reg_or_0_operand" "rO"))
(parallel [(const_int 1) (const_int 3)])))]
- ""
+ "!BYTES_BIG_ENDIAN"
"v4int_h\t%0, %r2, %r1"
[(set_attr "type" "X01")])
@@ -4550,11 +4724,14 @@
(match_operand:DI 2 "reg_or_0_operand" "")]
""
{
- /* Our instruction interleaves opposite of the way vec_interleave
- works, so we need to reverse the source operands. */
+ /* For little endian, our instruction interleaves opposite of the
+ way vec_interleave works, so we need to reverse the source
+ operands. */
+ rtx opnd1 = BYTES_BIG_ENDIAN ? operands[1] : operands[2];
+ rtx opnd2 = BYTES_BIG_ENDIAN ? operands[2] : operands[1];
tilegx_expand_builtin_vector_binop (gen_vec_interleave_highv2si, V2SImode,
- operands[0], V2SImode, operands[2],
- operands[1], true);
+ operands[0], V2SImode, opnd1, opnd2,
+ true);
DONE;
})
@@ -4562,13 +4739,38 @@
;; {B1,B0} {A1,A0}
;; => {A1,A0,B1,B0}
;; => {A0,B0}
-(define_insn "vec_interleave_lowv2si"
+(define_expand "vec_interleave_lowv2si"
+ [(match_operand:V2SI 0 "register_operand" "")
+ (match_operand:V2SI 1 "reg_or_0_operand" "")
+ (match_operand:V2SI 2 "reg_or_0_operand" "")]
+ ""
+{
+ if (BYTES_BIG_ENDIAN)
+ emit_insn (gen_vec_interleave_lowv2si_be (operands[0], operands[1],
+ operands[2]));
+ else
+ emit_insn (gen_vec_interleave_lowv2si_le (operands[0], operands[1],
+ operands[2]));
+ DONE;
+})
+
+(define_insn "vec_interleave_lowv2si_be"
+ [(set (match_operand:V2SI 0 "register_operand" "=r")
+ (vec_select:V2SI
+ (vec_concat:V4SI (match_operand:V2SI 1 "reg_or_0_operand" "rO")
+ (match_operand:V2SI 2 "reg_or_0_operand" "rO"))
+ (parallel [(const_int 1) (const_int 3)])))]
+ "BYTES_BIG_ENDIAN"
+ "v4int_l\t%0, %r1, %r2"
+ [(set_attr "type" "X01")])
+
+(define_insn "vec_interleave_lowv2si_le"
[(set (match_operand:V2SI 0 "register_operand" "=r")
(vec_select:V2SI
(vec_concat:V4SI (match_operand:V2SI 1 "reg_or_0_operand" "rO")
(match_operand:V2SI 2 "reg_or_0_operand" "rO"))
(parallel [(const_int 0) (const_int 2)])))]
- ""
+ "!BYTES_BIG_ENDIAN"
"v4int_l\t%0, %r2, %r1"
[(set_attr "type" "X01")])
@@ -4578,11 +4780,14 @@
(match_operand:DI 2 "reg_or_0_operand" "")]
""
{
- /* Our instruction interleaves opposite of the way vec_interleave
- works, so we need to reverse the source operands. */
+ /* For little endian, our instruction interleaves opposite of the
+ way vec_interleave works, so we need to reverse the source
+ operands. */
+ rtx opnd1 = BYTES_BIG_ENDIAN ? operands[1] : operands[2];
+ rtx opnd2 = BYTES_BIG_ENDIAN ? operands[2] : operands[1];
tilegx_expand_builtin_vector_binop (gen_vec_interleave_lowv2si, V2SImode,
- operands[0], V2SImode, operands[2],
- operands[1], true);
+ operands[0], V2SImode, opnd1, opnd2,
+ true);
DONE;
})