aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Weigand <ulrich.weigand@linaro.org>2012-03-02 17:08:55 +0000
committerUlrich Weigand <uweigand@gcc.gnu.org>2012-03-02 17:08:55 +0000
commit5d216c70d980e3169b42e9734cf4bea1648ff8f0 (patch)
tree54e677187e260d409904d535adb7790396d04961
parent2b57045bfc0c746c5bbc952cf8a4da70548b5775 (diff)
downloadgcc-5d216c70d980e3169b42e9734cf4bea1648ff8f0.zip
gcc-5d216c70d980e3169b42e9734cf4bea1648ff8f0.tar.gz
gcc-5d216c70d980e3169b42e9734cf4bea1648ff8f0.tar.bz2
arm.c (arm_sat_operator_match): New function.
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. From-SVN: r184803
-rw-r--r--gcc/ChangeLog15
-rw-r--r--gcc/config/arm/arm-fixed.md5
-rw-r--r--gcc/config/arm/arm-protos.h1
-rw-r--r--gcc/config/arm/arm.c36
-rw-r--r--gcc/config/arm/arm.md56
-rw-r--r--gcc/config/arm/predicates.md8
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.target/arm/sat-1.c64
8 files changed, 184 insertions, 5 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d1b971b..fa44419 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,18 @@
+2012-03-02 Ulrich Weigand <ulrich.weigand@linaro.org>
+
+ * 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.
+
2012-03-02 Uros Bizjak <ubizjak@gmail.com>
PR target/46716
diff --git a/gcc/config/arm/arm-fixed.md b/gcc/config/arm/arm-fixed.md
index bd33ce2..920c262 100644
--- a/gcc/config/arm/arm-fixed.md
+++ b/gcc/config/arm/arm-fixed.md
@@ -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")])
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 1767128..900d09a 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -107,6 +107,7 @@ extern int tls_mentioned_p (rtx);
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);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 21816d6..dfba8e1 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -10037,6 +10037,42 @@ minmax_code (rtx x)
}
}
+/* 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)
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index b21d0d2..4f6d965 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -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
diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md
index fa2f695..dea3a96 100644
--- a/gcc/config/arm/predicates.md
+++ b/gcc/config/arm/predicates.md
@@ -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.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 108fd36..81dfa4f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2012-03-02 Ulrich Weigand <ulrich.weigand@linaro.org>
+
+ * gcc.target/arm/sat-1.c: New test.
+
2012-03-02 Uros Bizjak <ubizjak@gmail.com>
PR target/46716
diff --git a/gcc/testsuite/gcc.target/arm/sat-1.c b/gcc/testsuite/gcc.target/arm/sat-1.c
new file mode 100644
index 0000000..ebde56a4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/sat-1.c
@@ -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 } } */
+