Hello,
this patch adds support for generating usat/ssat instructions to match code
along the lines of:
if (a amin) return amin;
else if (a amax) return amax;
else return a;
for appropriate values of amin/amax. This type code actually occurs in
real-life code (e.g. codecs).
Above code is already translated into a sequence of SMIN/SMAX RTX
operations by expand. The combine pass is able to fold those into
a single RTX pattern, so we only need to make such patterns available
to match the instruction. Note that usat/ssat may in addition shift
their input operand; this is also supported by the patch.
There are already pre-existing patterns that use usat/ssat to
implement us_truncate/ss_truncate. Those represent special
cases of the general instructions, and are left in place by
this patch. (However, some minor fixes e.g. to the sat_shift_operator
predicate and insn attributes apply to those patterns too.)
Tested on arm-linux-gnueabi with no regressions.
OK for 4.8?
Bye,
Ulrich
ChangeLog:
gcc/
* config/arm/arm.c (arm_sat_operator_match): New function.
* config/arm/arm-protos.h (arm_sat_operator_match): Add prototype.
* config/arm/arm.md (insn attribute): Add sat value.
(SAT, SATrev): New code iterators.
(SATlo, SAThi): New code iterator attributes.
(*satsi_SAT:code): New pattern.
(*satsi_SAT:code_shift): Likewise.
* config/arm/arm-fixed.md (arm_ssatsihi_shift): Add insn
and shift attributes.
(arm_usatsihi): Add insn attribute.
* config/arm/predicates.md (sat_shift_operator): Allow multiplication
by powers of two. Do not allow shift by 32.
gcc/testsuite/
* gcc.target/arm/sat-1.c: New test.
Index: gcc/testsuite/gcc.target/arm/sat-1.c
===
--- gcc/testsuite/gcc.target/arm/sat-1.c(revision 0)
+++ gcc/testsuite/gcc.target/arm/sat-1.c(revision 0)
@@ -0,0 +1,64 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arm_ok } */
+/* { dg-require-effective-target arm_arch_v6_ok } */
+/* { dg-options -O2 -marm } */
+/* { dg-add-options arm_arch_v6 } */
+
+
+static inline int sat1 (int a, int amin, int amax)
+{
+ if (a amin) return amin;
+ else if (a amax) return amax;
+ else return a;
+}
+
+static inline int sat2 (int a, int amin, int amax)
+{
+ if (a amax) return amax;
+ else if (a amin) return amin;
+ else return a;
+}
+
+int u1 (int x)
+{
+ return sat1 (x, 0, 63);
+}
+
+int us1 (int x)
+{
+ return sat1 (x 5, 0, 63);
+}
+
+int s1 (int x)
+{
+ return sat1 (x, -64, 63);
+}
+
+int ss1 (int x)
+{
+ return sat1 (x 5, -64, 63);
+}
+
+int u2 (int x)
+{
+ return sat2 (x, 0, 63);
+}
+
+int us2 (int x)
+{
+ return sat2 (x 5, 0, 63);
+}
+
+int s2 (int x)
+{
+ return sat2 (x, -64, 63);
+}
+
+int ss2 (int x)
+{
+ return sat2 (x 5, -64, 63);
+}
+
+/* { dg-final { scan-assembler-times usat 4 } } */
+/* { dg-final { scan-assembler-times ssat 4 } } */
+
Index: gcc/config/arm/arm.c
===
--- gcc/config/arm/arm.c(revision 184553)
+++ gcc/config/arm/arm.c(working copy)
@@ -10041,6 +10041,42 @@
}
}
+/* Match pair of min/max operators that can be implemented via usat/ssat. */
+
+bool
+arm_sat_operator_match (rtx lo_bound, rtx hi_bound,
+ int *mask, bool *signed_sat)
+{
+ /* The high bound must be a power of two minus one. */
+ int log = exact_log2 (INTVAL (hi_bound) + 1);
+ if (log == -1)
+return false;
+
+ /* The low bound is either zero (for usat) or one less than the
+ negation of the high bound (for ssat). */
+ if (INTVAL (lo_bound) == 0)
+{
+ if (mask)
+*mask = log;
+ if (signed_sat)
+*signed_sat = false;
+
+ return true;
+}
+
+ if (INTVAL (lo_bound) == -INTVAL (hi_bound) - 1)
+{
+ if (mask)
+*mask = log + 1;
+ if (signed_sat)
+*signed_sat = true;
+
+ return true;
+}
+
+ return false;
+}
+
/* Return 1 if memory locations are adjacent. */
int
adjacent_mem_locations (rtx a, rtx b)
Index: gcc/config/arm/arm-fixed.md
===
--- gcc/config/arm/arm-fixed.md (revision 184553)
+++ gcc/config/arm/arm-fixed.md (working copy)
@@ -374,6 +374,8 @@
TARGET_32BIT arm_arch6
ssat%?\\t%0, #16, %2%S1
[(set_attr predicable yes)
+ (set_attr insn sat)
+ (set_attr shift 1)
(set_attr type alu_shift)])
(define_insn arm_usatsihi
@@ -381,4 +383,5 @@
(us_truncate:HI (match_operand:SI 1 s_register_operand)))]
TARGET_INT_SIMD
usat%?\\t%0, #16, %1
- [(set_attr predicable yes)])
+ [(set_attr predicable yes)
+ (set_attr insn sat)])
Index: gcc/config/arm/arm-protos.h
===
---