[v1] LoongArch: Add new code model 'emdium'.
Commit Message
The function jump instruction in normal mode is 'bl',
so the scope of the function jump is +-128MB.
Now we've added support for 'medium' mode, this mode is
to complete the function jump through two instructions:
pcalau12i + jirl
So in this mode the function jump range is increased to +-2GB.
Compared with 'normal' mode, 'medium' mode only affects the
jump range of functions.
gcc/ChangeLog:
* config/loongarch/genopts/loongarch-strings: Support code model medium.
* config/loongarch/genopts/loongarch.opt.in: Likewise.
* config/loongarch/loongarch-def.c: Likewise.
* config/loongarch/loongarch-def.h (CMODEL_LARGE): Likewise.
(CMODEL_EXTREME): Likewise.
(N_CMODEL_TYPES): Likewise.
(CMODEL_MEDIUM): Likewise.
* config/loongarch/loongarch-opts.cc: Likewise.
* config/loongarch/loongarch-opts.h (TARGET_CMODEL_MEDIUM): Likewise.
* config/loongarch/loongarch-str.h (STR_CMODEL_MEDIUM): Likewise.
* config/loongarch/loongarch.cc (loongarch_call_tls_get_addr):
Tls symbol Loading support medium mode.
(loongarch_legitimize_call_address): When medium mode, make a symbolic
jump with two instructions.
(loongarch_option_override_internal): Support medium.
* config/loongarch/loongarch.md (@pcalau12i<mode>): New template.
(@sibcall_internal_1<mode>): New function call templates added to support
medium mode.
(@sibcall_value_internal_1<mode>): Likewise.
(@sibcall_value_multiple_internal_1<mode>): Likewise.
(@call_internal_1<mode>): Likewise.
(@call_value_internal_1<mode>): Likewise.
(@call_value_multiple_internal_1<mode>): Likewise.
* config/loongarch/loongarch.opt: Support medium.
* config/loongarch/predicates.md: Add processing about medium mode.
* doc/invoke.texi: Document for '-mcmodel=medium'.
gcc/testsuite/ChangeLog:
* gcc.target/loongarch/func-call-medium-1.c: New test.
* gcc.target/loongarch/func-call-medium-2.c: New test.
* gcc.target/loongarch/func-call-medium-3.c: New test.
* gcc.target/loongarch/func-call-medium-4.c: New test.
* gcc.target/loongarch/func-call-medium-5.c: New test.
* gcc.target/loongarch/func-call-medium-6.c: New test.
* gcc.target/loongarch/func-call-medium-7.c: New test.
* gcc.target/loongarch/func-call-medium-8.c: New test.
* gcc.target/loongarch/tls-gd-noplt.c: Add compile parameter '-mexplicit-relocs'.
---
.../loongarch/genopts/loongarch-strings | 1 +
gcc/config/loongarch/genopts/loongarch.opt.in | 3 +
gcc/config/loongarch/loongarch-def.c | 1 +
gcc/config/loongarch/loongarch-def.h | 7 +-
gcc/config/loongarch/loongarch-opts.cc | 15 ++-
gcc/config/loongarch/loongarch-opts.h | 1 +
gcc/config/loongarch/loongarch-str.h | 1 +
gcc/config/loongarch/loongarch.cc | 123 +++++++++++++----
gcc/config/loongarch/loongarch.md | 125 +++++++++++++++++-
gcc/config/loongarch/loongarch.opt | 3 +
gcc/config/loongarch/predicates.md | 15 ++-
gcc/doc/invoke.texi | 3 +
.../gcc.target/loongarch/func-call-medium-1.c | 41 ++++++
.../gcc.target/loongarch/func-call-medium-2.c | 41 ++++++
.../gcc.target/loongarch/func-call-medium-3.c | 41 ++++++
.../gcc.target/loongarch/func-call-medium-4.c | 41 ++++++
.../gcc.target/loongarch/func-call-medium-5.c | 42 ++++++
.../gcc.target/loongarch/func-call-medium-6.c | 42 ++++++
.../gcc.target/loongarch/func-call-medium-7.c | 43 ++++++
.../gcc.target/loongarch/func-call-medium-8.c | 42 ++++++
.../gcc.target/loongarch/tls-gd-noplt.c | 4 +-
21 files changed, 595 insertions(+), 40 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-1.c
create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-2.c
create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-3.c
create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-4.c
create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-5.c
create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-6.c
create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-7.c
create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-8.c
Comments
Hi, Lulu,
I think there is a typo in your subject line.
Huacai
On Sat, Aug 20, 2022 at 5:05 PM Lulu Cheng <chenglulu@loongson.cn> wrote:
>
> The function jump instruction in normal mode is 'bl',
> so the scope of the function jump is +-128MB.
>
> Now we've added support for 'medium' mode, this mode is
> to complete the function jump through two instructions:
> pcalau12i + jirl
> So in this mode the function jump range is increased to +-2GB.
>
> Compared with 'normal' mode, 'medium' mode only affects the
> jump range of functions.
>
> gcc/ChangeLog:
>
> * config/loongarch/genopts/loongarch-strings: Support code model medium.
> * config/loongarch/genopts/loongarch.opt.in: Likewise.
> * config/loongarch/loongarch-def.c: Likewise.
> * config/loongarch/loongarch-def.h (CMODEL_LARGE): Likewise.
> (CMODEL_EXTREME): Likewise.
> (N_CMODEL_TYPES): Likewise.
> (CMODEL_MEDIUM): Likewise.
> * config/loongarch/loongarch-opts.cc: Likewise.
> * config/loongarch/loongarch-opts.h (TARGET_CMODEL_MEDIUM): Likewise.
> * config/loongarch/loongarch-str.h (STR_CMODEL_MEDIUM): Likewise.
> * config/loongarch/loongarch.cc (loongarch_call_tls_get_addr):
> Tls symbol Loading support medium mode.
> (loongarch_legitimize_call_address): When medium mode, make a symbolic
> jump with two instructions.
> (loongarch_option_override_internal): Support medium.
> * config/loongarch/loongarch.md (@pcalau12i<mode>): New template.
> (@sibcall_internal_1<mode>): New function call templates added to support
> medium mode.
> (@sibcall_value_internal_1<mode>): Likewise.
> (@sibcall_value_multiple_internal_1<mode>): Likewise.
> (@call_internal_1<mode>): Likewise.
> (@call_value_internal_1<mode>): Likewise.
> (@call_value_multiple_internal_1<mode>): Likewise.
> * config/loongarch/loongarch.opt: Support medium.
> * config/loongarch/predicates.md: Add processing about medium mode.
> * doc/invoke.texi: Document for '-mcmodel=medium'.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.target/loongarch/func-call-medium-1.c: New test.
> * gcc.target/loongarch/func-call-medium-2.c: New test.
> * gcc.target/loongarch/func-call-medium-3.c: New test.
> * gcc.target/loongarch/func-call-medium-4.c: New test.
> * gcc.target/loongarch/func-call-medium-5.c: New test.
> * gcc.target/loongarch/func-call-medium-6.c: New test.
> * gcc.target/loongarch/func-call-medium-7.c: New test.
> * gcc.target/loongarch/func-call-medium-8.c: New test.
> * gcc.target/loongarch/tls-gd-noplt.c: Add compile parameter '-mexplicit-relocs'.
> ---
> .../loongarch/genopts/loongarch-strings | 1 +
> gcc/config/loongarch/genopts/loongarch.opt.in | 3 +
> gcc/config/loongarch/loongarch-def.c | 1 +
> gcc/config/loongarch/loongarch-def.h | 7 +-
> gcc/config/loongarch/loongarch-opts.cc | 15 ++-
> gcc/config/loongarch/loongarch-opts.h | 1 +
> gcc/config/loongarch/loongarch-str.h | 1 +
> gcc/config/loongarch/loongarch.cc | 123 +++++++++++++----
> gcc/config/loongarch/loongarch.md | 125 +++++++++++++++++-
> gcc/config/loongarch/loongarch.opt | 3 +
> gcc/config/loongarch/predicates.md | 15 ++-
> gcc/doc/invoke.texi | 3 +
> .../gcc.target/loongarch/func-call-medium-1.c | 41 ++++++
> .../gcc.target/loongarch/func-call-medium-2.c | 41 ++++++
> .../gcc.target/loongarch/func-call-medium-3.c | 41 ++++++
> .../gcc.target/loongarch/func-call-medium-4.c | 41 ++++++
> .../gcc.target/loongarch/func-call-medium-5.c | 42 ++++++
> .../gcc.target/loongarch/func-call-medium-6.c | 42 ++++++
> .../gcc.target/loongarch/func-call-medium-7.c | 43 ++++++
> .../gcc.target/loongarch/func-call-medium-8.c | 42 ++++++
> .../gcc.target/loongarch/tls-gd-noplt.c | 4 +-
> 21 files changed, 595 insertions(+), 40 deletions(-)
> create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-1.c
> create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-2.c
> create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-3.c
> create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-4.c
> create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-5.c
> create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-6.c
> create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-7.c
> create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-8.c
>
> diff --git a/gcc/config/loongarch/genopts/loongarch-strings b/gcc/config/loongarch/genopts/loongarch-strings
> index cb88ed56b68..44ebb7ab10b 100644
> --- a/gcc/config/loongarch/genopts/loongarch-strings
> +++ b/gcc/config/loongarch/genopts/loongarch-strings
> @@ -54,5 +54,6 @@ OPTSTR_CMODEL cmodel
> STR_CMODEL_NORMAL normal
> STR_CMODEL_TINY tiny
> STR_CMODEL_TS tiny-static
> +STR_CMODEL_MEDIUM medium
> STR_CMODEL_LARGE large
> STR_CMODEL_EXTREME extreme
> diff --git a/gcc/config/loongarch/genopts/loongarch.opt.in b/gcc/config/loongarch/genopts/loongarch.opt.in
> index a571b6b7524..ebdd9538d48 100644
> --- a/gcc/config/loongarch/genopts/loongarch.opt.in
> +++ b/gcc/config/loongarch/genopts/loongarch.opt.in
> @@ -172,6 +172,9 @@ Enum(cmodel) String(@@STR_CMODEL_TINY@@) Value(CMODEL_TINY)
> EnumValue
> Enum(cmodel) String(@@STR_CMODEL_TS@@) Value(CMODEL_TINY_STATIC)
>
> +EnumValue
> +Enum(cmodel) String(@@STR_CMODEL_MEDIUM@@) Value(CMODEL_MEDIUM)
> +
> EnumValue
> Enum(cmodel) String(@@STR_CMODEL_LARGE@@) Value(CMODEL_LARGE)
>
> diff --git a/gcc/config/loongarch/loongarch-def.c b/gcc/config/loongarch/loongarch-def.c
> index c8769b7d65e..cbf995d81b5 100644
> --- a/gcc/config/loongarch/loongarch-def.c
> +++ b/gcc/config/loongarch/loongarch-def.c
> @@ -152,6 +152,7 @@ loongarch_cmodel_strings[] = {
> [CMODEL_NORMAL] = STR_CMODEL_NORMAL,
> [CMODEL_TINY] = STR_CMODEL_TINY,
> [CMODEL_TINY_STATIC] = STR_CMODEL_TS,
> + [CMODEL_MEDIUM] = STR_CMODEL_MEDIUM,
> [CMODEL_LARGE] = STR_CMODEL_LARGE,
> [CMODEL_EXTREME] = STR_CMODEL_EXTREME,
> };
> diff --git a/gcc/config/loongarch/loongarch-def.h b/gcc/config/loongarch/loongarch-def.h
> index c2c35b6ba5c..b5985f07052 100644
> --- a/gcc/config/loongarch/loongarch-def.h
> +++ b/gcc/config/loongarch/loongarch-def.h
> @@ -82,9 +82,10 @@ extern const char* loongarch_cmodel_strings[];
> #define CMODEL_NORMAL 0
> #define CMODEL_TINY 1
> #define CMODEL_TINY_STATIC 2
> -#define CMODEL_LARGE 3
> -#define CMODEL_EXTREME 4
> -#define N_CMODEL_TYPES 5
> +#define CMODEL_MEDIUM 3
> +#define CMODEL_LARGE 4
> +#define CMODEL_EXTREME 5
> +#define N_CMODEL_TYPES 6
>
> /* enum switches */
> /* The "SW_" codes represent command-line switches (options that
> diff --git a/gcc/config/loongarch/loongarch-opts.cc b/gcc/config/loongarch/loongarch-opts.cc
> index 2ae89f23443..e13eafb5882 100644
> --- a/gcc/config/loongarch/loongarch-opts.cc
> +++ b/gcc/config/loongarch/loongarch-opts.cc
> @@ -376,11 +376,24 @@ fallback:
>
> /* 5. Target code model */
> t.cmodel = constrained.cmodel ? opt_cmodel : CMODEL_NORMAL;
> - if (t.cmodel != CMODEL_NORMAL && t.cmodel != CMODEL_EXTREME)
> +
> + switch (t.cmodel)
> {
> + case CMODEL_TINY:
> + case CMODEL_TINY_STATIC:
> + case CMODEL_LARGE:
> warning (0, "%qs is not supported, now cmodel is set to %qs",
> loongarch_cmodel_strings[t.cmodel], "normal");
> t.cmodel = CMODEL_NORMAL;
> + break;
> +
> + case CMODEL_NORMAL:
> + case CMODEL_MEDIUM:
> + case CMODEL_EXTREME:
> + break;
> +
> + default:
> + gcc_unreachable ();
> }
>
> /* Cleanup and return. */
> diff --git a/gcc/config/loongarch/loongarch-opts.h b/gcc/config/loongarch/loongarch-opts.h
> index da24ecd2b50..3523a4cf78d 100644
> --- a/gcc/config/loongarch/loongarch-opts.h
> +++ b/gcc/config/loongarch/loongarch-opts.h
> @@ -46,6 +46,7 @@ loongarch_config_target (struct loongarch_target *target,
> #define TARGET_CMODEL_NORMAL (la_target.cmodel == CMODEL_NORMAL)
> #define TARGET_CMODEL_TINY (la_target.cmodel == CMODEL_TINY)
> #define TARGET_CMODEL_TINY_STATIC (la_target.cmodel == CMODEL_TINY_STATIC)
> +#define TARGET_CMODEL_MEDIUM (la_target.cmodel == CMODEL_MEDIUM)
> #define TARGET_CMODEL_LARGE (la_target.cmodel == CMODEL_LARGE)
> #define TARGET_CMODEL_EXTREME (la_target.cmodel == CMODEL_EXTREME)
>
> diff --git a/gcc/config/loongarch/loongarch-str.h b/gcc/config/loongarch/loongarch-str.h
> index 0e8889b8c96..9f1b0989c82 100644
> --- a/gcc/config/loongarch/loongarch-str.h
> +++ b/gcc/config/loongarch/loongarch-str.h
> @@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see
> #define STR_CMODEL_NORMAL "normal"
> #define STR_CMODEL_TINY "tiny"
> #define STR_CMODEL_TS "tiny-static"
> +#define STR_CMODEL_MEDIUM "medium"
> #define STR_CMODEL_LARGE "large"
> #define STR_CMODEL_EXTREME "extreme"
>
> diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc
> index 207ac2762c6..16fd4acc970 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:
> diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md
> index 8fc10444c2a..3787fd8230f 100644
> --- a/gcc/config/loongarch/loongarch.md
> +++ b/gcc/config/loongarch/loongarch.md
> @@ -59,11 +59,15 @@ (define_c_enum "unspec" [
> UNSPEC_CRCC
>
> UNSPEC_LOAD_FROM_GOT
> + UNSPEC_PCALAU12I
> UNSPEC_ORI_L_LO12
> UNSPEC_LUI_L_HI20
> UNSPEC_LUI_H_LO20
> UNSPEC_LUI_H_HI12
> UNSPEC_TLS_LOW
> +
> + UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1
> + UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1
> ])
>
> (define_c_enum "unspecv" [
> @@ -1946,6 +1950,14 @@ (define_insn "@lui_l_hi20<mode>"
> [(set_attr "type" "move")]
> )
>
> +(define_insn "@pcalau12i<mode>"
> + [(set (match_operand:P 0 "register_operand" "=j")
> + (unspec:P [(match_operand:P 1 "symbolic_operand" "")]
> + UNSPEC_PCALAU12I))]
> + ""
> + "pcalau12i\t%0,%%pc_hi20(%1)"
> + [(set_attr "type" "move")])
> +
> (define_insn "@ori_l_lo12<mode>"
> [(set (match_operand:P 0 "register_operand" "=r")
> (unspec:P [(match_operand:P 1 "register_operand" "r")
> @@ -2877,7 +2889,12 @@ (define_expand "sibcall"
> {
> rtx target = loongarch_legitimize_call_address (XEXP (operands[0], 0));
>
> - emit_call_insn (gen_sibcall_internal (target, operands[1]));
> + if (GET_CODE (target) == LO_SUM)
> + emit_call_insn (gen_sibcall_internal_1 (Pmode, XEXP (target, 0),
> + XEXP (target, 1),
> + operands[1]));
> + else
> + emit_call_insn (gen_sibcall_internal (target, operands[1]));
> DONE;
> })
>
> @@ -2891,6 +2908,14 @@ (define_insn "sibcall_internal"
> b\t%%plt(%0)"
> [(set_attr "jirl" "indirect,direct,direct")])
>
> +(define_insn "@sibcall_internal_1<mode>"
> + [(call (mem:P (lo_sum:P (match_operand:P 0 "register_operand" "j")
> + (match_operand:P 1 "symbolic_operand" "")))
> + (match_operand 2 "" ""))]
> + "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
> + "jirl\t$r0,%0,%%pc_lo12(%1)"
> + [(set_attr "jirl" "indirect")])
> +
> (define_expand "sibcall_value"
> [(parallel [(set (match_operand 0 "")
> (call (match_operand 1 "")
> @@ -2906,7 +2931,14 @@ (define_expand "sibcall_value"
> rtx arg1 = XEXP (XVECEXP (operands[0],0, 0), 0);
> rtx arg2 = XEXP (XVECEXP (operands[0],0, 1), 0);
>
> - emit_call_insn (gen_sibcall_value_multiple_internal (arg1, target,
> + if (GET_CODE (target) == LO_SUM)
> + emit_call_insn (gen_sibcall_value_multiple_internal_1 (Pmode, arg1,
> + XEXP (target, 0),
> + XEXP (target, 1),
> + operands[2],
> + arg2));
> + else
> + emit_call_insn (gen_sibcall_value_multiple_internal (arg1, target,
> operands[2],
> arg2));
> }
> @@ -2916,7 +2948,13 @@ (define_expand "sibcall_value"
> if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 1)
> operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
>
> - emit_call_insn (gen_sibcall_value_internal (operands[0], target,
> + if (GET_CODE (target) == LO_SUM)
> + emit_call_insn (gen_sibcall_value_internal_1 (Pmode, operands[0],
> + XEXP (target, 0),
> + XEXP (target, 1),
> + operands[2]));
> + else
> + emit_call_insn (gen_sibcall_value_internal (operands[0], target,
> operands[2]));
> }
> DONE;
> @@ -2933,6 +2971,15 @@ (define_insn "sibcall_value_internal"
> b\t%%plt(%1)"
> [(set_attr "jirl" "indirect,direct,direct")])
>
> +(define_insn "@sibcall_value_internal_1<mode>"
> + [(set (match_operand 0 "register_operand" "")
> + (call (mem:P (lo_sum:P (match_operand:P 1 "register_operand" "j")
> + (match_operand:P 2 "symbolic_operand" "")))
> + (match_operand 3 "" "")))]
> + "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
> + "jirl\t$r0,%1,%%pc_lo12(%2)"
> + [(set_attr "jirl" "indirect")])
> +
> (define_insn "sibcall_value_multiple_internal"
> [(set (match_operand 0 "register_operand" "")
> (call (mem:SI (match_operand 1 "call_insn_operand" "j,c,b"))
> @@ -2947,6 +2994,21 @@ (define_insn "sibcall_value_multiple_internal"
> b\t%%plt(%1)"
> [(set_attr "jirl" "indirect,direct,direct")])
>
> +(define_insn "@sibcall_value_multiple_internal_1<mode>"
> + [(set (match_operand 0 "register_operand" "")
> + (call (mem:P (unspec:P [(match_operand:P 1 "register_operand" "j")
> + (match_operand:P 2 "symbolic_operand" "")]
> + UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1))
> + (match_operand 3 "" "")))
> + (set (match_operand 4 "register_operand" "")
> + (call (mem:P (unspec:P [(match_dup 1)
> + (match_dup 2)]
> + UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1))
> + (match_dup 3)))]
> + "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
> + "jirl\t$r0,%1,%%pc_lo12(%2)"
> + [(set_attr "jirl" "indirect")])
> +
> (define_expand "call"
> [(parallel [(call (match_operand 0 "")
> (match_operand 1 ""))
> @@ -2956,7 +3018,11 @@ (define_expand "call"
> {
> rtx target = loongarch_legitimize_call_address (XEXP (operands[0], 0));
>
> - emit_call_insn (gen_call_internal (target, operands[1]));
> + if (GET_CODE (target) == LO_SUM)
> + emit_call_insn (gen_call_internal_1 (Pmode, XEXP (target, 0),
> + XEXP (target, 1), operands[1]));
> + else
> + emit_call_insn (gen_call_internal (target, operands[1]));
> DONE;
> })
>
> @@ -2971,6 +3037,15 @@ (define_insn "call_internal"
> bl\t%%plt(%0)"
> [(set_attr "jirl" "indirect,direct,direct")])
>
> +(define_insn "@call_internal_1<mode>"
> + [(call (mem:P (lo_sum:P (match_operand:P 0 "register_operand" "j")
> + (match_operand:P 1 "symbolic_operand" "")))
> + (match_operand 2 "" ""))
> + (clobber (reg:SI RETURN_ADDR_REGNUM))]
> + "TARGET_CMODEL_MEDIUM"
> + "jirl\t$r1,%0,%%pc_lo12(%1)"
> + [(set_attr "jirl" "indirect")])
> +
> (define_expand "call_value"
> [(parallel [(set (match_operand 0 "")
> (call (match_operand 1 "")
> @@ -2985,7 +3060,13 @@ (define_expand "call_value"
> rtx arg1 = XEXP (XVECEXP (operands[0], 0, 0), 0);
> rtx arg2 = XEXP (XVECEXP (operands[0], 0, 1), 0);
>
> - emit_call_insn (gen_call_value_multiple_internal (arg1, target,
> + if (GET_CODE (target) == LO_SUM)
> + emit_call_insn (gen_call_value_multiple_internal_1 (Pmode, arg1,
> + XEXP (target, 0),
> + XEXP (target, 1),
> + operands[2], arg2));
> + else
> + emit_call_insn (gen_call_value_multiple_internal (arg1, target,
> operands[2], arg2));
> }
> else
> @@ -2994,7 +3075,13 @@ (define_expand "call_value"
> if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 1)
> operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
>
> - emit_call_insn (gen_call_value_internal (operands[0], target,
> + if (GET_CODE (target) == LO_SUM)
> + emit_call_insn (gen_call_value_internal_1 (Pmode, operands[0],
> + XEXP (target, 0),
> + XEXP (target, 1),
> + operands[2]));
> + else
> + emit_call_insn (gen_call_value_internal (operands[0], target,
> operands[2]));
> }
> DONE;
> @@ -3012,6 +3099,16 @@ (define_insn "call_value_internal"
> bl\t%%plt(%1)"
> [(set_attr "jirl" "indirect,direct,direct")])
>
> +(define_insn "@call_value_internal_1<mode>"
> + [(set (match_operand 0 "register_operand" "")
> + (call (mem:P (lo_sum:P (match_operand:P 1 "register_operand" "j")
> + (match_operand:P 2 "symbolic_operand" "")))
> + (match_operand 3 "" "")))
> + (clobber (reg:SI RETURN_ADDR_REGNUM))]
> + "TARGET_CMODEL_MEDIUM"
> + "jirl\t$r1,%1,%%pc_lo12(%2)"
> + [(set_attr "jirl" "indirect")])
> +
> (define_insn "call_value_multiple_internal"
> [(set (match_operand 0 "register_operand" "")
> (call (mem:SI (match_operand 1 "call_insn_operand" "e,c,b"))
> @@ -3027,6 +3124,22 @@ (define_insn "call_value_multiple_internal"
> bl\t%%plt(%1)"
> [(set_attr "jirl" "indirect,direct,direct")])
>
> +(define_insn "@call_value_multiple_internal_1<mode>"
> + [(set (match_operand 0 "register_operand" "")
> + (call (mem:P (unspec:P [(match_operand:P 1 "register_operand" "j")
> + (match_operand:P 2 "symbolic_operand" "")]
> + UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1))
> + (match_operand 3 "" "")))
> + (set (match_operand 4 "register_operand" "")
> + (call (mem:P (unspec:P [(match_dup 1)
> + (match_dup 2)]
> + UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1))
> + (match_dup 3)))
> + (clobber (reg:SI RETURN_ADDR_REGNUM))]
> + "TARGET_CMODEL_MEDIUM"
> + "jirl\t$r1,%1,%%pc_lo12(%2)"
> + [(set_attr "jirl" "indirect")])
> +
>
> ;; Call subroutine returning any type.
> (define_expand "untyped_call"
> diff --git a/gcc/config/loongarch/loongarch.opt b/gcc/config/loongarch/loongarch.opt
> index 9df7e187283..6395234218b 100644
> --- a/gcc/config/loongarch/loongarch.opt
> +++ b/gcc/config/loongarch/loongarch.opt
> @@ -179,6 +179,9 @@ Enum(cmodel) String(tiny) Value(CMODEL_TINY)
> EnumValue
> Enum(cmodel) String(tiny-static) Value(CMODEL_TINY_STATIC)
>
> +EnumValue
> +Enum(cmodel) String(medium) Value(CMODEL_MEDIUM)
> +
> EnumValue
> Enum(cmodel) String(large) Value(CMODEL_LARGE)
>
> diff --git a/gcc/config/loongarch/predicates.md b/gcc/config/loongarch/predicates.md
> index e38c6fbdd5f..8bd0c1376c9 100644
> --- a/gcc/config/loongarch/predicates.md
> +++ b/gcc/config/loongarch/predicates.md
> @@ -123,16 +123,27 @@ (define_predicate "const_call_insn_operand"
> if (offset != const0_rtx)
> return false;
>
> + /* When compiling with '-mcmodel=medium -mexplicit-relocs'
> + symbols are splited in loongarch_legitimize_call_address.
> +
> + When compiling with '-mcmodel=medium -mno-explicit-relocs',
> + first obtain the symbolic address or the address of the
> + plt entry, and then perform an indirect jump, so return false. */
> +
> switch (symbol_type)
> {
> case SYMBOL_PCREL:
> - if (TARGET_CMODEL_EXTREME)
> + if (TARGET_CMODEL_EXTREME
> + || (TARGET_CMODEL_MEDIUM && !TARGET_EXPLICIT_RELOCS))
> return false;
> else
> return 1;
>
> case SYMBOL_GOT_DISP:
> - if (TARGET_CMODEL_EXTREME || !flag_plt)
> + if (TARGET_CMODEL_EXTREME
> + || !flag_plt
> + || (flag_plt && TARGET_CMODEL_MEDIUM
> + && !TARGET_EXPLICIT_RELOCS))
> return false;
> else
> return 1;
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 8712bc25e3c..60702a52c8f 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -25084,6 +25084,9 @@ Set the code model to one of:
> The text segment must be within 128MB addressing space. The data segment must
> be within 2GB addressing space.
>
> +@item medium
> +The text segment and data segment must be within 2GB addressing space.
> +
> @item large (Not implemented yet)
>
> @item extreme
> diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-medium-1.c b/gcc/testsuite/gcc.target/loongarch/func-call-medium-1.c
> new file mode 100644
> index 00000000000..276d73e5ee8
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/loongarch/func-call-medium-1.c
> @@ -0,0 +1,41 @@
> +/* { dg-do compile } */
> +/* { dg-options "-mabi=lp64d -O0 -fpic -fplt -mno-explicit-relocs -mcmodel=medium" } */
> +/* { dg-final { scan-assembler "test:.*la\.global\t.*g\n\tjirl" } } */
> +/* { dg-final { scan-assembler "test1:.*la\.global\t.*f\n\tjirl" } } */
> +/* { dg-final { scan-assembler "test2:.*la\.local\t.*l\n\tjirl" } } */
> +/* { dg-final { scan-assembler "test3:.*la\.global\t.*\_\_tls\_get\_addr" } } */
> +
> +extern void g (void);
> +void
> +f (void)
> +{}
> +
> +static void
> +l (void)
> +{}
> +
> +void
> +test (void)
> +{
> + g ();
> +}
> +
> +void
> +test1 (void)
> +{
> + f ();
> +}
> +
> +void
> +test2 (void)
> +{
> + l ();
> +}
> +
> +__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
> +
> +void
> +test3 (void)
> +{
> + a = 10;
> +}
> diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-medium-2.c b/gcc/testsuite/gcc.target/loongarch/func-call-medium-2.c
> new file mode 100644
> index 00000000000..237821c066b
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/loongarch/func-call-medium-2.c
> @@ -0,0 +1,41 @@
> +/* { dg-do compile } */
> +/* { dg-options "-mabi=lp64d -O0 -fno-pic -fplt -mno-explicit-relocs -mcmodel=medium" } */
> +/* { dg-final { scan-assembler "test:.*la\.global\t.*g\n\tjirl" } } */
> +/* { dg-final { scan-assembler "test1:.*la\.local\t.*f\n\tjirl" } } */
> +/* { dg-final { scan-assembler "test2:.*la\.local\t.*l\n\tjirl" } } */
> +/* { dg-final { scan-assembler "test3:.*la\.global\t.*\_\_tls\_get\_addr" } } */
> +
> +extern void g (void);
> +void
> +f (void)
> +{}
> +
> +static void
> +l (void)
> +{}
> +
> +void
> +test (void)
> +{
> + g ();
> +}
> +
> +void
> +test1 (void)
> +{
> + f ();
> +}
> +
> +void
> +test2 (void)
> +{
> + l ();
> +}
> +
> +__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
> +
> +void
> +test3 (void)
> +{
> + a = 10;
> +}
> diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-medium-3.c b/gcc/testsuite/gcc.target/loongarch/func-call-medium-3.c
> new file mode 100644
> index 00000000000..9a6e16103bc
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/loongarch/func-call-medium-3.c
> @@ -0,0 +1,41 @@
> +/* { dg-do compile } */
> +/* { dg-options "-mabi=lp64d -O0 -fpic -fno-plt -mno-explicit-relocs -mcmodel=medium" } */
> +/* { dg-final { scan-assembler "test:.*la\.global\t.*g\n\tjirl" } } */
> +/* { dg-final { scan-assembler "test1:.*la\.global\t.*f\n\tjirl" } } */
> +/* { dg-final { scan-assembler "test2:.*la\.local\t.*l\n\tjirl" } } */
> +/* { dg-final { scan-assembler "test3:.*la\.global\t.*\_\_tls\_get\_addr" } } */
> +
> +extern void g (void);
> +void
> +f (void)
> +{}
> +
> +static void
> +l (void)
> +{}
> +
> +void
> +test (void)
> +{
> + g ();
> +}
> +
> +void
> +test1 (void)
> +{
> + f ();
> +}
> +
> +void
> +test2 (void)
> +{
> + l ();
> +}
> +
> +__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
> +
> +void
> +test3 (void)
> +{
> + a = 10;
> +}
> diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-medium-4.c b/gcc/testsuite/gcc.target/loongarch/func-call-medium-4.c
> new file mode 100644
> index 00000000000..2577e345239
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/loongarch/func-call-medium-4.c
> @@ -0,0 +1,41 @@
> +/* { dg-do compile } */
> +/* { dg-options "-mabi=lp64d -O0 -fno-pic -fno-plt -mno-explicit-relocs -mcmodel=medium" } */
> +/* { dg-final { scan-assembler "test:.*la\.global\t.*g\n\tjirl" } } */
> +/* { dg-final { scan-assembler "test1:.*la\.local\t.*f\n\tjirl" } } */
> +/* { dg-final { scan-assembler "test2:.*la\.local\t.*l\n\tjirl" } } */
> +/* { dg-final { scan-assembler "test3:.*la\.global\t.*\_\_tls\_get\_addr" } } */
> +
> +extern void g (void);
> +void
> +f (void)
> +{}
> +
> +static void
> +l (void)
> +{}
> +
> +void
> +test (void)
> +{
> + g ();
> +}
> +
> +void
> +test1 (void)
> +{
> + f ();
> +}
> +
> +void
> +test2 (void)
> +{
> + l ();
> +}
> +
> +__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
> +
> +void
> +test3 (void)
> +{
> + a = 10;
> +}
> diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-medium-5.c b/gcc/testsuite/gcc.target/loongarch/func-call-medium-5.c
> new file mode 100644
> index 00000000000..d70b6ea4663
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/loongarch/func-call-medium-5.c
> @@ -0,0 +1,42 @@
> +/* { dg-do compile } */
> +/* { dg-options "-mabi=lp64d -O0 -fpic -fplt -mexplicit-relocs -mcmodel=medium" } */
> +/* { dg-final { scan-assembler "test:.*pcalau12i.*%pc_hi20\\(g\\)\n\tjirl.*pc_lo12\\(g\\)" } } */
> +/* { dg-final { scan-assembler "test1:.*pcalau12i.*%pc_hi20\\(f\\)\n\tjirl.*%pc_lo12\\(f\\)" } } */
> +/* { dg-final { scan-assembler "test2:.*pcalau12i.*%pc_hi20\\(l\\)\n\tjirl.*%pc_lo12\\(l\\)" } } */
> +/* { dg-final { scan-assembler "test3:.*pcalau12i.*%pc_hi20\\(__tls_get_addr\\)\n\t.*\n\tjirl.*%pc_lo12\\(__tls_get_addr\\)" } } */
> +
> +extern void g (void);
> +
> +void
> +f (void)
> +{}
> +
> +static void
> +l (void)
> +{}
> +
> +void
> +test (void)
> +{
> + g ();
> +}
> +
> +void
> +test1 (void)
> +{
> + f ();
> +}
> +
> +void
> +test2 (void)
> +{
> + l ();
> +}
> +
> +__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
> +
> +void
> +test3 (void)
> +{
> + a = 10;
> +}
> diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-medium-6.c b/gcc/testsuite/gcc.target/loongarch/func-call-medium-6.c
> new file mode 100644
> index 00000000000..f963a99441a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/loongarch/func-call-medium-6.c
> @@ -0,0 +1,42 @@
> +/* { dg-do compile } */
> +/* { dg-options "-mabi=lp64d -O0 -fno-pic -fplt -mexplicit-relocs -mcmodel=medium" } */
> +/* { dg-final { scan-assembler "test:.*pcalau12i.*%pc_hi20\\(g\\)\n\tjirl.*pc_lo12\\(g\\)" } } */
> +/* { dg-final { scan-assembler "test1:.*pcalau12i.*%pc_hi20\\(f\\)\n\tjirl.*%pc_lo12\\(f\\)" } } */
> +/* { dg-final { scan-assembler "test2:.*pcalau12i.*%pc_hi20\\(l\\)\n\tjirl.*%pc_lo12\\(l\\)" } } */
> +/* { dg-final { scan-assembler "test3:.*pcalau12i.*%pc_hi20\\(__tls_get_addr\\)\n\t.*\n\tjirl.*%pc_lo12\\(__tls_get_addr\\)" } } */
> +
> +extern void g (void);
> +
> +void
> +f (void)
> +{}
> +
> +static void
> +l (void)
> +{}
> +
> +void
> +test (void)
> +{
> + g ();
> +}
> +
> +void
> +test1 (void)
> +{
> + f ();
> +}
> +
> +void
> +test2 (void)
> +{
> + l ();
> +}
> +
> +__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
> +
> +void
> +test3 (void)
> +{
> + a = 10;
> +}
> diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-medium-7.c b/gcc/testsuite/gcc.target/loongarch/func-call-medium-7.c
> new file mode 100644
> index 00000000000..f2818b2da76
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/loongarch/func-call-medium-7.c
> @@ -0,0 +1,43 @@
> +/* { dg-do compile } */
> +/* { dg-options "-mabi=lp64d -O0 -fpic -fno-plt -mexplicit-relocs -mcmodel=medium" } */
> +/* { dg-final { scan-assembler "test:.*pcalau12i\t.*%got_pc_hi20\\(g\\)\n\tld\.d\t.*%got_pc_lo12\\(g\\)\n\tjirl" } } */
> +/* { dg-final { scan-assembler "test1:.*pcalau12i\t.*%got_pc_hi20\\(f\\)\n\tld\.d\t.*%got_pc_lo12\\(f\\)\n\tjirl" } } */
> +/* { dg-final { scan-assembler "test2:.*pcalau12i\t.*%pc_hi20\\(l\\)\n\tjirl.*%pc_lo12\\(l\\)" } } */
> +/* { dg-final { scan-assembler "test3:.*pcalau12i.*%got_pc_hi20\\(__tls_get_addr\\)\n\tld\.d.*%got_pc_lo12\\(__tls_get_addr\\)" } } */
> +
> +
> +extern void g (void);
> +
> +void
> +f (void)
> +{}
> +
> +static void
> +l (void)
> +{}
> +
> +void
> +test (void)
> +{
> + g ();
> +}
> +
> +void
> +test1 (void)
> +{
> + f ();
> +}
> +
> +void
> +test2 (void)
> +{
> + l ();
> +}
> +
> +__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
> +
> +void
> +test3 (void)
> +{
> + a = 10;
> +}
> diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-medium-8.c b/gcc/testsuite/gcc.target/loongarch/func-call-medium-8.c
> new file mode 100644
> index 00000000000..7fa873d84bb
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/loongarch/func-call-medium-8.c
> @@ -0,0 +1,42 @@
> +/* { dg-do compile } */
> +/* { dg-options "-mabi=lp64d -O0 -fno-pic -fno-plt -mexplicit-relocs -mcmodel=medium" } */
> +/* { dg-final { scan-assembler "test:.*pcalau12i\t.*%got_pc_hi20\\(g\\)\n\tld\.d\t.*%got_pc_lo12\\(g\\)\n\tjirl" } } */
> +/* { dg-final { scan-assembler "test1:.*pcalau12i\t.*%pc_hi20\\(f\\)\n\tjirl.*%pc_lo12\\(f\\)" } } */
> +/* { dg-final { scan-assembler "test2:.*pcalau12i\t.*%pc_hi20\\(l\\)\n\tjirl.*%pc_lo12\\(l\\)" } } */
> +/* { dg-final { scan-assembler "test3:.*pcalau12i.*%got_pc_hi20\\(__tls_get_addr\\)\n\tld\.d.*%got_pc_lo12\\(__tls_get_addr\\)" } } */
> +
> +extern void g (void);
> +
> +void
> +f (void)
> +{}
> +
> +static void
> +l (void)
> +{}
> +
> +void
> +test (void)
> +{
> + g ();
> +}
> +
> +void
> +test1 (void)
> +{
> + f ();
> +}
> +
> +void
> +test2 (void)
> +{
> + l ();
> +}
> +
> +__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
> +
> +void
> +test3 (void)
> +{
> + a = 10;
> +}
> diff --git a/gcc/testsuite/gcc.target/loongarch/tls-gd-noplt.c b/gcc/testsuite/gcc.target/loongarch/tls-gd-noplt.c
> index 32a0acf9b18..375663286f0 100644
> --- a/gcc/testsuite/gcc.target/loongarch/tls-gd-noplt.c
> +++ b/gcc/testsuite/gcc.target/loongarch/tls-gd-noplt.c
> @@ -1,6 +1,6 @@
> /* { dg-do compile } */
> -/* { dg-options "-O2 -fno-plt -mcmodel=normal" } */
> -/* { dg-final { scan-assembler "pcalau12i\t.*%got_pc_hi20\\(__tls_get_addr\\)" } } */
> +/* { dg-options "-O0 -fno-plt -mcmodel=normal -mexplicit-relocs" } */
> +/* { dg-final { scan-assembler "pcalau12i\t.*%got_pc_hi20\\(__tls_get_addr\\)\n\tld\.d.*%got_pc_lo12\\(__tls_get_addr\\)" } } */
>
> __attribute__ ((tls_model ("global-dynamic"))) __thread int a;
>
> --
> 2.31.1
>
Pushed to r13-2165.
在 2022/8/20 下午5:18, Huacai Chen 写道:
> Hi, Lulu,
>
> I think there is a typo in your subject line.
>
> Huacai
>
> On Sat, Aug 20, 2022 at 5:05 PM Lulu Cheng <chenglulu@loongson.cn> wrote:
>> The function jump instruction in normal mode is 'bl',
>> so the scope of the function jump is +-128MB.
>>
>> Now we've added support for 'medium' mode, this mode is
>> to complete the function jump through two instructions:
>> pcalau12i + jirl
>> So in this mode the function jump range is increased to +-2GB.
>>
>> Compared with 'normal' mode, 'medium' mode only affects the
>> jump range of functions.
>>
>> gcc/ChangeLog:
>>
>> * config/loongarch/genopts/loongarch-strings: Support code model medium.
>> * config/loongarch/genopts/loongarch.opt.in: Likewise.
>> * config/loongarch/loongarch-def.c: Likewise.
>> * config/loongarch/loongarch-def.h (CMODEL_LARGE): Likewise.
>> (CMODEL_EXTREME): Likewise.
>> (N_CMODEL_TYPES): Likewise.
>> (CMODEL_MEDIUM): Likewise.
>> * config/loongarch/loongarch-opts.cc: Likewise.
>> * config/loongarch/loongarch-opts.h (TARGET_CMODEL_MEDIUM): Likewise.
>> * config/loongarch/loongarch-str.h (STR_CMODEL_MEDIUM): Likewise.
>> * config/loongarch/loongarch.cc (loongarch_call_tls_get_addr):
>> Tls symbol Loading support medium mode.
>> (loongarch_legitimize_call_address): When medium mode, make a symbolic
>> jump with two instructions.
>> (loongarch_option_override_internal): Support medium.
>> * config/loongarch/loongarch.md (@pcalau12i<mode>): New template.
>> (@sibcall_internal_1<mode>): New function call templates added to support
>> medium mode.
>> (@sibcall_value_internal_1<mode>): Likewise.
>> (@sibcall_value_multiple_internal_1<mode>): Likewise.
>> (@call_internal_1<mode>): Likewise.
>> (@call_value_internal_1<mode>): Likewise.
>> (@call_value_multiple_internal_1<mode>): Likewise.
>> * config/loongarch/loongarch.opt: Support medium.
>> * config/loongarch/predicates.md: Add processing about medium mode.
>> * doc/invoke.texi: Document for '-mcmodel=medium'.
>>
>> gcc/testsuite/ChangeLog:
>>
>> * gcc.target/loongarch/func-call-medium-1.c: New test.
>> * gcc.target/loongarch/func-call-medium-2.c: New test.
>> * gcc.target/loongarch/func-call-medium-3.c: New test.
>> * gcc.target/loongarch/func-call-medium-4.c: New test.
>> * gcc.target/loongarch/func-call-medium-5.c: New test.
>> * gcc.target/loongarch/func-call-medium-6.c: New test.
>> * gcc.target/loongarch/func-call-medium-7.c: New test.
>> * gcc.target/loongarch/func-call-medium-8.c: New test.
>> * gcc.target/loongarch/tls-gd-noplt.c: Add compile parameter '-mexplicit-relocs'.
>> ---
>> .../loongarch/genopts/loongarch-strings | 1 +
>> gcc/config/loongarch/genopts/loongarch.opt.in | 3 +
>> gcc/config/loongarch/loongarch-def.c | 1 +
>> gcc/config/loongarch/loongarch-def.h | 7 +-
>> gcc/config/loongarch/loongarch-opts.cc | 15 ++-
>> gcc/config/loongarch/loongarch-opts.h | 1 +
>> gcc/config/loongarch/loongarch-str.h | 1 +
>> gcc/config/loongarch/loongarch.cc | 123 +++++++++++++----
>> gcc/config/loongarch/loongarch.md | 125 +++++++++++++++++-
>> gcc/config/loongarch/loongarch.opt | 3 +
>> gcc/config/loongarch/predicates.md | 15 ++-
>> gcc/doc/invoke.texi | 3 +
>> .../gcc.target/loongarch/func-call-medium-1.c | 41 ++++++
>> .../gcc.target/loongarch/func-call-medium-2.c | 41 ++++++
>> .../gcc.target/loongarch/func-call-medium-3.c | 41 ++++++
>> .../gcc.target/loongarch/func-call-medium-4.c | 41 ++++++
>> .../gcc.target/loongarch/func-call-medium-5.c | 42 ++++++
>> .../gcc.target/loongarch/func-call-medium-6.c | 42 ++++++
>> .../gcc.target/loongarch/func-call-medium-7.c | 43 ++++++
>> .../gcc.target/loongarch/func-call-medium-8.c | 42 ++++++
>> .../gcc.target/loongarch/tls-gd-noplt.c | 4 +-
>> 21 files changed, 595 insertions(+), 40 deletions(-)
>> create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-1.c
>> create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-2.c
>> create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-3.c
>> create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-4.c
>> create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-5.c
>> create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-6.c
>> create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-7.c
>> create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-medium-8.c
>>
>> diff --git a/gcc/config/loongarch/genopts/loongarch-strings b/gcc/config/loongarch/genopts/loongarch-strings
>> index cb88ed56b68..44ebb7ab10b 100644
>> --- a/gcc/config/loongarch/genopts/loongarch-strings
>> +++ b/gcc/config/loongarch/genopts/loongarch-strings
>> @@ -54,5 +54,6 @@ OPTSTR_CMODEL cmodel
>> STR_CMODEL_NORMAL normal
>> STR_CMODEL_TINY tiny
>> STR_CMODEL_TS tiny-static
>> +STR_CMODEL_MEDIUM medium
>> STR_CMODEL_LARGE large
>> STR_CMODEL_EXTREME extreme
>> diff --git a/gcc/config/loongarch/genopts/loongarch.opt.in b/gcc/config/loongarch/genopts/loongarch.opt.in
>> index a571b6b7524..ebdd9538d48 100644
>> --- a/gcc/config/loongarch/genopts/loongarch.opt.in
>> +++ b/gcc/config/loongarch/genopts/loongarch.opt.in
>> @@ -172,6 +172,9 @@ Enum(cmodel) String(@@STR_CMODEL_TINY@@) Value(CMODEL_TINY)
>> EnumValue
>> Enum(cmodel) String(@@STR_CMODEL_TS@@) Value(CMODEL_TINY_STATIC)
>>
>> +EnumValue
>> +Enum(cmodel) String(@@STR_CMODEL_MEDIUM@@) Value(CMODEL_MEDIUM)
>> +
>> EnumValue
>> Enum(cmodel) String(@@STR_CMODEL_LARGE@@) Value(CMODEL_LARGE)
>>
>> diff --git a/gcc/config/loongarch/loongarch-def.c b/gcc/config/loongarch/loongarch-def.c
>> index c8769b7d65e..cbf995d81b5 100644
>> --- a/gcc/config/loongarch/loongarch-def.c
>> +++ b/gcc/config/loongarch/loongarch-def.c
>> @@ -152,6 +152,7 @@ loongarch_cmodel_strings[] = {
>> [CMODEL_NORMAL] = STR_CMODEL_NORMAL,
>> [CMODEL_TINY] = STR_CMODEL_TINY,
>> [CMODEL_TINY_STATIC] = STR_CMODEL_TS,
>> + [CMODEL_MEDIUM] = STR_CMODEL_MEDIUM,
>> [CMODEL_LARGE] = STR_CMODEL_LARGE,
>> [CMODEL_EXTREME] = STR_CMODEL_EXTREME,
>> };
>> diff --git a/gcc/config/loongarch/loongarch-def.h b/gcc/config/loongarch/loongarch-def.h
>> index c2c35b6ba5c..b5985f07052 100644
>> --- a/gcc/config/loongarch/loongarch-def.h
>> +++ b/gcc/config/loongarch/loongarch-def.h
>> @@ -82,9 +82,10 @@ extern const char* loongarch_cmodel_strings[];
>> #define CMODEL_NORMAL 0
>> #define CMODEL_TINY 1
>> #define CMODEL_TINY_STATIC 2
>> -#define CMODEL_LARGE 3
>> -#define CMODEL_EXTREME 4
>> -#define N_CMODEL_TYPES 5
>> +#define CMODEL_MEDIUM 3
>> +#define CMODEL_LARGE 4
>> +#define CMODEL_EXTREME 5
>> +#define N_CMODEL_TYPES 6
>>
>> /* enum switches */
>> /* The "SW_" codes represent command-line switches (options that
>> diff --git a/gcc/config/loongarch/loongarch-opts.cc b/gcc/config/loongarch/loongarch-opts.cc
>> index 2ae89f23443..e13eafb5882 100644
>> --- a/gcc/config/loongarch/loongarch-opts.cc
>> +++ b/gcc/config/loongarch/loongarch-opts.cc
>> @@ -376,11 +376,24 @@ fallback:
>>
>> /* 5. Target code model */
>> t.cmodel = constrained.cmodel ? opt_cmodel : CMODEL_NORMAL;
>> - if (t.cmodel != CMODEL_NORMAL && t.cmodel != CMODEL_EXTREME)
>> +
>> + switch (t.cmodel)
>> {
>> + case CMODEL_TINY:
>> + case CMODEL_TINY_STATIC:
>> + case CMODEL_LARGE:
>> warning (0, "%qs is not supported, now cmodel is set to %qs",
>> loongarch_cmodel_strings[t.cmodel], "normal");
>> t.cmodel = CMODEL_NORMAL;
>> + break;
>> +
>> + case CMODEL_NORMAL:
>> + case CMODEL_MEDIUM:
>> + case CMODEL_EXTREME:
>> + break;
>> +
>> + default:
>> + gcc_unreachable ();
>> }
>>
>> /* Cleanup and return. */
>> diff --git a/gcc/config/loongarch/loongarch-opts.h b/gcc/config/loongarch/loongarch-opts.h
>> index da24ecd2b50..3523a4cf78d 100644
>> --- a/gcc/config/loongarch/loongarch-opts.h
>> +++ b/gcc/config/loongarch/loongarch-opts.h
>> @@ -46,6 +46,7 @@ loongarch_config_target (struct loongarch_target *target,
>> #define TARGET_CMODEL_NORMAL (la_target.cmodel == CMODEL_NORMAL)
>> #define TARGET_CMODEL_TINY (la_target.cmodel == CMODEL_TINY)
>> #define TARGET_CMODEL_TINY_STATIC (la_target.cmodel == CMODEL_TINY_STATIC)
>> +#define TARGET_CMODEL_MEDIUM (la_target.cmodel == CMODEL_MEDIUM)
>> #define TARGET_CMODEL_LARGE (la_target.cmodel == CMODEL_LARGE)
>> #define TARGET_CMODEL_EXTREME (la_target.cmodel == CMODEL_EXTREME)
>>
>> diff --git a/gcc/config/loongarch/loongarch-str.h b/gcc/config/loongarch/loongarch-str.h
>> index 0e8889b8c96..9f1b0989c82 100644
>> --- a/gcc/config/loongarch/loongarch-str.h
>> +++ b/gcc/config/loongarch/loongarch-str.h
>> @@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see
>> #define STR_CMODEL_NORMAL "normal"
>> #define STR_CMODEL_TINY "tiny"
>> #define STR_CMODEL_TS "tiny-static"
>> +#define STR_CMODEL_MEDIUM "medium"
>> #define STR_CMODEL_LARGE "large"
>> #define STR_CMODEL_EXTREME "extreme"
>>
>> diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc
>> index 207ac2762c6..16fd4acc970 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:
>> diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md
>> index 8fc10444c2a..3787fd8230f 100644
>> --- a/gcc/config/loongarch/loongarch.md
>> +++ b/gcc/config/loongarch/loongarch.md
>> @@ -59,11 +59,15 @@ (define_c_enum "unspec" [
>> UNSPEC_CRCC
>>
>> UNSPEC_LOAD_FROM_GOT
>> + UNSPEC_PCALAU12I
>> UNSPEC_ORI_L_LO12
>> UNSPEC_LUI_L_HI20
>> UNSPEC_LUI_H_LO20
>> UNSPEC_LUI_H_HI12
>> UNSPEC_TLS_LOW
>> +
>> + UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1
>> + UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1
>> ])
>>
>> (define_c_enum "unspecv" [
>> @@ -1946,6 +1950,14 @@ (define_insn "@lui_l_hi20<mode>"
>> [(set_attr "type" "move")]
>> )
>>
>> +(define_insn "@pcalau12i<mode>"
>> + [(set (match_operand:P 0 "register_operand" "=j")
>> + (unspec:P [(match_operand:P 1 "symbolic_operand" "")]
>> + UNSPEC_PCALAU12I))]
>> + ""
>> + "pcalau12i\t%0,%%pc_hi20(%1)"
>> + [(set_attr "type" "move")])
>> +
>> (define_insn "@ori_l_lo12<mode>"
>> [(set (match_operand:P 0 "register_operand" "=r")
>> (unspec:P [(match_operand:P 1 "register_operand" "r")
>> @@ -2877,7 +2889,12 @@ (define_expand "sibcall"
>> {
>> rtx target = loongarch_legitimize_call_address (XEXP (operands[0], 0));
>>
>> - emit_call_insn (gen_sibcall_internal (target, operands[1]));
>> + if (GET_CODE (target) == LO_SUM)
>> + emit_call_insn (gen_sibcall_internal_1 (Pmode, XEXP (target, 0),
>> + XEXP (target, 1),
>> + operands[1]));
>> + else
>> + emit_call_insn (gen_sibcall_internal (target, operands[1]));
>> DONE;
>> })
>>
>> @@ -2891,6 +2908,14 @@ (define_insn "sibcall_internal"
>> b\t%%plt(%0)"
>> [(set_attr "jirl" "indirect,direct,direct")])
>>
>> +(define_insn "@sibcall_internal_1<mode>"
>> + [(call (mem:P (lo_sum:P (match_operand:P 0 "register_operand" "j")
>> + (match_operand:P 1 "symbolic_operand" "")))
>> + (match_operand 2 "" ""))]
>> + "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
>> + "jirl\t$r0,%0,%%pc_lo12(%1)"
>> + [(set_attr "jirl" "indirect")])
>> +
>> (define_expand "sibcall_value"
>> [(parallel [(set (match_operand 0 "")
>> (call (match_operand 1 "")
>> @@ -2906,7 +2931,14 @@ (define_expand "sibcall_value"
>> rtx arg1 = XEXP (XVECEXP (operands[0],0, 0), 0);
>> rtx arg2 = XEXP (XVECEXP (operands[0],0, 1), 0);
>>
>> - emit_call_insn (gen_sibcall_value_multiple_internal (arg1, target,
>> + if (GET_CODE (target) == LO_SUM)
>> + emit_call_insn (gen_sibcall_value_multiple_internal_1 (Pmode, arg1,
>> + XEXP (target, 0),
>> + XEXP (target, 1),
>> + operands[2],
>> + arg2));
>> + else
>> + emit_call_insn (gen_sibcall_value_multiple_internal (arg1, target,
>> operands[2],
>> arg2));
>> }
>> @@ -2916,7 +2948,13 @@ (define_expand "sibcall_value"
>> if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 1)
>> operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
>>
>> - emit_call_insn (gen_sibcall_value_internal (operands[0], target,
>> + if (GET_CODE (target) == LO_SUM)
>> + emit_call_insn (gen_sibcall_value_internal_1 (Pmode, operands[0],
>> + XEXP (target, 0),
>> + XEXP (target, 1),
>> + operands[2]));
>> + else
>> + emit_call_insn (gen_sibcall_value_internal (operands[0], target,
>> operands[2]));
>> }
>> DONE;
>> @@ -2933,6 +2971,15 @@ (define_insn "sibcall_value_internal"
>> b\t%%plt(%1)"
>> [(set_attr "jirl" "indirect,direct,direct")])
>>
>> +(define_insn "@sibcall_value_internal_1<mode>"
>> + [(set (match_operand 0 "register_operand" "")
>> + (call (mem:P (lo_sum:P (match_operand:P 1 "register_operand" "j")
>> + (match_operand:P 2 "symbolic_operand" "")))
>> + (match_operand 3 "" "")))]
>> + "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
>> + "jirl\t$r0,%1,%%pc_lo12(%2)"
>> + [(set_attr "jirl" "indirect")])
>> +
>> (define_insn "sibcall_value_multiple_internal"
>> [(set (match_operand 0 "register_operand" "")
>> (call (mem:SI (match_operand 1 "call_insn_operand" "j,c,b"))
>> @@ -2947,6 +2994,21 @@ (define_insn "sibcall_value_multiple_internal"
>> b\t%%plt(%1)"
>> [(set_attr "jirl" "indirect,direct,direct")])
>>
>> +(define_insn "@sibcall_value_multiple_internal_1<mode>"
>> + [(set (match_operand 0 "register_operand" "")
>> + (call (mem:P (unspec:P [(match_operand:P 1 "register_operand" "j")
>> + (match_operand:P 2 "symbolic_operand" "")]
>> + UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1))
>> + (match_operand 3 "" "")))
>> + (set (match_operand 4 "register_operand" "")
>> + (call (mem:P (unspec:P [(match_dup 1)
>> + (match_dup 2)]
>> + UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1))
>> + (match_dup 3)))]
>> + "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
>> + "jirl\t$r0,%1,%%pc_lo12(%2)"
>> + [(set_attr "jirl" "indirect")])
>> +
>> (define_expand "call"
>> [(parallel [(call (match_operand 0 "")
>> (match_operand 1 ""))
>> @@ -2956,7 +3018,11 @@ (define_expand "call"
>> {
>> rtx target = loongarch_legitimize_call_address (XEXP (operands[0], 0));
>>
>> - emit_call_insn (gen_call_internal (target, operands[1]));
>> + if (GET_CODE (target) == LO_SUM)
>> + emit_call_insn (gen_call_internal_1 (Pmode, XEXP (target, 0),
>> + XEXP (target, 1), operands[1]));
>> + else
>> + emit_call_insn (gen_call_internal (target, operands[1]));
>> DONE;
>> })
>>
>> @@ -2971,6 +3037,15 @@ (define_insn "call_internal"
>> bl\t%%plt(%0)"
>> [(set_attr "jirl" "indirect,direct,direct")])
>>
>> +(define_insn "@call_internal_1<mode>"
>> + [(call (mem:P (lo_sum:P (match_operand:P 0 "register_operand" "j")
>> + (match_operand:P 1 "symbolic_operand" "")))
>> + (match_operand 2 "" ""))
>> + (clobber (reg:SI RETURN_ADDR_REGNUM))]
>> + "TARGET_CMODEL_MEDIUM"
>> + "jirl\t$r1,%0,%%pc_lo12(%1)"
>> + [(set_attr "jirl" "indirect")])
>> +
>> (define_expand "call_value"
>> [(parallel [(set (match_operand 0 "")
>> (call (match_operand 1 "")
>> @@ -2985,7 +3060,13 @@ (define_expand "call_value"
>> rtx arg1 = XEXP (XVECEXP (operands[0], 0, 0), 0);
>> rtx arg2 = XEXP (XVECEXP (operands[0], 0, 1), 0);
>>
>> - emit_call_insn (gen_call_value_multiple_internal (arg1, target,
>> + if (GET_CODE (target) == LO_SUM)
>> + emit_call_insn (gen_call_value_multiple_internal_1 (Pmode, arg1,
>> + XEXP (target, 0),
>> + XEXP (target, 1),
>> + operands[2], arg2));
>> + else
>> + emit_call_insn (gen_call_value_multiple_internal (arg1, target,
>> operands[2], arg2));
>> }
>> else
>> @@ -2994,7 +3075,13 @@ (define_expand "call_value"
>> if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 1)
>> operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
>>
>> - emit_call_insn (gen_call_value_internal (operands[0], target,
>> + if (GET_CODE (target) == LO_SUM)
>> + emit_call_insn (gen_call_value_internal_1 (Pmode, operands[0],
>> + XEXP (target, 0),
>> + XEXP (target, 1),
>> + operands[2]));
>> + else
>> + emit_call_insn (gen_call_value_internal (operands[0], target,
>> operands[2]));
>> }
>> DONE;
>> @@ -3012,6 +3099,16 @@ (define_insn "call_value_internal"
>> bl\t%%plt(%1)"
>> [(set_attr "jirl" "indirect,direct,direct")])
>>
>> +(define_insn "@call_value_internal_1<mode>"
>> + [(set (match_operand 0 "register_operand" "")
>> + (call (mem:P (lo_sum:P (match_operand:P 1 "register_operand" "j")
>> + (match_operand:P 2 "symbolic_operand" "")))
>> + (match_operand 3 "" "")))
>> + (clobber (reg:SI RETURN_ADDR_REGNUM))]
>> + "TARGET_CMODEL_MEDIUM"
>> + "jirl\t$r1,%1,%%pc_lo12(%2)"
>> + [(set_attr "jirl" "indirect")])
>> +
>> (define_insn "call_value_multiple_internal"
>> [(set (match_operand 0 "register_operand" "")
>> (call (mem:SI (match_operand 1 "call_insn_operand" "e,c,b"))
>> @@ -3027,6 +3124,22 @@ (define_insn "call_value_multiple_internal"
>> bl\t%%plt(%1)"
>> [(set_attr "jirl" "indirect,direct,direct")])
>>
>> +(define_insn "@call_value_multiple_internal_1<mode>"
>> + [(set (match_operand 0 "register_operand" "")
>> + (call (mem:P (unspec:P [(match_operand:P 1 "register_operand" "j")
>> + (match_operand:P 2 "symbolic_operand" "")]
>> + UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1))
>> + (match_operand 3 "" "")))
>> + (set (match_operand 4 "register_operand" "")
>> + (call (mem:P (unspec:P [(match_dup 1)
>> + (match_dup 2)]
>> + UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1))
>> + (match_dup 3)))
>> + (clobber (reg:SI RETURN_ADDR_REGNUM))]
>> + "TARGET_CMODEL_MEDIUM"
>> + "jirl\t$r1,%1,%%pc_lo12(%2)"
>> + [(set_attr "jirl" "indirect")])
>> +
>>
>> ;; Call subroutine returning any type.
>> (define_expand "untyped_call"
>> diff --git a/gcc/config/loongarch/loongarch.opt b/gcc/config/loongarch/loongarch.opt
>> index 9df7e187283..6395234218b 100644
>> --- a/gcc/config/loongarch/loongarch.opt
>> +++ b/gcc/config/loongarch/loongarch.opt
>> @@ -179,6 +179,9 @@ Enum(cmodel) String(tiny) Value(CMODEL_TINY)
>> EnumValue
>> Enum(cmodel) String(tiny-static) Value(CMODEL_TINY_STATIC)
>>
>> +EnumValue
>> +Enum(cmodel) String(medium) Value(CMODEL_MEDIUM)
>> +
>> EnumValue
>> Enum(cmodel) String(large) Value(CMODEL_LARGE)
>>
>> diff --git a/gcc/config/loongarch/predicates.md b/gcc/config/loongarch/predicates.md
>> index e38c6fbdd5f..8bd0c1376c9 100644
>> --- a/gcc/config/loongarch/predicates.md
>> +++ b/gcc/config/loongarch/predicates.md
>> @@ -123,16 +123,27 @@ (define_predicate "const_call_insn_operand"
>> if (offset != const0_rtx)
>> return false;
>>
>> + /* When compiling with '-mcmodel=medium -mexplicit-relocs'
>> + symbols are splited in loongarch_legitimize_call_address.
>> +
>> + When compiling with '-mcmodel=medium -mno-explicit-relocs',
>> + first obtain the symbolic address or the address of the
>> + plt entry, and then perform an indirect jump, so return false. */
>> +
>> switch (symbol_type)
>> {
>> case SYMBOL_PCREL:
>> - if (TARGET_CMODEL_EXTREME)
>> + if (TARGET_CMODEL_EXTREME
>> + || (TARGET_CMODEL_MEDIUM && !TARGET_EXPLICIT_RELOCS))
>> return false;
>> else
>> return 1;
>>
>> case SYMBOL_GOT_DISP:
>> - if (TARGET_CMODEL_EXTREME || !flag_plt)
>> + if (TARGET_CMODEL_EXTREME
>> + || !flag_plt
>> + || (flag_plt && TARGET_CMODEL_MEDIUM
>> + && !TARGET_EXPLICIT_RELOCS))
>> return false;
>> else
>> return 1;
>> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
>> index 8712bc25e3c..60702a52c8f 100644
>> --- a/gcc/doc/invoke.texi
>> +++ b/gcc/doc/invoke.texi
>> @@ -25084,6 +25084,9 @@ Set the code model to one of:
>> The text segment must be within 128MB addressing space. The data segment must
>> be within 2GB addressing space.
>>
>> +@item medium
>> +The text segment and data segment must be within 2GB addressing space.
>> +
>> @item large (Not implemented yet)
>>
>> @item extreme
>> diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-medium-1.c b/gcc/testsuite/gcc.target/loongarch/func-call-medium-1.c
>> new file mode 100644
>> index 00000000000..276d73e5ee8
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/loongarch/func-call-medium-1.c
>> @@ -0,0 +1,41 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-mabi=lp64d -O0 -fpic -fplt -mno-explicit-relocs -mcmodel=medium" } */
>> +/* { dg-final { scan-assembler "test:.*la\.global\t.*g\n\tjirl" } } */
>> +/* { dg-final { scan-assembler "test1:.*la\.global\t.*f\n\tjirl" } } */
>> +/* { dg-final { scan-assembler "test2:.*la\.local\t.*l\n\tjirl" } } */
>> +/* { dg-final { scan-assembler "test3:.*la\.global\t.*\_\_tls\_get\_addr" } } */
>> +
>> +extern void g (void);
>> +void
>> +f (void)
>> +{}
>> +
>> +static void
>> +l (void)
>> +{}
>> +
>> +void
>> +test (void)
>> +{
>> + g ();
>> +}
>> +
>> +void
>> +test1 (void)
>> +{
>> + f ();
>> +}
>> +
>> +void
>> +test2 (void)
>> +{
>> + l ();
>> +}
>> +
>> +__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
>> +
>> +void
>> +test3 (void)
>> +{
>> + a = 10;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-medium-2.c b/gcc/testsuite/gcc.target/loongarch/func-call-medium-2.c
>> new file mode 100644
>> index 00000000000..237821c066b
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/loongarch/func-call-medium-2.c
>> @@ -0,0 +1,41 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-mabi=lp64d -O0 -fno-pic -fplt -mno-explicit-relocs -mcmodel=medium" } */
>> +/* { dg-final { scan-assembler "test:.*la\.global\t.*g\n\tjirl" } } */
>> +/* { dg-final { scan-assembler "test1:.*la\.local\t.*f\n\tjirl" } } */
>> +/* { dg-final { scan-assembler "test2:.*la\.local\t.*l\n\tjirl" } } */
>> +/* { dg-final { scan-assembler "test3:.*la\.global\t.*\_\_tls\_get\_addr" } } */
>> +
>> +extern void g (void);
>> +void
>> +f (void)
>> +{}
>> +
>> +static void
>> +l (void)
>> +{}
>> +
>> +void
>> +test (void)
>> +{
>> + g ();
>> +}
>> +
>> +void
>> +test1 (void)
>> +{
>> + f ();
>> +}
>> +
>> +void
>> +test2 (void)
>> +{
>> + l ();
>> +}
>> +
>> +__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
>> +
>> +void
>> +test3 (void)
>> +{
>> + a = 10;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-medium-3.c b/gcc/testsuite/gcc.target/loongarch/func-call-medium-3.c
>> new file mode 100644
>> index 00000000000..9a6e16103bc
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/loongarch/func-call-medium-3.c
>> @@ -0,0 +1,41 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-mabi=lp64d -O0 -fpic -fno-plt -mno-explicit-relocs -mcmodel=medium" } */
>> +/* { dg-final { scan-assembler "test:.*la\.global\t.*g\n\tjirl" } } */
>> +/* { dg-final { scan-assembler "test1:.*la\.global\t.*f\n\tjirl" } } */
>> +/* { dg-final { scan-assembler "test2:.*la\.local\t.*l\n\tjirl" } } */
>> +/* { dg-final { scan-assembler "test3:.*la\.global\t.*\_\_tls\_get\_addr" } } */
>> +
>> +extern void g (void);
>> +void
>> +f (void)
>> +{}
>> +
>> +static void
>> +l (void)
>> +{}
>> +
>> +void
>> +test (void)
>> +{
>> + g ();
>> +}
>> +
>> +void
>> +test1 (void)
>> +{
>> + f ();
>> +}
>> +
>> +void
>> +test2 (void)
>> +{
>> + l ();
>> +}
>> +
>> +__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
>> +
>> +void
>> +test3 (void)
>> +{
>> + a = 10;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-medium-4.c b/gcc/testsuite/gcc.target/loongarch/func-call-medium-4.c
>> new file mode 100644
>> index 00000000000..2577e345239
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/loongarch/func-call-medium-4.c
>> @@ -0,0 +1,41 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-mabi=lp64d -O0 -fno-pic -fno-plt -mno-explicit-relocs -mcmodel=medium" } */
>> +/* { dg-final { scan-assembler "test:.*la\.global\t.*g\n\tjirl" } } */
>> +/* { dg-final { scan-assembler "test1:.*la\.local\t.*f\n\tjirl" } } */
>> +/* { dg-final { scan-assembler "test2:.*la\.local\t.*l\n\tjirl" } } */
>> +/* { dg-final { scan-assembler "test3:.*la\.global\t.*\_\_tls\_get\_addr" } } */
>> +
>> +extern void g (void);
>> +void
>> +f (void)
>> +{}
>> +
>> +static void
>> +l (void)
>> +{}
>> +
>> +void
>> +test (void)
>> +{
>> + g ();
>> +}
>> +
>> +void
>> +test1 (void)
>> +{
>> + f ();
>> +}
>> +
>> +void
>> +test2 (void)
>> +{
>> + l ();
>> +}
>> +
>> +__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
>> +
>> +void
>> +test3 (void)
>> +{
>> + a = 10;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-medium-5.c b/gcc/testsuite/gcc.target/loongarch/func-call-medium-5.c
>> new file mode 100644
>> index 00000000000..d70b6ea4663
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/loongarch/func-call-medium-5.c
>> @@ -0,0 +1,42 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-mabi=lp64d -O0 -fpic -fplt -mexplicit-relocs -mcmodel=medium" } */
>> +/* { dg-final { scan-assembler "test:.*pcalau12i.*%pc_hi20\\(g\\)\n\tjirl.*pc_lo12\\(g\\)" } } */
>> +/* { dg-final { scan-assembler "test1:.*pcalau12i.*%pc_hi20\\(f\\)\n\tjirl.*%pc_lo12\\(f\\)" } } */
>> +/* { dg-final { scan-assembler "test2:.*pcalau12i.*%pc_hi20\\(l\\)\n\tjirl.*%pc_lo12\\(l\\)" } } */
>> +/* { dg-final { scan-assembler "test3:.*pcalau12i.*%pc_hi20\\(__tls_get_addr\\)\n\t.*\n\tjirl.*%pc_lo12\\(__tls_get_addr\\)" } } */
>> +
>> +extern void g (void);
>> +
>> +void
>> +f (void)
>> +{}
>> +
>> +static void
>> +l (void)
>> +{}
>> +
>> +void
>> +test (void)
>> +{
>> + g ();
>> +}
>> +
>> +void
>> +test1 (void)
>> +{
>> + f ();
>> +}
>> +
>> +void
>> +test2 (void)
>> +{
>> + l ();
>> +}
>> +
>> +__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
>> +
>> +void
>> +test3 (void)
>> +{
>> + a = 10;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-medium-6.c b/gcc/testsuite/gcc.target/loongarch/func-call-medium-6.c
>> new file mode 100644
>> index 00000000000..f963a99441a
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/loongarch/func-call-medium-6.c
>> @@ -0,0 +1,42 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-mabi=lp64d -O0 -fno-pic -fplt -mexplicit-relocs -mcmodel=medium" } */
>> +/* { dg-final { scan-assembler "test:.*pcalau12i.*%pc_hi20\\(g\\)\n\tjirl.*pc_lo12\\(g\\)" } } */
>> +/* { dg-final { scan-assembler "test1:.*pcalau12i.*%pc_hi20\\(f\\)\n\tjirl.*%pc_lo12\\(f\\)" } } */
>> +/* { dg-final { scan-assembler "test2:.*pcalau12i.*%pc_hi20\\(l\\)\n\tjirl.*%pc_lo12\\(l\\)" } } */
>> +/* { dg-final { scan-assembler "test3:.*pcalau12i.*%pc_hi20\\(__tls_get_addr\\)\n\t.*\n\tjirl.*%pc_lo12\\(__tls_get_addr\\)" } } */
>> +
>> +extern void g (void);
>> +
>> +void
>> +f (void)
>> +{}
>> +
>> +static void
>> +l (void)
>> +{}
>> +
>> +void
>> +test (void)
>> +{
>> + g ();
>> +}
>> +
>> +void
>> +test1 (void)
>> +{
>> + f ();
>> +}
>> +
>> +void
>> +test2 (void)
>> +{
>> + l ();
>> +}
>> +
>> +__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
>> +
>> +void
>> +test3 (void)
>> +{
>> + a = 10;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-medium-7.c b/gcc/testsuite/gcc.target/loongarch/func-call-medium-7.c
>> new file mode 100644
>> index 00000000000..f2818b2da76
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/loongarch/func-call-medium-7.c
>> @@ -0,0 +1,43 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-mabi=lp64d -O0 -fpic -fno-plt -mexplicit-relocs -mcmodel=medium" } */
>> +/* { dg-final { scan-assembler "test:.*pcalau12i\t.*%got_pc_hi20\\(g\\)\n\tld\.d\t.*%got_pc_lo12\\(g\\)\n\tjirl" } } */
>> +/* { dg-final { scan-assembler "test1:.*pcalau12i\t.*%got_pc_hi20\\(f\\)\n\tld\.d\t.*%got_pc_lo12\\(f\\)\n\tjirl" } } */
>> +/* { dg-final { scan-assembler "test2:.*pcalau12i\t.*%pc_hi20\\(l\\)\n\tjirl.*%pc_lo12\\(l\\)" } } */
>> +/* { dg-final { scan-assembler "test3:.*pcalau12i.*%got_pc_hi20\\(__tls_get_addr\\)\n\tld\.d.*%got_pc_lo12\\(__tls_get_addr\\)" } } */
>> +
>> +
>> +extern void g (void);
>> +
>> +void
>> +f (void)
>> +{}
>> +
>> +static void
>> +l (void)
>> +{}
>> +
>> +void
>> +test (void)
>> +{
>> + g ();
>> +}
>> +
>> +void
>> +test1 (void)
>> +{
>> + f ();
>> +}
>> +
>> +void
>> +test2 (void)
>> +{
>> + l ();
>> +}
>> +
>> +__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
>> +
>> +void
>> +test3 (void)
>> +{
>> + a = 10;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-medium-8.c b/gcc/testsuite/gcc.target/loongarch/func-call-medium-8.c
>> new file mode 100644
>> index 00000000000..7fa873d84bb
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/loongarch/func-call-medium-8.c
>> @@ -0,0 +1,42 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-mabi=lp64d -O0 -fno-pic -fno-plt -mexplicit-relocs -mcmodel=medium" } */
>> +/* { dg-final { scan-assembler "test:.*pcalau12i\t.*%got_pc_hi20\\(g\\)\n\tld\.d\t.*%got_pc_lo12\\(g\\)\n\tjirl" } } */
>> +/* { dg-final { scan-assembler "test1:.*pcalau12i\t.*%pc_hi20\\(f\\)\n\tjirl.*%pc_lo12\\(f\\)" } } */
>> +/* { dg-final { scan-assembler "test2:.*pcalau12i\t.*%pc_hi20\\(l\\)\n\tjirl.*%pc_lo12\\(l\\)" } } */
>> +/* { dg-final { scan-assembler "test3:.*pcalau12i.*%got_pc_hi20\\(__tls_get_addr\\)\n\tld\.d.*%got_pc_lo12\\(__tls_get_addr\\)" } } */
>> +
>> +extern void g (void);
>> +
>> +void
>> +f (void)
>> +{}
>> +
>> +static void
>> +l (void)
>> +{}
>> +
>> +void
>> +test (void)
>> +{
>> + g ();
>> +}
>> +
>> +void
>> +test1 (void)
>> +{
>> + f ();
>> +}
>> +
>> +void
>> +test2 (void)
>> +{
>> + l ();
>> +}
>> +
>> +__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
>> +
>> +void
>> +test3 (void)
>> +{
>> + a = 10;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/loongarch/tls-gd-noplt.c b/gcc/testsuite/gcc.target/loongarch/tls-gd-noplt.c
>> index 32a0acf9b18..375663286f0 100644
>> --- a/gcc/testsuite/gcc.target/loongarch/tls-gd-noplt.c
>> +++ b/gcc/testsuite/gcc.target/loongarch/tls-gd-noplt.c
>> @@ -1,6 +1,6 @@
>> /* { dg-do compile } */
>> -/* { dg-options "-O2 -fno-plt -mcmodel=normal" } */
>> -/* { dg-final { scan-assembler "pcalau12i\t.*%got_pc_hi20\\(__tls_get_addr\\)" } } */
>> +/* { dg-options "-O0 -fno-plt -mcmodel=normal -mexplicit-relocs" } */
>> +/* { dg-final { scan-assembler "pcalau12i\t.*%got_pc_hi20\\(__tls_get_addr\\)\n\tld\.d.*%got_pc_lo12\\(__tls_get_addr\\)" } } */
>>
>> __attribute__ ((tls_model ("global-dynamic"))) __thread int a;
>>
>> --
>> 2.31.1
>>
@@ -54,5 +54,6 @@ OPTSTR_CMODEL cmodel
STR_CMODEL_NORMAL normal
STR_CMODEL_TINY tiny
STR_CMODEL_TS tiny-static
+STR_CMODEL_MEDIUM medium
STR_CMODEL_LARGE large
STR_CMODEL_EXTREME extreme
@@ -172,6 +172,9 @@ Enum(cmodel) String(@@STR_CMODEL_TINY@@) Value(CMODEL_TINY)
EnumValue
Enum(cmodel) String(@@STR_CMODEL_TS@@) Value(CMODEL_TINY_STATIC)
+EnumValue
+Enum(cmodel) String(@@STR_CMODEL_MEDIUM@@) Value(CMODEL_MEDIUM)
+
EnumValue
Enum(cmodel) String(@@STR_CMODEL_LARGE@@) Value(CMODEL_LARGE)
@@ -152,6 +152,7 @@ loongarch_cmodel_strings[] = {
[CMODEL_NORMAL] = STR_CMODEL_NORMAL,
[CMODEL_TINY] = STR_CMODEL_TINY,
[CMODEL_TINY_STATIC] = STR_CMODEL_TS,
+ [CMODEL_MEDIUM] = STR_CMODEL_MEDIUM,
[CMODEL_LARGE] = STR_CMODEL_LARGE,
[CMODEL_EXTREME] = STR_CMODEL_EXTREME,
};
@@ -82,9 +82,10 @@ extern const char* loongarch_cmodel_strings[];
#define CMODEL_NORMAL 0
#define CMODEL_TINY 1
#define CMODEL_TINY_STATIC 2
-#define CMODEL_LARGE 3
-#define CMODEL_EXTREME 4
-#define N_CMODEL_TYPES 5
+#define CMODEL_MEDIUM 3
+#define CMODEL_LARGE 4
+#define CMODEL_EXTREME 5
+#define N_CMODEL_TYPES 6
/* enum switches */
/* The "SW_" codes represent command-line switches (options that
@@ -376,11 +376,24 @@ fallback:
/* 5. Target code model */
t.cmodel = constrained.cmodel ? opt_cmodel : CMODEL_NORMAL;
- if (t.cmodel != CMODEL_NORMAL && t.cmodel != CMODEL_EXTREME)
+
+ switch (t.cmodel)
{
+ case CMODEL_TINY:
+ case CMODEL_TINY_STATIC:
+ case CMODEL_LARGE:
warning (0, "%qs is not supported, now cmodel is set to %qs",
loongarch_cmodel_strings[t.cmodel], "normal");
t.cmodel = CMODEL_NORMAL;
+ break;
+
+ case CMODEL_NORMAL:
+ case CMODEL_MEDIUM:
+ case CMODEL_EXTREME:
+ break;
+
+ default:
+ gcc_unreachable ();
}
/* Cleanup and return. */
@@ -46,6 +46,7 @@ loongarch_config_target (struct loongarch_target *target,
#define TARGET_CMODEL_NORMAL (la_target.cmodel == CMODEL_NORMAL)
#define TARGET_CMODEL_TINY (la_target.cmodel == CMODEL_TINY)
#define TARGET_CMODEL_TINY_STATIC (la_target.cmodel == CMODEL_TINY_STATIC)
+#define TARGET_CMODEL_MEDIUM (la_target.cmodel == CMODEL_MEDIUM)
#define TARGET_CMODEL_LARGE (la_target.cmodel == CMODEL_LARGE)
#define TARGET_CMODEL_EXTREME (la_target.cmodel == CMODEL_EXTREME)
@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see
#define STR_CMODEL_NORMAL "normal"
#define STR_CMODEL_TINY "tiny"
#define STR_CMODEL_TS "tiny-static"
+#define STR_CMODEL_MEDIUM "medium"
#define STR_CMODEL_LARGE "large"
#define STR_CMODEL_EXTREME "extreme"
@@ -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:
@@ -59,11 +59,15 @@ (define_c_enum "unspec" [
UNSPEC_CRCC
UNSPEC_LOAD_FROM_GOT
+ UNSPEC_PCALAU12I
UNSPEC_ORI_L_LO12
UNSPEC_LUI_L_HI20
UNSPEC_LUI_H_LO20
UNSPEC_LUI_H_HI12
UNSPEC_TLS_LOW
+
+ UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1
+ UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1
])
(define_c_enum "unspecv" [
@@ -1946,6 +1950,14 @@ (define_insn "@lui_l_hi20<mode>"
[(set_attr "type" "move")]
)
+(define_insn "@pcalau12i<mode>"
+ [(set (match_operand:P 0 "register_operand" "=j")
+ (unspec:P [(match_operand:P 1 "symbolic_operand" "")]
+ UNSPEC_PCALAU12I))]
+ ""
+ "pcalau12i\t%0,%%pc_hi20(%1)"
+ [(set_attr "type" "move")])
+
(define_insn "@ori_l_lo12<mode>"
[(set (match_operand:P 0 "register_operand" "=r")
(unspec:P [(match_operand:P 1 "register_operand" "r")
@@ -2877,7 +2889,12 @@ (define_expand "sibcall"
{
rtx target = loongarch_legitimize_call_address (XEXP (operands[0], 0));
- emit_call_insn (gen_sibcall_internal (target, operands[1]));
+ if (GET_CODE (target) == LO_SUM)
+ emit_call_insn (gen_sibcall_internal_1 (Pmode, XEXP (target, 0),
+ XEXP (target, 1),
+ operands[1]));
+ else
+ emit_call_insn (gen_sibcall_internal (target, operands[1]));
DONE;
})
@@ -2891,6 +2908,14 @@ (define_insn "sibcall_internal"
b\t%%plt(%0)"
[(set_attr "jirl" "indirect,direct,direct")])
+(define_insn "@sibcall_internal_1<mode>"
+ [(call (mem:P (lo_sum:P (match_operand:P 0 "register_operand" "j")
+ (match_operand:P 1 "symbolic_operand" "")))
+ (match_operand 2 "" ""))]
+ "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
+ "jirl\t$r0,%0,%%pc_lo12(%1)"
+ [(set_attr "jirl" "indirect")])
+
(define_expand "sibcall_value"
[(parallel [(set (match_operand 0 "")
(call (match_operand 1 "")
@@ -2906,7 +2931,14 @@ (define_expand "sibcall_value"
rtx arg1 = XEXP (XVECEXP (operands[0],0, 0), 0);
rtx arg2 = XEXP (XVECEXP (operands[0],0, 1), 0);
- emit_call_insn (gen_sibcall_value_multiple_internal (arg1, target,
+ if (GET_CODE (target) == LO_SUM)
+ emit_call_insn (gen_sibcall_value_multiple_internal_1 (Pmode, arg1,
+ XEXP (target, 0),
+ XEXP (target, 1),
+ operands[2],
+ arg2));
+ else
+ emit_call_insn (gen_sibcall_value_multiple_internal (arg1, target,
operands[2],
arg2));
}
@@ -2916,7 +2948,13 @@ (define_expand "sibcall_value"
if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 1)
operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
- emit_call_insn (gen_sibcall_value_internal (operands[0], target,
+ if (GET_CODE (target) == LO_SUM)
+ emit_call_insn (gen_sibcall_value_internal_1 (Pmode, operands[0],
+ XEXP (target, 0),
+ XEXP (target, 1),
+ operands[2]));
+ else
+ emit_call_insn (gen_sibcall_value_internal (operands[0], target,
operands[2]));
}
DONE;
@@ -2933,6 +2971,15 @@ (define_insn "sibcall_value_internal"
b\t%%plt(%1)"
[(set_attr "jirl" "indirect,direct,direct")])
+(define_insn "@sibcall_value_internal_1<mode>"
+ [(set (match_operand 0 "register_operand" "")
+ (call (mem:P (lo_sum:P (match_operand:P 1 "register_operand" "j")
+ (match_operand:P 2 "symbolic_operand" "")))
+ (match_operand 3 "" "")))]
+ "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
+ "jirl\t$r0,%1,%%pc_lo12(%2)"
+ [(set_attr "jirl" "indirect")])
+
(define_insn "sibcall_value_multiple_internal"
[(set (match_operand 0 "register_operand" "")
(call (mem:SI (match_operand 1 "call_insn_operand" "j,c,b"))
@@ -2947,6 +2994,21 @@ (define_insn "sibcall_value_multiple_internal"
b\t%%plt(%1)"
[(set_attr "jirl" "indirect,direct,direct")])
+(define_insn "@sibcall_value_multiple_internal_1<mode>"
+ [(set (match_operand 0 "register_operand" "")
+ (call (mem:P (unspec:P [(match_operand:P 1 "register_operand" "j")
+ (match_operand:P 2 "symbolic_operand" "")]
+ UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1))
+ (match_operand 3 "" "")))
+ (set (match_operand 4 "register_operand" "")
+ (call (mem:P (unspec:P [(match_dup 1)
+ (match_dup 2)]
+ UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1))
+ (match_dup 3)))]
+ "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
+ "jirl\t$r0,%1,%%pc_lo12(%2)"
+ [(set_attr "jirl" "indirect")])
+
(define_expand "call"
[(parallel [(call (match_operand 0 "")
(match_operand 1 ""))
@@ -2956,7 +3018,11 @@ (define_expand "call"
{
rtx target = loongarch_legitimize_call_address (XEXP (operands[0], 0));
- emit_call_insn (gen_call_internal (target, operands[1]));
+ if (GET_CODE (target) == LO_SUM)
+ emit_call_insn (gen_call_internal_1 (Pmode, XEXP (target, 0),
+ XEXP (target, 1), operands[1]));
+ else
+ emit_call_insn (gen_call_internal (target, operands[1]));
DONE;
})
@@ -2971,6 +3037,15 @@ (define_insn "call_internal"
bl\t%%plt(%0)"
[(set_attr "jirl" "indirect,direct,direct")])
+(define_insn "@call_internal_1<mode>"
+ [(call (mem:P (lo_sum:P (match_operand:P 0 "register_operand" "j")
+ (match_operand:P 1 "symbolic_operand" "")))
+ (match_operand 2 "" ""))
+ (clobber (reg:SI RETURN_ADDR_REGNUM))]
+ "TARGET_CMODEL_MEDIUM"
+ "jirl\t$r1,%0,%%pc_lo12(%1)"
+ [(set_attr "jirl" "indirect")])
+
(define_expand "call_value"
[(parallel [(set (match_operand 0 "")
(call (match_operand 1 "")
@@ -2985,7 +3060,13 @@ (define_expand "call_value"
rtx arg1 = XEXP (XVECEXP (operands[0], 0, 0), 0);
rtx arg2 = XEXP (XVECEXP (operands[0], 0, 1), 0);
- emit_call_insn (gen_call_value_multiple_internal (arg1, target,
+ if (GET_CODE (target) == LO_SUM)
+ emit_call_insn (gen_call_value_multiple_internal_1 (Pmode, arg1,
+ XEXP (target, 0),
+ XEXP (target, 1),
+ operands[2], arg2));
+ else
+ emit_call_insn (gen_call_value_multiple_internal (arg1, target,
operands[2], arg2));
}
else
@@ -2994,7 +3075,13 @@ (define_expand "call_value"
if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 1)
operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
- emit_call_insn (gen_call_value_internal (operands[0], target,
+ if (GET_CODE (target) == LO_SUM)
+ emit_call_insn (gen_call_value_internal_1 (Pmode, operands[0],
+ XEXP (target, 0),
+ XEXP (target, 1),
+ operands[2]));
+ else
+ emit_call_insn (gen_call_value_internal (operands[0], target,
operands[2]));
}
DONE;
@@ -3012,6 +3099,16 @@ (define_insn "call_value_internal"
bl\t%%plt(%1)"
[(set_attr "jirl" "indirect,direct,direct")])
+(define_insn "@call_value_internal_1<mode>"
+ [(set (match_operand 0 "register_operand" "")
+ (call (mem:P (lo_sum:P (match_operand:P 1 "register_operand" "j")
+ (match_operand:P 2 "symbolic_operand" "")))
+ (match_operand 3 "" "")))
+ (clobber (reg:SI RETURN_ADDR_REGNUM))]
+ "TARGET_CMODEL_MEDIUM"
+ "jirl\t$r1,%1,%%pc_lo12(%2)"
+ [(set_attr "jirl" "indirect")])
+
(define_insn "call_value_multiple_internal"
[(set (match_operand 0 "register_operand" "")
(call (mem:SI (match_operand 1 "call_insn_operand" "e,c,b"))
@@ -3027,6 +3124,22 @@ (define_insn "call_value_multiple_internal"
bl\t%%plt(%1)"
[(set_attr "jirl" "indirect,direct,direct")])
+(define_insn "@call_value_multiple_internal_1<mode>"
+ [(set (match_operand 0 "register_operand" "")
+ (call (mem:P (unspec:P [(match_operand:P 1 "register_operand" "j")
+ (match_operand:P 2 "symbolic_operand" "")]
+ UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1))
+ (match_operand 3 "" "")))
+ (set (match_operand 4 "register_operand" "")
+ (call (mem:P (unspec:P [(match_dup 1)
+ (match_dup 2)]
+ UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1))
+ (match_dup 3)))
+ (clobber (reg:SI RETURN_ADDR_REGNUM))]
+ "TARGET_CMODEL_MEDIUM"
+ "jirl\t$r1,%1,%%pc_lo12(%2)"
+ [(set_attr "jirl" "indirect")])
+
;; Call subroutine returning any type.
(define_expand "untyped_call"
@@ -179,6 +179,9 @@ Enum(cmodel) String(tiny) Value(CMODEL_TINY)
EnumValue
Enum(cmodel) String(tiny-static) Value(CMODEL_TINY_STATIC)
+EnumValue
+Enum(cmodel) String(medium) Value(CMODEL_MEDIUM)
+
EnumValue
Enum(cmodel) String(large) Value(CMODEL_LARGE)
@@ -123,16 +123,27 @@ (define_predicate "const_call_insn_operand"
if (offset != const0_rtx)
return false;
+ /* When compiling with '-mcmodel=medium -mexplicit-relocs'
+ symbols are splited in loongarch_legitimize_call_address.
+
+ When compiling with '-mcmodel=medium -mno-explicit-relocs',
+ first obtain the symbolic address or the address of the
+ plt entry, and then perform an indirect jump, so return false. */
+
switch (symbol_type)
{
case SYMBOL_PCREL:
- if (TARGET_CMODEL_EXTREME)
+ if (TARGET_CMODEL_EXTREME
+ || (TARGET_CMODEL_MEDIUM && !TARGET_EXPLICIT_RELOCS))
return false;
else
return 1;
case SYMBOL_GOT_DISP:
- if (TARGET_CMODEL_EXTREME || !flag_plt)
+ if (TARGET_CMODEL_EXTREME
+ || !flag_plt
+ || (flag_plt && TARGET_CMODEL_MEDIUM
+ && !TARGET_EXPLICIT_RELOCS))
return false;
else
return 1;
@@ -25084,6 +25084,9 @@ Set the code model to one of:
The text segment must be within 128MB addressing space. The data segment must
be within 2GB addressing space.
+@item medium
+The text segment and data segment must be within 2GB addressing space.
+
@item large (Not implemented yet)
@item extreme
new file mode 100644
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-mabi=lp64d -O0 -fpic -fplt -mno-explicit-relocs -mcmodel=medium" } */
+/* { dg-final { scan-assembler "test:.*la\.global\t.*g\n\tjirl" } } */
+/* { dg-final { scan-assembler "test1:.*la\.global\t.*f\n\tjirl" } } */
+/* { dg-final { scan-assembler "test2:.*la\.local\t.*l\n\tjirl" } } */
+/* { dg-final { scan-assembler "test3:.*la\.global\t.*\_\_tls\_get\_addr" } } */
+
+extern void g (void);
+void
+f (void)
+{}
+
+static void
+l (void)
+{}
+
+void
+test (void)
+{
+ g ();
+}
+
+void
+test1 (void)
+{
+ f ();
+}
+
+void
+test2 (void)
+{
+ l ();
+}
+
+__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
+
+void
+test3 (void)
+{
+ a = 10;
+}
new file mode 100644
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-mabi=lp64d -O0 -fno-pic -fplt -mno-explicit-relocs -mcmodel=medium" } */
+/* { dg-final { scan-assembler "test:.*la\.global\t.*g\n\tjirl" } } */
+/* { dg-final { scan-assembler "test1:.*la\.local\t.*f\n\tjirl" } } */
+/* { dg-final { scan-assembler "test2:.*la\.local\t.*l\n\tjirl" } } */
+/* { dg-final { scan-assembler "test3:.*la\.global\t.*\_\_tls\_get\_addr" } } */
+
+extern void g (void);
+void
+f (void)
+{}
+
+static void
+l (void)
+{}
+
+void
+test (void)
+{
+ g ();
+}
+
+void
+test1 (void)
+{
+ f ();
+}
+
+void
+test2 (void)
+{
+ l ();
+}
+
+__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
+
+void
+test3 (void)
+{
+ a = 10;
+}
new file mode 100644
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-mabi=lp64d -O0 -fpic -fno-plt -mno-explicit-relocs -mcmodel=medium" } */
+/* { dg-final { scan-assembler "test:.*la\.global\t.*g\n\tjirl" } } */
+/* { dg-final { scan-assembler "test1:.*la\.global\t.*f\n\tjirl" } } */
+/* { dg-final { scan-assembler "test2:.*la\.local\t.*l\n\tjirl" } } */
+/* { dg-final { scan-assembler "test3:.*la\.global\t.*\_\_tls\_get\_addr" } } */
+
+extern void g (void);
+void
+f (void)
+{}
+
+static void
+l (void)
+{}
+
+void
+test (void)
+{
+ g ();
+}
+
+void
+test1 (void)
+{
+ f ();
+}
+
+void
+test2 (void)
+{
+ l ();
+}
+
+__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
+
+void
+test3 (void)
+{
+ a = 10;
+}
new file mode 100644
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-mabi=lp64d -O0 -fno-pic -fno-plt -mno-explicit-relocs -mcmodel=medium" } */
+/* { dg-final { scan-assembler "test:.*la\.global\t.*g\n\tjirl" } } */
+/* { dg-final { scan-assembler "test1:.*la\.local\t.*f\n\tjirl" } } */
+/* { dg-final { scan-assembler "test2:.*la\.local\t.*l\n\tjirl" } } */
+/* { dg-final { scan-assembler "test3:.*la\.global\t.*\_\_tls\_get\_addr" } } */
+
+extern void g (void);
+void
+f (void)
+{}
+
+static void
+l (void)
+{}
+
+void
+test (void)
+{
+ g ();
+}
+
+void
+test1 (void)
+{
+ f ();
+}
+
+void
+test2 (void)
+{
+ l ();
+}
+
+__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
+
+void
+test3 (void)
+{
+ a = 10;
+}
new file mode 100644
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-mabi=lp64d -O0 -fpic -fplt -mexplicit-relocs -mcmodel=medium" } */
+/* { dg-final { scan-assembler "test:.*pcalau12i.*%pc_hi20\\(g\\)\n\tjirl.*pc_lo12\\(g\\)" } } */
+/* { dg-final { scan-assembler "test1:.*pcalau12i.*%pc_hi20\\(f\\)\n\tjirl.*%pc_lo12\\(f\\)" } } */
+/* { dg-final { scan-assembler "test2:.*pcalau12i.*%pc_hi20\\(l\\)\n\tjirl.*%pc_lo12\\(l\\)" } } */
+/* { dg-final { scan-assembler "test3:.*pcalau12i.*%pc_hi20\\(__tls_get_addr\\)\n\t.*\n\tjirl.*%pc_lo12\\(__tls_get_addr\\)" } } */
+
+extern void g (void);
+
+void
+f (void)
+{}
+
+static void
+l (void)
+{}
+
+void
+test (void)
+{
+ g ();
+}
+
+void
+test1 (void)
+{
+ f ();
+}
+
+void
+test2 (void)
+{
+ l ();
+}
+
+__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
+
+void
+test3 (void)
+{
+ a = 10;
+}
new file mode 100644
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-mabi=lp64d -O0 -fno-pic -fplt -mexplicit-relocs -mcmodel=medium" } */
+/* { dg-final { scan-assembler "test:.*pcalau12i.*%pc_hi20\\(g\\)\n\tjirl.*pc_lo12\\(g\\)" } } */
+/* { dg-final { scan-assembler "test1:.*pcalau12i.*%pc_hi20\\(f\\)\n\tjirl.*%pc_lo12\\(f\\)" } } */
+/* { dg-final { scan-assembler "test2:.*pcalau12i.*%pc_hi20\\(l\\)\n\tjirl.*%pc_lo12\\(l\\)" } } */
+/* { dg-final { scan-assembler "test3:.*pcalau12i.*%pc_hi20\\(__tls_get_addr\\)\n\t.*\n\tjirl.*%pc_lo12\\(__tls_get_addr\\)" } } */
+
+extern void g (void);
+
+void
+f (void)
+{}
+
+static void
+l (void)
+{}
+
+void
+test (void)
+{
+ g ();
+}
+
+void
+test1 (void)
+{
+ f ();
+}
+
+void
+test2 (void)
+{
+ l ();
+}
+
+__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
+
+void
+test3 (void)
+{
+ a = 10;
+}
new file mode 100644
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-options "-mabi=lp64d -O0 -fpic -fno-plt -mexplicit-relocs -mcmodel=medium" } */
+/* { dg-final { scan-assembler "test:.*pcalau12i\t.*%got_pc_hi20\\(g\\)\n\tld\.d\t.*%got_pc_lo12\\(g\\)\n\tjirl" } } */
+/* { dg-final { scan-assembler "test1:.*pcalau12i\t.*%got_pc_hi20\\(f\\)\n\tld\.d\t.*%got_pc_lo12\\(f\\)\n\tjirl" } } */
+/* { dg-final { scan-assembler "test2:.*pcalau12i\t.*%pc_hi20\\(l\\)\n\tjirl.*%pc_lo12\\(l\\)" } } */
+/* { dg-final { scan-assembler "test3:.*pcalau12i.*%got_pc_hi20\\(__tls_get_addr\\)\n\tld\.d.*%got_pc_lo12\\(__tls_get_addr\\)" } } */
+
+
+extern void g (void);
+
+void
+f (void)
+{}
+
+static void
+l (void)
+{}
+
+void
+test (void)
+{
+ g ();
+}
+
+void
+test1 (void)
+{
+ f ();
+}
+
+void
+test2 (void)
+{
+ l ();
+}
+
+__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
+
+void
+test3 (void)
+{
+ a = 10;
+}
new file mode 100644
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-mabi=lp64d -O0 -fno-pic -fno-plt -mexplicit-relocs -mcmodel=medium" } */
+/* { dg-final { scan-assembler "test:.*pcalau12i\t.*%got_pc_hi20\\(g\\)\n\tld\.d\t.*%got_pc_lo12\\(g\\)\n\tjirl" } } */
+/* { dg-final { scan-assembler "test1:.*pcalau12i\t.*%pc_hi20\\(f\\)\n\tjirl.*%pc_lo12\\(f\\)" } } */
+/* { dg-final { scan-assembler "test2:.*pcalau12i\t.*%pc_hi20\\(l\\)\n\tjirl.*%pc_lo12\\(l\\)" } } */
+/* { dg-final { scan-assembler "test3:.*pcalau12i.*%got_pc_hi20\\(__tls_get_addr\\)\n\tld\.d.*%got_pc_lo12\\(__tls_get_addr\\)" } } */
+
+extern void g (void);
+
+void
+f (void)
+{}
+
+static void
+l (void)
+{}
+
+void
+test (void)
+{
+ g ();
+}
+
+void
+test1 (void)
+{
+ f ();
+}
+
+void
+test2 (void)
+{
+ l ();
+}
+
+__attribute__ ((tls_model ("global-dynamic"))) __thread int a;
+
+void
+test3 (void)
+{
+ a = 10;
+}
@@ -1,6 +1,6 @@
/* { dg-do compile } */
-/* { dg-options "-O2 -fno-plt -mcmodel=normal" } */
-/* { dg-final { scan-assembler "pcalau12i\t.*%got_pc_hi20\\(__tls_get_addr\\)" } } */
+/* { dg-options "-O0 -fno-plt -mcmodel=normal -mexplicit-relocs" } */
+/* { dg-final { scan-assembler "pcalau12i\t.*%got_pc_hi20\\(__tls_get_addr\\)\n\tld\.d.*%got_pc_lo12\\(__tls_get_addr\\)" } } */
__attribute__ ((tls_model ("global-dynamic"))) __thread int a;