URL
https://opencores.org/ocsvn/or1k_old/or1k_old/trunk
Subversion Repositories or1k_old
[/] [or1k_old/] [trunk/] [gcc/] [gcc-3.4.4/] [gcc-3.4.4-or32-unified.diff] - Rev 1782
Compare with Previous | Blame | View Log
diff -Nru gcc-3.4.4.orig/config.sub gcc-3.4.4-DONE/config.sub --- gcc-3.4.4.orig/config.sub 2004-02-22 16:44:23.000000000 +0200 +++ gcc-3.4.4-DONE/config.sub 2005-12-13 17:38:35.000000000 +0200 @@ -256,7 +256,7 @@ | mn10200 | mn10300 \ | msp430 \ | ns16k | ns32k \ - | openrisc | or32 \ + | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ @@ -750,9 +750,8 @@ basic_machine=hppa1.1-oki os=-proelf ;; - or32 | or32-*) - basic_machine=or32-unknown - os=-coff + or32 | or32-*) + basic_machine=or32-`echo $basic_machine | sed 's/^[^-]*-//'` ;; os400) basic_machine=powerpc-ibm @@ -1355,8 +1354,8 @@ mips*-*) os=-elf ;; - or32-*) - os=-coff + or32-*) + os=-elf ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 diff -Nru gcc-3.4.4.orig/configure.in gcc-3.4.4-DONE/configure.in --- gcc-3.4.4.orig/configure.in 2005-03-08 19:31:40.000000000 +0200 +++ gcc-3.4.4-DONE/configure.in 2005-12-13 17:38:35.000000000 +0200 @@ -608,6 +608,9 @@ mn10300-*-*) noconfigdirs="$noconfigdirs ${libgcj}" ;; + or32-*-*) + noconfigdirs="$noconfigdirs target-libgloss ${libgcj}" + ;; powerpc-*-aix*) # copied from rs6000-*-* entry noconfigdirs="$noconfigdirs gprof target-libgloss ${libgcj}" diff -Nru gcc-3.4.4.orig/gcc/config/or32/default.h gcc-3.4.4-DONE/gcc/config/or32/default.h --- gcc-3.4.4.orig/gcc/config/or32/default.h 1970-01-01 02:00:00.000000000 +0200 +++ gcc-3.4.4-DONE/gcc/config/or32/default.h 2005-11-29 16:23:09.000000000 +0200 @@ -0,0 +1,74 @@ +/* Definitions of target machine for GNU compiler for OR1K running Linux. + (Actually OR1K is not yet running Linux but eventually it will). + Copyright (C) 1996, 1997, 1998, 2005 Free Software Foundation, Inc. + Contributed by Damjan Lampret <damjanl@bsemi.com> in 1999. + Based upon the rs6000 port. + +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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES \ + "-DOR1K -D__or1k__ -D__OR1K__ -D__ELF__ -Dunix -Dlinux -Dor1k -Asystem(unix) -Asystem(linux) -Acpu(or1k) -Amachine(or1k)" + +#undef CPP_OS_DEFAULT_SPEC +#define CPP_OS_DEFAULT_SPEC "%(cpp_os_linux)" + +#undef LINK_SPEC +#define LINK_SPEC "-m elf32or32 %{G*} %{shared:-shared} \ + %{!shared: \ + %{!static: \ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/ld.so.1}} \ + %{static:-static}}" + +#undef LIB_DEFAULT_SPEC +#define LIB_DEFAULT_SPEC "%(lib_linux)" + +#undef STARTFILE_DEFAULT_SPEC +#define STARTFILE_DEFAULT_SPEC "%(startfile_linux)" + +#undef ENDFILE_DEFAULT_SPEC +#define ENDFILE_DEFAULT_SPEC "%(endfile_linux)" + +#undef LINK_START_DEFAULT_SPEC +#define LINK_START_DEFAULT_SPEC "%(link_start_linux)" + +#undef LINK_OS_DEFAULT_SPEC +#define LINK_OS_DEFAULT_SPEC "%(link_os_linux)" + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (OpenRISC 1000 GNU/Linux)"); + +/* Define this macro as a C expression for the initializer of an + array of string to tell the driver program which options are + defaults for this target and thus do not need to be handled + specially when using `MULTILIB_OPTIONS'. + + Do not define this macro if `MULTILIB_OPTIONS' is not defined in + the target makefile fragment or if none of the options listed in + `MULTILIB_OPTIONS' are set by default. *Note Target Fragment::. */ + +#undef MULTILIB_DEFAULTS +#define MULTILIB_DEFAULTS { "mbig", "mcall-linux" } + +#undef DEFAULT_VTABLE_THUNKS +#ifndef USE_GNULIBC_1 +#define DEFAULT_VTABLE_THUNKS 1 +#endif + +#undef JUMP_TABLES_IN_TEXT_SECTION +#define JUMP_TABLES_IN_TEXT_SECTION 0 diff -Nru gcc-3.4.4.orig/gcc/config/or32/elf.h gcc-3.4.4-DONE/gcc/config/or32/elf.h --- gcc-3.4.4.orig/gcc/config/or32/elf.h 1970-01-01 02:00:00.000000000 +0200 +++ gcc-3.4.4-DONE/gcc/config/or32/elf.h 2005-11-29 16:23:09.000000000 +0200 @@ -0,0 +1,45 @@ +/* Definitions for rtems targeting an OpenRisc OR32 using COFF + Copyright (C) 1996, 1997, 2005 Free Software Foundation, Inc. + Contributed by Joel Sherrill (joel@OARcorp.com). + +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. */ + +#undef TARGET_VERSION +#define TARGET_VERSION fputs (" (OR32/ELF)", stderr); + +/* Use ELF */ +#undef OBJECT_FORMAT_ELF +#define OBJECT_FORMAT_ELF + +/* use SDB debugging info and make it default */ +#undef DBX_DEBUGGING_INFO +#define DBX_DEBUGGING_INFO + +#undef PREFERRED_DEBUGGING_TYPE +#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG + +#undef PUT_SDB_DEF +#define PUT_SDB_DEF + +/* Generate calls to memcpy, memcmp and memset. */ +#ifndef TARGET_MEM_FUNCTIONS +# define TARGET_MEM_FUNCTIONS +#endif + +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "_" diff -Nru gcc-3.4.4.orig/gcc/config/or32/linux-elf.h gcc-3.4.4-DONE/gcc/config/or32/linux-elf.h --- gcc-3.4.4.orig/gcc/config/or32/linux-elf.h 1970-01-01 02:00:00.000000000 +0200 +++ gcc-3.4.4-DONE/gcc/config/or32/linux-elf.h 2005-11-29 16:23:09.000000000 +0200 @@ -0,0 +1,65 @@ +/* Definitions for or32 running Linux-based GNU systems using ELF + Copyright (C) 2002, 2005 + Free Software Foundation, Inc. + Contributed by Marko Mlinar <markom@opencores.org> + +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 this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* elfos.h should have already been included. Now just override + any conflicting definitions and add any extras. */ + +/* Run-time Target Specification. */ +#undef TARGET_VERSION +#define TARGET_VERSION fputs (" (OR32 GNU/Linux with ELF)", stderr); + +/* Do not assume anything about header files. */ +#define NO_IMPLICIT_EXTERN_C + +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "_" + + +/* This is how we tell the assembler that two symbols have the same value. */ +#define ASM_OUTPUT_DEF(FILE, NAME1, NAME2) \ + do \ + { \ + assemble_name (FILE, NAME1); \ + fputs (" = ", FILE); \ + assemble_name (FILE, NAME2); \ + fputc ('\n', FILE); \ + } \ + while (0) + + +#if 0 +/* Node: Label Output */ + +#define SET_ASM_OP "\t.set\t" + +#define ASM_OUTPUT_EXTERNAL_LIBCALL(FILE, FUN) \ + (*targetm.asm_out.globalize_label) (FILE, XSTR (FUN, 0)) + +#define ASM_WEAKEN_LABEL(FILE, NAME) \ + do \ + { \ + fputs ("\t.weak\t", (FILE)); \ + assemble_name ((FILE), (NAME)); \ + fputc ('\n', (FILE)); \ + } \ + while (0) +#endif diff -Nru gcc-3.4.4.orig/gcc/config/or32/linux-gas.h gcc-3.4.4-DONE/gcc/config/or32/linux-gas.h --- gcc-3.4.4.orig/gcc/config/or32/linux-gas.h 1970-01-01 02:00:00.000000000 +0200 +++ gcc-3.4.4-DONE/gcc/config/or32/linux-gas.h 2005-11-29 16:23:09.000000000 +0200 @@ -0,0 +1,37 @@ +/* Definitions of target machine for GNU compiler. + Or32 Linux-based GNU systems version. + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + Contributed by Marko Mlinar <markom@opencores.org> + +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 this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Unsigned chars produces much better code than signed. */ +#undef DEFAULT_SIGNED_CHAR +#define DEFAULT_SIGNED_CHAR 1 + +/* Make gcc agree with <machine/ansi.h> */ + +#define SIZE_TYPE "unsigned int" +#define PTRDIFF_TYPE "int" +#define WCHAR_TYPE "unsigned int" +#define WCHAR_TYPE_SIZE 32 + + +/* Clear the instruction cache from `beg' to `end'. This makes an + inline system call to SYS_cacheflush. */ +#define CLEAR_INSN_CACHE(BEG, END) /* Do something here !!! */ diff -Nru gcc-3.4.4.orig/gcc/config/or32/or32.c gcc-3.4.4-DONE/gcc/config/or32/or32.c --- gcc-3.4.4.orig/gcc/config/or32/or32.c 1970-01-01 02:00:00.000000000 +0200 +++ gcc-3.4.4-DONE/gcc/config/or32/or32.c 2005-11-29 16:23:09.000000000 +0200 @@ -0,0 +1,1260 @@ +/* Subroutines for insn-output.c for GNU compiler. OpenRISC 1000 version. + Copyright (C) 1987, 1992, 1997, 1999, 2000, 2001, 2002, 2003, 2004, + 2005 Free Software Foundation, Inc + Contributed by Damjan Lampret <damjanl@bsemi.com> in 1999. + Major optimizations by Matjaz Breskvar <matjazb@bsemi.com> in 2005. + +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 1, 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. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "real.h" +#include "insn-config.h" +#include "conditions.h" +#include "insn-attr.h" +#include "flags.h" +#include "tree.h" +#include "expr.h" +#include "except.h" +#include "function.h" +#include "toplev.h" +#include "recog.h" +#include "tm_p.h" +#include "debug.h" +#include "output.h" +#include "target.h" +#include "target-def.h" +#include "ggc.h" +#include "optabs.h" + +/* Set thist to nonzero if you want l.nop instruction in delay slot + of l.jr instruction in epilogue. */ +#define NOP_DELAY_SLOT_FILL 0 + +/* This is the pseudo register number that holds the comparison flags */ + +#define FLAGS_REG 32 + +/* Save information from a "cmpxx" operation until the branch or scc is + emitted. */ +rtx or32_compare_op0, or32_compare_op1; + +/* used in function prologue/epilogue generation */ +extern int leaf_function; + +/* Local function prototypes */ +static void or32_output_function_prologue (FILE * file, HOST_WIDE_INT vars); +static void or32_output_function_epilogue (FILE * file, HOST_WIDE_INT vars); +static bool or32_save_reg_p (int regno); +HOST_WIDE_INT or32_compute_frame_size (HOST_WIDE_INT size); +static rtx emit_frame_insn (rtx insn); +static rtx indexed_memory (rtx base, HOST_WIDE_INT disp); +void or32_expand_prologue (void); +void or32_expand_epilogue (int sibcall); +const char *or32_output_move_double (rtx * operands); +enum rtx_code or32_reverse_condition (enum machine_mode mode, + enum rtx_code code); +enum machine_mode or32_cc_mode (enum rtx_code code, rtx op0, rtx op1); +rtx or32_expand_compare (enum rtx_code code, rtx op0, rtx op1); +void or32_expand_branch (enum rtx_code code, rtx label); +static int or32_emit_int_cmove (rtx dest, rtx op, rtx true_cond, + rtx false_cond); +int or32_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond); +const char *output_cmov (rtx * operands); +const char *output_bf (rtx * operands); +void or32_emit_set_const32 (rtx op0, rtx op1); +int or32_register_move_cost (enum machine_mode mode, enum reg_class from, + enum reg_class to); +int or32_memory_move_cost (enum machine_mode mode, enum reg_class class, + int in); +int or32_branch_cost (); + + +#undef TARGET_ASM_FUNCTION_PROLOGUE +#define TARGET_ASM_FUNCTION_PROLOGUE or32_output_function_prologue +#undef TARGET_ASM_FUNCTION_EPILOGUE +#define TARGET_ASM_FUNCTION_EPILOGUE or32_output_function_epilogue + +static bool or32_function_ok_for_sibcall (tree decl, tree exp); + +#undef TARGET_FUNCTION_OK_FOR_SIBCALL +#define TARGET_FUNCTION_OK_FOR_SIBCALL or32_function_ok_for_sibcall + + +/* Initialize the GCC target structure. */ +struct gcc_target targetm = TARGET_INITIALIZER; + +/* Stack layout we use for pushing and poping saved registers */ +struct or32_frame_info +{ + bool save_lr_p; + int lr_save_offset; + bool save_fp_p; + int fp_save_offset; + int gpr_size; + int gpr_offset; + int total_size; + int vars_size; + int args_size; + HOST_WIDE_INT mask; +}; + +static struct or32_frame_info frame_info; + +/* Returns 1 if OP is either a pseudo-register or a register denoting a + CR field. */ + +int +cc_reg_operand (rtx op, enum machine_mode mode) +{ + register_operand (op, mode); + + if (GET_CODE (op) == REG && REGNO (op) == 32) + return 1; + + return 0; +} + +int +sym_ref_mem_operand (op, mode) + register rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + if (GET_CODE (op) == MEM) + { + rtx t1 = XEXP (op, 0); + if (GET_CODE (t1) == SYMBOL_REF) + return 1; + } + return 0; +} + +/* Return 1 if OP is a valid operand for the source of a move insn. */ + +int +input_operand (rtx op, enum machine_mode mode) +{ + + /* If both modes are non-void they must be the same. */ + if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op)) + return 0; + + /* Accept CONSTANT_P_RTX, since it will be gone by CSE1 and result in 0/1. */ + if (GET_CODE (op) == CONSTANT_P_RTX) + return 1; + + /* Allow any one instruction integer constant, and all CONST_INT + variants when we are working in DImode and !arch64. */ + if (GET_MODE_CLASS (mode) == MODE_INT + && ((GET_CODE (op) == CONST_INT) + && (CONST_OK_FOR_LETTER_P (INTVAL (op), 'K') + || CONST_OK_FOR_LETTER_P (INTVAL (op), 'M') + || CONST_OK_FOR_LETTER_P (INTVAL (op), 'I')))) + return 1; + + if (register_operand (op, mode)) + return 1; + + /* If this is a SUBREG, look inside so that we handle + paradoxical ones. */ + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + + /* Check for valid MEM forms. */ + if (GET_CODE (op) == MEM) + return memory_address_p (mode, XEXP (op, 0)); + + return 0; +} + +/* Test for a valid operand for a call instruction. Don't allow the + arg pointer register or virtual regs since they may decay into + reg + const, which the patterns can't handle. */ + +int +sibcall_insn_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + + + /* Disallow indirect through a virtual register. This leads to + compiler aborts when trying to eliminate them. */ + if (GET_CODE (op) == REG + && (op == arg_pointer_rtx + || op == frame_pointer_rtx + || (REGNO (op) >= FIRST_PSEUDO_REGISTER + && REGNO (op) <= LAST_VIRTUAL_REGISTER))) + { + + fprintf (stderr, "0\n"); + return 0; + } + + /* Explicitly allow SYMBOL_REF even if pic. */ + if (GET_CODE (op) == SYMBOL_REF) + return 1; + + /* Otherwise we can only allow register operands. */ + return register_operand (op, Pmode); +} + + +/* Add a REG_MAYBE_DEAD note to the insn. */ +static void +or32_maybe_dead (rtx insn) +{ + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, + const0_rtx, REG_NOTES (insn)); +} + +int +print_operand_punct_valid_p (code) + int code; +{ + switch (code) + { + case '(': /* idea taken from sparc; output nop for %( if + not optimizing or the slot is not filled. */ + case '%': + return 1; + } + return 0; +} + +void +print_operand_address (file, addr) + FILE *file; + register rtx addr; +{ + register rtx reg1, reg2, breg, ireg; + rtx offset; + + switch (GET_CODE (addr)) + { + case MEM: + if (GET_CODE (XEXP (addr, 0)) == REG) + fprintf (file, "%s", reg_names[REGNO (addr)]); + else + abort (); + break; + + case REG: + fprintf (file, "0(%s)", reg_names[REGNO (addr)]); + break; + + case PLUS: + reg1 = 0; + reg2 = 0; + ireg = 0; + breg = 0; + offset = 0; + if (GET_CODE (XEXP (addr, 0)) == REG) + { + offset = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + else if (GET_CODE (XEXP (addr, 1)) == REG) + { + offset = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + output_address (offset); + fprintf (file, "(%s)", reg_names[REGNO (addr)]); + break; + + default: + /* fprintf(file, "{%d}", GET_CODE (addr)); */ + output_addr_const (file, addr); + } +} + +/* Calulcate and return stack size for current function. */ +static int +calculate_stack_size (int vars, int *lr_save_area, + int *fp_save_area, int *gpr_save_area, int *save_area) +{ + int regno; + + *gpr_save_area = 0; + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + { + if (regs_ever_live[regno] && !call_used_regs[regno]) + *gpr_save_area += 4; + } + + *lr_save_area = (!current_function_is_leaf + || regs_ever_live[LINK_REGNUM]) ? 4 : 0; + *fp_save_area = frame_pointer_needed ? 4 : 0; + + *save_area = (OR32_ALIGN (current_function_outgoing_args_size, 4) + + *lr_save_area + *fp_save_area); + + return + (OR32_ALIGN (current_function_outgoing_args_size, 4) + + *lr_save_area + *fp_save_area + *gpr_save_area + OR32_ALIGN (vars, 4)); +} + +/* Set up the stack and frame pointer (if desired) for the + function. */ +static void +or32_output_function_prologue (FILE * file, HOST_WIDE_INT vars) +{ + int save_area; + int gpr_save_area; + int lr_save_area; + int fp_save_area; + int stack_size; + int regno; + + if (TARGET_SCHED_LOGUE) + return; + +#if 0 + save_area = 0; + + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + { + if (regs_ever_live[regno] && !call_used_regs[regno]) + { + save_area += 1; + } + } + + if (save_area != 0) + fprintf (file, "\tl.nop \t0x%x\n", 0x100 + save_area); + + return; +#endif + + if (vars < 0) + abort (); + + stack_size = calculate_stack_size + (vars, &lr_save_area, &fp_save_area, &gpr_save_area, &save_area); + + fprintf (file, + "\n\t# gpr_save_area %d vars %ld current_function_outgoing_args_size %d\n", + gpr_save_area, vars, current_function_outgoing_args_size); + + if (stack_size >= 0x8000) + { + fprintf (file, "\tl.movhi \tr%d,hi(%d)\n", GP_ARG_RETURN, stack_size); + fprintf (file, "\tl.ori \tr%d,r%d,lo(%d)\n", GP_ARG_RETURN, + GP_ARG_RETURN, stack_size); + fprintf (file, "\tl.sub \tr%d,r%d,r%d\n", STACK_POINTER_REGNUM, + STACK_POINTER_REGNUM, GP_ARG_RETURN); + } + else if (stack_size > 0) + { + fprintf (file, "\tl.addi \tr%d,r%d,%d\n", STACK_POINTER_REGNUM, + STACK_POINTER_REGNUM, -stack_size); + } + + if (fp_save_area) + { + fprintf (file, "\tl.sw \t%d(r%d),r%d\n", + OR32_ALIGN (current_function_outgoing_args_size, 4) + + lr_save_area, STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM); + if (stack_size >= 0x8000) + fprintf (file, "\tl.add \tr%d,r%d,r%d\n", FRAME_POINTER_REGNUM, + STACK_POINTER_REGNUM, GP_ARG_RETURN); + else + fprintf (file, "\tl.addi \tr%d,r%d,%d\n", FRAME_POINTER_REGNUM, + STACK_POINTER_REGNUM, stack_size); + } + + if (lr_save_area) + { + fprintf (file, "\tl.sw \t%d(r%d),r%d\n", + OR32_ALIGN (current_function_outgoing_args_size, 4), + STACK_POINTER_REGNUM, LINK_REGNUM); + } + + save_area = (OR32_ALIGN (current_function_outgoing_args_size, 4) + + lr_save_area + fp_save_area); + + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + { + if (regs_ever_live[regno] && !call_used_regs[regno]) + { + fprintf (file, "\tl.sw \t%d(r%d),r%d\n", save_area, + STACK_POINTER_REGNUM, regno); + save_area += 4; + } + } +} + +/* Do any necessary cleanup after a function to restore stack, frame, + and regs. */ +static void +or32_output_function_epilogue (FILE * file, HOST_WIDE_INT vars) +{ + int save_area; + int gpr_save_area; + int lr_save_area; + int fp_save_area; + int stack_size; + int regno; + + if (TARGET_SCHED_LOGUE) + return; + +#if 0 + save_area = 0; + + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + { + if (regs_ever_live[regno] && !call_used_regs[regno]) + { + save_area += 1; + } + } + + fprintf (file, "\tl.nop \t0x%x\n", 0x200 + save_area); + return; +#endif + + stack_size = calculate_stack_size + (vars, &lr_save_area, &fp_save_area, &gpr_save_area, &save_area); + + if (lr_save_area) + { + fprintf (file, "\tl.lwz \tr%d,%d(r%d)\n", LINK_REGNUM, + OR32_ALIGN (current_function_outgoing_args_size, 4), + STACK_POINTER_REGNUM); + } + if (fp_save_area) + { + fprintf (file, "\tl.lwz \tr%d,%d(r%d)\n", FRAME_POINTER_REGNUM, + OR32_ALIGN (current_function_outgoing_args_size, 4) + + lr_save_area, STACK_POINTER_REGNUM); + } + save_area = (OR32_ALIGN (current_function_outgoing_args_size, 4) + + lr_save_area + fp_save_area); + + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + { + if (regs_ever_live[regno] && !call_used_regs[regno]) + { + fprintf (file, "\tl.lwz \tr%d,%d(r%d)\n", regno, save_area, + STACK_POINTER_REGNUM); + save_area += 4; + } + } + + if (stack_size >= 0x8000) + { + fprintf (file, "\tl.movhi \tr3,hi(%d)\n", stack_size); + fprintf (file, "\tl.ori \tr3,r3,lo(%d)\n", stack_size); + + if (!TARGET_ALIGNED_JUMPS) + fprintf (file, "\tl.jr \tr%d\n", LINK_REGNUM); + else + fprintf (file, "\t.balignl 0x8,0x15000015,0x4;l.jr \tr%d\n", + LINK_REGNUM); + + fprintf (file, "\tl.add \tr%d,r%d,r3\n", STACK_POINTER_REGNUM, + STACK_POINTER_REGNUM); + } + else if (stack_size > 0) + { + if (!TARGET_ALIGNED_JUMPS) + fprintf (file, "\tl.jr \tr%d\n", LINK_REGNUM); + else + fprintf (file, "\t.balignl 0x8,0x15000015,0x4;l.jr \tr%d\n", + LINK_REGNUM); + + fprintf (file, "\tl.addi \tr%d,r%d,%d\n", STACK_POINTER_REGNUM, + STACK_POINTER_REGNUM, stack_size); + } + else + { + if (!TARGET_ALIGNED_JUMPS) + fprintf (file, "\tl.jr \tr%d\n", LINK_REGNUM); + else + fprintf (file, "\t.balignl 0x8,0x15000015,0x4;l.jr \tr%d\n", + LINK_REGNUM); + + fprintf (file, "\tl.nop\n"); + } + +#if 0 + fprintf (file, ".endproc _%s\n", get_function_name ()); +#endif +} + +/* Compuate full frame size and layout. SIZE is the size of the + functions local variables. Store information in FRAME_INFO and + return total size of stack frame. */ + +HOST_WIDE_INT +or32_compute_frame_size (HOST_WIDE_INT size) +{ + HOST_WIDE_INT args_size; + HOST_WIDE_INT vars_size; + HOST_WIDE_INT stack_offset; + int regno; + + args_size = current_function_outgoing_args_size; + vars_size = OR32_ALIGN (size, 4); + + frame_info.args_size = args_size; + frame_info.vars_size = vars_size; + + /* If the function has local variables, we're committed to + allocating it anyway. Otherwise reclaim it here. */ + /* FIXME: Verify this. Got if from the MIPS port. */ + if (vars_size == 0 && current_function_is_leaf) + args_size = 0; + + stack_offset = args_size; + + /* Save link register right after possible outgoing arguments. */ + if (or32_save_reg_p (LINK_REGNUM)) + { + frame_info.lr_save_offset = stack_offset; + frame_info.save_lr_p = true; + stack_offset = stack_offset + UNITS_PER_WORD; + } + else + frame_info.save_lr_p = false; + + /* Save frame pointer right after possible link register. */ + if (or32_save_reg_p (FRAME_POINTER_REGNUM)) + { + frame_info.fp_save_offset = stack_offset; + frame_info.save_fp_p = true; + stack_offset = stack_offset + UNITS_PER_WORD; + } + else + frame_info.save_fp_p = false; + + frame_info.gpr_size = 0; + frame_info.mask = 0; + frame_info.gpr_offset = stack_offset; + + for (regno = 0; regno <= LAST_INT_REG; regno++) + { + if (regno == LINK_REGNUM || regno == FRAME_POINTER_REGNUM) + /* These has already been saved if so needed. */ + continue; + + if (or32_save_reg_p (regno)) + { + frame_info.gpr_size += UNITS_PER_WORD; + frame_info.mask |= (1 << regno); + } + } + + frame_info.total_size = ((frame_info.save_fp_p ? UNITS_PER_WORD : 0) + + (frame_info.save_lr_p ? UNITS_PER_WORD : 0) + + args_size + frame_info.gpr_size + vars_size); + + return frame_info.total_size; +} + + +/* Return true if current function must save REGNO. */ +static bool +or32_save_reg_p (int regno) +{ + /* No need to save the faked cc0 register. */ + if (regno == FLAGS_REG) + return false; + + /* Check call-saved registers. */ + if (regs_ever_live[regno] && !call_used_regs[regno]) + return true; + + /* We need to save the old frame pointer before setting up a new + one. */ + if (regno == FRAME_POINTER_REGNUM && frame_pointer_needed) + return true; + + /* We need to save the incoming return address if it is ever clobbered + within the function. */ + if (regno == LINK_REGNUM && regs_ever_live[regno]) + return true; + + return false; +} + +/* Emit a frame related insn. Same as emit_insn, but sets + RTX_FRAME_RELATED_P to one. */ + +static rtx +emit_frame_insn (rtx insn) +{ + insn = emit_insn (insn); + RTX_FRAME_RELATED_P (insn) = 1; + return (insn); +} + +static rtx +indexed_memory (rtx base, HOST_WIDE_INT disp) +{ + return gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, base, GEN_INT (disp))); +} + +/* Called after register allocation to add any instructions needed for + the prologue. Using a prologue insn is favored compared to putting + all of the instructions in output_function_prologue(), since it + allows the scheduler to intermix instructions with the saves of the + caller saved registers. In some cases, it might be necessary to + emit a barrier instruction as the last insn to prevent such + scheduling. */ + +void +or32_expand_prologue () +{ + int total_size = or32_compute_frame_size (get_frame_size ()); + rtx sp_rtx; + rtx value_rtx; + + if (!total_size) + /* No frame needed. */ + return; + + sp_rtx = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM); + + if (total_size > 32767) + { + value_rtx = gen_rtx_REG (Pmode, GP_ARG_RETURN); + emit_frame_insn (gen_rtx_SET (Pmode, value_rtx, GEN_INT (total_size))); + } + else + value_rtx = GEN_INT (total_size); + + /* Update the stack pointer to reflect frame size. */ + emit_frame_insn + (gen_rtx_SET (Pmode, stack_pointer_rtx, + gen_rtx_MINUS (Pmode, stack_pointer_rtx, value_rtx))); + + if (frame_info.save_fp_p) + { + emit_frame_insn + (gen_rtx_SET (Pmode, + indexed_memory (stack_pointer_rtx, + frame_info.fp_save_offset), + frame_pointer_rtx)); + + emit_frame_insn + (gen_rtx_SET (Pmode, frame_pointer_rtx, + gen_rtx_PLUS (Pmode, frame_pointer_rtx, value_rtx))); + } + if (frame_info.save_lr_p) + { + + emit_frame_insn + (gen_rtx_SET (Pmode, + indexed_memory (stack_pointer_rtx, + frame_info.lr_save_offset), + gen_rtx_REG (Pmode, LINK_REGNUM))); + } + if (frame_info.gpr_size) + { + int offset = 0; + int regno; + + for (regno = 0; regno <= LAST_INT_REG; regno++) + { + HOST_WIDE_INT disp = frame_info.gpr_offset + offset; + + if (!(frame_info.mask & (1 << regno))) + continue; + + emit_frame_insn + (gen_rtx_SET (Pmode, + indexed_memory (stack_pointer_rtx, disp), + gen_rtx_REG (Pmode, regno))); + offset = offset + UNITS_PER_WORD; + } + } +} + +/* Called after register allocation to add any instructions needed for + the epilogue. Using an epilogue insn is favored compared to + putting all of the instructions in output_function_epilogue(), + since it allows the scheduler to intermix instructions with the + restores of the caller saved registers. In some cases, it might be + necessary to emit a barrier instruction as the first insn to + prevent such scheduling. */ + +void +or32_expand_epilogue (int sibcall) +{ + int total_size = or32_compute_frame_size (get_frame_size ()); + rtx value_rtx; + + if (total_size > 32767) + { + value_rtx = gen_rtx_REG (Pmode, 3); + + emit_insn (gen_rtx_SET (Pmode, value_rtx, GEN_INT (total_size))); + } + else + value_rtx = GEN_INT (total_size); + + if (frame_info.save_lr_p) + { + or32_maybe_dead + (emit_insn + (gen_rtx_SET (Pmode, gen_rtx_REG (Pmode, LINK_REGNUM), + indexed_memory (stack_pointer_rtx, + frame_info.lr_save_offset)))); + } + if (frame_info.save_fp_p) + { + emit_insn + (gen_rtx_SET (Pmode, gen_rtx_REG (Pmode, FRAME_POINTER_REGNUM), + indexed_memory (stack_pointer_rtx, + frame_info.fp_save_offset))); + } + + if (frame_info.gpr_size) + { + int offset = 0; + int regno; + + for (regno = 0; regno <= LAST_INT_REG; regno++) + { + HOST_WIDE_INT disp = frame_info.gpr_offset + offset; + + if (!(frame_info.mask & (1 << regno))) + continue; + + emit_insn + (gen_rtx_SET (Pmode, gen_rtx_REG (Pmode, regno), + indexed_memory (stack_pointer_rtx, disp))); + offset = offset + UNITS_PER_WORD; + } + } + + if (total_size) + { + emit_insn (gen_rtx_SET (Pmode, stack_pointer_rtx, + gen_rtx_PLUS (Pmode, + stack_pointer_rtx, value_rtx))); + } + + if (!sibcall) + emit_jump_insn (gen_return_internal (gen_rtx (REG, Pmode, 9))); +} + + +void +print_operand (FILE * file, rtx x, int code) +{ + if (code == 'r' && GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == REG) + fprintf (file, "%s", reg_names[REGNO (XEXP (x, 0))]); + else if (code == '(') + { + if (dbr_sequence_length ()) + fprintf (file, "\t# delay slot filled"); + else + fprintf (file, "\n\tl.nop\t\t\t# nop delay slot"); + } + else if (code == 'C') + { + switch (GET_CODE (x)) + { + case EQ: + fputs ("eq", file); + break; + case NE: + fputs ("ne", file); + break; + case GT: + fputs ("gts", file); + break; + case GE: + fputs ("ges", file); + break; + case LT: + fputs ("lts", file); + break; + case LE: + fputs ("les", file); + break; + case GTU: + fputs ("gtu", file); + break; + case GEU: + fputs ("geu", file); + break; + case LTU: + fputs ("ltu", file); + break; + case LEU: + fputs ("leu", file); + break; + default: + abort (); + } + } + else if (code == 'H') + { + if (GET_CODE (x) == REG) + fprintf (file, "%s", reg_names[REGNO (x) + 1]); + else + abort (); + } + else if (GET_CODE (x) == REG) + fprintf (file, "%s", reg_names[REGNO (x)]); + else if (GET_CODE (x) == MEM) + output_address (XEXP (x, 0)); + else + output_addr_const (file, x); +} + +/* Generate assembler code for a movdi/movdf */ + +const char * +or32_output_move_double (rtx * operands) +{ + rtx xoperands[3]; + + switch (GET_CODE (operands[0])) + { + case REG: + if (GET_CODE (operands[1]) == REG) + { + if (REGNO (operands[0]) == REGNO (operands[1]) + 1) + { + output_asm_insn ("\tl.or \t%H0, %H1, r0", operands); + output_asm_insn ("\tl.or \t%0, %1, r0", operands); + return ""; + } + else + { + output_asm_insn ("\tl.or \t%0, %1, r0", operands); + output_asm_insn ("\tl.or \t%H0, %H1, r0", operands); + return ""; + } + } + else if (GET_CODE (operands[1]) == MEM) + { + xoperands[1] = XEXP (operands[1], 0); + if (GET_CODE (xoperands[1]) == REG) + { + xoperands[0] = operands[0]; + if (REGNO (xoperands[0]) == REGNO (xoperands[1])) + { + output_asm_insn ("\tl.lwz \t%H0, 4(%1)", xoperands); + output_asm_insn ("\tl.lwz \t%0, 0(%1)", xoperands); + return ""; + } + else + { + output_asm_insn ("\tl.lwz \t%0, 0(%1)", xoperands); + output_asm_insn ("\tl.lwz \t%H0, 4(%1)", xoperands); + return ""; + } + } + else if (GET_CODE (xoperands[1]) == PLUS) + { + if (GET_CODE (xoperands[2] = XEXP (xoperands[1], 1)) == REG) + { + xoperands[0] = operands[0]; + xoperands[1] = XEXP (xoperands[1], 0); + if (REGNO (xoperands[0]) == REGNO (xoperands[2])) + { + output_asm_insn ("\tl.lwz \t%H0, %1+4(%2)", + xoperands); + output_asm_insn ("\tl.lwz \t%0, %1(%2)", xoperands); + return ""; + } + else + { + output_asm_insn ("\tl.lwz \t%0, %1(%2)", xoperands); + output_asm_insn ("\tl.lwz \t%H0, %1+4(%2)", + xoperands); + return ""; + } + } + else if (GET_CODE (xoperands[2] = XEXP (xoperands[1], 0)) == + REG) + { + xoperands[0] = operands[0]; + xoperands[1] = XEXP (xoperands[1], 1); + if (REGNO (xoperands[0]) == REGNO (xoperands[2])) + { + output_asm_insn ("\tl.lwz \t%H0, %1+4(%2)", + xoperands); + output_asm_insn ("\tl.lwz \t%0, %1(%2)", xoperands); + return ""; + } + else + { + output_asm_insn ("\tl.lwz \t%0, %1(%2)", xoperands); + output_asm_insn ("\tl.lwz \t%H0, %1+4(%2)", + xoperands); + return ""; + } + } + else + abort (); + } + else + abort (); + } + else if (GET_CODE (operands[1]) == CONST_INT) + { + if (INTVAL (operands[1]) < 0) + output_asm_insn ("\tl.addi \t%0, r0, -1", operands); + else + output_asm_insn ("\tl.or \t%0, r0, r0", operands); + output_asm_insn ("\tl.movhi \t%H0, hi(%1)", operands); + output_asm_insn ("\tl.ori \t%H0, %H0, lo(%1)", operands); + return ""; + } + else + abort (); + case MEM: + xoperands[0] = XEXP (operands[0], 0); + if (GET_CODE (xoperands[0]) == REG) + { + xoperands[1] = operands[1]; + output_asm_insn ("\tl.sw \t0(%0), %1", xoperands); + output_asm_insn ("\tl.sw \t4(%0), %H1", xoperands); + return ""; + } + else if (GET_CODE (xoperands[0]) == PLUS) + { + if (GET_CODE (xoperands[1] = XEXP (xoperands[0], 1)) == REG) + { + xoperands[0] = XEXP (xoperands[0], 0); + xoperands[2] = operands[1]; + output_asm_insn ("\tl.sw \t%0(%1), %2", xoperands); + output_asm_insn ("\tl.sw \t%0+4(%1), %H2", xoperands); + return ""; + } + else if (GET_CODE (xoperands[1] = XEXP (xoperands[0], 0)) == REG) + { + xoperands[0] = XEXP (xoperands[0], 1); + xoperands[2] = operands[1]; + output_asm_insn ("\tl.sw \t%0(%1), %2", xoperands); + output_asm_insn ("\tl.sw \t%0+4(%1), %H2", xoperands); + return ""; + } + else + abort (); + } + else + abort (); + default: + abort (); + } +} + +enum rtx_code +or32_reverse_condition (enum machine_mode mode ATTRIBUTE_UNUSED, + enum rtx_code code) +{ + return reverse_condition (code); +} + +enum machine_mode +or32_cc_mode (enum rtx_code code, + rtx op0 ATTRIBUTE_UNUSED, rtx op1 ATTRIBUTE_UNUSED) +{ + + switch (code) + { + case EQ: + return CCEQmode; + case NE: + return CCNEmode; + case GEU: + return CCGEUmode; + case GTU: + return CCGTUmode; + case LTU: + return CCLTUmode; + case LEU: + return CCLEUmode; + case GE: + return CCGEmode; + case LT: + return CCLTmode; + case GT: + return CCGTmode; + case LE: + return CCLEmode; + + default: + abort (); + } +} + +/* Generate insn patterns to do an integer compare of OPERANDS. */ + +static rtx +or32_expand_int_compare (enum rtx_code code, rtx op0, rtx op1) +{ + enum machine_mode cmpmode; + rtx tmp, flags; + + cmpmode = SELECT_CC_MODE (code, op0, op1); + flags = gen_rtx_REG (cmpmode, FLAGS_REG); + + /* This is very simple, but making the interface the same as in the + FP case makes the rest of the code easier. */ + tmp = gen_rtx_COMPARE (cmpmode, op0, op1); + emit_insn (gen_rtx_SET (VOIDmode, flags, tmp)); + + /* Return the test that should be put into the flags user, i.e. + the bcc, scc, or cmov instruction. */ + return gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx); +} + +rtx +or32_expand_compare (enum rtx_code code, rtx op0, rtx op1) +{ + return or32_expand_int_compare (code, op0, op1); +} + +void +or32_expand_branch (enum rtx_code code, rtx label) +{ + rtx tmp; + + switch (GET_MODE (or32_compare_op0)) + { + case SImode: + tmp = or32_expand_compare (code, or32_compare_op0, or32_compare_op1); + 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 (); + } + +} + +static int +or32_emit_int_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond) +{ + rtx condition_rtx, cr; + + if ((GET_MODE (or32_compare_op0) != SImode) && + (GET_MODE (or32_compare_op0) != HImode) && + (GET_MODE (or32_compare_op0) != QImode)) + return 0; + + /* We still have to do the compare, because cmov doesn't do a + compare, it just looks at the FLAG bit set by a previous compare + instruction. */ + + condition_rtx = or32_expand_compare (GET_CODE (op), + or32_compare_op0, or32_compare_op1); + + cr = XEXP (condition_rtx, 0); + + emit_insn (gen_cmov (dest, condition_rtx, true_cond, false_cond, cr)); + + return 1; +} + + +/* Emit a conditional move: move TRUE_COND to DEST if OP of the + operands of the last comparison is nonzero/true, FALSE_COND if it + is zero/false. Return 0 if the hardware has no such operation. */ + +int +or32_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond) +{ + enum machine_mode result_mode = GET_MODE (dest); + + if (GET_MODE (true_cond) != result_mode) + return 0; + + if (GET_MODE (false_cond) != result_mode) + return 0; + + /* First, work out if the hardware can do this at all */ + return or32_emit_int_cmove (dest, op, true_cond, false_cond); +} + +const char * +output_bf (rtx * operands) +{ + enum rtx_code code; + enum machine_mode mode_calc, mode_got; + + code = GET_CODE (operands[1]); + mode_calc = SELECT_CC_MODE (code, or32_compare_op0, or32_compare_op1); + mode_got = GET_MODE (operands[2]); + + if (!TARGET_ALIGNED_JUMPS) + { + if (mode_calc != mode_got) + return "l.bnf \t%l0%("; + else + return "l.bf \t%l0%("; + } + else + { + if (mode_calc != mode_got) + return "\t.balignl 0x8,0x15000015,0x4;l.bnf \t%l0%("; + else + return "\t.balignl 0x8,0x15000015,0x4;l.bf \t%l0%("; + } +} + +const char * +output_cmov (rtx * operands) +{ + enum rtx_code code; + enum machine_mode mode_calc, mode_got; + + code = GET_CODE (operands[1]); + mode_calc = SELECT_CC_MODE (code, or32_compare_op0, or32_compare_op1); + mode_got = GET_MODE (operands[4]); + + if (mode_calc != mode_got) + return "l.cmov \t%0,%3,%2"; /* reversed */ + else + return "l.cmov \t%0,%2,%3"; +} + +/* Any function is ok for sibcall optimization if we allow this optimization + */ +static bool +or32_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED, + tree exp ATTRIBUTE_UNUSED) +{ + return TARGET_SIBCALL; +} + +/* For now this is very simple way for sibcall support */ + +void +or32_expand_sibcall (rtx result, rtx addr, rtx args_size) +{ + emit_call_insn (gen_sibcall_internal (addr, args_size)); +} + + +/* We know it can't be done in one insn when we get here, + the movsi expander guarantees this. */ +void +or32_emit_set_const32 (rtx op0, rtx op1) +{ + enum machine_mode mode = GET_MODE (op0); + rtx temp; + + + if (GET_CODE (op1) == CONST_INT) + { + HOST_WIDE_INT value = INTVAL (op1); + + if (CONST_OK_FOR_LETTER_P (value & GET_MODE_MASK (mode), 'K') + || CONST_OK_FOR_LETTER_P (value, 'M') + || CONST_OK_FOR_LETTER_P (value, 'I')) + abort (); + } + + + /* Full 2-insn decomposition is needed. */ + if (reload_in_progress || reload_completed) + { + temp = op0; + } + else + temp = gen_reg_rtx (mode); + + if (GET_CODE (op1) == CONST_INT) + { + /* Emit them as real moves instead of a HIGH/LO_SUM, + this way CSE can see everything and reuse intermediate + values if it wants. */ + emit_insn (gen_rtx_SET (VOIDmode, temp, + GEN_INT (INTVAL (op1) + & ~(HOST_WIDE_INT) 0xffff))); + + emit_insn (gen_rtx_SET (VOIDmode, + op0, + gen_rtx_IOR (mode, temp, + GEN_INT (INTVAL (op1) & 0xffff)))); + } + else + { + +#if 0 + /* A symbol, emit in the traditional way. */ + + emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_HIGH (mode, op1))); + emit_insn (gen_rtx_SET (VOIDmode, + op0, gen_rtx_LO_SUM (mode, temp, op1))); +#else + /* since or32 bfd can not deal with relocs that are not of type + OR32_CONSTH_RELOC + OR32_CONST_RELOC (ie move high must be + followed by exactly one lo_sum) + */ + emit_insn (gen_movsi_insn_big (op0, op1)); +#endif + } +} + + +/* Functions returning costs and making code size/performance tradeoffs */ + +int +or32_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, + enum reg_class from ATTRIBUTE_UNUSED, + enum reg_class to ATTRIBUTE_UNUSED) +{ + return 2; +} + +/* A C expressions returning the cost of moving data of MODE from a register to + or from memory. */ + +int +or32_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, + enum reg_class class ATTRIBUTE_UNUSED, + int in ATTRIBUTE_UNUSED) +{ + return 2; +} + +/* Specify the cost of a branch insn; roughly the number of extra insns that + should be added to avoid a branch. + + Set this to 3 on the or32 since that is roughly the average cost of an + unscheduled conditional branch. + + Cost of 2 and 3 give equal and ~0.7% bigger binaries + +*/ +int +or32_branch_cost () +{ + return 1; +} diff -Nru gcc-3.4.4.orig/gcc/config/or32/or32.h gcc-3.4.4-DONE/gcc/config/or32/or32.h --- gcc-3.4.4.orig/gcc/config/or32/or32.h 1970-01-01 02:00:00.000000000 +0200 +++ gcc-3.4.4-DONE/gcc/config/or32/or32.h 2005-11-29 17:01:54.000000000 +0200 @@ -0,0 +1,1361 @@ +/* Definitions of target machine for GNU compiler. OpenRISC 1000 version. + Copyright (C) 1987, 1988, 1992, 1995, 1996, 1999, 2000, 2001, 2002, + 2003, 2004, 2005 Free Software Foundation, Inc. + Contributed by Damjan Lampret <damjanl@bsemi.com> in 1999. + Major optimizations by Matjaz Breskvar <matjazb@bsemi.com> in 2005. + +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 1, 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. */ + +#ifndef _OR32_H_ +#define _OR32_H_ + +/* Target CPU builtins */ +#define TARGET_CPU_CPP_BUILTINS() \ + do \ + { \ + builtin_define_std ("OR1K"); \ + builtin_define_std ("or1k"); \ + builtin_assert ("cpu=or1k"); \ + builtin_assert ("machine=or1k"); \ + } \ + while (0) + +#if 0 + +/* Which library to get. The only difference from the default is to get + libsc.a if -sim is given to the driver. Repeat -lc -lsysX + {X=sim,linux}, because libsysX needs (at least) errno from libc, and + then we want to resolve new unknowns in libc against libsysX, not + libnosys. */ +/* Override previous definitions (linux.h). */ +#undef LIB_SPEC +#define LIB_SPEC \ + "%{sim*:-lc -lsyssim -lc -lsyssim}\ + %{!sim*:%{g*:-lg}\ + %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} -lbsp}\ + -lnosys" +#endif + +#define TARGET_VERSION fprintf (stderr, " (OpenRISC 1000)"); + +/* Run-time compilation parameters selecting different hardware subsets. */ + +extern int target_flags; + +/* Enable hardware fp support. */ +#define MASK_HARD_FLOAT 0x00000001 + +/* Enable hardware div instruction. */ +#define MASK_HARD_DIV 0x00000002 + +/* Enable hardware mul instruction. */ +#define MASK_HARD_MUL 0x00000004 + +/* Use aligned jumps. */ +#define MASK_ALIGNED_JUMPS 0x00000008 + +/* Use l.extbs and l.exths instructions. */ +#define MASK_SEXT 0x00000010 + +/* Use l.cmov instruction. */ +#define MASK_CMOV 0x00000020 + +/* Emit prologue and epilogue. */ +#define MASK_SCHED_LOGUE 0x00000040 + +/* Emit prologue and epilogue. */ +#define MASK_ROR 0x00000080 + +/* Emit prologue and epilogue. */ +#define MASK_SIBCALL 0x00000100 + + +/* Macros used in the machine description to test the flags. */ + +#define TARGET_HARD_FLOAT (target_flags & MASK_HARD_FLOAT) +#define TARGET_HARD_DIV (target_flags & MASK_HARD_DIV) +#define TARGET_HARD_MUL (target_flags & MASK_HARD_MUL) +#define TARGET_ALIGNED_JUMPS (target_flags & MASK_ALIGNED_JUMPS) +#define TARGET_SEXT (target_flags & MASK_SEXT) +#define TARGET_CMOV (target_flags & MASK_CMOV) +#define TARGET_SCHED_LOGUE (target_flags & MASK_SCHED_LOGUE) +#define TARGET_ROR (target_flags & MASK_ROR) +#define TARGET_SIBCALL (target_flags & MASK_SIBCALL) + +/* Macro to define tables used to set the flags. + This is a list in braces of pairs in braces, + each pair being { "NAME", VALUE } + where VALUE is the bits to set or minus the bits to clear. + An empty string NAME is used to identify the default VALUE. */ + +#define TARGET_SWITCHES \ + { {"hard-float", MASK_HARD_FLOAT, N_("Use hardware floating point.")}, \ + {"soft-float", - MASK_HARD_FLOAT, N_("Use software floating point.")}, \ + {"hard-div", MASK_HARD_DIV, N_("Use hardware divison.")}, \ + {"soft-div", - MASK_HARD_DIV, N_("Use software divison.")}, \ + {"hard-mul", MASK_HARD_MUL, N_("Use hardware multiplication.")}, \ + {"soft-mul", - MASK_HARD_MUL, N_("Use software multiplication.")}, \ + {"aj", MASK_ALIGNED_JUMPS, N_("Use aligned jumps.")}, \ + {"no-aj", - MASK_ALIGNED_JUMPS, N_("Do not use aligned jumps.")}, \ + {"sext", MASK_SEXT, N_("Use sign extending instructions.")}, \ + {"no-sext", - MASK_SEXT, N_("Do not use sign extending insn.")}, \ + {"cmov", MASK_CMOV, N_("Use conditional move insn.")}, \ + {"no-cmov", - MASK_CMOV, N_("Do not use conditional move insn.")},\ + {"logue", MASK_SCHED_LOGUE, N_("Schedule pro/epi-logue.")}, \ + {"no-logue", - MASK_SCHED_LOGUE, N_("Do not schedule pro/epi-logue.")}, \ + {"ror", MASK_ROR, N_("Emit ror insns.")}, \ + {"no-ror", - MASK_ROR, N_("Do not emit ror insns.")}, \ + {"sibcall", MASK_SIBCALL, N_("Enable sibcall optimization.")}, \ + {"no-sibcall", - MASK_SIBCALL, N_("Disable sibcall optimization.")}, \ + { "", TARGET_DEFAULT, 0}} + +/* Default target_flags if no switches specified. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_HARD_MUL) +#endif + +#undef TARGET_ASM_NAMED_SECTION +#define TARGET_ASM_NAMED_SECTION default_elf_asm_named_section + +/* Target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. + This is not true on the or1k. */ +#define BITS_BIG_ENDIAN 0 + +/* Define this if most significant byte of a word is the lowest numbered. */ +#define BYTES_BIG_ENDIAN 1 + +/* Define this if most significant word of a multiword number is numbered. */ +#define WORDS_BIG_ENDIAN 1 + +/* Number of bits in an addressable storage unit */ +#define BITS_PER_UNIT 8 + +#define BITS_PER_WORD 32 +#define SHORT_TYPE_SIZE 16 +#define INT_TYPE_SIZE 32 +#define LONG_TYPE_SIZE 32 +#define LONG_LONG_TYPE_SIZE 64 +#define FLOAT_TYPE_SIZE 32 +#define DOUBLE_TYPE_SIZE 64 +#define LONG_DOUBLE_TYPE_SIZE 64 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 32 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 8 + +/* Every structure's size must be a multiple of this. */ +#define STRUCTURE_SIZE_BOUNDARY 32 + +/* A bitfield declared as `int' forces `int' alignment for the struct. */ +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* No data type wants to be aligned rounder than this. */ +#define BIGGEST_ALIGNMENT 32 + +/* The best alignment to use in cases where we have a choice. */ +#define FASTEST_ALIGNMENT 32 + +/* Make strings word-aligned so strcpy from constants will be faster. */ +/* +#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ + ((TREE_CODE (EXP) == STRING_CST || TREE_CODE (EXP) == CONSTRUCTOR) \ + && (ALIGN) < FASTEST_ALIGNMENT \ + ? FASTEST_ALIGNMENT : (ALIGN)) +*/ + +/* One use of this macro is to increase alignment of medium-size + data to make it all fit in fewer cache lines. Another is to + cause character arrays to be word-aligned so that `strcpy' calls + that copy constants to character arrays can be done inline. */ +/* +#define DATA_ALIGNMENT(TYPE, ALIGN) \ + ((((ALIGN) < FASTEST_ALIGNMENT) \ + && (TREE_CODE (TYPE) == ARRAY_TYPE \ + || TREE_CODE (TYPE) == UNION_TYPE \ + || TREE_CODE (TYPE) == RECORD_TYPE)) ? FASTEST_ALIGNMENT : (ALIGN)) +*/ /* CHECK - btw code gets bigger with this one */ + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT 1 /* CHECK */ + +/* Align an address */ +#define OR32_ALIGN(n,a) (((n) + (a) - 1) & ~((a) - 1)) + +/* Define this macro if an argument declared as `char' or `short' in a + prototype should actually be passed as an `int'. In addition to + avoiding errors in certain cases of mismatch, it also makes for + better code on certain machines. */ +#define PROMOTE_PROTOTYPES 1 + +/* Define if operations between registers always perform the operation + on the full register even if a narrower mode is specified. */ +#define WORD_REGISTER_OPERATIONS /* CHECK */ + + +/* Define if loading in MODE, an integral mode narrower than BITS_PER_WORD + will either zero-extend or sign-extend. The value of this macro should + be the code that says which one of the two operations is implicitly + done, NIL if none. */ +#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND + +/* Define this macro if it is advisable to hold scalars in registers + in a wider mode than that declared by the program. In such cases, + the value is constrained to be within the bounds of the declared + type, but kept valid in the wider mode. The signedness of the + extension may differ from that of the type. */ + +#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \ + if (GET_MODE_CLASS (MODE) == MODE_INT \ + && GET_MODE_SIZE (MODE) < UNITS_PER_WORD) \ + (MODE) = SImode; + /* CHECK */ + +/* Define this if function arguments should also be promoted using the above + procedure. */ + +#define PROMOTE_FUNCTION_ARGS + +/* Likewise, if the function return value is promoted. */ + +#define PROMOTE_FUNCTION_RETURN + +/* + * brings 0.4% improvment in static size for linux + * +#define PROMOTE_FOR_CALL_ONLY +*/ + +/* Define this macro if it is as good or better to call a constant + function address than to call an address kept in a register. */ +#define NO_FUNCTION_CSE 1 /* check */ + +/* Define this macro if it is as good or better for a function to + call itself with an explicit address than to call an address + kept in a register. */ +#define NO_RECURSIVE_FUNCTION_CSE 1 /*check*/ + +/* Standard register usage. */ + +/* Number of actual hardware registers. + The hardware registers are assigned numbers for the compiler + from 0 to just below FIRST_PSEUDO_REGISTER. + All registers that the compiler knows about must be given numbers, + even those that are not normally considered general registers. */ +#define FIRST_PSEUDO_REGISTER 33 +#define LAST_INT_REG (FIRST_PSEUDO_REGISTER - 1) + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + On the or1k, these are r1 as stack pointer and + r2 as frame/arg pointer. */ +#define FIXED_REGISTERS {1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. */ +#define CALL_USED_REGISTERS {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, \ + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1} + +/* stack pointer: must be FIXED and CALL_USED */ +/* frame pointer: must be FIXED and CALL_USED */ + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. + On the or1k, all registers are one word long. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) 1 + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, + for any hard reg, then this must be 0 for correct output. */ +#define MODES_TIEABLE_P(MODE1, MODE2) 1 + +/* A C expression returning the cost of moving data from a register of class + CLASS1 to one of CLASS2. */ +#define REGISTER_MOVE_COST or32_register_move_cost + +/* A C expressions returning the cost of moving data of MODE from a register to + or from memory. */ +#define MEMORY_MOVE_COST or32_memory_move_cost + +/* Specify the cost of a branch insn; roughly the number of extra insns that + should be added to avoid a branch. */ +#define BRANCH_COST or32_branch_cost() + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 1 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 2 + +/* Link register. */ +#define LINK_REGNUM 9 + +/* Value should be nonzero if functions must have frame pointers. + Zero means the frame pointer need not be set up (and parms + may be accessed via the stack pointer) in functions that seem suitable. + This is computed in `reload', in reload1.c. */ +#define FRAME_POINTER_REQUIRED 0 + +/* De ne this macro if debugging can be performed even without a frame pointer. + If this macro is de ned, GCC will turn on the `-fomit-frame-pointer' option + whenever `-O' is specifed. + */ +/* +#define CAN_DEBUG_WITHOUT_FP + */ + +#define INITIAL_FRAME_POINTER_OFFSET(DEPTH) \ +{ int regno; \ + int offset = 0; \ + for( regno=0; regno < FIRST_PSEUDO_REGISTER; regno++ ) \ + if( regs_ever_live[regno] && !call_used_regs[regno] ) \ + offset += 4; \ + (DEPTH) = (!current_function_is_leaf || regs_ever_live[LINK_REGNUM] ? 4 : 0) + \ + (frame_pointer_needed ? 4 : 0) + \ + offset + \ + OR32_ALIGN(current_function_outgoing_args_size,4) + \ + OR32_ALIGN(get_frame_size(),4); \ +} + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM FRAME_POINTER_REGNUM + +/* Register in which static-chain is passed to a function. */ +#define STATIC_CHAIN_REGNUM 0 + +/* Register in which address to store a structure value + is passed to a function. */ +/*#define STRUCT_VALUE_REGNUM 0*/ + +/* Pass address of result struct to callee as "invisible" first argument */ +#define STRUCT_VALUE 0 + +/* -----------------------[ PHX start ]-------------------------------- */ + +/* Define the classes of registers for register constraints in the + machine description. Also define ranges of constants. + + One of the classes must always be named ALL_REGS and include all hard regs. + If there is more than one class, another class must be named NO_REGS + and contain no registers. + + The name GENERAL_REGS must be the name of a class (or an alias for + another name such as ALL_REGS). This is the class of registers + that is allowed by "g" or "r" in a register constraint. + Also, registers outside this class are allocated only when + instructions express preferences for them. + + GENERAL_REGS and BASE_REGS classess are the same on or32. + + The classes must be numbered in nondecreasing order; that is, + a larger-numbered class must never be contained completely + in a smaller-numbered class. + + For any two classes, it is very desirable that there be another + class that represents their union. */ + +/* The or1k has only one kind of registers, so NO_REGS, GENERAL_REGS + and ALL_REGS are the only classes. */ + +enum reg_class +{ + NO_REGS, + GENERAL_REGS, + CR_REGS, + ALL_REGS, + LIM_REG_CLASSES +}; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ +{ \ + "NO_REGS", \ + "GENERAL_REGS", \ + "ALL_REGS" \ +} + + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ + +/* An initializer containing the contents of the register classes, + as integers which are bit masks. The Nth integer specifies the + contents of class N. The way the integer MASK is interpreted is + that register R is in the class if `MASK & (1 << R)' is 1. + + When the machine has more than 32 registers, an integer does not + suffice. Then the integers are replaced by sub-initializers, + braced groupings containing several integers. Each + sub-initializer must be suitable as an initializer for the type + `HARD_REG_SET' which is defined in `hard-reg-set.h'. */ + +#define REG_CLASS_CONTENTS \ +{ \ + { 0x00000000, 0x00000000 }, /* NO_REGS */ \ + { 0xffffffff, 0x00000001 }, /* GENERAL_REGS */ \ + { 0xffffffff, 0x00000000 } /* ALL_REGS */ \ +} + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ + +#define REGNO_REG_CLASS(REGNO) \ + ((REGNO) < 32 ? GENERAL_REGS \ + : NO_REGS) + +/* The class value for index registers, and the one for base regs. */ +#define INDEX_REG_CLASS GENERAL_REGS +#define BASE_REG_CLASS GENERAL_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) NO_REGS + +#if 1 +/* The letters I, J, K, L and M in a register constraint string + can be used to stand for particular ranges of immediate operands. + This macro defines what the ranges are. + C is the letter, and VALUE is a constant value. + Return 1 if VALUE is in the range specified by C. */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ( (C) == 'I' ? ((VALUE) >=-32768 && (VALUE) <=32767) \ + : (C) == 'J' ? ((VALUE) >=0 && (VALUE) <=0) \ + : (C) == 'K' ? ((VALUE) >=0 && (VALUE) <=65535) \ + : (C) == 'L' ? ((VALUE) >=0 && (VALUE) <=31) \ + : (C) == 'M' ? (((VALUE) & 0xffff) == 0 ) \ + : (C) == 'N' ? ((VALUE) >=-33554432 && (VALUE) <=33554431) \ + : (C) == 'O' ? ((VALUE) >=0 && (VALUE) <=0) \ + : 0 ) +#else + +/* The letters I, J, K, L, M, N, and P in a register constraint string + can be used to stand for particular ranges of immediate operands. + This macro defines what the ranges are. + C is the letter, and VALUE is a constant value. + Return 1 if VALUE is in the range specified by C. + + `I' is a signed 16-bit constant + `J' is a constant with only the high-order 16 bits nonzero + `K' is a constant with only the low-order 16 bits nonzero + `L' is a signed 16-bit constant shifted left 16 bits + `M' is a constant that is greater than 31 + `N' is a positive constant that is an exact power of two + `O' is the constant zero + `P' is a constant whose negation is a signed 16-bit constant */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ( (C) == 'I' ? (unsigned HOST_WIDE_INT) ((VALUE) + 0x8000) < 0x10000 \ + : (C) == 'J' ? ((VALUE) & (~ (unsigned HOST_WIDE_INT) 0xffff0000)) == 0 \ + : (C) == 'K' ? ((VALUE) & (~ (HOST_WIDE_INT) 0xffff)) == 0 \ + : (C) == 'L' ? (((VALUE) & 0xffff) == 0 \ + && ((VALUE) >> 31 == -1 || (VALUE) >> 31 == 0)) \ + : (C) == 'M' ? (VALUE) > 31 \ + : (C) == 'N' ? (VALUE) > 0 && exact_log2 (VALUE) >= 0 \ + : (C) == 'O' ? (VALUE) == 0 \ + : (C) == 'P' ? (unsigned HOST_WIDE_INT) ((- (VALUE)) + 0x8000) < 0x10000 \ + : 0) +#endif + +/* -----------------------[ PHX stop ]-------------------------------- */ + +/* Similar, but for floating constants, and defining letters G and H. + Here VALUE is the CONST_DOUBLE rtx itself. */ + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 1 + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS) + +/* Define the codes that are matched by predicates in or32.c. */ + +#define PREDICATE_CODES \ + {"cc_reg_operand", {SUBREG, REG}}, \ + {"branch_comparison_operator", {EQ, NE, LE, LT, GE, \ + GT, LEU, LTU, GEU, GTU, \ + UNORDERED, ORDERED, \ + UNGE, UNLE }}, \ + {"sibcall_insn_operand", {REG, SUBREG, SYMBOL_REF}}, \ + {"input_operand", {SUBREG, REG, CONST_INT, MEM, CONST}}, \ + {"sym_ref_mem_operand", {MEM} }, + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +/* On the or1k, this is always the size of MODE in words, + since all registers are the same size. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD + +/* Define this if the nominal address of the stack frame + is at the high-address end of the local variables; + that is, each additional local variable allocated + goes at a more negative offset in the frame. */ +#define FRAME_GROWS_DOWNWARD + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET 0 + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Define this if stack space is still allocated for a parameter passed + in a register. The value is the number of bytes allocated to this + area. */ +/* +#define REG_PARM_STACK_SPACE(FNDECL) (UNITS_PER_WORD * GP_ARG_NUM_REG) +*/ +/* Define this if the above stack space is to be considered part of the + space allocated by the caller. */ +/* +#define OUTGOING_REG_PARM_STACK_SPACE +*/ +/* Define this macro if `REG_PARM_STACK_SPACE' is defined, but the + stack parameters don't skip the area specified by it. */ +/* +#define STACK_PARMS_IN_REG_PARM_AREA +*/ +/* Define this if the maximum size of all the outgoing args is to be + accumulated and pushed during the prologue. The amount can be + found in the variable current_function_outgoing_args_size. */ +#define ACCUMULATE_OUTGOING_ARGS 1 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + FUNDECL is the declaration node of the function (as a tree), + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. + + On the Vax, the RET insn always pops all the args for any function. */ +/* SIMON */ +/*#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) (SIZE)*/ +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 + +/* Minimum and maximum general purpose registers used to hold arguments. */ +#define GP_ARG_MIN_REG 3 +#define GP_ARG_MAX_REG 8 +#define GP_ARG_NUM_REG (GP_ARG_MAX_REG - GP_ARG_MIN_REG + 1) + +/* Return registers */ +#define GP_ARG_RETURN 11 + +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ + +/* Return value is in R11. */ +#define FUNCTION_VALUE(VALTYPE, FUNC) LIBCALL_VALUE (TYPE_MODE (VALTYPE)) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +/* Return value is in R11. */ + +#define LIBCALL_VALUE(MODE) \ + gen_rtx (REG, \ + ((GET_MODE_CLASS (MODE) != MODE_INT \ + || GET_MODE_SIZE (MODE) >= 4) \ + ? (MODE) \ + : SImode), \ + GP_ARG_RETURN) + +/* Define this if PCC uses the nonreentrant convention for returning + structure and union values. */ + +/*#define PCC_STATIC_STRUCT_RETURN */ + +/* 1 if N is a possible register number for a function value. + R3 to R8 are possible (set to 1 in CALL_USED_REGISTERS) */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == GP_ARG_RETURN) + +/* 1 if N is a possible register number for function argument passing. */ + +#define FUNCTION_ARG_REGNO_P(N) \ + ((N) >= GP_ARG_MIN_REG && (N) <= GP_ARG_MAX_REG) + +/* A code distinguishing the floating point format of the target + machine. There are three defined values: IEEE_FLOAT_FORMAT, + VAX_FLOAT_FORMAT, and UNKNOWN_FLOAT_FORMAT. */ + +#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT +#define FLOAT_WORDS_BIG_ENDIAN 1 + +/* Define a data type for recording info about an argument list + during the scan of that argument list. This data type should + hold all necessary information about the function itself + and about the args processed so far, enough to enable macros + such as FUNCTION_ARG to determine where the next arg should go. + + On the vax, this is a single integer, which is a number of bytes + of arguments scanned so far. */ + +#define CUMULATIVE_ARGS int + +/* Initialize a variable CUM of type CUMULATIVE_ARGS + for a call to a function whose data type is FNTYPE. + For a library call, FNTYPE is 0. + + On the vax, the offset starts at 0. */ + +/* The regs member is an integer, the number of arguments got into + registers so far. */ +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \ + (CUM = 0) + +/* Define intermediate macro to compute the size (in registers) of an argument + for the or1k. */ + +/* The ROUND_ADVANCE* macros are local to this file. */ +/* Round SIZE up to a word boundary. */ +#define ROUND_ADVANCE(SIZE) \ +(((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Round arg MODE/TYPE up to the next word boundary. */ +#define ROUND_ADVANCE_ARG(MODE, TYPE) \ +((MODE) == BLKmode \ + ? ROUND_ADVANCE (int_size_in_bytes (TYPE)) \ + : ROUND_ADVANCE (GET_MODE_SIZE (MODE))) + +/* Round CUM up to the necessary point for argument MODE/TYPE. */ +/* This is either rounded to nearest reg or nearest double-reg boundary */ +#define ROUND_ADVANCE_CUM(CUM, MODE, TYPE) \ +((((MODE) == BLKmode ? TYPE_ALIGN (TYPE) : GET_MODE_BITSIZE (MODE)) \ + > BITS_PER_WORD) \ + ? (((CUM) + 1) & ~1) \ + : (CUM)) + +/* A C expression that indicates when an argument must be passed by + reference. If nonzero for an argument, a copy of that argument is + made in memory and a pointer to the argument is passed instead of + the argument itself. The pointer is passed in whatever way is + appropriate for passing a pointer to that type. */ +/* All aggregates and arguments greater than 8 bytes are passed this way. */ +#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \ +(TYPE \ + && (AGGREGATE_TYPE_P (TYPE) \ + || int_size_in_bytes (TYPE) > 8)) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ +((CUM) = (ROUND_ADVANCE_CUM ((CUM), (MODE), (TYPE)) \ + + ROUND_ADVANCE_ARG ((MODE), (TYPE)))) + +/* Return boolean indicating arg of type TYPE and mode MODE will be passed in + a reg. This includes arguments that have to be passed by reference as the + pointer to them is passed in a reg if one is available (and that is what + we're given). + When passing arguments NAMED is always 1. When receiving arguments NAMED + is 1 for each argument except the last in a stdarg/varargs function. In + a stdarg function we want to treat the last named arg as named. In a + varargs function we want to treat the last named arg (which is + `__builtin_va_alist') as unnamed. + This macro is only used in this file. */ +#define PASS_IN_REG_P(CUM, MODE, TYPE, NAMED) \ +((NAMED) \ + && ((ROUND_ADVANCE_CUM ((CUM), (MODE), (TYPE)) \ + + ROUND_ADVANCE_ARG ((MODE), (TYPE)) \ + <= GP_ARG_NUM_REG))) + +/* 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. + + 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. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). */ +/* On the ARC the first MAX_ARC_PARM_REGS args are normally in registers + and the rest are pushed. */ +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ +(PASS_IN_REG_P ((CUM), (MODE), (TYPE), (NAMED)) \ + ? gen_rtx_REG ((MODE), ROUND_ADVANCE_CUM ((CUM), (MODE), (TYPE)) + GP_ARG_MIN_REG) \ + : 0) + +/* For an arg passed partly in registers and partly in memory, + this is the number of registers used. + For args passed entirely in registers or entirely in memory, zero. */ + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0 + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tl.load32u\tr0,LP%d\n\tcall\tmcount\n", (LABELNO)); + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. */ + +#define EXIT_IGNORE_STACK 0 + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ +{ int offset = -1; \ + rtx regs = stack_pointer_rtx; \ + if (ADDR == frame_pointer_rtx) \ + offset = 0; \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 1) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 0)) == CONST_INT) \ + offset = INTVAL (XEXP (ADDR, 0)); \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + offset = INTVAL (XEXP (ADDR, 1)); \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 1); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 1) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 0); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + if (offset >= 0) \ + { int regno; \ + extern char call_used_regs[]; \ + offset += 4; /* I don't know why??? */ \ + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 4; \ + ADDR = plus_constant (regs, offset + (DEPTH)); } } + + +/* Addressing modes, and classification of registers for them. */ + +/* #define HAVE_POST_INCREMENT */ +/* #define HAVE_POST_DECREMENT */ + +/* #define HAVE_PRE_DECREMENT */ +/* #define HAVE_PRE_INCREMENT */ + +/* Macros to check register numbers against specific register classes. */ + +#define MAX_REGS_PER_ADDRESS 1 + +/* True if X is an rtx for a constant that is a valid address. */ +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \ + || GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST \ + || GET_CODE (X) == HIGH) + +#define REGNO_OK_FOR_BASE_P(REGNO) \ +((REGNO) < FIRST_PSEUDO_REGISTER ? ((REGNO) > 0 && (REGNO) <= LAST_INT_REG) \ + : (reg_renumber[REGNO] > 0 && (reg_renumber[REGNO] <= LAST_INT_REG ))) + +#ifdef REG_OK_STRICT +/* Strict version, used in reload pass. This should not + * accept pseudo registers. + */ +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P(REGNO(X)) +#else +/* Accept an int register or a pseudo reg. */ +#define REG_OK_FOR_BASE_P(X) (REGNO(X) <= LAST_INT_REG || \ + REGNO(X) >= FIRST_PSEUDO_REGISTER) +#endif + +/* + * OR1K doesn't have any indexed addressing. + */ +#define REG_OK_FOR_INDEX_P(X) 0 +#define REGNO_OK_FOR_INDEX_P(X) 0 + +#define LEGITIMATE_ADDRESS_INTEGER_P(X,OFFSET) \ + (GET_CODE (X) == CONST_INT && SMALL_INT(X)) + +#define LEGITIMATE_OFFSET_ADDRESS_P(MODE,X) \ + (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && LEGITIMATE_ADDRESS_INTEGER_P (XEXP (X, 1), 0) \ + && (((MODE) != DFmode && (MODE) != DImode) \ + || LEGITIMATE_ADDRESS_INTEGER_P (XEXP (X, 1), 4))) + +#define LEGITIMATE_NONOFFSET_ADDRESS_P(MODE,X) \ + (GET_CODE(X) == REG && REG_OK_FOR_BASE_P(X)) +/* + * OR1K only has one addressing mode: + * register + 16 bit signed offset. + */ +#define GO_IF_LEGITIMATE_ADDRESS(MODE,X,ADDR) \ + if(LEGITIMATE_OFFSET_ADDRESS_P(MODE,X)) goto ADDR; \ + if(LEGITIMATE_NONOFFSET_ADDRESS_P(MODE,X)) goto ADDR; + +/* + if(GET_CODE(X) == SYMBOL_REF) goto ADDR; */ /* If used, smaller code */ + +/* Alternative */ +#if 0 +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ \ + if (GET_CODE (X) == REG) goto ADDR; \ + if (GET_CODE (X) == SYMBOL_REF) goto ADDR; \ + if (CONSTANT_ADDRESS_P (X)) goto ADDR; \ + if (GET_CODE (X) == PLUS) \ + { \ + /* Handle [index]<address> represented with index-sum outermost */\ + if (GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT) \ + goto ADDR; \ + if (GET_CODE (XEXP (X, 1)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 0)) == CONST_INT) \ + goto ADDR; \ + } \ + } +#endif +/* + * We have to force symbol_ref's into registers here + * because nobody else seems to want to do that! + */ +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) {} +/* +{ if (GET_CODE (x) == SYMBOL_REF) \ + (X) = copy_to_reg (X); \ + if (memory_address_p (MODE, X)) \ + goto WIN; \ +} +*/ + +/* + * OR1K addresses do not depend on the machine mode they are + * being used in. + */ +#define GO_IF_MODE_DEPENDENT_ADDRESS(addr,label) + +/* OR1K has 16 bit immediates. + */ +#define SMALL_INT(X) (INTVAL(X) >= -32768 && INTVAL(X) <= 32767) + +#define LEGITIMATE_CONSTANT_P(x) (GET_CODE(x) != CONST_DOUBLE) + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE SImode + +/* Define as C expression which evaluates to nonzero if the tablejump + instruction expects the table to contain offsets from the address of the + table. + Do not define this if the table should contain absolute addresses. */ +/* #define CASE_VECTOR_PC_RELATIVE 1 */ + +/* Define this as 1 if `char' should by default be signed; else as 0. */ +#define DEFAULT_SIGNED_CHAR 1 + +/* This flag, if defined, says the same insns that convert to a signed fixnum + also convert validly to an unsigned one. */ +#define FIXUNS_TRUNC_LIKE_FIX_TRUNC + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 4 + +/* Define this if zero-extension is slow (more than one real instruction). */ +/* #define SLOW_ZERO_EXTEND */ + +/* Nonzero if access to memory by bytes is slow and undesirable. + For RISC chips, it means that access to memory by bytes is no + better than access by words when possible, so grab a whole word + and maybe make use of that. */ +#define SLOW_BYTE_ACCESS 1 + +/* Define if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. */ +/* #define SHIFT_COUNT_TRUNCATED */ + +/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits + is done just by pretending it is already truncated. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +/* Specify the machine mode that pointers have. + After generation of rtl, the compiler makes no further distinction + between pointers and any other objects of this machine mode. */ +#define Pmode SImode + +/* A function address in a call instruction + is a byte address (for indexing purposes) + so give the MEM rtx a byte's mode. */ +#define FUNCTION_MODE SImode + +/* Compute the cost of computing a constant rtl expression RTX + whose rtx-code is CODE. The body of this macro is a portion + of a switch statement. If the code is computed here, + return it with a return statement. Otherwise, break from the switch. */ +#if 0 +__PHX__ cleanup +#define CONST_COSTS(RTX,CODE,OUTER_CODE) \ + case CONST_INT: \ + /* Constant zero is super cheap due to clr instruction. */ \ + if (RTX == const0_rtx) return 0; \ + if ((unsigned) INTVAL (RTX) < 077) return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 3; \ + case CONST_DOUBLE: \ + return 5; +#endif + + +/* Given a comparison code (EQ, NE, etc.) and the first operand of a + COMPARE, return the mode to be used for the comparison. +*/ + +#define SELECT_CC_MODE(OP, X, Y) or32_cc_mode ((OP), (X), (Y)) + +/* Can the condition code MODE be safely reversed? This is safe in + all cases on this port, because at present it doesn't use the + trapping FP comparisons (fcmpo). */ +#define REVERSIBLE_CC_MODE(MODE) 1 + +/* Given a condition code and a mode, return the inverse condition. */ +#define REVERSE_CONDITION(CODE, MODE) or32_reverse_condition (MODE, CODE) + + +/* Control the assembler format that we output. */ + +/* A C string constant describing how to begin a comment in the target + assembler language. The compiler assumes that the comment will end at + the end of the line. */ +#define ASM_COMMENT_START "#" + +/* Output at beginning of assembler file. */ +/* +__PHX__ clenup +#ifndef ASM_FILE_START +#define ASM_FILE_START(FILE) do {\ +fprintf (FILE, "%s file %s\n", ASM_COMMENT_START, main_input_filename);\ +fprintf (FILE, ".file\t"); \ + output_quoted_string (FILE, main_input_filename);\ + fputc ('\n', FILE);} while (0) +#endif +*/ +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "" + +/* Switch to the text or data segment. */ + +/* Output before read-only data. */ +#define TEXT_SECTION_ASM_OP ".section .text" + +/* Output before writable data. */ +#define DATA_SECTION_ASM_OP ".section .data" + +/* Output before uninitialized data. */ +#define BSS_SECTION_ASM_OP ".section .bss" + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +#define REGISTER_NAMES \ +{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" \ +, "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", "cc-flag"} + + +/* Define this to be the delimiter between SDB sub-sections. The default + is ";". */ +#define SDB_DELIM "\n" + +/* Do not break .stabs pseudos into continuations. */ +#define DBX_CONTIN_LENGTH 0 + +/* Don't try to use the type-cross-reference character in DBX data. + Also has the consequence of putting each struct, union or enum + into a separate .stabs, containing only cross-refs to the others. */ +#define DBX_NO_XREFS + +/* How to renumber registers for dbx and gdb. + Vax needs no change in the numeration. */ + +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* This is the char to use for continuation (in case we need to turn + continuation back on). */ + +#define DBX_CONTIN_CHAR '?' + + + + + +/* Node: Label Output */ + +/* Globalizing directive for a label. */ +#define GLOBAL_ASM_OP "\t.global " + +#define SUPPORTS_WEAK 1 + +/* This is how to output the definition of a user-level label named NAME, + such as the label on a static function or variable NAME. */ + +#define ASM_OUTPUT_LABEL(FILE,NAME) \ + { assemble_name (FILE, NAME); fputs (":\n", FILE); } +#if 0 +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ +/* + __PHX__ CLEANUP +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + { fputs ("\t.global ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE); } +*/ + +/* SIMON */ +/*#define ASM_OUTPUT_LABELREF(stream,name) \ + { fputc('_',stream); fputs(name,stream); } +*/ +#define ASM_OUTPUT_LABELREF(stream,name) \ +{if(name[0] == '*') \ + fputs(name,stream); \ +else { \ + fputc('_',stream); fputs(name,stream); \ +}} +#endif + +/* The prefix to add to user-visible assembler symbols. */ + +/* Remove any previous definition (elfos.h). */ +/* We use -fno-leading-underscore to remove it, when necessary. */ +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "_" + +/* Remove any previous definition (elfos.h). */ +#ifndef ASM_GENERATE_INTERNAL_LABEL +#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \ + sprintf (LABEL, "*%s%d", PREFIX, NUM) +#endif + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( \ + fprintf (FILE, "\t.word "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_FLOAT(stream,value) \ + { long l; \ + REAL_VALUE_TO_TARGET_SINGLE(value,l); \ + fprintf(stream,"\t.word 0x%08x\t\n# float %26.7e\n",l,value); } + +#define ASM_OUTPUT_DOUBLE(stream,value) \ + { long l[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE(value,&l[0]); \ + fprintf(stream,"\t.word 0x%08x,0x%08x\t\n# float %26.16le\n", \ + l[0],l[1],value); } + +#define ASM_OUTPUT_LONG_DOUBLE(stream,value) \ + { long l[4]; \ + REAL_VALUE_TO_TARGET_DOUBLE(value,&l[0]); \ + fprintf(stream,"\t.word 0x%08x,0x%08x,0x%08x,0x%08x\t\n# float %26.18lle\n", \ + l[0],l[1],l[2],l[3],value); } + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.half "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\t.byte 0x%02x\n", (VALUE)) + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tl.sub \tr1,4\n\tl.sw \t0(r1),%s\n", reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tl.lwz \t%s,0(r1)\n\tl.addi \tr1,4\n", reg_names[REGNO]) + +/* This is how to output an element of a case-vector that is absolute. + (The Vax does not use such vectors, + but we must define this macro anyway.) */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.word .L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + fprintf (FILE, "\t.word .L%d-.L%d\n", VALUE, REL) + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) != 0) fprintf (FILE, "\t.align %d\n", 1 << (LOG)) + +/* This is how to output an assembler line + that says to advance the location counter by SIZE bytes. */ + +#ifndef ASM_OUTPUT_SKIP +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.space %d\n", (SIZE)) +#endif + +/* Need to split up .ascii directives to avoid breaking + the linker. */ + +/* This is how to output a string. */ +#ifndef ASM_OUTPUT_ASCII +#define ASM_OUTPUT_ASCII(STREAM, STRING, LEN) \ +do { \ + register int i, c, len = (LEN), cur_pos = 17; \ + register unsigned char *string = (unsigned char *)(STRING); \ + fprintf ((STREAM), "\t.ascii\t\""); \ + for (i = 0; i < len; i++) \ + { \ + register int c = string[i]; \ + \ + switch (c) \ + { \ + case '\"': \ + case '\\': \ + putc ('\\', (STREAM)); \ + putc (c, (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_NEWLINE: \ + fputs ("\\n", (STREAM)); \ + if (i+1 < len \ + && (((c = string[i+1]) >= '\040' && c <= '~') \ + || c == TARGET_TAB)) \ + cur_pos = 32767; /* break right here */ \ + else \ + cur_pos += 2; \ + break; \ + \ + case TARGET_TAB: \ + fputs ("\\t", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_FF: \ + fputs ("\\f", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_BS: \ + fputs ("\\b", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_CR: \ + fputs ("\\r", (STREAM)); \ + cur_pos += 2; \ + break; \ + \ + default: \ + if (c >= ' ' && c < 0177) \ + { \ + putc (c, (STREAM)); \ + cur_pos++; \ + } \ + else \ + { \ + fprintf ((STREAM), "\\%03o", c); \ + cur_pos += 4; \ + } \ + } \ + \ + if (cur_pos > 72 && i+1 < len) \ + { \ + cur_pos = 17; \ + fprintf ((STREAM), "\"\n\t.ascii\t\""); \ + } \ + } \ + fprintf ((STREAM), "\"\n"); \ +} while (0) +#endif /* ASM_OUTPUT_ASCII */ + +/* Invoked just before function output. */ + +#define ASM_OUTPUT_FUNCTION_PREFIX(stream, fnname) \ + fputs(".proc ",stream); assemble_name(stream,fnname); \ + fputs("\n",stream); + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(stream,name,size,rounded) \ +{ data_section(); \ + fputs(".global\t",stream); assemble_name(stream,name); \ + fputs("\n",stream); assemble_name(stream,name); \ + fprintf(stream,":\n\t.space %d\n",rounded); } + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".bss ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%d,%d\n", (SIZE),(ROUNDED))) + +/* This says how to output an assembler line to define a global common symbol + with size SIZE (in bytes) and alignment ALIGN (in bits). */ +#ifndef ASM_OUTPUT_ALIGNED_COMMON +#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \ +{ data_section(); \ + if ((ALIGN) > 8) \ + fprintf(FILE, "\t.align %d\n", ((ALIGN) / BITS_PER_UNIT)); \ + fputs(".global\t", FILE); assemble_name(FILE, NAME); \ + fputs("\n", FILE); \ + assemble_name(FILE, NAME); \ + fprintf(FILE, ":\n\t.space %d\n", SIZE); \ +} +#endif /* ASM_OUTPUT_ALIGNED_COMMON */ + +/* This says how to output an assembler line to define a local common symbol + with size SIZE (in bytes) and alignment ALIGN (in bits). */ + +#ifndef ASM_OUTPUT_ALIGNED_LOCAL +#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \ +{ data_section(); \ + if ((ALIGN) > 8) \ + fprintf(FILE, "\t.align %d\n", ((ALIGN) / BITS_PER_UNIT)); \ + assemble_name(FILE, NAME); \ + fprintf(FILE, ":\n\t.space %d\n", SIZE); \ +} +#endif /* ASM_OUTPUT_ALIGNED_LOCAL */ + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) + +/* Macro for %code validation. Returns nonzero if valid. */ +#define PRINT_OPERAND_PUNCT_VALID_P(code) print_operand_punct_valid_p(code) + +/* Print an instruction operand X on file FILE. + CODE is the code from the %-spec that requested printing this operand; + if `%z3' was used to print operand 3, then CODE is 'z'. */ + +#define PRINT_OPERAND(FILE, X, CODE) print_operand(FILE, X, CODE) + +/* Print a memory operand whose address is X, on file FILE. + This uses a function in output-vax.c. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address (FILE, ADDR) + +/* These are stubs, and have yet to bee written. */ + +#define TRAMPOLINE_SIZE 26 +#define TRAMPOLINE_TEMPLATE(FILE) +#define INITIALIZE_TRAMPOLINE(TRAMP,FNADDR,CXT) + +extern GTY(()) rtx or32_compare_op0; +extern GTY(()) rtx or32_compare_op1; + +/* We don't use libg.a */ +#undef LIB_SPEC +#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}" +#endif /* _OR32_H_ */ diff -Nru gcc-3.4.4.orig/gcc/config/or32/or32.md gcc-3.4.4-DONE/gcc/config/or32/or32.md --- gcc-3.4.4.orig/gcc/config/or32/or32.md 1970-01-01 02:00:00.000000000 +0200 +++ gcc-3.4.4-DONE/gcc/config/or32/or32.md 2005-11-29 16:23:09.000000000 +0200 @@ -0,0 +1,1281 @@ +;; Machine description for GNU compiler, OpenRISC 1000 family, OR32 ISA +;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. +;; Contributed by Damjan Lampret <damjanl@bsemi.com> in 1999. +;; Major optimizations by Matjaz Breskvar <matjazb@bsemi.com> in 2005. + +;; 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 1, 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. + +(define_attr "type" + "unknown,load,store,move,extend,logic,add,mul,shift,compare,branch,jump,fp" + (const_string "unknown")) + +;; Number of instructions +(define_attr "length" "" (const_int 1)) + +(define_delay (eq_attr "type" "branch,jump") + [(and (eq_attr "type" "!branch,jump") + (eq_attr "length" "1")) (nil) (nil)]) + +;; (define_function_unit NAME MULTIPLICITY SIMULTANEITY +;; TEST READY-DELAY ISSUE-DELAY [CONFLICT-LIST]) +;; MULTIPLICITY - Number of functional units of this type +;; SIMULTANEITY - Zero for pipelined functional unit +;; READY-DELAY - Number of cycles before result is available +;; ISSUE-DELAY - Number of cycles before unit can accept new instruction +;; +(define_function_unit "bit_unit" 1 0 (eq_attr "type" "shift") 3 1) +(define_function_unit "lsu" 1 0 (eq_attr "type" "load") 3 3) +(define_function_unit "lsu" 1 0 (eq_attr "type" "store") 2 1) +(define_function_unit "alu" 1 0 (eq_attr "type" "add,logic,extend,move,compare") 2 1) +(define_function_unit "mul_unit" 1 0 (eq_attr "type" "mul") 16 16) + + +;; Called after register allocation to add any instructions needed for the +;; prologue. Using a prologue insn is favored compared to putting all of the +;; instructions in output_function_prologue(), since it allows the scheduler +;; to intermix instructions with the saves of the caller saved registers. In +;; some cases, it might be necessary to emit a barrier instruction as the last +;; insn to prevent such scheduling. + +(define_expand "prologue" + [(use (const_int 1))] + "TARGET_SCHED_LOGUE" +{ + or32_expand_prologue (); + DONE; +}) + +;; Called after register allocation to add any instructions needed for the +;; epilogue. Using an epilogue insn is favored compared to putting all of the +;; instructions in output_function_epilogue(), since it allows the scheduler +;; to intermix instructions with the restores of the caller saved registers. +;; In some cases, it might be necessary to emit a barrier instruction as the +;; first insn to prevent such scheduling. +(define_expand "epilogue" + [(use (const_int 2))] + "TARGET_SCHED_LOGUE" +{ + or32_expand_epilogue (false); + DONE; +}) + +(define_expand "sibcall_epilogue" + [(use (const_int 2))] + "TARGET_SCHED_LOGUE" +{ + or32_expand_epilogue (true); + DONE; +}) + +(define_insn "return_internal" + [(return) + (use (match_operand 0 "pmode_register_operand" ""))] + "TARGET_SCHED_LOGUE" + "l.jr \t%0%(" + [(set_attr "type" "jump") + (set_attr "length" "1")]) + +;; +;; Sibcalls +;; + +(define_expand "sibcall" + [(parallel [(call (match_operand 0 "" "") + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) ;; next_arg_reg + (use (match_operand 3 "" ""))])] ;; struct_value_size_rtx + "TARGET_SIBCALL" + " +{ + or32_expand_sibcall (0, XEXP (operands[0], 0), operands[1]); + DONE; +}") + +(define_expand "sibcall_value" + [(set (match_operand 0 "" "") + (call (match_operand:SI 1 "" "") + (match_operand 2 "" "")))] + "TARGET_SIBCALL" + " +{ + or32_expand_sibcall (operands[0], XEXP (operands[1], 0), operands[2]); + DONE; +}") + +(define_insn "sibcall_internal" + [(call (mem:SI (match_operand:SI 0 "sibcall_insn_operand" "s,r")) + (match_operand 1 "" "")) + (use (reg:SI 9))] + "TARGET_SIBCALL" + "@ + l.j \t%S0%(\t # sibcall s + l.jr \t%0%(\t # sibcall r" + [(set_attr "type" "jump,jump")]) + + + +;; +;; movQI +;; + +(define_expand "movqi" + [(set (match_operand:QI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" + " + if (!no_new_pseudos) + { + if (GET_CODE (operands[1]) == CONST_INT) + { + rtx reg = gen_reg_rtx (SImode); + + emit_insn (gen_movsi (reg, operands[1])); + operands[1] = gen_lowpart (QImode, reg); + } + if (GET_CODE (operands[1]) == MEM && optimize > 0) + { + rtx reg = gen_reg_rtx (SImode); + + emit_insn (gen_rtx_SET (SImode, reg, + gen_rtx_ZERO_EXTEND (SImode, + operands[1]))); + + operands[1] = gen_lowpart (QImode, reg); + } + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (QImode, operands[1]); + } +") + +(define_insn "*movqi_internal" + [(set (match_operand:QI 0 "nonimmediate_operand" "=m,r,r,r,r") + (match_operand:QI 1 "general_operand" "r,r,I,K,m"))] + "" + "@ + l.sb \t%0,%1\t # movqi + l.ori \t%0,%1,0\t # movqi: move reg to reg + l.addi \t%0,r0,%1\t # movqi: move immediate + l.ori \t%0,r0,%1\t # movqi: move immediate + l.lbz \t%0,%1\t # movqi" + [(set_attr "type" "store,add,add,logic,load")]) + + +;; +;; movHI +;; + +(define_expand "movhi" + [(set (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + " + if (!no_new_pseudos) + { + if (GET_CODE (operands[1]) == CONST_INT) + { + rtx reg = gen_reg_rtx (SImode); + + emit_insn (gen_movsi (reg, operands[1])); + operands[1] = gen_lowpart (HImode, reg); + } + if (GET_CODE (operands[1]) == MEM && optimize > 0) + { + rtx reg = gen_reg_rtx (SImode); + + emit_insn (gen_rtx_SET (SImode, reg, + gen_rtx_ZERO_EXTEND (SImode, + operands[1]))); + operands[1] = gen_lowpart (HImode, reg); + } + if (GET_CODE (operands[0]) != REG) + operands[1] = force_reg (HImode, operands[1]); + } +") + +(define_insn "*movhi_internal" + [(set (match_operand:HI 0 "nonimmediate_operand" "=m,r,r,r,r") + (match_operand:HI 1 "general_operand" "r,r,I,K,m"))] + "" + "@ + l.sh \t%0,%1\t # movhi + l.ori \t%0,%1,0\t # movhi: move reg to reg + l.addi \t%0,r0,%1\t # movhi: move immediate + l.ori \t%0,r0,%1\t # movhi: move immediate + l.lhz \t%0,%1\t # movhi" + [(set_attr "type" "store,add,add,logic,load")]) + +(define_expand "movsi" + [(set (match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" +{ + /* Working with CONST_INTs is easier, so convert + a double if needed. */ + + if (GET_CODE (operands[1]) == CONST_DOUBLE) { + operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1])); + } + + /* Handle sets of MEM first. */ + if (GET_CODE (operands[0]) == MEM) + { + if (register_operand(operands[1], SImode) + || (operands[1] == const0_rtx)) + goto movsi_is_ok; + + if (! reload_in_progress) + { + operands[0] = validize_mem (operands[0]); + operands[1] = force_reg (SImode, operands[1]); + } + } + + /* This makes sure we will not get rematched due to splittage. */ + if (! CONSTANT_P (operands[1]) || input_operand (operands[1], SImode)) + ; + else if (CONSTANT_P (operands[1]) + && GET_CODE (operands[1]) != HIGH + && GET_CODE (operands[1]) != LO_SUM) + { + or32_emit_set_const32 (operands[0], operands[1]); + DONE; + } + movsi_is_ok: + ; +}) + +;; +;; movSI +;; + +(define_insn "*movsi_insn" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,m") + (match_operand:SI 1 "input_operand" "I,K,M,r,m,r"))] + "(register_operand (operands[0], SImode) + || register_operand (operands[1], SImode) + || (operands[1] == const0_rtx))" + "@ + l.addi \t%0,r0,%1\t # move immediate I + l.ori \t%0,r0,%1\t # move immediate K + l.movhi \t%0,hi(%1)\t # move immediate M + l.ori \t%0,%1,0\t # move reg to reg + l.lwz \t%0,%1\t # SI load + l.sw \t%0,%1\t # SI store" + [(set_attr "type" "add,load,store,add,logic,move") + (set_attr "length" "1,1,1,1,1,1")]) + +(define_insn "*movsi_lo_sum" + [(set (match_operand:SI 0 "register_operand" "=r") + (lo_sum:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "immediate_operand" "i")))] + "" + "l.ori \t%0,%1,lo(%2)" + [(set_attr "type" "logic") + (set_attr "length" "1")]) + +(define_insn "*movsi_high" + [(set (match_operand:SI 0 "register_operand" "=r") + (high:SI (match_operand:SI 1 "immediate_operand" "i")))] + "" + "l.movhi \t%0,hi(%1)" +[(set_attr "type" "move") + (set_attr "length" "1")]) + +(define_insn "movsi_insn_big" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r") + (match_operand:SI 1 "immediate_operand" "i"))] + "GET_CODE(operands[1]) != CONST_INT" + "l.movhi \t%0,hi(%1)\;l.ori \t%0,%0,lo(%1)" + [(set_attr "type" "move") + (set_attr "length" "2")]) + + +;; +;; Conditional Branches & Moves +;; + +(define_expand "addsicc" + [(match_operand:SI 0 "register_operand" "") + (match_operand 1 "comparison_operator" "") + (match_operand:SI 2 "register_operand" "") + (match_operand:SI 3 "register_operand" "")] + "" + "FAIL;") + +(define_expand "addhicc" + [(match_operand:HI 0 "register_operand" "") + (match_operand 1 "comparison_operator" "") + (match_operand:HI 2 "register_operand" "") + (match_operand:HI 3 "register_operand" "")] + "" + "FAIL;") + +(define_expand "addqicc" + [(match_operand:QI 0 "register_operand" "") + (match_operand 1 "comparison_operator" "") + (match_operand:QI 2 "register_operand" "") + (match_operand:QI 3 "register_operand" "")] + "" + "FAIL;") + + +;; +;; conditional moves +;; + +(define_expand "movsicc" + [(set (match_operand:SI 0 "register_operand" "") + (if_then_else:SI (match_operand 1 "comparison_operator" "") + (match_operand:SI 2 "register_operand" "") + (match_operand:SI 3 "register_operand" "")))] + "TARGET_CMOV" + " +{ + if (or32_emit_cmove (operands[0], operands[1], operands[2], operands[3])) + DONE; +}") + +(define_expand "movhicc" + [(set (match_operand:HI 0 "register_operand" "") + (if_then_else:SI (match_operand 1 "comparison_operator" "") + (match_operand:HI 2 "register_operand" "") + (match_operand:HI 3 "register_operand" "")))] + "" + " +{ + FAIL; +}") + +(define_expand "movqicc" + [(set (match_operand:QI 0 "register_operand" "") + (if_then_else:SI (match_operand 1 "comparison_operator" "") + (match_operand:QI 2 "register_operand" "") + (match_operand:QI 3 "register_operand" "")))] + "" + " +{ + FAIL; +}") + + +;; We use the BASE_REGS for the cmov input operands because, if rA is +;; 0, the value of 0 is placed in rD upon truth. Similarly for rB +;; because we may switch the operands and rB may end up being rA. + +(define_insn "cmov" + [(set (match_operand:SI 0 "register_operand" "=r") + (if_then_else:SI + (match_operator 1 "comparison_operator" + [(match_operand 4 "cc_reg_operand" "") + (const_int 0)]) + (match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "r")))] + "TARGET_CMOV" + "* +{ output_cmov(operands); }") + +;; +;; .................... +;; +;; COMPARISONS +;; +;; .................... + +;; Flow here is rather complex: +;; +;; 1) The cmp{si,di,sf,df} routine is called. It deposits the +;; arguments into the branch_cmp array, and the type into +;; branch_type. No RTL is generated. +;; +;; 2) The appropriate branch define_expand is called, which then +;; creates the appropriate RTL for the comparison and branch. +;; Different CC modes are used, based on what type of branch is +;; done, so that we can constrain things appropriately. There +;; are assumptions in the rest of GCC that break if we fold the +;; operands into the branches for integer operations, and use cc0 +;; for floating point, so we use the fp status register instead. +;; If needed, an appropriate temporary is created to hold the +;; of the integer compare. + +;; Compare insns are next. Note that the RS/6000 has two types of compares, +;; signed & unsigned, and one type of branch. +;; +;; Start with the DEFINE_EXPANDs to generate the rtl for compares, scc +;; insns, and branches. We store the operands of compares until we see +;; how it is used. + +(define_expand "cmpsi" + [(set (reg:CC 32) + (compare:CC (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "nonmemory_operand" "")))] + "" +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + operands[0] = force_reg (SImode, operands[0]); + or32_compare_op0 = operands[0]; + or32_compare_op1 = operands[1]; + DONE; +}) + + + +;; +;; Conditional branches +;; + +(define_expand "beq" + [(use (match_operand 0 "" ""))] + "" + "or32_expand_branch (EQ, operands[0]); DONE;") + +(define_expand "bne" + [(use (match_operand 0 "" ""))] + "" + "or32_expand_branch (NE, operands[0]); DONE;") + +(define_expand "bgt" + [(use (match_operand 0 "" ""))] + "" + "or32_expand_branch (GT, operands[0]); DONE;") + +(define_expand "bgtu" + [(use (match_operand 0 "" ""))] + "" + "or32_expand_branch (GTU, operands[0]); DONE;") + +(define_expand "blt" + [(use (match_operand 0 "" ""))] + "" + "or32_expand_branch (LT, operands[0]); DONE;") + +(define_expand "bltu" + [(use (match_operand 0 "" ""))] + "" + "or32_expand_branch (LTU, operands[0]); DONE;") + +(define_expand "bge" + [(use (match_operand 0 "" ""))] + "" + "or32_expand_branch (GE, operands[0]); DONE;") + +(define_expand "bgeu" + [(use (match_operand 0 "" ""))] + "" + "or32_expand_branch (GEU, operands[0]); DONE;") + +(define_expand "ble" + [(use (match_operand 0 "" ""))] + "" + "or32_expand_branch (LE, operands[0]); DONE;") + +(define_expand "bleu" + [(use (match_operand 0 "" ""))] + "" + "or32_expand_branch (LEU, operands[0]); DONE;") + + + +;; +;; Setting a CCxx registers from comparision +;; + + + +;; Here are the actual compare insns. +(define_insn "*cmpsi_eq" + [(set (reg:CCEQ 32) + (compare:CCEQ (match_operand:SI 0 "register_operand" "r,r") + (match_operand:SI 1 "nonmemory_operand" "I,r")))] + "" + "@ + l.sfeqi\t%0,%1 + l.sfeq \t%0,%1") + +(define_insn "*cmpsi_ne" + [(set (reg:CCNE 32) + (compare:CCNE (match_operand:SI 0 "register_operand" "r,r") + (match_operand:SI 1 "nonmemory_operand" "I,r")))] + "" + "@ + l.sfnei\t%0,%1 + l.sfne \t%0,%1") + +(define_insn "*cmpsi_gt" + [(set (reg:CCGT 32) + (compare:CCGT (match_operand:SI 0 "register_operand" "r,r") + (match_operand:SI 1 "nonmemory_operand" "I,r")))] + "" + "@ + l.sfgtsi\t%0,%1 + l.sfgts \t%0,%1") + +(define_insn "*cmpsi_gtu" + [(set (reg:CCGTU 32) + (compare:CCGTU (match_operand:SI 0 "register_operand" "r,r") + (match_operand:SI 1 "nonmemory_operand" "I,r")))] + "" + "@ + l.sfgtui\t%0,%1 + l.sfgtu \t%0,%1") + +(define_insn "*cmpsi_lt" + [(set (reg:CCLT 32) + (compare:CCLT (match_operand:SI 0 "register_operand" "r,r") + (match_operand:SI 1 "nonmemory_operand" "I,r")))] + "" + "@ + l.sfltsi\t%0,%1 + l.sflts \t%0,%1") + +(define_insn "*cmpsi_ltu" + [(set (reg:CCLTU 32) + (compare:CCLTU (match_operand:SI 0 "register_operand" "r,r") + (match_operand:SI 1 "nonmemory_operand" "I,r")))] + "" + "@ + l.sfltui\t%0,%1 + l.sfltu \t%0,%1") + +(define_insn "*cmpsi_ge" + [(set (reg:CCGE 32) + (compare:CCGE (match_operand:SI 0 "register_operand" "r,r") + (match_operand:SI 1 "nonmemory_operand" "I,r")))] + "" + "@ + l.sfgesi\t%0,%1 + l.sfges \t%0,%1") + + +(define_insn "*cmpsi_geu" + [(set (reg:CCGEU 32) + (compare:CCGEU (match_operand:SI 0 "register_operand" "r,r") + (match_operand:SI 1 "nonmemory_operand" "I,r")))] + "" + "@ + l.sfgeui\t%0,%1 + l.sfgeu \t%0,%1") + + +(define_insn "*cmpsi_le" + [(set (reg:CCLE 32) + (compare:CCLE (match_operand:SI 0 "register_operand" "r,r") + (match_operand:SI 1 "nonmemory_operand" "I,r")))] + "" + "@ + l.sflesi\t%0,%1 + l.sfles \t%0,%1") + +(define_insn "*cmpsi_leu" + [(set (reg:CCLEU 32) + (compare:CCLEU (match_operand:SI 0 "register_operand" "r,r") + (match_operand:SI 1 "nonmemory_operand" "I,r")))] + "" + "@ + l.sfleui\t%0,%1 + l.sfleu \t%0,%1") + +(define_insn "*bf" + [(set (pc) + (if_then_else (match_operator 1 "comparison_operator" + [(match_operand 2 + "cc_reg_operand" "") + (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ output_bf(operands); }" + [(set_attr "type" "branch") + (set_attr "length" "1")]) + +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; + + +(define_insn "movdi" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r, r, m, r") + (match_operand:DI 1 "general_operand" " r, m, r, i"))] + "" + "* + return or32_output_move_double (operands); + " + [(set_attr "length" "2,2,2,3")]) + +(define_insn "movdf" + [(set (match_operand:DF 0 "nonimmediate_operand" "=r, r, m, r") + (match_operand:DF 1 "general_operand" " r, m, r, i"))] + "" + "* + return or32_output_move_double (operands); + " + [(set_attr "length" "2,2,2,3")]) + + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=r,r,m") + (match_operand:SF 1 "general_operand" "r,m,r"))] + "" + "@ + l.ori \t%0,%1,0\t # movsf + l.lwz \t%0,%1\t # movsf + l.sw \t%0,%1\t # movsf" +[(set_attr "type" "move,load,store") + (set_attr "length" "1,1,1")]) + +;; +;; extendqisi2 +;; + +(define_expand "extendqisi2" + [(use (match_operand:SI 0 "register_operand" "")) + (use (match_operand:QI 1 "nonimmediate_operand" ""))] + "" + " +{ + if (TARGET_SEXT) + emit_insn (gen_extendqisi2_sext(operands[0], operands[1])); + else { + if ( GET_CODE(operands[1]) == MEM ) { + emit_insn (gen_extendqisi2_no_sext_mem(operands[0], operands[1])); + } + else { + emit_insn (gen_extendqisi2_no_sext_reg(operands[0], operands[1])); + } + } + DONE; +}") + +(define_insn "extendqisi2_sext" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] + "TARGET_SEXT" + "@ + l.extbs \t%0,%1\t # extendqisi2_has_signed_extend + l.lbs \t%0,%1\t # extendqisi2_has_signed_extend" + [(set_attr "length" "1,1") + (set_attr "type" "extend,load")]) + +(define_insn "extendqisi2_no_sext_mem" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "!TARGET_SEXT" + "l.lbs \t%0,%1\t # extendqisi2_no_sext_mem" + [(set_attr "length" "1") + (set_attr "type" "load")]) + +(define_expand "extendqisi2_no_sext_reg" + [(set (match_dup 2) + (ashift:SI (match_operand:QI 1 "register_operand" "") + (const_int 24))) + (set (match_operand:SI 0 "register_operand" "") + (ashiftrt:SI (match_dup 2) + (const_int 24)))] + "!TARGET_SEXT" + " +{ + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); }") + +;; +;; extendhisi2 +;; + +(define_expand "extendhisi2" + [(use (match_operand:SI 0 "register_operand" "")) + (use (match_operand:HI 1 "nonimmediate_operand" ""))] + "" + " +{ + if (TARGET_SEXT) + emit_insn (gen_extendhisi2_sext(operands[0], operands[1])); + else { + if ( GET_CODE(operands[1]) == MEM ) { + emit_insn (gen_extendhisi2_no_sext_mem(operands[0], operands[1])); + } + else { + emit_insn (gen_extendhisi2_no_sext_reg(operands[0], operands[1])); + } + } + DONE; +}") + +(define_insn "extendhisi2_sext" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] + "TARGET_SEXT" + "@ + l.exths \t%0,%1\t # extendhisi2_has_signed_extend + l.lhs \t%0,%1\t # extendhisi2_has_signed_extend" + [(set_attr "length" "1,1") + (set_attr "type" "extend,load")]) + +(define_insn "extendhisi2_no_sext_mem" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "!TARGET_SEXT" + "l.lhs \t%0,%1\t # extendhisi2_no_sext_mem" + [(set_attr "length" "1") + (set_attr "type" "load")]) + +(define_expand "extendhisi2_no_sext_reg" + [(set (match_dup 2) + (ashift:SI (match_operand:HI 1 "register_operand" "") + (const_int 16))) + (set (match_operand:SI 0 "register_operand" "") + (ashiftrt:SI (match_dup 2) + (const_int 16)))] + "!TARGET_SEXT" + " +{ + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); }") + + +;; +;; zero_extend<m><n>2 +;; + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] + "" + "@ + l.andi \t%0,%1,0xff\t # zero_extendqisi2 + l.lbz \t%0,%1\t # zero_extendqisi2" + [(set_attr "type" "logic,load") + (set_attr "length" "1,1")]) + + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] + "" + "@ + l.andi \t%0,%1,0xffff\t # zero_extendqisi2 + l.lhz \t%0,%1\t # zero_extendqisi2" + [(set_attr "type" "logic,load") + (set_attr "length" "1,1")]) + +;; +;; Shift/rotate operations +;; + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (ashift:SI (match_operand:SI 1 "register_operand" "r,r") + (match_operand:SI 2 "nonmemory_operand" "r,L")))] + "" + "@ + l.sll \t%0,%1,%2 + l.slli \t%0,%1,%2" + [(set_attr "type" "shift,shift") + (set_attr "length" "1,1")]) + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "r,r") + (match_operand:SI 2 "nonmemory_operand" "r,L")))] + "" + "@ + l.sra \t%0,%1,%2 + l.srai \t%0,%1,%2" + [(set_attr "type" "shift,shift") + (set_attr "length" "1,1")]) + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r") + (match_operand:SI 2 "nonmemory_operand" "r,L")))] + "" + "@ + l.srl \t%0,%1,%2 + l.srli \t%0,%1,%2" + [(set_attr "type" "shift,shift") + (set_attr "length" "1,1")]) + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (rotatert:SI (match_operand:SI 1 "register_operand" "r,r") + (match_operand:SI 2 "nonmemory_operand" "r,L")))] + "TARGET_ROR" + "@ + l.ror \t%0,%1,%2 + l.rori \t%0,%1,%2" + [(set_attr "type" "shift,shift") + (set_attr "length" "1,1")]) + +;; +;; Logical bitwise operations +;; + +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (and:SI (match_operand:SI 1 "register_operand" "%r,r") + (match_operand:SI 2 "nonmemory_operand" "r,K")))] + "" + "@ + l.and \t%0,%1,%2 + l.andi \t%0,%1,%2" + [(set_attr "type" "logic,logic") + (set_attr "length" "1,1")]) + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (ior:SI (match_operand:SI 1 "register_operand" "%r,r") + (match_operand:SI 2 "nonmemory_operand" "r,K")))] + "" + "@ + l.or \t%0,%1,%2 + l.ori \t%0,%1,%2" + [(set_attr "type" "logic,logic") + (set_attr "length" "1,1")]) + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (xor:SI (match_operand:SI 1 "register_operand" "%r,r") + (match_operand:SI 2 "nonmemory_operand" "r,I")))] + "" + "@ + l.xor \t%0,%1,%2 + l.xori \t%0,%1,%2" + [(set_attr "type" "logic,logic") + (set_attr "length" "1,1")]) + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "register_operand" "=r") + (not:QI (match_operand:QI 1 "register_operand" "r")))] + "" + "l.xori \t%0,%1,0x00ff" + [(set_attr "type" "logic") + (set_attr "length" "1")]) + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (not:SI (match_operand:SI 1 "register_operand" "r")))] + "" + "l.xori \t%0,%1,0xffff" + [(set_attr "type" "logic") + (set_attr "length" "1")]) + +;; +;; Arithmetic operations +;; + +(define_insn "negsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (match_operand:SI 1 "register_operand" "r")))] + "" + "l.sub \t%0,r0,%1" + [(set_attr "type" "add") + (set_attr "length" "1")]) + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (plus:SI (match_operand:SI 1 "register_operand" "%r,r") + (match_operand:SI 2 "nonmemory_operand" "r,I")))] + "" + "@ + l.add \t%0,%1,%2 + l.addi \t%0,%1,%2" + [(set_attr "type" "add,add") + (set_attr "length" "1,1")]) + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (minus:SI (match_operand:SI 1 "register_operand" "r,r") + (match_operand:SI 2 "nonmemory_operand" "r,I")))] + "" + "@ + l.sub \t%0,%1,%2 + l.addi \t%0,%1,%n2" + [(set_attr "type" "add,add")] +) + +;; +;; mul and div +;; + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (mult:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")))] + "TARGET_HARD_MUL" + "l.mul \t%0,%1,%2" + [(set_attr "type" "mul") + (set_attr "length" "1")]) + +(define_insn "divsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (div:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")))] + "TARGET_HARD_DIV" + "l.div \t%0,%1,%2" + [(set_attr "type" "mul") + (set_attr "length" "1")]) + +(define_insn "udivsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (udiv:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")))] + "TARGET_HARD_DIV" + "l.divu \t%0,%1,%2" + [(set_attr "type" "mul") + (set_attr "length" "1")]) + +;; +;; jumps +;; + +;; jump + +(define_expand "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + " +{ + if (!TARGET_ALIGNED_JUMPS) + emit_jump_insn (gen_jump_internal (operands[0])); + else + emit_jump_insn (gen_jump_aligned (operands[0])); + DONE; +}") + +(define_insn "jump_internal" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "!TARGET_ALIGNED_JUMPS" + "l.j \t%l0%(" + [(set_attr "type" "jump") + (set_attr "length" "1")]) + +(define_insn "jump_aligned" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "TARGET_ALIGNED_JUMPS" + ".balignl 0x8,0x15000015,0x4\;l.j \t%l0%(" + [(set_attr "type" "jump") + (set_attr "length" "1")]) + +;; indirect jump + +(define_expand "indirect_jump" + [(set (pc) (match_operand:SI 0 "register_operand" "r"))] + "" + " +{ + if (!TARGET_ALIGNED_JUMPS) + emit_jump_insn (gen_indirect_jump_internal (operands[0])); + else + emit_jump_insn (gen_indirect_jump_aligned (operands[0])); + DONE; + +}") + +(define_insn "indirect_jump_internal" + [(set (pc) (match_operand:SI 0 "register_operand" "r"))] + "!TARGET_ALIGNED_JUMPS" + "l.jr \t%0%(" + [(set_attr "type" "jump") + (set_attr "length" "1")]) + +(define_insn "indirect_jump_aligned" + [(set (pc) (match_operand:SI 0 "register_operand" "r"))] + "TARGET_ALIGNED_JUMPS" + ".balignl 0x8,0x15000015,0x4\;l.jr \t%0%(" + [(set_attr "type" "jump") + (set_attr "length" "1")]) + +;; +;; calls +;; + +;; call + +(define_expand "call" + [(parallel [(call (match_operand:SI 0 "sym_ref_mem_operand" "") + (match_operand 1 "" "i")) + (clobber (reg:SI 9))])] + "" + " +{ + if (!TARGET_ALIGNED_JUMPS) + emit_call_insn (gen_call_internal (operands[0], operands[1])); + else + emit_call_insn (gen_call_aligned (operands[0], operands[1])); + DONE; +}") + +(define_insn "call_internal" +[(parallel [(call (match_operand:SI 0 "sym_ref_mem_operand" "") + (match_operand 1 "" "i")) + (clobber (reg:SI 9))])] + "!TARGET_ALIGNED_JUMPS" + "l.jal \t%S0%(" + [(set_attr "type" "jump") + (set_attr "length" "1")]) + +(define_insn "call_aligned" +[(parallel [(call (match_operand:SI 0 "sym_ref_mem_operand" "") + (match_operand 1 "" "i")) + (clobber (reg:SI 9))])] + "TARGET_ALIGNED_JUMPS" + ".balignl 0x8,0x15000015,0x4\;l.jal \t%S0%(" + [(set_attr "type" "jump") + (set_attr "length" "1")]) + +;; call value + +(define_expand "call_value" + [(parallel [(set (match_operand 0 "register_operand" "=r") + (call (match_operand:SI 1 "sym_ref_mem_operand" "") + (match_operand 2 "" "i"))) + (clobber (reg:SI 9))])] + "" + " +{ + if (!TARGET_ALIGNED_JUMPS) + emit_call_insn (gen_call_value_internal (operands[0], operands[1], operands[2])); + else + emit_call_insn (gen_call_value_aligned (operands[0], operands[1], operands[2])); + DONE; +}") + +(define_insn "call_value_internal" +[(parallel [(set (match_operand 0 "register_operand" "=r") + (call (match_operand:SI 1 "sym_ref_mem_operand" "") + (match_operand 2 "" "i"))) + (clobber (reg:SI 9))])] + "!TARGET_ALIGNED_JUMPS" + "l.jal \t%S1%(" + [(set_attr "type" "jump") + (set_attr "length" "1")]) + +(define_insn "call_value_aligned" +[(parallel [(set (match_operand 0 "register_operand" "=r") + (call (match_operand:SI 1 "sym_ref_mem_operand" "") + (match_operand 2 "" "i"))) + (clobber (reg:SI 9))])] + "TARGET_ALIGNED_JUMPS" + ".balignl 0x8,0x15000015,0x4\;l.jal \t%S1%(" + [(set_attr "type" "jump") + (set_attr "length" "1")]) + +;; indirect call value + +(define_expand "call_value_indirect" + [(parallel [(set (match_operand 0 "register_operand" "=r") + (call (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand 2 "" "i"))) + (clobber (reg:SI 9))])] + "" + " +{ + if (!TARGET_ALIGNED_JUMPS) + emit_call_insn (gen_call_value_indirect_internal (operands[0], operands[1], operands[2])); + else + emit_call_insn (gen_call_value_indirect_aligned (operands[0], operands[1], operands[2])); + DONE; +}") + +(define_insn "call_value_indirect_internal" + [(parallel [(set (match_operand 0 "register_operand" "=r") + (call (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand 2 "" "i"))) + (clobber (reg:SI 9))])] + "!TARGET_ALIGNED_JUMPS" + "l.jalr \t%1%(" + [(set_attr "type" "jump") + (set_attr "length" "1")]) + +(define_insn "call_value_indirect_aligned" + [(parallel [(set (match_operand 0 "register_operand" "=r") + (call (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand 2 "" "i"))) + (clobber (reg:SI 9))])] + "TARGET_ALIGNED_JUMPS" + ".balignl 0x8,0x15000015,0x4\;l.jalr \t%1%(" + [(set_attr "type" "jump") + (set_attr "length" "1")]) + +;; indirect call + +(define_expand "call_indirect" + [(parallel [(call (mem:SI (match_operand:SI 0 "register_operand" "r")) + (match_operand 1 "" "i")) + (clobber (reg:SI 9))])] + "" + " +{ + if (!TARGET_ALIGNED_JUMPS) + emit_call_insn (gen_call_indirect_internal (operands[0], operands[1])); + else + emit_call_insn (gen_call_indirect_aligned (operands[0], operands[1])); + DONE; +}") + +(define_insn "call_indirect_internal" +[(parallel [(call (mem:SI (match_operand:SI 0 "register_operand" "r")) + (match_operand 1 "" "i")) + (clobber (reg:SI 9))])] + "!TARGET_ALIGNED_JUMPS" + "l.jalr \t%0%(" + [(set_attr "type" "jump") + (set_attr "length" "1")]) + +(define_insn "call_indirect_aligned" +[(parallel [(call (mem:SI (match_operand:SI 0 "register_operand" "r")) + (match_operand 1 "" "i")) + (clobber (reg:SI 9))])] + "TARGET_ALIGNED_JUMPS" + ".balignl 0x8,0x15000015,0x4\;l.jalr \t%0%(" + [(set_attr "type" "jump") + (set_attr "length" "1")]) + +;; table jump + +(define_expand "tablejump" + [(set (pc) (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + " +{ + if (!TARGET_ALIGNED_JUMPS) + emit_jump_insn (gen_tablejump_internal (operands[0], operands[1])); + else + emit_jump_insn (gen_tablejump_aligned (operands[0], operands[1])); + DONE; +}") + +(define_insn "tablejump_internal" + [(set (pc) (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "!TARGET_ALIGNED_JUMPS" + "l.jr \t%0%(" + [(set_attr "type" "jump") + (set_attr "length" "1")]) + +(define_insn "tablejump_aligned" + [(set (pc) (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "TARGET_ALIGNED_JUMPS" + ".balignl 0x8,0x15000015,0x4\;l.jr \t%0%(" + [(set_attr "type" "jump") + (set_attr "length" "1")]) + + +;; no-op + +(define_insn "nop" + [(const_int 0)] + "" + "l.nop" + [(set_attr "type" "logic") + (set_attr "length" "1")]) + +;; +;; floating point +;; + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (plus:SF (match_operand:SF 1 "register_operand" "r") + (match_operand:SF 2 "register_operand" "r")))] + "TARGET_HARD_FLOAT" + "lf.add.s\t%0,%1,%2" + [(set_attr "type" "fp") + (set_attr "length" "1")]) + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (plus:DF (match_operand:DF 1 "register_operand" "r") + (match_operand:DF 2 "register_operand" "r")))] + "TARGET_HARD_FLOAT" + "lf.add.d\t%0,%1,%2" + [(set_attr "type" "fp") + (set_attr "length" "1")]) + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (minus:SF (match_operand:SF 1 "register_operand" "r") + (match_operand:SF 2 "register_operand" "r")))] + "TARGET_HARD_FLOAT" + "lf.sub.s\t%0,%1,%2" + [(set_attr "type" "fp") + (set_attr "length" "1")]) + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (minus:DF (match_operand:DF 1 "register_operand" "r") + (match_operand:DF 2 "register_operand" "r")))] + "TARGET_HARD_FLOAT" + "lf.sub.d\t%0,%1,%2" + [(set_attr "type" "fp") + (set_attr "length" "1")]) + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (mult:SF (match_operand:SF 1 "register_operand" "r") + (match_operand:SF 2 "register_operand" "r")))] + "TARGET_HARD_FLOAT" + "lf.mul.s\t%0,%1,%2" + [(set_attr "type" "fp") + (set_attr "length" "1")]) + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (mult:DF (match_operand:DF 1 "register_operand" "r") + (match_operand:DF 2 "register_operand" "r")))] + "TARGET_HARD_FLOAT" + "lf.mul.d\t%0,%1,%2" + [(set_attr "type" "fp") + (set_attr "length" "1")]) + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (div:SF (match_operand:SF 1 "register_operand" "r") + (match_operand:SF 2 "register_operand" "r")))] + "TARGET_HARD_FLOAT" + "lf.div.s\t%0,%1,%2" + [(set_attr "type" "fp") + (set_attr "length" "1")]) + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (div:DF (match_operand:DF 1 "register_operand" "r") + (match_operand:DF 2 "register_operand" "r")))] + "TARGET_HARD_FLOAT" + "lf.div.d\t%0,%1,%2" + [(set_attr "type" "fp") + (set_attr "length" "1")]) + + +;; Local variables: +;; mode:emacs-lisp +;; comment-start: ";; " +;; eval: (set-syntax-table (copy-sequence (syntax-table))) +;; eval: (modify-syntax-entry ?[ "(]") +;; eval: (modify-syntax-entry ?] ")[") +;; eval: (modify-syntax-entry ?{ "(}") +;; eval: (modify-syntax-entry ?} "){") +;; eval: (setq indent-tabs-mode t) +;; End: diff -Nru gcc-3.4.4.orig/gcc/config/or32/or32-modes.def gcc-3.4.4-DONE/gcc/config/or32/or32-modes.def --- gcc-3.4.4.orig/gcc/config/or32/or32-modes.def 1970-01-01 02:00:00.000000000 +0200 +++ gcc-3.4.4-DONE/gcc/config/or32/or32-modes.def 2005-11-29 16:23:09.000000000 +0200 @@ -0,0 +1,39 @@ +/* Definitions of target machine for GNU compiler, for IBM RS/6000. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GCC 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; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. */ + +/* Add any extra modes needed to represent the condition code. + */ + +CC_MODE (CCEQ); +CC_MODE (CCNE); + +CC_MODE (CCLE); +CC_MODE (CCGE); +CC_MODE (CCLT); +CC_MODE (CCGT); + +CC_MODE (CCLEU); +CC_MODE (CCGEU); +CC_MODE (CCLTU); +CC_MODE (CCGTU); + +CC_MODE(CCFP); +CC_MODE(CCUNS); diff -Nru gcc-3.4.4.orig/gcc/config/or32/or32-protos.h gcc-3.4.4-DONE/gcc/config/or32/or32-protos.h --- gcc-3.4.4.orig/gcc/config/or32/or32-protos.h 1970-01-01 02:00:00.000000000 +0200 +++ gcc-3.4.4-DONE/gcc/config/or32/or32-protos.h 2005-11-29 16:23:09.000000000 +0200 @@ -0,0 +1,37 @@ +/* Definitions of target machine for GNU compiler, Argonaut ARC cpu. + Copyright (C) 2000 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. */ + +#ifdef RTX_CODE +#ifdef TREE_CODE +#endif /* TREE_CODE */ + +extern void print_operand PARAMS ((FILE *, rtx, int)); +extern void print_operand_address PARAMS ((FILE *, register rtx)); +extern const char *or1k_output_move_double PARAMS ((rtx *operands)); + +extern rtx or1k_cmp_op[]; + +#endif /* RTX_CODE */ + +#ifdef TREE_CODE + +#endif /* TREE_CODE */ + +extern int print_operand_punct_valid_p PARAMS ((int)); diff -Nru gcc-3.4.4.orig/gcc/config/or32/or32.S gcc-3.4.4-DONE/gcc/config/or32/or32.S --- gcc-3.4.4.orig/gcc/config/or32/or32.S 1970-01-01 02:00:00.000000000 +0200 +++ gcc-3.4.4-DONE/gcc/config/or32/or32.S 2005-11-29 16:23:09.000000000 +0200 @@ -0,0 +1,182 @@ +/* + * Assembly functions for software multiplication and devision. + */ + +#define ENTRY(symbol) \ + .align 4 ;\ + .global symbol ;\ +symbol: + +#ifdef L__mulsi3 +ENTRY(___mulsi3) + l.addi r11,r0,0x0 + l.sfne r3,r11 + l.bnf 3f + l.ori r5,r3,0x0 + l.addi r6,r0,0x0 +1: + l.andi r3,r5,0x1 + l.sfeq r3,r6 + l.bf 2f + l.srli r5,r5,0x1 + l.add r11,r11,r4 +2: + l.sfne r5,r6 + l.bf 1b + l.slli r4,r4,0x1 +3: + l.jr r9 + l.nop 0x0 +#endif + +#ifdef L__udivsi3 +ENTRY(___udivsi3) + l.addi r1,r1,-4 + l.sw 0(r1),r9 + l.addi r11,r0,0 + l.addi r8,r4,0 + l.addi r5,r3,0 + l.sfne r8,r11 + l.bnf 4f + l.addi r7,r0,0 + l.sfgtu r8,r5 + l.bf 5f + l.sfeq r8,r5 + l.bf 6f + l.sfltu r11,r8 + l.bnf 2f + l.addi r13,r0,32 + l.movhi r9,hi(0x80000000) + l.addi r6,r0,-1 +1: + l.and r3,r5,r9 + l.slli r4,r7,1 + l.addi r15,r5,0 + l.srli r3,r3,31 + l.add r13,r13,r6 + l.or r7,r4,r3 + l.sfltu r7,r8 + l.bf 1b + l.slli r5,r5,1 +2: + l.srli r7,r7,1 + l.addi r13,r13,1 + l.addi r9,r0,0 + l.sfltu r9,r13 + l.bnf 4f + l.addi r5,r15,0 + l.movhi r15,hi(0x80000000) + l.addi r17,r0,0 +3: + l.and r3,r5,r15 + l.slli r4,r7,1 + l.srli r3,r3,31 + l.or r7,r4,r3 + l.sub r6,r7,r8 + l.and r3,r6,r15 + l.srli r3,r3,31 + l.addi r4,r0,0 + l.sfne r3,r4 + l.bf 1f + l.slli r3,r11,1 + l.addi r4,r0,1 +1: + l.slli r5,r5,1 + l.sfne r4,r17 + l.bnf 2f + l.or r11,r3,r4 + l.addi r7,r6,0 +2: + l.addi r9,r9,1 + l.sfltu r9,r13 + l.bf 3b + l.nop 0 + l.j 4f + l.nop 0 +6: + l.j 4f + l.addi r11,r0,1 +5: + l.addi r7,r5,0 +4: + l.lwz r9,0(r1) + l.jr r9 + l.addi r1,r1,4 +#endif + + +#ifdef L__divsi3 +ENTRY(___divsi3) + l.addi r1,r1,-8 + l.sw 0(r1),r9 + l.sw 4(r1),r10 + l.addi r5,r3,0 + l.addi r10,r0,0 + l.sflts r5,r0 + l.bnf 1f + l.addi r3,r0,0 + l.addi r10,r0,1 + l.sub r5,r0,r5 +1: + l.sflts r4,r0 + l.bnf 1f + l.nop 0 + l.addi r10,r10,1 + l.sub r4,r0,r4 +1: + l.jal ___udivsi3 + l.addi r3,r5,0 + l.sfeqi r10,1 + l.bnf 1f + l.nop 0 + l.sub r11,r0,r11 +1: + l.lwz r9,0(r1) + l.lwz r10,4(r1) + l.jr r9 + l.addi r1,r1,8 +#endif + + +#ifdef L__umodsi3 +ENTRY(___umodsi3) + l.addi r1,r1,-4 + l.sw 0(r1),r9 + l.jal ___udivsi3 + l.nop 0 + l.addi r11,r7,0 + l.lwz r9,0(r1) + l.jr r9 + l.addi r1,r1,4 +#endif + + +#ifdef L__modsi3 +ENTRY(___modsi3) + l.addi r1,r1,-8 + l.sw 0(r1),r9 + l.sw 4(r1),r10 + l.addi r10,r0,0 + l.sflts r3,r0 + l.bnf 1f + l.nop 0 + l.addi r10,r0,1 + l.sub r3,r0,r3 +1: + l.sflts r4,r0 + l.bnf 1f + l.nop 0 + l.sub r4,r0,r4 +1: + l.jal ___udivsi3 + l.nop 0 + l.sfeqi r10,1 + l.bnf 1f + l.addi r11,r7,0 + l.sub r11,r0,r11 +1: + l.lwz r9,0(r1) + l.lwz r10,4(r1) + l.jr r9 + l.addi r1,r1,8 +#endif diff -Nru gcc-3.4.4.orig/gcc/config/or32/rtems.h gcc-3.4.4-DONE/gcc/config/or32/rtems.h --- gcc-3.4.4.orig/gcc/config/or32/rtems.h 1970-01-01 02:00:00.000000000 +0200 +++ gcc-3.4.4-DONE/gcc/config/or32/rtems.h 2005-11-29 16:23:09.000000000 +0200 @@ -0,0 +1,37 @@ +/* Definitions for rtems targeting an OpenRisc OR32 using COFF + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Joel Sherrill (joel@OARcorp.com). + +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. */ + +/* Specify predefined symbols in preprocessor. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-DOR1K -Dor1k -D__or1k__ -D__OR1K__ \ + -Drtems -D__rtems__ -Asystem(rtems) -Acpu(or1k) -Amachine(or1k)" + +/* Generate calls to memcpy, memcmp and memset. */ +#ifndef TARGET_MEM_FUNCTIONS +#define TARGET_MEM_FUNCTIONS +#endif + +/* We use COFF, so we need SDB format. */ +#define SDB_DEBUGGING_INFO + +/* Get machine-independent configuration parameters for RTEMS. */ +#include <rtems.h> diff -Nru gcc-3.4.4.orig/gcc/config/or32/t-default gcc-3.4.4-DONE/gcc/config/or32/t-default --- gcc-3.4.4.orig/gcc/config/or32/t-default 1970-01-01 02:00:00.000000000 +0200 +++ gcc-3.4.4-DONE/gcc/config/or32/t-default 2005-11-29 16:23:09.000000000 +0200 @@ -0,0 +1,34 @@ +# +# t-default is Makefile fragment to be included when +# building gcc for or32 target +# + +# we don't support -g so don't use it +LIBGCC2_DEBUG_CFLAGS = + +TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer + +LIB1ASMSRC = or32/or32.S +LIB1ASMFUNCS = __mulsi3 __udivsi3 __divsi3 __umodsi3 __modsi3 + +# These are really part of libgcc1, but this will cause them to be +# built correctly, so... [taken from t-sparclite] +LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c + +dp-bit.c: $(srcdir)/config/fp-bit.c + cat $(srcdir)/config/fp-bit.c > dp-bit.c + +fp-bit.c: $(srcdir)/config/fp-bit.c + echo '#define FLOAT' > fp-bit.c + cat $(srcdir)/config/fp-bit.c >> fp-bit.c + +# Build the libraries for both hard and soft floating point + +#MULTILIB_OPTIONS = msoft-float +#MULTILIB_DIRNAMES = soft-float + +#LIBGCC = stmp-multilib +#INSTALL_LIBGCC = install-multilib + +#LIBGCC = +#INSTALL_LIBGCC = diff -Nru gcc-3.4.4.orig/gcc/config.gcc gcc-3.4.4-DONE/gcc/config.gcc --- gcc-3.4.4.orig/gcc/config.gcc 2005-04-25 07:47:59.000000000 +0300 +++ gcc-3.4.4-DONE/gcc/config.gcc 2005-12-13 17:38:36.000000000 +0200 @@ -1681,6 +1681,21 @@ extra_parts="" use_collect2=yes ;; +or32-*-coff*) + tm_file="${tm_file} or32/or32.h" + tmake_file=or32/t-default + ;; +or32-*-elf*) + tm_file="${tm_file} dbxelf.h elfos.h or32/or32.h or32/elf.h" + tmake_file=or32/t-default + if test x$enable_threads = xyes; then + thread_file='rtems' + fi + ;; +or32-*linux*) + tm_file="${tm_file} dbxelf.h elfos.h or32/or32.h or32/elf.h or32/linux-gas.h or32/linux-elf.h" + tmake_file=or32/t-default + ;; pdp11-*-bsd) tm_file="${tm_file} pdp11/2bsd.h" use_fixproto=yes