]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[PR122215, IRA]: Fix undefined behaviour of improve_allocation
authorVladimir N. Makarov <vmakarov@redhat.com>
Fri, 5 Dec 2025 19:21:38 +0000 (14:21 -0500)
committerVladimir N. Makarov <vmakarov@redhat.com>
Fri, 5 Dec 2025 19:29:08 +0000 (14:29 -0500)
Register filters are used in one loop of improve_allocation to ignore some
hard regs for cost calculation but it is missed in the subsequent loop
using the costs.  This results in usage of random (undefined) register costs
and in sporadic code generation for riscv32 which uses the filters.

gcc/ChangeLog:

PR rtl-optimization/122215
* ira-color.cc (improve_allocation): Use register filter for all
loop on hard regs.

gcc/testsuite/ChangeLog:

PR rtl-optimization/122215
* gcc.target/riscv/pr122215.c: New.
* lib/target-supports.exp (check_effective_target_valgrind): New.

gcc/ira-color.cc
gcc/testsuite/gcc.target/riscv/pr122215.c [new file with mode: 0644]
gcc/testsuite/lib/target-supports.exp

index 4ee2a65e29117e1aeaa71442b0a931f678e8fb4c..a051db27fbfa258e7bb229a7a6f3127150000cc5 100644 (file)
@@ -3369,6 +3369,9 @@ improve_allocation (void)
       for (j = 0; j < class_size; j++)
        {
          hregno = ira_class_hard_regs[aclass][j];
+         if (NUM_REGISTER_FILTERS
+             && !test_register_filters (ALLOCNO_REGISTER_FILTERS (a), hregno))
+           continue;
          if (check_hard_reg_p (a, hregno,
                                conflicting_regs, profitable_hard_regs)
              && min_cost > costs[hregno])
diff --git a/gcc/testsuite/gcc.target/riscv/pr122215.c b/gcc/testsuite/gcc.target/riscv/pr122215.c
new file mode 100644 (file)
index 0000000..cdc1ed7
--- /dev/null
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target valgrind } */
+/* { dg-additional-files "sparseset.supp" } */
+/* { dg-options "-wrapper valgrind,-q,--exit-on-first-error=yes,--error-exitcode=1,--suppressions=${srcdir}/sparseset.supp" } */
+
+typedef signed int int32_t;
+typedef signed long int int64_t;
+
+int64_t dual_reg_insn(int64_t x) {
+    int64_t res;
+    int64_t zero = 0;
+    asm ("some_custom_insn %0,%1,%2" : "=R" (res) : "R" (x), "R" (zero));
+    return res;
+}
+
+int32_t single_reg_insn(int32_t x) {
+    int32_t res;
+    int32_t zero = 0;
+    asm ("some_custom_insn %0,%1,%2" : "=r" (res) : "r" (x), "r" (zero));
+    return res;
+}
+
+int32_t single_reg_insn_explicit_zero(int32_t x) {
+    int32_t res;
+    asm ("some_custom_insn %0,%1,%2" : "=r" (res) : "r" (x), "r" (0));
+    return res;
+}
+
+int64_t dual_reg_insn2(int64_t x) {
+    int64_t res;
+    int64_t zero = 0;
+    asm ("some_custom_insn %0,%1,%2" : "=R" (res) : "R" (x), "R" (zero));
+    return res;
+    /* This function is IDENTICAL to dual_reg_insn,
+     * but for some obscure reason (alignment?)
+     * it decides to use sX registers instead of aX to store zero,
+     * resulting in a much larger code since it needs to use the stack.
+     * THIS ONLY HAPPENS SOMETIMES!
+     */
+}
+
+int64_t dual_reg_insn_explicit_zero(int64_t x) {
+    int64_t res;
+    asm ("some_custom_insn %0,%1,%2" : "=R" (res) : "R" (x), "R" (0LL));
+    return res;
+}
index 1df80d412da7d83c7d526ee2f0e9a5bd1e4bd492..6251f4e58f86fdceeca920f88034b0f6410c0dba 100644 (file)
@@ -14762,3 +14762,11 @@ proc check_effective_target_fentry { } {
        }
     }]
 }
+
+# Check if valgrind executable exists in PATH on host
+proc check_effective_target_valgrind { } {
+    if { [which valgrind] != 0 } {
+        return 1
+    }
+    return 0
+}