@@ -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 */
@@ -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)
@@ -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")]
)
@@ -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:
new file mode 100644
@@ -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\\\)" } } */