Initial TI PRU GCC port

ChangeLog:

2019-06-19  Dimitar Dimitrov  <dimitar@dinux.eu>

	* configure: Regenerate.
	* configure.ac: Add PRU target.

gcc/ChangeLog:

2019-06-19  Dimitar Dimitrov  <dimitar@dinux.eu>

	* common/config/pru/pru-common.c: New file.
	* config.gcc: Add PRU target.
	* config/pru/alu-zext.md: New file.
	* config/pru/constraints.md: New file.
	* config/pru/predicates.md: New file.
	* config/pru/pru-opts.h: New file.
	* config/pru/pru-passes.c: New file.
	* config/pru/pru-pragma.c: New file.
	* config/pru/pru-protos.h: New file.
	* config/pru/pru.c: New file.
	* config/pru/pru.h: New file.
	* config/pru/pru.md: New file.
	* config/pru/pru.opt: New file.
	* config/pru/t-pru: New file.
	* doc/extend.texi: Document PRU pragmas.
	* doc/invoke.texi: Document PRU-specific options.
	* doc/md.texi: Document PRU asm constraints.

From-SVN: r272202
This commit is contained in:
Dimitar Dimitrov 2019-06-12 19:04:24 +00:00 committed by Dimitar Dimitrov
parent 974b8e618b
commit 8d2af3a25b
21 changed files with 5898 additions and 0 deletions

View File

@ -1,3 +1,8 @@
2019-06-19 Dimitar Dimitrov <dimitar@dinux.eu>
* configure: Regenerate.
* configure.ac: Add PRU target.
2019-06-11  Matthew Beliveau  <mbelivea@redhat.com>
* MAINTAINERS (Write After Approval): Add myself.

7
configure vendored
View File

@ -3356,6 +3356,10 @@ case "${target}" in
powerpc-*-aix* | rs6000-*-aix*)
noconfigdirs="$noconfigdirs target-libssp"
;;
pru-*-*)
# No hosted I/O support.
noconfigdirs="$noconfigdirs target-libssp"
;;
rl78-*-*)
# libssp uses a misaligned load to trigger a fault, but the RL78
# doesn't fault for those - instead, it gives a build-time error
@ -3574,6 +3578,9 @@ case "${target}" in
powerpc*-*-*)
libgloss_dir=rs6000
;;
pru-*-*)
libgloss_dir=pru
;;
sparc*-*-*)
libgloss_dir=sparc
;;

View File

@ -641,6 +641,10 @@ case "${target}" in
powerpc-*-aix* | rs6000-*-aix*)
noconfigdirs="$noconfigdirs target-libssp"
;;
pru-*-*)
# No hosted I/O support.
noconfigdirs="$noconfigdirs target-libssp"
;;
rl78-*-*)
# libssp uses a misaligned load to trigger a fault, but the RL78
# doesn't fault for those - instead, it gives a build-time error
@ -856,6 +860,9 @@ case "${target}" in
powerpc*-*-*)
libgloss_dir=rs6000
;;
pru-*-*)
libgloss_dir=pru
;;
sparc*-*-*)
libgloss_dir=sparc
;;

View File

@ -1,3 +1,23 @@
2019-06-19 Dimitar Dimitrov <dimitar@dinux.eu>
* common/config/pru/pru-common.c: New file.
* config.gcc: Add PRU target.
* config/pru/alu-zext.md: New file.
* config/pru/constraints.md: New file.
* config/pru/predicates.md: New file.
* config/pru/pru-opts.h: New file.
* config/pru/pru-passes.c: New file.
* config/pru/pru-pragma.c: New file.
* config/pru/pru-protos.h: New file.
* config/pru/pru.c: New file.
* config/pru/pru.h: New file.
* config/pru/pru.md: New file.
* config/pru/pru.opt: New file.
* config/pru/t-pru: New file.
* doc/extend.texi: Document PRU pragmas.
* doc/invoke.texi: Document PRU-specific options.
* doc/md.texi: Document PRU asm constraints.
2019-06-12 Martin Sebor <msebor@redhat.com>
PR middle-end/90676

View File

@ -0,0 +1,36 @@
/* Common hooks for TI PRU
Copyright (C) 2014-2019 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/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "diagnostic-core.h"
#include "tm.h"
#include "common/common-target.h"
#include "common/common-target-def.h"
#include "opts.h"
#include "flags.h"
#undef TARGET_DEFAULT_TARGET_FLAGS
#define TARGET_DEFAULT_TARGET_FLAGS (MASK_OPT_LOOP)
#undef TARGET_EXCEPT_UNWIND_INFO
#define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info
struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER;

View File

@ -514,6 +514,9 @@ powerpc*-*-*)
esac
extra_options="${extra_options} g.opt fused-madd.opt rs6000/rs6000-tables.opt"
;;
pru-*-*)
cpu_type=pru
;;
riscv*)
cpu_type=riscv
extra_objs="riscv-builtins.o riscv-c.o"
@ -2764,6 +2767,12 @@ powerpcle-*-eabi*)
extra_options="${extra_options} rs6000/sysv4.opt"
use_gcc_stdint=wrap
;;
pru*-*-*)
tm_file="elfos.h newlib-stdint.h ${tm_file}"
tmake_file="${tmake_file} pru/t-pru"
extra_objs="pru-pragma.o pru-passes.o"
use_gcc_stdint=wrap
;;
rs6000-ibm-aix6.* | powerpc-ibm-aix6.*)
tm_file="${tm_file} rs6000/aix.h rs6000/aix61.h rs6000/xcoff.h rs6000/aix-stdint.h"
tmake_file="rs6000/t-aix52 t-slibgcc"

181
gcc/config/pru/alu-zext.md Normal file
View File

@ -0,0 +1,181 @@
;; ALU operations with zero extensions
;;
;; Copyright (C) 2015-2019 Free Software Foundation, Inc.
;; Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
;;
;; 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/>.
; All PRU ALU instructions automatically zero-extend their source operands,
; and zero-extract the result into the destination register. This is
; described in the machine description by defining a separate pattern
; for each possible combination of zero_extend and mode for input operands.
;
; An unfortunate side effect is that quite a few invalid RTL patterns are
; generated. For example:
; ... (zero_extend:SI (match_operand:SI ...)) ...
; These patterns are harmless since no pass should generate such RTL. This
; shortcut allows us to keep small and concise machine description patterns.
(define_subst_attr "alu2_zext" "alu2_zext_subst" "_z" "_noz")
(define_subst_attr "alu3_zext_op1" "alu3_zext_op1_subst" "_z1" "_noz1")
(define_subst_attr "alu3_zext_op2" "alu3_zext_op2_subst" "_z2" "_noz2")
(define_subst_attr "alu3_zext" "alu3_zext_subst" "_z" "_noz")
(define_subst_attr "bitalu_zext" "bitalu_zext_subst" "_z" "_noz")
(define_code_iterator ALUOP3 [plus minus and ior xor umin umax ashift lshiftrt])
(define_code_iterator ALUOP2 [neg not])
;; Arithmetic Operations
(define_insn "add_impl<EQD:mode><EQS0:mode><EQS1:mode>_<alu3_zext><alu3_zext_op1><alu3_zext_op2>"
[(set (match_operand:EQD 0 "register_operand" "=r,r,r")
(plus:EQD
(zero_extend:EQD
(match_operand:EQS0 1 "register_operand" "%r,r,r"))
(zero_extend:EQD
(match_operand:EQS1 2 "nonmemory_operand" "r,<EQS1:ubyte_constr>,M"))))]
""
"@
add\\t%0, %1, %2
add\\t%0, %1, %u2
sub\\t%0, %1, %n2"
[(set_attr "type" "alu")])
(define_insn "sub_impl<EQD:mode><EQS0:mode><EQS1:mode>_<alu3_zext><alu3_zext_op1><alu3_zext_op2>"
[(set (match_operand:EQD 0 "register_operand" "=r,r")
(minus:EQD
(zero_extend:EQD
(match_operand:EQS0 1 "reg_or_ubyte_operand" "r,<EQS0:ubyte_constr>"))
(zero_extend:EQD
(match_operand:EQS1 2 "register_operand" "r,r"))))]
""
"@
sub\\t%0, %1, %2
rsb\\t%0, %2, %u1"
[(set_attr "type" "alu")])
(define_insn "neg_impl<EQD:mode><EQS0:mode>_<alu2_zext>"
[(set (match_operand:EQD 0 "register_operand" "=r")
(neg:EQD
(zero_extend:EQD (match_operand:EQS0 1 "register_operand" "r"))))]
""
"rsb\\t%0, %1, 0"
[(set_attr "type" "alu")])
(define_insn "one_cmpl_impl<EQD:mode><EQS0:mode>_<alu2_zext>"
[(set (match_operand:EQD 0 "register_operand" "=r")
(not:EQD
(zero_extend:EQD (match_operand:EQS0 1 "register_operand" "r"))))]
""
"not\\t%0, %1"
[(set_attr "type" "alu")])
; Specialized IOR/AND patterns for matching setbit/clearbit instructions.
;
; TODO - allow clrbit and setbit to support (1 << REG) constructs
(define_insn "clearbit_<EQD:mode><EQS0:mode>_<bitalu_zext>"
[(set (match_operand:EQD 0 "register_operand" "=r")
(and:EQD
(zero_extend:EQD
(match_operand:EQS0 1 "register_operand" "r"))
(match_operand:EQD 2 "single_zero_operand" "n")))]
""
"clr\\t%0, %1, %V2"
[(set_attr "type" "alu")])
(define_insn "setbit_<EQD:mode><EQS0:mode>_<bitalu_zext>"
[(set (match_operand:EQD 0 "register_operand" "=r")
(ior:EQD
(zero_extend:EQD
(match_operand:EQS0 1 "register_operand" "r"))
(match_operand:EQD 2 "single_one_operand" "n")))]
""
"set\\t%0, %1, %T2"
[(set_attr "type" "alu")])
; Regular ALU ops
(define_insn "<code>_impl<EQD:mode><EQS0:mode><EQS1:mode>_<alu3_zext><alu3_zext_op1><alu3_zext_op2>"
[(set (match_operand:EQD 0 "register_operand" "=r")
(LOGICAL:EQD
(zero_extend:EQD
(match_operand:EQS0 1 "register_operand" "%r"))
(zero_extend:EQD
(match_operand:EQS1 2 "reg_or_ubyte_operand" "r<EQS1:ubyte_constr>"))))]
""
"<logical_asm>\\t%0, %1, %u2"
[(set_attr "type" "alu")])
; Shift ALU ops
(define_insn "<shift_op>_impl<EQD:mode><EQS0:mode><EQS1:mode>_<alu3_zext><alu3_zext_op1><alu3_zext_op2>"
[(set (match_operand:EQD 0 "register_operand" "=r")
(SHIFT:EQD
(zero_extend:EQD (match_operand:EQS0 1 "register_operand" "r"))
(zero_extend:EQD (match_operand:EQS1 2 "shift_operand" "rL"))))]
""
"<shift_asm>\\t%0, %1, %2"
[(set_attr "type" "alu")])
;; Substitutions
(define_subst "alu2_zext_subst"
[(set (match_operand:EQD 0)
(ALUOP2:EQD (zero_extend:EQD (match_operand:EQD 1))))]
""
[(set (match_dup 0)
(ALUOP2:EQD (match_dup 1)))])
(define_subst "bitalu_zext_subst"
[(set (match_operand:EQD 0)
(ALUOP3:EQD (zero_extend:EQD (match_operand:EQD 1))
(match_operand:EQD 2)))]
""
[(set (match_dup 0)
(ALUOP3:EQD (match_dup 1)
(match_dup 2)))])
(define_subst "alu3_zext_subst"
[(set (match_operand:EQD 0)
(ALUOP3:EQD (zero_extend:EQD (match_operand:EQD 1))
(zero_extend:EQD (match_operand:EQD 2))))]
""
[(set (match_dup 0)
(ALUOP3:EQD (match_dup 1)
(match_dup 2)))])
(define_subst "alu3_zext_op1_subst"
[(set (match_operand:EQD 0)
(ALUOP3:EQD (zero_extend:EQD (match_operand:EQD 1))
(zero_extend:EQD (match_operand:EQS1 2))))]
""
[(set (match_dup 0)
(ALUOP3:EQD (match_dup 1)
(zero_extend:EQD (match_dup 2))))])
(define_subst "alu3_zext_op2_subst"
[(set (match_operand:EQD 0)
(ALUOP3:EQD (zero_extend:EQD (match_operand:EQS0 1))
(zero_extend:EQD (match_operand:EQD 2))))]
""
[(set (match_dup 0)
(ALUOP3:EQD (zero_extend:EQD (match_dup 1))
(match_dup 2)))])

View File

@ -0,0 +1,108 @@
;; Constraint definitions for TI PRU.
;; Copyright (C) 2014-2019 Free Software Foundation, Inc.
;; Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
;;
;; 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/>.
;; We use the following constraint letters for constants:
;;
;; I: 0 to 255.
;; J: 0 to 65535.
;; L: 0 to 31 (for shift counts).
;; T: Text segment label. Needed to know when to select %pmem relocation.
;; Z: Constant integer zero.
;;
;; We use the following built-in register classes:
;;
;; r: General purpose register (r0..r31).
;; m: Memory operand.
;;
;; The following constraints are intended for internal use only:
;; Rmd0, Rms0, Rms1: Registers for MUL instruction operands.
;; Rsib: Jump address register suitable for sibling calls.
;; M: -255 to 0 (for converting ADD to SUB with suitable UBYTE OP2).
;; N: -32768 to 32767 (16-bit signed integer).
;; O: -128 to 127 (8-bit signed integer).
;; P: 1
;; Register constraints.
(define_register_constraint "Rsib" "SIB_REGS"
"@internal
A register suitable for an indirect sibcall.")
(define_register_constraint "Rmd0" "MULDST_REGS"
"@internal
The multiply destination register.")
(define_register_constraint "Rms0" "MULSRC0_REGS"
"@internal
The multiply source 0 register.")
(define_register_constraint "Rms1" "MULSRC1_REGS"
"@internal
The multiply source 1 register.")
;; Integer constraints.
(define_constraint "I"
"An unsigned 8-bit constant."
(and (match_code "const_int")
(match_test "UBYTE_INT (ival)")))
(define_constraint "J"
"An unsigned 16-bit constant."
(and (match_code "const_int")
(match_test "UHWORD_INT (ival)")))
(define_constraint "L"
"An unsigned 5-bit constant (for shift counts)."
(and (match_code "const_int")
(match_test "ival >= 0 && ival <= 31")))
(define_constraint "M"
"@internal
A constant in the range [-255, 0]."
(and (match_code "const_int")
(match_test "UBYTE_INT (-ival)")))
(define_constraint "N"
"@internal
A constant in the range [-32768, 32767]."
(and (match_code "const_int")
(match_test "SHWORD_INT (ival)")))
(define_constraint "O"
"@internal
A constant in the range [-128, 127]."
(and (match_code "const_int")
(match_test "SBYTE_INT (ival)")))
(define_constraint "P"
"@internal
A constant 1."
(and (match_code "const_int")
(match_test "ival == 1")))
(define_constraint "T"
"A text segment (program memory) constant label."
(match_test "text_segment_operand (op, VOIDmode)"))
(define_constraint "Z"
"An integer constant zero."
(and (match_code "const_int")
(match_test "ival == 0")))

View File

@ -0,0 +1,287 @@
;; Predicate definitions for TI PRU.
;; Copyright (C) 2014-2019 Free Software Foundation, Inc.
;; Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
;;
;; This file is part of GCC.
;;
;; GCC is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;;
;; GCC is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GCC; see the file COPYING3. If not see
;; <http://www.gnu.org/licenses/>.
(define_predicate "const_1_operand"
(and (match_code "const_int")
(match_test "INTVAL (op) == 1")))
; Note: Always pass a valid mode!
(define_predicate "const_ubyte_operand"
(match_code "const_int")
{
gcc_assert (mode != VOIDmode);
return IN_RANGE (INTVAL (op) & GET_MODE_MASK (mode), 0, 0xff);
})
(define_predicate "const_uhword_operand"
(match_code "const_int")
{
gcc_assert (mode != VOIDmode);
return IN_RANGE (INTVAL (op) & GET_MODE_MASK (mode), 0, 0xffff);
})
; TRUE for comparisons we support.
(define_predicate "pru_cmp_operator"
(match_code "eq,ne,leu,ltu,geu,gtu"))
; TRUE for signed comparisons that need special handling for PRU.
(define_predicate "pru_signed_cmp_operator"
(match_code "ge,gt,le,lt"))
;; FP Comparisons handled by pru_expand_pru_compare.
(define_predicate "pru_fp_comparison_operator"
(match_code "eq,ne,lt,gt,le,ge"))
;; Return true if OP is a constant that contains only one 1 in its
;; binary representation.
(define_predicate "single_one_operand"
(and (match_code "const_int")
(match_test "exact_log2 (INTVAL (op) & GET_MODE_MASK (mode)) >= 0")))
;; Return true if OP is a constant that contains only one 0 in its
;; binary representation.
(define_predicate "single_zero_operand"
(and (match_code "const_int")
(match_test "exact_log2 (~INTVAL (op) & GET_MODE_MASK (mode)) >= 0")))
(define_predicate "pru_muldst_operand"
(match_code "subreg,reg")
{
if (register_operand (op, mode))
{
int regno;
if (REG_P (op))
regno = REGNO (op);
else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
regno = REGNO (SUBREG_REG (op));
else
return 0;
return REGNO_REG_CLASS (regno) == MULDST_REGS
|| regno >= FIRST_PSEUDO_REGISTER;
}
return 0;
})
(define_predicate "pru_mulsrc0_operand"
(match_code "subreg,reg")
{
if (register_operand (op, mode))
{
int regno;
if (REG_P (op))
regno = REGNO (op);
else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
regno = REGNO (SUBREG_REG (op));
else
return 0;
return REGNO_REG_CLASS (regno) == MULSRC0_REGNUM
|| regno >= FIRST_PSEUDO_REGISTER;
}
return 0;
})
(define_predicate "pru_mulsrc1_operand"
(match_code "subreg,reg")
{
if (register_operand (op, mode))
{
int regno;
if (REG_P (op))
regno = REGNO (op);
else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
regno = REGNO (SUBREG_REG (op));
else
return 0;
return REGNO_REG_CLASS (regno) == MULSRC1_REGNUM
|| regno >= FIRST_PSEUDO_REGISTER;
}
return 0;
})
(define_predicate "reg_or_const_int_operand"
(ior (match_operand 0 "const_int_operand")
(match_operand 0 "register_operand")))
(define_predicate "reg_or_ubyte_operand"
(ior (match_operand 0 "const_ubyte_operand")
(match_operand 0 "register_operand")))
(define_predicate "reg_or_const_1_operand"
(ior (match_operand 0 "const_1_operand")
(match_operand 0 "register_operand")))
(define_predicate "const_shift_operand"
(and (match_code "const_int")
(match_test "SHIFT_INT (INTVAL (op))")))
(define_predicate "shift_operand"
(ior (match_operand 0 "const_shift_operand")
(match_operand 0 "register_operand")))
(define_predicate "ctable_addr_operand"
(and (match_code "const_int")
(match_test "pru_get_ctable_base_index (INTVAL (op)) >= 0")))
(define_predicate "ctable_base_operand"
(and (match_code "const_int")
(match_test "pru_get_ctable_exact_base_index (INTVAL (op)) >= 0")))
;; Ideally we should enforce a restriction to all text labels to fit in
;; 16bits, as required by the PRU ISA. But for the time being we'll rely on
;; binutils to catch text segment overflows.
(define_predicate "call_operand"
(ior (match_operand 0 "immediate_operand")
(match_operand 0 "register_operand")))
;; Return true if OP is a text segment reference.
;; This is needed for program memory address expressions. Borrowed from AVR.
(define_predicate "text_segment_operand"
(match_code "code_label,label_ref,symbol_ref,plus,minus")
{
poly_int64 offset;
rtx base = strip_offset (op, &offset);
switch (GET_CODE (base))
{
case CODE_LABEL:
/* Why AVR lists this as a valid option? Let's catch it. */
gcc_unreachable ();
return false;
case LABEL_REF:
return true;
case SYMBOL_REF:
return SYMBOL_REF_FUNCTION_P (base);
case PLUS:
case MINUS:
/* Handle constructs like (&&label1 - &&label2). See pr70460.c. */
return text_segment_operand (XEXP (op, 0), VOIDmode);
default:
return false;
}
})
;; Return true if OP is a load multiple operation. It is known to be a
;; PARALLEL and the first section will be tested.
(define_special_predicate "load_multiple_operation"
(match_code "parallel")
{
machine_mode elt_mode;
int count = XVECLEN (op, 0);
unsigned int dest_regno;
rtx src_addr, base_reg;
poly_int64 base_offs;
int i;
/* Perform a quick check so we don't blow up below. */
if (GET_CODE (XVECEXP (op, 0, 0)) != SET
|| GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
|| GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
return false;
dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
elt_mode = GET_MODE (SET_DEST (XVECEXP (op, 0, 0)));
base_reg = strip_offset (src_addr, &base_offs);
if (GET_CODE (base_reg) != REG)
return false;
for (i = 1; i < count; i++)
{
rtx elt_reg;
poly_int64 elt_offs;
rtx elt = XVECEXP (op, 0, i);
if (GET_CODE (elt) != SET
|| GET_CODE (SET_DEST (elt)) != REG
|| GET_MODE (SET_DEST (elt)) != elt_mode
|| REGNO (SET_DEST (elt)) != dest_regno + i * GET_MODE_SIZE (elt_mode)
|| GET_CODE (SET_SRC (elt)) != MEM
|| GET_MODE (SET_SRC (elt)) != elt_mode)
return false;
elt_reg = strip_offset (XEXP (SET_SRC (elt), 0), &elt_offs);
if (GET_CODE (elt_reg) != REG
|| ! rtx_equal_p (elt_reg, base_reg)
|| elt_offs != base_offs + i * GET_MODE_SIZE (elt_mode))
return false;
}
return true;
})
;; Return true if OP is a store multiple operation. It is known to be a
;; PARALLEL and the first section will be tested.
(define_special_predicate "store_multiple_operation"
(match_code "parallel")
{
machine_mode elt_mode;
int count = XVECLEN (op, 0);
unsigned int src_regno;
rtx dest_addr, base_reg;
poly_int64 base_offs;
int i;
/* Perform a quick check so we don't blow up below. */
if (GET_CODE (XVECEXP (op, 0, 0)) != SET
|| GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
|| GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
return false;
src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
elt_mode = GET_MODE (SET_SRC (XVECEXP (op, 0, 0)));
base_reg = strip_offset (dest_addr, &base_offs);
if (GET_CODE (base_reg) != REG)
return false;
for (i = 1; i < count; i++)
{
rtx elt_reg;
poly_int64 elt_offs;
rtx elt = XVECEXP (op, 0, i);
if (GET_CODE (elt) != SET
|| GET_CODE (SET_SRC (elt)) != REG
|| GET_MODE (SET_SRC (elt)) != elt_mode
|| REGNO (SET_SRC (elt)) != src_regno + i * GET_MODE_SIZE (elt_mode)
|| GET_CODE (SET_DEST (elt)) != MEM
|| GET_MODE (SET_DEST (elt)) != elt_mode)
return false;
elt_reg = strip_offset (XEXP (SET_DEST (elt), 0), &elt_offs);
if (GET_CODE (elt_reg) != REG
|| ! rtx_equal_p (elt_reg, base_reg)
|| elt_offs != base_offs + i * GET_MODE_SIZE (elt_mode))
return false;
}
return true;
})

31
gcc/config/pru/pru-opts.h Normal file
View File

@ -0,0 +1,31 @@
/* Copyright (C) 2017-2019 Free Software Foundation, Inc.
Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
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/>. */
/* Definitions for option handling for PRU. */
#ifndef GCC_PRU_OPTS_H
#define GCC_PRU_OPTS_H
/* ABI variant for code generation. */
enum pru_abi {
PRU_ABI_GNU,
PRU_ABI_TI
};
#endif

228
gcc/config/pru/pru-passes.c Normal file
View File

@ -0,0 +1,228 @@
/* PRU target specific passes
Copyright (C) 2017-2019 Free Software Foundation, Inc.
Dimitar Dimitrov <dimitar@dinux.eu>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3, or (at your
option) any later version.
GCC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#define IN_TARGET_CODE 1
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "backend.h"
#include "context.h"
#include "tm.h"
#include "alias.h"
#include "symtab.h"
#include "tree.h"
#include "diagnostic-core.h"
#include "function.h"
#include "gimple.h"
#include "gimple-iterator.h"
#include "gimple-walk.h"
#include "gimple-expr.h"
#include "tree-pass.h"
#include "pru-protos.h"
namespace {
/* Scan the tree to ensure that the compiled code by GCC
conforms to the TI ABI specification. If GCC cannot
output a conforming code, raise an error. */
const pass_data pass_data_tiabi_check =
{
GIMPLE_PASS, /* type */
"*tiabi_check", /* name */
OPTGROUP_NONE, /* optinfo_flags */
TV_NONE, /* tv_id */
PROP_gimple_any, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
};
/* Implementation class for the TI ABI compliance-check pass. */
class pass_tiabi_check : public gimple_opt_pass
{
public:
pass_tiabi_check (gcc::context *ctxt)
: gimple_opt_pass (pass_data_tiabi_check, ctxt)
{}
/* opt_pass methods: */
virtual unsigned int execute (function *);
virtual bool gate (function *fun ATTRIBUTE_UNUSED)
{
return pru_current_abi == PRU_ABI_TI;
}
}; // class pass_tiabi_check
/* Return 1 if type TYPE is a pointer to function type or a
structure having a pointer to function type as one of its fields.
Otherwise return 0. */
static bool
chkp_type_has_function_pointer (const_tree type)
{
bool res = false;
if (POINTER_TYPE_P (type) && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (type)))
res = true;
else if (RECORD_OR_UNION_TYPE_P (type))
{
tree field;
for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL)
res = res || chkp_type_has_function_pointer (TREE_TYPE (field));
}
else if (TREE_CODE (type) == ARRAY_TYPE)
res = chkp_type_has_function_pointer (TREE_TYPE (type));
return res;
}
/* Check the function declaration FNTYPE for TI ABI compatibility. */
static void
chk_function_decl (const_tree fntype, location_t call_location)
{
/* GCC does not check if the RETURN VALUE pointer is NULL,
so do not allow GCC functions with large return values. */
if (!VOID_TYPE_P (TREE_TYPE (fntype))
&& pru_return_in_memory (TREE_TYPE (fntype), fntype))
error_at (call_location,
"large return values not supported with %<-mabi=ti%> option");
/* Check this function's arguments. */
for (tree p = TYPE_ARG_TYPES (fntype); p; p = TREE_CHAIN (p))
{
tree arg_type = TREE_VALUE (p);
if (chkp_type_has_function_pointer (arg_type))
error_at (call_location,
"function pointers not supported with %<-mabi=ti%> option");
}
}
/* Callback for walk_gimple_seq that checks TP tree for TI ABI compliance. */
static tree
check_op_callback (tree *tp, int *walk_subtrees, void *data)
{
struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
if (RECORD_OR_UNION_TYPE_P (*tp) || TREE_CODE (*tp) == ENUMERAL_TYPE)
{
/* Forward declarations have NULL tree type. Skip them. */
if (TREE_TYPE (*tp) == NULL)
return NULL;
}
/* TODO - why C++ leaves INTEGER_TYPE forward declarations around? */
if (TREE_TYPE (*tp) == NULL)
return NULL;
const tree type = TREE_TYPE (*tp);
/* Direct function calls are allowed, obviously. */
gcall *call = dyn_cast <gcall *> (gsi_stmt (wi->gsi));
if (call
&& tp == gimple_call_fn_ptr (call)
&& gimple_call_fndecl (call))
return NULL;
switch (TREE_CODE (type))
{
case FUNCTION_TYPE:
case METHOD_TYPE:
{
/* Note: Do not enforce a small return value. It is safe to
call any TI ABI function from GCC, since GCC will
never pass NULL. */
/* Check arguments for function pointers. */
for (tree p = TYPE_ARG_TYPES (type); p; p = TREE_CHAIN (p))
{
tree arg_type = TREE_VALUE (p);
if (chkp_type_has_function_pointer (arg_type))
error_at (gimple_location (wi->stmt), "function pointers "
"not supported with %<-mabi=ti%> option");
}
break;
}
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
case POINTER_TYPE:
{
if (chkp_type_has_function_pointer (type))
{
error_at (gimple_location (wi->stmt),
"function pointers not supported with "
"%<-mabi=ti%> option");
*walk_subtrees = false;
}
break;
}
default:
break;
}
return NULL;
}
/* Pass implementation. */
unsigned
pass_tiabi_check::execute (function *fun)
{
struct walk_stmt_info wi;
const_tree fntype = TREE_TYPE (fun->decl);
gimple_seq body = gimple_body (current_function_decl);
memset (&wi, 0, sizeof (wi));
wi.info = NULL;
wi.want_locations = true;
/* Check the function body. */
walk_gimple_seq (body, NULL, check_op_callback, &wi);
/* Check the function declaration. */
chk_function_decl (fntype, fun->function_start_locus);
return 0;
}
} // anon namespace
gimple_opt_pass *
make_pass_tiabi_check (gcc::context *ctxt)
{
return new pass_tiabi_check (ctxt);
}
/* Register as early as possible. */
void
pru_register_abicheck_pass (void)
{
opt_pass *tiabi_check = make_pass_tiabi_check (g);
struct register_pass_info tiabi_check_info
= { tiabi_check, "*warn_unused_result",
1, PASS_POS_INSERT_AFTER
};
register_pass (&tiabi_check_info);
}

View File

@ -0,0 +1,86 @@
/* PRU target specific pragmas
Copyright (C) 2015-2019 Free Software Foundation, Inc.
Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3, or (at your
option) any later version.
GCC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#define IN_TARGET_CODE 1
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "alias.h"
#include "symtab.h"
#include "tree.h"
#include "c-family/c-pragma.h"
#include "c-family/c-common.h"
#include "diagnostic-core.h"
#include "cpplib.h"
#include "pru-protos.h"
/* Implements the "pragma CTABLE_ENTRY" pragma. This pragma takes a
CTABLE index and an address, and instructs the compiler that
LBCO/SBCO can be used on that base address.
WARNING: Only immediate constant addresses are currently supported. */
static void
pru_pragma_ctable_entry (cpp_reader * reader ATTRIBUTE_UNUSED)
{
tree ctable_index, base_addr;
enum cpp_ttype type;
type = pragma_lex (&ctable_index);
if (type == CPP_NUMBER && tree_fits_uhwi_p (ctable_index))
{
type = pragma_lex (&base_addr);
if (type == CPP_NUMBER && tree_fits_uhwi_p (base_addr))
{
unsigned HOST_WIDE_INT i = tree_to_uhwi (ctable_index);
unsigned HOST_WIDE_INT base = tree_to_uhwi (base_addr);
type = pragma_lex (&base_addr);
if (type != CPP_EOF)
error ("junk at end of %<#pragma CTABLE_ENTRY%>");
else if (i >= ARRAY_SIZE (pru_ctable))
error ("%<CTABLE_ENTRY%> index %" HOST_WIDE_INT_PRINT "d"
" is not valid", i);
else if (pru_ctable[i].valid && pru_ctable[i].base != base)
error ("redefinition of %<CTABLE_ENTRY "
"%" HOST_WIDE_INT_PRINT "d%>", i);
else
{
if (base & 0xff)
warning (0, "%<CTABLE_ENTRY%> base address is not "
"a multiple of 256");
pru_ctable[i].base = base;
pru_ctable[i].valid = true;
}
return;
}
}
error ("malformed %<#pragma CTABLE_ENTRY%> variable address");
}
/* Implements REGISTER_TARGET_PRAGMAS. */
void
pru_register_pragmas (void)
{
c_register_pragma (NULL, "ctable_entry", pru_pragma_ctable_entry);
c_register_pragma (NULL, "CTABLE_ENTRY", pru_pragma_ctable_entry);
}

View File

@ -0,0 +1,72 @@
/* Subroutine declarations for TI PRU target support.
Copyright (C) 2014-2019 Free Software Foundation, Inc.
Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
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_PRU_PROTOS_H
#define GCC_PRU_PROTOS_H
struct pru_ctable_entry {
bool valid;
unsigned HOST_WIDE_INT base;
};
extern struct pru_ctable_entry pru_ctable[32];
extern int pru_initial_elimination_offset (int, int);
extern int pru_can_use_return_insn (void);
extern void pru_expand_prologue (void);
extern void pru_expand_epilogue (bool);
extern void pru_function_profiler (FILE *, int);
void pru_register_pragmas (void);
#ifdef RTX_CODE
extern rtx pru_get_return_address (int);
extern int pru_hard_regno_rename_ok (unsigned int, unsigned int);
extern const char *pru_output_sign_extend (rtx *);
extern const char *pru_output_signed_cbranch (rtx *, bool);
extern const char *pru_output_signed_cbranch_ubyteop2 (rtx *, bool);
extern const char *pru_output_signed_cbranch_zeroop2 (rtx *, bool);
extern rtx pru_expand_fp_compare (rtx comparison, machine_mode mode);
extern void pru_emit_doloop (rtx *, int);
extern bool pru_regno_ok_for_base_p (int, bool);
static inline bool
pru_regno_ok_for_index_p (int regno, bool strict_p)
{
/* Selection logic is the same - PRU instructions are quite orthogonal. */
return pru_regno_ok_for_base_p (regno, strict_p);
}
extern int pru_get_ctable_exact_base_index (unsigned HOST_WIDE_INT caddr);
extern int pru_get_ctable_base_index (unsigned HOST_WIDE_INT caddr);
extern int pru_get_ctable_base_offset (unsigned HOST_WIDE_INT caddr);
extern void pru_register_abicheck_pass (void);
#endif /* RTX_CODE */
#ifdef TREE_CODE
extern bool pru_return_in_memory (const_tree type, const_tree fntype);
#endif /* TREE_CODE */
#endif /* GCC_PRU_PROTOS_H */

3036
gcc/config/pru/pru.c Normal file

File diff suppressed because it is too large Load Diff

573
gcc/config/pru/pru.h Normal file
View File

@ -0,0 +1,573 @@
/* Definitions of target machine for TI PRU.
Copyright (C) 2014-2019 Free Software Foundation, Inc.
Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
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_PRU_H
#define GCC_PRU_H
#include "config/pru/pru-opts.h"
/* Define built-in preprocessor macros. */
#define TARGET_CPU_CPP_BUILTINS() \
do \
{ \
builtin_define_std ("__PRU__"); \
builtin_define_std ("__pru__"); \
builtin_define_std ("__PRU_V3__"); \
builtin_define_std ("__LITTLE_ENDIAN__"); \
builtin_define_std ("__little_endian__"); \
/* Trampolines are disabled for now. */ \
builtin_define_std ("NO_TRAMPOLINES"); \
} \
while (0)
/* TI ABI implementation is not feature-complete enough (e.g. function
pointers are not supported), so we cannot list it as a multilib variant.
To prevent misuse from users, do not link any of the standard libraries. */
#define DRIVER_SELF_SPECS \
"%{mabi=ti:-nodefaultlibs} " \
"%{mmcu=*:-specs=device-specs/%*%s %<mmcu=*} "
#undef CPP_SPEC
#define CPP_SPEC \
"%(cpp_device) " \
"%{mabi=ti:-D__PRU_EABI_TI__; :-D__PRU_EABI_GNU__}"
/* Do not relax when in TI ABI mode since TI tools do not always
put PRU_S10_PCREL. */
#undef LINK_SPEC
#define LINK_SPEC \
"%(link_device) " \
"%{mabi=ti:--no-relax;:%{mno-relax:--no-relax;:--relax}} " \
"%{shared:%eshared is not supported} "
/* CRT0 is carefully maintained to be compatible with both GNU and TI ABIs. */
#undef STARTFILE_SPEC
#define STARTFILE_SPEC \
"%{!pg:%{minrt:crt0-minrt.o%s}%{!minrt:crt0.o%s}} %{!mabi=ti:-lgcc} "
#undef ENDFILE_SPEC
#define ENDFILE_SPEC "%{!mabi=ti:-lgloss} "
/* TI ABI mandates that ELF symbols do not start with any prefix. */
#undef USER_LABEL_PREFIX
#define USER_LABEL_PREFIX ""
#undef LOCAL_LABEL_PREFIX
#define LOCAL_LABEL_PREFIX ".L"
/* Storage layout. */
#define DEFAULT_SIGNED_CHAR 0
#define BITS_BIG_ENDIAN 0
#define BYTES_BIG_ENDIAN 0
#define WORDS_BIG_ENDIAN 0
/* PRU is represented in GCC as an 8-bit CPU with fast 16-bit and 32-bit
arithmetic. */
#define BITS_PER_WORD 8
#ifdef IN_LIBGCC2
/* This is to get correct SI and DI modes in libgcc2.c (32 and 64 bits). */
#define UNITS_PER_WORD 4
#else
/* Width of a word, in units (bytes). */
#define UNITS_PER_WORD 1
#endif
#define POINTER_SIZE 32
#define BIGGEST_ALIGNMENT 8
#define STRICT_ALIGNMENT 0
#define FUNCTION_BOUNDARY 8 /* Func pointers are word-addressed. */
#define PARM_BOUNDARY 8
#define STACK_BOUNDARY 8
#define MAX_FIXED_MODE_SIZE 64
#define POINTERS_EXTEND_UNSIGNED 1
/* 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 DOUBLE_TYPE_SIZE
#undef SIZE_TYPE
#define SIZE_TYPE "unsigned int"
#undef PTRDIFF_TYPE
#define PTRDIFF_TYPE "int"
/* Basic characteristics of PRU registers:
Regno Name
0 r0 Caller Saved. Also used as a static chain register.
1 r1 Caller Saved. Also used as a temporary by function.
profiler and function prologue/epilogue.
2 r2 sp Stack Pointer.
3* r3.w0 ra Return Address (16-bit).
4 r4 fp Frame Pointer, also called Argument Pointer in ABI.
5-13 r5-r13 Callee Saved Registers.
14-29 r14-r29 Register Arguments. Caller Saved Registers.
14-15 r14-r15 Return Location.
30 r30 Special I/O register. Not used by compiler.
31 r31 Special I/O register. Not used by compiler.
32 loop_cntr Internal register used as a counter by LOOP insns.
33 pc Not an actual register.
34 fake_fp Fake Frame Pointer (always eliminated).
35 fake_ap Fake Argument Pointer (always eliminated).
36 First Pseudo Register.
The definitions for some hard register numbers are located in pru.md.
Note that GCC's internal register numbering differs from the conventional
register naming in PRU ISA. PRU ISA defines word-based register numbers
and sub-register suffixes (e.g. RA is r3.w0). GCC uses linear numbering
of 8 bit sub-registers (e.g. RA starts at r12). When outputting assembly,
GCC will take into account the RTL operand size (e.g. r12:HI) in order to
translate to the conventional PRU ISA format expected by GAS (r3.w0).
*/
#define FIXED_REGISTERS \
{ \
/* 0 */ 0,0,0,0, 0,0,0,0, 1,1,1,1, 1,1,1,1, \
/* 4 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, \
/* 8 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, \
/* 12 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, \
/* 16 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, \
/* 20 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, \
/* 24 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, \
/* 28 */ 0,0,0,0, 0,0,0,0, 1,1,1,1, 1,1,1,1, \
/* 32 */ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1 \
}
/* Call used == caller saved + fixed regs + args + ret vals. */
#define CALL_USED_REGISTERS \
{ \
/* 0 */ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, \
/* 4 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, \
/* 8 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, \
/* 12 */ 0,0,0,0, 0,0,0,0, 1,1,1,1, 1,1,1,1, \
/* 16 */ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, \
/* 20 */ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, \
/* 24 */ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, \
/* 28 */ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, \
/* 32 */ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1 \
}
#define PRU_SEQ_R(X) (X) * 4 + 0, (X) * 4 + 1, (X) * 4 + 2, (X) * 4 + 3
#define REG_ALLOC_ORDER \
{ \
/* Call-clobbered, yet not used for parameters. */ \
PRU_SEQ_R (0), PRU_SEQ_R ( 1), \
\
PRU_SEQ_R (14), PRU_SEQ_R (15), PRU_SEQ_R (16), PRU_SEQ_R (17), \
PRU_SEQ_R (18), PRU_SEQ_R (19), PRU_SEQ_R (20), PRU_SEQ_R (21), \
PRU_SEQ_R (22), PRU_SEQ_R (23), PRU_SEQ_R (24), PRU_SEQ_R (25), \
PRU_SEQ_R (26), PRU_SEQ_R (27), PRU_SEQ_R (28), PRU_SEQ_R (29), \
\
PRU_SEQ_R ( 5), PRU_SEQ_R ( 6), PRU_SEQ_R ( 7), PRU_SEQ_R ( 8), \
PRU_SEQ_R ( 9), PRU_SEQ_R (10), PRU_SEQ_R (11), PRU_SEQ_R (12), \
PRU_SEQ_R (13), \
\
PRU_SEQ_R ( 4), \
PRU_SEQ_R ( 2), PRU_SEQ_R ( 3), \
\
/* I/O and virtual registers. */ \
PRU_SEQ_R (30), PRU_SEQ_R (31), PRU_SEQ_R (32), PRU_SEQ_R (33), \
PRU_SEQ_R (34), PRU_SEQ_R (35) \
}
/* Register Classes. */
enum reg_class
{
NO_REGS,
SIB_REGS,
LOOPCNTR_REGS,
MULDST_REGS,
MULSRC0_REGS,
MULSRC1_REGS,
GP_REGS,
ALL_REGS,
LIM_REG_CLASSES
};
#define N_REG_CLASSES (int) LIM_REG_CLASSES
#define REG_CLASS_NAMES \
{ "NO_REGS", \
"SIB_REGS", \
"LOOPCNTR_REGS", \
"MULDST_REGS", \
"MULSRC0_REGS", \
"MULSRC1_REGS", \
"GP_REGS", \
"ALL_REGS" }
#define GENERAL_REGS ALL_REGS
#define REG_CLASS_CONTENTS \
{ \
/* NO_REGS */ { 0, 0, 0, 0, 0}, \
/* SIB_REGS */ { 0xf, 0xff000000, ~0, 0xffffff, 0}, \
/* LOOPCNTR_REGS */ { 0, 0, 0, 0, 0xf}, \
/* MULDST_REGS */ { 0, 0, 0, 0x00000f00, 0}, \
/* MULSRC0_REGS */ { 0, 0, 0, 0x000f0000, 0}, \
/* MULSRC1_REGS */ { 0, 0, 0, 0x00f00000, 0}, \
/* GP_REGS */ { ~0, ~0, ~0, ~0, 0}, \
/* ALL_REGS */ { ~0,~0, ~0, ~0, ~0} \
}
#define GP_REG_P(REGNO) ((unsigned)(REGNO) <= LAST_GP_REGNUM)
#define REGNO_REG_CLASS(REGNO) \
((REGNO) == MULDST_REGNUM ? MULDST_REGS \
: (REGNO) == MULSRC0_REGNUM ? MULSRC0_REGS \
: (REGNO) == MULSRC1_REGNUM ? MULSRC1_REGS \
: (REGNO) >= FIRST_ARG_REGNUM \
&& (REGNO) <= LAST_ARG_REGNUM ? SIB_REGS \
: (REGNO) == STATIC_CHAIN_REGNUM ? SIB_REGS \
: (REGNO) == LOOPCNTR_REGNUM ? LOOPCNTR_REGS \
: (REGNO) <= LAST_NONIO_GP_REGNUM ? GP_REGS \
: ALL_REGS)
#define CLASS_MAX_NREGS(CLASS, MODE) \
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
/* Arbitrarily set to a non-argument register. Not defined by TI ABI. */
#define STATIC_CHAIN_REGNUM 0 /* r0 */
/* Tests for various kinds of constants used in the PRU port. */
#define SHIFT_INT(X) (IN_RANGE ((X), 0, 31))
#define UHWORD_INT(X) (IN_RANGE ((X), 0, 0xffff))
#define SHWORD_INT(X) (IN_RANGE ((X), -32768, 32767))
#define UBYTE_INT(X) (IN_RANGE ((X), 0, 0xff))
#define SBYTE_INT(X) (IN_RANGE ((X), -128, 127))
/* Say that the epilogue uses the return address register. Note that
in the case of sibcalls, the values "used by the epilogue" are
considered live at the start of the called function. */
#define EPILOGUE_USES(REGNO) (epilogue_completed \
&& (((REGNO) == RA_REGNUM) \
|| (REGNO) == (RA_REGNUM + 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 1
/* Trampolines are not supported, but put a define to keep the build. */
#define TRAMPOLINE_SIZE 4
/* Stack layout. */
#define STACK_GROWS_DOWNWARD 1
#undef FRAME_GROWS_DOWNWARD
#define FIRST_PARM_OFFSET(FUNDECL) 0
/* Before the prologue, RA lives in r3.w2. */
#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (HImode, RA_REGNUM)
#define RETURN_ADDR_RTX(C,F) pru_get_return_address (C)
#define DWARF_FRAME_RETURN_COLUMN RA_REGNUM
/* The CFA includes the pretend args. */
#define ARG_POINTER_CFA_OFFSET(FNDECL) \
(gcc_assert ((FNDECL) == current_function_decl), \
FIRST_PARM_OFFSET (FNDECL) + crtl->args.pretend_args_size)
/* Frame/arg pointer elimination settings. */
#define ELIMINABLE_REGS \
{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \
{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
(OFFSET) = pru_initial_elimination_offset ((FROM), (TO))
#define HARD_REGNO_RENAME_OK(OLD_REG, NEW_REG) \
pru_hard_regno_rename_ok (OLD_REG, NEW_REG)
/* Calling convention definitions. */
#if !defined(IN_LIBGCC2)
#define NUM_ARG_REGS (LAST_ARG_REGNUM - FIRST_ARG_REGNUM + 1)
typedef struct pru_args
{
bool regs_used[NUM_ARG_REGS];
} CUMULATIVE_ARGS;
#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \
do { \
memset ((CUM).regs_used, 0, sizeof ((CUM).regs_used)); \
} while (0)
#define FUNCTION_ARG_REGNO_P(REGNO) \
((REGNO) >= FIRST_ARG_REGNUM && (REGNO) <= LAST_ARG_REGNUM)
/* Passing function arguments on stack. */
#define PUSH_ARGS 0
#define ACCUMULATE_OUTGOING_ARGS 1
/* We define TARGET_RETURN_IN_MEMORY, so set to zero. */
#define DEFAULT_PCC_STRUCT_RETURN 0
/* Profiling. */
#define PROFILE_BEFORE_PROLOGUE
#define NO_PROFILE_COUNTERS 1
#define FUNCTION_PROFILER(FILE, LABELNO) \
pru_function_profiler ((FILE), (LABELNO))
#endif /* IN_LIBGCC2 */
/* Addressing modes. */
#define CONSTANT_ADDRESS_P(X) \
(CONSTANT_P (X) && memory_address_p (SImode, X))
#define MAX_REGS_PER_ADDRESS 2
#define BASE_REG_CLASS ALL_REGS
#define INDEX_REG_CLASS ALL_REGS
#define REGNO_OK_FOR_BASE_P(REGNO) pru_regno_ok_for_base_p ((REGNO), true)
#define REGNO_OK_FOR_INDEX_P(REGNO) pru_regno_ok_for_index_p ((REGNO), true)
/* Limited by the insns in pru-ldst-multiple.md. */
#define MOVE_MAX 8
#define SLOW_BYTE_ACCESS 1
/* It is as good to call a constant function address as to call an address
kept in a register. */
#define NO_FUNCTION_CSE 1
/* Define output assembler language. */
#define ASM_APP_ON "#APP\n"
#define ASM_APP_OFF "#NO_APP\n"
#define ASM_COMMENT_START "# "
#define GLOBAL_ASM_OP "\t.global\t"
#define PRU_NAME_R(X) X".b0", X".b1", X".b2", X".b3"
#define REGISTER_NAMES \
{ \
PRU_NAME_R ("r0"), \
PRU_NAME_R ("r1"), \
PRU_NAME_R ("r2"), \
PRU_NAME_R ("r3"), \
PRU_NAME_R ("r4"), \
PRU_NAME_R ("r5"), \
PRU_NAME_R ("r6"), \
PRU_NAME_R ("r7"), \
PRU_NAME_R ("r8"), \
PRU_NAME_R ("r9"), \
PRU_NAME_R ("r10"), \
PRU_NAME_R ("r11"), \
PRU_NAME_R ("r12"), \
PRU_NAME_R ("r13"), \
PRU_NAME_R ("r14"), \
PRU_NAME_R ("r15"), \
PRU_NAME_R ("r16"), \
PRU_NAME_R ("r17"), \
PRU_NAME_R ("r18"), \
PRU_NAME_R ("r19"), \
PRU_NAME_R ("r20"), \
PRU_NAME_R ("r21"), \
PRU_NAME_R ("r22"), \
PRU_NAME_R ("r23"), \
PRU_NAME_R ("r24"), \
PRU_NAME_R ("r25"), \
PRU_NAME_R ("r26"), \
PRU_NAME_R ("r27"), \
PRU_NAME_R ("r28"), \
PRU_NAME_R ("r29"), \
PRU_NAME_R ("r30"), \
PRU_NAME_R ("r31"), \
PRU_NAME_R ("loopcntr_reg"), \
PRU_NAME_R ("pc"), \
PRU_NAME_R ("fake_fp"), \
PRU_NAME_R ("fake_ap"), \
}
#define PRU_OVERLAP_R(X) \
{ "r" #X , X * 4 , 4 }, \
{ "r" #X ".w0", X * 4 + 0 , 2 }, \
{ "r" #X ".w1", X * 4 + 1 , 2 }, \
{ "r" #X ".w2", X * 4 + 2 , 2 }
#define OVERLAPPING_REGISTER_NAMES \
{ \
/* Aliases. */ \
{ "sp", 2 * 4, 4 }, \
{ "ra", 3 * 4, 2 }, \
{ "fp", 4 * 4, 4 }, \
PRU_OVERLAP_R (0), \
PRU_OVERLAP_R (1), \
PRU_OVERLAP_R (2), \
PRU_OVERLAP_R (3), \
PRU_OVERLAP_R (4), \
PRU_OVERLAP_R (5), \
PRU_OVERLAP_R (6), \
PRU_OVERLAP_R (7), \
PRU_OVERLAP_R (8), \
PRU_OVERLAP_R (9), \
PRU_OVERLAP_R (10), \
PRU_OVERLAP_R (11), \
PRU_OVERLAP_R (12), \
PRU_OVERLAP_R (13), \
PRU_OVERLAP_R (14), \
PRU_OVERLAP_R (15), \
PRU_OVERLAP_R (16), \
PRU_OVERLAP_R (17), \
PRU_OVERLAP_R (18), \
PRU_OVERLAP_R (19), \
PRU_OVERLAP_R (20), \
PRU_OVERLAP_R (21), \
PRU_OVERLAP_R (22), \
PRU_OVERLAP_R (23), \
PRU_OVERLAP_R (24), \
PRU_OVERLAP_R (25), \
PRU_OVERLAP_R (26), \
PRU_OVERLAP_R (27), \
PRU_OVERLAP_R (28), \
PRU_OVERLAP_R (29), \
PRU_OVERLAP_R (30), \
PRU_OVERLAP_R (31), \
}
#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
do \
{ \
fputs (integer_asm_op (POINTER_SIZE / BITS_PER_UNIT, TRUE), FILE); \
fprintf (FILE, "%%pmem(.L%u)\n", (unsigned) (VALUE)); \
} \
while (0)
#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, BODY, VALUE, REL) \
do \
{ \
fputs (integer_asm_op (POINTER_SIZE / BITS_PER_UNIT, TRUE), STREAM); \
fprintf (STREAM, "%%pmem(.L%u-.L%u)\n", (unsigned) (VALUE), \
(unsigned) (REL)); \
} \
while (0)
/* Section directives. */
/* Output before read-only data. */
#define TEXT_SECTION_ASM_OP "\t.section\t.text"
/* Output before writable data. */
#define DATA_SECTION_ASM_OP "\t.section\t.data"
/* Output before uninitialized data. */
#define BSS_SECTION_ASM_OP "\t.section\t.bss"
#define CTORS_SECTION_ASM_OP "\t.section\t.init_array,\"aw\",%init_array"
#define DTORS_SECTION_ASM_OP "\t.section\t.fini_array,\"aw\",%fini_array"
#undef INIT_SECTION_ASM_OP
#undef FINI_SECTION_ASM_OP
#define INIT_ARRAY_SECTION_ASM_OP CTORS_SECTION_ASM_OP
#define FINI_ARRAY_SECTION_ASM_OP DTORS_SECTION_ASM_OP
/* Since we use .init_array/.fini_array we don't need the markers at
the start and end of the ctors/dtors arrays. */
#define CTOR_LIST_BEGIN asm (CTORS_SECTION_ASM_OP)
#define CTOR_LIST_END /* empty */
#define DTOR_LIST_BEGIN asm (DTORS_SECTION_ASM_OP)
#define DTOR_LIST_END /* empty */
#undef TARGET_ASM_CONSTRUCTOR
#define TARGET_ASM_CONSTRUCTOR pru_elf_asm_constructor
#undef TARGET_ASM_DESTRUCTOR
#define TARGET_ASM_DESTRUCTOR pru_elf_asm_destructor
#define ASM_OUTPUT_ALIGN(FILE, LOG) \
do { \
fprintf ((FILE), "%s%d\n", ALIGN_ASM_OP, (LOG)); \
} while (0)
#undef ASM_OUTPUT_ALIGNED_COMMON
#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \
do \
{ \
fprintf ((FILE), "%s", COMMON_ASM_OP); \
assemble_name ((FILE), (NAME)); \
fprintf ((FILE), "," HOST_WIDE_INT_PRINT_UNSIGNED ",%u\n", (SIZE), \
(ALIGN) / BITS_PER_UNIT); \
} \
while (0)
/* This says how to output assembler code to declare an
uninitialized internal linkage data object. Under SVR4,
the linker seems to want the alignment of data objects
to depend on their types. We do exactly that here. */
#undef ASM_OUTPUT_ALIGNED_LOCAL
#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
do { \
switch_to_section (bss_section); \
ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \
if (!flag_inhibit_size_directive) \
ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE); \
ASM_OUTPUT_ALIGN ((FILE), exact_log2 ((ALIGN) / BITS_PER_UNIT)); \
ASM_OUTPUT_LABEL (FILE, NAME); \
ASM_OUTPUT_SKIP ((FILE), (SIZE) ? (SIZE) : 1); \
} while (0)
/* Misc parameters. */
#define TARGET_SUPPORTS_WIDE_INT 1
#define STORE_FLAG_VALUE 1
#define Pmode SImode
#define FUNCTION_MODE Pmode
#define CASE_VECTOR_MODE Pmode
/* Jumps are cheap on PRU. */
#define LOGICAL_OP_NON_SHORT_CIRCUIT 0
/* Unfortunately the LBBO instruction does not zero-extend data. */
#undef LOAD_EXTEND_OP
#undef WORD_REGISTER_OPERATIONS
#define HAS_LONG_UNCOND_BRANCH 1
#define HAS_LONG_COND_BRANCH 1
#define REGISTER_TARGET_PRAGMAS() pru_register_pragmas ()
#endif /* GCC_PRU_H */

1022
gcc/config/pru/pru.md Normal file

File diff suppressed because it is too large Load Diff

54
gcc/config/pru/pru.opt Normal file
View File

@ -0,0 +1,54 @@
; Options for the TI PRU port of the compiler.
; Copyright (C) 2018-2019 Free Software Foundation, Inc.
; Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
;
; 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/>.
HeaderInclude
config/pru/pru-opts.h
minrt
Target Report Mask(MINRT) RejectNegative
Use a minimum runtime (no static initializers or ctors) for memory-constrained
devices.
mmcu=
Target RejectNegative Joined
-mmcu=MCU Select the target System-On-Chip variant that embeds this PRU.
mno-relax
Target Report RejectNegative
Make GCC pass the --no-relax command-line option to the linker instead of
the --relax option.
mloop
Target Mask(OPT_LOOP)
Allow (or do not allow) gcc to use the LOOP instruction.
mabi=
Target RejectNegative Report Joined Enum(pru_abi_t) Var(pru_current_abi) Init(PRU_ABI_GNU) Save
Select target ABI variant.
Enum
Name(pru_abi_t) Type(enum pru_abi)
ABI variant code generation (for use with -mabi= option):
EnumValue
Enum(pru_abi_t) String(gnu) Value(PRU_ABI_GNU)
EnumValue
Enum(pru_abi_t) String(ti) Value(PRU_ABI_TI)

31
gcc/config/pru/t-pru Normal file
View File

@ -0,0 +1,31 @@
# Makefile fragment for building GCC for the TI PRU target.
# Copyright (C) 2012-2019 Free Software Foundation, Inc.
# Contributed by Dimitar Dimitrov <dimitar.dinux.eu>
# Based on the t-nios2
#
# 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/>.
# Unfortunately mabi=ti is not feature-complete enough to build newlib.
# Hence we cannot present mabi=gnu/ti as a multilib option.
pru-pragma.o: $(srcdir)/config/pru/pru-pragma.c $(RTL_H) $(TREE_H) \
$(CONFIG_H) $(TM_H) $(srcdir)/config/pru/pru-protos.h
$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<
pru-passes.o: $(srcdir)/config/pru/pru-passes.c $(RTL_H) $(TREE_H) \
$(CONFIG_H) $(TM_H) $(srcdir)/config/pru/pru-protos.h
$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<

View File

@ -23039,6 +23039,7 @@ information.
* ARM Pragmas::
* M32C Pragmas::
* MeP Pragmas::
* PRU Pragmas::
* RS/6000 and PowerPC Pragmas::
* S/390 Pragmas::
* Darwin Pragmas::
@ -23190,6 +23191,26 @@ extern int foo ();
@end table
@node PRU Pragmas
@subsection PRU Pragmas
@table @code
@item ctable_entry @var{index} @var{constant_address}
@cindex pragma, ctable_entry
Specifies that the PRU CTABLE entry given by @var{index} has the value
@var{constant_address}. This enables GCC to emit LBCO/SBCO instructions
when the load/store address is known and can be addressed with some CTABLE
entry. For example:
@smallexample
/* will compile to "sbco Rx, 2, 0x10, 4" */
#pragma ctable_entry 2 0x4802a000
*(unsigned int *)0x4802a010 = val;
@end smallexample
@end table
@node RS/6000 and PowerPC Pragmas
@subsection RS/6000 and PowerPC Pragmas

View File

@ -1045,6 +1045,10 @@ Objective-C and Objective-C++ Dialects}.
@emph{PowerPC Options}
See RS/6000 and PowerPC Options.
@emph{PRU Options}
@gccoptlist{-mmcu=@var{mcu} -minrt -mno-relax -mloop @gol
-mabi=@var{variant} @gol}
@emph{RISC-V Options}
@gccoptlist{-mbranch-cost=@var{N-instruction} @gol
-mplt -mno-plt @gol
@ -15588,6 +15592,7 @@ platform.
* PDP-11 Options::
* picoChip Options::
* PowerPC Options::
* PRU Options::
* RISC-V Options::
* RL78 Options::
* RS/6000 and PowerPC Options::
@ -23763,6 +23768,66 @@ these warnings.
These are listed under @xref{RS/6000 and PowerPC Options}.
@node PRU Options
@subsection PRU Options
@cindex PRU Options
These command-line options are defined for PRU target:
@table @gcctabopt
@item -minrt
@opindex minrt
Link with a minimum runtime environment, with no support for static
initializers and constructors. Using this option can significantly reduce
the size of the final ELF binary. Beware that the compiler could still
generate code with static initializers and constructors. It is up to the
programmer to ensure that the source program will not use those features.
@item -mmcu=@var{mcu}
@opindex mmcu
Specify the PRU MCU variant to use. Check Newlib for the exact list of
supported MCUs.
@item -mno-relax
@opindex mno-relax
Make GCC pass the @option{--no-relax} command-line option to the linker
instead of the @option{--relax} option.
@item -mloop
@opindex mloop
Allow (or do not allow) GCC to use the LOOP instruction.
@item -mabi=@var{variant}
@opindex mabi
Specify the ABI variant to output code for. @option{-mabi=ti} selects the
unmodified TI ABI while @option{-mabi=gnu} selects a GNU variant that copes
more naturally with certain GCC assumptions. These are the differences:
@table @samp
@item Function Pointer Size
TI ABI specifies that function (code) pointers are 16-bit, whereas GNU
supports only 32-bit data and code pointers.
@item Optional Return Value Pointer
Function return values larger than 64 bits are passed by using a hidden
pointer as the first argument of the function. TI ABI, though, mandates that
the pointer can be NULL in case the caller is not using the returned value.
GNU always passes and expects a valid return value pointer.
@end table
The current @option{-mabi=ti} implementation simply raises a compile error
when any of the above code constructs is detected. As a consequence
the standard C library cannot be built and it is omitted when linking with
@option{-mabi=ti}.
Relaxation is a GNU feature and for safety reasons is disabled when using
@option{-mabi=ti}. The TI toolchain does not emit relocations for QBBx
instructions, so the GNU linker cannot adjust them when shortening adjacent
LDI32 pseudo instructions.
@end table
@node RISC-V Options
@subsection RISC-V Options
@cindex RISC-V Options

View File

@ -3400,6 +3400,25 @@ Vector constant that is all zeros.
@end table
@item PRU---@file{config/pru/constraints.md}
@table @code
@item I
An unsigned 8-bit integer constant.
@item J
An unsigned 16-bit integer constant.
@item L
An unsigned 5-bit integer constant (for shift counts).
@item T
A text segment (program memory) constant label.
@item Z
Integer constant zero.
@end table
@item RL78---@file{config/rl78/constraints.md}
@table @code