summaryrefslogtreecommitdiff
path: root/gcc/config/pj/pj.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/pj/pj.c')
-rw-r--r--gcc/config/pj/pj.c1286
1 files changed, 0 insertions, 1286 deletions
diff --git a/gcc/config/pj/pj.c b/gcc/config/pj/pj.c
deleted file mode 100644
index 736a30a0966..00000000000
--- a/gcc/config/pj/pj.c
+++ /dev/null
@@ -1,1286 +0,0 @@
-/* Output routines for GCC for picoJava II
- Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC 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 option)
-any later version.
-
-GNU CC 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 GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
-
-/* Contributed by Steve Chamberlain (sac@pobox.com), of Transmeta. */
-
-/* The picoJava architecture doesn't have general registers, it has an
- operand stack. Any of the first 256 words on the operand stack between
- the locations indicated by the vars register and the optop register
- are accessible with one instruction, almost as if they were registers.
- The opstack isn't aliased into memory, so deferecencing address of
- something on the opstack is impossible.
-
- Small scalar incoming arguments to a function arrive on the operand
- stack, large scalars and aggregates arrive in the `aggregate'
- stack. The aggregate stack lives in normal memory.
-
-
- just before a call after the call insn and frame setup.
-
- vars-> ....
-
- arg-5 vars->arg-5
- arg-4 arg-4
- arg-3 arg-3
- arg-2 arg-2
- arg-1 arg-1
- arg-0 arg-0
- target-addr old-vars
- #arg words old-pc
- optop-> saved globals
- local-0
- local-1
- ....
- optop->
-
- This port generates code for a machine with 32 general purpose
- registers, and on output changes the references to the fake registers
- into offsets from the vars register. Because the opstack grows
- downwards and all indexes are negated, some care has to be taken here
- to deal with endian problems; for example after a call on a little endian
- machine, an incoming DImode argument of value 0x1122334455667788 in
- `register 0', would live on the opstack like this:
-
- vars - 0 0x11223344
- vars - 4 0x55667788
- vars - 8 old-vars
- vars - 12 old-pc
-
- The picoJava instructon to read and put that onto the opstack as a
- DImode value is `lload 0', yet the least significant word lives at
- vars - 4, for which the instruction is `iload 1'. The incoming
- argument code remembers which arguments arrive swapped in the
- CUMULATIVE_ARGS structure. The information is used to fill in
- pj_si_vars_offset_vec and pj_di_vars_offset_vec during the prologue
- printing.
-
- Outgoing arguments are collected in fake `outgoing' registers, or
- in the aggregate stack. The emitted code to write into an outgoing
- register does nothing, which leaves the expression to be written on
- the top of the opstack. GCC always evaluates arguments in the right
- order, so nothing more needs to be done. */
-
-
-#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"
-
-/* Compare insns in pj.md store the information needed to generate
- branch instructions here. */
-rtx pj_cmp_op0;
-rtx pj_cmp_op1;
-enum machine_mode pj_cmp_mode;
-
-static void pj_output_rval PARAMS ((rtx, enum machine_mode, rtx));
-static void pj_output_store_into_lval PARAMS ((enum machine_mode mode, rtx op));
-static void pj_output_push_int PARAMS ((int));
-static void pj_output_load PARAMS ((enum machine_mode, int));
-static void pj_output_inc PARAMS ((rtx, int));
-static void pj_output_cnv_op PARAMS ((enum insn_code, rtx));
-static char mode_to_char PARAMS ((enum machine_mode));
-static void pj_output_varidx PARAMS ((enum machine_mode, int, int));
-static void pj_print_cond PARAMS ((enum rtx_code));
-static rtx *unique_src_operand PARAMS ((rtx *, rtx));
-
-/* These vectors turn a register number into an offset from the vars
- pointer register. */
-short pj_si_vars_offset_vec[FIRST_PSEUDO_REGISTER];
-short pj_di_vars_offset_vec[FIRST_PSEUDO_REGISTER];
-short pj_debugreg_renumber_vec[FIRST_PSEUDO_REGISTER];
-
-/* Number of fake registers in the frame, used by prologue and epilogue
- code. */
-static int nfakes;
-
-/* Whether anything has been printed to the current assembly output
- line. */
-int pj_stuff_on_line;
-
-/* Initialize the GCC target structure. */
-
-struct gcc_target targetm = TARGET_INITIALIZER;
-
-/* printf to the asm_out_file, with special format control characters
- for decoding operands.
-
- %* - start of opcode
- %d,%x,%c,%s - as printf
- %X - address constant.
- %<alpha><digit> - operand <digit> passed to pj_print_operand with code <alpha>. */
-
-static void
-pj_printf VPARAMS ((const char *template, ...))
-{
- register int c;
- int ops_read = 0;
- rtx operands[10];
-
- VA_OPEN (argptr, template);
- VA_FIXEDARG (argptr, const char *, template);
-
- while ((c = *template++))
- {
- int was_stuff_on_line = pj_stuff_on_line;
- pj_stuff_on_line = 1;
- switch (c)
- {
- case '\n':
- putc (c, asm_out_file);
- pj_stuff_on_line = 0;
- break;
- default:
- putc (c, asm_out_file);
- break;
- case '%':
- {
- switch (*template)
- {
- case '%':
- putc ('%', asm_out_file);
- template++;
- pj_stuff_on_line = 1;
- break;
- case '*':
- /* Marks start of opcode, tab out. */
- if (was_stuff_on_line)
- fprintf (asm_out_file, "; ");
- template++;
- break;
- case 'd':
- template++;
- fprintf (asm_out_file, "%d", va_arg (argptr, int));
- break;
- case 'x':
- template++;
- fprintf (asm_out_file, "%x", va_arg (argptr, int));
- break;
- case 'c':
- template++;
- fprintf (asm_out_file, "%c", va_arg (argptr, int));
- break;
- case 's':
- template++;
- fputs (va_arg (argptr, const char *), asm_out_file);
- break;
- case 'X':
- template++;
- output_addr_const (asm_out_file, va_arg (argptr, rtx));
- break;
- default:
- {
- int code = 0;
- rtx send;
-
- if (ISALPHA (*template))
- code = *template++;
- if (ISDIGIT (*template))
- {
- int num = atoi (template);
- template++;
- while (ops_read <= num)
- operands[ops_read++] = va_arg (argptr, rtx);
- send = operands[num];
- }
- else
- send = va_arg (argptr, rtx);
-
- /* A null means leave the word on the stack, so there's
- no need to do anything for that. */
-
- if (send)
- pj_print_operand (asm_out_file, send, code);
- }
- }
- }
- }
- }
- VA_CLOSE (argptr);
-}
-
-/* Output code to efficiently push a single word integer constant onto
- the opstack. */
-
-static void
-pj_output_push_int (val)
- int val;
-{
- int low = ((val & 0x8000) ? ~0xffff : 0) | (val & 0xffff);
-
- if (low == -1)
- pj_printf ("%*iconst_m1");
- else if (low >= 0 && low <= 5)
- pj_printf ("%*iconst_%d", low);
- else if (low >= -128 && low < 128)
- pj_printf ("%*bipush %d", low);
- else
- pj_printf ("%*sipush %d", low);
-
- if ((low & 0xffff0000) != (val & 0xffff0000))
- pj_printf ("%*sethi 0x%x", (val >> 16) & 0xffff);
-}
-
-/* Output code to add a constant to the value on the top of the
- opstack. */
-
-static void
-pj_output_print_add_k (int size)
-{
- if (size >= 0)
- {
- pj_output_push_int (size);
- pj_printf ("%*iadd");
- }
- else
- {
- pj_output_push_int (-size);
- pj_printf ("%*isub");
- }
-}
-
-/* Output code to load the value pointed to by the top of stack onto
- the stack. */
-
-static void
-pj_output_load (mode, uns)
- enum machine_mode mode;
- int uns;
-{
- int i;
- switch (GET_MODE_SIZE (mode))
- {
- case 1:
- pj_printf (uns ? "%*load_ubyte" : "%*load_byte");
- break;
- case 2:
- pj_printf (uns ? "%*load_char" : "%*load_short");
- break;
- case 8:
- if (TARGET_TM_EXTENSIONS)
- {
- pj_printf ("%*tm_load_long");
- break;
- }
- /* Fall through. */
- default:
- for (i = GET_MODE_SIZE (mode); i > 4; i -= 4)
- {
- pj_printf ("%*dup");
- pj_output_print_add_k (i - 4);
- pj_printf ("%*load_word");
- pj_printf ("%*swap");
- }
- pj_printf ("%*load_word");
- }
-}
-
-/* Output code to increment the provided lval operand. */
-
-static void
-pj_output_inc (op, size)
- rtx op;
- int size;
-{
- if (STACK_REG_RTX_P (op))
- pj_printf ("%*iinc %d,%d", pj_si_vars_offset_vec[REGNO (op)], size);
- else
- {
- pj_output_rval (op, SImode, 0);
- pj_output_push_int (size);
- pj_printf ("%*iadd");
- pj_output_store_into_lval (SImode, op);
- }
-}
-
-/* Output the text for a conversion operator. */
-
-static void
-pj_output_cnv_op (e, op)
- enum insn_code e;
- rtx op;
-{
- pj_printf ((const char *) insn_data[(int) e].output, 0, XEXP (op, 0));
-}
-
-/* Turn a machine_mode into an opcode modifier chararacter. */
-
-static char
-mode_to_char (mode)
- enum machine_mode mode;
-{
- switch (mode)
- {
- case QImode:
- case HImode:
- case SImode:
- return 'i';
- break;
- case DImode:
- return 'l';
- break;
- case DFmode:
- return 'd';
- break;
- case SFmode:
- return 'f';
- break;
- default:
- abort ();
- }
-}
-
-/* Output an index off the var register. If we're moving an 8 byte
- value then reduce the index, since the picoJava instruction loading
- the value uses the index of the highest part of the register as
- it's name. */
-
-static void
-pj_output_varidx (mode, do_store, idx)
- enum machine_mode mode;
- int do_store;
- int idx;
-{
- pj_printf ("%*%c%s%c%d",
- mode_to_char (mode),
- do_store ? "store" : "load",
- (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8)
- && idx <= 3 ? '_' : ' ', idx);
-}
-
-/* Output an rvalue expression. */
-
-static void
-pj_output_rval (op, mode, outer_op)
- rtx op;
- enum machine_mode mode;
- rtx outer_op;
-{
- enum rtx_code code = GET_CODE (op);
-
- optab tab;
-
- if (code == DIV && GET_MODE_CLASS (mode) == MODE_INT)
- tab = sdiv_optab;
- else
- tab = code_to_optab[code];
-
- if (code == PLUS)
- {
- pj_output_rval (XEXP (op, 0), mode, op);
- pj_output_rval (XEXP (op, 1), mode, op);
- pj_printf ("%*%cadd", mode_to_char (mode));
- }
- else if (tab && tab->handlers[mode].insn_code != CODE_FOR_nothing)
- {
- const char *const template =
- (const char *) insn_data[tab->handlers[mode].insn_code].output;
- if (code == NEG)
- pj_printf (template, 0, XEXP (op, 0));
- else
- pj_printf (template, 0, XEXP (op, 0), XEXP (op, 1));
- }
- else
- switch (GET_CODE (op))
- {
- case PC:
- fprintf (asm_out_file, " pc ");
- break;
-
- case CONST:
- pj_output_rval (XEXP (op, 0), mode, op);
- break;
-
- case MEM:
- pj_output_rval (XEXP (op, 0), Pmode, op);
- pj_output_load (mode, 0);
- break;
-
- case SYMBOL_REF:
- pj_printf ("%*ipush %X", op);
- break;
-
- case REG:
- switch (mode)
- {
- case SImode:
- case SFmode:
- case HImode:
- case QImode:
- if (pj_si_vars_offset_vec[REGNO (op)] >= 0)
- pj_output_varidx (mode, 0, pj_si_vars_offset_vec[REGNO (op)]);
- else
- pj_printf ("%*read_%s", reg_names[REGNO (op)]);
- break;
- case DImode:
- case DFmode:
- if (pj_di_vars_offset_vec[REGNO (op)] >= 0)
- pj_output_varidx (mode, 0, pj_di_vars_offset_vec[REGNO (op)]);
- else
- switch (REGNO (op))
- {
- case G1_REG:
- pj_printf ("%*read_global2");
- pj_printf ("%*read_global1");
- break;
-
- /* A 64 bit read of global0 gives global0 and
- optop. */
- case G0_REG:
- pj_printf ("%*read_optop");
- pj_printf ("%*read_global0");
- break;
-
- default:
- abort ();
- }
- break;
- default:
- abort ();
- }
- break;
-
- case CONST_DOUBLE:
- pj_printf (pj_standard_float_constant (op));
- break;
-
- case CONST_INT:
- if (mode == SImode || mode == HImode || mode == QImode)
- pj_output_push_int (INTVAL (op));
- else if (mode == DImode)
- {
- int v = INTVAL (op);
- if (v == 1)
- pj_printf ("%*lconst_1", 0);
- else if (v == 0)
- pj_printf ("%*lconst_0", 0);
- else
- {
- rtx hi = GEN_INT (v < 0 ? -1 : 0);
- rtx lo = op;
- pj_output_rval (TARGET_LITTLE_ENDIAN ? hi : lo, SImode, op);
- pj_output_rval (TARGET_LITTLE_ENDIAN ? lo : hi, SImode, op);
- }
- }
- else
- abort ();
- break;
-
- case FLOAT_TRUNCATE:
- pj_printf ("%S0%*d2f", XEXP (op, 0));
- break;
- case LABEL_REF:
- pj_printf ("%*ipush %X", XEXP (op, 0));
- break;
-
- case SUBREG:
- pj_output_rval (alter_subreg (&op), mode, outer_op);
- break;
-
- case POST_INC:
- pj_output_rval (XEXP (op, 0), mode, op);
- pj_output_inc (XEXP (op, 0), GET_MODE_SIZE (GET_MODE (outer_op)));
- break;
-
- case POST_DEC:
- pj_output_rval (XEXP (op, 0), mode, op);
- pj_output_inc (XEXP (op, 0), -GET_MODE_SIZE (GET_MODE (outer_op)));
- break;
-
- case PRE_INC:
- pj_output_inc (XEXP (op, 0), GET_MODE_SIZE (GET_MODE (outer_op)));
- pj_output_rval (XEXP (op, 0), mode, op);
- break;
-
- case PRE_DEC:
- if (OPTOP_REG_RTX_P (XEXP (op, 0)))
- pj_output_rval (XEXP (op, 0), mode, op);
- else if (STACK_REG_RTX_P (XEXP (op, 0)))
- {
- pj_output_inc (XEXP (op, 0),
- -GET_MODE_SIZE (GET_MODE (outer_op)));
- pj_output_rval (XEXP (op, 0), mode, op);
- }
- else
- {
- pj_printf ("%S0", XEXP (op, 0));
- pj_output_print_add_k (-GET_MODE_SIZE (GET_MODE (outer_op)));
- pj_printf ("%*dup%R0", XEXP (op, 0));
- }
- break;
-
- case FIX:
- pj_output_cnv_op (fixtrunctab[GET_MODE (XEXP (op, 0))][mode][0], op);
- break;
-
- case FLOAT:
- if (mode == DFmode && GET_CODE (XEXP (op, 0)) == CONST_INT)
- pj_output_cnv_op (floattab[mode][SImode][0], op);
- else
- pj_output_cnv_op (floattab[mode][GET_MODE (XEXP (op, 0))][0], op);
- break;
-
- case FLOAT_EXTEND:
- case SIGN_EXTEND:
- /* Sign extending from a memop to register is automatic. */
- if (mode == SImode && GET_CODE (XEXP (op, 0)) == MEM)
- pj_output_rval (XEXP (op, 0), GET_MODE (XEXP (op, 0)), op);
- else
- pj_output_cnv_op (extendtab[mode][GET_MODE (XEXP (op, 0))][0], op);
- break;
-
- case ZERO_EXTEND:
- pj_output_cnv_op (extendtab[mode][GET_MODE (XEXP (op, 0))][1], op);
- break;
-
- default:
- abort ();
- break;
- }
-}
-
-/* Store the top of stack into the lval operand OP. */
-
-static void
-pj_output_store_into_lval (mode, op)
- enum machine_mode mode;
- rtx op;
-{
- if (GET_CODE (op) == REG)
- {
- int rn = REGNO (op);
-
- /* Outgoing values are left on the stack and not written
- anywhere. */
- if (!OUTGOING_REG_RTX_P (op))
- {
- switch (GET_MODE (op))
- {
- case SImode:
- case QImode:
- case HImode:
- case SFmode:
- if (pj_si_vars_offset_vec[rn] >= 0)
- pj_output_varidx (mode, 1, pj_si_vars_offset_vec[rn]);
- else
- pj_printf ("%*write_%s", reg_names[rn]);
- break;
- case DImode:
- case DFmode:
- if (pj_di_vars_offset_vec[rn] >= 0)
- pj_output_varidx (mode, 1, pj_di_vars_offset_vec[rn]);
- else
- switch (rn)
- {
- case G1_REG:
- pj_printf ("%*write_global1");
- pj_printf ("%*write_global2");
- break;
- default:
- abort ();
- }
- break;
- default:
- abort ();
- }
- }
- }
- else
- {
- pj_output_rval (XEXP (op, 0), Pmode, op);
-
- switch (GET_MODE_SIZE (mode))
- {
- case 1:
- pj_printf ("%*store_byte", 0);
- break;
- case 2:
- pj_printf ("%*store_short", 0);
- break;
- case 8:
- if (TARGET_TM_EXTENSIONS)
- {
- pj_printf ("%*tm_store_long");
- break;
- }
- /* Fall through. */
- default:
- {
- int i;
- for (i = GET_MODE_SIZE (mode); i > 4; i -= 4)
- {
- pj_printf ("%*dup_x1", 0);
- pj_printf ("%*store_word", 0);
- pj_printf ("%*iconst_4", 0);
- pj_printf ("%*iadd", 0);
- }
- }
- pj_printf ("%*store_word", 0);
- break;
- }
- }
-}
-
-/* Print a condition, unsigned and signed have the same text because
- the unsigned operands have been run through icmp first. */
-
-static void
-pj_print_cond (code)
- enum rtx_code code;
-{
- switch (code)
- {
- case EQ:
- fputs ("eq", asm_out_file);
- break;
- case NE:
- fputs ("ne", asm_out_file);
- break;
- case GT:
- case GTU:
- fputs ("gt", asm_out_file);
- break;
- case GE:
- case GEU:
- fputs ("ge", asm_out_file);
- break;
- case LT:
- case LTU:
- fputs ("lt", asm_out_file);
- break;
- case LE:
- case LEU:
- fputs ("le", asm_out_file);
- break;
- default:
- abort ();
- }
-}
-/* Print operand X (an rtx) in assembler syntax to file STREAM
- according to modifier CODE.
-
- C emit the first part of a Check_call pseudop.
- D emit operand, if no mode, assume DImode.
- E emit the second part of a check_call pseudop.
- I print the XEXP (X, 0) Inside of the operand.
- J print Just the integer or register part of an operand, for iinc.
- P emit source is SI padded to DI with 0, used for unsigned mod and divide.
- R emit the operand as an lval Result.
- S emit Source operand, if no mode, assume SImode.
- X nan choice suffix for floating point comparision.
- Y condition name from op.
- Z Y, reversed.
- * marks start of opcode. */
-
-void
-pj_print_operand (stream, x, code)
- FILE *stream;
- rtx x;
- int code;
-{
- static int last_call_known;
- switch (code)
- {
- case 'C':
- if (GET_CODE (x) == SYMBOL_REF)
- {
- last_call_known = 1;
- pj_printf ("%*.check_call %0", x);
- }
- else
- last_call_known = 0;
- break;
-
- case 'D':
- pj_output_rval (x,
- GET_MODE (x) == VOIDmode ? DImode : GET_MODE (x),
- NULL_RTX);
- break;
-
- case 'E':
- if (last_call_known)
- pj_printf (",%d", INTVAL (x));
- break;
-
- case 'I':
- pj_output_rval (XEXP (x, 0), GET_MODE (XEXP (x, 0)), NULL_RTX);
- break;
-
- case 'J':
- if (GET_CODE (x) == CONST_INT)
- pj_printf ("%d", INTVAL (x));
- else if (GET_CODE (x) == REG)
- pj_printf ("%d", pj_si_vars_offset_vec[REGNO (x)]);
- else
- abort ();
- break;
-
- case 'P':
- if (TARGET_LITTLE_ENDIAN)
- pj_printf ("%*iconst_0", 0);
- pj_output_rval (x,
- GET_MODE (x) == VOIDmode ? SImode : GET_MODE (x),
- NULL_RTX);
- if (!TARGET_LITTLE_ENDIAN)
- pj_printf ("%*iconst_0", 0);
- break;
-
- case 'R':
- pj_output_store_into_lval (GET_MODE (x), x);
- break;
-
- case 'S':
- pj_output_rval (x,
- GET_MODE (x) == VOIDmode ? SImode : GET_MODE (x),
- NULL_RTX);
- break;
-
- case 'X':
- fputc (GET_CODE (x) == LT || GET_CODE (x) == LE ? 'g' : 'l', stream);
- break;
-
- case 'Y':
- pj_print_cond (GET_CODE (x));
- break;
-
- case 'Z':
- pj_print_cond (reverse_condition (GET_CODE (x)));
- break;
-
- case '*':
- pj_printf ("%*");
- break;
-
- default:
- output_addr_const (stream, x);
- break;
- }
-}
-
-/* Return in an rtx the number of words pushed onto the optop to be
- used as the word count in a call insn. (NEXT_ARG_REG is NULL when
- called from expand_builtin_apply). */
-
-rtx
-pj_workout_arg_words (stack_size, next_arg_reg)
- rtx stack_size ATTRIBUTE_UNUSED;
- rtx next_arg_reg;
-{
- return GEN_INT ((next_arg_reg ? REGNO (next_arg_reg) - O0_REG : 0) + 2);
-}
-
-/* Handle the INCOMING_FUNCTION_ARG macro.
- Determine where to put an argument to a function.
- Value is zero to push the argument on the stack,
- or a hard register in which to store the argument.
-
- CUM is a variable of type CUMULATIVE_ARGS which gives info about
- the preceding args and about the function being called.
- MODE is the argument's machine mode.
- TYPE is the data type of the argument (as a tree).
- This is null for libcalls where that information may
- not be available.
- NAMED is nonzero if this argument is a named parameter
- (otherwise it is an extra parameter matching an ellipsis). */
-
-rtx
-pj_function_incoming_arg (cum, mode, passed_type, named_arg)
- CUMULATIVE_ARGS *cum;
- enum machine_mode mode;
- tree passed_type ATTRIBUTE_UNUSED;
- int named_arg ATTRIBUTE_UNUSED;
-{
- int arg_words = PJ_ARG_WORDS (mode);
-
- /* If the whole argument will fit into registers, return the first
- register needed. Also fill in the arg_adjust information so that
- we can work out the right offset to use when looking at the
- insides of a DI or DF value. */
-
- if (cum->total_words + arg_words <= ARGS_IN_REGS)
- {
- int i;
- if (mode == DImode || mode == DFmode)
- {
- cum->arg_adjust[cum->total_words + 0] = 1;
- cum->arg_adjust[cum->total_words + 1] = -1;
- }
- else
- for (i = 0; i < arg_words; i++)
- cum->arg_adjust[cum->total_words + i] = 0;
-
- return gen_rtx (REG, mode, I0_REG + cum->total_words);
- }
- return NULL_RTX;
-}
-
-/* Output code to add two SImode values. Deals carefully with the the common
- case of moving the optop. */
-
-const char *
-pj_output_addsi3 (operands)
- rtx *operands;
-{
- if (OPTOP_REG_RTX_P (operands[0]) && OPTOP_REG_RTX_P (operands[1])
- && GET_CODE (operands[2]) == CONST_INT
- && INTVAL (operands[2]) >= -32 && INTVAL (operands[2]) <= 32)
- {
- static struct
- {
- const char *two;
- const char *one;
- }
- name[2] =
- {
- { "pop2", "pop"},
- { "lconst_0", "iconst_0"}
- };
- int size = INTVAL (operands[2]);
- int d = 0;
-
- if (size < 0)
- {
- d = 1;
- size = -size;
- }
-
- for (; size >= 8; size -= 8)
- output_asm_insn (name[d].two, 0);
-
-
- if (size > 0)
- output_asm_insn (name[d].one, 0);
-
- return "";
- }
-
- if (STACK_REG_RTX_P (operands[0])
- && rtx_equal_p (operands[0], operands[1])
- && GET_CODE (operands[2]) == CONST_INT
- && INTVAL (operands[2]) >= -128 && INTVAL (operands[2]) <= 127)
- {
- return "iinc %J0,%J2";
- }
-
- return "%S1%S2%*iadd%R0";
-}
-
-/* Generate rtl for the prologue of the current function. */
-
-void
-pj_expand_prologue ()
-{
- int i;
- int off = 0;
- int arg_words = current_function_args_info.named_words;
-
- memset (pj_si_vars_offset_vec, -1, sizeof (pj_si_vars_offset_vec));
- memset (pj_di_vars_offset_vec, -1, sizeof (pj_di_vars_offset_vec));
-
- /* Work out the register numbers of the named arguments. */
- for (i = 0; i < current_function_args_info.named_words; i++)
- {
- pj_debugreg_renumber_vec[I0_REG + i]
- = off + R0_REG + current_function_args_info.arg_adjust[i];
- pj_si_vars_offset_vec[I0_REG + i]
- = off + current_function_args_info.arg_adjust[i];
- pj_di_vars_offset_vec[I0_REG + i] = off;
- off++;
- }
-
- if (current_function_varargs || current_function_stdarg)
- {
- /* If the function is varadic we need to call the vhelper
- function. vhelper pops off the unnamed argument words from
- the opstack and puts them onto the the aggregate stack. The
- unnamed words are replacedwith two extra arguments, a pointer
- to the aggreagate stack for the first vararg and the original
- global0 value. */
-
- emit_insn (gen_varargs (GEN_INT (arg_words * 4)));
- pj_si_vars_offset_vec[VA_REG] = off++;
- off++;
- arg_words += 2;
- }
-
- /* Skip over the return pc and old vars in the frame. */
- off += 2;
-
- /* Work out the register numbers and offsets from the var pointer
- for the normal registers. */
- nfakes = 0;
-
- for (i = LAST_I_REG; i >= R0_REG; i--)
- if (regs_ever_live[i] && pj_si_vars_offset_vec[i] == -1)
- {
- nfakes++;
- pj_si_vars_offset_vec[i] = off;
- pj_di_vars_offset_vec[i] = off - 1;
- pj_debugreg_renumber_vec[i] = off + R0_REG;
- off++;
- }
-
- if (TARGET_TEST)
- {
- fprintf (asm_out_file, "\n\t! args %d, size %d, fakes %d\n",
- arg_words,
- get_frame_size () / 4,
- nfakes);
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (pj_si_vars_offset_vec[i] >= 0)
- fprintf (asm_out_file, "\t!vars - %d %d: %s\n",
- pj_si_vars_offset_vec[i],
- pj_di_vars_offset_vec[i],
- reg_names[i]);
- }
-
- /* Make room on the opstack for the fake registers. */
- if (TARGET_TM_EXTENSIONS)
- RTX_FRAME_RELATED_P (emit_insn (gen_tm_frame (GEN_INT (arg_words),
- GEN_INT (nfakes)))) = 1;
- else
- RTX_FRAME_RELATED_P (emit_insn
- (gen_addsi3
- (gen_rtx_REG (SImode, OPTOP_REG),
- gen_rtx_REG (SImode, OPTOP_REG),
- GEN_INT (-nfakes * 4)))) = 1;
-
-
- if (frame_pointer_needed)
- emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
-
- if (get_frame_size ())
- RTX_FRAME_RELATED_P (emit_insn (gen_addsi3 (stack_pointer_rtx,
- stack_pointer_rtx,
- GEN_INT
- (-get_frame_size ())))) = 1;
-
- emit_insn (gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, OPTOP_REG)));
-}
-
-/* Generate rtl for the epilogue of the current function. */
-
-void
-pj_expand_epilogue ()
-{
- if (frame_pointer_needed)
- emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
- else if (get_frame_size ())
- emit_insn (gen_addsi3 (stack_pointer_rtx,
- stack_pointer_rtx, GEN_INT (get_frame_size ())));
- if (nfakes)
- emit_insn (gen_addsi3 (gen_rtx_REG (SImode, OPTOP_REG),
- gen_rtx_REG (SImode, OPTOP_REG),
- GEN_INT (nfakes * 4)));
-
-
- /* If this is a varargs function, then global0 is stashed away on
- the top of the optop stack as the last secret argument by the
- __vhelper. Pop off the va pointer provided too. */
-
- if (current_function_varargs || current_function_stdarg)
- emit_insn (gen_varargs_finish
- (GEN_INT (current_function_args_info.named_words + 1)));
-
- emit_insn (gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, OPTOP_REG)));
-}
-
-/* Return the opcode name for an instruction to load a standard
- floating point constant, or NULL. */
-
-const char *
-pj_standard_float_constant (op)
- rtx op;
-{
- REAL_VALUE_TYPE r;
- enum machine_mode mode = GET_MODE (op);
-
- if (GET_CODE (op) != CONST_DOUBLE || (mode != DFmode && mode != SFmode))
- return NULL;
-
- REAL_VALUE_FROM_CONST_DOUBLE (r, op);
-
- if (REAL_VALUES_EQUAL (r, dconst0) && !REAL_VALUE_MINUS_ZERO (r))
- return mode == DFmode ? "%*dconst_0" : "%*fconst_0";
-
- if (REAL_VALUES_EQUAL (r, dconst1))
- return mode == DFmode ? "%*dconst_1" : "%*fconst_1";
-
- if (REAL_VALUES_EQUAL (r, dconst2))
- return mode == DFmode ? 0 : "%*fconst_2";
-
- return NULL;
-}
-
-/* Read the value at the current address, and decrement by the size.
- The function is interesting because we're reading from high memory to low memory
- and have to adjust the addresses of reads of 8 byte values
- accordingly. */
-
-rtx
-pj_expand_builtin_va_arg (valist, type)
- tree valist;
- tree type;
-{
- tree addr_tree, t;
- HOST_WIDE_INT align;
- HOST_WIDE_INT rounded_size;
- rtx addr;
-
- /* Compute the rounded size of the type. */
- align = PARM_BOUNDARY / BITS_PER_UNIT;
- rounded_size = (((int_size_in_bytes (type) + align - 1) / align) * align);
-
- /* Get AP. */
- addr_tree = valist;
- addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
- addr = copy_to_reg (addr);
-
- /* Aggregates and large scalars are passed by reference. */
- if (AGGREGATE_TYPE_P (type) || rounded_size > 8)
- {
- addr = gen_rtx_MEM (Pmode, addr);
- rounded_size = 4;
- }
-
- /* adjust address to cope with double word sizes */
- if (rounded_size > 4)
- addr = gen_rtx_PLUS (Pmode, addr, GEN_INT (-4));
-
- /* Compute new value for AP; AP = AP - SIZE */
- t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
- build (MINUS_EXPR, TREE_TYPE (valist), valist,
- build_int_2 (rounded_size, 0)));
-
- TREE_SIDE_EFFECTS (t) = 1;
-
- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
-
- return addr;
-}
-
-/* Return nonzero if the operand is valid as a source operand; it's
- general and it's not an outgoing argument register. */
-
-int
-pj_source_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return !OUTGOING_REG_RTX_P (op) && general_operand (op, mode);
-}
-
-/* Return nonzero if the operator is a signed compare. */
-
-int
-pj_signed_comparison_operator (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- if (mode != GET_MODE (op))
- return 0;
-
- switch (GET_CODE (op))
- {
- case EQ:
- case NE:
- case LE:
- case LT:
- case GE:
- case GT:
- return 1;
- default:
- return 0;
- }
-}
-
-/* Return nonzero if the operator is an unsigned compare. */
-
-int
-pj_unsigned_comparison_operator (op, mode)
- rtx op;
- enum machine_mode mode ATTRIBUTE_UNUSED;
-{
- if (mode != GET_MODE (op))
- return 0;
-
- switch (GET_CODE (op))
- {
- case GTU:
- case GEU:
- case LTU:
- case LEU:
- return 1;
- default:
- return 0;
- }
-}
-
-/* Helper function for pj_machine_dependent_reorg. Find the one
- instance of register OP in the source part of PAT. If there are no
- copies return NULL, if there are more than one, return NOT_UNIQUE. */
-
-#define NOT_UNIQUE (&const0_rtx)
-
-static rtx *
-unique_src_operand (pat, reg)
- rtx *pat;
- rtx reg;
-{
- register rtx *result = 0;
- register const char *fmt;
- register int i;
- register int j;
-
- if (GET_CODE (*pat) == SET)
- {
- if (GET_CODE (XEXP (*pat, 0)) == MEM)
- result = unique_src_operand (&XEXP (SET_DEST (*pat), 0), reg);
- pat = &SET_SRC (*pat);
- }
-
- if (GET_CODE (*pat) == REG && REGNO (*pat) == REGNO (reg))
- return pat;
-
- fmt = GET_RTX_FORMAT (GET_CODE (*pat));
- for (i = GET_RTX_LENGTH (GET_CODE (*pat)) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- {
- rtx *new_result = unique_src_operand (&XEXP (*pat, i), reg);
-
- if (new_result)
- {
- if (result)
- return NOT_UNIQUE;
- result = new_result;
- }
- }
- else if (fmt[i] == 'E')
- {
- for (j = XVECLEN (*pat, i) - 1; j >= 0; j--)
- {
- rtx *new_result =
- unique_src_operand (&XVECEXP (*pat, i, j), reg);
-
- if (new_result)
- {
- if (result)
- return NOT_UNIQUE;
- result = new_result;
- }
- }
- }
- }
- return result;
-}
-
-/* Clean up the instructions to remove unneeded loads and stores.
-
- For example, rewrite
-
- iload a; iload b; iadd; istore z
- iload z; iload c; iadd; istore z
-
- as
-
- iload a; iload b; iadd ; iload c; iadd; istore z
-
- This function moves a cursor over each instruction, inspecting the
- LOG_LINKS. Each of the cursor's LOG_LINK incoming instructions are
- inspected, any which have a simple register destination which is
- also used as a source in the cursor instruction, and aren't used
- again between the the incoming instruction and the cursor, and
- which become dead or set after the cursor get their sources
- substituted into the position of the source register in the cursor
- instruction. */
-
-void
-pj_machine_dependent_reorg (insns)
- rtx insns;
-{
- rtx cursor;
-
- if (!optimize || !TARGET_REORG)
- return;
-
- for (cursor = insns; cursor; cursor = NEXT_INSN (cursor))
- {
- rtx links;
- rtx cursor_pat;
-
- /* We only care about INSNs, JUMP_INSNs. Ignore any special USE insns. */
-
- if ((GET_CODE (cursor) != INSN && GET_CODE (cursor) != JUMP_INSN)
- || GET_CODE (cursor_pat = PATTERN (cursor)) == USE
- || GET_CODE (cursor_pat) == CLOBBER
- || GET_CODE (cursor_pat) == ADDR_VEC
- || GET_CODE (cursor_pat) == ADDR_DIFF_VEC)
- continue;
-
- for (links = LOG_LINKS (cursor); links; links = XEXP (links, 1))
- {
- rtx prev = XEXP (links, 0);
- rtx prev_pat;
- rtx prev_dest;
- rtx prev_src;
- rtx *dst_place;
-
- if (GET_CODE (prev) == INSN
- && GET_CODE (prev_pat = PATTERN (prev)) == SET
- && GET_CODE (prev_dest = SET_DEST (prev_pat)) == REG
- && dead_or_set_p (cursor, prev_dest)
- && !reg_used_between_p (prev_dest, prev, cursor)
- && no_labels_between_p (prev, cursor)
- && no_jumps_between_p (prev, cursor)
- && !modified_between_p ((prev_src = SET_SRC (prev_pat)), prev,
- cursor)
- && (dst_place = unique_src_operand (&cursor_pat, prev_dest))
- && dst_place != NOT_UNIQUE
- && REGNO (prev_dest) != OPTOP_REG
- && GET_MODE (prev_dest) != XFmode
- && GET_MODE (*dst_place) == GET_MODE (SET_DEST (prev_pat)))
- {
- *dst_place = SET_SRC (prev_pat);
- PUT_CODE (prev, NOTE);
- NOTE_LINE_NUMBER (prev) = NOTE_INSN_DELETED;
- }
- }
- }
-}