]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
LoongArch: Add new code model 'medium'.
authorLulu Cheng <chenglulu@loongson.cn>
Sat, 20 Aug 2022 07:19:51 +0000 (15:19 +0800)
committerLulu Cheng <chenglulu@loongson.cn>
Wed, 24 Aug 2022 06:55:34 +0000 (14:55 +0800)
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'.

21 files changed:
gcc/config/loongarch/genopts/loongarch-strings
gcc/config/loongarch/genopts/loongarch.opt.in
gcc/config/loongarch/loongarch-def.c
gcc/config/loongarch/loongarch-def.h
gcc/config/loongarch/loongarch-opts.cc
gcc/config/loongarch/loongarch-opts.h
gcc/config/loongarch/loongarch-str.h
gcc/config/loongarch/loongarch.cc
gcc/config/loongarch/loongarch.md
gcc/config/loongarch/loongarch.opt
gcc/config/loongarch/predicates.md
gcc/doc/invoke.texi
gcc/testsuite/gcc.target/loongarch/func-call-medium-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/func-call-medium-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/func-call-medium-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/func-call-medium-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/func-call-medium-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/func-call-medium-6.c [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/func-call-medium-7.c [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/func-call-medium-8.c [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/tls-gd-noplt.c

index cb88ed56b6885e5a05cfce8b7953ae5cfa4f240c..44ebb7ab10bdbe2c92244ae30c2ea985311ee5e2 100644 (file)
@@ -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
index a571b6b75240d2c175e744f254bc631b441d9239..ebdd9538d48dd85e17acac98ebd2dce9b875afa1 100644 (file)
@@ -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)
 
index c8769b7d65e596751a486bca21aef5f8c9b90044..cbf995d81b5aea8c1a1cf45a68bfe6f0cc724796 100644 (file)
@@ -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,
 };
index c2c35b6ba5cf2f47bef94fad49b385809567f63f..b5985f070521743b72a95cb302f6e8f36faa316a 100644 (file)
@@ -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
index 2ae89f234430e8fda1fd2c6dcca74333e9a86045..e13eafb588254b309e5e37e25c5e8ef8d36bbc49 100644 (file)
@@ -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.  */
index da24ecd2b50bf1d611102644986cf848b53acd27..3523a4cf78d4e66e86efd9d1f0e95e4194c25b1d 100644 (file)
@@ -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)
 
index 0e8889b8c9622e1519d2c560fe4b53afa81b29fb..9f1b0989c82d92ff0b3780f4adc4d03ba1145c61 100644 (file)
@@ -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"
 
index 207ac2762c6aa594b6d11dbaf4d00c9b5aefa0a3..16fd4acc97008af1144e165b545eb368bcc4acb7 100644 (file)
@@ -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:
index 8fc10444c2aefd2a84354f144e6eae8c7b64db81..3787fd8230f4e6d7def8b12d94c3e6e42137912d 100644 (file)
   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" [
   [(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")
 {
   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;
 })
 
    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 "")
       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));
     }
       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;
    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"))
    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 ""))
 {
   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;
 })
 
    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 "")
       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
       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;
    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"))
    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"
index 9df7e187283539b4d17e505458de761e916f2209..6395234218b460504bf226f7f908c0f8cac4b8bb 100644 (file)
@@ -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)
 
index e38c6fbdd5fad0fd9883fc4a76d8506a50bdc11d..8bd0c1376c94b11e998820ee8824f427778c84d2 100644 (file)
   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;
index 78eb7ad7e7408b3eb312360bb3cbf47727dbf9be..3359313d9c5d4f9d2c11eb8a403aeafc977b7bd0 100644 (file)
@@ -25098,6 +25098,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 (file)
index 0000000..276d73e
--- /dev/null
@@ -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 (file)
index 0000000..237821c
--- /dev/null
@@ -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 (file)
index 0000000..9a6e161
--- /dev/null
@@ -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 (file)
index 0000000..2577e34
--- /dev/null
@@ -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 (file)
index 0000000..d70b6ea
--- /dev/null
@@ -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 (file)
index 0000000..f963a99
--- /dev/null
@@ -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 (file)
index 0000000..f2818b2
--- /dev/null
@@ -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 (file)
index 0000000..7fa873d
--- /dev/null
@@ -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;
+}
index 32a0acf9b1813aa31e2dd2efb54c65d95fb8b667..375663286f09f906f17c69bd0eac1c6a030464c4 100644 (file)
@@ -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;