OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /or1k/trunk/gcc/gcc-3.4.4/gcc
    from Rev 1613 to Rev 1765
    Reverse comparison

Rev 1613 → Rev 1765

/config/or32/or32.h
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_ */
/config/or32/or32-protos.h
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));
/config/or32/rtems.h
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>
/config/or32/or32.md
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:
/config/or32/t-default
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 =
/config/or32/or32.S
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
/config/or32/or32.c
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;
}
/config/or32/or32-modes.def
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);
/config/or32/linux-elf.h
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
/config/or32/default.h
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
/config/or32/elf.h
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 "_"
/config/or32/linux-gas.h
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 !!! */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.