[(set_attr "type" "bitmanip")
(set_attr "mode" "<X:MODE>")])
+(define_insn_and_split "*<optab>_not_const<mode>"
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (bitmanip_bitwise:X (not:X (match_operand:X 1 "register_operand" "r"))
+ (match_operand:X 2 "const_arith_operand" "I")))
+ (clobber (match_scratch:X 3 "=&r"))]
+ "(TARGET_ZBB || TARGET_ZBKB) && !TARGET_ZCB
+ && !optimize_function_for_size_p (cfun)"
+ "#"
+ "&& reload_completed"
+ [(set (match_dup 3) (match_dup 2))
+ (set (match_dup 0) (bitmanip_bitwise:X (not:X (match_dup 1)) (match_dup 3)))])
+
;; '(a >= 0) ? b : 0' is emitted branchless (from if-conversion). Without a
;; bit of extra help for combine (i.e., the below split), we end up emitting
;; not/srai/and instead of combining the not into an andn.
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zbb -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-g" "-Oz" "-Os" } } */
+
+int foo1(int rs1)
+{
+ return 100 & ~rs1;
+}
+
+int foo2(int rs1)
+{
+ return 100 | ~rs1;
+}
+
+/* { dg-final { scan-assembler-times "andn\t" 1 } } */
+/* { dg-final { scan-assembler-times "orn\t" 1 } } */
+/* { dg-final { scan-assembler-times "li\t" 2 } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_zbb -mabi=ilp32" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-g" "-Oz" "-Os" } } */
+
+int foo1(int rs1)
+{
+ return 100 & ~rs1;
+}
+
+int foo2(int rs1)
+{
+ return 100 | ~rs1;
+}
+
+/* { dg-final { scan-assembler-times "andn\t" 1 } } */
+/* { dg-final { scan-assembler-times "orn\t" 1 } } */
+/* { dg-final { scan-assembler-times "li\t" 2 } } */