aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/loongarch/loongarch.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/loongarch/loongarch.cc')
-rw-r--r--gcc/config/loongarch/loongarch.cc123
1 files changed, 97 insertions, 26 deletions
diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc
index 207ac27..16fd4ac 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -2461,44 +2461,96 @@ loongarch_call_tls_get_addr (rtx sym, enum loongarch_symbol_type type, rtx v0)
}
if (flag_plt)
- insn = emit_call_insn (gen_call_value_internal (v0,
- loongarch_tls_symbol,
- const0_rtx));
- else
{
- rtx dest = gen_reg_rtx (Pmode);
-
- if (TARGET_CMODEL_EXTREME)
+ switch (la_opt_cmodel)
{
- gcc_assert (TARGET_EXPLICIT_RELOCS);
+ case CMODEL_NORMAL:
+ insn = emit_call_insn (gen_call_value_internal (v0,
+ loongarch_tls_symbol,
+ const0_rtx));
+ break;
- rtx tmp1 = gen_reg_rtx (Pmode);
- rtx high = gen_reg_rtx (Pmode);
+ case CMODEL_MEDIUM:
+ {
+ rtx reg = gen_reg_rtx (Pmode);
+ if (TARGET_EXPLICIT_RELOCS)
+ {
+ emit_insn (gen_pcalau12i (Pmode, reg, loongarch_tls_symbol));
+ rtx call = gen_call_value_internal_1 (Pmode, v0, reg,
+ loongarch_tls_symbol,
+ const0_rtx);
+ insn = emit_call_insn (call);
+ }
+ else
+ {
+ emit_move_insn (reg, loongarch_tls_symbol);
+ insn = emit_call_insn (gen_call_value_internal (v0,
+ reg,
+ const0_rtx));
+ }
+ break;
+ }
- loongarch_emit_move (high,
- gen_rtx_HIGH (Pmode, loongarch_tls_symbol));
- loongarch_emit_move (tmp1, gen_rtx_LO_SUM (Pmode,
- gen_rtx_REG (Pmode, 0),
- loongarch_tls_symbol));
- emit_insn (gen_lui_h_lo20 (tmp1, tmp1, loongarch_tls_symbol));
- emit_insn (gen_lui_h_hi12 (tmp1, tmp1, loongarch_tls_symbol));
- loongarch_emit_move (dest,
- gen_rtx_MEM (Pmode,
- gen_rtx_PLUS (Pmode, high, tmp1)));
+ /* code model extreme not support plt. */
+ case CMODEL_EXTREME:
+ case CMODEL_LARGE:
+ case CMODEL_TINY:
+ case CMODEL_TINY_STATIC:
+ default:
+ gcc_unreachable ();
}
- else
+ }
+ else
+ {
+ rtx dest = gen_reg_rtx (Pmode);
+
+ switch (la_opt_cmodel)
{
- if (TARGET_EXPLICIT_RELOCS)
+ case CMODEL_NORMAL:
+ case CMODEL_MEDIUM:
+ {
+ if (TARGET_EXPLICIT_RELOCS)
+ {
+ rtx high = gen_reg_rtx (Pmode);
+ loongarch_emit_move (high,
+ gen_rtx_HIGH (Pmode,
+ loongarch_tls_symbol));
+ emit_insn (gen_ld_from_got (Pmode, dest, high,
+ loongarch_tls_symbol));
+ }
+ else
+ loongarch_emit_move (dest, loongarch_tls_symbol);
+ break;
+ }
+
+ case CMODEL_EXTREME:
{
+ gcc_assert (TARGET_EXPLICIT_RELOCS);
+
+ rtx tmp1 = gen_reg_rtx (Pmode);
rtx high = gen_reg_rtx (Pmode);
+
loongarch_emit_move (high,
gen_rtx_HIGH (Pmode, loongarch_tls_symbol));
- emit_insn (gen_ld_from_got (Pmode, dest, high,
- loongarch_tls_symbol));
+ loongarch_emit_move (tmp1, gen_rtx_LO_SUM (Pmode,
+ gen_rtx_REG (Pmode, 0),
+ loongarch_tls_symbol));
+ emit_insn (gen_lui_h_lo20 (tmp1, tmp1, loongarch_tls_symbol));
+ emit_insn (gen_lui_h_hi12 (tmp1, tmp1, loongarch_tls_symbol));
+ loongarch_emit_move (dest,
+ gen_rtx_MEM (Pmode,
+ gen_rtx_PLUS (Pmode,
+ high, tmp1)));
}
- else
- loongarch_emit_move (dest, loongarch_tls_symbol);
+ break;
+
+ case CMODEL_LARGE:
+ case CMODEL_TINY:
+ case CMODEL_TINY_STATIC:
+ default:
+ gcc_unreachable ();
}
+
insn = emit_call_insn (gen_call_value_internal (v0, dest, const0_rtx));
}
@@ -2618,6 +2670,24 @@ loongarch_legitimize_call_address (rtx addr)
loongarch_emit_move (reg, addr);
return reg;
}
+
+ enum loongarch_symbol_type symbol_type = loongarch_classify_symbol (addr);
+
+ /* Split function call insn 'bl sym' or 'bl %plt(sym)' to :
+ pcalau12i $rd, %pc_hi20(sym)
+ jr $rd, %pc_lo12(sym). */
+
+ if (TARGET_CMODEL_MEDIUM
+ && TARGET_EXPLICIT_RELOCS
+ && (SYMBOL_REF_P (addr) || LABEL_REF_P (addr))
+ && (symbol_type == SYMBOL_PCREL
+ || (symbol_type == SYMBOL_GOT_DISP && flag_plt)))
+ {
+ rtx reg = gen_reg_rtx (Pmode);
+ emit_insn (gen_pcalau12i (Pmode, reg, addr));
+ return gen_rtx_LO_SUM (Pmode, reg, addr);
+ }
+
return addr;
}
@@ -5996,6 +6066,7 @@ loongarch_option_override_internal (struct gcc_options *opts)
break;
case CMODEL_TINY_STATIC:
+ case CMODEL_MEDIUM:
case CMODEL_NORMAL:
case CMODEL_TINY:
case CMODEL_LARGE: