#define CASE_VECTOR_MODE Pmode
-/* See definition of clz pattern for rationale of value -1. */
-#define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) ((VALUE) = -1, 2)
+/* See definition of clz pattern for rationale of the value. */
+#define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \
+ ((VALUE) = GET_MODE_BITSIZE (MODE) - 1 - 32, 2)
/* Jumps are cheap on PRU. */
#define LOGICAL_OP_NON_SHORT_CIRCUIT 0
[(set_attr "type" "control")])
;; Count Leading Zeros implemented using LMBD.
-;; LMBD returns 32 if bit value is not present, and we subtract 31 to get CLZ.
-;; Hence we get a defined value -1 for CLZ_DEFINED_VALUE_AT_ZERO.
+;;
+;; LMBD returns 32 if bit value is not present, for any kind of input MODE.
+;; The LMBD's search result for a "1" bit is subtracted from the
+;; mode bit size minus one, in order to get CLZ.
+;;
+;; Hence for SImode we get a defined value -1 for CLZ_DEFINED_VALUE_AT_ZERO.
+;;
+;; The QImode and HImode defined values for zero inputs end up to be
+;; non-standard (-25 and -17). But this is considered acceptable in
+;; order to keep the CLZ expansion to only two instructions.
(define_expand "clz<mode>2"
[(set (match_operand:QISI 0 "register_operand")
(clz:QISI (match_operand:QISI 1 "register_operand")))]
rtx tmpval = gen_reg_rtx (<MODE>mode);
emit_insn (gen_pru_lmbd (<MODE>mode, tmpval, src, const1_rtx));
- emit_insn (gen_sub3_insn (dst, GEN_INT (31), tmpval));
+ int msb_bitn = GET_MODE_BITSIZE (<MODE>mode) - 1;
+ emit_insn (gen_sub3_insn (dst, GEN_INT (msb_bitn), tmpval));
DONE;
})
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-tree-ch" } */
+
+/* This test case is based on gcc.dg/tree-ssa/clz-char.c. */
+
+#define PREC (sizeof(short) * 8)
+
+int
+__attribute__ ((noinline, noclone))
+foo (unsigned short b) {
+ int c = 0;
+
+ if (b == 0)
+ return PREC;
+
+ while (!(b & (1 << (PREC - 1)))) {
+ b <<= 1;
+ c++;
+ }
+
+ return c;
+}
+
+/* { dg-final { scan-assembler "lmbd\\tr\[012\]\[0-9\]?.w\[0-2\], r\[012\]\[0-9\]?.w\[0-2\], 1" } } */
--- /dev/null
+/* { dg-do run } */
+/* { dg-options "-O2 -fno-tree-ch -fdump-tree-optimized" } */
+
+/* This test case is based on gcc.dg/tree-ssa/clz-char.c. */
+
+#define PREC (sizeof(short) * 8)
+
+int
+__attribute__ ((noinline, noclone))
+foo (unsigned short b) {
+ int c = 0;
+
+ if (b == 0)
+ return PREC;
+
+ while (!(b & (1 << (PREC - 1)))) {
+ b <<= 1;
+ c++;
+ }
+
+ return c;
+}
+
+int main()
+{
+ if (foo(0) != PREC)
+ __builtin_abort ();
+ if (foo(1 << (PREC - 1)) != 0)
+ __builtin_abort ();
+ if (foo(35) != PREC - 6)
+ __builtin_abort ();
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "__builtin_clz|\\.CLZ" 1 "optimized" } } */