summaryrefslogtreecommitdiff
path: root/gcc/config/arm/aarch-common.c
diff options
context:
space:
mode:
authorktkachov <ktkachov@138bc75d-0d04-0410-961f-82ee72b054a4>2014-04-23 15:26:28 +0000
committerktkachov <ktkachov@138bc75d-0d04-0410-961f-82ee72b054a4>2014-04-23 15:26:28 +0000
commitd049924de943f809fbec2111ab3e611693dcef89 (patch)
tree2510b3a45cf0d83f6649c31498711958ba864a74 /gcc/config/arm/aarch-common.c
parent3ee551163e8eecd02539f39a4f7a14701eca35e1 (diff)
downloadgcc-d049924de943f809fbec2111ab3e611693dcef89.tar.gz
[AArch64][2/3] Recognise rev16 operations on SImode and DImode data
* config/aarch64/aarch64.md (rev16<mode>2): New pattern. (rev16<mode>2_alt): Likewise. * config/aarch64/aarch64.c (aarch64_rtx_costs): Handle rev16 case. * config/arm/aarch-common.c (aarch_rev16_shright_mask_imm_p): New. (aarch_rev16_shleft_mask_imm_p): Likewise. (aarch_rev16_p_1): Likewise. (aarch_rev16_p): Likewise. * config/arm/aarch-common-protos.h (aarch_rev16_p): Declare extern. (aarch_rev16_shright_mask_imm_p): Likewise. (aarch_rev16_shleft_mask_imm_p): Likewise. * gcc.target/aarch64/rev16_1.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@209704 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/arm/aarch-common.c')
-rw-r--r--gcc/config/arm/aarch-common.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/gcc/config/arm/aarch-common.c b/gcc/config/arm/aarch-common.c
index af8fc9996fa..884d4b37fac 100644
--- a/gcc/config/arm/aarch-common.c
+++ b/gcc/config/arm/aarch-common.c
@@ -191,6 +191,79 @@ arm_get_set_operands (rtx producer, rtx consumer,
return 0;
}
+bool
+aarch_rev16_shright_mask_imm_p (rtx val, enum machine_mode mode)
+{
+ return CONST_INT_P (val)
+ && INTVAL (val) == trunc_int_for_mode (0xff00ff00ff00ff, mode);
+}
+
+bool
+aarch_rev16_shleft_mask_imm_p (rtx val, enum machine_mode mode)
+{
+ return CONST_INT_P (val)
+ && INTVAL (val) == trunc_int_for_mode (0xff00ff00ff00ff00, mode);
+}
+
+
+static bool
+aarch_rev16_p_1 (rtx lhs, rtx rhs, enum machine_mode mode)
+{
+ if (GET_CODE (lhs) == AND
+ && GET_CODE (XEXP (lhs, 0)) == ASHIFT
+ && CONST_INT_P (XEXP (XEXP (lhs, 0), 1))
+ && INTVAL (XEXP (XEXP (lhs, 0), 1)) == 8
+ && REG_P (XEXP (XEXP (lhs, 0), 0))
+ && CONST_INT_P (XEXP (lhs, 1))
+ && GET_CODE (rhs) == AND
+ && GET_CODE (XEXP (rhs, 0)) == LSHIFTRT
+ && REG_P (XEXP (XEXP (rhs, 0), 0))
+ && CONST_INT_P (XEXP (XEXP (rhs, 0), 1))
+ && INTVAL (XEXP (XEXP (rhs, 0), 1)) == 8
+ && CONST_INT_P (XEXP (rhs, 1))
+ && REGNO (XEXP (XEXP (rhs, 0), 0)) == REGNO (XEXP (XEXP (lhs, 0), 0)))
+
+ {
+ rtx lhs_mask = XEXP (lhs, 1);
+ rtx rhs_mask = XEXP (rhs, 1);
+
+ return aarch_rev16_shright_mask_imm_p (rhs_mask, mode)
+ && aarch_rev16_shleft_mask_imm_p (lhs_mask, mode);
+ }
+
+ return false;
+}
+
+/* Recognise a sequence of bitwise operations corresponding to a rev16 operation.
+ These will be of the form:
+ ((x >> 8) & 0x00ff00ff)
+ | ((x << 8) & 0xff00ff00)
+ for SImode and with similar but wider bitmasks for DImode.
+ The two sub-expressions of the IOR can appear on either side so check both
+ permutations with the help of aarch_rev16_p_1 above. */
+
+bool
+aarch_rev16_p (rtx x)
+{
+ rtx left_sub_rtx, right_sub_rtx;
+ bool is_rev = false;
+
+ if (GET_CODE (x) != IOR)
+ return false;
+
+ left_sub_rtx = XEXP (x, 0);
+ right_sub_rtx = XEXP (x, 1);
+
+ /* There are no canonicalisation rules for the position of the two shifts
+ involved in a rev, so try both permutations. */
+ is_rev = aarch_rev16_p_1 (left_sub_rtx, right_sub_rtx, GET_MODE (x));
+
+ if (!is_rev)
+ is_rev = aarch_rev16_p_1 (right_sub_rtx, left_sub_rtx, GET_MODE (x));
+
+ return is_rev;
+}
+
/* Return nonzero if the CONSUMER instruction (a load) does need
PRODUCER's value to calculate the address. */
int