]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[committed] Fix fr30-elf newlib build failure with late-combine
authorJeff Law <jlaw@ventanamicro.com>
Tue, 25 Jun 2024 17:22:01 +0000 (11:22 -0600)
committerJeff Law <jlaw@ventanamicro.com>
Tue, 25 Jun 2024 17:24:19 +0000 (11:24 -0600)
So the late combine work has exposed a latent bug in the fr30 port.

The fr30 "call" instruction is pc-relative with a *very* limited range, 12 bits
to be precise.

With such a limited range its hard to see how we could ever consistently use it
in the compiler, with the possible exception of self-recursion.  Even for a
call to a locally binding function -ffunction-sections and linker placement of
functions may separate the caller/callee.  Code generation seemed to be using
indirect forms pretty consistently, though the RTL would allow direct calls.

With late-combine some of those indirects would be optimized into direct calls.
This naturally led to out of range scenarios.

With the fr30 port slated for removal unless it gets updated to use LRA and the
fundamental problems using direct calls, I took the shortest path to keep
things working -- namely forcing all calls to be indirect.

Tested in my tester with no regressions (and fixes the newlib build failure
with late-combine enabled).    Pushed to the trunk.

gcc/
* config/fr30/constraints.md (Q): Remove unused constraint.
* config/fr30/predicates.md (call_operand): Remove unused predicate.
* config/fr30/fr30.md (call, vall_value): Turn into expanders and
force the call address into a register.
(*call, *call_value): Adjust to only allow indirect calls.  Adjust
output template accordingly.

gcc/config/fr30/constraints.md
gcc/config/fr30/fr30.md
gcc/config/fr30/predicates.md

index e4e2be1bfd900a6503391e21456e4078388ff9b8..1beee7cc3a27de07b7bebc6f710f5e6c0198458f 100644 (file)
@@ -63,9 +63,3 @@
   "An integer in the range -256 to 255."
   (and (match_code "const_int")
        (match_test "IN_RANGE (ival, -256, 255)")))
-
-;; Extra constraints.
-(define_constraint "Q"
-  "@internal"
-  (and (match_code "mem")
-       (match_code "symbol_ref" "0")))
index ecde60b455dafff1e8cf24f1d618753fb74c2a43..04f6d9090540449b8780ff8b38ed763c712f63d1 100644 (file)
 ;; `SImode', except it is normally a `const_int'); operand 2 is the number of
 ;; registers used as operands.
 
-(define_insn "call"
-  [(call (match_operand 0 "call_operand" "Qm")
+(define_expand "call"
+  [(parallel [(call (mem:QI (match_operand:SI  0 "register_operand" "r"))
+                    (match_operand 1 ""             "g"))
+              (clobber (reg:SI 17))])]
+  ""
+  " { operands[0] = force_reg (SImode, XEXP (operands[0], 0)); } ")
+
+(define_insn "*call"
+  [(call (mem:QI (match_operand:SI 0 "register_operand" "r"))
         (match_operand 1 ""             "g"))
    (clobber (reg:SI 17))]
   ""
-  "call%#\\t%0"
+  "call%#\\t@%0"
   [(set_attr "delay_type" "delayed")]
 )
 
 ;; increased by one).
 
 ;; Subroutines that return `BLKmode' objects use the `call' insn.
+(define_expand "call_value"
+  [(parallel [(set (match_operand 0 "register_operand"  "=r")
+                   (call (mem:QI (match_operand:SI 1 "register_operand" "r"))
+                         (match_operand 2 ""             "g")))
+              (clobber (reg:SI 17))])]
+  ""
+  " { operands[1] = force_reg (SImode, XEXP (operands[1], 0)); } ")
 
-(define_insn "call_value"
+(define_insn "*call_value"
   [(set (match_operand 0 "register_operand"  "=r")
-       (call (match_operand 1 "call_operand" "Qm")
+       (call (mem:QI (match_operand:SI 1 "register_operand" "r"))
              (match_operand 2 ""             "g")))
    (clobber (reg:SI 17))]
   ""
-  "call%#\\t%1"
+  "call%#\\t@%1"
   [(set_attr "delay_type" "delayed")]
 )
 
index f67c6097430908e868b4bfa0cdab60e59585a2cb..2f87a4c81b258bc64c9052d0b2a5cf4061edb3ff 100644 (file)
      && REGNO (op) <= 7);
 })
 
-;; Returns true if OP is suitable for use in a CALL insn.
-
-(define_predicate "call_operand"
-  (match_code "mem")
-{
-  return (GET_CODE (op) == MEM
-         && (GET_CODE (XEXP (op, 0)) == SYMBOL_REF
-             || GET_CODE (XEXP (op, 0)) == REG));
-})
-
 ;; Returns TRUE if OP is a valid operand of a DImode operation.
 
 (define_predicate "di_operand"