The patch optimizes code generation for comparisons of the form
X & C1 == C2 by converting them to (X | ~C1) == (C2 | ~C1).
C1 is a constant that requires li and addi to be loaded,
while ~C1 requires a single lui instruction.
As the values of C1 and C2 are not visible within
the equality expression, a plus pattern is matched instead.
2024-12-16 Oliver Kozul <[email protected]>
PR target/114087
gcc/ChangeLog:
* config/riscv/riscv.md (*lui_constraint<ANYI:mode>_and_to_or): New
pattern
gcc/testsuite/ChangeLog:
* gcc.target/riscv/pr114087-1.c: New test.
CONFIDENTIALITY: The contents of this e-mail are confidential and intended only
for the above addressee(s). If you are not the intended recipient, or the
person responsible for delivering it to the intended recipient, copying or
delivering it to anyone else or using it in any unauthorized manner is
prohibited and may be unlawful. If you receive this e-mail by mistake, please
notify the sender and the systems administrator at [email protected]
immediately.
---
gcc/config/riscv/riscv.md | 28 +++++++++++++++++++++
gcc/testsuite/gcc.target/riscv/pr114087-1.c | 16 ++++++++++++
2 files changed, 44 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/riscv/pr114087-1.c
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 3a4cd1d93a0..75b0947e597 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -858,6 +858,34 @@
[(set_attr "type" "arith")
(set_attr "mode" "SI")])
+;; Transform (X & C1) + C2 into (X | ~C1) - (-C2 | ~C1)
+;; Where C1 is not a LUI operand, but ~C1 is a LUI operand
+
+(define_insn_and_split "*lui_constraint<ANYI:mode>_and_to_or"
+ [(set (match_operand:ANYI 0 "register_operand" "=r")
+ (plus:ANYI (and:ANYI (match_operand:ANYI 1 "register_operand" "r")
+ (match_operand 2 "const_int_operand"))
+ (match_operand 3 "const_int_operand")))
+ (clobber (match_scratch:X 4 "=&r"))]
+ "LUI_OPERAND (~INTVAL (operands[2]))
+ && ((INTVAL (operands[2]) & (-INTVAL (operands[3])))
+ == (-INTVAL (operands[3])))
+ && riscv_const_insns (operands[3], false)
+ && (riscv_const_insns
+ (GEN_INT (~INTVAL (operands[2]) | -INTVAL (operands[3])), false)
+ <= riscv_const_insns (operands[3], false))"
+ "#"
+ "&& reload_completed"
+ [(set (match_dup 4) (match_dup 5))
+ (set (match_dup 0) (ior:X (match_dup 1) (match_dup 4)))
+ (set (match_dup 4) (match_dup 6))
+ (set (match_dup 0) (minus:X (match_dup 0) (match_dup 4)))]
+ {
+ operands[5] = GEN_INT (~INTVAL (operands[2]));
+ operands[6] = GEN_INT ((~INTVAL (operands[2])) | (-INTVAL (operands[3])));
+ }
+ [(set_attr "type" "arith")])
+
;;
;; ....................
;;
diff --git a/gcc/testsuite/gcc.target/riscv/pr114087-1.c
b/gcc/testsuite/gcc.target/riscv/pr114087-1.c
new file mode 100644
index 00000000000..9df02db6d5d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr114087-1.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target rv64 } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" } } */
+/* { dg-options "-march=rv64gc -mabi=lp64d" } */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+static uint32_t mask1 = 0x55555FFF;
+static uint32_t val1 = 0x14501DEF;
+
+bool pred1a(uint32_t x) {
+ return ((x & mask1) == val1);
+}
+
+/* { dg-final { scan-assembler {or\s*[a-x0-9]+,\s*[a-x0-9]+,\s*[a-x0-9]+} } }
*/
--
2.43.0