#include "config.h"
#include "system.h"
#include "rtl.h"
#include "tree.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 "recog.h"
#include "function.h"
#include "expr.h"
#include "obstack.h"
#include "reload.h"
#include "tm_p.h"
#include "target.h"
#include "target-def.h"
static int shift_constant_operand PARAMS ((rtx, enum machine_mode, int));
static void a29k_set_memflags_1 PARAMS ((rtx, int, int, int, int));
static void compute_regstack_size PARAMS ((void));
static void check_epilogue_internal_label PARAMS ((FILE *));
static void output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
static void output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
static void a29k_asm_named_section PARAMS ((const char *, unsigned int));
static int a29k_adjust_cost PARAMS ((rtx, rtx, rtx, int));
#define min(A,B) ((A) < (B) ? (A) : (B))
static int a29k_regstack_size;
static int a29k_makes_calls;
static char *a29k_last_prologue_insn;
static char *a29k_first_epilogue_insn;
static int a29k_first_epilogue_insn_used;
const char *a29k_function_name;
int a29k_debug_reg_map[FIRST_PSEUDO_REGISTER];
rtx a29k_compare_op0, a29k_compare_op1;
int a29k_compare_fp_p;
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
#undef TARGET_ASM_ALIGNED_SI_OP
#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE output_function_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE output_function_epilogue
#undef TARGET_SCHED_ADJUST_COST
#define TARGET_SCHED_ADJUST_COST a29k_adjust_cost
struct gcc_target targetm = TARGET_INITIALIZER;
int
cint_8_operand (op, mode)
register rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffffff00) == 0;
}
int
cint_16_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff0000) == 0;
}
int
long_const_operand (op, mode)
register rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (! CONSTANT_P (op))
return 0;
if (TARGET_29050 && GET_CODE (op) == CONST_INT
&& (INTVAL (op) & 0xffff) == 0)
return 0;
return (GET_CODE (op) != CONST_INT
|| ((INTVAL (op) & 0xffff0000) != 0
&& (INTVAL (op) & 0xffff0000) != 0xffff0000
&& INTVAL (op) != 0x80000000));
}
static int
shift_constant_operand (op, mode, val)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
int val;
{
return ((GET_CODE (op) == CONST_INT && INTVAL (op) == val)
|| (GET_CODE (op) == ASHIFT
&& GET_CODE (XEXP (op, 0)) == CONST_INT
&& INTVAL (XEXP (op, 0)) == val / 8
&& GET_CODE (XEXP (op, 1)) == CONST_INT
&& INTVAL (XEXP (op, 1)) == 3));
}
int
const_0_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return shift_constant_operand (op, mode, 0);
}
int
const_8_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return shift_constant_operand (op, mode, 8);
}
int
const_16_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return shift_constant_operand (op, mode, 16);
}
int
const_24_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return shift_constant_operand (op, mode, 24);
}
int
float_const_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == mode;
}
int
gpc_reg_or_float_constant_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return float_const_operand (op, mode) || gpc_reg_operand (op, mode);
}
int
gpc_reg_or_integer_constant_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return ((GET_MODE (op) == VOIDmode
&& (GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE))
|| gpc_reg_operand (op, mode));
}
int
spec_reg_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (GET_CODE (op) != REG || GET_MODE (op) != mode)
return 0;
switch (GET_MODE_CLASS (mode))
{
case MODE_PARTIAL_INT:
return REGNO (op) >= R_BP && REGNO (op) <= R_CR;
case MODE_INT:
return REGNO (op) >= R_Q && REGNO (op) <= R_EXO;
default:
return 0;
}
}
int
accum_reg_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == REG
&& REGNO (op) >= R_ACU (0) && REGNO (op) <= R_ACU (3));
}
int
gpc_reg_operand (op, mode)
rtx op;
enum machine_mode mode;
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return 0;
if (GET_CODE (op) == REG)
regno = REGNO (op);
else if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)
{
if (REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER)
regno = subreg_regno (op);
else
regno = REGNO (SUBREG_REG (op));
}
else
return 0;
return (regno >= FIRST_PSEUDO_REGISTER || regno < R_BP
|| (regno >= R_KR (0) && regno <= R_KR (31)));
}
int
srcb_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
if (GET_CODE (op) == CONST_INT
&& (mode == QImode
|| (INTVAL (op) & 0xffffff00) == 0))
return 1;
if (GET_MODE (op) != mode && mode != VOIDmode)
return 0;
return gpc_reg_operand (op, mode);
}
int
cmplsrcb_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
if (GET_CODE (op) == CONST_INT
&& (mode == QImode
|| (INTVAL (op) & 0xffffff00) == 0xffffff00))
return 1;
if (GET_MODE (op) != mode && mode != VOIDmode)
return 0;
return gpc_reg_operand (op, mode);
}
int
gpc_reg_or_immediate_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return gpc_reg_operand (op, mode) || immediate_operand (op, mode);
}
int
and_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (srcb_operand (op, mode)
|| (GET_CODE (op) == CONST_INT
&& ((unsigned) ((~ INTVAL (op)) & GET_MODE_MASK (mode)) < 256)));
}
int
add_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (srcb_operand (op, mode)
|| (GET_CODE (op) == CONST_INT
&& ((unsigned) ((- INTVAL (op)) & GET_MODE_MASK (mode)) < 256)));
}
int
call_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
switch (GET_CODE (op))
{
case SYMBOL_REF:
return (TARGET_SMALL_MEMORY
|| (! TARGET_LARGE_MEMORY
&& ((GET_CODE (op) == SYMBOL_REF && SYMBOL_REF_FLAG (op))
|| ! strcmp (XSTR (op, 0), current_function_name))));
case CONST_INT:
return (unsigned HOST_WIDE_INT) INTVAL (op) < 0x40000;
default:
return 0;
}
}
int
in_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (! general_operand (op, mode))
return 0;
while (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
switch (GET_CODE (op))
{
case REG:
return 1;
case MEM:
return (GET_MODE_SIZE (mode) >= UNITS_PER_WORD || TARGET_DW_ENABLE);
case CONST_INT:
if (GET_MODE_CLASS (mode) != MODE_INT
&& GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
return 0;
return 1;
case CONST:
case SYMBOL_REF:
case LABEL_REF:
return (GET_MODE (op) == mode
|| mode == SImode || mode == HImode || mode == QImode);
case CONST_DOUBLE:
return ((GET_MODE_CLASS (mode) == MODE_FLOAT
&& mode == GET_MODE (op))
|| (GET_MODE (op) == VOIDmode
&& GET_MODE_CLASS (mode) == MODE_INT));
default:
return 0;
}
}
int
out_operand (op, mode)
rtx op;
enum machine_mode mode;
{
rtx orig_op = op;
if (! general_operand (op, mode))
return 0;
while (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) == REG)
return (gpc_reg_operand (orig_op, mode)
|| spec_reg_operand (orig_op, mode)
|| (GET_MODE_CLASS (mode) == MODE_FLOAT
&& accum_reg_operand (orig_op, mode)));
else if (GET_CODE (op) == MEM)
return (GET_MODE_SIZE (mode) >= UNITS_PER_WORD || TARGET_DW_ENABLE);
else
return 0;
}
int
reload_memory_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
int regno = true_regnum (op);
return (! CONSTANT_P (op)
&& (regno == -1
|| (GET_CODE (op) == REG
&& REGNO (op) >= FIRST_PSEUDO_REGISTER)));
}
rtx
a29k_get_reloaded_address (op)
rtx op;
{
if (GET_CODE (op) == SUBREG)
{
if (SUBREG_BYTE (op) != 0)
abort ();
op = SUBREG_REG (op);
}
if (GET_CODE (op) == REG)
op = reg_equiv_mem[REGNO (op)];
return find_replacement (&XEXP (op, 0));
}
static void
a29k_set_memflags_1 (x, in_struct_p, scalar_p, volatile_p, unchanging_p)
rtx x;
int in_struct_p, scalar_p, volatile_p, unchanging_p;
{
int i;
switch (GET_CODE (x))
{
case SEQUENCE:
case PARALLEL:
for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
a29k_set_memflags_1 (XVECEXP (x, 0, i), in_struct_p, scalar_p,
volatile_p, unchanging_p);
break;
case INSN:
a29k_set_memflags_1 (PATTERN (x), in_struct_p, scalar_p, volatile_p,
unchanging_p);
break;
case SET:
a29k_set_memflags_1 (SET_DEST (x), in_struct_p, scalar_p, volatile_p,
unchanging_p);
a29k_set_memflags_1 (SET_SRC (x), in_struct_p, scalar_p, volatile_p,
unchanging_p);
break;
case MEM:
MEM_IN_STRUCT_P (x) = in_struct_p;
MEM_SCALAR_P (x) = scalar_p;
MEM_VOLATILE_P (x) = volatile_p;
RTX_UNCHANGING_P (x) = unchanging_p;
break;
default:
break;
}
}
void
a29k_set_memflags (insn, ref)
rtx insn;
rtx ref;
{
int in_struct_p = MEM_IN_STRUCT_P (ref);
int scalar_p = MEM_SCALAR_P (ref);
int volatile_p = MEM_VOLATILE_P (ref);
int unchanging_p = RTX_UNCHANGING_P (ref);
if (GET_CODE (ref) != MEM
|| (! in_struct_p && ! volatile_p && ! unchanging_p))
return;
a29k_set_memflags_1 (insn, in_struct_p, scalar_p, volatile_p, unchanging_p);
}
int
fp_comparison_operator (op, mode)
rtx op;
enum machine_mode mode;
{
return ((mode == VOIDmode || mode == GET_MODE (op))
&& (GET_CODE (op) == EQ || GET_CODE (op) == GT ||
GET_CODE (op) == GE));
}
int
branch_operator (op, mode)
rtx op;
enum machine_mode mode;
{
return ((mode == VOIDmode || mode == GET_MODE (op))
&& (GET_CODE (op) == GE || GET_CODE (op) == LT));
}
int
load_multiple_operation (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
int count = XVECLEN (op, 0) - 2;
int dest_regno;
rtx src_addr;
int i;
if (count <= 1
|| GET_CODE (XVECEXP (op, 0, 0)) != SET
|| GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
|| GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
return 0;
dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
for (i = 1; i < count; i++)
{
rtx elt = XVECEXP (op, 0, i + 2);
if (GET_CODE (elt) != SET
|| GET_CODE (SET_DEST (elt)) != REG
|| GET_MODE (SET_DEST (elt)) != SImode
|| REGNO (SET_DEST (elt)) != dest_regno + i
|| GET_CODE (SET_SRC (elt)) != MEM
|| GET_MODE (SET_SRC (elt)) != SImode
|| GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
|| ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
|| GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
|| INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != i * 4)
return 0;
}
return 1;
}
int
store_multiple_operation (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
int num_special = TARGET_NO_STOREM_BUG ? 2 : 1;
int count = XVECLEN (op, 0) - num_special;
int src_regno;
rtx dest_addr;
int i;
if (count <= 1
|| GET_CODE (XVECEXP (op, 0, 0)) != SET
|| GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
|| GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
return 0;
src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
for (i = 1; i < count; i++)
{
rtx elt = XVECEXP (op, 0, i + num_special);
if (GET_CODE (elt) != SET
|| GET_CODE (SET_SRC (elt)) != REG
|| GET_MODE (SET_SRC (elt)) != SImode
|| REGNO (SET_SRC (elt)) != src_regno + i
|| GET_CODE (SET_DEST (elt)) != MEM
|| GET_MODE (SET_DEST (elt)) != SImode
|| GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
|| ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
|| GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
|| INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != i * 4)
return 0;
}
return 1;
}
int
masks_bits_for_special (reg, mask)
rtx reg;
rtx mask;
{
int needed_mask_value;
if (GET_CODE (reg) != REG || GET_CODE (mask) != CONST_INT)
abort ();
switch (REGNO (reg))
{
case R_BP:
case R_INT:
needed_mask_value = 3;
break;
case R_FC:
needed_mask_value = 31;
break;
case R_CR:
case R_LRU:
needed_mask_value = 255;
break;
case R_FPE:
needed_mask_value = 511;
break;
case R_MMU:
needed_mask_value = 0x3ff;
break;
case R_OPS:
case R_CPS:
case R_RBP:
case R_FPS:
needed_mask_value = 0xffff;
break;
case R_VAB:
needed_mask_value = 0xffff0000;
break;
case R_Q:
case R_CFG:
case R_CHA:
case R_CHD:
case R_CHC:
case R_TMC:
case R_TMR:
case R_PC0:
case R_PC1:
case R_PC2:
return 0;
default:
abort ();
}
return (INTVAL (mask) & ~ needed_mask_value) == 0;
}
int
epilogue_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return next_active_insn (op) == 0 && a29k_first_epilogue_insn != 0;
}
enum reg_class
secondary_reload_class (class, mode, in)
enum reg_class class;
enum machine_mode mode;
rtx in;
{
int regno = -1;
enum rtx_code code = GET_CODE (in);
if (! CONSTANT_P (in))
{
regno = true_regnum (in);
if (regno == -1 || regno >= FIRST_PSEUDO_REGISTER)
code = MEM;
}
if (code == MEM && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
return CR_REGS;
if (code == MEM && ! TARGET_DW_ENABLE
&& GET_MODE_SIZE (mode) < UNITS_PER_WORD)
return BP_REGS;
if (class == GENERAL_REGS
|| (regno != -1
&& (regno < R_BP
|| (regno >= R_KR (0) && regno <= R_KR (31)))))
return NO_REGS;
if (code == CONST_INT
&& (GET_MODE_BITSIZE (mode) <= 16 || (unsigned) INTVAL (in) <= 65535)
&& (class == BP_REGS || class == Q_REGS || class == SPECIAL_REGS))
return NO_REGS;
return GENERAL_REGS;
}
int
incoming_reg (start, count)
int start;
int count;
{
int i;
if (start + count > 16)
count = 16 - start;
if (! TARGET_NO_REUSE_ARGS)
for (i = R_AR (start); i < R_AR (start + count); i++)
{
fixed_regs[i] = call_used_regs[i] = call_fixed_regs[i] = 0;
CLEAR_HARD_REG_BIT (fixed_reg_set, i);
CLEAR_HARD_REG_BIT (call_used_reg_set, i);
CLEAR_HARD_REG_BIT (call_fixed_reg_set, i);
}
for (i = (R_AR (0) - 2 - start - count) & ~1; i < R_AR (0) - 2 - start; i++)
{
fixed_regs[i] = call_used_regs[i] = call_fixed_regs[i] = 1;
SET_HARD_REG_BIT (fixed_reg_set, i);
SET_HARD_REG_BIT (call_used_reg_set, i);
SET_HARD_REG_BIT (call_fixed_reg_set, i);
}
return R_AR (start);
}
void
a29k_clobbers_to (insn, op)
rtx insn;
rtx op;
{
int i;
int high_regno;
if (op == 0)
high_regno = R_LR (18);
else if (GET_CODE (op) != REG || REGNO (op) < R_LR (0)
|| REGNO (op) > R_LR (18))
abort ();
else
high_regno = REGNO (op);
for (i = R_LR (2); i < high_regno; i++)
CALL_INSN_FUNCTION_USAGE (insn)
= gen_rtx_EXPR_LIST (VOIDmode,
gen_rtx_CLOBBER (VOIDmode,
gen_rtx (REG, SImode, i)),
CALL_INSN_FUNCTION_USAGE (insn));
}
int
needs_regstack_p ()
{
int i;
rtx insn;
if (frame_pointer_needed)
return 1;
for (i = R_LR (127); i >= R_LR (0); i --)
if (regs_ever_live[i])
return 1;
for (insn = get_insns (); insn; insn = next_insn (insn))
if (GET_CODE (insn) == CALL_INSN
|| (GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) == SEQUENCE
&& GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN))
return 1;
return 0;
}
int
uses_local_reg_p (x)
rtx x;
{
const char *fmt;
int i, j;
switch (GET_CODE (x))
{
case REG:
return REGNO (x) >= R_LR (0) && REGNO (x) <= R_FP;
case CONST_INT:
case CONST:
case PC:
case CC0:
case LABEL_REF:
case SYMBOL_REF:
return 0;
default:
break;
}
fmt = GET_RTX_FORMAT (GET_CODE (x));
for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
{
if (uses_local_reg_p (XEXP (x, i)))
return 1;
}
else if (fmt[i] == 'E')
{
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
if (uses_local_reg_p (XVECEXP (x, i, j)))
return 1;
}
}
return 0;
}
int
null_epilogue ()
{
return (reload_completed && ! needs_regstack_p ()
&& get_frame_size () == 0
&& current_function_pretend_args_size == 0);
}
void
print_operand (file, x, code)
FILE *file;
rtx x;
char code;
{
char buf[100];
#define INT_P(X) \
((GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST_DOUBLE) \
&& GET_MODE (X) == VOIDmode)
#define INT_LOWPART(X) \
(GET_CODE (X) == CONST_INT ? INTVAL (X) : CONST_DOUBLE_LOW (X))
switch (code)
{
case 'Q':
if (GET_CODE (x) == REG)
break;
else if (! INT_P (x))
output_operand_lossage ("invalid %%Q value");
fprintf (file, "%d", INT_LOWPART (x) & 0xff);
return;
case 'C':
if (! INT_P (x))
output_operand_lossage ("invalid %%C value");
fprintf (file, "%d", (~ INT_LOWPART (x)) & 0xff);
return;
case 'N':
if (! INT_P (x))
output_operand_lossage ("invalid %%N value");
fprintf (file, "%d", (- INT_LOWPART (x)) & 0xff);
return;
case 'M':
if (! INT_P (x))
output_operand_lossage ("invalid %%M value");
fprintf (file, "%d", INT_LOWPART (x) & 0xffff);
return;
case 'm':
if (! INT_P (x))
output_operand_lossage ("invalid %%m value");
fprintf (file, "%d", (INT_LOWPART (x) & 0xffff) << 16);
return;
case 'b':
if (GET_CODE (x) == GE)
fprintf (file, "f");
else
fprintf (file, "t");
return;
case 'B':
if (GET_CODE (x) == GE)
fprintf (file, "t");
else
fprintf (file, "f");
return;
case 'J':
fprintf (file, GET_RTX_NAME (GET_CODE (x)));
if (GET_CODE (x) == NE)
fprintf (file, "q");
return;
case 'e':
if (optimize && flag_delayed_branch
&& a29k_last_prologue_insn == 0 && epilogue_operand (x, VOIDmode)
&& dbr_sequence_length () == 0)
{
while (NEXT_INSN (x) != 0)
x = NEXT_INSN (x);
while (GET_CODE (x) != CODE_LABEL)
x = PREV_INSN (x);
ASM_GENERATE_INTERNAL_LABEL (buf, "LX", CODE_LABEL_NUMBER (x));
assemble_name (file, buf);
}
else
output_asm_label (x);
return;
case 'E':
if (dbr_sequence_length ())
;
else if (a29k_last_prologue_insn)
{
fprintf (file, "\n\t%s", a29k_last_prologue_insn);
free (a29k_last_prologue_insn);
a29k_last_prologue_insn = 0;
}
else if (optimize && flag_delayed_branch
&& epilogue_operand (x, VOIDmode))
{
fprintf (file, "\n\t%s", a29k_first_epilogue_insn);
a29k_first_epilogue_insn_used = 1;
}
else
fprintf (file, "\n\tnop");
return;
case 'F':
output_addr_const (file, x);
if (dbr_sequence_length () == 0)
{
if (a29k_last_prologue_insn)
{
fprintf (file, "\n\t%s", a29k_last_prologue_insn);
free (a29k_last_prologue_insn);
a29k_last_prologue_insn = 0;
}
else if (GET_CODE (x) == SYMBOL_REF
&& ! strcmp (XSTR (x, 0), current_function_name))
fprintf (file, "+4\n\t%s,%d",
a29k_regstack_size >= 64 ? "const gr121" : "sub gr1,gr1",
a29k_regstack_size * 4);
else
fprintf (file, "\n\tnop");
}
return;
case 'L':
if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
{
union real_extract u;
memcpy ((char *) &u, (char *) &CONST_DOUBLE_LOW (x), sizeof u);
fprintf (file, "$double1(%.20e)", u.d);
}
else if (GET_CODE (x) == REG)
fprintf (file, "%s", reg_names[REGNO (x) + 1]);
else
output_operand_lossage ("invalid %%L value");
return;
case 'O':
if (GET_CODE (x) != REG)
output_operand_lossage ("invalid %%O value");
fprintf (file, "%s", reg_names[REGNO (x) + 2]);
return;
case 'P':
if (GET_CODE (x) != REG)
output_operand_lossage ("invalid %%P value");
fprintf (file, "%s", reg_names[REGNO (x) + 3]);
return;
case 'S':
fprintf (file, "%d", (GET_MODE_SIZE (GET_MODE (x)) / UNITS_PER_WORD)-1);
return;
case 'V':
if (GET_CODE (x) != PARALLEL)
output_operand_lossage ("invalid %%V value");
fprintf (file, "%d", XVECLEN (x, 0) - 2);
return;
case '#':
if (dbr_sequence_length () == 0)
{
if (a29k_last_prologue_insn)
{
fprintf (file, "\n\t%s", a29k_last_prologue_insn);
free (a29k_last_prologue_insn);
a29k_last_prologue_insn = 0;
}
else
fprintf (file, "\n\tnop");
}
return;
case '*':
fprintf (file, "%s", reg_names [R_TPC]);
return;
}
if (GET_CODE (x) == REG)
fprintf (file, "%s", reg_names [REGNO (x)]);
else if (GET_CODE (x) == MEM)
output_address (XEXP (x, 0));
else if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == SUBREG
&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == CONST_DOUBLE)
{
union real_extract u;
if (GET_MODE (SUBREG_REG (XEXP (x, 0))) == SFmode)
fprintf (file, "$float");
else
fprintf (file, "$double%d",
(SUBREG_BYTE (XEXP (x, 0)) / GET_MODE_SIZE (GET_MODE (x))));
memcpy ((char *) &u,
(char *) &CONST_DOUBLE_LOW (SUBREG_REG (XEXP (x, 0))), sizeof u);
fprintf (file, "(%.20e)", u.d);
}
else if (GET_CODE (x) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
{
union real_extract u;
memcpy ((char *) &u, (char *) &CONST_DOUBLE_LOW (x), sizeof u);
fprintf (file, "$%s(%.20e)",
GET_MODE (x) == SFmode ? "float" : "double0", u.d);
}
else
output_addr_const (file, x);
}
static void
compute_regstack_size ()
{
int i;
rtx insn;
a29k_makes_calls = 0;
for (insn = get_insns (); insn; insn = next_insn (insn))
if (GET_CODE (insn) == CALL_INSN
|| (GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) == SEQUENCE
&& GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN))
{
a29k_makes_calls = 1;
break;
}
for (i = R_LR (127); i >= R_LR (0); i--)
if (regs_ever_live[i])
break;
a29k_regstack_size = i - (R_LR (0) - 1);
if (a29k_makes_calls && a29k_regstack_size < 2)
a29k_regstack_size = 2;
a29k_regstack_size += frame_pointer_needed;
if (a29k_regstack_size & 1) a29k_regstack_size++;
}
void
a29k_compute_reg_names ()
{
int i;
compute_regstack_size ();
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
a29k_debug_reg_map[i] = i;
reg_names[FRAME_POINTER_REGNUM] = reg_names[R_LR (a29k_regstack_size - 1)];
a29k_debug_reg_map[FRAME_POINTER_REGNUM] = R_LR (a29k_regstack_size - 1);
for (i = 0; i < 16; i++)
{
reg_names[R_AR (i)] = reg_names[R_LR (a29k_regstack_size + i + 2)];
a29k_debug_reg_map[R_AR (i)] = R_LR (a29k_regstack_size + i + 2);
}
if (TARGET_KERNEL_REGISTERS)
for (i = 0; i < 32; i++)
{
int tem = a29k_debug_reg_map[i];
a29k_debug_reg_map[i] = a29k_debug_reg_map[R_KR (i)];
a29k_debug_reg_map[R_KR (i)] = tem;
}
}
static void
output_function_prologue (file, size)
FILE *file;
HOST_WIDE_INT size;
{
int i;
int arg_count = 0;
rtx insn;
unsigned int tag_word;
for (i = R_AR (0); i < R_AR (16); i++)
if (! fixed_regs[i])
arg_count++;
arg_count += 2;
size += (current_function_pretend_args_size
+ current_function_outgoing_args_size);
size = (size + 7) & ~7;
tag_word = (frame_pointer_needed ? 0x400000 : 0) + (arg_count << 16);
if (size / 8 > 0xff)
fprintf (file, "\t.word %d, 0x%0x\n", (size / 8) << 2,
0x800000 + tag_word);
else
fprintf (file, "\t.word 0x%0x\n", tag_word + ((size / 8) << 3));
assemble_name (file, a29k_function_name);
fprintf (file, ":\n");
if (a29k_regstack_size >= 256/4)
fprintf (file, "\tconst %s,%d\n\tsub gr1,gr1,%s\n",
reg_names[R_TAV], a29k_regstack_size * 4, reg_names[R_TAV]);
else if (a29k_regstack_size)
fprintf (file, "\tsub gr1,gr1,%d\n", a29k_regstack_size * 4);
if (a29k_regstack_size)
fprintf (file, "\tasgeu V_%sSPILL,gr1,%s\n",
TARGET_KERNEL_REGISTERS ? "K" : "", reg_names[R_RAB]);
if (frame_pointer_needed)
fprintf (file, "\tsll %s,%s,0\n", reg_names[FRAME_POINTER_REGNUM],
reg_names[R_MSP]);
if (size >= 256)
{
fprintf (file, "\tconst %s,%d\n", reg_names[R_TAV], size);
if (size >= 65536)
fprintf (file, "\tconsth %s,%d\n", reg_names[R_TAV], size);
if (TARGET_STACK_CHECK)
fprintf (file, "\tcall %s,__msp_check\n", reg_names[R_TPC]);
fprintf (file, "\tsub %s,%s,%s\n",
reg_names[R_MSP], reg_names[R_MSP], reg_names[R_TAV]);
}
else if (size)
{
if (TARGET_STACK_CHECK)
fprintf (file, "\tcall %s,__msp_check\n", reg_names[R_TPC]);
fprintf (file, "\tsub %s,%s,%d\n",
reg_names[R_MSP], reg_names[R_MSP], size);
}
a29k_last_prologue_insn = 0;
if (a29k_makes_calls)
{
i = (a29k_regstack_size + arg_count) * 4;
if (i >= 256)
fprintf (file, "\tconst %s,%d\n\tadd lr1,gr1,%s\n",
reg_names[R_TAV], i, reg_names[R_TAV]);
else
{
if (optimize && flag_delayed_branch)
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
if (GET_CODE (insn) == CODE_LABEL
|| (GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) == SEQUENCE))
break;
if (GET_CODE (insn) == NOTE
|| (GET_CODE (insn) == INSN
&& (GET_CODE (PATTERN (insn)) == USE
|| GET_CODE (PATTERN (insn)) == CLOBBER)))
continue;
if (num_delay_slots (insn) > 0)
{
a29k_last_prologue_insn = (char *) xmalloc (100);
sprintf (a29k_last_prologue_insn, "add lr1,gr1,%d", i);
break;
}
}
if (a29k_last_prologue_insn == 0)
fprintf (file, "\tadd lr1,gr1,%d\n", i);
}
}
a29k_first_epilogue_insn_used = 0;
if (size == 0 && a29k_regstack_size == 0 && ! frame_pointer_needed)
a29k_first_epilogue_insn = 0;
else
a29k_first_epilogue_insn = (char *) xmalloc (100);
if (frame_pointer_needed)
sprintf (a29k_first_epilogue_insn, "sll %s,%s,0",
reg_names[R_MSP], reg_names[FRAME_POINTER_REGNUM]);
else if (a29k_regstack_size)
{
if (a29k_regstack_size >= 256 / 4)
sprintf (a29k_first_epilogue_insn, "const %s,%d",
reg_names[R_TAV], a29k_regstack_size * 4);
else
sprintf (a29k_first_epilogue_insn, "add gr1,gr1,%d",
a29k_regstack_size * 4);
}
else if (size)
{
if (size >= 256)
sprintf (a29k_first_epilogue_insn, "const %s,%d",
reg_names[R_TAV], size);
else
sprintf (a29k_first_epilogue_insn, "add %s,%s,%d",
reg_names[R_MSP], reg_names[R_MSP], size);
}
}
static void
check_epilogue_internal_label (file)
FILE *file;
{
rtx insn;
if (! a29k_first_epilogue_insn_used)
return;
for (insn = get_last_insn ();
GET_CODE (insn) != CODE_LABEL;
insn = PREV_INSN (insn))
;
ASM_OUTPUT_INTERNAL_LABEL (file, "LX", CODE_LABEL_NUMBER (insn));
a29k_first_epilogue_insn_used = 0;
}
static void
output_function_epilogue (file, size)
FILE *file;
HOST_WIDE_INT size;
{
rtx insn;
int locals_unavailable = 0;
insn = get_last_insn ();
if (GET_CODE (insn) == NOTE)
insn = prev_nonnote_insn (insn);
if (insn && GET_CODE (insn) == BARRIER)
return;
if (frame_pointer_needed)
{
fprintf (file, "\tsll %s,%s,0\n",
reg_names[R_MSP], reg_names[FRAME_POINTER_REGNUM]);
check_epilogue_internal_label (file);
}
if (a29k_regstack_size)
{
if (a29k_regstack_size >= 256/4)
{
fprintf (file, "\tconst %s,%d\n",
reg_names[R_TAV], a29k_regstack_size * 4);
check_epilogue_internal_label (file);
fprintf (file, "\tadd gr1,gr1,%s\n", reg_names[R_TAV]);
}
else
{
fprintf (file, "\tadd gr1,gr1,%d\n", a29k_regstack_size * 4);
check_epilogue_internal_label (file);
}
locals_unavailable = 1;
}
size += (current_function_pretend_args_size
+ current_function_outgoing_args_size);
size = (size + 7) & ~7;
if (size && ! frame_pointer_needed)
{
if (size >= 256)
{
fprintf (file, "\tconst %s,%d\n", reg_names[R_TAV], size);
check_epilogue_internal_label (file);
locals_unavailable = 0;
if (size >= 65536)
fprintf (file, "\tconsth %s,%d\n", reg_names[R_TAV], size);
fprintf (file, "\tadd %s,%s,%s\n",
reg_names[R_MSP], reg_names[R_MSP], reg_names[R_TAV]);
}
else
{
fprintf (file, "\tadd %s,%s,%d\n",
reg_names[R_MSP], reg_names[R_MSP], size);
check_epilogue_internal_label (file);
locals_unavailable = 0;
}
}
if (locals_unavailable)
{
if (current_function_epilogue_delay_list)
final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
file, 1, -2, 1);
else
fprintf (file, "\tnop\n");
}
fprintf (file, "\tjmpi lr0\n");
if (a29k_regstack_size)
fprintf (file, "\tasleu V_%sFILL,lr1,%s\n",
TARGET_KERNEL_REGISTERS ? "K" : "", reg_names[R_RFB]);
else if (current_function_epilogue_delay_list)
final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
file, 1, -2, 1);
else
fprintf (file, "\tnop\n");
if (a29k_first_epilogue_insn)
free (a29k_first_epilogue_insn);
a29k_first_epilogue_insn = 0;
}
static void
a29k_asm_named_section (name, flags)
const char *name;
unsigned int flags ATTRIBUTE_UNUSED;
{
fprintf (asm_out_file, "\t.sect %s, bss\n\t.use %s\n", name, name);
}
static int
a29k_adjust_cost (insn, link, dep_insn, cost)
rtx insn ATTRIBUTE_UNUSED;
rtx link;
rtx dep_insn ATTRIBUTE_UNUSED;
int cost;
{
if (REG_NOTE_KIND (link) != 0)
return 0;
return cost;
}