FT32 target added. Approved by Jeff Law [law@redhat.com]

From-SVN: r223261
This commit is contained in:
James Bowman 2015-05-16 23:49:08 +00:00 committed by James Bowman
parent 9261aa4364
commit fef939d6a9
26 changed files with 4257 additions and 1 deletions

View File

@ -1,3 +1,14 @@
2015-05-16 James Bowman <james.bowman@ftdichip.com>
* configure.ac: FT32 target added.
* libgcc/config.host: FT32 target added.
* gcc/config/ft32/: FT32 target added.
* libgcc/config/ft32/: FT32 target added.
* gcc/doc/install.texi, invoke.texi, md.texi: FT32 details added.
* gcc/doc/contrib.texi: self added.
* contrib/config-list.mk: FT32 target added.
* configure: Regenerated.
2015-05-16 Iain Buclaw <ibuclaw@gdcproject.org>
* MAINTAINERS (Write After Approval): Add myself.

3
configure vendored
View File

@ -3363,6 +3363,9 @@ if test "${ENABLE_LIBSTDCXX}" = "default" ; then
avr-*-*)
noconfigdirs="$noconfigdirs target-libstdc++-v3"
;;
ft32-*-*)
noconfigdirs="$noconfigdirs target-libstdc++-v3"
;;
esac
fi

View File

@ -710,6 +710,9 @@ if test "${ENABLE_LIBSTDCXX}" = "default" ; then
avr-*-*)
noconfigdirs="$noconfigdirs target-libstdc++-v3"
;;
ft32-*-*)
noconfigdirs="$noconfigdirs target-libstdc++-v3"
;;
esac
fi

View File

@ -22,7 +22,7 @@ LIST = aarch64-elf aarch64-linux-gnu \
bfin-elf bfin-uclinux bfin-linux-uclibc bfin-rtems bfin-openbsd \
c6x-elf c6x-uclinux cr16-elf cris-elf cris-linux crisv32-elf crisv32-linux \
epiphany-elf epiphany-elfOPT-with-stack-offset=16 fido-elf \
fr30-elf frv-elf frv-linux h8300-elf h8300-rtems hppa-linux-gnu \
fr30-elf frv-elf frv-linux ft32-elf h8300-elf h8300-rtems hppa-linux-gnu \
hppa-linux-gnuOPT-enable-sjlj-exceptions=yes hppa64-linux-gnu \
hppa2.0-hpux10.1 hppa64-hpux11.3 \
hppa64-hpux11.0OPT-enable-sjlj-exceptions=yes hppa2.0-hpux11.9 \

View File

@ -340,6 +340,9 @@ crisv32-*)
frv*) cpu_type=frv
extra_options="${extra_options} g.opt"
;;
ft32*) cpu_type=ft32
target_has_targetm_common=no
;;
moxie*) cpu_type=moxie
target_has_targetm_common=no
;;
@ -1194,6 +1197,12 @@ frv-*-*linux*)
gnu-user.h linux.h glibc-stdint.h frv/linux.h"
tmake_file="${tmake_file} frv/t-frv frv/t-linux"
;;
ft32-*-elf)
gas=yes
gnu_ld=yes
tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}"
tmake_file="${tmake_file} ft32/t-ft32"
;;
moxie-*-elf)
gas=yes
gnu_ld=yes

View File

@ -0,0 +1,113 @@
;; Constraint definitions for FT32
;; Copyright (C) 2015 Free Software Foundation, Inc.
;; Contributed by FTDI <support@ftdi.com>
;; 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/>.
;; -------------------------------------------------------------------------
;; Constraints
;; -------------------------------------------------------------------------
(define_memory_constraint "A"
"An absolute address."
(and (match_code "mem")
(match_test "(!ft32_is_mem_pm(op))")
(ior (match_test "GET_CODE (XEXP (op, 0)) == SYMBOL_REF")
(match_test "GET_CODE (XEXP (op, 0)) == LABEL_REF")
(match_test "GET_CODE (XEXP (op, 0)) == CONST_INT")
(and (match_test "(GET_CODE (XEXP (op, 0)) == PLUS)")
(ior (match_test "GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF")
(match_test "GET_CODE (XEXP (XEXP (op, 0), 0)) == LABEL_REF")
(match_test "GET_CODE (XEXP (XEXP (op, 0), 0)) == CONST_INT"))
(ior (match_test "GET_CODE (XEXP (XEXP (op, 0), 1)) == SYMBOL_REF")
(match_test "GET_CODE (XEXP (XEXP (op, 0), 1)) == LABEL_REF")
(match_test "GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT"))))))
(define_memory_constraint "B"
"An offset address."
(and (match_code "mem")
(match_test "(!ft32_is_mem_pm(op))")
(match_test "(GET_CODE (XEXP (op, 0)) == PLUS)")))
(define_memory_constraint "W"
"A register indirect memory operand."
(and (match_code "mem")
(match_test "!ft32_is_mem_pm(op)
&& REG_P (XEXP (op, 0))
&& REGNO_OK_FOR_BASE_P (REGNO (XEXP (op, 0)))")))
(define_memory_constraint "e"
"An offset address."
(and (match_code "mem")
(match_test "ft32_is_mem_pm(op) && (
(GET_CODE (XEXP (op, 0)) == SYMBOL_REF) ||
(GET_CODE (XEXP (op, 0)) == LABEL_REF) ||
(GET_CODE (XEXP (op, 0)) == CONST_INT) ||
(GET_CODE (XEXP (op, 0)) == CONST))"
)))
(define_memory_constraint "f"
"An offset address."
(and (match_code "mem")
(match_test "ft32_is_mem_pm(op) && (
((GET_CODE (XEXP (op, 0)) == PLUS)) ||
(GET_CODE (XEXP (op, 0)) == REG))"
)))
(define_constraint "O"
"The constant zero or one"
(and (match_code "const_int")
(match_test "((ival == 0) || (ival == 1))")))
(define_constraint "I"
"A 16-bit signed constant (-32768..32767)"
(and (match_code "const_int")
(match_test "ival >= -32768 && ival <= 32767")))
(define_constraint "w"
"A bitfield mask suitable for bext or bins"
(and (match_code "const_int")
(match_test "ft32_as_bitfield(ival) != -1")))
(define_constraint "x"
"An inverted bitfield mask suitable for bext or bins"
(and (match_code "const_int")
(match_test "ft32_as_bitfield(0xffffffff ^ ival) != -1")))
(define_constraint "L"
"A 16-bit unsigned constant, multiple of 4 (-65532..0)"
(and (match_code "const_int")
(match_test "-65532 <= ival && ival <= 0 && (ival & 3) == 0")))
(define_constraint "S"
"A 20-bit signed constant (-524288..524287)"
(ior
(and (match_code "const_int")
(match_test "ival >= -524288 && ival <= 524287"))
(match_test "GET_CODE (op) == LABEL_REF")
(match_test "GET_CODE (op) == SYMBOL_REF")
(match_test "GET_CODE (op) == CONST")))
(define_constraint "b"
"A constant for a bitfield width (1..16)"
(and (match_code "const_int")
(match_test "1 <= ival && ival <= 16")))
(define_constraint "KA"
"A 10-bit signed constant (-512..511)"
(and (match_code "const_int")
(match_test "-512 <= ival && ival <= 511")))

View File

@ -0,0 +1,26 @@
/* Prototypes for ft32.c functions used in the md file & elsewhere.
Copyright (C) 2015 Free Software Foundation, Inc.
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/>. */
extern void ft32_expand_prologue (void);
extern void ft32_expand_epilogue (void);
extern int ft32_initial_elimination_offset (int, int);
extern void ft32_print_operand (FILE *, rtx, int);
extern void ft32_print_operand_address (FILE *, rtx);
extern const char* ft32_load_immediate(rtx, int32_t i);
extern int ft32_as_bitfield(unsigned int x);

921
gcc/config/ft32/ft32.c Normal file
View File

@ -0,0 +1,921 @@
/* Target Code for ft32
Copyright (C) 2015 Free Software Foundation
Contributed by FTDI <support@ftdi.com>
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/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "insn-config.h"
#include "conditions.h"
#include "insn-flags.h"
#include "output.h"
#include "insn-attr.h"
#include "flags.h"
#include "recog.h"
#include "reload.h"
#include "diagnostic-core.h"
#include "obstack.h"
#include "hash-set.h"
#include "machmode.h"
#include "vec.h"
#include "double-int.h"
#include "input.h"
#include "alias.h"
#include "symtab.h"
#include "wide-int.h"
#include "inchash.h"
#include "tree.h"
#include "stor-layout.h"
#include "calls.h"
#include "expr.h"
#include "optabs.h"
#include "except.h"
#include "function.h"
#include "ggc.h"
#include "target.h"
#include "target-def.h"
#include "tm_p.h"
#include "langhooks.h"
#include "dominance.h"
#include "cfg.h"
#include "cfgrtl.h"
#include "cfganal.h"
#include "lcm.h"
#include "cfgbuild.h"
#include "cfgcleanup.h"
#include "predict.h"
#include "basic-block.h"
#include "df.h"
#include "builtins.h"
#include <stdint.h>
#define LOSE_AND_RETURN(msgid, x) \
do \
{ \
ft32_operand_lossage (msgid, x); \
return; \
} while (0)
/* Worker function for TARGET_RETURN_IN_MEMORY. */
static bool
ft32_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
{
const HOST_WIDE_INT size = int_size_in_bytes (type);
return (size == -1 || size > 2 * UNITS_PER_WORD);
}
/* 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.
We always return values in register $r0 for ft32. */
static rtx
ft32_function_value (const_tree valtype,
const_tree fntype_or_decl ATTRIBUTE_UNUSED,
bool outgoing ATTRIBUTE_UNUSED)
{
return gen_rtx_REG (TYPE_MODE (valtype), FT32_R0);
}
/* Define how to find the value returned by a library function.
We always return values in register $r0 for ft32. */
static rtx
ft32_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
{
return gen_rtx_REG (mode, FT32_R0);
}
/* Handle TARGET_FUNCTION_VALUE_REGNO_P.
We always return values in register $r0 for ft32. */
static bool
ft32_function_value_regno_p (const unsigned int regno)
{
return (regno == FT32_R0);
}
/* Emit an error message when we're in an asm, and a fatal error for
"normal" insns. Formatted output isn't easily implemented, since we
use output_operand_lossage to output the actual message and handle the
categorization of the error. */
static void
ft32_operand_lossage (const char *msgid, rtx op)
{
debug_rtx (op);
output_operand_lossage ("%s", msgid);
}
/* The PRINT_OPERAND_ADDRESS worker. */
void
ft32_print_operand_address (FILE * file, rtx x)
{
switch (GET_CODE (x))
{
case REG:
fprintf (file, "%s,0", reg_names[REGNO (x)]);
break;
case PLUS:
switch (GET_CODE (XEXP (x, 1)))
{
case CONST_INT:
fprintf (file, "%s,%ld",
reg_names[REGNO (XEXP (x, 0))], INTVAL (XEXP (x, 1)));
break;
case SYMBOL_REF:
output_addr_const (file, XEXP (x, 1));
fprintf (file, "(%s)", reg_names[REGNO (XEXP (x, 0))]);
break;
case CONST:
{
rtx plus = XEXP (XEXP (x, 1), 0);
if (GET_CODE (XEXP (plus, 0)) == SYMBOL_REF
&& CONST_INT_P (XEXP (plus, 1)))
{
output_addr_const (file, XEXP (plus, 0));
fprintf (file, "+%ld(%s)", INTVAL (XEXP (plus, 1)),
reg_names[REGNO (XEXP (x, 0))]);
}
else
abort ();
}
break;
default:
abort ();
}
break;
default:
output_addr_const (file, x);
break;
}
}
/* The PRINT_OPERAND worker. */
void
ft32_print_operand (FILE * file, rtx x, int code)
{
rtx operand = x;
/* New code entries should just be added to the switch below. If
handling is finished, just return. If handling was just a
modification of the operand, the modified operand should be put in
"operand", and then do a break to let default handling
(zero-modifier) output the operand. */
switch (code)
{
case 0:
/* No code, print as usual. */
break;
case 'h':
if (GET_CODE (operand) != REG)
internal_error ("'h' applied to non-register operand");
fprintf (file, "%s", reg_names[REGNO (operand) + 1]);
return;
case 'm':
fprintf (file, "%d", -INTVAL(x));
return;
case 'd': // a DW spec, from an integer alignment (for BLKmode insns)
{
int i = INTVAL (x);
char dwspec;
switch (i)
{
case 1:
dwspec = 'b';
break;
case 2:
dwspec = 's';
break;
case 4:
dwspec = 'l';
break;
default:
if ((i % 4) != 0)
internal_error ("bad alignment: %d", i);
else
dwspec = 'l';
break;
}
fprintf (file, "%c", dwspec);
return;
}
case 'f':
{
int bf = ft32_as_bitfield (INTVAL (x));
fprintf (file, "512|(%d<<5)|%d", bf >> 5, bf & 31);
return;
}
case 'g':
{
int bf = ft32_as_bitfield (0xffffffff ^ INTVAL (x));
fprintf (file, "(%d<<5)|%d", bf >> 5, bf & 31);
return;
}
case 'b':
{
ft32_print_operand (file, XEXP (x, 0), 0);
return;
}
default:
LOSE_AND_RETURN ("invalid operand modifier letter", x);
}
/* Print an operand as without a modifier letter. */
switch (GET_CODE (operand))
{
case REG:
fprintf (file, "%s", reg_names[REGNO (operand)]);
return;
case MEM:
output_address (XEXP (operand, 0));
return;
default:
/* No need to handle all strange variants, let output_addr_const
do it for us. */
if (CONSTANT_P (operand))
{
output_addr_const (file, operand);
return;
}
LOSE_AND_RETURN ("unexpected operand", x);
}
}
const char *
ft32_load_immediate (rtx dst, int32_t i)
{
char pattern[100];
if ((-524288 <= i) && (i <= 524287))
{
sprintf (pattern, "ldk.l %%0,%d", i);
output_asm_insn (pattern, &dst);
}
else if ((-536870912 <= i) && (i <= 536870911))
{
ft32_load_immediate (dst, i >> 10);
sprintf (pattern, "ldl.l %%0,%%0,%d", i & 1023);
output_asm_insn (pattern, &dst);
}
else
{
int rd; // rotate distance
uint32_t u = i;
for (rd = 1; rd < 32; rd++)
{
u = ((u >> 31) & 1) | (u << 1);
if ((-524288 <= (int32_t) u) && ((int32_t) u <= 524287))
{
ft32_load_immediate (dst, (int32_t) u);
sprintf (pattern, "ror.l %%0,%%0,%d", rd);
output_asm_insn (pattern, &dst);
return "";
}
}
ft32_load_immediate (dst, i >> 10);
sprintf (pattern, "ldl.l %%0,%%0,%d", i & 1023);
output_asm_insn (pattern, &dst);
}
return "";
}
// x is a bit mask, for example:
// 00000000000000000000001111111110
// If x contains a single bit mask, return the bitfield spec.
// in the above case it returns ((9 << 5) | 1)
// Otherwise return -1.
//
#define NBITS(n) ((1U << (n)) - 1U)
int
ft32_as_bitfield (unsigned int x)
{
int lobit, hibit;
if (x == 0)
return -1;
for (lobit = 0; lobit < 32; lobit++)
if (x & (1 << lobit))
break;
for (hibit = 31; hibit >= 0; hibit--)
if (x & (1 << hibit))
break;
int width = 1 + hibit - lobit;
if (width > 16)
return -1;
if (x != (NBITS (width) << lobit))
return -1; // not a clean bitfield
return ((width & 15) << 5) | lobit;
}
/* Per-function machine data. */
struct GTY (()) machine_function
{
/* Number of bytes saved on the stack for callee saved registers. */
int callee_saved_reg_size;
/* Number of bytes saved on the stack for local variables. */
int local_vars_size;
/* The sum of 2 sizes: locals vars and padding byte for saving the
* registers. Used in expand_prologue () and expand_epilogue (). */
int size_for_adjusting_sp;
};
/* Zero initialization is OK for all current fields. */
static struct machine_function *
ft32_init_machine_status (void)
{
return ggc_cleared_alloc < machine_function > ();
}
/* The TARGET_OPTION_OVERRIDE worker.
All this curently does is set init_machine_status. */
static void
ft32_option_override (void)
{
/* Set the per-function-data initializer. */
init_machine_status = ft32_init_machine_status;
}
/* Implement targetm.select_section. */
static section *
ft32_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
{
/* Variables and constants defined in the __ea address space
go into a special section named "._ea". */
if (TREE_TYPE (decl) != error_mark_node
&& TYPE_ADDR_SPACE (TREE_TYPE (decl)) == ADDR_SPACE_PM)
{
/* We might get called with string constants, but get_named_section
doesn't like them as they are not DECLs. Also, we need to set
flags in that case. */
if (!DECL_P (decl))
return get_section ("._pm", SECTION_WRITE | SECTION_DEBUG, NULL);
return get_named_section (decl, "._pm", reloc);
}
return default_elf_select_section (decl, reloc, align);
}
/* Compute the size of the local area and the size to be adjusted by the
* prologue and epilogue. */
static void
ft32_compute_frame (void)
{
/* For aligning the local variables. */
int stack_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
int padding_locals;
int regno;
/* Padding needed for each element of the frame. */
cfun->machine->local_vars_size = get_frame_size ();
/* Align to the stack alignment. */
padding_locals = cfun->machine->local_vars_size % stack_alignment;
if (padding_locals)
padding_locals = stack_alignment - padding_locals;
cfun->machine->local_vars_size += padding_locals;
cfun->machine->callee_saved_reg_size = 0;
/* Save callee-saved registers. */
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (df_regs_ever_live_p (regno) && (!call_used_regs[regno]))
cfun->machine->callee_saved_reg_size += 4;
cfun->machine->size_for_adjusting_sp =
crtl->args.pretend_args_size
+ cfun->machine->local_vars_size
+ (ACCUMULATE_OUTGOING_ARGS ? crtl->outgoing_args_size : 0);
}
// Must use LINK/UNLINK when...
// the frame is bigger than 512 bytes so cannot just "SUB" from SP
// the function actually uses $fp
static int
must_link (void)
{
int bigframe = (cfun->machine->size_for_adjusting_sp >= 512);
return (bigframe || frame_pointer_needed || df_regs_ever_live_p (FT32_FP)
|| df_regs_ever_live_p (FT32_FP));
}
void
ft32_expand_prologue (void)
{
int regno;
rtx insn;
ft32_compute_frame ();
if (!must_link () && (cfun->machine->callee_saved_reg_size == 4))
{
insn =
emit_insn (gen_link
(gen_rtx_REG (Pmode, FT32_R13),
GEN_INT (-cfun->machine->size_for_adjusting_sp)));
RTX_FRAME_RELATED_P (insn) = 1;
return;
}
/* Save callee-saved registers. */
if (optimize_size)
{
for (regno = FIRST_PSEUDO_REGISTER; regno-- > 0;)
{
if (!fixed_regs[regno] && !call_used_regs[regno]
&& df_regs_ever_live_p (regno))
{
rtx preg = gen_rtx_REG (Pmode, regno);
emit_insn (gen_call_prolog (preg));
break;
}
}
}
else
{
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
{
if (!fixed_regs[regno] && df_regs_ever_live_p (regno)
&& !call_used_regs[regno])
{
insn = emit_insn (gen_movsi_push (gen_rtx_REG (Pmode, regno)));
RTX_FRAME_RELATED_P (insn) = 1;
}
}
}
if (65536 <= cfun->machine->size_for_adjusting_sp)
{
error ("stack frame must be smaller than 64K");
return;
}
if (must_link ())
{
insn =
emit_insn (gen_link
(gen_rtx_REG (Pmode, FT32_FP),
GEN_INT (-cfun->machine->size_for_adjusting_sp)));
RTX_FRAME_RELATED_P (insn) = 1;
}
else if (cfun->machine->size_for_adjusting_sp > 0)
{
insn = emit_insn (gen_addsi3 (gen_rtx_REG (SImode, FT32_SP),
gen_rtx_REG (SImode, FT32_SP),
GEN_INT (-(cfun->machine->
size_for_adjusting_sp))));
RTX_FRAME_RELATED_P (insn) = 1;
}
}
void
ft32_expand_epilogue (void)
{
int regno;
if (!must_link ()
&& (cfun->machine->size_for_adjusting_sp == 24)
&& (cfun->machine->callee_saved_reg_size == 0))
{
emit_jump_insn (gen_returner24 ());
return;
}
// Set when the epilog code will also add 24 to $sp
int epilog24 = (!must_link ()
&& (cfun->machine->size_for_adjusting_sp == 24)
&& optimize_size);
if (must_link ())
{
emit_insn (gen_unlink ());
}
else if (!epilog24 && (cfun->machine->size_for_adjusting_sp > 0))
{
emit_insn (gen_addsi3 (gen_rtx_REG (SImode, FT32_SP),
gen_rtx_REG (SImode, FT32_SP),
GEN_INT (cfun->machine->size_for_adjusting_sp)));
}
if (cfun->machine->callee_saved_reg_size != 0)
{
for (regno = FIRST_PSEUDO_REGISTER; regno-- > 0;)
{
if (!fixed_regs[regno] && !call_used_regs[regno]
&& df_regs_ever_live_p (regno))
{
rtx preg = gen_rtx_REG (Pmode, regno);
if (optimize_size)
{
if (epilog24)
emit_insn (gen_jump_epilog24 (preg));
else
emit_insn (gen_jump_epilog (preg));
return;
}
emit_insn (gen_movsi_pop (preg));
}
}
}
emit_jump_insn (gen_returner ());
}
#undef TARGET_FRAME_POINTER_REQUIRED
#define TARGET_FRAME_POINTER_REQUIRED ft32_frame_pointer_required
static bool
ft32_frame_pointer_required (void)
{
return cfun->calls_alloca;
}
#undef TARGET_CAN_ELIMINATE
#define TARGET_CAN_ELIMINATE ft32_can_eliminate
/* Return true if register FROM can be eliminated via register TO. */
static bool
ft32_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
{
return 1;
return (to == FRAME_POINTER_REGNUM) || !ft32_frame_pointer_required ();
}
/* Implements the macro INITIAL_ELIMINATION_OFFSET, return the OFFSET. */
int
ft32_initial_elimination_offset (int from, int to)
{
ft32_compute_frame ();
if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
{
return cfun->machine->callee_saved_reg_size + 2 * UNITS_PER_WORD;
}
if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
{
int arg_offset;
arg_offset = must_link ()? 2 : 1;
return ((cfun->machine->callee_saved_reg_size
+ arg_offset * UNITS_PER_WORD)
+ cfun->machine->size_for_adjusting_sp);
}
if ((from == FRAME_POINTER_REGNUM) && (to == STACK_POINTER_REGNUM))
{
return cfun->machine->size_for_adjusting_sp;
}
gcc_unreachable ();
}
/* Worker function for TARGET_SETUP_INCOMING_VARARGS. */
static void
ft32_setup_incoming_varargs (cumulative_args_t cum_v,
enum machine_mode mode ATTRIBUTE_UNUSED,
tree type ATTRIBUTE_UNUSED,
int *pretend_size, int no_rtl)
{
CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
int regno;
int regs = 8 - *cum;
*pretend_size = regs < 0 ? 0 : GET_MODE_SIZE (SImode) * regs;
if (no_rtl)
return;
for (regno = *cum; regno < 8; regno++)
{
rtx reg = gen_rtx_REG (SImode, regno);
rtx slot = gen_rtx_PLUS (Pmode,
gen_rtx_REG (SImode, ARG_POINTER_REGNUM),
GEN_INT (UNITS_PER_WORD * (regno - FT32_R0)));
emit_move_insn (gen_rtx_MEM (SImode, slot), reg);
}
}
/* Return the fixed registers used for condition codes. */
static bool
ft32_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
{
*p1 = CC_REG;
*p2 = INVALID_REGNUM;
return true;
}
/* Return the next register to be used to hold a function argument or
NULL_RTX if there's no more space. */
static rtx
ft32_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
const_tree type ATTRIBUTE_UNUSED,
bool named ATTRIBUTE_UNUSED)
{
CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
if (*cum < 8)
return gen_rtx_REG (mode, *cum);
else
return NULL_RTX;
}
#define FT32_FUNCTION_ARG_SIZE(MODE, TYPE) \
((MODE) != BLKmode ? GET_MODE_SIZE (MODE) \
: (unsigned) int_size_in_bytes (TYPE))
static void
ft32_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode,
const_tree type, bool named ATTRIBUTE_UNUSED)
{
CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
*cum = (*cum < FT32_R6
? *cum + ((3 + FT32_FUNCTION_ARG_SIZE (mode, type)) / 4) : *cum);
}
/* Return non-zero if the function argument described by TYPE is to be
passed by reference. */
static bool
ft32_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
enum machine_mode mode, const_tree type,
bool named ATTRIBUTE_UNUSED)
{
unsigned HOST_WIDE_INT size;
if (type)
{
if (AGGREGATE_TYPE_P (type))
return true;
size = int_size_in_bytes (type);
}
else
size = GET_MODE_SIZE (mode);
return size > 4 * 6;
}
/* Some function arguments will only partially fit in the registers
that hold arguments. Given a new arg, return the number of bytes
that fit in argument passing registers. */
static int
ft32_arg_partial_bytes (cumulative_args_t cum_v,
enum machine_mode mode, tree type, bool named)
{
CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
int bytes_left, size;
if (*cum >= 8)
return 0;
if (ft32_pass_by_reference (cum_v, mode, type, named))
size = 4;
else if (type)
{
if (AGGREGATE_TYPE_P (type))
return 0;
size = int_size_in_bytes (type);
}
else
size = GET_MODE_SIZE (mode);
bytes_left = (4 * 6) - ((*cum - 2) * 4);
if (size > bytes_left)
return bytes_left;
else
return 0;
}
/* Used by constraints.md to distinguish between GENERIC and PM
memory addresses. */
int
ft32_is_mem_pm (rtx o)
{
if (GET_CODE (o) != MEM)
return false;
if (MEM_EXPR (o))
return TYPE_ADDR_SPACE (TREE_TYPE (MEM_EXPR (o))) == ADDR_SPACE_PM;
else
return MEM_ADDR_SPACE (o) == ADDR_SPACE_PM;
}
/* The Global `targetm' Variable. */
/* Initialize the GCC target structure. */
#undef TARGET_PROMOTE_PROTOTYPES
#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
#undef TARGET_RETURN_IN_MEMORY
#define TARGET_RETURN_IN_MEMORY ft32_return_in_memory
#undef TARGET_MUST_PASS_IN_STACK
#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
#undef TARGET_PASS_BY_REFERENCE
#define TARGET_PASS_BY_REFERENCE ft32_pass_by_reference
#undef TARGET_ARG_PARTIAL_BYTES
#define TARGET_ARG_PARTIAL_BYTES ft32_arg_partial_bytes
#undef TARGET_FUNCTION_ARG
#define TARGET_FUNCTION_ARG ft32_function_arg
#undef TARGET_FUNCTION_ARG_ADVANCE
#define TARGET_FUNCTION_ARG_ADVANCE ft32_function_arg_advance
#undef TARGET_SETUP_INCOMING_VARARGS
#define TARGET_SETUP_INCOMING_VARARGS ft32_setup_incoming_varargs
#undef TARGET_FIXED_CONDITION_CODE_REGS
#define TARGET_FIXED_CONDITION_CODE_REGS ft32_fixed_condition_code_regs
/* Define this to return an RTX representing the place where a
function returns or receives a value of data type RET_TYPE, a tree
node node representing a data type. */
#undef TARGET_FUNCTION_VALUE
#define TARGET_FUNCTION_VALUE ft32_function_value
#undef TARGET_LIBCALL_VALUE
#define TARGET_LIBCALL_VALUE ft32_libcall_value
#undef TARGET_FUNCTION_VALUE_REGNO_P
#define TARGET_FUNCTION_VALUE_REGNO_P ft32_function_value_regno_p
#undef TARGET_OPTION_OVERRIDE
#define TARGET_OPTION_OVERRIDE ft32_option_override
#undef TARGET_ASM_SELECT_SECTION
#define TARGET_ASM_SELECT_SECTION ft32_select_section
#undef TARGET_VALID_POINTER_MODE
#define TARGET_VALID_POINTER_MODE ft32_valid_pointer_mode
static bool
ft32_valid_pointer_mode (enum machine_mode mode)
{
if (mode == SImode)
return 1;
return 0;
}
#undef TARGET_ADDR_SPACE_POINTER_MODE
#define TARGET_ADDR_SPACE_POINTER_MODE ft32_addr_space_pointer_mode
static enum machine_mode
ft32_addr_space_pointer_mode (addr_space_t addrspace ATTRIBUTE_UNUSED)
{
return Pmode;
}
#undef TARGET_ADDR_SPACE_ADDRESS_MODE
#define TARGET_ADDR_SPACE_ADDRESS_MODE ft32_addr_space_address_mode
static enum machine_mode
ft32_addr_space_address_mode (addr_space_t addrspace ATTRIBUTE_UNUSED)
{
return Pmode;
}
#undef TARGET_ADDR_SPACE_SUBSET_P
#define TARGET_ADDR_SPACE_SUBSET_P ft32_addr_space_subset_p
static bool
ft32_addr_space_subset_p (addr_space_t subset ATTRIBUTE_UNUSED,
addr_space_t superset ATTRIBUTE_UNUSED)
{
return false;
}
#undef TARGET_CASE_VALUES_THRESHOLD
#define TARGET_CASE_VALUES_THRESHOLD ft32_target_case_values_threshold
static unsigned int
ft32_target_case_values_threshold (void)
{
return 4;
}
#undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P
#define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P \
ft32_addr_space_legitimate_address_p
// Enabling LRA gives the infamous
// internal compiler error: Max. number of generated reload insns per insn is achieved (90)
// errors e.g. when compiling sieve.c
static bool
ft32_lra_p (void)
{
return ft32_lra_flag;
}
#undef TARGET_LRA_P
#define TARGET_LRA_P ft32_lra_p
static bool
reg_ok_for_base_p (rtx r, bool strict)
{
int NUM = REGNO (r);
if (strict)
return (HARD_REGNO_OK_FOR_BASE_P (NUM)
|| HARD_REGNO_OK_FOR_BASE_P (reg_renumber[(NUM)]));
else
return ((NUM) >= FIRST_PSEUDO_REGISTER || HARD_REGNO_OK_FOR_BASE_P (NUM));
}
static bool
ft32_addr_space_legitimate_address_p (enum machine_mode mode, rtx x,
bool strict,
addr_space_t as ATTRIBUTE_UNUSED)
{
if (mode != BLKmode)
{
if (GET_CODE (x) == PLUS)
{
rtx op1, op2;
op1 = XEXP (x, 0);
op2 = XEXP (x, 1);
if (GET_CODE (op1) == REG
&& CONST_INT_P (op2)
&& INTVAL (op2) >= -128
&& INTVAL (op2) < 128 && reg_ok_for_base_p (op1, strict))
goto yes;
if (GET_CODE (op1) == SYMBOL_REF && CONST_INT_P (op2))
goto yes;
}
if (REG_P (x) && reg_ok_for_base_p (x, strict))
goto yes;
if (GET_CODE (x) == SYMBOL_REF
|| GET_CODE (x) == LABEL_REF || CONST_INT_P (x))
goto yes;
}
else
{
if (REG_P (x) && reg_ok_for_base_p (x, strict))
goto yes;
}
return 0;
yes:
return 1;
}
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-ft32.h"

518
gcc/config/ft32/ft32.h Normal file
View File

@ -0,0 +1,518 @@
/* Target Definitions for ft32.
Copyright (C) 2015 Free Software Foundation, Inc.
Contributed by FTDI <support@ftdi.com>
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/>. */
#ifndef GCC_FT32_H
#define GCC_FT32_H
#undef STARTFILE_SPEC
#define STARTFILE_SPEC "crt0%O%s %{msim:crti.o%s} %{!msim:crti-hw.o%s} crtbegin.o%s"
/* Provide an ENDFILE_SPEC appropriate for svr4. Here we tack on our own
magical crtend.o file (see crtstuff.c) which provides part of the
support for getting C++ file-scope static object constructed before
entering `main', followed by the normal svr3/svr4 "finalizer" file,
which is either `gcrtn.o' or `crtn.o'. */
#undef ENDFILE_SPEC
#define ENDFILE_SPEC "crtend.o%s crtn.o%s"
/* Provide a LIB_SPEC appropriate for svr4. Here we tack on the default
standard C library (unless we are building a shared library) and
the simulator BSP code. */
#undef LIB_SPEC
#define LIB_SPEC "%{!shared:%{!symbolic:-lc}} \
%{msim:-Tsim.ld}"
#undef LINK_SPEC
#define LINK_SPEC "%{h*} %{v:-V} \
%{static:-Bstatic} %{shared:-shared} %{symbolic:-Bsymbolic}"
/* Layout of Source Language Data Types */
#define INT_TYPE_SIZE 32
#define SHORT_TYPE_SIZE 16
#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
#define DEFAULT_SIGNED_CHAR 1
#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 REGISTER_NAMES { \
"$fp", "$sp", "$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", "$cc", \
"?fp", "?ap", "$pc", "?cc" }
#define FT32_FP 0
#define FT32_SP 1
#define FT32_R0 2
#define FT32_R1 3
#define FT32_R2 4
#define FT32_R3 5
#define FT32_R4 6
#define FT32_R5 7
#define FT32_R6 8
#define FT32_R7 9
#define FT32_R8 10
#define FT32_R9 11
#define FT32_R10 12
#define FT32_R11 13
#define FT32_R12 14
#define FT32_R13 15
#define FT32_R14 16
#define FT32_R15 17
#define FT32_R16 18
#define FT32_R17 19
#define FT32_R18 20
#define FT32_R19 21
#define FT32_R20 22
#define FT32_R21 23
#define FT32_R22 24
#define FT32_R23 25
#define FT32_R24 26
#define FT32_R25 27
#define FT32_R26 28
#define FT32_R27 29
#define FT32_R28 30
#define FT32_R29 31
#define FT32_QAP (32 + 1)
#define FT32_PC (32 + 2)
#define FT32_CC (32 + 3)
#define FIRST_PSEUDO_REGISTER (32 + 4)
enum reg_class
{
NO_REGS,
GENERAL_REGS,
SPECIAL_REGS,
CC_REGS,
ALL_REGS,
LIM_REG_CLASSES
};
#define REG_CLASS_CONTENTS \
{ { 0x00000000, 0x00000000 }, /* Empty */ \
{ 0xFFFFFFFF, 0x00000003 }, /* $fp, $sp, $r0 to $r13, ?fp */ \
{ 0x00000000, 0x00000004 }, /* $pc */ \
{ 0x00000000, 0x00000008 }, /* ?cc */ \
{ 0xFFFFFFFF, 0x0000000F } /* All registers */ \
}
#define N_REG_CLASSES LIM_REG_CLASSES
#define REG_CLASS_NAMES {\
"NO_REGS", \
"GENERAL_REGS", \
"SPECIAL_REGS", \
"CC_REGS", \
"ALL_REGS" }
#define FIXED_REGISTERS /* fp sp r0 r1 */ { 1, 1, 0, 0, \
/* r2 r3 r4 r5 */ 0, 0, 0, 0, \
/* r6 r7 r8 r9 */ 0, 0, 0, 0, \
/* r10 r11 r12 r13 */ 0, 0, 0, 0, \
/* r14 r15 r16 r17 */ 0, 0, 0, 0, \
/* r18 r19 r20 r21 */ 0, 0, 0, 0, \
/* r22 r23 r24 r25 */ 0, 0, 0, 0, \
/* r26 r27 r28 r29 */ 0, 0, 1, 1, \
/* r30 r31 */ 1, 1, 1, 1 }
#define CALL_USED_REGISTERS \
/* fp sp r0 r1 */ { 1, 1, 1, 1, \
/* r2 r3 r4 r5 */ 1, 1, 1, 1, \
/* r6 r7 r8 r9 */ 1, 1, 1, 1, \
/* r10 r11 r12 r13 */ 1, 1, 1, 0, \
/* r14 r15 r16 r17 */ 0, 0, 0, 0, \
/* r18 r19 r20 r21 */ 0, 0, 0, 0, \
/* r22 r23 r24 r25 */ 0, 0, 0, 0, \
/* r26 r27 r28 r29 */ 0, 0, 1, 1, \
/* r30 r31 */ 1, 1, 1, 1 }
/* We can't copy to or from our CC register. */
#define AVOID_CCMODE_COPIES 1
/* A C expression that is nonzero if it is permissible to store a
value of mode MODE in hard register number REGNO (or in several
registers starting with that one). All gstore registers are
equivalent, so we can set this to 1. */
#define HARD_REGNO_MODE_OK(R,M) 1
/* A C expression whose value is a register class containing hard
register REGNO. */
#define REGNO_REG_CLASS(R) ((R < FT32_PC) ? GENERAL_REGS : \
(R == FT32_CC ? CC_REGS : SPECIAL_REGS))
/* A C expression for the number of consecutive hard registers,
starting at register number REGNO, required to hold a value of mode
MODE. */
#define HARD_REGNO_NREGS(REGNO, MODE) \
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \
/ UNITS_PER_WORD)
/* A C expression that is nonzero if a value of mode MODE1 is
accessible in mode MODE2 without copying. */
#define MODES_TIEABLE_P(MODE1, MODE2) 1
/* The Overall Framework of an Assembler File */
#undef ASM_SPEC
#define ASM_COMMENT_START "#"
#define ASM_APP_ON ""
#define ASM_APP_OFF ""
#define FILE_ASM_OP "\t.file\n"
/* Switch to the text or data segment. */
#define TEXT_SECTION_ASM_OP "\t.text"
#define DATA_SECTION_ASM_OP "\t.data"
/* Assembler Commands for Alignment */
#define ASM_OUTPUT_ALIGN(STREAM,POWER) \
fprintf (STREAM, "\t.p2align\t%d\n", POWER);
/* A C compound statement to output to stdio stream STREAM the
assembler syntax for an instruction operand X. */
#define PRINT_OPERAND(STREAM, X, CODE) ft32_print_operand (STREAM, X, CODE)
#define PRINT_OPERAND_ADDRESS(STREAM ,X) ft32_print_operand_address (STREAM, X)
/* Output and Generation of Labels */
#define GLOBAL_ASM_OP "\t.global\t"
#define JUMP_TABLES_IN_TEXT_SECTION 1
/* This is how to output an element of a case-vector that is absolute. */
#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
fprintf (FILE, "\tjmp\t.L%d\n", VALUE); \
/* Passing Arguments in Registers */
/* A C type for declaring a variable that is used as the first
argument of `FUNCTION_ARG' and other related values. */
#define CUMULATIVE_ARGS unsigned int
/* If defined, the maximum amount of space required for outgoing arguments
will be computed and placed into the variable
`current_function_outgoing_args_size'. No space will be pushed
onto the stack for each call; instead, the function prologue should
increase the stack frame size by this amount. */
#define ACCUMULATE_OUTGOING_ARGS 1
/* A C statement (sans semicolon) for initializing the variable CUM
for the state at the beginning of the argument list.
For ft32, the first arg is passed in register 2 (aka $r0). */
#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,FNDECL,N_NAMED_ARGS) \
(CUM = FT32_R0)
/* How Scalar Function Values Are Returned */
/* STACK AND CALLING */
/* Define this macro if pushing a word onto the stack moves the stack
pointer to a smaller address. */
#define STACK_GROWS_DOWNWARD
#define INITIAL_FRAME_POINTER_OFFSET(DEPTH) (DEPTH) = 0
/* Offset from the frame pointer to the first local variable slot to
be allocated. */
#define STARTING_FRAME_OFFSET 0
/* 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(FNTYPE) 1
/* #define STACK_PARMS_IN_REG_PARM_AREA */
/* Define this if it is the responsibility of the caller to allocate
the area reserved for arguments passed in registers. */
#define REG_PARM_STACK_SPACE(FNDECL) (6 * UNITS_PER_WORD)
/* Offset from the argument pointer register to the first argument's
address. On some machines it may depend on the data type of the
function. */
#define FIRST_PARM_OFFSET(F) 0
/* Define this macro to nonzero value if the addresses of local variable slots
are at negative offsets from the frame pointer. */
#define FRAME_GROWS_DOWNWARD 1
/* 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
/* Define this macro as a C expression that is nonzero for registers that are
used by the epilogue or the return pattern. The stack and frame
pointer registers are already assumed to be used as needed. */
#define EPILOGUE_USES(R) (R == FT32_R5)
/* A C expression whose value is RTL representing the location of the
incoming return address at the beginning of any function, before
the prologue. */
#define INCOMING_RETURN_ADDR_RTX \
gen_frame_mem (Pmode, \
plus_constant (Pmode, stack_pointer_rtx, 333 * UNITS_PER_WORD))
#define RETURN_ADDR_RTX(COUNT, FRAMEADDR) \
((COUNT) == 0 \
? gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, arg_pointer_rtx, GEN_INT (-4))) \
: NULL_RTX)
/* Describe how we implement __builtin_eh_return. */
#define EH_RETURN_DATA_REGNO(N) ((N) < 4 ? (N+2) : INVALID_REGNUM)
/* Store the return handler into the call frame. */
#define EH_RETURN_HANDLER_RTX \
gen_frame_mem (Pmode, \
plus_constant (Pmode, frame_pointer_rtx, UNITS_PER_WORD))
/* Storage Layout */
#define BITS_BIG_ENDIAN 0
#define BYTES_BIG_ENDIAN 0
#define WORDS_BIG_ENDIAN 0
/* Alignment required for a function entry point, in bits. */
#define FUNCTION_BOUNDARY 32
#define BRANCH_COST(speed_p, predictable_p) 2
/* Define this macro as a C expression which is nonzero if accessing
less than a word of memory (i.e. a `char' or a `short') is no
faster than accessing a word of memory. */
#define SLOW_BYTE_ACCESS 1
#define STORE_FLAG_VALUE 1
#define MOVE_RATIO(speed) ((speed) ? 6 : 2)
/* Number of storage units in a word; normally the size of a
general-purpose register, a power of two from 1 or 8. */
#define UNITS_PER_WORD 4
/* Define this macro to the minimum alignment enforced by hardware
for the stack pointer on this machine. The definition is a C
expression for the desired alignment (measured in bits). */
#define STACK_BOUNDARY 32
/* Normal alignment required for function parameters on the stack, in
bits. All stack parameters receive at least this much alignment
regardless of data type. */
#define PARM_BOUNDARY 32
/* Alignment of field after `int : 0' in a structure. */
#define EMPTY_FIELD_BOUNDARY 32
/* 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
/* Align definitions of arrays, unions and structures so that
initializations and copies can be made more efficient. This is not
ABI-changing, so it only affects places where we can see the
definition. Increasing the alignment tends to introduce padding,
so don't do this when optimizing for size/conserving stack space. */
#define FT32_EXPAND_ALIGNMENT(COND, EXP, ALIGN) \
(((COND) && ((ALIGN) < BITS_PER_WORD) \
&& (TREE_CODE (EXP) == ARRAY_TYPE \
|| TREE_CODE (EXP) == UNION_TYPE \
|| TREE_CODE (EXP) == RECORD_TYPE)) ? BITS_PER_WORD : (ALIGN))
/* Make arrays of chars word-aligned for the same reasons. */
#define DATA_ALIGNMENT(TYPE, ALIGN) \
(TREE_CODE (TYPE) == ARRAY_TYPE \
&& TYPE_MODE (TREE_TYPE (TYPE)) == QImode \
&& (ALIGN) < FASTEST_ALIGNMENT ? FASTEST_ALIGNMENT : (ALIGN))
/* Similarly, make sure that objects on the stack are sensibly aligned. */
#define LOCAL_ALIGNMENT(EXP, ALIGN) \
FT32_EXPAND_ALIGNMENT(/*!flag_conserve_stack*/ 1, EXP, ALIGN)
/* Every structures size must be a multiple of 8 bits. */
#define STRUCTURE_SIZE_BOUNDARY 8
/* Look at the fundamental type that is used for a bit-field and use
that to impose alignment on the enclosing structure.
struct s {int a:8}; should have same alignment as "int", not "char". */
#define PCC_BITFIELD_TYPE_MATTERS 1
/* Largest integer machine mode for structures. If undefined, the default
is GET_MODE_SIZE(DImode). */
#define MAX_FIXED_MODE_SIZE 32
/* Make strings word-aligned so strcpy from constants will be faster. */
#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
((TREE_CODE (EXP) == STRING_CST \
&& (ALIGN) < FASTEST_ALIGNMENT) \
? FASTEST_ALIGNMENT : (ALIGN))
/* Set this nonzero if move instructions will actually fail to work
when given unaligned data. */
#define STRICT_ALIGNMENT 1
/* Generating Code for Profiling */
#define FUNCTION_PROFILER(FILE,LABELNO) (abort (), 0)
/* Trampolines for Nested Functions. */
#define TRAMPOLINE_SIZE (2 + 6 + 6 + 2 + 2 + 6)
/* Alignment required for trampolines, in bits. */
#define TRAMPOLINE_ALIGNMENT 32
/* An alias for the machine mode for pointers. */
#define Pmode SImode
#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \
do { \
if (((MODE) == HImode) \
|| ((MODE) == QImode)) \
(MODE) = SImode; \
} while (0)
/* An alias for the machine mode used for memory references to
functions being called, in `call' RTL expressions. */
#define FUNCTION_MODE QImode
#define STATIC_CHAIN_REGNUM FT32_R28
/* The register number of the stack pointer register, which must also
be a fixed register according to `FIXED_REGISTERS'. */
#define STACK_POINTER_REGNUM FT32_SP
/* The register number of the frame pointer register, which is used to
access automatic variables in the stack frame. */
#define FRAME_POINTER_REGNUM FT32_FP
/* The register number of the arg pointer register, which is used to
access the function's argument list. */
#define ARG_POINTER_REGNUM FT32_QAP
#define ELIMINABLE_REGS \
{{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
{FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}
/* This macro is similar to `INITIAL_FRAME_POINTER_OFFSET'. It
specifies the initial difference between the specified pair of
registers. This macro must be defined if `ELIMINABLE_REGS' is
defined. */
#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
do { \
(OFFSET) = ft32_initial_elimination_offset ((FROM), (TO)); \
} while (0)
/* A C expression that is nonzero if REGNO is the number of a hard
register in which function arguments are sometimes passed. */
#define FUNCTION_ARG_REGNO_P(r) (r >= FT32_R0 && r <= FT32_R5)
/* A macro whose definition is the name of the class to which a valid
base register must belong. A base register is one used in an
address which is the register value plus a displacement. */
#define BASE_REG_CLASS GENERAL_REGS
#define INDEX_REG_CLASS NO_REGS
#define HARD_REGNO_OK_FOR_BASE_P(NUM) \
((unsigned) (NUM) < FIRST_PSEUDO_REGISTER \
&& (REGNO_REG_CLASS(NUM) == GENERAL_REGS \
|| (NUM) == HARD_FRAME_POINTER_REGNUM))
/* A C expression which is nonzero if register number NUM is suitable
for use as a base register in operand addresses. */
#ifdef REG_OK_STRICT
#define REGNO_OK_FOR_BASE_P(NUM) \
(HARD_REGNO_OK_FOR_BASE_P(NUM) \
|| HARD_REGNO_OK_FOR_BASE_P(reg_renumber[(NUM)]))
#else
#define REGNO_OK_FOR_BASE_P(NUM) \
((NUM) >= FIRST_PSEUDO_REGISTER || HARD_REGNO_OK_FOR_BASE_P(NUM))
#endif
/* A C expression which is nonzero if register number NUM is suitable
for use as an index register in operand addresses. */
#define REGNO_OK_FOR_INDEX_P(NUM) FT32_FP
/* The maximum number of bytes that a single instruction can move
quickly between memory and registers or between two memory
locations. */
#define MOVE_MAX 4
#define TRULY_NOOP_TRUNCATION(op,ip) 1
/* Define this to be nonzero if shift instructions ignore all but the low-order
few bits. */
#define SHIFT_COUNT_TRUNCATED 1
/* All load operations zero extend. */
#define LOAD_EXTEND_OP(MEM) ZERO_EXTEND
/* A number, the maximum number of registers that can appear in a
valid memory address. */
#define MAX_REGS_PER_ADDRESS 1
/* An alias for a machine mode name. This is the machine mode that
elements of a jump-table should have. */
#define CASE_VECTOR_MODE SImode
/* Run-time Target Specification */
#define TARGET_CPU_CPP_BUILTINS() \
{ \
builtin_define ("__FT32__"); \
}
#define HAS_LONG_UNCOND_BRANCH true
#define NO_FUNCTION_CSE 1
#define ADDR_SPACE_PM 1
#define REGISTER_TARGET_PRAGMAS() do { \
c_register_addr_space ("__flash__", ADDR_SPACE_PM); \
} while (0);
extern int ft32_is_mem_pm(rtx o);
#endif /* GCC_FT32_H */

932
gcc/config/ft32/ft32.md Normal file
View File

@ -0,0 +1,932 @@
;; Machine description for FT32
;; Copyright (C) 2015 Free Software Foundation, Inc.
;; Contributed by FTDI <support@ftdi.com>
;; 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/>.
;; -------------------------------------------------------------------------
;; FT32 specific constraints, predicates and attributes
;; -------------------------------------------------------------------------
(include "constraints.md")
(include "predicates.md")
(define_constants [
(FP_REG 0)
(SP_REG 1)
(CC_REG 35)
])
(define_c_enum "unspec"
[UNSPEC_STRLEN
UNSPEC_MOVMEM
UNSPEC_SETMEM
UNSPEC_STPCPY
UNSPEC_INDEX_JMP
UNSPEC_LPM
UNSPEC_FMUL
UNSPEC_FMULS
UNSPEC_FMULSU
UNSPEC_COPYSIGN
UNSPEC_IDENTITY
UNSPEC_INSERT_BITS
UNSPEC_JMP_EPILOG
UNSPEC_JMP_EPILOG24
UNSPEC_JMP_PROLOG
UNSPEC_XCHG
])
;; -------------------------------------------------------------------------
;; nop instruction
;; -------------------------------------------------------------------------
(define_insn "nop"
[(const_int 0)]
""
"nop")
;; -------------------------------------------------------------------------
;; Arithmetic instructions
;; -------------------------------------------------------------------------
(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 "ft32_rimm_operand" "KA,r")))
]
""
"add.l %0,%1,%2")
(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 "ft32_rimm_operand" "KA,r")))]
""
"sub.l %0,%1,%2")
(define_insn "mulsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(mult:SI
(match_operand:SI 1 "register_operand" "r,r")
(match_operand:SI 2 "ft32_rimm_operand" "KA,r")))]
""
"mul.l %0,%1,%2")
(define_insn "umulsidi3"
[(set (match_operand:DI 0 "register_operand" "=r,r")
(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r,r"))
(zero_extend:DI (match_operand:SI 2 "ft32_rimm_operand" "r,KA"))))
(clobber (reg:CC CC_REG))]
""
"mul.l $cc,%1,%2\;muluh.l %h0,%1,%2\;move.l %0,$cc")
(define_insn "divsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(div:SI
(match_operand:SI 1 "register_operand" "r,r")
(match_operand:SI 2 "ft32_rimm_operand" "r,KA")))]
""
"div.l %0,%1,%2")
(define_insn "modsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(mod:SI
(match_operand:SI 1 "register_operand" "r,r")
(match_operand:SI 2 "ft32_rimm_operand" "r,KA")))]
""
"mod.l %0,%1,%2")
(define_insn "udivsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(udiv:SI
(match_operand:SI 1 "register_operand" "r,r")
(match_operand:SI 2 "ft32_rimm_operand" "r,KA")))]
""
"udiv.l %0,%1,%2")
(define_insn "umodsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(umod:SI
(match_operand:SI 1 "register_operand" "r,r")
(match_operand:SI 2 "register_operand" "r,KA")))]
""
"umod.l %0,%1,%2")
(define_insn "extvsi"
[(set (match_operand:SI 0 "register_operand" "=r")
(sign_extract:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "ft32_bwidth_operand" "b")
(match_operand:SI 3 "const_int_operand" "i")))]
""
"bexts.l %0,%1,((15 & %2) << 5) | (%3)")
(define_insn "extzvsi"
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extract:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "ft32_bwidth_operand" "b")
(match_operand:SI 3 "const_int_operand" "i")))]
""
"bextu.l %0,%1,((15 & %2) << 5) | (%3)")
(define_insn "insvsi"
[(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r,r")
(match_operand:SI 1 "ft32_bwidth_operand" "b,b")
(match_operand:SI 2 "const_int_operand" "i,i"))
(match_operand:SI 3 "general_operand" "r,O"))
(clobber (match_scratch:SI 4 "=&r,r"))]
""
{
if (which_alternative == 0)
{
return \"ldl.l %4,%3,((%1&15)<<5)|(%2)\;bins.l %0,%0,%4\";
}
else
{
if ((INTVAL(operands[3]) == 0) || (INTVAL(operands[1]) == 1))
return \"bins.l %0,%0,(%3<<9)|((%1&15)<<5)|(%2)\";
else
return \"ldk.l %4,(%3<<10)|((%1&15)<<5)|(%2)\;bins.l %0,%0,%4\";
}
})
;; -------------------------------------------------------------------------
;; Unary arithmetic instructions
;; -------------------------------------------------------------------------
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(not:SI (match_operand:SI 1 "register_operand" "r")))]
""
"xor.l %0,%1,-1")
;; -------------------------------------------------------------------------
;; Logical operators
;; -------------------------------------------------------------------------
(define_insn "andsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r")
(and:SI (match_operand:SI 1 "register_operand" "r,r,r")
(match_operand:SI 2 "general_operand" "r,x,KA")))]
""
"@
and.l %0,%1,%2
bins.l %0,%1,%g2
and.l %0,%1,%2")
(define_insn "andqi3"
[(set (match_operand:QI 0 "register_operand" "=r,r,r")
(and:QI (match_operand:QI 1 "register_operand" "r,r,r")
(match_operand:QI 2 "general_operand" "r,x,KA")))]
""
"@
and.b %0,%1,%2
bins.b %0,%1,%g2
and.b %0,%1,%2")
(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 "ft32_rimm_operand" "r,KA")))]
""
{
return "xor.l %0,%1,%2";
})
(define_insn "iorsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r")
(ior:SI (match_operand:SI 1 "register_operand" "r,r,r")
(match_operand:SI 2 "general_operand" "r,w,KA")))]
""
"@
or.l %0,%1,%2
bins.l %0,%1,%f2
or.l %0,%1,%2")
;; -------------------------------------------------------------------------
;; Shifters
;; -------------------------------------------------------------------------
(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 "ft32_rimm_operand" "r,KA")))]
""
{
return "ashl.l %0,%1,%2";
})
(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 "ft32_rimm_operand" "r,KA")))]
""
{
return "ashr.l %0,%1,%2";
})
(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 "ft32_rimm_operand" "r,KA")))]
""
{
return "lshr.l %0,%1,%2";
})
;; -------------------------------------------------------------------------
;; Move instructions
;; -------------------------------------------------------------------------
;; SImode
;; Push a register onto the stack
(define_insn "movsi_push"
[(set (mem:SI (pre_dec:SI (reg:SI SP_REG)))
(match_operand:SI 0 "register_operand" "r"))]
""
"push.l %0")
;; Pop a register from the stack
(define_insn "movsi_pop"
[(set (match_operand:SI 0 "register_operand" "=r")
(mem:SI (post_inc:SI (reg:SI SP_REG))))]
""
"pop.l %0")
(define_expand "movsi"
[(set (match_operand:SI 0 "general_operand" "")
(match_operand:SI 1 "general_operand" ""))]
""
{
/* If this is a store, force the value into a register. */
if (!(reload_in_progress || reload_completed))
{
if (MEM_P (operands[0]))
{
operands[1] = force_reg (SImode, operands[1]);
if (MEM_P (XEXP (operands[0], 0)))
operands[0] = gen_rtx_MEM (SImode, force_reg (SImode, XEXP (operands[0], 0)));
}
else
{
if (MEM_P (operands[1]) && MEM_P (XEXP (operands[1], 0)))
operands[1] = gen_rtx_MEM (SImode, force_reg (SImode, XEXP (operands[1], 0)));
}
/*
if (MEM_P (operands[0])) {
rtx o = XEXP (operands[0], 0);
if (!REG_P(o) &&
!CONST_INT_P(o) &&
GET_CODE(o) != SYMBOL_REF &&
GET_CODE(o) != LABEL_REF) {
operands[0] = gen_rtx_MEM (SImode, force_reg (SImode, XEXP (operands[0], 0)));
}
}
*/
}
})
(define_insn "*rtestsi"
[(set (reg:SI CC_REG)
(match_operand:SI 0 "register_operand" "r"))]
""
"cmp.l %0,0"
)
(define_insn "*rtestqi"
[(set (reg:QI CC_REG)
(match_operand:QI 0 "register_operand" "r"))]
""
"cmp.b %0,0"
)
(define_insn "*movsi"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,BW,r,r,r,r,A,r,r")
(match_operand:SI 1 "ft32_general_movsrc_operand" "r,r,BW,A,S,i,r,e,f"))]
"register_operand (operands[0], SImode) || register_operand (operands[1], SImode)"
"@
move.l %0,%1
sti.l %0,%1
ldi.l %0,%1
lda.l %0,%1
ldk.l %0,%1
*return ft32_load_immediate(operands[0], INTVAL(operands[1]));
sta.l %0,%1
lpm.l %0,%1
lpmi.l %0,%1"
)
(define_expand "movqi"
[(set (match_operand:QI 0 "general_operand" "")
(match_operand:QI 1 "general_operand" ""))]
""
{
/* If this is a store, force the value into a register. */
if (!(reload_in_progress || reload_completed))
{
if (MEM_P (operands[0]))
{
operands[1] = force_reg (QImode, operands[1]);
if (MEM_P (XEXP (operands[0], 0)))
operands[0] = gen_rtx_MEM (QImode, force_reg (SImode, XEXP (operands[0], 0)));
}
else
{
if (MEM_P (operands[1]) && MEM_P (XEXP (operands[1], 0)))
operands[1] = gen_rtx_MEM (QImode, force_reg (SImode, XEXP (operands[1], 0)));
}
if (MEM_P (operands[0]) && !REG_P(XEXP (operands[0], 0)))
{
operands[0] = gen_rtx_MEM (QImode, force_reg (SImode, XEXP (operands[0], 0)));
}
}
})
(define_insn "zero_extendqisi2"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r")
(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "BW,r,f")))]
""
"@
ldi.b %0,%1
and.l %0,%1,255
lpmi.b %0,%1"
)
(define_insn "extendqisi2"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r")
(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r")))]
""
"bexts.l %0,%1,(8<<5)|0"
)
(define_insn "zero_extendhisi2"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r")
(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "BW,r,f")))]
""
"@
ldi.s %0,%1
bextu.l %0,%1,(0<<5)|0
lpmi.s %0,%1"
)
(define_insn "extendhisi2"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r")
(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r")))]
""
"bexts.l %0,%1,(0<<5)|0"
)
(define_insn "*movqi"
[(set (match_operand:QI 0 "nonimmediate_operand" "=r,BW,r,r,A,r,r,r")
(match_operand:QI 1 "ft32_general_movsrc_operand" "r,r,BW,A,r,I,e,f"))]
"register_operand (operands[0], QImode)
|| register_operand (operands[1], QImode)"
"@
move.b %0,%1
sti.b %0,%1
ldi.b %0,%1
lda.b %0,%1
sta.b %0,%1
ldk.b %0,%1
lpm.b %0,%1
lpmi.b %0,%1"
)
(define_expand "movhi"
[(set (match_operand:HI 0 "general_operand" "")
(match_operand:HI 1 "general_operand" ""))]
""
{
/* If this is a store, force the value into a register. */
if (!(reload_in_progress || reload_completed))
{
if (MEM_P (operands[0]))
{
operands[1] = force_reg (HImode, operands[1]);
if (MEM_P (XEXP (operands[0], 0)))
operands[0] = gen_rtx_MEM (HImode, force_reg (SImode, XEXP (operands[0], 0)));
}
else
{
if (MEM_P (operands[1]) && MEM_P (XEXP (operands[1], 0)))
operands[1] = gen_rtx_MEM (HImode, force_reg (SImode, XEXP (operands[1], 0)));
}
if (MEM_P (operands[0]))
{
rtx o = XEXP (operands[0], 0);
if (!REG_P(o) &&
!CONST_INT_P(o) &&
GET_CODE(o) != SYMBOL_REF &&
GET_CODE(o) != LABEL_REF) {
operands[0] = gen_rtx_MEM (HImode, force_reg (SImode, XEXP (operands[0], 0)));
}
}
}
})
(define_insn "*movhi"
[(set (match_operand:HI 0 "nonimmediate_operand" "=r,BW,r,r,A,r,r,r")
(match_operand:HI 1 "ft32_general_movsrc_operand" "r,r,BW,A,r,I,e,f"))]
"(register_operand (operands[0], HImode)
|| register_operand (operands[1], HImode))"
"@
move.s %0,%1
sti.s %0,%1
ldi.s %0,%1
lda.s %0,%1
sta.s %0,%1
ldk.s %0,%1
lpm.s %0,%1
lpmi.s %0,%1"
)
(define_expand "movsf"
[(set (match_operand:SF 0 "general_operand" "")
(match_operand:SF 1 "general_operand" ""))]
""
{
/* If this is a store, force the value into a register. */
if (MEM_P (operands[0]))
operands[1] = force_reg (SFmode, operands[1]);
if (CONST_DOUBLE_P(operands[1]))
operands[1] = force_const_mem(SFmode, operands[1]);
})
(define_insn "*movsf"
[(set (match_operand:SF 0 "nonimmediate_operand" "=r,BW,r,r,A,r,r")
(match_operand:SF 1 "ft32_general_movsrc_operand" "r,r,BW,A,r,I,f"))]
"(register_operand (operands[0], SFmode)
|| register_operand (operands[1], SFmode))"
"@
move.l %0,%1
sti.l %0,%1
ldi.l %0,%1
lda.l %0,%1
sta.l %0,%1
ldk.l %0,%1
lpmi.l %0,%1"
)
;; -------------------------------------------------------------------------
;; Compare instructions
;; -------------------------------------------------------------------------
(define_expand "cbranchsi4"
[(set (reg:CC CC_REG)
(compare:CC
(match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "ft32_rimm_operand" "")))
(set (pc)
(if_then_else (match_operator 0 "comparison_operator"
[(reg:CC CC_REG) (const_int 0)])
(label_ref (match_operand 3 "" ""))
(pc)))]
""
"")
(define_insn "cmpsi"
[(set (reg:CC CC_REG)
(compare:CC
(match_operand:SI 0 "register_operand" "r,r")
(match_operand:SI 1 "ft32_rimm_operand" "r,KA")))]
""
"cmp.l %0,%1")
(define_insn ""
[(set (pc)
(if_then_else
(ne (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
(const_int 1)
(match_operand:SI 1 "const_int_operand" "i"))
(const_int 0))
(label_ref (match_operand 2 "" ""))
(pc)))
(clobber (reg:CC CC_REG))]
""
"btst.l %0,(1<<5)|%1\;jmpc nz,%l2")
(define_insn ""
[(set (pc)
(if_then_else
(eq (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
(const_int 1)
(match_operand:SI 1 "const_int_operand" "i"))
(const_int 0))
(label_ref (match_operand 2 "" ""))
(pc)))
(clobber (reg:CC CC_REG))]
""
"btst.l %0,(1<<5)|%1\;jmpc z,%l2")
(define_expand "cbranchqi4"
[(set (reg:CC CC_REG)
(compare:CC
(match_operand:QI 1 "register_operand" "")
(match_operand:QI 2 "ft32_rimm_operand" "")))
(set (pc)
(if_then_else (match_operator 0 "comparison_operator"
[(reg:CC CC_REG) (const_int 0)])
(label_ref (match_operand 3 "" ""))
(pc)))]
""
"")
(define_insn "*cmpqi"
[(set (reg:CC CC_REG)
(compare:CC
(match_operand:QI 0 "register_operand" "r,r")
(match_operand:QI 1 "ft32_rimm_operand" "r,KA")))]
""
"cmp.b %0,%1")
;; -------------------------------------------------------------------------
;; Branch instructions
;; -------------------------------------------------------------------------
(define_code_iterator cond [ne eq lt ltu gt gtu ge le geu leu])
(define_code_attr CC [(ne "nz") (eq "z") (lt "lt") (ltu "b")
(gt "gt") (gtu "a") (ge "gte") (le "lte")
(geu "ae") (leu "be") ])
(define_code_attr rCC [(ne "z") (eq "nz") (lt "gte") (ltu "ae")
(gt "lte") (gtu "be") (ge "lt") (le "gt")
(geu "b") (leu "a") ])
(define_insn "*b<cond:code>"
[(set (pc)
(if_then_else (cond (reg:CC CC_REG)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
{
return "jmpc <CC>,%l0";
}
)
(define_expand "cstoresi4"
[(set (reg:CC CC_REG)
(compare:CC (match_operand:SI 2 "register_operand" "r,r")
(match_operand:SI 3 "ft32_rimm_operand" "r,KA")))
(set (match_operand:SI 0 "register_operand")
(match_operator:SI 1 "ordered_comparison_operator"
[(reg:CC CC_REG) (const_int 0)]))]
""
{
rtx test;
switch (GET_CODE (operands[1])) {
case NE:
case GEU:
case LT:
case LE:
case LEU:
test = gen_rtx_fmt_ee (reverse_condition (GET_CODE (operands[1])),
SImode, operands[2], operands[3]);
emit_insn(gen_cstoresi4(operands[0], test, operands[2], operands[3]));
emit_insn(gen_xorsi3(operands[0], operands[0], gen_int_mode(1, SImode)));
DONE;
default:
;
}
})
(define_insn "*seq"
[(set (match_operand:SI 0 "register_operand" "=r")
(eq:SI (reg CC_REG) (const_int 0)))]
""
"bextu.l %0,$cc,32|0"
)
(define_insn "*sltu"
[(set (match_operand:SI 0 "register_operand" "=r")
(ltu:SI (reg CC_REG) (const_int 0)))]
""
"bextu.l %0,$cc,32|1"
)
(define_insn "*sge"
[(set (match_operand:SI 0 "register_operand" "=r")
(ge:SI (reg CC_REG) (const_int 0)))]
""
"bextu.l %0,$cc,32|4"
)
(define_insn "*sgt"
[(set (match_operand:SI 0 "register_operand" "=r")
(gt:SI (reg CC_REG) (const_int 0)))]
""
"bextu.l %0,$cc,32|5"
)
(define_insn "*sgtu"
[(set (match_operand:SI 0 "register_operand" "=r")
(gtu:SI (reg CC_REG) (const_int 0)))]
""
"bextu.l %0,$cc,32|6"
)
;; -------------------------------------------------------------------------
;; Call and Jump instructions
;; -------------------------------------------------------------------------
(define_expand "call"
[(call (match_operand:QI 0 "memory_operand" "")
(match_operand 1 "general_operand" ""))]
""
{
gcc_assert (MEM_P (operands[0]));
})
(define_insn "*call"
[(call (mem:QI (match_operand:SI
0 "nonmemory_operand" "i,r"))
(match_operand 1 "" ""))]
""
"@
call %0
calli %0"
)
(define_expand "call_value"
[(set (match_operand 0 "" "")
(call (match_operand:QI 1 "memory_operand" "")
(match_operand 2 "" "")))]
""
{
gcc_assert (MEM_P (operands[1]));
})
(define_insn "*call_value"
[(set (match_operand 0 "register_operand" "=r")
(call (mem:QI (match_operand:SI
1 "immediate_operand" "i"))
(match_operand 2 "" "")))]
""
"call %1"
)
(define_insn "*call_value_indirect"
[(set (match_operand 0 "register_operand" "=r")
(call (mem:QI (match_operand:SI
1 "register_operand" "r"))
(match_operand 2 "" "")))]
""
"calli %1"
)
(define_insn "indirect_jump"
[(set (pc) (match_operand:SI 0 "nonimmediate_operand" "r"))]
""
"jmpi %0")
(define_insn "jump"
[(set (pc)
(label_ref (match_operand 0 "" "")))]
""
"jmp %l0"
)
(define_insn "call_prolog"
[(unspec:SI [(match_operand 0 "" "")]
UNSPEC_JMP_PROLOG)]
""
"call __prolog_%0"
)
(define_insn "jump_epilog"
[(unspec:SI [(match_operand 0 "" "")]
UNSPEC_JMP_EPILOG)]
""
"jmp __epilog_%0"
)
(define_insn "jump_epilog24"
[(unspec:SI [(match_operand 0 "" "")]
UNSPEC_JMP_EPILOG24)]
""
"jmp __epilog24_%0"
)
;; Subroutines of "casesi".
;; operand 0 is index
;; operand 1 is the minimum bound
;; operand 2 is the maximum bound - minimum bound + 1
;; operand 3 is CODE_LABEL for the table;
;; operand 4 is the CODE_LABEL to go to if index out of range.
(define_expand "casesi"
[(match_operand:SI 0 "general_operand" "")
(match_operand:SI 1 "const_int_operand" "")
(match_operand:SI 2 "const_int_operand" "")
(match_operand 3 "" "")
(match_operand 4 "" "")]
""
"
{
if (GET_CODE (operands[0]) != REG)
operands[0] = force_reg (SImode, operands[0]);
if (operands[1] != const0_rtx)
{
rtx index = gen_reg_rtx (SImode);
rtx offset = gen_reg_rtx (SImode);
emit_insn (gen_movsi (offset, operands[1]));
emit_insn (gen_subsi3 (index, operands[0], offset));
operands[0] = index;
}
{
rtx test = gen_rtx_GTU (VOIDmode, operands[0], operands[2]);
emit_jump_insn (gen_cbranchsi4 (test, operands[0], operands[2], operands[4]));
}
emit_jump_insn (gen_casesi0 (operands[0], operands[3]));
DONE;
}")
(define_insn "casesi0"
[(set (pc) (mem:SI (plus:SI
(mult:SI (match_operand:SI 0 "register_operand" "r")
(const_int 4))
(label_ref (match_operand 1 "" "")))))
(clobber (match_scratch:SI 2 "=&r"))
]
""
"ldk.l\t$cc,%l1\;ashl.l\t%2,%0,2\;add.l\t%2,%2,$cc\;jmpi\t%2"
)
;; -------------------------------------------------------------------------
;; Atomic exchange instruction
;; -------------------------------------------------------------------------
(define_insn "atomic_exchangesi"
[(set (match_operand:SI 0 "register_operand" "=&r,r") ;; output
(match_operand:SI 1 "memory_operand" "+BW,A")) ;; memory
(set (match_dup 1)
(unspec:SI
[(match_operand:SI 2 "register_operand" "0,0") ;; input
(match_operand:SI 3 "const_int_operand")] ;; model
UNSPEC_XCHG))]
""
"@
exi.l %0,%1
exa.l %0,%1")
(define_insn "atomic_exchangehi"
[(set (match_operand:HI 0 "register_operand" "=&r,r") ;; output
(match_operand:HI 1 "memory_operand" "+BW,A")) ;; memory
(set (match_dup 1)
(unspec:HI
[(match_operand:HI 2 "register_operand" "0,0") ;; input
(match_operand:HI 3 "const_int_operand")] ;; model
UNSPEC_XCHG))]
""
"@
exi.s %0,%1
exa.s %0,%1")
(define_insn "atomic_exchangeqi"
[(set (match_operand:QI 0 "register_operand" "=&r,r") ;; output
(match_operand:QI 1 "memory_operand" "+BW,A")) ;; memory
(set (match_dup 1)
(unspec:QI
[(match_operand:QI 2 "register_operand" "0,0") ;; input
(match_operand:QI 3 "const_int_operand")] ;; model
UNSPEC_XCHG))]
""
"@
exi.b %0,%1
exa.b %0,%1")
;; -------------------------------------------------------------------------
;; String instructions
;; -------------------------------------------------------------------------
(define_insn "cmpstrsi"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(compare:SI (match_operand:BLK 1 "memory_operand" "W,BW")
(match_operand:BLK 2 "memory_operand" "W,BW")))
(clobber (match_operand:SI 3))
]
""
"strcmp.%d3 %0,%b1,%b2"
)
(define_insn "movstr"
[(set (match_operand:BLK 1 "memory_operand" "=W")
(match_operand:BLK 2 "memory_operand" "W"))
(use (match_operand:SI 0))
(clobber (match_dup 0))
]
"0"
"stpcpy %b1,%b2 # %0 %b1 %b2"
)
(define_insn "movmemsi"
[(set (match_operand:BLK 0 "memory_operand" "=W,W,BW")
(match_operand:BLK 1 "memory_operand" "W,W,BW"))
(use (match_operand:SI 2 "ft32_rimm_operand" "r,KA,rKA"))
(use (match_operand:SI 3))
]
""
"memcpy.%d3 %b0,%b1,%2 # %3!"
)
(define_insn "setmemsi"
[(set (match_operand:BLK 0 "memory_operand" "=BW,BW") (unspec:BLK [
(use (match_operand:QI 2 "register_operand" "r,r"))
(use (match_operand:SI 1 "ft32_rimm_operand" "r,KA"))
] UNSPEC_SETMEM))
(use (match_operand:SI 3))
]
""
"memset.%d3 %b0,%2,%1"
)
(define_insn "strlensi"
[(set (match_operand:SI 0 "register_operand" "=r")
(unspec:SI [(match_operand:BLK 1 "memory_operand" "W")
(match_operand:QI 2 "const_int_operand" "")
(match_operand:SI 3 "ft32_rimm_operand" "")]
UNSPEC_STRLEN))]
""
"strlen.%d3 %0,%b1 # %2 %3"
)
;; -------------------------------------------------------------------------
;; Prologue & Epilogue
;; -------------------------------------------------------------------------
(define_expand "prologue"
[(clobber (const_int 0))]
""
{
extern void ft32_expand_prologue();
ft32_expand_prologue ();
DONE;
})
(define_expand "epilogue"
[(return)]
""
{
extern void ft32_expand_epilogue();
ft32_expand_epilogue ();
DONE;
})
(define_insn "link"
[
;; (set (mem:SI (pre_dec:SI (reg:SI SP_REG)))
;; (reg:SI FP_REG))
(set (match_operand:SI 0)
(reg:SI SP_REG))
(set (reg:SI SP_REG)
(plus:SI (reg:SI SP_REG)
(match_operand:SI 1 "general_operand" "L")))]
""
"link %0,%m1"
)
(define_insn "unlink"
[(set (reg:SI FP_REG)
(mem:SI (reg:SI FP_REG)))
(set (reg:SI SP_REG)
(plus:SI (reg:SI FP_REG)
(const_int 4)))]
""
"unlink $r29"
)
(define_insn "returner"
[(return)]
"reload_completed"
"return")
(define_insn "returner24"
[
(set (reg:SI SP_REG)
(plus:SI
(reg:SI SP_REG)
(const_int 24)))
(return)]
""
"jmp __epilog24")

27
gcc/config/ft32/ft32.opt Normal file
View File

@ -0,0 +1,27 @@
; Options for the FT32 port of the compiler.
; Copyright (C) 2015 Free Software Foundation, Inc.
;
; 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/>.
msim
Target Report Mask(SIM)
target the software simulator
mlra
Target Report Var(ft32_lra_flag) Init(0) Save
Use LRA instead of reload

View File

@ -0,0 +1,85 @@
;; Predicate definitions for FT32
;; Copyright (C) 2015 Free Software Foundation, Inc.
;; Contributed by FTDI <support@ftdi.com>
;; 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/>.
;; -------------------------------------------------------------------------
;; Predicates
;; -------------------------------------------------------------------------
;; Nonzero if OP can be source of a simple move operation.
(define_predicate "ft32_general_movsrc_operand"
(match_code "mem,const_int,reg,subreg,symbol_ref,label_ref,const")
{
/* Any (MEM LABEL_REF) is OK. That is a pc-relative load. */
if (MEM_P (op) && GET_CODE (XEXP (op, 0)) == LABEL_REF)
return 1;
if (MEM_P (op)
&& GET_CODE (XEXP (op, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
&& GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST)
return 1;
return general_operand (op, mode);
})
(define_predicate "ft32_general_movdst_operand"
(match_code "mem,const_int,reg,subreg,symbol_ref,label_ref,const")
{
if (MEM_P (op)
&& GET_CODE (XEXP (op, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
&& CONST_INT_P (XEXP (XEXP (op, 0), 1)))
return 1;
if (MEM_P (op) && GET_CODE (XEXP (op, 0)) == SYMBOL_REF)
return 1;
return REG_P(op) ||
(MEM_P(op) && REG_P(XEXP (op, 0)));
})
(define_predicate "reg_indirect"
(match_code "mem")
{
return (MEM_P(op) && REG_P(XEXP (op, 0)));
})
;; Nonzero if OP can be an operand to an add/inc/dec instruction.
(define_predicate "ft32_add_operand"
(ior (match_code "reg")
(and (match_code "const_int")
(match_test "IN_RANGE (INTVAL (op), -32768, 32767)"))))
;; Nonzero if OP can be an operand to an sub/dec instruction.
(define_predicate "ft32_sub_operand"
(ior (match_code "reg")
(and (match_code "const_int")
(match_test "IN_RANGE (INTVAL (op), -32767, 32768)"))))
(define_predicate "ft32_rimm_operand"
(ior (match_code "reg")
(and (match_code "const_int")
(match_test "IN_RANGE (INTVAL (op), -512, 511)"))))
(define_predicate "ft32_bwidth_operand"
(and (match_code "const_int")
(match_test "IN_RANGE (INTVAL (op), 1, 16)")))

19
gcc/config/ft32/t-ft32 Normal file
View File

@ -0,0 +1,19 @@
# Target Makefile Fragment for ft32
# Copyright (C) 2015 Free Software Foundation, Inc.
# Contributed by FTDI <support@ftdi.com>
#
# 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/>.

View File

@ -112,6 +112,9 @@ Devon Bowen helped port GCC to the Tahoe.
@item
Don Bowman for mips-vxworks contributions.
@item
James Bowman for the FT32 port.
@item
Dave Brolley for work on cpplib and Chill.

View File

@ -3662,6 +3662,14 @@ results. However, it is currently known that boehm-gc (which itself
is required for java) may not configure properly on FreeBSD prior to
the FreeBSD 7.0 release with GNU binutils after 2.16.1.
@html
<hr />
@end html
@anchor{ft32-x-elf}
@heading ft32-*-elf
The FT32 processor.
This configuration is intended for embedded systems.
@html
<hr />
@end html

View File

@ -651,6 +651,9 @@ Objective-C and Objective-C++ Dialects}.
@emph{FR30 Options}
@gccoptlist{-msmall-model -mno-lsim}
@emph{FT32 Options}
@gccoptlist{-msim -mlra}
@emph{FRV Options}
@gccoptlist{-mgpr-32 -mgpr-64 -mfpr-32 -mfpr-64 @gol
-mhard-float -msoft-float @gol
@ -12278,6 +12281,7 @@ platform.
* Darwin Options::
* DEC Alpha Options::
* FR30 Options::
* FT32 Options::
* FRV Options::
* GNU/Linux Options::
* H8/300 Options::
@ -15111,6 +15115,29 @@ command line.
@end table
@node FT32 Options
@subsection FT32 Options
@cindex FT32 Options
These options are defined specifically for the FT32 port.
@table @gcctabopt
@item -msim
@opindex msim
Specifies that the program will be run on the simulator. This causes
an alternate runtime startup and library to be linked.
You must not use this option when generating programs that will run on
real hardware; you must provide your own runtime library for whatever
I/O functions are needed.
@item -mlra
@opindex mlra
Enable Local Register Allocation. This is still experimental for FT32,
so by default the compiler uses standard reload.
@end table
@node FRV Options
@subsection FRV Options
@cindex FRV Options

View File

@ -2247,6 +2247,49 @@ range of 1 to 2047.
@end table
@item FT32---@file{config/ft32/constraints.md}
@table @code
@item A
An absolute address
@item B
An offset address
@item W
A register indirect memory operand
@item e
An offset address.
@item f
An offset address.
@item O
The constant zero or one
@item I
A 16-bit signed constant (@minus{}32768 @dots{} 32767)
@item w
A bitfield mask suitable for bext or bins
@item x
An inverted bitfield mask suitable for bext or bins
@item L
A 16-bit unsigned constant, multiple of 4 (0 @dots{} 65532)
@item S
A 20-bit signed constant (@minus{}524288 @dots{} 524287)
@item b
A constant for a bitfield width (1 @dots{} 16)
@item KA
A 10-bit signed constant (@minus{}512 @dots{} 511)
@end table
@item Hewlett-Packard PA-RISC---@file{config/pa/pa.h}
@table @code
@item a

View File

@ -113,6 +113,8 @@ fido-*-*)
;;
frv*) cpu_type=frv
;;
ft32*) cpu_type=ft32
;;
moxie*) cpu_type=moxie
;;
i[34567]86-*-*)
@ -478,6 +480,10 @@ frv-*-*linux*)
tmake_file="$tmake_file frv/t-frv frv/t-linux t-fdpbit"
tm_file="$tm_file frv/elf-lib.h frv/frv-abi.h"
;;
ft32-*-elf)
tmake_file="ft32/t-ft32 t-softfp-sfdf t-softfp-excl t-softfp"
extra_parts="$extra_parts crti.o crti-hw.o crtn.o"
;;
h8300-*-rtems*)
tmake_file="$tmake_file h8300/t-h8300 t-fpbit"
tm_file="$tm_file h8300/h8300-lib.h"

View File

@ -0,0 +1,193 @@
.equ SYS_REGMSC0CFG_B3 , 0x1001b
.equ SYS_REGIRQCTL_B3 , 0x100e3
.global _start
_start:
# START Interrupt Vector Table [[
jmp 0x3fffc # RESET Vector
jmp _watchdog_isr # WATCHDOG Vector # TODO: Change me to reset the chip proper
jmp interrupt_0
jmp interrupt_1
jmp interrupt_2
jmp interrupt_3
jmp interrupt_4
jmp interrupt_5
jmp interrupt_6
jmp interrupt_7
jmp interrupt_8
jmp interrupt_9
jmp interrupt_10
jmp interrupt_11
jmp interrupt_12
jmp interrupt_13
jmp interrupt_14
jmp interrupt_15
jmp interrupt_16
jmp interrupt_17
jmp interrupt_18
jmp interrupt_19
jmp interrupt_20
jmp interrupt_21
jmp interrupt_22
jmp interrupt_23
jmp interrupt_24
jmp interrupt_25
jmp interrupt_26
jmp interrupt_27
jmp interrupt_28
jmp interrupt_29
jmp interrupt_30
jmp interrupt_31
jmp 0x3fff8
# ]] END Interrupt Vector Table
codestart:
jmp init
.global _exithook
_exithook: # Debugger uses '_exithook' at 0x90 to catch program exit
return
init:
# Disable all interrupts
ldk $r0,0x80
sta.b 0x100e3,$r0
# Reset all peripherals
# lda.l $r0, 0x10018
# bins.l $r0, $r0, 0x23F # Set bit 31
# sta.l 0x10018, $r0
# Initialize DATA by copying from program memory
ldk.l $r0,__data_load_start
ldk.l $r1,__data_load_end
ldk.l $r2,0 # Will use __data after binutils patch
jmp .dscopy
.dsloop:
# Copy PM[$r0] to RAM $r2
lpmi.l $r3,$r0,0
sti.l $r2,0,$r3
add.l $r0,$r0,4
add.l $r2,$r2,4
.dscopy:
cmp.l $r0,$r1
jmpc lt,.dsloop
# Zero BSS
ldk.l $r0,_bss_start
ldk.l $r2,_end
sub.l $r2,$r2,$r0
ldk.l $r1,0
memset.l $r0,$r1,$r2
sub.l $sp,$sp,24 # Space for the caller argument frame
call main
.equ EXITEXIT , 0x1fffc
.global _exit
_exit:
sta.l EXITEXIT,$r0 # simulator end of test
jmp _exithook
_watchdog_isr:
ldk.l $sp, 0x80FFFF # Reset the stack pointer so it doesn't grow to a huge size
jmp 0
# Macro to construct the interrupt stub code.
# it just saves r0, loads r0 with the int vector
# and branches to interrupt_common.
.macro inth i=0
interrupt_\i:
push $r0 # {
lda $r0,(vector_table + 4 * \i)
jmp interrupt_common
.endm
inth 0
inth 1
inth 2
inth 3
inth 4
inth 5
inth 6
inth 7
inth 8
inth 9
inth 10
inth 11
inth 12
inth 13
inth 14
inth 15
inth 16
inth 17
inth 18
inth 19
inth 20
inth 21
inth 22
inth 23
inth 24
inth 25
inth 26
inth 27
inth 28
inth 29
inth 30
inth 31
inth 32
# On entry: r0, already saved, holds the handler function
interrupt_common:
push $r1 # {
push $r2 # {
push $r3 # {
push $r4 # {
push $r5 # {
push $r6 # {
push $r7 # {
push $r8 # {
push $r9 # {
push $r10 # {
push $r11 # {
push $r12 # {
push $cc # {
calli $r0
pop $cc # }
pop $r12 # }
pop $r11 # }
pop $r10 # }
pop $r9 # }
pop $r8 # }
pop $r7 # }
pop $r6 # }
pop $r5 # }
pop $r4 # }
pop $r3 # }
pop $r2 # }
pop $r1 # }
pop $r0 # } matching push in interrupt_0-31 above
reti
# Null function for unassigned interrupt to point at
.global nullvector
nullvector:
return
.section .data
.global vector_table
vector_table:
.rept 33
.long nullvector
.endr
.section .text
.global __gxx_personality_sj0
__gxx_personality_sj0:

40
libgcc/config/ft32/crti.S Normal file
View File

@ -0,0 +1,40 @@
# crti.S for FT32
#
# Copyright (C) 2009-2013 Free Software Foundation, Inc.
#
# This file 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.
#
# This file 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.
#
# Under Section 7 of GPL version 3, you are granted additional
# permissions described in the GCC Runtime Library Exception, version
# 3.1, as published by the Free Software Foundation.
#
# You should have received a copy of the GNU General Public License and
# a copy of the GCC Runtime Library Exception along with this program;
# see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
# <http://www.gnu.org/licenses/>.
# This file just make a stack frame for the contents of the .fini and
# .init sections. Users may put any desired instructions in those
# sections.
.file "crti.S"
.section ".init"
.global _init
.type _init, @function
.p2align 2
_init:
.section ".fini"
.global _fini
.type _fini,@function
.p2align 2
_fini:

34
libgcc/config/ft32/crtn.S Normal file
View File

@ -0,0 +1,34 @@
# crtn.S for FT32
#
# Copyright (C) 2009-2013 Free Software Foundation, Inc.
#
# This file 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.
#
# This file 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.
#
# Under Section 7 of GPL version 3, you are granted additional
# permissions described in the GCC Runtime Library Exception, version
# 3.1, as published by the Free Software Foundation.
#
# You should have received a copy of the GNU General Public License and
# a copy of the GCC Runtime Library Exception along with this program;
# see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
# <http://www.gnu.org/licenses/>.
# This file just makes sure that the .fini and .init sections do in
# fact return. Users may put any desired instructions in those sections.
# This file is the last thing linked into any executable.
.file "crtn.S"
.section ".init"
return
.section ".fini"
return

View File

@ -0,0 +1,52 @@
.macro e r=0
.global __epilog_$r\r
__epilog_$r\r:
pop $r\r
.endm
e 28
e 27
e 26
e 25
e 24
e 23
e 22
e 21
e 20
e 19
e 18
e 17
e 16
e 15
e 14
e 13
return
.global __epilog24
__epilog24:
add $sp,$sp,24
return
.macro f r=0
.global __epilog24_$r\r
__epilog24_$r\r:
add $sp,$sp,24
jmp __epilog_$r\r
.endm
f 13
f 14
f 15
f 16
f 17
f 18
f 19
f 20
f 21
f 22
f 23
f 24
f 25
f 26
f 27
f 28

View File

@ -0,0 +1,919 @@
# ieee754 sf routines for FT32
/* Copyright (C) 1995-2014 Free Software Foundation, Inc.
This file 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.
This file 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.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
# See http://www.ens-lyon.fr/LIP/Pub/Rapports/PhD/PhD2006/PhD2006-02.pdf
# for implementation details of all except division which is detailed below
#
// .global __cmpsf2_
nan: .long 0x7FFFFFFF # also abs mask
inf: .long 0x7F800000
sign_mask: .long 0x80000000
m_mask: .long 0x007FFFFF
exp_bias: .long 127
edge_case: .long 0x00FFFFFF
smallest_norm: .long 0x00800000 # implicit bit
high_FF: .long 0xFF000000
high_uint: .long 0xFFFFFFFF
# Supply a few 'missing' instructions
# not
.macro not rd,r1
xor \rd,\r1,-1
.endm
# negate
.macro neg x
not \x, \x
add \x, \x, 1
.endm
# set $cc from the result of "ashl reg,dist"
.macro ashlcc reg,dist
.long 0x5de04008 | (\reg << 15) | (\dist << 4)
.endm
# converts an unsigned number x to a signed rep based on the bits in sign
# sign should be 0x00000000 or 0xffffffff.
.macro to_signed x, sign
add \x,\x,\sign # conditionally decrement x
xor \x,\x,\sign # conditionally complement x
.endm
.macro ld32 r,v
ldk \r,(\v>>10)
ldl \r,\r,(\v & 1023)
.endm
# calculate trailing zero count in x, also uses scr.
# Using Seal's algorithm
.macro ntz x, scr
not \scr, \x
add \scr, \scr, 1
and \x, \x, \scr
ashl \scr, \x, 4
add \x, \scr, \x
ashl \scr, \x, 6
add \x, \scr, \x
ashl \scr, \x, 16
sub \x, \scr, \x
lshr \x, \x, 26
ldk \scr, ntz_table
add \x, \x, \scr
lpmi.b \x, \x, 0
.endm
ntz_table:
.byte 32,0,1,12,2,6,0,13,3,0,7,0,0,0,0,14
.byte 10,4,0,0,8,0,0,25,0,0,0,0,0,21,27,15
.byte 31,11,5,0,0,0,0,0,9,0,0,24,0,0,20,26
.byte 30,0,0,0,0,23,0,19,29,0,22,18,28,17,16,0
# calculate leading zero count
.macro nlz x, scr
flip \x, \x, 31
ntz \x, \scr
.endm
# Round 26 bit mantissa to nearest
# | 23 bits frac | G | R | S |
.macro round m, s1, s2
ldk \s1,0xc8
and \s2,\m,7
lshr \s1,\s1,\s2
and \s1,\s1,1
lshr \m,\m,2
add \m,\m,\s1
.endm
# If NZ, set the LSB of reg
.macro sticky reg
jmpc z,1f
or \reg,\reg,1 # set the sticky bit to 1
1:
.endm
##########################################################################
##########################################################################
## addition & subtraction
#if defined(L_subsf3) || defined(L_addsub_sf)
.global __subsf3
__subsf3:
# this is subtraction, so we just change the sign of r1
lpm $r2,sign_mask
xor $r1,$r1,$r2
jmp __addsf3
#endif
#if defined(L_addsf3) || defined(L_addsub_sf)
.global __addsf3
__addsf3:
# x in $r0, y in $r1, result z in $r0 --||| 100 instructions +/- |||--
# unpack e, calc d
bextu $r2,$r0,(8<<5)|23 # ex in r2
bextu $r3,$r1,(8<<5)|23 # ey in r3
sub $r5,$r2,$r3 # d = ex - ey
# Special values are 0x00 and 0xff in ex and ey.
# If (ex&ey) != 0 or (xy|ey)=255 then there may be
# a special value.
tst $r2,$r3
jmpc nz,1f
jmp slow
1: or $r4,$r2,$r3
cmp $r4,255
jmpc nz,no_special_vals
slow:
# Check for early exit
cmp $r2,0
jmpc z,test_if_not_255
cmp $r3,0
jmpc nz,no_early_exit
test_if_not_255:
cmp $r2,255
jmpc z,no_early_exit
cmp $r3,255
jmpc z,no_early_exit
or $r6,$r2,$r3
cmp $r6,0
jmpc nz,was_not_zero
and $r0,$r0,$r1
lpm $r1,sign_mask
and $r0,$r0,$r1
return
was_not_zero:
cmp $r2,0
jmpc nz,ret_x
move $r0,$r1
return
ret_x:
return
no_early_exit:
# setup to test for special values
sub $r6,$r2,1
and $r6,$r6,0xFE
sub $r7,$r3,1
and $r7,$r7,0xFE
# test for special values
cmp $r6,$r7
jmpc gte,ex_spec_is_gte
move $r6,$r7
ex_spec_is_gte:
cmp $r6,0xFE
jmpc nz,no_special_vals
cmp $r5,0
jmpc ns,d_gte_0
cmp $r3,0xFF
jmpc z,ret_y
cmp $r2,0
jmpc z,ret_y
ret_y:
move $r0,$r1
return
d_gte_0:
cmp $r5,0
jmpc z,d_is_0
cmp $r2,0xFF
jmpc z,ret_x
cmp $r3,0
jmpc z,ret_x
d_is_0:
cmp $r2,0xFF
jmpc nz,no_special_vals
ashl $r6,$r0,9 # clear all except x frac
ashl $r7,$r1,9 # clear all except y frac
or $r6,$r6,$r7
cmp $r6,0
jmpc nz,ret_nan
lshr $r4,$r0,31 # sx in r4
lshr $r5,$r1,31 # sy in r4
cmp $r4,$r5
jmpc nz,ret_nan
return
ret_nan:
lpm $r0,nan
return
no_special_vals:
ldk $r8,(1<<10)|(9<<5)|26 # setup implicit bit and mask for e
#----------------------
ashr $r4,$r0,31 # sx in r4
ashl $r0,$r0,3 # shift mx 3 for GRS bits
bins $r0,$r0,$r8 # clear sx, ex and add implicit bit mx
# change mx to signed mantissa
to_signed $r0,$r4
#----------------------
ashr $r4,$r1,31 # sy in r4
ashl $r1,$r1,3 # shift my 3 for GRS bits
bins $r1,$r1,$r8 # clear sy, ey and add implicit bit my
# change my to signed mantissa
to_signed $r1,$r4
#----------------------
# test if we swap ms based on d sign
cmp $r5,0
jmpc gte,noswap
# swap mx & my
xor $r0,$r0,$r1
xor $r1,$r0,$r1
xor $r0,$r0,$r1
# d positive means that ex>=ey, so ez = ex
# d negative means that ey>ex, so ez = ey
move $r2,$r3
# |d|
neg $r5
noswap:
# now $r2 = ez = max(ex,ey)
cmp $r5,26 # max necessary alignment shift is 26
jmpc lt,under_26
ldk $r5,26
under_26:
ldk $r7,-1
ashl $r7,$r7,$r5 # create inverse of mask for test of S bit value in discarded my
not $r7,$r7
tst $r1,$r7 # determine value of sticky bit
# shift my >> |d|
ashr $r1,$r1,$r5
sticky $r1
# add ms
add $r0,$r0,$r1
# $r4 = sign(mx), mx = |mx|
ashr $r4,$r0,31
xor $r0,$r0,$r4
sub $r0,$r0,$r4
# realign mantissa using leading zero count
flip $r7,$r0,31
ntz $r7,$r8
ashl $r0,$r0,$r7
btst $r0,(6<<5)|0 # test low bits for sticky again
lshr $r0,$r0,6
sticky $r0
# update exponent
add $r2,$r2,5
sub $r2,$r2,$r7
# Round to nearest
round $r0,$r7,$r6
# detect_exp_update
lshr $r6,$r0,24
add $r2,$r2,$r6
# final tests
# mz == 0? if so, we just bail with a +0
cmp $r0,0
jmpc nz,msum_not_zero
ldk $r0,0
return
msum_not_zero:
# Combined check that (1 <= ez <= 254)
sub $r3,$r2,1
cmp $r3,254
jmpc b,no_special_ret
# underflow?
cmp $r2,0
jmpc gt,no_under
ldk $r0,0
jmp pack_sz
no_under:
# overflow?
cmp $r2,255
jmpc lt,no_special_ret
ldk $r0,0x7F8
ashl $r0,$r0,20
jmp pack_sz
no_special_ret:
# Pack ez
ldl $r2,$r2,(8<<5)|23
bins $r0,$r0,$r2 # width = 8, pos = 23 pack ez
# Pack sz
pack_sz:
ldl $r4,$r4,(1<<5)|31
bins $r0,$r0,$r4 # width = 1, pos = 31 set sz to sy
return
#endif
##########################################################################
##########################################################################
## multiplication
#ifdef L_mulsf3
.global __mulsf3
__mulsf3:
# x in $r0, y in $r1, result z in $r0 --||| 61 instructions +/- |||--
# unpack e
bextu $r2,$r0,(8<<5)|23 # ex in r2
bextu $r3,$r1,(8<<5)|23 # ey in r3
# calc result sign
xor $r4,$r0,$r1
lpm $r5,sign_mask
and $r4,$r4,$r5 # sz in r4
# unpack m add implicit bit
ldk $r5,(1<<10)|(9<<5)|23 # setup implicit bit and mask for e
#----------------------
bins $r0,$r0,$r5 # clear sx, ex and add implicit bit mx
sub $r6,$r2,1
cmp $r6,254
jmpc b,1f
jmp slow_mul
1: sub $r6,$r3,1
cmp $r6,254
jmpc b,no_special_vals_mul
slow_mul:
# Check for early exit
cmp $r2,0
jmpc z,op_is_zero
cmp $r3,0
jmpc nz,no_early_exit_mul
op_is_zero:
cmp $r2,255
jmpc z,no_early_exit_mul
cmp $r3,255
jmpc z,no_early_exit_mul
move $r0,$r4
return
no_early_exit_mul:
# setup to test for special values
sub $r6,$r2,1
and $r6,$r6,0xFE
sub $r7,$r3,1
and $r7,$r7,0xFE
# test for special values
cmp $r6,$r7
jmpc gte,ex_spec_is_gte_ey_mul
move $r6,$r7
ex_spec_is_gte_ey_mul:
cmp $r6,0xFE
jmpc nz,no_special_vals_mul
cmp $r2,0xFF
jmpc nz,ex_not_FF_mul
ashl $r6,$r0,9
cmp $r6,0
jmpc nz,ret_nan
cmp $r3,0
jmpc z,ret_nan
ashl $r6,$r1,1
lpm $r7,high_FF
cmp $r6,$r7
jmpc a,ret_nan
cmp $r6,0
jmpc z,ret_nan
# infinity
lpm $r0,inf
or $r0,$r0,$r4
return
ex_not_FF_mul:
cmp $r2,0
jmpc nz,no_nan_mul
cmp $r3,0xFF
jmpc nz,no_nan_mul
jmp ret_nan
no_nan_mul:
lpm $r0,nan
and $r0,$r0,$r1
or $r0,$r0,$r4
return
ret_nan:
lpm $r0,nan
return
no_special_vals_mul:
bins $r1,$r1,$r5 # clear sy, ey and add implicit bit my
# calc ez
add $r3,$r2,$r3
sub $r3,$r3,127 # ez in r3
# (r1,r2) = R0 * R1
mul $r2,$r0,$r1
muluh $r1,$r0,$r1
btst $r1,(1<<5)|15 # XXX use jmpx
jmpc z,mul_z0
# mz is 1X.XX...X
# 48-bit product is in (r1,r2). The low 22 bits of r2
# are discarded.
lshr $r0,$r2,22
ashl $r1,$r1,10
or $r0,$r0,$r1 # r0 = (r1,r2) >> 22
ashlcc 2,10
sticky $r0
add $r3,$r3,1 # bump exponent
# Round to nearest
round $r0, $r1, $r2
lshr $r6,$r0,24
add $r3,$r3,$r6
sub $r6,$r3,1
cmp $r6,254
jmpc b,no_special_ret_mul
special_ret_mul:
# When the final exponent <= 0, result is flushed to 0 except
# for the border case 0x00FFFFFF which is promoted to next higher
# FP no., that is, the smallest "normalized" number.
cmp $r3,0
jmpc gt,exp_normal
# Pack ez
ldl $r3,$r3,(8<<5)|23
bins $r0,$r0,$r3 # width = 8, pos = 23 pack ez
lpm $r2,edge_case
cmp $r0,$r2
jmpc nz,no_edge_case
lpm $r0,smallest_norm
jmp pack_sz_mul
no_edge_case:
ldk $r0,0
jmp pack_sz_mul
exp_normal:
# overflow?
cmp $r3,255
jmpc lt,no_special_ret_mul
ldk $r0,0x7F8
ashl $r0,$r0,20
jmp pack_sz_mul
no_special_ret_mul:
# Pack ez
ldl $r3,$r3,(8<<5)|23
bins $r0,$r0,$r3 # width = 8, pos = 23 pack ez
# Pack sz
pack_sz_mul:
or $r0,$r0,$r4
return
mul_z0:
# mz is 0X.XX...X
# 48-bit product is in (r1,r2). The low 21 bits of r2
# are discarded.
lshr $r0,$r2,21
ashl $r1,$r1,11
or $r0,$r0,$r1 # r0 = (r1,r2) >> 22
ashlcc 2,11
sticky $r0
# Round to nearest
round $r0, $r1, $r2
lshr $r6,$r0,24
add $r3,$r3,$r6
sub $r6,$r3,1
cmp $r6,254
jmpc b,no_special_ret_mul
jmp special_ret_mul
#endif
##########################################################################
##########################################################################
## division
## See http://perso.ens-lyon.fr/gilles.villard/BIBLIOGRAPHIE/PDF/arith19.pdf
## for implementation details
dc_1: .long 0xffffe7d7
dc_2: .long 0xffffffe8
dc_3: .long 0xffbad86f
dc_4: .long 0xfffbece7
dc_5: .long 0xf3672b51
dc_6: .long 0xfd9d3a3e
dc_7: .long 0x9a3c4390
dc_8: .long 0xd4d2ce9b
dc_9: .long 0x1bba92b3
dc_10: .long 0x525a1a8b
dc_11: .long 0x0452b1bf
dc_12: .long 0xFFFFFFC0
spec_val_test: .long 0x7F7FFFFF
#ifdef L_divsf3
.global __divsf3
__divsf3:
push $r13
# x in $r0, y in $r1, result z in $r0 --||| 73 instructions +/- |||-
bextu $r10,$r0,(8<<5)|23 # ex in r2
bextu $r11,$r1,(8<<5)|23 # ey in r3
lpm $r6, m_mask
and $r2, $r0, $r6 # mx
and $r3, $r1, $r6 # my
cmp $r2,$r3
bextu $r2,$r30,(1<<5)|4 # c = Tx >= T;
ashl $r3,$r3,9 # T = X << 9;
lpm $r13, sign_mask
ashl $r4,$r0,8 # X8 = X << 8;
or $r4,$r4,$r13 # Mx = X8 | 0x80000000;
lshr $r5,$r4,$r2 # S = Mx >> c;
# calc D
sub $r2, $r11, $r2
add $r12, $r10, 125
sub $r2, $r12, $r2 # int D = (Ex + 125) - (Ey - c);
# calc result sign
xor $r12,$r0,$r1
and $r12,$r12,$r13 # Sr = ( X ˆ Y ) & 0x80000000;
# check early exit
cmp $r10, 0
jmpc nz, no_early_ret_dev
cmp $r11, 0
jmpc z, no_early_ret_dev
cmp $r11, 255
jmpc z, no_early_ret_dev
move $r0, $r12
pop $r13
return
no_early_ret_dev:
# setup to test for special values
sub $r8,$r10,1
and $r8,$r8,0xFE
sub $r9,$r11,1
and $r9,$r9,0xFE
# test for special values
cmp $r8, $r9
jmpc gte, absXm1_gte_absYm1
move $r8, $r9
absXm1_gte_absYm1:
cmp $r8, 0xFE
jmpc nz, no_spec_ret_div
cmp $r10, 0xFF
jmpc nz, ex_not_FF_div
lpm $r6, m_mask
and $r2, $r0, $r6 # mx
cmp $r2, 0
jmpc nz, ret_nan_div
cmp $r11, 0xFF
jmpc z, ret_nan_div
jmp ret_inf_div
ex_not_FF_div:
cmp $r11, 0xFF
jmpc nz, ey_not_FF_div
ashl $r13, $r1, 9
cmp $r13, 0
jmpc nz, ret_nan_div
move $r0, $r12
pop $r13
return
ey_not_FF_div:
or $r10, $r10, $r11
cmp $r10, 0
jmpc z, ret_nan_div
ret_inf_div:
lpm $r6, inf
move $r0, $r6
or $r0, $r0, $r12
pop $r13
return
ret_nan_div:
lpm $r0, nan
pop $r13
return
no_spec_ret_div:
# check for overflow
ldk $r6, 0xFE
cmp $r2, $r6
jmpc lt, no_overflow_div
lpm $r6, inf
or $r0, $r12, $r6
pop $r13
return
no_overflow_div:
# check for underflow
cmp $r2, 0
jmpc ns, no_underflow_div
xnor $r6, $r6, $r6 # -1
cmp $r2, $r6
jmpc nz, ret_sr_div
ldk $r7, 0xFF
xor $r6, $r6, $r7 # 0xFF ^ -1 = 0xFFFFFF00
cmp $r4, $r6
jmpc nz, ret_sr_div
lpm $r6, sign_mask
cmp $r4, $r6
jmpc nz, ret_sr_div
lshr $r0, $r6, 8
or $r0, $r0, $r12
pop $r13
return
ret_sr_div:
move $r0, $r12
pop $r13
return
no_underflow_div:
lpm $r6, dc_1
muluh $r7, $r3, $r6 # i0 = mul( T , 0xffffe7d7 );
lpm $r6, dc_2
sub $r7, $r6, $r7 # i1 = 0xffffffe8 - i0;
muluh $r7, $r5, $r7 # i2 = mul( S , i1 );
add $r7, $r7, 0x20 # i3 = 0x00000020 + i2;
muluh $r8, $r3, $r3 # i4 = mul( T , T );
muluh $r9, $r5, $r8 # i5 = mul( S , i4 );
lpm $r6, dc_3
muluh $r10, $r3, $r6 # i6 = mul( T , 0xffbad86f );
lpm $r6, dc_4
sub $r10, $r6, $r10 # i7 = 0xfffbece7 - i6;
muluh $r10, $r9, $r10 # i8 = mul( i5 , i7 );
add $r7, $r7, $r10 # i9 = i3 + i8;
muluh $r9, $r8, $r9 # i10 = mul( i4 , i5 );
lpm $r6, dc_5
muluh $r10, $r3, $r6 # i11 = mul( T , 0xf3672b51 );
lpm $r6, dc_6
sub $r10, $r6, $r10 # i12 = 0xfd9d3a3e - i11;
lpm $r6, dc_7
muluh $r11, $r3, $r6 # i13 = mul( T , 0x9a3c4390 );
lpm $r6, dc_8
sub $r11, $r6, $r11 # i14 = 0xd4d2ce9b - i13
muluh $r11, $r8, $r11 # i15 = mul( i4 , i14 );
add $r10, $r10, $r11 # i16 = i12 + i15;
muluh $r10, $r9, $r10 # i17 = mul( i10 , i16 )
add $r7, $r7, $r10 # i18 = i9 + i17;
muluh $r10, $r8, $r8 # i19 = mul( i4 , i4 );
lpm $r6, dc_9
muluh $r11, $r3, $r6 # i20 = mul( T , 0x1bba92b3 );
lpm $r6, dc_10
sub $r11, $r6, $r11 # i21 = 0x525a1a8b - i20;
lpm $r6, dc_11
muluh $r8, $r8, $r6 # i22 = mul( i4 , 0x0452b1bf );
add $r8, $r11, $r8 # i23 = i21 + i22;
muluh $r8, $r10, $r8 # i24 = mul( i19 , i23 );
muluh $r8, $r9, $r8 # i25 = mul( i10 , i24 );
add $r3, $r7, $r8 # V = i18 + i25;
# W = V & 0xFFFFFFC0;
lpm $r6, dc_12
and $r3, $r3, $r6 # W
# round and pack final values
ashl $r0, $r2, 23 # pack D
or $r0, $r0, $r12 # pack Sr
ashl $r12, $r1, 8
or $r12, $r12, $r13 # My
muluh $r10, $r3, $r12
lshr $r11, $r5, 1
cmp $r10, $r11
jmpc gte, div_ret_1
add $r3, $r3, 0x40
div_ret_1:
lshr $r3, $r3, 7
add $r0, $r0, $r3
pop $r13
return
#endif
##########################################################################
##########################################################################
## Negate
#ifdef L_negsf
.global __negsf
__negsf:
lpm $r1, sign_mask
xor $r0, $r0, $r1
return
#endif
##########################################################################
##########################################################################
## float to int & unsigned int
#ifdef L_fixsfsi
.global __fixsfsi
__fixsfsi: # 20 instructions
bextu $r1,$r0,(8<<5)|23 # e in r1
lshr $r2,$r0,31 # s in r2
lpm $r3, m_mask
and $r0,$r0,$r3 # m in r0
# test nan
cmp $r1,0xFF
jmpc nz, int_not_nan
cmp $r0,0
jmpc z, int_not_nan
ldk $r0,0
return
int_not_nan:
# test edges
cmp $r1, 127
jmpc gte, int_not_zero # lower limit
ldk $r0,0
return
int_not_zero:
cmp $r1, 158
jmpc lt, int_not_max # upper limit
lpm $r0, nan
cmp $r2, 0
jmpc z, int_positive
xnor $r0, $r0, 0
return
int_not_max:
lpm $r3, smallest_norm
or $r0, $r0, $r3 # set implicit bit
sub $r1, $r1, 150
cmp $r1, 0
jmpc s, shift_right
ashl $r0, $r0, $r1
jmp set_int_sign
shift_right:
xnor $r1, $r1, 0
add $r1, $r1, 1
lshr $r0, $r0, $r1
set_int_sign:
cmp $r2, 0
jmpc z, int_positive
xnor $r0, $r0, 0
add $r0, $r0, 1
int_positive:
return
#endif
#ifdef L_fixunssfsi
.global __fixunssfsi
__fixunssfsi: # 19 instructions
lshr $r2, $r0, 31 # s in r2
cmp $r2, 0
jmpc z, uint_not_neg
ldk $r0, 0
return
uint_not_neg:
bextu $r1, $r0, (8<<5)|23 # e in r1
sub $r1, $r1, 127
lpm $r3, m_mask
and $r0, $r0, $r3 # m in r0
# test nan
cmp $r1, 0xFF
jmpc nz, uint_not_nan
cmp $r0, 0
jmpc z, uint_not_nan
ldk $r0, 0
return
uint_not_nan:
# test edges
cmp $r1, 0
jmpc ns, uint_not_zero # lower limit
ldk $r0, 0
return
uint_not_zero:
lpm $r3, smallest_norm
or $r0, $r0, $r3 # set implicit bit
cmp $r1, 23
jmpc lt, shift_uint_right
sub $r1, $r1, 23
ashl $r0, $r0, $r1
return
shift_uint_right:
ldk $r3, 23
sub $r1, $r3, $r1
lshr $r0, $r0, $r1
return
#endif
##########################################################################
##########################################################################
## int & unsigned int to float
.macro i2f x, s1, s2, s3, lbl
move \s1, \x
nlz \s1, \s2
cmp \s1, 8
jmpc s, float_round\lbl
sub \s2, \s1, 8
ashl \x, \x, \s2
jmp float_no_round\lbl
float_round\lbl:
cmp \s1, 6
jmpc s, float_shift_right\lbl
sub \s2, \s1, 6
ashl \x, \x, \s2
jmp float_round_and_pack\lbl
float_shift_right\lbl:
ldk \s2, 6
sub \s2, \s2, \s1
xnor \s3, \s3 ,\s3 # 0xFFFFFFFF
ashl \s3, \s3 ,\s2 # create inverse of mask for test of S bit value in discarded my
xnor \s3, \s3 ,0 # NOT
tst \x, \s3 # determine value of sticky bit
lshr \x, \x, \s2
jmpc z,float_round_and_pack\lbl
or \x, \x, 1 # set the sticky bit to 1
float_round_and_pack\lbl:
bextu \s2, \x, (1<<5)|2 # extract low bit of m
or \x, \x, \s2 # or p into r
add \x, \x, 1
lshr \x, \x, 2
btst \x, (1<<5)|24 # test for carry from round
jmpc z, float_no_round\lbl
sub \s1, \s1, 1 # inc e for carry (actually dec nlz)
lshr \x, \x, 1
float_no_round\lbl:
ldk \s2, 158
sub \s1, \s2, \s1
# Pack e
ldl \s1, \s1, (8<<5)|23
bins \x, \x, \s1
.endm
#ifdef L_floatsisf
.global __floatsisf
__floatsisf: # 32 instructions
cmp $r0, 0
jmpc nz, float_not_zero
return
float_not_zero:
ashr $r1, $r0, 31 # s in r1
xor $r0, $r0, $r1 # cond neg
sub $r0, $r0, $r1
i2f $r0, $r2, $r3, $r4, 1
ldl $r1, $r1, (1<<5)|31
bins $r0, $r0, $r1
return
#endif
#ifdef L_floatunsisf
.global __floatunsisf
__floatunsisf: # 26 instructions
cmp $r0, 0
jmpc nz, float_not_zero2
return
float_not_zero2:
i2f $r0, $r1, $r2, $r3, 2
return
#endif
##########################################################################
##########################################################################
## float compare
__cmpsf2_:
# calc abs vals
lpm $r3, nan # also abs mask
and $r2, $r0, $r3
and $r3, $r1, $r3
# test if either abs is nan
lpm $r4, inf
cmp $r2, $r4
jmpc gt, cmp_is_gt
cmp $r3, $r4
jmpc gt, cmp_is_gt
# test if both are 0
or $r2, $r2, $r3
cmp $r2, 0
jmpc z, cmp_is_eq
# test if eq
cmp $r0, $r1
jmpc z, cmp_is_eq
# -- if either is pos
and $r2, $r0, $r1
cmp $r2, 0
jmpc s, cmp_both_neg
cmp $r0, $r1
jmpc gt, cmp_is_gt
# r0 < r1
lpm $r0, high_uint
return
cmp_both_neg:
cmp $r0, $r1
jmpc lt, cmp_is_gt
# r0 < r1
lpm $r0, high_uint
return
cmp_is_gt:
ldk $r0, 1
return
cmp_is_eq:
ldk $r0, 0
return

199
libgcc/config/ft32/prolog.S Normal file
View File

@ -0,0 +1,199 @@
.global __prolog_$r13
__prolog_$r13:
exi $r13,$sp,0
jmpi $r13
.global __prolog_$r14
__prolog_$r14:
exi $r13,$sp,0
push $r14
jmpi $r13
.global __prolog_$r15
__prolog_$r15:
exi $r13,$sp,0
push $r14
push $r15
jmpi $r13
.global __prolog_$r16
__prolog_$r16:
exi $r13,$sp,0
push $r14
push $r15
push $r16
jmpi $r13
.global __prolog_$r17
__prolog_$r17:
exi $r13,$sp,0
push $r14
push $r15
push $r16
push $r17
jmpi $r13
.global __prolog_$r18
__prolog_$r18:
exi $r13,$sp,0
push $r14
push $r15
push $r16
push $r17
push $r18
jmpi $r13
.global __prolog_$r19
__prolog_$r19:
exi $r13,$sp,0
push $r14
push $r15
push $r16
push $r17
push $r18
push $r19
jmpi $r13
.global __prolog_$r20
__prolog_$r20:
exi $r13,$sp,0
push $r14
push $r15
push $r16
push $r17
push $r18
push $r19
push $r20
jmpi $r13
.global __prolog_$r21
__prolog_$r21:
exi $r13,$sp,0
push $r14
push $r15
push $r16
push $r17
push $r18
push $r19
push $r20
push $r21
jmpi $r13
.global __prolog_$r22
__prolog_$r22:
exi $r13,$sp,0
push $r14
push $r15
push $r16
push $r17
push $r18
push $r19
push $r20
push $r21
push $r22
jmpi $r13
.global __prolog_$r23
__prolog_$r23:
exi $r13,$sp,0
push $r14
push $r15
push $r16
push $r17
push $r18
push $r19
push $r20
push $r21
push $r22
push $r23
jmpi $r13
.global __prolog_$r24
__prolog_$r24:
exi $r13,$sp,0
push $r14
push $r15
push $r16
push $r17
push $r18
push $r19
push $r20
push $r21
push $r22
push $r23
push $r24
jmpi $r13
.global __prolog_$r25
__prolog_$r25:
exi $r13,$sp,0
push $r14
push $r15
push $r16
push $r17
push $r18
push $r19
push $r20
push $r21
push $r22
push $r23
push $r24
push $r25
jmpi $r13
.global __prolog_$r26
__prolog_$r26:
exi $r13,$sp,0
push $r14
push $r15
push $r16
push $r17
push $r18
push $r19
push $r20
push $r21
push $r22
push $r23
push $r24
push $r25
push $r26
jmpi $r13
.global __prolog_$r27
__prolog_$r27:
exi $r13,$sp,0
push $r14
push $r15
push $r16
push $r17
push $r18
push $r19
push $r20
push $r21
push $r22
push $r23
push $r24
push $r25
push $r26
push $r27
jmpi $r13
.global __prolog_$r28
__prolog_$r28:
exi $r13,$sp,0
push $r14
push $r15
push $r16
push $r17
push $r18
push $r19
push $r20
push $r21
push $r22
push $r23
push $r24
push $r25
push $r26
push $r27
push $r28
jmpi $r13

View File

@ -0,0 +1,61 @@
#define _FP_W_TYPE_SIZE 32
#define _FP_W_TYPE unsigned long
#define _FP_WS_TYPE signed long
#define _FP_I_TYPE long
/* The type of the result of a floating point comparison. This must
match `__libgcc_cmp_return__' in GCC for the target. */
typedef int __gcc_CMPtype __attribute__ ((mode (__libgcc_cmp_return__)));
#define CMPtype __gcc_CMPtype
#define _FP_MUL_MEAT_S(R,X,Y) \
_FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm)
#define _FP_MUL_MEAT_D(R,X,Y) \
_FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
#define _FP_MUL_MEAT_Q(R,X,Y) \
_FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_loop(S,R,X,Y)
#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv(D,R,X,Y)
#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_4_udiv(Q,R,X,Y)
#define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1)
#define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1), -1
#define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1
#define _FP_NANSIGN_S 0
#define _FP_NANSIGN_D 0
#define _FP_NANSIGN_Q 0
#define _FP_KEEPNANFRACP 1
#define _FP_QNANNEGATEDP 0
/* Someone please check this. */
#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \
do { \
if ((_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs) \
&& !(_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs)) \
{ \
R##_s = Y##_s; \
_FP_FRAC_COPY_##wc(R,Y); \
} \
else \
{ \
R##_s = X##_s; \
_FP_FRAC_COPY_##wc(R,X); \
} \
R##_c = FP_CLS_NAN; \
} while (0)
/* Not checked. */
#define _FP_TININESS_AFTER_ROUNDING 0
#define __LITTLE_ENDIAN 1234
#define __BIG_ENDIAN 4321
# define __BYTE_ORDER __LITTLE_ENDIAN
/* Define ALIASNAME as a strong alias for NAME. */
# define strong_alias(name, aliasname) _strong_alias(name, aliasname)
# define _strong_alias(name, aliasname) \
extern __typeof (name) aliasname __attribute__ ((alias (#name)));

View File

@ -0,0 +1,4 @@
LIB2ADD = $(srcdir)/config/ft32/epilog.S $(srcdir)/config/ft32/prolog.S
crti-hw.o: $(srcdir)/config/ft32/crti-hw.S
$(crt_compile) -c -x assembler-with-cpp $<