Hi all,This is the arm equivalent of patch [2/3] in the series that adds combine patterns for the bitwise operations leading to a rev16 instruction. It reuses the functions that were put in aarch-common.c to properly cost these operations.
I tried matching a DImode rev16 (with the intent of splitting it into two rev16 ops) like aarch64 but combine wouldn't try to match that bitwise pattern in DImode like aarch64 does. Instead it tries various exotic combinations with subregs.
Tested arm-none-eabi, bootstrap on arm-none-linux-gnueabihf. Ok for stage1? [gcc/] 2014-03-19 Kyrylo Tkachov <kyrylo.tkac...@arm.com> * config/arm/arm.md (arm_rev16si2): New pattern. (arm_rev16si2_alt): Likewise. * config/arm/arm.c (arm_new_rtx_costs): Handle rev16 case. [gcc/testsuite/] 2014-03-19 Kyrylo Tkachov <kyrylo.tkac...@arm.com> * gcc.target/arm/rev16.c: New test.
commit 04e60723bd1fa2f8e2adcfeed676390643ffec0c Author: Kyrylo Tkachov <kyrylo.tkac...@arm.com> Date: Tue Feb 25 15:26:52 2014 +0000 [ARM] Implement SImode rev16 diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 8d1d721..ed603f0 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -9716,8 +9716,17 @@ arm_new_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code, /* Vector mode? */ *cost = LIBCALL_COST (2); return false; + case IOR: + if (mode == SImode && arm_arch6 && aarch_rev16_p (x)) + { + *cost = COSTS_N_INSNS (1); + if (speed_p) + *cost += extra_cost->alu.rev; - case AND: case XOR: case IOR: + return true; + } + /* Fall through. */ + case AND: case XOR: if (mode == SImode) { enum rtx_code subcode = GET_CODE (XEXP (x, 0)); diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 4df24a2..47bc747 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -12668,6 +12668,44 @@ (set_attr "type" "rev")] ) +;; There are no canonicalisation rules for the position of the lshiftrt, ashift +;; operations within an IOR/AND RTX, therefore we have two patterns matching +;; each valid permutation. + +(define_insn "arm_rev16si2" + [(set (match_operand:SI 0 "register_operand" "=l,l,r") + (ior:SI (and:SI (ashift:SI (match_operand:SI 1 "register_operand" "l,l,r") + (const_int 8)) + (match_operand:SI 3 "const_int_operand" "n,n,n")) + (and:SI (lshiftrt:SI (match_dup 1) + (const_int 8)) + (match_operand:SI 2 "const_int_operand" "n,n,n"))))] + "arm_arch6 + && aarch_rev16_shleft_mask_imm_p (operands[3], SImode) + && aarch_rev16_shright_mask_imm_p (operands[2], SImode)" + "rev16\\t%0, %1" + [(set_attr "arch" "t1,t2,32") + (set_attr "length" "2,2,4") + (set_attr "type" "rev")] +) + +(define_insn "arm_rev16si2_alt" + [(set (match_operand:SI 0 "register_operand" "=l,l,r") + (ior:SI (and:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" "l,l,r") + (const_int 8)) + (match_operand:SI 2 "const_int_operand" "n,n,n")) + (and:SI (ashift:SI (match_dup 1) + (const_int 8)) + (match_operand:SI 3 "const_int_operand" "n,n,n"))))] + "arm_arch6 + && aarch_rev16_shleft_mask_imm_p (operands[3], SImode) + && aarch_rev16_shright_mask_imm_p (operands[2], SImode)" + "rev16\\t%0, %1" + [(set_attr "arch" "t1,t2,32") + (set_attr "length" "2,2,4") + (set_attr "type" "rev")] +) + (define_expand "bswaphi2" [(set (match_operand:HI 0 "s_register_operand" "=r") (bswap:HI (match_operand:HI 1 "s_register_operand" "r")))] diff --git a/gcc/testsuite/gcc.target/arm/rev16.c b/gcc/testsuite/gcc.target/arm/rev16.c new file mode 100644 index 0000000..1c869b3 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/rev16.c @@ -0,0 +1,35 @@ +/* { dg-options "-O2" } */ +/* { dg-do run } */ + +extern void abort (void); + +typedef unsigned int __u32; + +__u32 +__rev16_32_alt (__u32 x) +{ + return (((__u32)(x) & (__u32)0xff00ff00UL) >> 8) + | (((__u32)(x) & (__u32)0x00ff00ffUL) << 8); +} + +__u32 +__rev16_32 (__u32 x) +{ + return (((__u32)(x) & (__u32)0x00ff00ffUL) << 8) + | (((__u32)(x) & (__u32)0xff00ff00UL) >> 8); +} + +int +main (void) +{ + volatile __u32 in32 = 0x12345678; + volatile __u32 expected32 = 0x34127856; + + if (__rev16_32 (in32) != expected32) + abort (); + + if (__rev16_32_alt (in32) != expected32) + abort (); + + return 0; +}