[NDS32] Implment indirect funciton call attribute.
authorKuan-Lin Chen <kuanlinchentw@gmail.com>
Sat, 19 May 2018 08:57:57 +0000 (08:57 +0000)
committerChung-Ju Wu <jasonwucj@gcc.gnu.org>
Sat, 19 May 2018 08:57:57 +0000 (08:57 +0000)
* config/nds32/constants.md (unspec_element): Add UNSPEC_ICT.
* config/nds32/nds32-md-auxiliary.c
(symbolic_reference_mentioned_p): New.
(nds32_legitimize_ict_address): New.
(nds32_expand_ict_move): New.
(nds32_indirect_call_referenced_p): New.
(nds32_symbol_binds_local_p): Delete.
(nds32_long_call_p): Modify.
* config/nds32/nds32-opts.h (nds32_ict_model_type): New enum type.
* config/nds32/nds32-protos.h
(symbolic_reference_mentioned_p): Declare.
(nds32_legitimize_ict_address): Declare.
(nds32_expand_ict_move): Declare.
(nds32_indirect_call_referenced_p): Declare.
* config/nds32/nds32-relax-opt.c (nds32_ict_const_p): New.
(nds32_relax_group): Use nds32_ict_const_p as condition.
* config/nds32/nds32.c (nds32_attribute_table): Add "indirect_call".
(nds32_asm_file_start): Output ict_model directive in asm code.
(nds32_legitimate_address_p): Consider indirect call.
(nds32_print_operand): Consider indirect call.
(nds32_print_operand_address): Consider indirect call.
(nds32_insert_attributes): Handle "indirect_call" attribute.
(TARGET_LEGITIMATE_ADDRESS_P): Define.
(TARGET_LEGITIMATE_CONSTANT_P): Define.
(TARGET_CANNOT_FORCE_CONST_MEM): Define.
(TARGET_DELEGITIMIZE_ADDRESS): Define.
(TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA): Define.
* config/nds32/nds32.h (SYMBOLIC_CONST_P): Define.
(TARGET_ICT_MODEL_SMALL): Define.
(TARGET_ICT_MODEL_LARGE): Define.
* config/nds32/nds32.md (movsi): Consider ict model.
(call, call_value): Consider ict model.
(sibcall, sibcall_value): Consider ict model.
* config/nds32/nds32.opt (mict-model): New option.
* config/nds32/predicates.md (nds32_symbolic_operand): Consider ict
model.

Co-Authored-By: Chung-Ju Wu <jasonwucj@gmail.com>
From-SVN: r260390

gcc/ChangeLog
gcc/config/nds32/constants.md
gcc/config/nds32/nds32-md-auxiliary.c
gcc/config/nds32/nds32-opts.h
gcc/config/nds32/nds32-protos.h
gcc/config/nds32/nds32-relax-opt.c
gcc/config/nds32/nds32.c
gcc/config/nds32/nds32.h
gcc/config/nds32/nds32.md
gcc/config/nds32/nds32.opt
gcc/config/nds32/predicates.md

index 145c3aa468ae45fbcd54dcebd04046e917463034..ceabfc19b628c7c5e9fc4d91df344d302a5f591f 100644 (file)
@@ -1,3 +1,43 @@
+2018-05-19  Kuan-Lin Chen <kuanlinchentw@gmail.com>
+           Chung-Ju Wu  <jasonwucj@gmail.com>
+
+       * config/nds32/constants.md (unspec_element): Add UNSPEC_ICT.
+       * config/nds32/nds32-md-auxiliary.c
+       (symbolic_reference_mentioned_p): New.
+       (nds32_legitimize_ict_address): New.
+       (nds32_expand_ict_move): New.
+       (nds32_indirect_call_referenced_p): New.
+       (nds32_symbol_binds_local_p): Delete.
+       (nds32_long_call_p): Modify.
+       * config/nds32/nds32-opts.h (nds32_ict_model_type): New enum type.
+       * config/nds32/nds32-protos.h
+       (symbolic_reference_mentioned_p): Declare.
+       (nds32_legitimize_ict_address): Declare.
+       (nds32_expand_ict_move): Declare.
+       (nds32_indirect_call_referenced_p): Declare.
+       * config/nds32/nds32-relax-opt.c (nds32_ict_const_p): New.
+       (nds32_relax_group): Use nds32_ict_const_p as condition.
+       * config/nds32/nds32.c (nds32_attribute_table): Add "indirect_call".
+       (nds32_asm_file_start): Output ict_model directive in asm code.
+       (nds32_legitimate_address_p): Consider indirect call.
+       (nds32_print_operand): Consider indirect call.
+       (nds32_print_operand_address): Consider indirect call.
+       (nds32_insert_attributes): Handle "indirect_call" attribute.
+       (TARGET_LEGITIMATE_ADDRESS_P): Define.
+       (TARGET_LEGITIMATE_CONSTANT_P): Define.
+       (TARGET_CANNOT_FORCE_CONST_MEM): Define.
+       (TARGET_DELEGITIMIZE_ADDRESS): Define.
+       (TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA): Define.
+       * config/nds32/nds32.h (SYMBOLIC_CONST_P): Define.
+       (TARGET_ICT_MODEL_SMALL): Define.
+       (TARGET_ICT_MODEL_LARGE): Define.
+       * config/nds32/nds32.md (movsi): Consider ict model.
+       (call, call_value): Consider ict model.
+       (sibcall, sibcall_value): Consider ict model.
+       * config/nds32/nds32.opt (mict-model): New option.
+       * config/nds32/predicates.md (nds32_symbolic_operand): Consider ict
+       model.
+
 2018-05-18  Kito Cheng  <kito.cheng@gmail.com>
            Monk Chiang  <sh.chiang04@gmail.com>
            Jim Wilson <jimw@sifive.com>
index cba989f99a6a8f3b03a6983edef77c146b9a68bc..c4cde8d7ebe3eebf259d8bbb9792179854a5c41d 100644 (file)
@@ -83,6 +83,7 @@
   UNSPEC_LOOP_END
   UNSPEC_TLS_DESC
   UNSPEC_TLS_IE
+  UNSPEC_ICT
   UNSPEC_KADDH
   UNSPEC_KSUBH
 ])
index 96966115402ec6f6fea1f5a78d85c5f2ca08973f..99beff6d8288c29cc5af14ee7c8828000cc76cb2 100644 (file)
@@ -39,6 +39,9 @@
 #include "expr.h"
 #include "emit-rtl.h"
 #include "explow.h"
+#include "stringpool.h"
+#include "attribs.h"
+
 
 /* ------------------------------------------------------------------------ */
 
@@ -2970,16 +2973,6 @@ nds32_output_unpkd8 (rtx output, rtx input,
   return "";
 }
 
-/* Return true if SYMBOL_REF X binds locally.  */
-
-static bool
-nds32_symbol_binds_local_p (const_rtx x)
-{
-  return (SYMBOL_REF_DECL (x)
-         ? targetm.binds_local_p (SYMBOL_REF_DECL (x))
-         : SYMBOL_REF_LOCAL_P (x));
-}
-
 const char *
 nds32_output_call (rtx insn, rtx *operands, rtx symbol, const char *long_call,
                   const char *call, bool align_p)
@@ -3400,11 +3393,100 @@ nds32_split_rotatertdi3 (rtx dst, rtx src, rtx shiftamount)
   emit_insn (gen_cmovnsi (dst_high_part, select_reg,
                          dst_high_part_l32, dst_high_part_g32));
 }
+
+/* Return true if OP contains a symbol reference.  */
+bool
+symbolic_reference_mentioned_p (rtx op)
+{
+  const char *fmt;
+  int i;
+
+  if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
+    return true;
+
+  fmt = GET_RTX_FORMAT (GET_CODE (op));
+  for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'E')
+       {
+         int j;
+
+         for (j = XVECLEN (op, i) - 1; j >= 0; j--)
+           if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
+             return true;
+       }
+
+      else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
+       return true;
+    }
+
+  return false;
+}
+
+/* Expand ICT symbol.
+    Example for @ICT and ICT model=large:
+
+    la $r0, symbol@ICT
+      -> sethi $rt, hi20(symbol@ICT)
+        lwi $r0, [$rt + lo12(symbol@ICT)]
+
+*/
+rtx
+nds32_legitimize_ict_address (rtx x)
+{
+  rtx symbol = x;
+  rtx addr = x;
+  rtx reg = gen_reg_rtx (Pmode);
+  gcc_assert (GET_CODE (x) == SYMBOL_REF
+             && nds32_indirect_call_referenced_p (x));
+
+  addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, symbol), UNSPEC_ICT);
+  addr = gen_rtx_CONST (SImode, addr);
+  emit_insn (gen_sethi (reg, addr));
+
+  x = gen_const_mem (SImode, gen_rtx_LO_SUM (Pmode, reg, addr));
+
+  return x;
+}
+
+void
+nds32_expand_ict_move (rtx *operands)
+{
+  rtx src = operands[1];
+
+  src = nds32_legitimize_ict_address (src);
+
+  emit_move_insn (operands[0], src);
+}
+
+/* Return true X is a indirect call symbol.  */
+bool
+nds32_indirect_call_referenced_p (rtx x)
+{
+  if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_ICT)
+    x = XVECEXP (x, 0, 0);
+
+  if (GET_CODE (x) == SYMBOL_REF)
+    {
+      tree decl = SYMBOL_REF_DECL (x);
+
+      return decl
+            && (lookup_attribute("indirect_call",
+                                 DECL_ATTRIBUTES(decl))
+                != NULL);
+    }
+
+  return false;
+}
+
 /* Return true X is need use long call.  */
 bool
 nds32_long_call_p (rtx symbol)
 {
-  return TARGET_CMODEL_LARGE;
+  if (nds32_indirect_call_referenced_p (symbol))
+    return TARGET_ICT_MODEL_LARGE;
+  else
+    return TARGET_CMODEL_LARGE;
 }
 
 void
index e0400655757b1f76f583e47157aef7f1918bf20b..e75e75f433282d56263186692dc059aebf002542 100644 (file)
@@ -57,6 +57,13 @@ enum nds32_cmodel_type
   CMODEL_LARGE
 };
 
+/* The code model defines the address generation strategy.  */
+enum nds32_ict_model_type
+{
+  ICT_MODEL_SMALL,
+  ICT_MODEL_LARGE
+};
+
 /* Multiply instruction configuration.  */
 enum nds32_mul_type
 {
index a7d679e01f05e8ed220f55ec855c8039fe0d5341..4bf82f1f723d96002a4ec42843a6cebb4d8663cd 100644 (file)
@@ -183,9 +183,25 @@ extern void nds32_expand_float_movcc (rtx *);
 extern enum nds32_expand_result_type nds32_expand_extv (rtx *);
 extern enum nds32_expand_result_type nds32_expand_insv (rtx *);
 
+/* Auxiliary functions for expand ICT instruction.  */
+
+extern void nds32_expand_ict_move (rtx *);
+
+/* Auxiliary functions to legitimize address for indirect-call symbol.  */
+
+extern rtx nds32_legitimize_ict_address (rtx);
+
+/* Auxiliary functions to identify indirect-call symbol.  */
+
+extern bool nds32_indirect_call_referenced_p (rtx);
+
 /* Auxiliary functions to identify long-call symbol.  */
 extern bool nds32_long_call_p (rtx);
 
+/* Auxiliary functions to identify SYMBOL_REF and LABEL_REF pattern.  */
+
+extern bool symbolic_reference_mentioned_p (rtx);
+
 /* Auxiliary functions to identify conditional move comparison operand.  */
 
 extern int nds32_cond_move_p (rtx);
index 0349be4725d2aacb356864f6a7ccf06be6e0621d..0a878aaff9fb11f0bd146f31cb44c718f5922466 100644 (file)
@@ -185,6 +185,17 @@ nds32_plus_reg_load_store_p (rtx_insn *insn)
   return false;
 }
 
+/* Return true if x is const and the referance is ict symbol.  */
+static bool
+nds32_ict_const_p (rtx x)
+{
+  if (GET_CODE (x) == CONST)
+    {
+      x = XEXP (x, 0);
+      return nds32_indirect_call_referenced_p (x);
+    }
+  return FALSE;
+}
 /* Group the relax candidates with group id.  */
 static void
 nds32_group_insns (rtx sethi)
@@ -271,7 +282,8 @@ nds32_relax_group (void)
          /* Find sethi ra, symbol  instruction.  */
          if (recog_memoized (insn) == CODE_FOR_sethi
              && nds32_symbolic_operand (XEXP (SET_SRC (PATTERN (insn)), 0),
-                                        SImode))
+                                        SImode)
+             && !nds32_ict_const_p (XEXP (SET_SRC (PATTERN (insn)), 0)))
            nds32_group_insns (insn);
        }
     }
index 50eb709aa489188f33d0038063c67554b862ba56..fe97854fe739ccad1afcf089aada719d547ddcb9 100644 (file)
@@ -317,6 +317,9 @@ static const struct attribute_spec nds32_attribute_table[] =
   /* The attribute telling no prologue/epilogue.  */
   { "naked",        0,  0, false, false, false, false, NULL, NULL },
 
+  /* The attribute is used to tell this function to be ROM patch.  */
+  { "indirect_call",0,  0, false, false, false, false, NULL, NULL },
+
   /* The last attribute spec is set to be NULL.  */
   { NULL,           0,  0, false, false, false, false, NULL, NULL }
 };
@@ -2576,6 +2579,9 @@ nds32_legitimate_address_p (machine_mode mode, rtx x, bool strict)
 
     case SYMBOL_REF:
       /* (mem (symbol_ref A)) => [symbol_ref] */
+      if (TARGET_ICT_MODEL_LARGE && nds32_indirect_call_referenced_p (x))
+       return false;
+
       /* If -mcmodel=large, the 'symbol_ref' is not a valid address
         during or after LRA/reload phase.  */
       if (TARGET_CMODEL_LARGE
@@ -2685,19 +2691,124 @@ nds32_legitimate_address_p (machine_mode mode, rtx x, bool strict)
 
     case LO_SUM:
       /* (mem (lo_sum (reg) (symbol_ref))) */
-      /* (mem (lo_sum (reg) (const))) */
-      gcc_assert (REG_P (XEXP (x, 0)));
-      if (GET_CODE (XEXP (x, 1)) == SYMBOL_REF
-         || GET_CODE (XEXP (x, 1)) == CONST)
-       return nds32_legitimate_address_p (mode, XEXP (x, 1), strict);
-      else
-       return false;
+      /* (mem (lo_sum (reg) (const (plus (symbol_ref) (reg)))) */
+      {
+       rtx sym = NULL_RTX;
+
+       if (!REG_P (XEXP (x, 0)))
+         return false;
+
+       if (GET_CODE (XEXP (x, 1)) == SYMBOL_REF)
+         sym = XEXP (x, 1);
+       else if (GET_CODE (XEXP (x, 1)) == CONST)
+         {
+           rtx plus = XEXP(XEXP (x, 1), 0);
+           if (GET_CODE (plus) == PLUS)
+             sym = XEXP (plus, 0);
+           else if (GET_CODE (plus) == UNSPEC)
+             sym = XVECEXP (plus, 0, 0);
+         }
+       else
+         return false;
+
+       gcc_assert (GET_CODE (sym) == SYMBOL_REF);
+
+       if (TARGET_ICT_MODEL_LARGE
+           && nds32_indirect_call_referenced_p (sym))
+         return true;
+
+       if (TARGET_CMODEL_LARGE)
+         return true;
+       else if (TARGET_CMODEL_MEDIUM
+                && NDS32_SYMBOL_REF_RODATA_P (sym))
+         return true;
+       else
+         return false;
+      }
 
     default:
       return false;
     }
 }
 
+static rtx
+nds32_legitimize_address (rtx x,
+                         rtx oldx ATTRIBUTE_UNUSED,
+                         machine_mode mode ATTRIBUTE_UNUSED)
+{
+  if (TARGET_ICT_MODEL_LARGE && nds32_indirect_call_referenced_p (x))
+    x = nds32_legitimize_ict_address (x);
+
+  return x;
+}
+
+static bool
+nds32_legitimate_constant_p (machine_mode mode, rtx x)
+{
+  switch (GET_CODE (x))
+    {
+    case CONST_DOUBLE:
+      if ((TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE)
+         && (mode == DFmode || mode == SFmode))
+       return false;
+      break;
+    case CONST:
+      x = XEXP (x, 0);
+
+      if (GET_CODE (x) == PLUS)
+       {
+         if (!CONST_INT_P (XEXP (x, 1)))
+           return false;
+         x = XEXP (x, 0);
+       }
+
+      if (GET_CODE (x) == UNSPEC)
+       {
+         switch (XINT (x, 1))
+           {
+           case UNSPEC_ICT:
+             return false;
+           default:
+             return true;
+           }
+       }
+      break;
+    default:
+      return true;
+    }
+
+  return true;
+}
+
+/* Reorgnize the UNSPEC CONST and return its direct symbol.  */
+static rtx
+nds32_delegitimize_address (rtx x)
+{
+  x = delegitimize_mem_from_attrs (x);
+
+  if (GET_CODE(x) == CONST)
+    {
+      rtx inner = XEXP (x, 0);
+
+      /* Handle for GOTOFF.  */
+      if (GET_CODE (inner) == PLUS)
+       inner = XEXP (inner, 0);
+
+      if (GET_CODE (inner) == UNSPEC)
+       {
+         switch (XINT (inner, 1))
+           {
+           case UNSPEC_ICT:
+             x = XVECEXP (inner, 0, 0);
+             break;
+           default:
+             break;
+           }
+       }
+    }
+  return x;
+}
+
 static machine_mode
 nds32_vectorize_preferred_simd_mode (scalar_mode mode)
 {
@@ -2715,6 +2826,29 @@ nds32_vectorize_preferred_simd_mode (scalar_mode mode)
     }
 }
 
+static bool
+nds32_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
+{
+  switch (GET_CODE (x))
+    {
+    case CONST:
+      return !nds32_legitimate_constant_p (mode, x);
+    case SYMBOL_REF:
+      /* All symbols have to be accessed through gp-relative in PIC mode.  */
+      /* We don't want to force symbol as constant pool in .text section,
+        because we use the gp-relatived instruction to load in small
+        or medium model.  */
+      if (SYMBOL_REF_TLS_MODEL (x)
+         || TARGET_CMODEL_SMALL
+         || TARGET_CMODEL_MEDIUM)
+       return true;
+      break;
+    default:
+      return false;
+    }
+  return false;
+}
+
 \f
 /* Condition Code Status.  */
 
@@ -2862,6 +2996,11 @@ nds32_asm_file_start (void)
   /* Tell assembler that this asm code is generated by compiler.  */
   fprintf (asm_out_file, "\t! This asm file is generated by compiler\n");
   fprintf (asm_out_file, "\t.flag\tverbatim\n");
+
+  if (TARGET_ICT_MODEL_LARGE)
+    fprintf (asm_out_file, "\t.ict_model\tlarge\n");
+  else
+    fprintf (asm_out_file, "\t.ict_model\tsmall\n");
   /* Give assembler the size of each vector for interrupt handler.  */
   fprintf (asm_out_file, "\t! This vector size directive is required "
                         "for checking inconsistency on interrupt handler\n");
@@ -2956,6 +3095,26 @@ nds32_asm_file_end (void)
   fprintf (asm_out_file, "\t! ------------------------------------\n");
 }
 
+static bool
+nds32_asm_output_addr_const_extra (FILE *file, rtx x)
+{
+  if (GET_CODE (x) == UNSPEC)
+    {
+      switch (XINT (x, 1))
+       {
+       case UNSPEC_ICT:
+         output_addr_const (file, XVECEXP (x, 0, 0));
+         fputs ("@ICT", file);
+         break;
+       default:
+         return false;
+       }
+      return true;
+    }
+  else
+    return false;
+}
+
 /* -- Output and Generation of Labels.  */
 
 static void
@@ -3123,8 +3282,15 @@ nds32_print_operand (FILE *stream, rtx x, int code)
   switch (GET_CODE (x))
     {
     case LABEL_REF:
+      output_addr_const (stream, x);
+      break;
+
     case SYMBOL_REF:
       output_addr_const (stream, x);
+
+      if (nds32_indirect_call_referenced_p (x))
+       fprintf (stream, "@ICT");
+
       break;
 
     case REG:
@@ -3211,6 +3377,13 @@ nds32_print_operand (FILE *stream, rtx x, int code)
       fprintf (stream, HOST_WIDE_INT_PRINT_HEX, const_vector_to_hwint (x));
       break;
 
+    case LO_SUM:
+      /* This is a special case for inline assembly using memory address 'p'.
+        The inline assembly code is expected to use pesudo instruction
+        for the operand.  EX: la  */
+      output_addr_const (stream, XEXP(x, 1));
+      break;
+
     default:
       /* Generally, output_addr_const () is able to handle most cases.
         We want to see what CODE could appear,
@@ -3222,7 +3395,9 @@ nds32_print_operand (FILE *stream, rtx x, int code)
 }
 
 static void
-nds32_print_operand_address (FILE *stream, machine_mode /*mode*/, rtx x)
+nds32_print_operand_address (FILE *stream,
+                            machine_mode mode ATTRIBUTE_UNUSED,
+                            rtx x)
 {
   rtx op0, op1;
 
@@ -3237,6 +3412,16 @@ nds32_print_operand_address (FILE *stream, machine_mode /*mode*/, rtx x)
       fputs ("]", stream);
       break;
 
+    case LO_SUM:
+      /* This is a special case for inline assembly using memory operand 'm'.
+        The inline assembly code is expected to use pesudo instruction
+        for the operand.  EX: [ls].[bhw]  */
+      fputs ("[ + ", stream);
+      op1 = XEXP (x, 1);
+      output_addr_const (stream, op1);
+      fputs ("]", stream);
+      break;
+
     case REG:
       /* Forbid using static chain register ($r16)
         on reduced-set registers configuration.  */
@@ -3511,6 +3696,24 @@ nds32_merge_decl_attributes (tree olddecl, tree newdecl)
 static void
 nds32_insert_attributes (tree decl, tree *attributes)
 {
+  /* A "indirect_call" function attribute implies "noinline" and "noclone"
+     for elf toolchain to support ROM patch mechanism.  */
+  if (TREE_CODE (decl) == FUNCTION_DECL
+      && lookup_attribute ("indirect_call", *attributes) != NULL)
+    {
+      tree new_attrs = *attributes;
+
+      if (lookup_attribute ("noinline", new_attrs) == NULL)
+       new_attrs = tree_cons (get_identifier ("noinline"), NULL, new_attrs);
+      if (lookup_attribute ("noclone", new_attrs) == NULL)
+       new_attrs = tree_cons (get_identifier ("noclone"), NULL, new_attrs);
+
+      if (!TREE_PUBLIC (decl))
+       error("indirect_call attribute can't apply for static function");
+
+      *attributes = new_attrs;
+    }
+
   /* For function declaration, we need to check isr-specific attributes:
        1. Call nds32_check_isr_attrs_conflict() to check any conflict.
        2. Check valid integer value for interrupt/exception.
@@ -5149,9 +5352,21 @@ nds32_use_blocks_for_constant_p (machine_mode mode,
 #undef TARGET_LEGITIMATE_ADDRESS_P
 #define TARGET_LEGITIMATE_ADDRESS_P nds32_legitimate_address_p
 
+#undef TARGET_LEGITIMIZE_ADDRESS
+#define TARGET_LEGITIMIZE_ADDRESS nds32_legitimize_address
+
+#undef TARGET_LEGITIMATE_CONSTANT_P
+#define TARGET_LEGITIMATE_CONSTANT_P nds32_legitimate_constant_p
+
 #undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE nds32_vectorize_preferred_simd_mode
 
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM nds32_cannot_force_const_mem
+
+#undef TARGET_DELEGITIMIZE_ADDRESS
+#define TARGET_DELEGITIMIZE_ADDRESS nds32_delegitimize_address
+
 \f
 /* Anchored Addresses.  */
 
@@ -5212,6 +5427,9 @@ nds32_use_blocks_for_constant_p (machine_mode mode,
 #undef TARGET_ASM_ALIGNED_SI_OP
 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
 
+#undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA
+#define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA nds32_asm_output_addr_const_extra
+
 /* -- Output of Uninitialized Variables.  */
 
 /* -- Output and Generation of Labels.  */
index 229012a9965376754214b9ceb0381a79f22bc3af..481c196e30cdc0009918b8dd558565a3c989c961 100644 (file)
@@ -855,6 +855,12 @@ enum nds32_builtins
 #define TARGET_CMODEL_LARGE \
    (nds32_cmodel_option == CMODEL_LARGE)
 
+#define TARGET_ICT_MODEL_SMALL \
+   (nds32_ict_model == ICT_MODEL_SMALL)
+
+#define TARGET_ICT_MODEL_LARGE \
+   (nds32_ict_model == ICT_MODEL_LARGE)
+
 /* When -mcmodel=small or -mcmodel=medium,
    compiler may generate gp-base instruction directly.  */
 #define TARGET_GP_DIRECT \
@@ -1461,6 +1467,11 @@ enum reg_class
 
 #define PIC_OFFSET_TABLE_REGNUM GP_REGNUM
 
+#define SYMBOLIC_CONST_P(X)    \
+(GET_CODE (X) == SYMBOL_REF                                            \
+ || GET_CODE (X) == LABEL_REF                                          \
+ || (GET_CODE (X) == CONST && symbolic_reference_mentioned_p (X)))
+
 \f
 /* Defining the Output Assembler Language.  */
 
index 6379212550e1bdc3b841644279192225d7e128ba..a4f204b0ed24e301c5325da1e0358c7ab13348ad 100644 (file)
                                                  low12_int));
       DONE;
     }
+
+  if ((REG_P (operands[0]) || GET_CODE (operands[0]) == SUBREG)
+       && SYMBOLIC_CONST_P (operands[1]))
+    {
+      if (TARGET_ICT_MODEL_LARGE
+         && nds32_indirect_call_referenced_p (operands[1]))
+       {
+         nds32_expand_ict_move (operands);
+         DONE;
+       }
+    }
 })
 
 (define_insn "*mov<mode>"
              (clobber (reg:SI LP_REGNUM))
              (clobber (reg:SI TA_REGNUM))])]
   ""
-  ""
+  {
+    rtx insn;
+    rtx sym = XEXP (operands[0], 0);
+
+    if (TARGET_ICT_MODEL_LARGE
+       && nds32_indirect_call_referenced_p (sym))
+      {
+       rtx reg = gen_reg_rtx (Pmode);
+       emit_move_insn (reg, sym);
+       operands[0] = gen_const_mem (Pmode, reg);
+      }
+
+    if (flag_pic)
+      {
+       insn = emit_call_insn (gen_call_internal
+                              (XEXP (operands[0], 0), GEN_INT (0)));
+       use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
+       DONE;
+      }
+  }
 )
 
 (define_insn "call_internal"
                         (match_operand 2)))
              (clobber (reg:SI LP_REGNUM))
              (clobber (reg:SI TA_REGNUM))])]
-  "")
+  ""
+  {
+    rtx insn;
+    rtx sym = XEXP (operands[1], 0);
+
+    if (TARGET_ICT_MODEL_LARGE
+       && nds32_indirect_call_referenced_p (sym))
+      {
+       rtx reg = gen_reg_rtx (Pmode);
+       emit_move_insn (reg, sym);
+       operands[1] = gen_const_mem (Pmode, reg);
+      }
+
+    if (flag_pic)
+      {
+       insn =
+         emit_call_insn (gen_call_value_internal
+                         (operands[0], XEXP (operands[1], 0), GEN_INT (0)));
+       use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
+       DONE;
+      }
+  }
+)
 
 (define_insn "call_value_internal"
   [(parallel [(set (match_operand 0)
                    (const_int 0))
              (clobber (reg:SI TA_REGNUM))
              (return)])]
-  "")
+  ""
+{
+    rtx sym = XEXP (operands[0], 0);
+
+    if (TARGET_ICT_MODEL_LARGE
+       && nds32_indirect_call_referenced_p (sym))
+      {
+       rtx reg = gen_reg_rtx (Pmode);
+       emit_move_insn (reg, sym);
+       operands[0] = gen_const_mem (Pmode, reg);
+      }
+})
 
 (define_insn "sibcall_internal"
   [(parallel [(call (mem (match_operand:SI 0 "nds32_call_address_operand" "r, i"))
                         (const_int 0)))
              (clobber (reg:SI TA_REGNUM))
              (return)])]
-  "")
+  ""
+{
+    rtx sym = XEXP (operands[1], 0);
+
+    if (TARGET_ICT_MODEL_LARGE
+       && nds32_indirect_call_referenced_p (sym))
+      {
+       rtx reg = gen_reg_rtx (Pmode);
+       emit_move_insn (reg, sym);
+       operands[1] = gen_const_mem (Pmode, reg);
+      }
+})
 
 (define_insn "sibcall_value_internal"
   [(parallel [(set (match_operand 0)
index f1c1bf9189555d9df2234ca16ae45c8e9c78d33c..9e481549d9dbb0d34bbecae6e9ab9699de7e2f8c 100644 (file)
@@ -85,6 +85,19 @@ mlittle-endian
 Target Undocumented RejectNegative Negative(mbig-endian) InverseMask(BIG_ENDIAN)
 Generate code in little-endian mode.
 
+mict-model=
+Target Undocumented RejectNegative Joined Enum(nds32_ict_model_type) Var(nds32_ict_model) Init(ICT_MODEL_SMALL)
+Specify the address generation strategy for ICT call's code model.
+
+Enum
+Name(nds32_ict_model_type) Type(enum nds32_ict_model_type)
+Known cmodel types (for use with the -mict-model= option):
+
+EnumValue
+Enum(nds32_ict_model_type) String(small) Value(ICT_MODEL_SMALL)
+
+EnumValue
+Enum(nds32_ict_model_type) String(large) Value(ICT_MODEL_LARGE)
 
 mcmov
 Target Report Mask(CMOV)
index e5f7ba4a3da62cdc4dc5f57fbf23d7d334cce627..59292da8328814418387cdc8e06920730cefb7fd 100644 (file)
@@ -40,7 +40,9 @@
   (match_code "mult,and,ior,xor"))
 
 (define_predicate "nds32_symbolic_operand"
-  (match_code "const,symbol_ref,label_ref"))
+  (and (match_code "const,symbol_ref,label_ref")
+       (match_test "!(TARGET_ICT_MODEL_LARGE
+                     && nds32_indirect_call_referenced_p (op))")))
 
 (define_predicate "nds32_reg_constant_operand"
   (ior (match_operand 0 "register_operand")