@@ -27,6 +27,12 @@
(ior (match_operand 0 "const_arith_operand")
(match_operand 0 "register_operand")))
+(define_predicate "arith_operand_or_mode_mask"
+ (ior (match_operand 0 "arith_operand")
+ (and (match_code "const_int")
+ (match_test "INTVAL (op) == GET_MODE_MASK (HImode)
+ || INTVAL (op) == GET_MODE_MASK (SImode)"))))
+
(define_predicate "lui_operand"
(and (match_code "const_int")
(match_test "LUI_OPERAND (INTVAL (op))")))
@@ -1342,9 +1342,46 @@
;; For RV64, we don't expose the SImode operations to the rtl expanders,
;; but SImode versions exist for combine.
+(define_expand "and<mode>3"
+ [(set (match_operand:X 0 "register_operand")
+ (and:X (match_operand:X 1 "register_operand")
+ (match_operand:X 2 "arith_operand_or_mode_mask")))]
+ ""
+{
+ if (CONST_INT_P (operands[2]))
+ {
+ enum machine_mode tmode = VOIDmode;
+ if (INTVAL (operands[2]) == GET_MODE_MASK (HImode))
+ tmode = HImode;
+ else if (INTVAL (operands[2]) == GET_MODE_MASK (SImode))
+ tmode = SImode;
+
+ if (tmode != VOIDmode)
+ {
+ rtx tmp = gen_lowpart (tmode, operands[1]);
+ emit_insn (gen_extend_insn (operands[0], tmp, <MODE>mode, tmode, 1));
+ DONE;
+ }
+ }
+ else
+ {
+ emit_move_insn (operands[0], gen_rtx_AND (<MODE>mode, operands[1], operands[2]));
+ DONE;
+ }
+})
+
+(define_insn "*and<mode>3"
+ [(set (match_operand:X 0 "register_operand" "=r,r")
+ (and:X (match_operand:X 1 "register_operand" "%r,r")
+ (match_operand:X 2 "arith_operand" " r,I")))]
+ ""
+ "and%i2\t%0,%1,%2"
+ [(set_attr "type" "logical")
+ (set_attr "mode" "<MODE>")])
+
(define_insn "<optab><mode>3"
[(set (match_operand:X 0 "register_operand" "=r,r")
- (any_bitwise:X (match_operand:X 1 "register_operand" "%r,r")
+ (any_or:X (match_operand:X 1 "register_operand" "%r,r")
(match_operand:X 2 "arith_operand" " r,I")))]
""
"<insn>%i2\t%0,%1,%2"
new file mode 100644
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zba_zbb -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+void
+foo(unsigned long a, unsigned long* ptr)
+{
+ ptr[0] = a & 0xffffffffUL;
+ ptr[1] &= 0xffffffffUL;
+}
+
+void
+foo2(unsigned long a, unsigned long* ptr)
+{
+ ptr[0] = a & 0xffff;
+ ptr[1] &= 0xffff;
+}
+
+void
+foo3(unsigned int a, unsigned int* ptr)
+{
+ ptr[0] = a & 0xffff;
+ ptr[1] &= 0xffff;
+}
+
+/* { dg-final { scan-assembler-times "zext.w" 1 } } */
+/* { dg-final { scan-assembler-times "zext.h" 2 } } */
+/* { dg-final { scan-assembler-times "lwu" 1 } } */
+/* { dg-final { scan-assembler-times "lhu" 2 } } */
+/* { dg-final { scan-assembler-not "and\t" } } */
new file mode 100644
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_zba_zbb -mabi=ilp32" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+void
+foo(unsigned long a, unsigned long* ptr)
+{
+ ptr[0] = a & 0xffffffffUL;
+ ptr[1] &= 0xffffffffUL;
+}
+
+void
+foo2(unsigned long a, unsigned long* ptr)
+{
+ ptr[0] = a & 0xffff;
+ ptr[1] &= 0xffff;
+}
+
+void
+foo3(unsigned int a, unsigned int* ptr)
+{
+ ptr[0] = a & 0xffff;
+ ptr[1] &= 0xffff;
+}
+
+/* { dg-final { scan-assembler-times "zext.h" 2 } } */
+/* { dg-final { scan-assembler-times "lhu" 2 } } */
+/* { dg-final { scan-assembler-not "and\t" } } */