diff options
Diffstat (limited to 'gcc/config/pj/pj.c')
-rw-r--r-- | gcc/config/pj/pj.c | 1286 |
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; - } - } - } -} |