[(set_attr "type" "slt")
(set_attr "mode" "<X:MODE>")])
+;; We can sometimes do better for unsigned comparisons against
+;; values where there's a run of 1s in the LSBs.
+;;
+(define_split
+ [(set (match_operand:X 0 "register_operand")
+ (gtu:X (match_operand:X 1 "register_operand")
+ (match_operand 2 "const_int_operand")))
+ (clobber (match_operand:X 3 "register_operand"))]
+ "exact_log2 (INTVAL (operands[2]) + 1) >= 0"
+ [(set (match_dup 3) (lshiftrt:X (match_dup 1) (match_dup 2)))
+ (set (match_dup 0) (ne:X (match_dup 3) (const_int 0)))]
+{ operands[2] = GEN_INT (exact_log2 (INTVAL (operands[2]) + 1)); })
+
+(define_split
+ [(set (match_operand:X 0 "register_operand")
+ (leu:X (match_operand:X 1 "register_operand")
+ (match_operand 2 "const_int_operand")))
+ (clobber (match_operand:X 3 "register_operand"))]
+ "exact_log2 (INTVAL (operands[2]) + 1) >= 0"
+ [(set (match_dup 3) (lshiftrt:X (match_dup 1) (match_dup 2)))
+ (set (match_dup 0) (eq:X (match_dup 3) (const_int 0)))]
+{ operands[2] = GEN_INT (exact_log2 (INTVAL (operands[2]) + 1)); })
+
+;; Alternate forms that are ultimately just sltiu
+(define_insn ""
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (eq:X (zero_extract:X (match_operand:X 1 "register_operand" "r")
+ (match_operand 2 "const_int_operand")
+ (match_operand 3 "const_int_operand"))
+ (const_int 0)))]
+ "(INTVAL (operands[3]) < 11
+ && INTVAL (operands[2]) + INTVAL (operands[3]) == BITS_PER_WORD)"
+{
+ operands[2] = GEN_INT (HOST_WIDE_INT_1U << INTVAL (operands[3]));
+ return "sltiu\t%0,%1,%2";
+}
+ [(set_attr "type" "slt")
+ (set_attr "mode" "<X:MODE>")])
+
+(define_insn ""
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (eq:X (lshiftrt:X (match_operand:X 1 "register_operand" "r")
+ (match_operand 2 "const_int_operand"))
+ (const_int 0)))]
+ "INTVAL (operands[2]) < 11"
+{
+ operands[2] = GEN_INT (HOST_WIDE_INT_1U << INTVAL (operands[2]));
+ return "sltiu\t%0,%1,%2";
+}
+ [(set_attr "type" "slt")
+ (set_attr "mode" "<X:MODE>")])
;;
;; ....................
;;
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-std=gnu23 -O2 -march=rv64gc -mabi=lp64d" { target rv64} } */
+/* { dg-options "-std=gnu23 -O2 -march=rv32gc -mabi=ilp32" { target rv32} } */
+
+/* We need to adjust the constant so this works for rv32 and rv64. */
+#if __riscv_xlen == 32
+#define ONE 1U
+#define TYPE unsigned int
+#define CTZ __builtin_ctz
+#else
+#define ONE 1UL
+#define TYPE unsigned long
+#define CTZ __builtin_ctzl
+#endif
+
+#define F1(C) _Bool func1_##C(TYPE x) { return x <= C; }
+#define F2(C) _Bool func2_##C(TYPE x) { return ((x >> CTZ (C+ONE)) == 0); }
+#define F3(C) _Bool func3_##C(TYPE x) { return ((x / (C+ONE)) == 0); }
+
+#define F(C) F1(C) F2(C) F3(C)
+
+F (0x1U)
+F (0x3U)
+F (0x7U)
+F (0xfU)
+F (0x1fU)
+F (0x3fU)
+F (0x7fU)
+F (0xffU)
+F (0x1ffU)
+F (0x3ffU)
+F (0x7ffU)
+F (0xfffU)
+F (0x1fffU)
+F (0x3fffU)
+F (0x7fffU)
+F (0xffffU)
+F (0x1ffffU)
+F (0x3ffffU)
+F (0x7ffffU)
+F (0xfffffU)
+F (0x1fffffU)
+F (0x3fffffU)
+F (0x7fffffU)
+F (0xffffffU)
+F (0x1ffffffU)
+F (0x3ffffffU)
+F (0x7ffffffU)
+F (0xfffffffU)
+F (0x1fffffffU)
+F (0x3fffffffU)
+F (0x7fffffffU)
+#if __riscv_xlen == 64
+F (0xffffffffUL)
+F (0x1ffffffffUL)
+F (0x3ffffffffUL)
+F (0x7ffffffffUL)
+F (0xfffffffffUL)
+F (0x1fffffffffUL)
+F (0x3fffffffffUL)
+F (0x7fffffffffUL)
+F (0xffffffffffUL)
+F (0x1ffffffffffUL)
+F (0x3ffffffffffUL)
+F (0x7ffffffffffUL)
+F (0xfffffffffffUL)
+F (0x1fffffffffffUL)
+F (0x3fffffffffffUL)
+F (0x7fffffffffffUL)
+F (0xffffffffffffUL)
+F (0x1ffffffffffffUL)
+F (0x3ffffffffffffUL)
+F (0x7ffffffffffffUL)
+F (0xfffffffffffffUL)
+F (0x1fffffffffffffUL)
+F (0x3fffffffffffffUL)
+F (0x7fffffffffffffUL)
+F (0xffffffffffffffUL)
+F (0x1ffffffffffffffUL)
+F (0x3ffffffffffffffUL)
+F (0x7ffffffffffffffUL)
+F (0xfffffffffffffffUL)
+F (0x1fffffffffffffffUL)
+F (0x3fffffffffffffffUL)
+F (0x7fffffffffffffffUL)
+#endif
+
+/* These represent current state. They are not optimal as some of the cases
+ where we shift are better implemented by loading 2^n constant and using
+ sltu as the lui has no incoming data dependencies. */
+/* { dg-final { scan-assembler-times "\tsltiu" 30 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "\tnot" 3 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "\tsrli" 121 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "\tsltu" 38 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "\tseqz" 118 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "\tli" 38 { target { rv64 } } } } */
+
+/* { dg-final { scan-assembler-times "\tsltiu" 30 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "\tnot" 3 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "\tsrli" 25 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "\tsltu" 38 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "\tseqz" 22 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "\tli" 38 { target { rv32 } } } } */