Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / gcc / config / tilegx / tilegx.c
index 81e015d..beb1012 100644 (file)
@@ -1,6 +1,5 @@
 /* Subroutines used for code generation on the Tilera TILE-Gx.
-   Copyright (C) 2011, 2012
-   Free Software Foundation, Inc.
+   Copyright (C) 2011-2013 Free Software Foundation, Inc.
    Contributed by Walter Lee (walt@tilera.com)
 
    This file is part of GCC.
@@ -37,7 +36,7 @@
 #include "tm-constrs.h"
 #include "target.h"
 #include "target-def.h"
-#include "integrate.h"
+#include "function.h"
 #include "dwarf2.h"
 #include "timevar.h"
 #include "gimple.h"
@@ -67,6 +66,29 @@ static bool output_memory_autoinc_first;
 static void
 tilegx_option_override (void)
 {
+  if (global_options_set.x_tilegx_cmodel)
+    {
+      switch (tilegx_cmodel)
+       {
+       case CM_SMALL:
+       case CM_SMALL_PIC:
+         if (flag_pic)
+           tilegx_cmodel = CM_SMALL_PIC;
+         break;
+
+       case CM_LARGE:
+       case CM_LARGE_PIC:
+         if (flag_pic)
+           tilegx_cmodel = CM_LARGE_PIC;
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
+    }
+  else
+    tilegx_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL;
+
   /* When modulo scheduling is enabled, we still rely on regular
      scheduler for bundling.  */
   if (flag_modulo_sched)
@@ -119,7 +141,8 @@ tilegx_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED,
 static bool
 tilegx_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
-  return decl != NULL;
+  return (tilegx_cmodel != CM_LARGE && tilegx_cmodel != CM_LARGE_PIC
+         && (decl != NULL));
 }
 
 
@@ -352,7 +375,8 @@ tilegx_setup_incoming_varargs (cumulative_args_t cum,
        {
          alias_set_type set = get_varargs_alias_set ();
          rtx tmp =
-           gen_rtx_MEM (BLKmode, plus_constant (virtual_incoming_args_rtx,
+           gen_rtx_MEM (BLKmode, plus_constant (Pmode,
+                                                virtual_incoming_args_rtx,
                                                 -STACK_POINTER_OFFSET -
                                                 UNITS_PER_WORD *
                                                 (TILEGX_NUM_ARG_REGS -
@@ -1023,12 +1047,12 @@ tilegx_legitimize_tls_address (rtx addr)
 
 /* Returns a register that points to ADDR, a symbolic address, by
    computing its address relative to tilegx_text_label_symbol.  */
-static void
-compute_pcrel_address (rtx result, rtx addr)
+void
+tilegx_compute_pcrel_address (rtx result, rtx addr)
 {
   rtx text_label_symbol = tilegx_text_label_symbol ();
   rtx text_label_rtx = tilegx_text_label_rtx ();
-  rtx temp, temp2;
+  rtx temp, temp2, temp3;
 
   temp = create_temp_reg_if_possible (Pmode, result);
   temp2 = create_temp_reg_if_possible (Pmode, result);
@@ -1042,6 +1066,18 @@ compute_pcrel_address (rtx result, rtx addr)
                                            text_label_rtx,
                                            addr, text_label_symbol));
     }
+  else if (tilegx_cmodel == CM_LARGE_PIC)
+    {
+      temp3 = create_temp_reg_if_possible (Pmode, result);
+      emit_insn (gen_mov_large_pcrel_step1 (temp, addr, text_label_symbol));
+      emit_insn (gen_mov_large_pcrel_step2 (temp2, temp, addr,
+                                           text_label_symbol));
+      emit_insn (gen_mov_large_pcrel_step3 (temp3, temp2, addr,
+                                           text_label_symbol));
+      emit_insn (gen_mov_large_pcrel_step4 (result, temp3,
+                                           text_label_rtx,
+                                           addr, text_label_symbol));
+    }
   else
     {
       emit_insn (gen_mov_pcrel_step1 (temp, addr, text_label_symbol));
@@ -1053,6 +1089,41 @@ compute_pcrel_address (rtx result, rtx addr)
 }
 
 
+/* Returns a register that points to the plt entry of ADDR, a symbolic
+   address, by computing its address relative to
+   tilegx_text_label_symbol.  */
+void
+tilegx_compute_pcrel_plt_address (rtx result, rtx addr)
+{
+  rtx text_label_symbol = tilegx_text_label_symbol ();
+  rtx text_label_rtx = tilegx_text_label_rtx ();
+  rtx temp, temp2, temp3;
+
+  temp = create_temp_reg_if_possible (Pmode, result);
+  temp2 = create_temp_reg_if_possible (Pmode, result);
+
+  if (TARGET_32BIT)
+    {
+      emit_insn (gen_mov_plt_pcrel_step1_32bit (temp, addr,
+                                               text_label_symbol));
+      emit_insn (gen_mov_plt_pcrel_step2_32bit (temp2, temp, addr,
+                                               text_label_symbol));
+      emit_move_insn (result, gen_rtx_PLUS (Pmode, temp2, text_label_rtx));
+    }
+  else
+    {
+      temp3 = create_temp_reg_if_possible (Pmode, result);
+
+      emit_insn (gen_mov_plt_pcrel_step1 (temp, addr, text_label_symbol));
+      emit_insn (gen_mov_plt_pcrel_step2 (temp2, temp, addr,
+                                         text_label_symbol));
+      emit_insn (gen_mov_plt_pcrel_step3 (temp3, temp2, addr,
+                                         text_label_symbol));
+      emit_move_insn (result, gen_rtx_PLUS (Pmode, temp3, text_label_rtx));
+    }
+}
+
+
 /* Legitimize PIC addresses.  If the address is already
    position-independent, we return ORIG.  Newly generated
    position-independent addresses go into a reg.  This is REG if
@@ -1078,7 +1149,7 @@ tilegx_legitimize_pic_address (rtx orig,
             loading in the address, so that these instructions can be
             optimized properly.  */
          rtx temp_reg = create_temp_reg_if_possible (Pmode, reg);
-         compute_pcrel_address (temp_reg, orig);
+         tilegx_compute_pcrel_address (temp_reg, orig);
 
          /* Note: this is conservative.  We use the text_label but we
             don't use the pic_offset_table.  However, in some cases
@@ -1192,13 +1263,13 @@ tilegx_legitimize_pic_address (rtx orig,
        }
 
       /* If not during reload, allocate another temp reg here for
-         loading in the address, so that these instructions can be
-         optimized properly.  */
+        loading in the address, so that these instructions can be
+        optimized properly.  */
       temp_reg = create_temp_reg_if_possible (Pmode, reg);
-      compute_pcrel_address (temp_reg, orig);
+      tilegx_compute_pcrel_address (temp_reg, orig);
 
       /* Note: this is conservative.  We use the text_label but we
-         don't use the pic_offset_table.  */
+        don't use the pic_offset_table.  */
       crtl->uses_pic_offset_table = 1;
 
       address = temp_reg;
@@ -1249,7 +1320,13 @@ tilegx_delegitimize_address (rtx x)
          case UNSPEC_HW1_LAST:
          case UNSPEC_HW2_LAST:
          case UNSPEC_HW0_PCREL:
+         case UNSPEC_HW1_PCREL:
          case UNSPEC_HW1_LAST_PCREL:
+         case UNSPEC_HW2_LAST_PCREL:
+         case UNSPEC_HW0_PLT_PCREL:
+         case UNSPEC_HW1_PLT_PCREL:
+         case UNSPEC_HW1_LAST_PLT_PCREL:
+         case UNSPEC_HW2_LAST_PLT_PCREL:
          case UNSPEC_HW0_GOT:
          case UNSPEC_HW0_LAST_GOT:
          case UNSPEC_HW1_LAST_GOT:
@@ -1289,7 +1366,7 @@ load_pic_register (bool delay_pic_helper ATTRIBUTE_UNUSED)
       emit_insn (gen_insn_lnk_and_label (text_label_rtx, text_label_symbol));
     }
 
-  compute_pcrel_address (tilegx_got_rtx (), got_symbol);
+  tilegx_compute_pcrel_address (tilegx_got_rtx (), got_symbol);
 
   flag_pic = orig_flag_pic;
 
@@ -1757,7 +1834,7 @@ tilegx_expand_unaligned_load (rtx dest_reg, rtx mem, HOST_WIDE_INT bitsize,
      implicitly alias surrounding code.  Ideally we'd have some alias
      set that covered all types except those with alignment 8 or
      higher.  */
-  addr_lo = force_reg (Pmode, plus_constant (mema, byte_offset));
+  addr_lo = force_reg (Pmode, plus_constant (Pmode, mema, byte_offset));
   mem_lo = change_address (mem, mode,
                           gen_rtx_AND (GET_MODE (mema), addr_lo,
                                        GEN_INT (-8)));
@@ -1766,7 +1843,7 @@ tilegx_expand_unaligned_load (rtx dest_reg, rtx mem, HOST_WIDE_INT bitsize,
   /* Load the high word at an address that will not fault if the low
      address is aligned and at the very end of a page.  */
   last_byte_offset = (bit_offset + bitsize - 1) / BITS_PER_UNIT;
-  addr_hi = force_reg (Pmode, plus_constant (mema, last_byte_offset));
+  addr_hi = force_reg (Pmode, plus_constant (Pmode, mema, last_byte_offset));
   mem_hi = change_address (mem, mode,
                           gen_rtx_AND (GET_MODE (mema), addr_hi,
                                        GEN_INT (-8)));
@@ -2579,7 +2656,7 @@ tilegx_expand_tablejump (rtx op0, rtx op1)
       rtx temp = gen_reg_rtx (Pmode);
       rtx temp2 = gen_reg_rtx (Pmode);
 
-      compute_pcrel_address (temp, gen_rtx_LABEL_REF (Pmode, op1));
+      tilegx_compute_pcrel_address (temp, gen_rtx_LABEL_REF (Pmode, op1));
       emit_move_insn (temp2,
                      gen_rtx_PLUS (Pmode,
                                    convert_to_mode (Pmode, op0, false),
@@ -2595,20 +2672,8 @@ tilegx_expand_tablejump (rtx op0, rtx op1)
 void
 tilegx_pre_atomic_barrier (enum memmodel model)
 {
-  switch (model)
-    {
-    case MEMMODEL_RELAXED:
-    case MEMMODEL_CONSUME:
-    case MEMMODEL_ACQUIRE:
-      break;
-    case MEMMODEL_RELEASE:
-    case MEMMODEL_ACQ_REL:
-    case MEMMODEL_SEQ_CST:
-      emit_insn (gen_memory_barrier ());
-      break;
-    default:
-      gcc_unreachable ();
-    }
+  if (need_atomic_barrier_p (model, true))
+    emit_insn (gen_memory_barrier ());
 }
 
 
@@ -2616,20 +2681,8 @@ tilegx_pre_atomic_barrier (enum memmodel model)
 void
 tilegx_post_atomic_barrier (enum memmodel model)
 {
-  switch (model)
-    {
-    case MEMMODEL_RELAXED:
-    case MEMMODEL_CONSUME:
-    case MEMMODEL_RELEASE:
-      break;
-    case MEMMODEL_ACQUIRE:
-    case MEMMODEL_ACQ_REL:
-    case MEMMODEL_SEQ_CST:
-      emit_insn (gen_memory_barrier ());
-      break;
-    default:
-      gcc_unreachable ();
-    }
+  if (need_atomic_barrier_p (model, false))
+    emit_insn (gen_memory_barrier ());
 }
 
 
@@ -3703,7 +3756,7 @@ emit_sp_adjust (int offset, int *next_scratch_regno, bool frame_related,
 static bool
 tilegx_current_function_is_leaf (void)
 {
-  return current_function_is_leaf && !cfun->machine->calls_tls_get_addr;
+  return crtl->is_leaf && !cfun->machine->calls_tls_get_addr;
 }
 
 
@@ -3903,8 +3956,6 @@ tilegx_expand_prologue (void)
          address.  */
       rtx chain_addr = gen_rtx_REG (Pmode, next_scratch_regno--);
       rtx size_rtx = GEN_INT (-(total_size - UNITS_PER_WORD));
-      int cfa_offset =
-       frame_pointer_needed ? UNITS_PER_WORD - total_size : UNITS_PER_WORD;
 
       if (add_operand (size_rtx, Pmode))
        {
@@ -4827,7 +4878,6 @@ tilegx_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
      serial except for the tail call, so we're only wasting one cycle.
    */
   insn = get_insns ();
-  insn_locators_alloc ();
   shorten_branches (insn);
   final_start_function (insn, file, 1);
   final (insn, file, 1);
@@ -4890,7 +4940,7 @@ tilegx_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
 
   /* Get pointers to the beginning and end of the code block.  */
   begin_addr = force_reg (Pmode, XEXP (m_tramp, 0));
-  end_addr = force_reg (Pmode, plus_constant (XEXP (m_tramp, 0),
+  end_addr = force_reg (Pmode, plus_constant (Pmode, XEXP (m_tramp, 0),
                                              TRAMPOLINE_SIZE));
 
   emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"),
@@ -4984,6 +5034,7 @@ tilegx_print_operand (FILE *file, rtx x, int code)
              opstr = "hw0";
              break;
            case UNSPEC_HW1:
+           case UNSPEC_HW1_PCREL:
              opstr = "hw1";
              break;
            case UNSPEC_HW2:
@@ -5000,6 +5051,7 @@ tilegx_print_operand (FILE *file, rtx x, int code)
              opstr = "hw1_last";
              break;
            case UNSPEC_HW2_LAST:
+           case UNSPEC_HW2_LAST_PCREL:
              opstr = "hw2_last";
              break;
            case UNSPEC_HW0_GOT:
@@ -5029,6 +5081,18 @@ tilegx_print_operand (FILE *file, rtx x, int code)
            case UNSPEC_HW1_LAST_TLS_LE:
              opstr = "hw1_last_tls_le";
              break;
+           case UNSPEC_HW0_PLT_PCREL:
+             opstr = "hw0_plt";
+             break;
+           case UNSPEC_HW1_PLT_PCREL:
+             opstr = "hw1_plt";
+             break;
+           case UNSPEC_HW1_LAST_PLT_PCREL:
+             opstr = "hw1_last_plt";
+             break;
+           case UNSPEC_HW2_LAST_PLT_PCREL:
+             opstr = "hw2_last_plt";
+             break;
            default:
              output_operand_lossage ("invalid %%H specifier");
            }
@@ -5038,7 +5102,13 @@ tilegx_print_operand (FILE *file, rtx x, int code)
          output_addr_const (file, addr);
 
          if (unspec == UNSPEC_HW0_PCREL
-             || unspec == UNSPEC_HW1_LAST_PCREL)
+             || unspec == UNSPEC_HW1_PCREL
+             || unspec == UNSPEC_HW1_LAST_PCREL
+             || unspec == UNSPEC_HW2_LAST_PCREL
+             || unspec == UNSPEC_HW0_PLT_PCREL
+             || unspec == UNSPEC_HW1_PLT_PCREL
+             || unspec == UNSPEC_HW1_LAST_PLT_PCREL
+             || unspec == UNSPEC_HW2_LAST_PLT_PCREL)
            {
              rtx addr2 = XVECEXP (XEXP (x, 0), 0, 1);
              fputs (" - " , file);