diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 807bf1a..c5699d6 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -13407,9 +13407,12 @@ mips_vector_mode_supported_p (machine_mode mode) return TARGET_DSP; case E_V2SImode: + return TARGET_LOONGSON_MMI; + case E_V4HImode: case E_V8QImode: - return TARGET_LOONGSON_MMI; + return TARGET_LOONGSON_MMI + || (TARGET_64BIT && ISA_HAS_WSBH); default: return MSA_SUPPORTED_MODE_P (mode); @@ -21608,6 +21611,9 @@ mips_expand_vec_perm_const_1 (struct expand_vec_perm_d *d) if (d->one_vector_p) { + if (mips_expand_vselect (d->target, d->op0, d->perm, nelt)) + return true; + /* Try interleave with alternating operands. */ memcpy (perm2, d->perm, sizeof(perm2)); for (i = 1; i < nelt; i += 2) diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index 455b9b8..21364d6 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -81,11 +81,6 @@ UNSPEC_STORE_LEFT UNSPEC_STORE_RIGHT - ;; Integer operations that are too cumbersome to describe directly. - UNSPEC_WSBH - UNSPEC_DSBH - UNSPEC_DSHD - ;; Floating-point moves. UNSPEC_LOAD_LOW UNSPEC_LOAD_HIGH @@ -5866,45 +5861,139 @@ "wsbh\t%0,%1" [(set_attr "type" "shift")]) -(define_insn_and_split "bswapsi2" +(define_expand "bswapsi2" [(set (match_operand:SI 0 "register_operand" "=d") (bswap:SI (match_operand:SI 1 "register_operand" "d")))] "ISA_HAS_WSBH && ISA_HAS_ROR" - "#" - "&& 1" - [(set (match_dup 0) (unspec:SI [(match_dup 1)] UNSPEC_WSBH)) - (set (match_dup 0) (rotatert:SI (match_dup 0) (const_int 16)))] - "" - [(set_attr "insn_count" "2")]) +{ + rtx tmp = gen_reg_rtx (SImode); + emit_insn (gen_wsbh (tmp, operands[1])); + emit_insn (gen_rotrsi3 (operands[0], tmp, GEN_INT (16))); + DONE; +}) -(define_insn_and_split "bswapdi2" +(define_expand "bswapdi2" [(set (match_operand:DI 0 "register_operand" "=d") (bswap:DI (match_operand:DI 1 "register_operand" "d")))] "TARGET_64BIT && ISA_HAS_WSBH" - "#" - "&& 1" - [(set (match_dup 0) (unspec:DI [(match_dup 1)] UNSPEC_DSBH)) - (set (match_dup 0) (unspec:DI [(match_dup 0)] UNSPEC_DSHD))] - "" - [(set_attr "insn_count" "2")]) +{ + rtx tmp = gen_reg_rtx (DImode); + emit_insn (gen_dsbh (tmp, operands[1])); + emit_insn (gen_dshd (operands[0], tmp)); + DONE; +}) (define_insn "wsbh" [(set (match_operand:SI 0 "register_operand" "=d") - (unspec:SI [(match_operand:SI 1 "register_operand" "d")] UNSPEC_WSBH))] + (rotatert:SI (bswap:SI (match_operand:SI 1 "register_operand" "d")) + (const_int 16)))] + "ISA_HAS_WSBH" + "wsbh\t%0,%1" + [(set_attr "type" "shift")]) + +;; Non-canonical variant of wsbh +(define_insn "wsbh_2" + [(set (match_operand:SI 0 "register_operand" "=d") + (bswap:SI (rotatert:SI (match_operand:SI 1 "register_operand" "d") + (const_int 16))))] + "ISA_HAS_WSBH" + "wsbh\t%0,%1" + [(set_attr "type" "shift")]) + +;; V4QI form of wsbh +(define_insn "wsbh_v4qi" + [(set (match_operand:V4QI 0 "register_operand") + (vec_select:V4QI (match_operand:V4QI 1 "register_operand") + (parallel [(const_int 1) + (const_int 0) + (const_int 3) + (const_int 2)])))] + "ISA_HAS_WSBH" + "wsbh\t%0,%1" + [(set_attr "type" "shift")]) + +;; V2HI form of wsbh +(define_insn "wsbh_v2hi" + [(set (match_operand:V2HI 0 "register_operand") + (vec_select:V2HI (match_operand:V2HI 1 "register_operand") + (parallel [(const_int 1) + (const_int 0)])))] "ISA_HAS_WSBH" "wsbh\t%0,%1" [(set_attr "type" "shift")]) (define_insn "dsbh" - [(set (match_operand:DI 0 "register_operand" "=d") - (unspec:DI [(match_operand:DI 1 "register_operand" "d")] UNSPEC_DSBH))] + [(set (subreg:V8QI (match_operand:DI 0 "register_operand" "=d") 0) + (vec_select:V8QI + (subreg:V8QI (match_operand:DI 1 "register_operand" "d") 0) + (parallel [(const_int 1) + (const_int 0) + (const_int 3) + (const_int 2) + (const_int 5) + (const_int 4) + (const_int 7) + (const_int 6)])))] + "TARGET_64BIT && ISA_HAS_WSBH" + "dsbh\t%0,%1" + [(set_attr "type" "shift")]) + +;; V8QI form of dsbh +(define_insn "dsbh_v8qi" + [(set (match_operand:V8QI 0 "register_operand" "=d") + (vec_select:V8QI (match_operand:V8QI 1 "register_operand") + (parallel [(const_int 1) + (const_int 0) + (const_int 3) + (const_int 2) + (const_int 5) + (const_int 4) + (const_int 7) + (const_int 6)])))] "TARGET_64BIT && ISA_HAS_WSBH" "dsbh\t%0,%1" [(set_attr "type" "shift")]) (define_insn "dshd" - [(set (match_operand:DI 0 "register_operand" "=d") - (unspec:DI [(match_operand:DI 1 "register_operand" "d")] UNSPEC_DSHD))] + [(set (subreg:V8QI (match_operand:DI 0 "register_operand" "=d") 0) + (vec_select:V8QI + (subreg:V8QI (match_operand:DI 1 "register_operand" "d") 0) + (parallel [(const_int 6) + (const_int 7) + (const_int 4) + (const_int 5) + (const_int 2) + (const_int 3) + (const_int 0) + (const_int 1)])))] + "TARGET_64BIT && ISA_HAS_WSBH" + "dshd\t%0,%1" + [(set_attr "type" "shift")]) + +;; V8QI form of dshd +(define_insn "dshd_v8qi" + [(set (match_operand:V8QI 0 "register_operand" "=d") + (vec_select:V8QI (match_operand:V8QI 1 "register_operand") + (parallel [(const_int 6) + (const_int 7) + (const_int 4) + (const_int 5) + (const_int 2) + (const_int 3) + (const_int 0) + (const_int 1)])))] + "TARGET_64BIT && ISA_HAS_WSBH" + "dshd\t%0,%1" + [(set_attr "type" "shift")]) + +;; V4HI form of dshd +(define_insn "dshd_v4hi" + [(set (match_operand:V4HI 0 "register_operand" "=d") + (vec_select:V4HI (match_operand:V4HI 1 "register_operand") + (parallel [(const_int 3) + (const_int 2) + (const_int 1) + (const_int 0)])))] "TARGET_64BIT && ISA_HAS_WSBH" "dshd\t%0,%1" [(set_attr "type" "shift")]) diff --git a/gcc/testsuite/gcc.target/mips/dsbh-v8qi.c b/gcc/testsuite/gcc.target/mips/dsbh-v8qi.c new file mode 100644 index 0000000..0bb7a1a --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/dsbh-v8qi.c @@ -0,0 +1,12 @@ +/* { dg-options "isa_rev>=2 -mgp64" } */ + +typedef char v8qi __attribute__((vector_size (8))); + +long long foo(long long x) +{ + v8qi t = (v8qi)x; + t = __builtin_shufflevector (t, t, 1, 0, 3, 2, 5, 4, 7, 6); + return (long long)t; +} + +/* { dg-final { scan-assembler "\tdsbh\t" } } */ diff --git a/gcc/testsuite/gcc.target/mips/dshd-v4hi.c b/gcc/testsuite/gcc.target/mips/dshd-v4hi.c new file mode 100644 index 0000000..309468f --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/dshd-v4hi.c @@ -0,0 +1,13 @@ +/* { dg-options "isa_rev>=2 -mgp64" } */ + +typedef short v4hi __attribute__((vector_size (8))); + +long long foo(long long x) +{ + v4hi t = (v4hi)x; + t = __builtin_shufflevector (t, t, 3, 2, 1, 0); + return (long long)t; +} + +/* { dg-final { scan-assembler "\tdshd\t" } } */ + diff --git a/gcc/testsuite/gcc.target/mips/dshd-v8qi.c b/gcc/testsuite/gcc.target/mips/dshd-v8qi.c new file mode 100644 index 0000000..f07a735 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/dshd-v8qi.c @@ -0,0 +1,12 @@ +/* { dg-options "isa_rev>=2 -mgp64" } */ + +typedef char v8qi __attribute__((vector_size (8))); + +long long foo(long long x) +{ + v8qi t = (v8qi)x; + t = __builtin_shufflevector (t, t, 6, 7, 4, 5, 2, 3, 0, 1); + return (long long)t; +} + +/* { dg-final { scan-assembler "\tdshd\t" } } */ diff --git a/gcc/testsuite/gcc.target/mips/wsbh.c b/gcc/testsuite/gcc.target/mips/wsbh.c new file mode 100644 index 0000000..5f6c37b --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/wsbh.c @@ -0,0 +1,18 @@ +/* { dg-options "isa_rev>=2" } */ +/* { dg-skip-if "bswap recognition needs expensive optimizations" { *-*-* } { "-O0" "-O1" } { "" } } */ + +unsigned int foo(unsigned int x) +{ + unsigned int t = __builtin_bswap32(x); + return (t>>16) | (t<<16); +} + +unsigned int bar(unsigned int x) +{ + unsigned int t = (x>>16) | (x<<16); + return __builtin_bswap32(t); +} + +/* { dg-final { scan-assembler-times "\twsbh\t" 2 } } */ +/* { dg-final { scan-assembler-not "\tror\t" } } */ +