/* Definitions for the c6x target.
Copyright (C) 2004 Jan Parthey
This file is part of a TI TMS320 C6x target implementation for GCC, which
shall be called "GCC C6x target" for the purposes of this statement.
"GCC C6x target" 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 of the License, or
(at your option) any later version.
"GCC C6x target" is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with "GCC C6x target"; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "config.h"
#include "system.h"
#include "rtl.h"
#include "tree.h"
#include "tm_p.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
#include "output.h"
#include "insn-attr.h"
#include "flags.h"
#include "except.h"
#include "function.h"
#include "recog.h"
#include "expr.h"
#include "optabs.h"
#include "toplev.h"
#include "basic-block.h"
#include "ggc.h"
#include "target.h"
#include "target-def.h"
#include "langhooks.h"
/**** node: "Target Structure"
* */
struct gcc_target targetm = TARGET_INITIALIZER;
/* Place for storing away the operands of the `cmpM' standard action. For
* immediate use in `bCOND' and fellows. See info gccint, node "Standard
* Names", `bCOND'. */
rtx c6x_compare_op0 = NULL_RTX;
rtx c6x_compare_op1 = NULL_RTX;
/* - modelled to some extend on `ix86_comparison_operator'
* - <op> is supposed to be of the form
* (<comparison-type> (reg:<cc-mode> <creg>) (const_int 0)), which is
* among others used as part of
* (set (pc) (if_then_else <op> (label_ref <ref-no>) (pc)))
* for expressing a conditional jump. Note: eg. for i386, the comparison
* against zero is not to be understood literally, it just codes for using
* the flags (zero, sign, overflow, ...) in <creg> to form the condition of
* the jump.
* - TODO: I haven't figured out precisely the significance of the CC modes for
* mechanisms moving instructions (insn scheduling?). Such mechanisms might
* change the condition of branch instruction following the cmp. For now, I
* assume it's not wrong to introduce CCEQ, CCGT, CCGTU, CCLT, and CCLTU in
* c6x-modes.def, corresponding to the cmp<x> instructions on the c6x and
* to use other md files as a model.
* - return: 1 if OP is a valid comparison operator in valid mode. */
int
c6x_comparison_operator (op, mode)
register rtx op ATTRIBUTE_UNUSED;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
#if 0
REMOVE THIS FUNCTION AS IT IS NOT NEEDED ANYMORE
enum machine_mode inmode;
enum rtx_code code = GET_CODE (op);
if (mode != VOIDmode && GET_MODE (op) != mode)
return 0;
/* <op> must be a comparison operator */
if (GET_RTX_CLASS (code) != '<')
return 0;
/* get <creg>'s mode */
inmode = GET_MODE (XEXP (op, 0));
switch (code)
{
case EQ: case NE:
return (inmode == CCEQmode);
case GT: case LE:
return (inmode == CCGTmode);
case LT: case GE:
return (inmode == CCLTmode);
case GTU: case LEU:
return (inmode == CCGTUmode);
case LTU: case GEU:
return (inmode == CCLTUmode);
default:
return 0;
}
#endif
return 0;
}
/* - modelled on `ix86_expand_branch'
* - <code> is EQ, NE, GE, etc.
* TODO
* allocate a new pseudo reg number <preg> and generate RTL insns with patterns:
* */
void
c6x_expand_branch (code, label)
enum rtx_code code ATTRIBUTE_UNUSED;
rtx label ATTRIBUTE_UNUSED;
{
#if 0
rtx predreg; /* predicate register */
rtx tmp;
enum machine_mode cmpmode;
cmpmode = SELECT_CC_MODE (code, c6x_compare_op0, c6x_compare_op1);
predreg = gen_reg_rtx (cmpmode);
switch (GET_MODE (c6x_compare_op0))
{
case SImode:
/* 1. (set (reg:<cmpmode> <predreg>)
* (compare:<cmpmode> <c6x_compare_op0>, <c6x_compare_op1>)) */
tmp = gen_rtx_COMPARE (cmpmode, c6x_compare_op0, c6x_compare_op1);
emit_insn (gen_rtx_SET (VOIDmode, predreg, tmp));
/* 2. (set (pc) (if_then_else (<code> (reg:CCEQ <preg>) (const_int 0)))
* (label_ref (match_operand 0 "" ""))
* (pc)) */
tmp = gen_rtx_fmt_ee (code, VOIDmode, predreg, const0_rtx);
tmp = gen_rtx_IF_THEN_ELSE (VOIDmode,
tmp,
gen_rtx_LABEL_REF (VOIDmode, label),
pc_rtx);
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
return;
default:
abort ();
}
#endif
}
/* Emit comparison instruction if necessary, returning the expression that
* holds the compare result in the proper mode.
*
* Modelled after `ia64_expand_compare'. */
rtx
c6x_expand_compare (code, mode)
enum rtx_code code;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
rtx op0 = c6x_compare_op0, op1 = c6x_compare_op1;
rtx predreg;
/* normally NE, but EQ if the condition is to be reversed */
enum rtx_code predcode = NE;
/* There are no mnemonics for `ne', `ge', `le', `geu', `leu' on c6x, but we
* handle them by emitting the reversed `code' (ie. `lt' instead of `ge')
* and, correspondingly, EQ rather than NE as `predcode', which causes the
* jump to be conditionalized by an inverted predicate register, eg. [!B0].
*/
if (code == NE || code == GE || code == LE || code == GEU || code == LEU)
{
code = reverse_condition (code);
predcode = EQ;
}
/* Emit an insn with pattern (SET (REG:BI predreg) (code:BI op0 op1)),
* where `code' is something of GET_RTX_CLASS == '<', eg.: `GE'.
* Note that there must be appropriate `define_insn's in the .md file,
* recognizing (set ...) for all `rtx_code's in class '<'. */
predreg = gen_reg_rtx (BImode);
emit_insn (gen_rtx_SET (VOIDmode, predreg,
gen_rtx_fmt_ee (code, BImode, op0, op1)));
/* Conditional branching (see define_expand "bge" etc.) is represented as
* `(set (pc) (if_then_else (COMPARISON) (label_ref LABEL) (pc)))'.
* On c6x, COMPARISON must be of the form (ne PREDREG const0_rtx) in order
* to be recognized.
*
* The rationale of this is the fact that the predreg will have been set to
* the result of the comparison by the insn emitted above. So we want to
* jump to the true-label iff predreg is != 0, which is expressed by the
* notation of COMPARISON.
*
* On c6x, we have no `jge' command available, but only an unconditional
* branch `b <reg>'. In order to get conditional branching, we have to
* use predicate registers, which we initialize by computing comparisons
* into them.
*/
return gen_rtx_fmt_ee (predcode, BImode, predreg, const0_rtx);
}
/* This implements `GO_IF_LEGITIMATE_ADDRESS' for c6x.
*
* We accept as legitimate address:
* - a single (REG)
* - a (PLUS (REG) (CONST_INT ucst5)
* - a (PLUS (REG) (REG))
* Anything else is forced to a register by function like `memory_address'.
*
* `GO_IF_LEGITIMATE_ADDRESS' is used, for example, by
* `strict_memory_address_p', which is used in `find_reloads_address' for
* checking whether a reload is needed. */
int
c6x_legitimate_address_p (mode, x, strict)
enum machine_mode mode ATTRIBUTE_UNUSED;
rtx x;
int strict;
{
rtx op0, op1;
/* A reg is ok. */
if (GET_CODE (x) == REG && C6X_REG_OK_FOR_BASE_P (x, strict)
&& (! strict || REGNO (x) < FIRST_PSEUDO_REGISTER))
return 1;
/* The sum of a reg and a constant in range 'J' is ok -> "*+baseReg(ucst5)".
* Negative 'J' is also ok -> "*-baseReg(ucst5)". */
else if ((GET_CODE (x) == PLUS)
&& GET_CODE (op0 = XEXP (x, 0)) == REG
&& C6X_REG_OK_FOR_BASE
评论4
最新资源