/* 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.
#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"
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)
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));
}
{
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 -
/* 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);
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));
}
+/* 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
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
}
/* 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;
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:
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;
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)));
/* 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)));
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),
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 ());
}
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 ());
}
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;
}
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))
{
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);
/* 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"),
opstr = "hw0";
break;
case UNSPEC_HW1:
+ case UNSPEC_HW1_PCREL:
opstr = "hw1";
break;
case UNSPEC_HW2:
opstr = "hw1_last";
break;
case UNSPEC_HW2_LAST:
+ case UNSPEC_HW2_LAST_PCREL:
opstr = "hw2_last";
break;
case UNSPEC_HW0_GOT:
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");
}
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);