463 lines
13 KiB
C
463 lines
13 KiB
C
/* GCC backend definitions for the Renesas RL78 processor.
|
||
Copyright (C) 2011 Free Software Foundation, Inc.
|
||
Contributed by Red Hat.
|
||
|
||
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 3, 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 COPYING3. If not see
|
||
<http://www.gnu.org/licenses/>. */
|
||
|
||
|
||
#define RL78_MUL_NONE (rl78_mul_type == MUL_NONE)
|
||
#define RL78_MUL_RL78 (rl78_mul_type == MUL_RL78)
|
||
#define RL78_MUL_G13 (rl78_mul_type == MUL_G13)
|
||
|
||
#define TARGET_CPU_CPP_BUILTINS() \
|
||
do \
|
||
{ \
|
||
builtin_define ("__RL78__"); \
|
||
builtin_assert ("cpu=RL78"); \
|
||
if (RL78_MUL_RL78) \
|
||
builtin_define ("__RL78_MUL_RL78__"); \
|
||
if (RL78_MUL_G13) \
|
||
builtin_define ("__RL78_MUL_G13__"); \
|
||
} \
|
||
while (0)
|
||
|
||
#undef STARTFILE_SPEC
|
||
#define STARTFILE_SPEC "%{pg:gcrt0.o%s}%{!pg:crt0.o%s} crtbegin.o%s"
|
||
|
||
#undef ENDFILE_SPEC
|
||
#define ENDFILE_SPEC "crtend.o%s crtn.o%s"
|
||
|
||
#undef LIB_SPEC
|
||
#define LIB_SPEC " \
|
||
--start-group \
|
||
-lc \
|
||
-lsim \
|
||
%{fprofile-arcs|fprofile-generate|coverage:-lgcov} \
|
||
--end-group \
|
||
%{!T*: %{msim:%Trl78-sim.ld}%{!msim:%Trl78.ld}} \
|
||
"
|
||
|
||
|
||
#define BITS_BIG_ENDIAN 0
|
||
#define BYTES_BIG_ENDIAN 0
|
||
#define WORDS_BIG_ENDIAN 0
|
||
|
||
#ifdef IN_LIBGCC2
|
||
/* This is to get correct SI and DI modes in libgcc2.c (32 and 64 bits). */
|
||
#define UNITS_PER_WORD 4
|
||
/* We have a problem with libgcc2. It only defines two versions of
|
||
each function, one for "int" and one for "long long". Ie it assumes
|
||
that "sizeof (int) == sizeof (long)". For the RL78 this is not true
|
||
and we need a third set of functions. We explicitly define
|
||
LIBGCC2_UNITS_PER_WORD here so that it is clear that we are expecting
|
||
to get the SI and DI versions from the libgcc2.c sources, and we
|
||
provide our own set of HI functions, which is why this
|
||
definition is surrounded by #ifndef..#endif. */
|
||
#ifndef LIBGCC2_UNITS_PER_WORD
|
||
#define LIBGCC2_UNITS_PER_WORD 4
|
||
#endif
|
||
#else
|
||
/* Actual width of a word, in units (bytes). */
|
||
#define UNITS_PER_WORD 1
|
||
#endif
|
||
|
||
#define SHORT_TYPE_SIZE 16
|
||
#define INT_TYPE_SIZE 16
|
||
#define LONG_TYPE_SIZE 32
|
||
#define LONG_LONG_TYPE_SIZE 64
|
||
|
||
#define FLOAT_TYPE_SIZE 32
|
||
#define DOUBLE_TYPE_SIZE 32 /*64*/
|
||
#define LONG_DOUBLE_TYPE_SIZE 64 /*DOUBLE_TYPE_SIZE*/
|
||
|
||
#define LIBGCC2_HAS_DF_MODE 1
|
||
#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 64
|
||
|
||
#define DEFAULT_SIGNED_CHAR 0
|
||
|
||
#define STRICT_ALIGNMENT 1
|
||
#define FUNCTION_BOUNDARY 8
|
||
#define BIGGEST_ALIGNMENT 16
|
||
#define STACK_BOUNDARY 16
|
||
#define PARM_BOUNDARY 16
|
||
|
||
#define STACK_GROWS_DOWNWARD 1
|
||
#define FRAME_GROWS_DOWNWARD 1
|
||
#define FIRST_PARM_OFFSET(FNDECL) 0
|
||
|
||
#define MAX_REGS_PER_ADDRESS 1
|
||
|
||
#define Pmode HImode
|
||
#define POINTER_SIZE 16
|
||
#undef SIZE_TYPE
|
||
#define SIZE_TYPE "unsigned int"
|
||
#undef PTRDIFF_TYPE
|
||
#define PTRDIFF_TYPE "int"
|
||
#undef WCHAR_TYPE
|
||
#define WCHAR_TYPE "long int"
|
||
#undef WCHAR_TYPE_SIZE
|
||
#define WCHAR_TYPE_SIZE BITS_PER_WORD
|
||
#define POINTERS_EXTEND_UNSIGNED 1
|
||
#define FUNCTION_MODE HImode
|
||
#define CASE_VECTOR_MODE Pmode
|
||
#define WORD_REGISTER_OPERATIONS 0
|
||
#define HAS_LONG_COND_BRANCH 0
|
||
#define HAS_LONG_UNCOND_BRANCH 0
|
||
|
||
#define MOVE_MAX 2
|
||
#define STARTING_FRAME_OFFSET 0
|
||
|
||
#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
|
||
|
||
#define ADDR_SPACE_FAR 1
|
||
|
||
#define HAVE_PRE_DECCREMENT 0
|
||
#define HAVE_POST_INCREMENT 0
|
||
|
||
#define MOVE_RATIO(SPEED) ((SPEED) ? 24 : 16)
|
||
#define SLOW_BYTE_ACCESS 0
|
||
|
||
#define STORE_FLAG_VALUE 1
|
||
#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND
|
||
#define SHORT_IMMEDIATES_SIGN_EXTEND 0
|
||
|
||
|
||
/* The RL78 has four register banks. Normal operation uses RB0 as
|
||
real registers, RB1 and RB2 as "virtual" registers (because we know
|
||
they'll be there, and not used as variables), and RB3 is reserved
|
||
for interrupt handlers. The virtual registers are accessed as
|
||
SADDRs:
|
||
|
||
FFEE0-FFEE7 RB0
|
||
FFEE8-FFEEF RB1
|
||
FFEF0-FFEF7 RB2
|
||
FFEF8-FFEFF RB3
|
||
*/
|
||
#define REGISTER_NAMES \
|
||
{ \
|
||
"x", "a", "c", "b", "e", "d", "l", "h", \
|
||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", \
|
||
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", \
|
||
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", \
|
||
"sp", "ap", "psw", "es", "cs" \
|
||
}
|
||
|
||
#define ADDITIONAL_REGISTER_NAMES \
|
||
{ \
|
||
{ "ax", 0 }, \
|
||
{ "bc", 2 }, \
|
||
{ "de", 4 }, \
|
||
{ "hl", 6 }, \
|
||
{ "rp0", 0 }, \
|
||
{ "rp1", 2 }, \
|
||
{ "rp2", 4 }, \
|
||
{ "rp3", 6 }, \
|
||
{ "r0", 0 }, \
|
||
{ "r1", 1 }, \
|
||
{ "r2", 2 }, \
|
||
{ "r3", 3 }, \
|
||
{ "r4", 4 }, \
|
||
{ "r5", 5 }, \
|
||
{ "r6", 6 }, \
|
||
{ "r7", 7 }, \
|
||
}
|
||
|
||
enum reg_class
|
||
{
|
||
NO_REGS, /* No registers in set. */
|
||
XREG,
|
||
AREG,
|
||
AXREG,
|
||
CREG,
|
||
BREG,
|
||
BCREG,
|
||
EREG,
|
||
DREG,
|
||
DEREG,
|
||
LREG,
|
||
HREG,
|
||
HLREG,
|
||
IDX_REGS,
|
||
QI_REGS,
|
||
SPREG,
|
||
R8W_REGS,
|
||
R10W_REGS,
|
||
INT_REGS,
|
||
V_REGS, /* Virtual registers. */
|
||
GR_REGS, /* Integer registers. */
|
||
PSWREG,
|
||
ALL_REGS, /* All registers. */
|
||
LIM_REG_CLASSES /* Max value + 1. */
|
||
};
|
||
|
||
#define REG_CLASS_NAMES \
|
||
{ \
|
||
"NO_REGS", \
|
||
"XREG", \
|
||
"AREG", \
|
||
"AXREG", \
|
||
"CREG", \
|
||
"BREG", \
|
||
"BCREG", \
|
||
"EREG", \
|
||
"DREG", \
|
||
"DEREG", \
|
||
"LREG", \
|
||
"HREG", \
|
||
"HLREG", \
|
||
"IDX_REGS", \
|
||
"QI_REGS", \
|
||
"SPREG", \
|
||
"R8W_REGS", \
|
||
"R10W_REGS", \
|
||
"INT_REGS", \
|
||
"V_REGS", \
|
||
"GR_REGS", \
|
||
"PSWREG", \
|
||
"ALL_REGS" \
|
||
}
|
||
|
||
#define REG_CLASS_CONTENTS \
|
||
{ \
|
||
{ 0x00000000, 0x00000000 }, /* No registers, */ \
|
||
{ 0x00000001, 0x00000000 }, \
|
||
{ 0x00000002, 0x00000000 }, \
|
||
{ 0x00000003, 0x00000000 }, \
|
||
{ 0x00000004, 0x00000000 }, \
|
||
{ 0x00000008, 0x00000000 }, \
|
||
{ 0x0000000c, 0x00000000 }, \
|
||
{ 0x00000010, 0x00000000 }, \
|
||
{ 0x00000020, 0x00000000 }, \
|
||
{ 0x00000030, 0x00000000 }, \
|
||
{ 0x00000040, 0x00000000 }, \
|
||
{ 0x00000080, 0x00000000 }, \
|
||
{ 0x000000c0, 0x00000000 }, \
|
||
{ 0x0000000c, 0x00000000 }, /* B and C - index regs. */ \
|
||
{ 0x000000ff, 0x00000000 }, /* all real registers. */ \
|
||
{ 0x00000000, 0x00000001 }, /* SP */ \
|
||
{ 0x00000300, 0x00000000 }, /* R8 - HImode */ \
|
||
{ 0x00000c00, 0x00000000 }, /* R10 - HImode */ \
|
||
{ 0xff000000, 0x00000000 }, /* INT - HImode */ \
|
||
{ 0x007fff00, 0x00000000 }, /* Virtual registers. */ \
|
||
{ 0xff7fffff, 0x00000002 }, /* General registers. */ \
|
||
{ 0x04000000, 0x00000004 }, /* PSW. */ \
|
||
{ 0xff7fffff, 0x0000001f } /* All registers. */ \
|
||
}
|
||
|
||
#define SMALL_REGISTER_CLASSES 1
|
||
#define N_REG_CLASSES (int) LIM_REG_CLASSES
|
||
#define CLASS_MAX_NREGS(CLASS, MODE) ((GET_MODE_SIZE (MODE) \
|
||
+ UNITS_PER_WORD - 1) \
|
||
/ UNITS_PER_WORD)
|
||
|
||
#define GENERAL_REGS GR_REGS
|
||
#define BASE_REG_CLASS V_REGS
|
||
#define INDEX_REG_CLASS V_REGS
|
||
|
||
#define FIRST_PSEUDO_REGISTER 37
|
||
|
||
#define REGNO_REG_CLASS(REGNO) ((REGNO) < FIRST_PSEUDO_REGISTER \
|
||
? GR_REGS : NO_REGS)
|
||
|
||
#define FRAME_POINTER_REGNUM 22
|
||
#define STACK_POINTER_REGNUM 32
|
||
#define ARG_POINTER_REGNUM 33
|
||
#define CC_REGNUM 34
|
||
#define FUNC_RETURN_REGNUM 8
|
||
#define STATIC_CHAIN_REGNUM 14
|
||
|
||
/* Trampolines are implemented with a separate data stack. The memory
|
||
on stack only holds the function pointer for the chosen stub.
|
||
*/
|
||
|
||
#define TRAMPOLINE_SIZE 4
|
||
#define TRAMPOLINE_ALIGNMENT 16
|
||
|
||
#define ELIMINABLE_REGS \
|
||
{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM }, \
|
||
{ ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM }, \
|
||
{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM }}
|
||
|
||
#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
|
||
(OFFSET) = rl78_initial_elimination_offset ((FROM), (TO))
|
||
|
||
|
||
#define FUNCTION_ARG_REGNO_P(N) 0
|
||
#define FUNCTION_VALUE_REGNO_P(N) ((N) == 8)
|
||
#define DEFAULT_PCC_STRUCT_RETURN 0
|
||
|
||
#define FIXED_REGISTERS \
|
||
{ \
|
||
1,1,1,1, 1,1,1,1, \
|
||
0,0,0,0, 0,0,0,0, \
|
||
0,0,0,0, 0,0,1,1, \
|
||
1,1,1,1, 1,1,1,1, \
|
||
0, 1, 0, 1, 1 \
|
||
}
|
||
|
||
#define CALL_USED_REGISTERS \
|
||
{ \
|
||
1,1,1,1, 1,1,1,1, \
|
||
1,1,1,1, 1,1,1,1, \
|
||
0,0,0,0, 0,0,1,1, \
|
||
1,1,1,1, 1,1,1,1, \
|
||
0, 1, 1, 1, 1 \
|
||
}
|
||
|
||
#define LIBCALL_VALUE(MODE) \
|
||
gen_rtx_REG ((MODE), \
|
||
FUNC_RETURN_REGNUM)
|
||
|
||
/* Order of allocation of registers. */
|
||
|
||
#define REG_ALLOC_ORDER \
|
||
{ 8, 9, 10, 11, 12, 13, 14, 15, \
|
||
16, 17, 18, 19, 20, 21, 22, 23, \
|
||
0, 1, 6, 7, 2, 3, 4, 5, \
|
||
24, 25, 26, 27, 28, 29, 30, 31, \
|
||
32, 33, 34 \
|
||
}
|
||
|
||
#define REGNO_IN_RANGE(REGNO, MIN, MAX) \
|
||
(IN_RANGE ((REGNO), (MIN), (MAX)) \
|
||
|| (reg_renumber != NULL \
|
||
&& reg_renumber[(REGNO)] >= (MIN) \
|
||
&& reg_renumber[(REGNO)] <= (MAX)))
|
||
|
||
#ifdef REG_OK_STRICT
|
||
#define REGNO_OK_FOR_BASE_P(regno) REGNO_IN_RANGE (regno, 16, 23)
|
||
#else
|
||
#define REGNO_OK_FOR_BASE_P(regno) 1
|
||
#endif
|
||
|
||
#define REGNO_OK_FOR_INDEX_P(regno) REGNO_OK_FOR_BASE_P (regno)
|
||
|
||
#define REGNO_MODE_CODE_OK_FOR_BASE_P(regno, mode, address_space, outer_code, index_code) \
|
||
rl78_regno_mode_code_ok_for_base_p (regno, mode, address_space, outer_code, index_code)
|
||
|
||
#define MODE_CODE_BASE_REG_CLASS(mode, address_space, outer_code, index_code) \
|
||
rl78_mode_code_base_reg_class (mode, address_space, outer_code, index_code)
|
||
|
||
#define RETURN_ADDR_RTX(COUNT, FRAMEADDR) \
|
||
((COUNT) == 0 \
|
||
? gen_rtx_MEM (Pmode, gen_rtx_PLUS (HImode, arg_pointer_rtx, GEN_INT (-4))) \
|
||
: NULL_RTX)
|
||
|
||
#define INCOMING_RETURN_ADDR_RTX gen_rtx_MEM (Pmode, stack_pointer_rtx)
|
||
|
||
#define ACCUMULATE_OUTGOING_ARGS 1
|
||
|
||
typedef unsigned int CUMULATIVE_ARGS;
|
||
|
||
#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \
|
||
(CUM) = 0
|
||
|
||
|
||
/* FIXME */
|
||
#define NO_PROFILE_COUNTERS 1
|
||
#define PROFILE_BEFORE_PROLOGUE 1
|
||
|
||
#define FUNCTION_PROFILER(FILE, LABELNO) \
|
||
fprintf (FILE, "\tbsr\t__mcount\n");
|
||
|
||
|
||
#define HARD_REGNO_NREGS(REGNO, MODE) \
|
||
rl78_hard_regno_nregs (REGNO, MODE)
|
||
|
||
#define HARD_REGNO_MODE_OK(REGNO, MODE) \
|
||
rl78_hard_regno_mode_ok (REGNO, MODE)
|
||
|
||
#define MODES_TIEABLE_P(MODE1, MODE2) \
|
||
( ( GET_MODE_CLASS (MODE1) == MODE_FLOAT \
|
||
|| GET_MODE_CLASS (MODE1) == MODE_COMPLEX_FLOAT) \
|
||
== ( GET_MODE_CLASS (MODE2) == MODE_FLOAT \
|
||
|| GET_MODE_CLASS (MODE2) == MODE_COMPLEX_FLOAT))
|
||
|
||
|
||
#define TEXT_SECTION_ASM_OP ".text"
|
||
#define DATA_SECTION_ASM_OP ".data"
|
||
#define BSS_SECTION_ASM_OP ".bss"
|
||
#define CTORS_SECTION_ASM_OP ".section \".ctors\",\"a\""
|
||
#define DTORS_SECTION_ASM_OP ".section \".dtors\",\"a\""
|
||
|
||
#define ASM_COMMENT_START " ;"
|
||
#define ASM_APP_ON ""
|
||
#define ASM_APP_OFF ""
|
||
#define LOCAL_LABEL_PREFIX ".L"
|
||
#undef USER_LABEL_PREFIX
|
||
#define USER_LABEL_PREFIX "_"
|
||
|
||
#define GLOBAL_ASM_OP "\t.global\t"
|
||
|
||
#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
|
||
fprintf (FILE, "\t.long .L%d\n", VALUE)
|
||
|
||
/* This is how to output an element of a case-vector that is relative.
|
||
Note: The local label referenced by the "3b" below is emitted by
|
||
the tablejump insn. */
|
||
|
||
#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
|
||
fprintf (FILE, "\t.long .L%d - 1b\n", VALUE)
|
||
|
||
|
||
#define ASM_OUTPUT_ALIGN(STREAM, LOG) \
|
||
do \
|
||
{ \
|
||
if ((LOG) == 0) \
|
||
break; \
|
||
fprintf (STREAM, "\t.balign %d\n", 1 << (LOG)); \
|
||
} \
|
||
while (0)
|
||
|
||
/* For PIC put jump tables into the text section so that the offsets that
|
||
they contain are always computed between two same-section symbols. */
|
||
#define JUMP_TABLES_IN_TEXT_SECTION (flag_pic)
|
||
|
||
/* This is a version of REG_P that also returns TRUE for SUBREGs. */
|
||
#define RL78_REG_P(rtl) (REG_P (rtl) || GET_CODE (rtl) == SUBREG)
|
||
|
||
/* Like REG_P except that this macro is true for SET expressions. */
|
||
#define SET_P(rtl) (GET_CODE (rtl) == SET)
|
||
|
||
#undef PREFERRED_DEBUGGING_TYPE
|
||
#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
|
||
|
||
#undef DWARF2_ADDR_SIZE
|
||
#define DWARF2_ADDR_SIZE 4
|
||
|
||
#define DWARF2_ASM_LINE_DEBUG_INFO 1
|
||
|
||
#define EXIT_IGNORE_STACK 0
|
||
#define INCOMING_FRAME_SP_OFFSET 4
|
||
|
||
|
||
#define BRANCH_COST(SPEED,PREDICT) 1
|
||
#define REGISTER_MOVE_COST(MODE,FROM,TO) 2
|
||
|
||
#define EH_RETURN_DATA_REGNO(N) (N < 2 ? (8+(N)*2) : INVALID_REGNUM)
|
||
#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (HImode, 20)
|
||
|
||
#define ASM_PREFERRED_EH_DATA_FORMAT(CODE,GLOBAL) DW_EH_PE_udata4
|
||
|
||
/* NOTE: defined but zero means dwarf2 debugging, but sjlj EH. */
|
||
#define DWARF2_UNWIND_INFO 0
|
||
/*#define DONT_USE_BUILTIN_SETJMP 1*/
|
||
#undef DONT_USE_BUILTIN_SETJMP
|
||
#define JMP_BUF_SIZE (8*3+8)
|
||
|
||
#define REGISTER_TARGET_PRAGMAS() rl78_register_pragmas()
|