Commit 8d2af3a2 by Dimitar Dimitrov Committed by Dimitar Dimitrov

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
parent 974b8e61
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.
......
......@@ -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
;;
......
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
......
/* 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"
......
;; 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)))])
;; 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")))
;; 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;
})
/* 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
/* 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);
}
/* 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);
}
/* 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 */
; 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)
# 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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment