diff options
-rw-r--r-- | gcc/ChangeLog | 15 | ||||
-rw-r--r-- | gcc/config/arm/arm-fixed.md | 5 | ||||
-rw-r--r-- | gcc/config/arm/arm-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/arm/arm.c | 36 | ||||
-rw-r--r-- | gcc/config/arm/arm.md | 56 | ||||
-rw-r--r-- | gcc/config/arm/predicates.md | 8 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/arm/sat-1.c | 64 |
8 files changed, 184 insertions, 5 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d1b971bed3a..fa444196ad0 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 bd33ce28b38..920c262b425 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 1767128c8d5..900d09a09a3 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 21816d65dcb..dfba8e15fc1 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 b21d0d2539c..4f6d96575b9 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 fa2f695356b..dea3a96368e 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 108fd363455..81dfa4f90f8 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 00000000000..ebde56a4554 --- /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 } } */ + |