[2/5] LoongArch: Use explicit relocs for GOT access when -mexplicit-relocs=auto and LTO during a final link with linker plugin

Message ID 20231019140300.50323-3-xry111@xry111.site
State Unresolved
Headers
Series LoongArch: Better balance between relaxation and scheduling |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Xi Ruoyao Oct. 19, 2023, 2:02 p.m. UTC
  If we are performing LTO for a final link and linker plugin is enabled,
then we are sure any GOT access may resolve to a symbol out of the link
unit (otherwise the linker plugin will tell us the symbol should be
resolved locally and we'll use PC-relative access instead).

Produce machine instructions with explicit relocs instead of la.global
for better scheduling.

gcc/ChangeLog:

	* config/loongarch/loongarch-protos.h
	(loongarch_explicit_relocs_p): Declare new function.
	* config/loongarch/loongarch.cc (loongarch_explicit_relocs_p):
	Implement.
	(loongarch_symbol_insns): Call loongarch_explicit_relocs_p for
	SYMBOL_GOT_DISP, instead of using TARGET_EXPLICIT_RELOCS.
	(loongarch_split_symbol): Call loongarch_explicit_relocs_p for
	deciding if return early, instead of using
	TARGET_EXPLICIT_RELOCS.
	(loongarch_output_move): CAll loongarch_explicit_relocs_p
	instead of using TARGET_EXPLICIT_RELOCS.
	* config/loongarch/loongarch.md (*low<mode>): Remove
	TARGET_EXPLICIT_RELOCS from insn condition.
	(@ld_from_got<mode>): Likewise.
	* config/loongarch/predicates.md (move_operand): Call
	loongarch_explicit_relocs_p instead of using
	TARGET_EXPLICIT_RELOCS.

gcc/testsuite/ChangeLog:

	* gcc.target/loongarch/explicit-relocs-auto-lto.c: New test.
---
 gcc/config/loongarch/loongarch-protos.h       |  1 +
 gcc/config/loongarch/loongarch.cc             | 34 +++++++++++++++----
 gcc/config/loongarch/loongarch.md             |  4 +--
 gcc/config/loongarch/predicates.md            |  8 ++---
 .../loongarch/explicit-relocs-auto-lto.c      | 26 ++++++++++++++
 5 files changed, 59 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/loongarch/explicit-relocs-auto-lto.c
  

Comments

chenglulu Oct. 21, 2023, 7:32 a.m. UTC | #1
/* snip */

> +/* If -mexplicit-relocs=auto, we use machine operations with reloc hints
> +   for cases where the linker is unable to relax so we can schedule the
> +   machine operations, otherwise use an assembler pseudo-op so the
> +   assembler will generate R_LARCH_RELAX.  */
> +
> +bool
> +loongarch_explicit_relocs_p (enum loongarch_symbol_type type)
> +{
> +  if (la_opt_explicit_relocs != EXPLICIT_RELOCS_AUTO)
> +    return la_opt_explicit_relocs == EXPLICIT_RELOCS_ALWAYS;
> +
> +  /* If we are performing LTO for a final link, and we have the linker
> +     plugin so we know the resolution of the symbols, then all GOT
> +     references are binding to external symbols or preemptable symbols.
> +     So the linker cannot relax them.  */
> +  return (in_lto_p
> +	  && !flag_incremental_link

I don’t quite understand this condition "!flag_incremental_link". Can 
you explain it? Others LGTM.

Thanks.

> +	  && HAVE_LTO_PLUGIN == 2
> +	  && (!global_options_set.x_flag_use_linker_plugin
> +	      || global_options.x_flag_use_linker_plugin)
> +	  && type == SYMBOL_GOT_DISP);
> +}
> +
  
Xi Ruoyao Oct. 21, 2023, 8:42 a.m. UTC | #2
On Sat, 2023-10-21 at 15:32 +0800, chenglulu wrote:
> > +  /* If we are performing LTO for a final link, and we have the linker
> > +     plugin so we know the resolution of the symbols, then all GOT
> > +     references are binding to external symbols or preemptable symbols.
> > +     So the linker cannot relax them.  */
> > +  return (in_lto_p
> > +	  && !flag_incremental_link
> 
> I don’t quite understand this condition "!flag_incremental_link". Can 
> you explain it? Others LGTM.
> 
> Thanks.

If we have two (or several) .o files containing LTO bytecode, GCC
supports "LTO incremental linking" with:

gcc a.o b.o -o ab.o -O2 -flto -flinker-output=nolto-rel

The resulted ab.o will include data and code in a.o and b.o, but it
contains machine code instead of LTO bytecode.  Now if ab.o refers to an
external symbol c, the linker may relax "la.global c" to "la.local c"
(if ab.o is linked together with another file c.o which contains the
definition of c) or not.  As we cannot exclude the possibility of a
relaxation on la.global for incremental linking, just emit la.global and
let the linker to do the correct thing.
  
chenglulu Oct. 23, 2023, 12:56 a.m. UTC | #3
在 2023/10/21 下午4:42, Xi Ruoyao 写道:
> On Sat, 2023-10-21 at 15:32 +0800, chenglulu wrote:
>>> +  /* If we are performing LTO for a final link, and we have the linker
>>> +     plugin so we know the resolution of the symbols, then all GOT
>>> +     references are binding to external symbols or preemptable symbols.
>>> +     So the linker cannot relax them.  */
>>> +  return (in_lto_p
>>> +	  && !flag_incremental_link
>> I don’t quite understand this condition "!flag_incremental_link". Can
>> you explain it? Others LGTM.
>>
>> Thanks.
> If we have two (or several) .o files containing LTO bytecode, GCC
> supports "LTO incremental linking" with:
>
> gcc a.o b.o -o ab.o -O2 -flto -flinker-output=nolto-rel
>
> The resulted ab.o will include data and code in a.o and b.o, but it
> contains machine code instead of LTO bytecode.  Now if ab.o refers to an
> external symbol c, the linker may relax "la.global c" to "la.local c"
> (if ab.o is linked together with another file c.o which contains the
> definition of c) or not.  As we cannot exclude the possibility of a
> relaxation on la.global for incremental linking, just emit la.global and
> let the linker to do the correct thing.
>
I have no problem, thank you!
  

Patch

diff --git a/gcc/config/loongarch/loongarch-protos.h b/gcc/config/loongarch/loongarch-protos.h
index 72ae9918b09..cb8fc36b086 100644
--- a/gcc/config/loongarch/loongarch-protos.h
+++ b/gcc/config/loongarch/loongarch-protos.h
@@ -220,4 +220,5 @@  extern rtx loongarch_gen_const_int_vector_shuffle (machine_mode, int);
 extern tree loongarch_build_builtin_va_list (void);
 
 extern rtx loongarch_build_signbit_mask (machine_mode, bool, bool);
+extern bool loongarch_explicit_relocs_p (enum loongarch_symbol_type);
 #endif /* ! GCC_LOONGARCH_PROTOS_H */
diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc
index 5df8b12ed92..c12d77ea144 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -1925,6 +1925,29 @@  loongarch_symbolic_constant_p (rtx x, enum loongarch_symbol_type *symbol_type)
   gcc_unreachable ();
 }
 
+/* If -mexplicit-relocs=auto, we use machine operations with reloc hints
+   for cases where the linker is unable to relax so we can schedule the
+   machine operations, otherwise use an assembler pseudo-op so the
+   assembler will generate R_LARCH_RELAX.  */
+
+bool
+loongarch_explicit_relocs_p (enum loongarch_symbol_type type)
+{
+  if (la_opt_explicit_relocs != EXPLICIT_RELOCS_AUTO)
+    return la_opt_explicit_relocs == EXPLICIT_RELOCS_ALWAYS;
+
+  /* If we are performing LTO for a final link, and we have the linker
+     plugin so we know the resolution of the symbols, then all GOT
+     references are binding to external symbols or preemptable symbols.
+     So the linker cannot relax them.  */
+  return (in_lto_p
+	  && !flag_incremental_link
+	  && HAVE_LTO_PLUGIN == 2
+	  && (!global_options_set.x_flag_use_linker_plugin
+	      || global_options.x_flag_use_linker_plugin)
+	  && type == SYMBOL_GOT_DISP);
+}
+
 /* Returns the number of instructions necessary to reference a symbol.  */
 
 static int
@@ -1940,7 +1963,7 @@  loongarch_symbol_insns (enum loongarch_symbol_type type, machine_mode mode)
     case SYMBOL_GOT_DISP:
       /* The constant will have to be loaded from the GOT before it
 	 is used in an address.  */
-      if (!TARGET_EXPLICIT_RELOCS && mode != MAX_MACHINE_MODE)
+      if (!loongarch_explicit_relocs_p (type) && mode != MAX_MACHINE_MODE)
 	return 0;
 
       return 3;
@@ -3038,7 +3061,7 @@  loongarch_symbol_extreme_p (enum loongarch_symbol_type type)
    If so, and if LOW_OUT is nonnull, emit the high part and store the
    low part in *LOW_OUT.  Leave *LOW_OUT unchanged otherwise.
 
-   Return false if build with '-mno-explicit-relocs'.
+   Return false if build with '-mexplicit-relocs=none'.
 
    TEMP is as for loongarch_force_temporary and is used to load the high
    part into a register.
@@ -3052,12 +3075,9 @@  loongarch_split_symbol (rtx temp, rtx addr, machine_mode mode, rtx *low_out)
 {
   enum loongarch_symbol_type symbol_type;
 
-  /* If build with '-mno-explicit-relocs', don't split symbol.  */
-  if (!TARGET_EXPLICIT_RELOCS)
-    return false;
-
   if ((GET_CODE (addr) == HIGH && mode == MAX_MACHINE_MODE)
       || !loongarch_symbolic_constant_p (addr, &symbol_type)
+      || !loongarch_explicit_relocs_p (symbol_type)
       || loongarch_symbol_insns (symbol_type, mode) == 0
       || !loongarch_split_symbol_type (symbol_type))
     return false;
@@ -4797,7 +4817,7 @@  loongarch_output_move (rtx dest, rtx src)
 	}
     }
 
-  if (!TARGET_EXPLICIT_RELOCS
+  if (!loongarch_explicit_relocs_p (loongarch_classify_symbol (src))
       && dest_code == REG && symbolic_operand (src, VOIDmode))
     {
       if (loongarch_classify_symbol (src) == SYMBOL_PCREL)
diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md
index 365b4127e31..bec73f1bc91 100644
--- a/gcc/config/loongarch/loongarch.md
+++ b/gcc/config/loongarch/loongarch.md
@@ -2247,7 +2247,7 @@  (define_insn "*low<mode>"
   [(set (match_operand:P 0 "register_operand" "=r")
  (lo_sum:P (match_operand:P 1 "register_operand" " r")
      (match_operand:P 2 "symbolic_operand" "")))]
-  "TARGET_EXPLICIT_RELOCS"
+  ""
   "addi.<d>\t%0,%1,%L2"
   [(set_attr "type" "arith")
    (set_attr "mode" "<MODE>")])
@@ -2275,7 +2275,7 @@  (define_insn "@ld_from_got<mode>"
 				(match_operand:P 1 "register_operand" "r")
 				(match_operand:P 2 "symbolic_operand")))]
 	UNSPEC_LOAD_FROM_GOT))]
-  "TARGET_EXPLICIT_RELOCS"
+  ""
   "ld.<d>\t%0,%1,%L2"
   [(set_attr "type" "move")]
 )
diff --git a/gcc/config/loongarch/predicates.md b/gcc/config/loongarch/predicates.md
index 499518b82ba..359878f5bcf 100644
--- a/gcc/config/loongarch/predicates.md
+++ b/gcc/config/loongarch/predicates.md
@@ -541,16 +541,14 @@  (define_predicate "move_operand"
     case SYMBOL_REF:
     case LABEL_REF:
       return (loongarch_symbolic_constant_p (op, &symbol_type)
-	      && (!TARGET_EXPLICIT_RELOCS
+	      && (!loongarch_explicit_relocs_p (symbol_type)
 		  || !loongarch_split_symbol_type (symbol_type)));
 
     case HIGH:
-      /* '-mno-explicit-relocs' don't generate high/low pairs.  */
-      if (!TARGET_EXPLICIT_RELOCS)
-	return false;
-
       op = XEXP (op, 0);
+
       return (loongarch_symbolic_constant_p (op, &symbol_type)
+	      && loongarch_explicit_relocs_p (symbol_type)
 	      && loongarch_split_symbol_type (symbol_type));
 
     default:
diff --git a/gcc/testsuite/gcc.target/loongarch/explicit-relocs-auto-lto.c b/gcc/testsuite/gcc.target/loongarch/explicit-relocs-auto-lto.c
new file mode 100644
index 00000000000..f53b5468924
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/explicit-relocs-auto-lto.c
@@ -0,0 +1,26 @@ 
+/* { dg-do link } */
+/* { dg-require-effective-target lto } */
+/* { dg-require-linker-plugin "" } */
+/* { dg-options "-fpic -shared -O2 --save-temps -mexplicit-relocs=auto -flto -fuse-linker-plugin -flto-partition=one" } */
+
+int pcrel __attribute__ ((visibility ("hidden")));
+int got __attribute__ ((visibility ("default")));
+
+int
+*addr_pcrel (void)
+{
+  return &pcrel;
+}
+
+int
+*addr_got (void)
+{
+  return &got;
+}
+
+/* With linker plugin we should use la.local (it can be relaxed to pcaddi),
+   but not la.global (we are pretty sure the linker cannot relax la.global
+   got).  */
+/* { dg-final { scan-lto-assembler "la.local.*pcrel" } } */
+/* { dg-final { scan-lto-assembler "pcalau12i.*%got_pc_hi20\\\(got\\\)" } } */
+/* { dg-final { scan-lto-assembler "ld.*%got_pc_lo12\\\(got\\\)" } } */