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:
parent
974b8e618b
commit
8d2af3a25b
@ -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
7
configure
vendored
@ -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
|
||||
;;
|
||||
|
@ -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
|
||||
;;
|
||||
|
@ -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
|
||||
|
36
gcc/common/config/pru/pru-common.c
Normal file
36
gcc/common/config/pru/pru-common.c
Normal 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;
|
@ -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
181
gcc/config/pru/alu-zext.md
Normal 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)))])
|
108
gcc/config/pru/constraints.md
Normal file
108
gcc/config/pru/constraints.md
Normal 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")))
|
287
gcc/config/pru/predicates.md
Normal file
287
gcc/config/pru/predicates.md
Normal 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
31
gcc/config/pru/pru-opts.h
Normal 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
228
gcc/config/pru/pru-passes.c
Normal 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);
|
||||
}
|
86
gcc/config/pru/pru-pragma.c
Normal file
86
gcc/config/pru/pru-pragma.c
Normal 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);
|
||||
}
|
72
gcc/config/pru/pru-protos.h
Normal file
72
gcc/config/pru/pru-protos.h
Normal 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
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
573
gcc/config/pru/pru.h
Normal 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
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
54
gcc/config/pru/pru.opt
Normal 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
31
gcc/config/pru/t-pru
Normal 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) $<
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user