]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/config/nds32/nds32.c
[NDS32] Implment indirect funciton call attribute.
[thirdparty/gcc.git] / gcc / config / nds32 / nds32.c
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.  */