diff mbox

[ARM] Generate usat/ssat instructions

Message ID 201202291250.q1TCoNTX016768@d06av02.portsmouth.uk.ibm.com
State New
Headers show

Commit Message

Ulrich Weigand Feb. 29, 2012, 12:50 p.m. UTC
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.

Comments

Ramana Radhakrishnan Feb. 29, 2012, 1:18 p.m. UTC | #1
>        ("SAT", "SATrev"): New code iterators.
>        ("SATlo", "SAThi"): New code iterator attributes.
>        ("*satsi_<SAT:code>"): New pattern.
>        ("*satsi_<SAT:code>_shift"): Likewise.

Iterators must go into iterators.md.

Ok with that change for 4.8 if no regressions.

Ramana
Ramana Radhakrishnan Feb. 29, 2012, 1:27 p.m. UTC | #2
On 29 February 2012 13:25, Ulrich Weigand <uweigand@de.ibm.com> wrote:
> Ramana Radhakrishnan wrote:
>> >    ("SAT", "SATrev"): New code iterators.
>> >    ("SATlo", "SAThi"): New code iterator attributes.
>> >    ("*satsi_<SAT:code>"): New pattern.
>> >    ("*satsi_<SAT:code>_shift"): Likewise.
>>
>> Iterators must go into iterators.md.
>
> Hmm, I left them in arm.md deliberately, because they apply very
> specifically only to those new patters; e.g. the SATlo / SAThi
> attributes give operand numbers in the pattern, and don't make
> sense for anything else ...

Might as well leave them there then as you say.

Ramana
diff mbox

Patch

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
===================================================================
--- gcc/config/arm/arm-protos.h	(revision 184553)
+++ gcc/config/arm/arm-protos.h	(working copy)
@@ -107,6 +107,7 @@ 
 extern int symbol_mentioned_p (rtx);
 extern int label_mentioned_p (rtx);
 extern RTX_CODE minmax_code (rtx);
+extern bool arm_sat_operator_match (rtx, rtx, int *, bool *);
 extern int adjacent_mem_locations (rtx, rtx);
 extern bool gen_ldm_seq (rtx *, int, bool);
 extern bool gen_stm_seq (rtx *, int);
Index: gcc/config/arm/predicates.md
===================================================================
--- gcc/config/arm/predicates.md	(revision 184553)
+++ gcc/config/arm/predicates.md	(working copy)
@@ -243,9 +243,11 @@ 
 
 ;; True for shift operators which can be used with saturation instructions.
 (define_special_predicate "sat_shift_operator"
-  (and (match_code "ashift,ashiftrt")
-       (match_test "GET_CODE (XEXP (op, 1)) == CONST_INT
-		    && ((unsigned HOST_WIDE_INT) INTVAL (XEXP (op, 1)) <= 32)")
+  (and (ior (and (match_code "mult")
+                 (match_test "power_of_two_operand (XEXP (op, 1), mode)"))
+            (and (match_code "ashift,ashiftrt")
+                 (match_test "GET_CODE (XEXP (op, 1)) == CONST_INT
+		              && ((unsigned HOST_WIDE_INT) INTVAL (XEXP (op, 1)) < 32)")))
        (match_test "mode == GET_MODE (op)")))
 
 ;; True for MULT, to identify which variant of shift_operator is in use.
Index: gcc/config/arm/arm.md
===================================================================
--- gcc/config/arm/arm.md	(revision 184553)
+++ gcc/config/arm/arm.md	(working copy)
@@ -283,7 +283,7 @@ 
 ;; scheduling information.
 
 (define_attr "insn"
-        "mov,mvn,smulxy,smlaxy,smlalxy,smulwy,smlawx,mul,muls,mla,mlas,umull,umulls,umlal,umlals,smull,smulls,smlal,smlals,smlawy,smuad,smuadx,smlad,smladx,smusd,smusdx,smlsd,smlsdx,smmul,smmulr,smmla,umaal,smlald,smlsld,clz,mrs,msr,xtab,sdiv,udiv,other"
+        "mov,mvn,smulxy,smlaxy,smlalxy,smulwy,smlawx,mul,muls,mla,mlas,umull,umulls,umlal,umlals,smull,smulls,smlal,smlals,smlawy,smuad,smuadx,smlad,smladx,smusd,smusdx,smlsd,smlsdx,smmul,smmulr,smmla,umaal,smlald,smlsld,clz,mrs,msr,xtab,sdiv,udiv,sat,other"
         (const_string "other"))
 
 ; TYPE attribute is used to detect floating point instructions which, if
@@ -3446,6 +3446,60 @@ 
 		      (const_int 12)))]
 )
 
+(define_code_iterator SAT [smin smax])
+(define_code_iterator SATrev [smin smax])
+(define_code_attr SATlo [(smin "1") (smax "2")])
+(define_code_attr SAThi [(smin "2") (smax "1")])
+
+(define_insn "*satsi_<SAT:code>"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+        (SAT:SI (SATrev:SI (match_operand:SI 3 "s_register_operand" "r")
+                           (match_operand:SI 1 "const_int_operand" "i"))
+                (match_operand:SI 2 "const_int_operand" "i")))]
+  "TARGET_32BIT && arm_arch6 && <SAT:CODE> != <SATrev:CODE>
+   && arm_sat_operator_match (operands[<SAT:SATlo>], operands[<SAT:SAThi>], NULL, NULL)"
+{
+  int mask;
+  bool signed_sat;
+  if (!arm_sat_operator_match (operands[<SAT:SATlo>], operands[<SAT:SAThi>],
+                               &mask, &signed_sat))
+    gcc_unreachable ();
+
+  operands[1] = GEN_INT (mask);
+  if (signed_sat)
+    return "ssat%?\t%0, %1, %3";
+  else
+    return "usat%?\t%0, %1, %3";
+}
+  [(set_attr "predicable" "yes")
+   (set_attr "insn" "sat")])
+
+(define_insn "*satsi_<SAT:code>_shift"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+        (SAT:SI (SATrev:SI (match_operator:SI 3 "sat_shift_operator"
+                             [(match_operand:SI 4 "s_register_operand" "r")
+                              (match_operand:SI 5 "const_int_operand" "i")])
+                           (match_operand:SI 1 "const_int_operand" "i"))
+                (match_operand:SI 2 "const_int_operand" "i")))]
+  "TARGET_32BIT && arm_arch6 && <SAT:CODE> != <SATrev:CODE>
+   && arm_sat_operator_match (operands[<SAT:SATlo>], operands[<SAT:SAThi>], NULL, NULL)"
+{
+  int mask;
+  bool signed_sat;
+  if (!arm_sat_operator_match (operands[<SAT:SATlo>], operands[<SAT:SAThi>],
+                               &mask, &signed_sat))
+    gcc_unreachable ();
+
+  operands[1] = GEN_INT (mask);
+  if (signed_sat)
+    return "ssat%?\t%0, %1, %4%S3";
+  else
+    return "usat%?\t%0, %1, %4%S3";
+}
+  [(set_attr "predicable" "yes")
+   (set_attr "insn" "sat")
+   (set_attr "shift" "3")
+   (set_attr "type" "alu_shift")])
 
 ;; Shift and rotation insns