/* The Blackfin code generation auxiliary output file.
- Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
Contributed by Analog Devices.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 2, or (at your
+ by the Free Software Foundation; either version 3, or (at your
option) any later version.
GCC is distributed in the hope that it will be useful, but WITHOUT
License for more details.
You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING. If not, write to
- the Free Software Foundation, 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "langhooks.h"
#include "bfin-protos.h"
#include "tm-preds.h"
+#include "tm-constrs.h"
#include "gt-bfin.h"
#include "basic-block.h"
#include "cfglayout.h"
/* -mcpu support */
bfin_cpu_t bfin_cpu_type = DEFAULT_CPU_TYPE;
+/* -msi-revision support. There are three special values:
+ -1 -msi-revision=none.
+ 0xffff -msi-revision=any. */
+int bfin_si_revision;
+
+/* The workarounds enabled */
+unsigned int bfin_workarounds = 0;
+
+static bool cputype_selected = false;
+
+struct bfin_cpu
+{
+ const char *name;
+ bfin_cpu_t type;
+ int si_revision;
+ unsigned int workarounds;
+};
+
+struct bfin_cpu bfin_cpus[] =
+{
+ {"bf522", BFIN_CPU_BF522, 0x0000,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+
+ {"bf523", BFIN_CPU_BF523, 0x0000,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+
+ {"bf524", BFIN_CPU_BF524, 0x0000,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+
+ {"bf525", BFIN_CPU_BF525, 0x0000,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+
+ {"bf526", BFIN_CPU_BF526, 0x0000,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+
+ {"bf527", BFIN_CPU_BF527, 0x0000,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+
+ {"bf531", BFIN_CPU_BF531, 0x0005,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+ {"bf531", BFIN_CPU_BF531, 0x0004,
+ WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
+ {"bf531", BFIN_CPU_BF531, 0x0003,
+ WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
+
+ {"bf532", BFIN_CPU_BF532, 0x0005,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+ {"bf532", BFIN_CPU_BF532, 0x0004,
+ WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
+ {"bf532", BFIN_CPU_BF532, 0x0003,
+ WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
+
+ {"bf533", BFIN_CPU_BF533, 0x0005,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+ {"bf533", BFIN_CPU_BF533, 0x0004,
+ WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
+ {"bf533", BFIN_CPU_BF533, 0x0003,
+ WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
+
+ {"bf534", BFIN_CPU_BF534, 0x0003,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+ {"bf534", BFIN_CPU_BF534, 0x0002,
+ WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
+ {"bf534", BFIN_CPU_BF534, 0x0001,
+ WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
+
+ {"bf536", BFIN_CPU_BF536, 0x0003,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+ {"bf536", BFIN_CPU_BF536, 0x0002,
+ WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
+ {"bf536", BFIN_CPU_BF536, 0x0001,
+ WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
+
+ {"bf537", BFIN_CPU_BF537, 0x0003,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+ {"bf537", BFIN_CPU_BF537, 0x0002,
+ WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
+ {"bf537", BFIN_CPU_BF537, 0x0001,
+ WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
+
+ {"bf538", BFIN_CPU_BF538, 0x0004,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+ {"bf538", BFIN_CPU_BF538, 0x0003,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+
+ {"bf539", BFIN_CPU_BF539, 0x0004,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+ {"bf539", BFIN_CPU_BF539, 0x0003,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+ {"bf539", BFIN_CPU_BF539, 0x0002,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+
+ {"bf542", BFIN_CPU_BF542, 0x0000,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+
+ {"bf544", BFIN_CPU_BF544, 0x0000,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+
+ {"bf547", BFIN_CPU_BF547, 0x0000,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+
+ {"bf548", BFIN_CPU_BF548, 0x0000,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+
+ {"bf549", BFIN_CPU_BF549, 0x0000,
+ WA_SPECULATIVE_LOADS | WA_RETS},
+
+ {"bf561", BFIN_CPU_BF561, 0x0005, WA_RETS},
+ {"bf561", BFIN_CPU_BF561, 0x0003,
+ WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
+ {"bf561", BFIN_CPU_BF561, 0x0002,
+ WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
+
+ {NULL, 0, 0, 0}
+};
+
int splitting_for_sched;
static void
/* Examine machine-dependent attributes of function type FUNTYPE and return its
type. See the definition of E_FUNKIND. */
-static e_funkind funkind (tree funtype)
+static e_funkind
+funkind (const_tree funtype)
{
tree attrs = TYPE_ATTRIBUTES (funtype);
if (lookup_attribute ("interrupt_handler", attrs))
emit_move_insn (reg, new);
if (picreg == pic_offset_table_rtx)
- current_function_uses_pic_offset_table = 1;
+ crtl->uses_pic_offset_table = 1;
return reg;
}
\f
/* Stack frame layout. */
-/* Compute the number of DREGS to save with a push_multiple operation.
- This could include registers that aren't modified in the function,
- since push_multiple only takes a range of registers.
- If IS_INTHANDLER, then everything that is live must be saved, even
- if normally call-clobbered. */
-
-static int
-n_dregs_to_save (bool is_inthandler)
+/* For a given REGNO, determine whether it must be saved in the function
+ prologue. IS_INTHANDLER specifies whether we're generating a normal
+ prologue or an interrupt/exception one. */
+static bool
+must_save_p (bool is_inthandler, unsigned regno)
{
- unsigned i;
-
- for (i = REG_R0; i <= REG_R7; i++)
+ if (D_REGNO_P (regno))
{
- if (df_regs_ever_live_p (i) && (is_inthandler || ! call_used_regs[i]))
- return REG_R7 - i + 1;
-
- if (current_function_calls_eh_return)
+ bool is_eh_return_reg = false;
+ if (crtl->calls_eh_return)
{
unsigned j;
for (j = 0; ; j++)
unsigned test = EH_RETURN_DATA_REGNO (j);
if (test == INVALID_REGNUM)
break;
- if (test == i)
- return REG_R7 - i + 1;
+ if (test == regno)
+ is_eh_return_reg = true;
}
}
+ return (is_eh_return_reg
+ || (df_regs_ever_live_p (regno)
+ && !fixed_regs[regno]
+ && (is_inthandler || !call_used_regs[regno])));
}
- return 0;
+ else if (P_REGNO_P (regno))
+ {
+ return ((df_regs_ever_live_p (regno)
+ && !fixed_regs[regno]
+ && (is_inthandler || !call_used_regs[regno]))
+ || (!TARGET_FDPIC
+ && regno == PIC_OFFSET_TABLE_REGNUM
+ && (crtl->uses_pic_offset_table
+ || (TARGET_ID_SHARED_LIBRARY && !current_function_is_leaf))));
+ }
+ else
+ return ((is_inthandler || !call_used_regs[regno])
+ && (df_regs_ever_live_p (regno)
+ || (!leaf_function_p () && call_used_regs[regno])));
+
+}
+
+/* Compute the number of DREGS to save with a push_multiple operation.
+ This could include registers that aren't modified in the function,
+ since push_multiple only takes a range of registers.
+ If IS_INTHANDLER, then everything that is live must be saved, even
+ if normally call-clobbered.
+ If CONSECUTIVE, return the number of registers we can save in one
+ instruction with a push/pop multiple instruction. */
+
+static int
+n_dregs_to_save (bool is_inthandler, bool consecutive)
+{
+ int count = 0;
+ unsigned i;
+
+ for (i = REG_R7 + 1; i-- != REG_R0;)
+ {
+ if (must_save_p (is_inthandler, i))
+ count++;
+ else if (consecutive)
+ return count;
+ }
+ return count;
}
/* Like n_dregs_to_save, but compute number of PREGS to save. */
static int
-n_pregs_to_save (bool is_inthandler)
+n_pregs_to_save (bool is_inthandler, bool consecutive)
{
+ int count = 0;
unsigned i;
- for (i = REG_P0; i <= REG_P5; i++)
- if ((df_regs_ever_live_p (i) && (is_inthandler || ! call_used_regs[i]))
- || (!TARGET_FDPIC
- && i == PIC_OFFSET_TABLE_REGNUM
- && (current_function_uses_pic_offset_table
- || (TARGET_ID_SHARED_LIBRARY && ! current_function_is_leaf))))
- return REG_P5 - i + 1;
- return 0;
+ for (i = REG_P5 + 1; i-- != REG_P0;)
+ if (must_save_p (is_inthandler, i))
+ count++;
+ else if (consecutive)
+ return count;
+ return count;
}
/* Determine if we are going to save the frame pointer in the prologue. */
{
/* EH return puts a new return address into the frame using an
address relative to the frame pointer. */
- if (current_function_calls_eh_return)
+ if (crtl->calls_eh_return)
return true;
return frame_pointer_needed;
}
static void
expand_prologue_reg_save (rtx spreg, int saveall, bool is_inthandler)
{
- int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler);
- int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler);
- int dregno = REG_R7 + 1 - ndregs;
- int pregno = REG_P5 + 1 - npregs;
- int total = ndregs + npregs;
- int i;
- rtx pat, insn, val;
+ rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
+ rtx predec = gen_rtx_MEM (SImode, predec1);
+ int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler, false);
+ int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler, false);
+ int ndregs_consec = saveall ? 8 : n_dregs_to_save (is_inthandler, true);
+ int npregs_consec = saveall ? 6 : n_pregs_to_save (is_inthandler, true);
+ int dregno, pregno;
+ int total_consec = ndregs_consec + npregs_consec;
+ int i, d_to_save;
+
+ if (saveall || is_inthandler)
+ {
+ rtx insn = emit_move_insn (predec, gen_rtx_REG (SImode, REG_ASTAT));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
- if (total == 0)
- return;
+ if (total_consec != 0)
+ {
+ rtx insn;
+ rtx val = GEN_INT (-total_consec * 4);
+ rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_consec + 2));
+
+ XVECEXP (pat, 0, 0) = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, val),
+ UNSPEC_PUSH_MULTIPLE);
+ XVECEXP (pat, 0, total_consec + 1) = gen_rtx_SET (VOIDmode, spreg,
+ gen_rtx_PLUS (Pmode,
+ spreg,
+ val));
+ RTX_FRAME_RELATED_P (XVECEXP (pat, 0, total_consec + 1)) = 1;
+ d_to_save = ndregs_consec;
+ dregno = REG_R7 + 1 - ndregs_consec;
+ pregno = REG_P5 + 1 - npregs_consec;
+ for (i = 0; i < total_consec; i++)
+ {
+ rtx memref = gen_rtx_MEM (word_mode,
+ gen_rtx_PLUS (Pmode, spreg,
+ GEN_INT (- i * 4 - 4)));
+ rtx subpat;
+ if (d_to_save > 0)
+ {
+ subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
+ dregno++));
+ d_to_save--;
+ }
+ else
+ {
+ subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
+ pregno++));
+ }
+ XVECEXP (pat, 0, i + 1) = subpat;
+ RTX_FRAME_RELATED_P (subpat) = 1;
+ }
+ insn = emit_insn (pat);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
- val = GEN_INT (-total * 4);
- pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total + 2));
- XVECEXP (pat, 0, 0) = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, val),
- UNSPEC_PUSH_MULTIPLE);
- XVECEXP (pat, 0, total + 1) = gen_rtx_SET (VOIDmode, spreg,
- gen_rtx_PLUS (Pmode, spreg,
- val));
- RTX_FRAME_RELATED_P (XVECEXP (pat, 0, total + 1)) = 1;
- for (i = 0; i < total; i++)
- {
- rtx memref = gen_rtx_MEM (word_mode,
- gen_rtx_PLUS (Pmode, spreg,
- GEN_INT (- i * 4 - 4)));
- rtx subpat;
- if (ndregs > 0)
+ for (dregno = REG_R0; ndregs != ndregs_consec; dregno++)
+ {
+ if (must_save_p (is_inthandler, dregno))
{
- subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
- dregno++));
+ rtx insn = emit_move_insn (predec, gen_rtx_REG (word_mode, dregno));
+ RTX_FRAME_RELATED_P (insn) = 1;
ndregs--;
}
- else
+ }
+ for (pregno = REG_P0; npregs != npregs_consec; pregno++)
+ {
+ if (must_save_p (is_inthandler, pregno))
{
- subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
- pregno++));
- npregs++;
+ rtx insn = emit_move_insn (predec, gen_rtx_REG (word_mode, pregno));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ npregs--;
}
- XVECEXP (pat, 0, i + 1) = subpat;
- RTX_FRAME_RELATED_P (subpat) = 1;
}
- insn = emit_insn (pat);
- RTX_FRAME_RELATED_P (insn) = 1;
+ for (i = REG_P7 + 1; i < REG_CC; i++)
+ if (saveall
+ || (is_inthandler
+ && (df_regs_ever_live_p (i)
+ || (!leaf_function_p () && call_used_regs[i]))))
+ {
+ rtx insn;
+ if (i == REG_A0 || i == REG_A1)
+ insn = emit_move_insn (gen_rtx_MEM (PDImode, predec1),
+ gen_rtx_REG (PDImode, i));
+ else
+ insn = emit_move_insn (predec, gen_rtx_REG (SImode, i));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
}
/* Emit code to restore registers in the epilogue. SAVEALL is nonzero if we
static void
expand_epilogue_reg_restore (rtx spreg, bool saveall, bool is_inthandler)
{
- int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler);
- int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler);
- int total = ndregs + npregs;
- int i, regno;
- rtx pat, insn;
+ rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
+ rtx postinc = gen_rtx_MEM (SImode, postinc1);
- if (total == 0)
- return;
+ int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler, false);
+ int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler, false);
+ int ndregs_consec = saveall ? 8 : n_dregs_to_save (is_inthandler, true);
+ int npregs_consec = saveall ? 6 : n_pregs_to_save (is_inthandler, true);
+ int total_consec = ndregs_consec + npregs_consec;
+ int i, regno;
+ rtx insn;
- pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total + 1));
- XVECEXP (pat, 0, 0) = gen_rtx_SET (VOIDmode, spreg,
- gen_rtx_PLUS (Pmode, spreg,
- GEN_INT (total * 4)));
+ /* A slightly crude technique to stop flow from trying to delete "dead"
+ insns. */
+ MEM_VOLATILE_P (postinc) = 1;
- if (npregs > 0)
- regno = REG_P5 + 1;
- else
- regno = REG_R7 + 1;
+ for (i = REG_CC - 1; i > REG_P7; i--)
+ if (saveall
+ || (is_inthandler
+ && (df_regs_ever_live_p (i)
+ || (!leaf_function_p () && call_used_regs[i]))))
+ {
+ if (i == REG_A0 || i == REG_A1)
+ {
+ rtx mem = gen_rtx_MEM (PDImode, postinc1);
+ MEM_VOLATILE_P (mem) = 1;
+ emit_move_insn (gen_rtx_REG (PDImode, i), mem);
+ }
+ else
+ emit_move_insn (gen_rtx_REG (SImode, i), postinc);
+ }
- for (i = 0; i < total; i++)
+ regno = REG_P5 - npregs_consec;
+ for (; npregs != npregs_consec; regno--)
{
- rtx addr = (i > 0
- ? gen_rtx_PLUS (Pmode, spreg, GEN_INT (i * 4))
- : spreg);
- rtx memref = gen_rtx_MEM (word_mode, addr);
+ if (must_save_p (is_inthandler, regno))
+ {
+ emit_move_insn (gen_rtx_REG (word_mode, regno), postinc);
+ npregs--;
+ }
+ }
+ regno = REG_R7 - ndregs_consec;
+ for (; ndregs != ndregs_consec; regno--)
+ {
+ if (must_save_p (is_inthandler, regno))
+ {
+ emit_move_insn (gen_rtx_REG (word_mode, regno), postinc);
+ ndregs--;
+ }
+ }
- regno--;
- XVECEXP (pat, 0, i + 1)
- = gen_rtx_SET (VOIDmode, gen_rtx_REG (word_mode, regno), memref);
+ if (total_consec != 0)
+ {
+ rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_consec + 1));
+ XVECEXP (pat, 0, 0)
+ = gen_rtx_SET (VOIDmode, spreg,
+ gen_rtx_PLUS (Pmode, spreg,
+ GEN_INT (total_consec * 4)));
+
+ if (npregs_consec > 0)
+ regno = REG_P5 + 1;
+ else
+ regno = REG_R7 + 1;
- if (npregs > 0)
+ for (i = 0; i < total_consec; i++)
{
- if (--npregs == 0)
- regno = REG_R7 + 1;
+ rtx addr = (i > 0
+ ? gen_rtx_PLUS (Pmode, spreg, GEN_INT (i * 4))
+ : spreg);
+ rtx memref = gen_rtx_MEM (word_mode, addr);
+
+ regno--;
+ XVECEXP (pat, 0, i + 1)
+ = gen_rtx_SET (VOIDmode, gen_rtx_REG (word_mode, regno), memref);
+
+ if (npregs_consec > 0)
+ {
+ if (--npregs_consec == 0)
+ regno = REG_R7 + 1;
+ }
}
- }
- insn = emit_insn (pat);
- RTX_FRAME_RELATED_P (insn) = 1;
+ insn = emit_insn (pat);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ if (saveall || is_inthandler)
+ emit_move_insn (gen_rtx_REG (SImode, REG_ASTAT), postinc);
}
/* Perform any needed actions needed for a function that is receiving a
tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
bool all = (lookup_attribute ("saveall", attrs) != NULL_TREE
|| (is_inthandler && !current_function_is_leaf));
- int ndregs = all ? 8 : n_dregs_to_save (is_inthandler);
- int npregs = all ? 6 : n_pregs_to_save (is_inthandler);
+ int ndregs = all ? 8 : n_dregs_to_save (is_inthandler, false);
+ int npregs = all ? 6 : n_pregs_to_save (is_inthandler, false);
int n = ndregs + npregs;
+ int i;
if (all || stack_frame_needed_p ())
/* We use a LINK instruction in this case. */
n++;
}
+ if (fkind != SUBROUTINE || all)
+ /* Increment once for ASTAT. */
+ n++;
+
if (fkind != SUBROUTINE)
{
- int i;
-
- /* Increment once for ASTAT. */
- n++;
-
/* RETE/X/N. */
if (lookup_attribute ("nesting", attrs))
n++;
-
- for (i = REG_P7 + 1; i < REG_CC; i++)
- if (all
- || df_regs_ever_live_p (i)
- || (!leaf_function_p () && call_used_regs[i]))
- n += i == REG_A0 || i == REG_A1 ? 2 : 1;
}
+
+ for (i = REG_P7 + 1; i < REG_CC; i++)
+ if (all
+ || (fkind != SUBROUTINE
+ && (df_regs_ever_live_p (i)
+ || (!leaf_function_p () && call_used_regs[i]))))
+ n += i == REG_A0 || i == REG_A1 ? 2 : 1;
+
return n;
}
if (to == STACK_POINTER_REGNUM)
{
- if (current_function_outgoing_args_size >= FIXED_STACK_AREA)
- offset += current_function_outgoing_args_size;
- else if (current_function_outgoing_args_size)
+ if (crtl->outgoing_args_size >= FIXED_STACK_AREA)
+ offset += crtl->outgoing_args_size;
+ else if (crtl->outgoing_args_size)
offset += FIXED_STACK_AREA;
offset += get_frame_size ();
if ((df_regs_ever_live_p (i) && ! call_used_regs[i])
|| (!TARGET_FDPIC
&& i == PIC_OFFSET_TABLE_REGNUM
- && (current_function_uses_pic_offset_table
+ && (crtl->uses_pic_offset_table
|| (TARGET_ID_SHARED_LIBRARY
&& ! current_function_is_leaf))))
break;
static HOST_WIDE_INT
arg_area_size (void)
{
- if (current_function_outgoing_args_size)
+ if (crtl->outgoing_args_size)
{
- if (current_function_outgoing_args_size >= FIXED_STACK_AREA)
- return current_function_outgoing_args_size;
+ if (crtl->outgoing_args_size >= FIXED_STACK_AREA)
+ return crtl->outgoing_args_size;
else
return FIXED_STACK_AREA;
}
SPREG contains (reg:SI REG_SP). */
static void
-expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind)
+expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind, bool all)
{
- int i;
HOST_WIDE_INT frame_size = get_frame_size ();
rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
rtx predec = gen_rtx_MEM (SImode, predec1);
rtx insn;
tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
- bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
tree kspisusp = lookup_attribute ("kspisusp", attrs);
if (kspisusp)
RTX_FRAME_RELATED_P (insn) = 1;
}
- insn = emit_move_insn (predec, gen_rtx_REG (SImode, REG_ASTAT));
- RTX_FRAME_RELATED_P (insn) = 1;
-
/* If we're calling other functions, they won't save their call-clobbered
registers, so we must save everything here. */
if (!current_function_is_leaf)
all = true;
expand_prologue_reg_save (spreg, all, true);
- for (i = REG_P7 + 1; i < REG_CC; i++)
- if (all
- || df_regs_ever_live_p (i)
- || (!leaf_function_p () && call_used_regs[i]))
- {
- if (i == REG_A0 || i == REG_A1)
- insn = emit_move_insn (gen_rtx_MEM (PDImode, predec1),
- gen_rtx_REG (PDImode, i));
- else
- insn = emit_move_insn (predec, gen_rtx_REG (SImode, i));
- RTX_FRAME_RELATED_P (insn) = 1;
- }
-
if (lookup_attribute ("nesting", attrs))
{
rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
SPREG contains (reg:SI REG_SP). */
static void
-expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind)
+expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind, bool all)
{
- int i;
+ tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
rtx postinc = gen_rtx_MEM (SImode, postinc1);
- tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
- bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
/* A slightly crude technique to stop flow from trying to delete "dead"
insns. */
if (!current_function_is_leaf)
all = true;
- for (i = REG_CC - 1; i > REG_P7; i--)
- if (all
- || df_regs_ever_live_p (i)
- || (!leaf_function_p () && call_used_regs[i]))
- {
- if (i == REG_A0 || i == REG_A1)
- {
- rtx mem = gen_rtx_MEM (PDImode, postinc1);
- MEM_VOLATILE_P (mem) = 1;
- emit_move_insn (gen_rtx_REG (PDImode, i), mem);
- }
- else
- emit_move_insn (gen_rtx_REG (SImode, i), postinc);
- }
-
expand_epilogue_reg_restore (spreg, all, true);
- emit_move_insn (gen_rtx_REG (SImode, REG_ASTAT), postinc);
-
/* Deallocate any space we left on the stack in case we needed to save the
argument registers. */
if (fkind == EXCPT_HANDLER)
rtx spreg = gen_rtx_REG (Pmode, REG_SP);
e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
rtx pic_reg_loaded = NULL_RTX;
+ tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
+ bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
if (fkind != SUBROUTINE)
{
- expand_interrupt_handler_prologue (spreg, fkind);
+ expand_interrupt_handler_prologue (spreg, fkind, all);
return;
}
- if (current_function_limit_stack
+ if (crtl->limit_stack
|| TARGET_STACK_CHECK_L1)
{
HOST_WIDE_INT offset
= bfin_initial_elimination_offset (ARG_POINTER_REGNUM,
STACK_POINTER_REGNUM);
- rtx lim = current_function_limit_stack ? stack_limit_rtx : NULL_RTX;
+ rtx lim = crtl->limit_stack ? stack_limit_rtx : NULL_RTX;
rtx p2reg = gen_rtx_REG (Pmode, REG_P2);
if (!lim)
emit_insn (gen_compare_lt (bfin_cc_rtx, spreg, lim));
emit_insn (gen_trapifcc ());
}
- expand_prologue_reg_save (spreg, 0, false);
+ expand_prologue_reg_save (spreg, all, false);
do_link (spreg, frame_size, false);
if (TARGET_ID_SHARED_LIBRARY
&& !TARGET_SEP_DATA
- && (current_function_uses_pic_offset_table
+ && (crtl->uses_pic_offset_table
|| !current_function_is_leaf))
bfin_load_pic_reg (pic_offset_table_rtx);
}
rtx spreg = gen_rtx_REG (Pmode, REG_SP);
e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
int e = sibcall_p ? -1 : 1;
+ tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
+ bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
if (fkind != SUBROUTINE)
{
- expand_interrupt_handler_epilogue (spreg, fkind);
+ expand_interrupt_handler_epilogue (spreg, fkind, all);
return;
}
do_unlink (spreg, get_frame_size (), false, e);
- expand_epilogue_reg_restore (spreg, false, false);
+ expand_epilogue_reg_restore (spreg, all, false);
/* Omit the return insn if this is for a sibcall. */
if (! need_return)
case REG:
if (code == 'h')
{
- gcc_assert (REGNO (x) < 32);
- fprintf (file, "%s", short_reg_names[REGNO (x)]);
- /*fprintf (file, "\n%d\n ", REGNO (x));*/
- break;
+ if (REGNO (x) < 32)
+ fprintf (file, "%s", short_reg_names[REGNO (x)]);
+ else
+ output_operand_lossage ("invalid operand for code '%c'", code);
}
else if (code == 'd')
{
- gcc_assert (REGNO (x) < 32);
- fprintf (file, "%s", high_reg_names[REGNO (x)]);
- break;
+ if (REGNO (x) < 32)
+ fprintf (file, "%s", high_reg_names[REGNO (x)]);
+ else
+ output_operand_lossage ("invalid operand for code '%c'", code);
}
else if (code == 'w')
{
- gcc_assert (REGNO (x) == REG_A0 || REGNO (x) == REG_A1);
- fprintf (file, "%s.w", reg_names[REGNO (x)]);
+ if (REGNO (x) == REG_A0 || REGNO (x) == REG_A1)
+ fprintf (file, "%s.w", reg_names[REGNO (x)]);
+ else
+ output_operand_lossage ("invalid operand for code '%c'", code);
}
else if (code == 'x')
{
- gcc_assert (REGNO (x) == REG_A0 || REGNO (x) == REG_A1);
- fprintf (file, "%s.x", reg_names[REGNO (x)]);
+ if (REGNO (x) == REG_A0 || REGNO (x) == REG_A1)
+ fprintf (file, "%s.x", reg_names[REGNO (x)]);
+ else
+ output_operand_lossage ("invalid operand for code '%c'", code);
}
else if (code == 'v')
{
}
else if (code == 'D')
{
- fprintf (file, "%s", dregs_pair_names[REGNO (x)]);
+ if (D_REGNO_P (REGNO (x)))
+ fprintf (file, "%s", dregs_pair_names[REGNO (x)]);
+ else
+ output_operand_lossage ("invalid operand for code '%c'", code);
}
else if (code == 'H')
{
- gcc_assert (mode == DImode || mode == DFmode);
- gcc_assert (REG_P (x));
- fprintf (file, "%s", reg_names[REGNO (x) + 1]);
+ if ((mode == DImode || mode == DFmode) && REG_P (x))
+ fprintf (file, "%s", reg_names[REGNO (x) + 1]);
+ else
+ output_operand_lossage ("invalid operand for code '%c'", code);
}
else if (code == 'T')
{
- gcc_assert (D_REGNO_P (REGNO (x)));
- fprintf (file, "%s", byte_reg_names[REGNO (x)]);
+ if (D_REGNO_P (REGNO (x)))
+ fprintf (file, "%s", byte_reg_names[REGNO (x)]);
+ else
+ output_operand_lossage ("invalid operand for code '%c'", code);
}
else
fprintf (file, "%s", reg_names[REGNO (x)]);
static bool
bfin_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
enum machine_mode mode ATTRIBUTE_UNUSED,
- tree type, bool named ATTRIBUTE_UNUSED)
+ const_tree type, bool named ATTRIBUTE_UNUSED)
{
return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
}
/* Decide whether a type should be returned in memory (true)
or in a register (false). This is called by the macro
- RETURN_IN_MEMORY. */
+ TARGET_RETURN_IN_MEMORY. */
-int
-bfin_return_in_memory (tree type)
+static bool
+bfin_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
{
int size = int_size_in_bytes (type);
return size > 2 * UNITS_PER_WORD || size == -1;
if (TARGET_FDPIC)
{
+ int caller_has_l1_text, callee_has_l1_text;
+
+ caller_has_l1_text = callee_has_l1_text = 0;
+
+ if (lookup_attribute ("l1_text",
+ DECL_ATTRIBUTES (cfun->decl)) != NULL_TREE)
+ caller_has_l1_text = 1;
+
+ if (GET_CODE (callee) == SYMBOL_REF
+ && SYMBOL_REF_DECL (callee) && DECL_P (SYMBOL_REF_DECL (callee))
+ && lookup_attribute
+ ("l1_text",
+ DECL_ATTRIBUTES (SYMBOL_REF_DECL (callee))) != NULL_TREE)
+ callee_has_l1_text = 1;
+
if (GET_CODE (callee) != SYMBOL_REF
- || bfin_longcall_p (callee, INTVAL (cookie)))
+ || bfin_longcall_p (callee, INTVAL (cookie))
+ || (GET_CODE (callee) == SYMBOL_REF
+ && !SYMBOL_REF_LOCAL_P (callee)
+ && TARGET_INLINE_PLT)
+ || caller_has_l1_text != callee_has_l1_text
+ || (caller_has_l1_text && callee_has_l1_text
+ && (GET_CODE (callee) != SYMBOL_REF
+ || !SYMBOL_REF_LOCAL_P (callee))))
{
rtx addr = callee;
if (! address_operand (addr, Pmode))
scratch register. */
static enum reg_class
-bfin_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x, enum reg_class class,
- enum machine_mode mode, secondary_reload_info *sri)
+bfin_secondary_reload (bool in_p, rtx x, enum reg_class class,
+ enum machine_mode mode, secondary_reload_info *sri)
{
/* If we have HImode or QImode, we can only use DREGS as secondary registers;
in most other cases we can also use PREGS. */
if (fp_plus_const_operand (x, mode))
{
rtx op2 = XEXP (x, 1);
- int large_constant_p = ! CONST_7BIT_IMM_P (INTVAL (op2));
+ int large_constant_p = ! satisfies_constraint_Ks7 (op2);
if (class == PREGS || class == PREGS_CLOBBERED)
return NO_REGS;
if (class == AREGS || class == EVEN_AREGS || class == ODD_AREGS)
{
+ if (code == MEM)
+ {
+ sri->icode = in_p ? CODE_FOR_reload_inpdi : CODE_FOR_reload_outpdi;
+ return NO_REGS;
+ }
+
if (x != const0_rtx && x_class != DREGS)
- return DREGS;
+ {
+ return DREGS;
+ }
else
return NO_REGS;
}
if (code == MEM)
if (! reg_class_subset_p (class, default_class))
return default_class;
+
return NO_REGS;
}
\f
return true;
case OPT_mcpu_:
- if (strcmp (arg, "bf531") == 0)
- bfin_cpu_type = BFIN_CPU_BF531;
- else if (strcmp (arg, "bf532") == 0)
- bfin_cpu_type = BFIN_CPU_BF532;
- else if (strcmp (arg, "bf533") == 0)
- bfin_cpu_type = BFIN_CPU_BF533;
- else if (strcmp (arg, "bf534") == 0)
- bfin_cpu_type = BFIN_CPU_BF534;
- else if (strcmp (arg, "bf536") == 0)
- bfin_cpu_type = BFIN_CPU_BF536;
- else if (strcmp (arg, "bf537") == 0)
- bfin_cpu_type = BFIN_CPU_BF537;
- else if (strcmp (arg, "bf561") == 0)
- {
+ {
+ const char *p, *q;
+ int i;
+
+ i = 0;
+ while ((p = bfin_cpus[i].name) != NULL)
+ {
+ if (strncmp (arg, p, strlen (p)) == 0)
+ break;
+ i++;
+ }
+
+ if (p == NULL)
+ {
+ error ("-mcpu=%s is not valid", arg);
+ return false;
+ }
+
+ bfin_cpu_type = bfin_cpus[i].type;
+
+ q = arg + strlen (p);
+
+ cputype_selected = true;
+
+ if (*q == '\0')
+ {
+ bfin_si_revision = bfin_cpus[i].si_revision;
+ bfin_workarounds |= bfin_cpus[i].workarounds;
+ }
+ else if (strcmp (q, "-none") == 0)
+ bfin_si_revision = -1;
+ else if (strcmp (q, "-any") == 0)
+ {
+ bfin_si_revision = 0xffff;
+ while (bfin_cpus[i].type == bfin_cpu_type)
+ {
+ bfin_workarounds |= bfin_cpus[i].workarounds;
+ i++;
+ }
+ }
+ else
+ {
+ unsigned int si_major, si_minor;
+ int rev_len, n;
+
+ rev_len = strlen (q);
+
+ if (sscanf (q, "-%u.%u%n", &si_major, &si_minor, &n) != 2
+ || n != rev_len
+ || si_major > 0xff || si_minor > 0xff)
+ {
+ invalid_silicon_revision:
+ error ("-mcpu=%s has invalid silicon revision", arg);
+ return false;
+ }
+
+ bfin_si_revision = (si_major << 8) | si_minor;
+
+ while (bfin_cpus[i].type == bfin_cpu_type
+ && bfin_cpus[i].si_revision != bfin_si_revision)
+ i++;
+
+ if (bfin_cpus[i].type != bfin_cpu_type)
+ goto invalid_silicon_revision;
+
+ bfin_workarounds |= bfin_cpus[i].workarounds;
+ }
+
+ if (bfin_cpu_type == BFIN_CPU_BF561)
warning (0, "bf561 support is incomplete yet.");
- bfin_cpu_type = BFIN_CPU_BF561;
- }
- else
- return false;
- return true;
+
+ return true;
+ }
default:
return true;
void
override_options (void)
{
+ if (bfin_csync_anomaly == 1)
+ bfin_workarounds |= WA_SPECULATIVE_SYNCS;
+ else if (bfin_csync_anomaly == 0)
+ bfin_workarounds &= ~WA_SPECULATIVE_SYNCS;
+
+ if (bfin_specld_anomaly == 1)
+ bfin_workarounds |= WA_SPECULATIVE_LOADS;
+ else if (bfin_specld_anomaly == 0)
+ bfin_workarounds &= ~WA_SPECULATIVE_LOADS;
+
+ if (!cputype_selected)
+ bfin_workarounds |= WA_RETS;
+
if (TARGET_OMIT_LEAF_FRAME_POINTER)
flag_omit_frame_pointer = 1;
if (bfin_lib_id_given && ! TARGET_ID_SHARED_LIBRARY)
error ("-mshared-library-id= specified without -mid-shared-library");
- if (TARGET_ID_SHARED_LIBRARY && flag_pic == 0)
- flag_pic = 1;
-
if (stack_limit_rtx && TARGET_STACK_CHECK_L1)
error ("Can't use multiple stack checking methods together.");
if (TARGET_SEP_DATA)
target_flags |= MASK_ID_SHARED_LIBRARY | MASK_LEAF_ID_SHARED_LIBRARY;
+ if (TARGET_ID_SHARED_LIBRARY && flag_pic == 0)
+ flag_pic = 1;
+
/* There is no single unaligned SI op for PIC code. Sometimes we
need to use ".4byte" and sometimes we need to use ".picptr".
See bfin_assemble_integer for details. */
if (D_REGNO_P (regno))
{
- if (CONST_7BIT_IMM_P (tmp))
+ if (tmp >= -64 && tmp <= 63)
{
emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
emit_insn (gen_movstricthi_high (operands[0], GEN_INT (val & -65536)));
return 0;
if (optimize_size
- && num_compl_zero && CONST_7BIT_IMM_P (shifted_compl))
+ && num_compl_zero && shifted_compl >= -64 && shifted_compl <= 63)
{
/* If optimizing for size, generate a sequence that has more instructions
but is shorter. */
{
case CONST_INT:
if (outer_code == SET || outer_code == PLUS)
- *total = CONST_7BIT_IMM_P (INTVAL (x)) ? 0 : cost2;
+ *total = satisfies_constraint_Ks7 (x) ? 0 : cost2;
else if (outer_code == AND)
*total = log2constp (~INTVAL (x)) ? 0 : cost2;
else if (outer_code == LE || outer_code == LT || outer_code == EQ)
{
*total = 6 * cost2;
if (GET_CODE (op1) != CONST_INT
- || !CONST_7BIT_IMM_P (INTVAL (op1)))
+ || !satisfies_constraint_Ks7 (op1))
*total += rtx_cost (op1, PLUS);
if (GET_CODE (op0) != REG
&& (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
if (dep_insn_type == TYPE_MOVE || dep_insn_type == TYPE_MCLD)
{
rtx pat = PATTERN (dep_insn);
+ if (GET_CODE (pat) == PARALLEL)
+ pat = XVECEXP (pat, 0, 0);
rtx dest = SET_DEST (pat);
rtx src = SET_SRC (pat);
if (! ADDRESS_REGNO_P (REGNO (dest))
int length = 0;
if (JUMP_P (insn) && any_condjump_p (insn) && !optimize_size)
{
- if (TARGET_CSYNC_ANOMALY)
+ if (ENABLE_WA_SPECULATIVE_SYNCS)
length = 8;
- else if (TARGET_SPECLD_ANOMALY)
+ else if (ENABLE_WA_SPECULATIVE_LOADS)
length = 6;
}
else if (LABEL_P (insn))
{
- if (TARGET_CSYNC_ANOMALY)
+ if (ENABLE_WA_SPECULATIVE_SYNCS)
length = 4;
}
if (cfun->machine->has_hardware_loops)
bfin_reorg_loops (dump_file);
- if (! TARGET_SPECLD_ANOMALY && ! TARGET_CSYNC_ANOMALY)
+ if (! ENABLE_WA_SPECULATIVE_LOADS && ! ENABLE_WA_SPECULATIVE_SYNCS)
return;
/* First pass: find predicted-false branches; if something after them
if (cycles_since_jump < INT_MAX)
cycles_since_jump++;
- if (load_insn && TARGET_SPECLD_ANOMALY)
+ if (load_insn && ENABLE_WA_SPECULATIVE_LOADS)
{
if (trapping_loads_p (load_insn))
delay_needed = 3;
}
- else if (type == TYPE_SYNC && TARGET_CSYNC_ANOMALY)
+ else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS)
delay_needed = 4;
if (delay_needed > cycles_since_jump)
}
/* Second pass: for predicted-true branches, see if anything at the
branch destination needs extra nops. */
- if (! TARGET_CSYNC_ANOMALY)
+ if (! ENABLE_WA_SPECULATIVE_SYNCS)
+ return;
+
+ if (! ENABLE_WA_RETS)
return;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (cycles_since_jump < INT_MAX)
cycles_since_jump++;
- if (type == TYPE_SYNC && TARGET_CSYNC_ANOMALY)
+ if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS)
delay_needed = 2;
if (delay_needed > cycles_since_jump)
reorder_var_tracking_notes ();
timevar_pop (TV_VAR_TRACKING);
}
- df_finish_pass ();
+ df_finish_pass (false);
}
\f
/* Handle interrupt_handler, exception_handler and nmi_handler function
warning to be generated). */
static int
-bfin_comp_type_attributes (tree type1, tree type2)
+bfin_comp_type_attributes (const_tree type1, const_tree type2)
{
e_funkind kind1, kind2;
return NULL_TREE;
}
+/* Handle a "l1_text" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+bfin_handle_l1_text_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ tree decl = *node;
+
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ {
+ error ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ /* The decl may have already been given a section attribute
+ from a previous declaration. Ensure they match. */
+ else if (DECL_SECTION_NAME (decl) != NULL_TREE
+ && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
+ ".l1.text") != 0)
+ {
+ error ("section of %q+D conflicts with previous declaration",
+ decl);
+ *no_add_attrs = true;
+ }
+ else
+ DECL_SECTION_NAME (decl) = build_string (9, ".l1.text");
+
+ return NULL_TREE;
+}
+
+/* Handle a "l1_data", "l1_data_A" or "l1_data_B" attribute;
+ arguments as in struct attribute_spec.handler. */
+
+static tree
+bfin_handle_l1_data_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ tree decl = *node;
+
+ if (TREE_CODE (decl) != VAR_DECL)
+ {
+ error ("`%s' attribute only applies to variables",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else if (current_function_decl != NULL_TREE
+ && !TREE_STATIC (decl))
+ {
+ error ("`%s' attribute cannot be specified for local variables",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else
+ {
+ const char *section_name;
+
+ if (strcmp (IDENTIFIER_POINTER (name), "l1_data") == 0)
+ section_name = ".l1.data";
+ else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_A") == 0)
+ section_name = ".l1.data.A";
+ else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_B") == 0)
+ section_name = ".l1.data.B";
+ else
+ gcc_unreachable ();
+
+ /* The decl may have already been given a section attribute
+ from a previous declaration. Ensure they match. */
+ if (DECL_SECTION_NAME (decl) != NULL_TREE
+ && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
+ section_name) != 0)
+ {
+ error ("section of %q+D conflicts with previous declaration",
+ decl);
+ *no_add_attrs = true;
+ }
+ else
+ DECL_SECTION_NAME (decl)
+ = build_string (strlen (section_name) + 1, section_name);
+ }
+
+ return NULL_TREE;
+}
+
/* Table of valid machine attributes. */
const struct attribute_spec bfin_attribute_table[] =
{
{ "saveall", 0, 0, false, true, true, NULL },
{ "longcall", 0, 0, false, true, true, bfin_handle_longcall_attribute },
{ "shortcall", 0, 0, false, true, true, bfin_handle_longcall_attribute },
+ { "l1_text", 0, 0, true, false, false, bfin_handle_l1_text_attribute },
+ { "l1_data", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
+ { "l1_data_A", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
+ { "l1_data_B", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
{ NULL, 0, 0, false, false, false, NULL }
};
\f
{
BFIN_BUILTIN_CSYNC,
BFIN_BUILTIN_SSYNC,
+ BFIN_BUILTIN_ONES,
BFIN_BUILTIN_COMPOSE_2X16,
BFIN_BUILTIN_EXTRACTLO,
BFIN_BUILTIN_EXTRACTHI,
BFIN_BUILTIN_CPLX_MAC_16,
BFIN_BUILTIN_CPLX_MSU_16,
+ BFIN_BUILTIN_CPLX_MUL_16_S40,
+ BFIN_BUILTIN_CPLX_MAC_16_S40,
+ BFIN_BUILTIN_CPLX_MSU_16_S40,
+
+ BFIN_BUILTIN_CPLX_SQU,
+
+ BFIN_BUILTIN_LOADBYTES,
+
BFIN_BUILTIN_MAX
};
tree short_ftype_v2hi
= build_function_type_list (short_integer_type_node, V2HI_type_node,
NULL_TREE);
-
+ tree int_ftype_pint
+ = build_function_type_list (integer_type_node,
+ build_pointer_type (integer_type_node),
+ NULL_TREE);
+
/* Add the remaining MMX insns with somewhat more complicated types. */
def_builtin ("__builtin_bfin_csync", void_ftype_void, BFIN_BUILTIN_CSYNC);
def_builtin ("__builtin_bfin_ssync", void_ftype_void, BFIN_BUILTIN_SSYNC);
+ def_builtin ("__builtin_bfin_ones", short_ftype_int, BFIN_BUILTIN_ONES);
+
def_builtin ("__builtin_bfin_compose_2x16", v2hi_ftype_int_int,
BFIN_BUILTIN_COMPOSE_2X16);
def_builtin ("__builtin_bfin_extract_hi", short_ftype_v2hi,
def_builtin ("__builtin_bfin_abs_fr2x16", v2hi_ftype_v2hi,
BFIN_BUILTIN_ABS_2X16);
+ def_builtin ("__builtin_bfin_min_fr1x16", short_ftype_int_int,
+ BFIN_BUILTIN_MIN_1X16);
+ def_builtin ("__builtin_bfin_max_fr1x16", short_ftype_int_int,
+ BFIN_BUILTIN_MAX_1X16);
+
def_builtin ("__builtin_bfin_add_fr1x16", short_ftype_int_int,
BFIN_BUILTIN_SSADD_1X16);
def_builtin ("__builtin_bfin_sub_fr1x16", short_ftype_int_int,
def_builtin ("__builtin_bfin_mulhisihh", int_ftype_v2hi_v2hi,
BFIN_BUILTIN_MULHISIHH);
+ def_builtin ("__builtin_bfin_min_fr1x32", int_ftype_int_int,
+ BFIN_BUILTIN_MIN_1X32);
+ def_builtin ("__builtin_bfin_max_fr1x32", int_ftype_int_int,
+ BFIN_BUILTIN_MAX_1X32);
+
def_builtin ("__builtin_bfin_add_fr1x32", int_ftype_int_int,
BFIN_BUILTIN_SSADD_1X32);
def_builtin ("__builtin_bfin_sub_fr1x32", int_ftype_int_int,
BFIN_BUILTIN_SSASHIFT_1X32);
/* Complex numbers. */
+ def_builtin ("__builtin_bfin_cmplx_add", v2hi_ftype_v2hi_v2hi,
+ BFIN_BUILTIN_SSADD_2X16);
+ def_builtin ("__builtin_bfin_cmplx_sub", v2hi_ftype_v2hi_v2hi,
+ BFIN_BUILTIN_SSSUB_2X16);
def_builtin ("__builtin_bfin_cmplx_mul", v2hi_ftype_v2hi_v2hi,
BFIN_BUILTIN_CPLX_MUL_16);
def_builtin ("__builtin_bfin_cmplx_mac", v2hi_ftype_v2hi_v2hi_v2hi,
BFIN_BUILTIN_CPLX_MAC_16);
def_builtin ("__builtin_bfin_cmplx_msu", v2hi_ftype_v2hi_v2hi_v2hi,
BFIN_BUILTIN_CPLX_MSU_16);
+ def_builtin ("__builtin_bfin_cmplx_mul_s40", v2hi_ftype_v2hi_v2hi,
+ BFIN_BUILTIN_CPLX_MUL_16_S40);
+ def_builtin ("__builtin_bfin_cmplx_mac_s40", v2hi_ftype_v2hi_v2hi_v2hi,
+ BFIN_BUILTIN_CPLX_MAC_16_S40);
+ def_builtin ("__builtin_bfin_cmplx_msu_s40", v2hi_ftype_v2hi_v2hi_v2hi,
+ BFIN_BUILTIN_CPLX_MSU_16_S40);
+ def_builtin ("__builtin_bfin_csqu_fr16", v2hi_ftype_v2hi,
+ BFIN_BUILTIN_CPLX_SQU);
+
+ /* "Unaligned" load. */
+ def_builtin ("__builtin_bfin_loadbytes", int_ftype_pint,
+ BFIN_BUILTIN_LOADBYTES);
+
}
static const struct builtin_description bdesc_1arg[] =
{
+ { CODE_FOR_loadbytes, "__builtin_bfin_loadbytes", BFIN_BUILTIN_LOADBYTES, 0 },
+
+ { CODE_FOR_ones, "__builtin_bfin_ones", BFIN_BUILTIN_ONES, 0 },
+
{ CODE_FOR_signbitshi2, "__builtin_bfin_norm_fr1x16", BFIN_BUILTIN_NORM_1X16, 0 },
{ CODE_FOR_ssneghi2, "__builtin_bfin_negate_fr1x16", BFIN_BUILTIN_NEG_1X16, 0 },
{ CODE_FOR_abshi2, "__builtin_bfin_abs_fr1x16", BFIN_BUILTIN_ABS_1X16, 0 },
return target;
case BFIN_BUILTIN_CPLX_MUL_16:
+ case BFIN_BUILTIN_CPLX_MUL_16_S40:
arg0 = CALL_EXPR_ARG (exp, 0);
arg1 = CALL_EXPR_ARG (exp, 1);
op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
if (! register_operand (op1, GET_MODE (op1)))
op1 = copy_to_mode_reg (GET_MODE (op1), op1);
- emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
- const0_rtx, const0_rtx,
- const1_rtx, GEN_INT (MACFLAG_NONE)));
+ if (fcode == BFIN_BUILTIN_CPLX_MUL_16)
+ emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
+ const0_rtx, const0_rtx,
+ const1_rtx, GEN_INT (MACFLAG_W32)));
+ else
+ emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
+ const0_rtx, const0_rtx,
+ const1_rtx, GEN_INT (MACFLAG_NONE)));
emit_insn (gen_flag_macv2hi_parts (target, op0, op1, const1_rtx,
const1_rtx, const1_rtx,
const0_rtx, accvec, const1_rtx, const0_rtx,
case BFIN_BUILTIN_CPLX_MAC_16:
case BFIN_BUILTIN_CPLX_MSU_16:
+ case BFIN_BUILTIN_CPLX_MAC_16_S40:
+ case BFIN_BUILTIN_CPLX_MSU_16_S40:
arg0 = CALL_EXPR_ARG (exp, 0);
arg1 = CALL_EXPR_ARG (exp, 1);
arg2 = CALL_EXPR_ARG (exp, 2);
|| GET_MODE (target) != V2HImode
|| ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
target = gen_reg_rtx (tmode);
- if (! register_operand (op0, GET_MODE (op0)))
- op0 = copy_to_mode_reg (GET_MODE (op0), op0);
if (! register_operand (op1, GET_MODE (op1)))
op1 = copy_to_mode_reg (GET_MODE (op1), op1);
+ if (! register_operand (op2, GET_MODE (op2)))
+ op2 = copy_to_mode_reg (GET_MODE (op2), op2);
tmp1 = gen_reg_rtx (SImode);
tmp2 = gen_reg_rtx (SImode);
- emit_insn (gen_ashlsi3 (tmp1, gen_lowpart (SImode, op2), GEN_INT (16)));
- emit_move_insn (tmp2, gen_lowpart (SImode, op2));
+ emit_insn (gen_ashlsi3 (tmp1, gen_lowpart (SImode, op0), GEN_INT (16)));
+ emit_move_insn (tmp2, gen_lowpart (SImode, op0));
emit_insn (gen_movstricthi_1 (gen_lowpart (HImode, tmp2), const0_rtx));
emit_insn (gen_load_accumulator_pair (accvec, tmp1, tmp2));
- emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op0, op1, const0_rtx,
- const0_rtx, const0_rtx,
- const1_rtx, accvec, const0_rtx,
- const0_rtx,
- GEN_INT (MACFLAG_W32)));
- tmp1 = (fcode == BFIN_BUILTIN_CPLX_MAC_16 ? const1_rtx : const0_rtx);
- tmp2 = (fcode == BFIN_BUILTIN_CPLX_MAC_16 ? const0_rtx : const1_rtx);
- emit_insn (gen_flag_macv2hi_parts (target, op0, op1, const1_rtx,
+ if (fcode == BFIN_BUILTIN_CPLX_MAC_16
+ || fcode == BFIN_BUILTIN_CPLX_MSU_16)
+ emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
+ const0_rtx, const0_rtx,
+ const1_rtx, accvec, const0_rtx,
+ const0_rtx,
+ GEN_INT (MACFLAG_W32)));
+ else
+ emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
+ const0_rtx, const0_rtx,
+ const1_rtx, accvec, const0_rtx,
+ const0_rtx,
+ GEN_INT (MACFLAG_NONE)));
+ if (fcode == BFIN_BUILTIN_CPLX_MAC_16
+ || fcode == BFIN_BUILTIN_CPLX_MAC_16_S40)
+ {
+ tmp1 = const1_rtx;
+ tmp2 = const0_rtx;
+ }
+ else
+ {
+ tmp1 = const0_rtx;
+ tmp2 = const1_rtx;
+ }
+ emit_insn (gen_flag_macv2hi_parts (target, op1, op2, const1_rtx,
const1_rtx, const1_rtx,
const0_rtx, accvec, tmp1, tmp2,
GEN_INT (MACFLAG_NONE), accvec));
return target;
+ case BFIN_BUILTIN_CPLX_SQU:
+ arg0 = CALL_EXPR_ARG (exp, 0);
+ op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+ accvec = gen_reg_rtx (V2PDImode);
+ icode = CODE_FOR_flag_mulv2hi;
+ tmp1 = gen_reg_rtx (V2HImode);
+ tmp2 = gen_reg_rtx (V2HImode);
+
+ if (! target
+ || GET_MODE (target) != V2HImode
+ || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
+ target = gen_reg_rtx (V2HImode);
+ if (! register_operand (op0, GET_MODE (op0)))
+ op0 = copy_to_mode_reg (GET_MODE (op0), op0);
+
+ emit_insn (gen_flag_mulv2hi (tmp1, op0, op0, GEN_INT (MACFLAG_NONE)));
+
+ emit_insn (gen_flag_mulhi_parts (tmp2, op0, op0, const0_rtx,
+ const0_rtx, const1_rtx,
+ GEN_INT (MACFLAG_NONE)));
+
+ emit_insn (gen_ssaddhi3_parts (target, tmp2, tmp2, const1_rtx,
+ const0_rtx, const0_rtx));
+
+ emit_insn (gen_sssubhi3_parts (target, tmp1, tmp1, const0_rtx,
+ const0_rtx, const1_rtx));
+
+ return target;
+
default:
break;
}
#undef TARGET_ASM_OUTPUT_MI_THUNK
#define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
-#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
#undef TARGET_SCHED_ADJUST_COST
#define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
#define TARGET_SCHED_ISSUE_RATE bfin_issue_rate
#undef TARGET_PROMOTE_PROTOTYPES
-#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
+#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
#undef TARGET_PROMOTE_FUNCTION_ARGS
-#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
+#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
#undef TARGET_PROMOTE_FUNCTION_RETURN
-#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
+#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
#undef TARGET_ARG_PARTIAL_BYTES
#define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
#undef TARGET_CANNOT_FORCE_CONST_MEM
#define TARGET_CANNOT_FORCE_CONST_MEM bfin_cannot_force_const_mem
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY bfin_return_in_memory
+
struct gcc_target targetm = TARGET_INITIALIZER;