From: Dimitar Dimitrov <dimitar@dinux.eu>
To: Richard Biener <richard.guenther@gmail.com>
Cc: GCC Patches <gcc-patches@gcc.gnu.org>
Subject: Re: [PATCH][RFC] pru: Named address space for R30/R31 I/O access
Date: Wed, 15 Sep 2021 22:04:50 +0300 [thread overview]
Message-ID: <YUJD0uGuroNOMWvr@kendros> (raw)
In-Reply-To: <CAFiYyc0Buk+tiga29GtD0TPzp+J1tqEjQMv_uphR-SAsor_zLA@mail.gmail.com>
On Wed, Sep 15, 2021 at 11:12:18AM +0200, Richard Biener wrote:
> On Tue, Sep 14, 2021 at 11:13 PM Dimitar Dimitrov <dimitar@dinux.eu> wrote:
> >
> > Hi,
> >
> > I'm sending this patch to get feedback for a new PRU CPU port feature.
> > My intention is to push it to master by end of September, so that it gets
> > included in GCC 12.
> >
> > The PRU architecture provides single-cycle access to GPIO pins via
> > special designated CPU registers - R30 and R31. These two registers can
> > of course be accessed in C code using inline assembly, but that can be
> > intimidating to users.
> >
> > The TI proprietary compiler [1] can expose these I/O registers as global
> > volatile registers:
> > volatile register unsigned int __R31;
> >
> > Consequently, accessing them in user programs is as straightforward as
> > using a regular global variable:
> > __R31 |= (1 << 2);
> >
> > Unfortunately, global volatile registers are not supported by GCC [2].
>
> Yes, a "register" write or read does not follow volatile semantics, so
> exposing those as registers isn't supported (I consider the GPIO regs
> similar to MSRs on other CPUs?).
Yes, they are a lot like MSRs.
>
> > I decided to implement convenient access to __R30 and __R31 using a new
> > named address space:
> > extern volatile __regio_symbol unsigned int __R30;
> >
> > Unlike global registers, volatile global memory variables are well
> > supported in GCC. Memory writes and reads to the __regio_symbol address
> > space are converted to writes and reads to R30 and R31 CPU registers.
> > The declared variable name determines which of the two registers it is
> > representing.
>
> I think that's reasonable. I do wonder whether it's possible to prevent
> taking the address of __R30 though - otherwise I guess the backend
> will crash or do weird things on such code?
I believe I have handled those cases, and suitable error messages are
emitted by the compiler. See the negative test cases added in
regio-as-pointer*.c and regio-decl*.c.
Thanks,
Dimitar
>
> > With an ifdef for the __R30/__R31 declarations, user programs can now
> > be source-compatible with both TI and GCC toolchains.
> >
> > [1] https://www.ti.com/lit/ug/spruhv7c/spruhv7c.pdf , "Global Register Variables"
> > [2] https://gcc.gnu.org/ml/gcc-patches/2015-01/msg02241.html
> >
> > gcc/ChangeLog:
> >
> > * config/pru/constraints.md (Rrio): New constraint.
> > * config/pru/predicates.md (regio_operand): New predicate.
> > * config/pru/pru-pragma.c (pru_register_pragmas): Register
> > the __regio_symbol address space.
> > * config/pru/pru-protos.h (pru_symref2ioregno): Declaration.
> > * config/pru/pru.c (pru_symref2ioregno): New helper function.
> > (pru_legitimate_address_p): Remove.
> > (pru_addr_space_legitimate_address_p): Use the address space
> > aware hook variant.
> > (pru_nongeneric_pointer_addrspace): New helper function.
> > (pru_insert_attributes): New function to validate __regio_symbol
> > usage.
> > (TARGET_INSERT_ATTRIBUTES): New macro.
> > (TARGET_LEGITIMATE_ADDRESS_P): Remove.
> > (TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P): New macro.
> > * config/pru/pru.h (enum reg_class): Add REGIO_REGS class.
> > * config/pru/pru.md (*regio_readsi): New pattern to read I/O
> > registers.
> > (*regio_nozext_writesi): New pattern to write to I/O registers.
> > (*regio_zext_write_r30<EQS0:mode>): Ditto.
> > * doc/extend.texi: Document the new PRU Named Address Space.
> >
> > gcc/testsuite/ChangeLog:
> >
> > * gcc.target/pru/regio-as-pointer.c: New negative test.
> > * gcc.target/pru/regio-as-pointer2.c: New negative test.
> > * gcc.target/pru/regio-decl-2.c: New negative test.
> > * gcc.target/pru/regio-decl-3.c: New negative test.
> > * gcc.target/pru/regio-decl-4.c: New negative test.
> > * gcc.target/pru/regio-decl.c: New negative test.
> > * gcc.target/pru/regio-di.c: New negative test.
> > * gcc.target/pru/regio-hi.c: New negative test.
> > * gcc.target/pru/regio-qi.c: New negative test.
> > * gcc.target/pru/regio.c: New test.
> > * gcc.target/pru/regio.h: New helper header.
> >
> > Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
> > ---
> > gcc/config/pru/constraints.md | 5 +
> > gcc/config/pru/predicates.md | 19 +++
> > gcc/config/pru/pru-pragma.c | 2 +
> > gcc/config/pru/pru-protos.h | 3 +
> > gcc/config/pru/pru.c | 155 +++++++++++++++++-
> > gcc/config/pru/pru.h | 5 +
> > gcc/config/pru/pru.md | 102 +++++++++++-
> > gcc/doc/extend.texi | 19 ++-
> > .../gcc.target/pru/regio-as-pointer.c | 11 ++
> > .../gcc.target/pru/regio-as-pointer2.c | 11 ++
> > gcc/testsuite/gcc.target/pru/regio-decl-2.c | 13 ++
> > gcc/testsuite/gcc.target/pru/regio-decl-3.c | 19 +++
> > gcc/testsuite/gcc.target/pru/regio-decl-4.c | 17 ++
> > gcc/testsuite/gcc.target/pru/regio-decl.c | 15 ++
> > gcc/testsuite/gcc.target/pru/regio-di.c | 9 +
> > gcc/testsuite/gcc.target/pru/regio-hi.c | 9 +
> > gcc/testsuite/gcc.target/pru/regio-qi.c | 9 +
> > gcc/testsuite/gcc.target/pru/regio.c | 58 +++++++
> > gcc/testsuite/gcc.target/pru/regio.h | 7 +
> > 19 files changed, 477 insertions(+), 11 deletions(-)
> > create mode 100644 gcc/testsuite/gcc.target/pru/regio-as-pointer.c
> > create mode 100644 gcc/testsuite/gcc.target/pru/regio-as-pointer2.c
> > create mode 100644 gcc/testsuite/gcc.target/pru/regio-decl-2.c
> > create mode 100644 gcc/testsuite/gcc.target/pru/regio-decl-3.c
> > create mode 100644 gcc/testsuite/gcc.target/pru/regio-decl-4.c
> > create mode 100644 gcc/testsuite/gcc.target/pru/regio-decl.c
> > create mode 100644 gcc/testsuite/gcc.target/pru/regio-di.c
> > create mode 100644 gcc/testsuite/gcc.target/pru/regio-hi.c
> > create mode 100644 gcc/testsuite/gcc.target/pru/regio-qi.c
> > create mode 100644 gcc/testsuite/gcc.target/pru/regio.c
> > create mode 100644 gcc/testsuite/gcc.target/pru/regio.h
> >
> > diff --git a/gcc/config/pru/constraints.md b/gcc/config/pru/constraints.md
> > index a31ae9318b8..1e0e703c394 100644
> > --- a/gcc/config/pru/constraints.md
> > +++ b/gcc/config/pru/constraints.md
> > @@ -34,6 +34,7 @@
> > ;; 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.
> > +;; Rrio: The R30 and R31 I/O registers.
> > ;; 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).
> > @@ -57,6 +58,10 @@ (define_register_constraint "Rms1" "MULSRC1_REGS"
> > "@internal
> > The multiply source 1 register.")
> >
> > +(define_register_constraint "Rrio" "REGIO_REGS"
> > + "@internal
> > + The R30 and R31 I/O registers.")
> > +
> > ;; Integer constraints.
> >
> > (define_constraint "I"
> > diff --git a/gcc/config/pru/predicates.md b/gcc/config/pru/predicates.md
> > index 469002f0567..1a4b98eb216 100644
> > --- a/gcc/config/pru/predicates.md
> > +++ b/gcc/config/pru/predicates.md
> > @@ -121,6 +121,25 @@ (define_predicate "pru_mulsrc1_operand"
> > return 0;
> > })
> >
> > +(define_predicate "regio_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) == REGIO_REGS;
> > + }
> > + return 0;
> > +})
> > +
> > (define_predicate "reg_or_const_int_operand"
> > (ior (match_operand 0 "const_int_operand")
> > (match_operand 0 "register_operand")))
> > diff --git a/gcc/config/pru/pru-pragma.c b/gcc/config/pru/pru-pragma.c
> > index 01d076101f1..3beec236be1 100644
> > --- a/gcc/config/pru/pru-pragma.c
> > +++ b/gcc/config/pru/pru-pragma.c
> > @@ -83,4 +83,6 @@ pru_register_pragmas (void)
> > {
> > c_register_pragma (NULL, "ctable_entry", pru_pragma_ctable_entry);
> > c_register_pragma (NULL, "CTABLE_ENTRY", pru_pragma_ctable_entry);
> > +
> > + c_register_addr_space ("__regio_symbol", ADDR_SPACE_REGIO);
> > }
> > diff --git a/gcc/config/pru/pru-protos.h b/gcc/config/pru/pru-protos.h
> > index 74129e9b9ed..031ea9e2fab 100644
> > --- a/gcc/config/pru/pru-protos.h
> > +++ b/gcc/config/pru/pru-protos.h
> > @@ -62,7 +62,10 @@ 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 int pru_symref2ioregno (rtx op);
> > +
> > extern void pru_register_abicheck_pass (void);
> > +
> > #endif /* RTX_CODE */
> >
> > #ifdef TREE_CODE
> > diff --git a/gcc/config/pru/pru.c b/gcc/config/pru/pru.c
> > index 30d0da194ce..341be5a0ecd 100644
> > --- a/gcc/config/pru/pru.c
> > +++ b/gcc/config/pru/pru.c
> > @@ -1403,11 +1403,42 @@ pru_valid_addr_expr_p (machine_mode mode, rtx base, rtx offset, bool strict_p)
> > return false;
> > }
> >
> > -/* Implement TARGET_LEGITIMATE_ADDRESS_P. */
> > +/* Return register number (either for r30 or r31) which maps to the
> > + corresponding symbol OP's name in the __regio_symbol address namespace.
> > +
> > + If no mapping can be established (i.e. symbol name is invalid), then
> > + return -1. */
> > +int pru_symref2ioregno (rtx op)
> > +{
> > + if (!SYMBOL_REF_P (op))
> > + return -1;
> > +
> > + const char *name = XSTR (op, 0);
> > + if (!strcmp (name, "__R30"))
> > + return R30_REGNUM;
> > + else if (!strcmp (name, "__R31"))
> > + return R31_REGNUM;
> > + else
> > + return -1;
> > +}
> > +
> > +/* Implement TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P. */
> > static bool
> > -pru_legitimate_address_p (machine_mode mode,
> > - rtx operand, bool strict_p)
> > +pru_addr_space_legitimate_address_p (machine_mode mode, rtx operand,
> > + bool strict_p, addr_space_t as)
> > {
> > + if (as == ADDR_SPACE_REGIO)
> > + {
> > + /* Address space constraints for __regio_symbol have been checked in
> > + TARGET_INSERT_ATTRIBUTES, and some more checks will be done
> > + during RTL expansion of "mov<mode>". */
> > + return true;
> > + }
> > + else if (as != ADDR_SPACE_GENERIC)
> > + {
> > + gcc_unreachable ();
> > + }
> > +
> > switch (GET_CODE (operand))
> > {
> > /* Direct. */
> > @@ -2002,6 +2033,116 @@ pru_file_start (void)
> > need to confuse users with this warning. */
> > fprintf (asm_out_file, "\t.set no_warn_regname_label\n");
> > }
> > +
> > +/* Scan type TYP for pointer references to address space other than
> > + ADDR_SPACE_GENERIC. Return true if such reference is found. */
> > +
> > +static bool
> > +pru_nongeneric_pointer_addrspace (tree typ)
> > +{
> > + while (ARRAY_TYPE == TREE_CODE (typ))
> > + typ = TREE_TYPE (typ);
> > +
> > + if (POINTER_TYPE_P (typ))
> > + {
> > + addr_space_t as;
> > + tree target = TREE_TYPE (typ);
> > +
> > + /* Pointer to function: Test the function's return type. */
> > + if (FUNCTION_TYPE == TREE_CODE (target))
> > + return pru_nongeneric_pointer_addrspace (TREE_TYPE (target));
> > +
> > + /* "Ordinary" pointers... */
> > +
> > + while (TREE_CODE (target) == ARRAY_TYPE)
> > + target = TREE_TYPE (target);
> > +
> > + as = TYPE_ADDR_SPACE (target);
> > +
> > + if (!ADDR_SPACE_GENERIC_P (as))
> > + return true;
> > +
> > + /* Scan pointer's target type. */
> > + return pru_nongeneric_pointer_addrspace (target);
> > + }
> > +
> > + return false;
> > +}
> > +
> > +/* Implement `TARGET_INSERT_ATTRIBUTES'. For PRU it's used as a hook to
> > + provide better diagnostics for some invalid usages of the __regio_symbol
> > + address space.
> > +
> > + Any escapes of the following checks are supposed to be caught
> > + during the "mov<mode>" pattern expansion. */
> > +
> > +static void
> > +pru_insert_attributes (tree node, tree *attributes ATTRIBUTE_UNUSED)
> > +{
> > +
> > + /* Validate __regio_symbol variable declarations. */
> > + if (VAR_P (node))
> > + {
> > + const char *name = DECL_NAME (node)
> > + ? IDENTIFIER_POINTER (DECL_NAME (node))
> > + : "<unknown>";
> > + tree typ = TREE_TYPE (node);
> > + addr_space_t as = TYPE_ADDR_SPACE (typ);
> > +
> > + if (as == ADDR_SPACE_GENERIC)
> > + return;
> > +
> > + if (AGGREGATE_TYPE_P (typ))
> > + {
> > + error ("aggregate types are prohibited in "
> > + "%<__regio_symbol%> address space");
> > + /* Don't bother anymore. Below checks would pile
> > + meaningless errors, which would confuse user. */
> > + return;
> > + }
> > + if (DECL_INITIAL (node) != NULL_TREE)
> > + error ("variables in %<__regio_symbol%> address space "
> > + "cannot have initial value");
> > + if (DECL_REGISTER (node))
> > + error ("variables in %<__regio_symbol%> address space "
> > + "cannot be declared %<register%>");
> > + if (!TYPE_VOLATILE (typ))
> > + error ("variables in %<__regio_symbol%> address space "
> > + "must be declared %<volatile%>");
> > + if (!DECL_EXTERNAL (node))
> > + error ("variables in %<__regio_symbol%> address space "
> > + "must be declared %<extern%>");
> > + if (TYPE_MODE (typ) != SImode)
> > + error ("only 32-bit access is supported "
> > + "for %<__regio_symbol%> address space");
> > + if (strcmp (name, "__R30") != 0 && strcmp (name, "__R31") != 0)
> > + error ("register name %<%s%> not recognized "
> > + "in %<__regio_symbol%> address space", name);
> > + }
> > +
> > + tree typ = NULL_TREE;
> > +
> > + switch (TREE_CODE (node))
> > + {
> > + case FUNCTION_DECL:
> > + typ = TREE_TYPE (TREE_TYPE (node));
> > + break;
> > + case TYPE_DECL:
> > + case RESULT_DECL:
> > + case VAR_DECL:
> > + case FIELD_DECL:
> > + case PARM_DECL:
> > + typ = TREE_TYPE (node);
> > + break;
> > + case POINTER_TYPE:
> > + typ = node;
> > + break;
> > + default:
> > + break;
> > + }
> > + if (typ != NULL_TREE && pru_nongeneric_pointer_addrspace (typ))
> > + error ("pointers to %<__regio_symbol%> address space are prohibited");
> > +}
> >
> > /* Function argument related. */
> >
> > @@ -2933,6 +3074,9 @@ pru_unwind_word_mode (void)
> > #undef TARGET_ASM_FILE_START
> > #define TARGET_ASM_FILE_START pru_file_start
> >
> > +#undef TARGET_INSERT_ATTRIBUTES
> > +#define TARGET_INSERT_ATTRIBUTES pru_insert_attributes
> > +
> > #undef TARGET_INIT_BUILTINS
> > #define TARGET_INIT_BUILTINS pru_init_builtins
> > #undef TARGET_EXPAND_BUILTIN
> > @@ -2979,8 +3123,9 @@ pru_unwind_word_mode (void)
> > #undef TARGET_MUST_PASS_IN_STACK
> > #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
> >
> > -#undef TARGET_LEGITIMATE_ADDRESS_P
> > -#define TARGET_LEGITIMATE_ADDRESS_P pru_legitimate_address_p
> > +#undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P
> > +#define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P \
> > + pru_addr_space_legitimate_address_p
> >
> > #undef TARGET_INIT_LIBFUNCS
> > #define TARGET_INIT_LIBFUNCS pru_init_libfuncs
> > diff --git a/gcc/config/pru/pru.h b/gcc/config/pru/pru.h
> > index 9b6be323e6d..03f08b1720f 100644
> > --- a/gcc/config/pru/pru.h
> > +++ b/gcc/config/pru/pru.h
> > @@ -215,6 +215,7 @@ enum reg_class
> > MULDST_REGS,
> > MULSRC0_REGS,
> > MULSRC1_REGS,
> > + REGIO_REGS,
> > GP_REGS,
> > ALL_REGS,
> > LIM_REG_CLASSES
> > @@ -229,6 +230,7 @@ enum reg_class
> > "MULDST_REGS", \
> > "MULSRC0_REGS", \
> > "MULSRC1_REGS", \
> > + "REGIO_REGS", \
> > "GP_REGS", \
> > "ALL_REGS" }
> >
> > @@ -242,6 +244,7 @@ enum reg_class
> > /* MULDST_REGS */ { 0, 0, 0, 0x00000f00, 0}, \
> > /* MULSRC0_REGS */ { 0, 0, 0, 0x000f0000, 0}, \
> > /* MULSRC1_REGS */ { 0, 0, 0, 0x00f00000, 0}, \
> > + /* REGIO_REGS */ { 0, 0, 0, 0xff000000, 0}, \
> > /* GP_REGS */ { ~0, ~0, ~0, ~0, 0}, \
> > /* ALL_REGS */ { ~0,~0, ~0, ~0, ~0} \
> > }
> > @@ -252,6 +255,8 @@ enum reg_class
> > ((REGNO) == MULDST_REGNUM ? MULDST_REGS \
> > : (REGNO) == MULSRC0_REGNUM ? MULSRC0_REGS \
> > : (REGNO) == MULSRC1_REGNUM ? MULSRC1_REGS \
> > + : (REGNO) == R30_REGNUM ? REGIO_REGS \
> > + : (REGNO) == R31_REGNUM ? REGIO_REGS \
> > : (REGNO) >= FIRST_ARG_REGNUM \
> > && (REGNO) <= LAST_ARG_REGNUM ? SIB_REGS \
> > : (REGNO) == STATIC_CHAIN_REGNUM ? SIB_REGS \
> > diff --git a/gcc/config/pru/pru.md b/gcc/config/pru/pru.md
> > index e6cfa8ec3bf..c0ded8ea4e5 100644
> > --- a/gcc/config/pru/pru.md
> > +++ b/gcc/config/pru/pru.md
> > @@ -36,6 +36,8 @@ (define_constants
> > (MULSRC0_REGNUM 112) ; Multiply source register.
> > (MULSRC1_REGNUM 116) ; Multiply source register.
> > (LAST_NONIO_GP_REGNUM 119) ; Last non-I/O general purpose register.
> > + (R30_REGNUM 120) ; R30 I/O register.
> > + (R31_REGNUM 124) ; R31 I/O register.
> > (LOOPCNTR_REGNUM 128) ; internal LOOP counter register
> > (LAST_GP_REGNUM 132) ; Last general purpose register.
> >
> > @@ -49,6 +51,13 @@ (define_constants
> > ]
> > )
> >
> > +;; Enumerate address spaces.
> > +(define_constants
> > + [
> > + (ADDR_SPACE_REGIO 1) ; Access to R30 and R31 I/O registers.
> > + ]
> > +)
> > +
> > ;; Enumeration of UNSPECs.
> >
> > (define_c_enum "unspec" [
> > @@ -68,6 +77,9 @@ (define_c_enum "unspecv" [
> > UNSPECV_HALT
> >
> > UNSPECV_BLOCKAGE
> > +
> > + UNSPECV_REGIO_READ
> > + UNSPECV_REGIO_WRITE
> > ])
> >
> > ; Length of an instruction (in bytes).
> > @@ -129,11 +141,62 @@ (define_expand "mov<mode>"
> > (match_operand:MOV8_16_32 1 "general_operand"))]
> > ""
> > {
> > - /* It helps to split constant loading and memory access
> > - early, so that the LDI/LDI32 instructions can be hoisted
> > - outside a loop body. */
> > - if (MEM_P (operands[0]))
> > - operands[1] = force_reg (<MODE>mode, operands[1]);
> > + if (MEM_P (operands[0])
> > + && MEM_ADDR_SPACE (operands[0]) == ADDR_SPACE_REGIO)
> > +
> > + {
> > + /* Intercept writes to the SImode register I/O "address space". */
> > + gcc_assert (<MODE>mode == SImode);
> > +
> > + if (!SYMBOL_REF_P (XEXP (operands[0], 0)))
> > + {
> > + error ("invalid access to %<__regio_symbol%> address space");
> > + FAIL;
> > + }
> > +
> > + if (!REG_P (operands[1]))
> > + operands[1] = force_reg (<MODE>mode, operands[1]);
> > +
> > + int regiono = pru_symref2ioregno (XEXP (operands[0], 0));
> > + gcc_assert (regiono >= 0);
> > + rtx regio = gen_rtx_REG (<MODE>mode, regiono);
> > + rtx unspecv = gen_rtx_UNSPEC_VOLATILE (<MODE>mode,
> > + gen_rtvec (1, operands[1]),
> > + UNSPECV_REGIO_WRITE);
> > + emit_insn (gen_rtx_SET (regio, unspecv));
> > + DONE;
> > + }
> > + else if (MEM_P (operands[1])
> > + && MEM_ADDR_SPACE (operands[1]) == ADDR_SPACE_REGIO)
> > + {
> > + /* Intercept reads from the SImode register I/O "address space". */
> > + gcc_assert (<MODE>mode == SImode);
> > +
> > + if (!SYMBOL_REF_P (XEXP (operands[1], 0)))
> > + {
> > + error ("invalid access to %<__regio_symbol%> address space");
> > + FAIL;
> > + }
> > +
> > + if (MEM_P (operands[0]))
> > + operands[0] = force_reg (<MODE>mode, operands[0]);
> > +
> > + int regiono = pru_symref2ioregno (XEXP (operands[1], 0));
> > + gcc_assert (regiono >= 0);
> > + rtx regio = gen_rtx_REG (<MODE>mode, regiono);
> > + rtx unspecv = gen_rtx_UNSPEC_VOLATILE (<MODE>mode,
> > + gen_rtvec (1, regio),
> > + UNSPECV_REGIO_READ);
> > + emit_insn (gen_rtx_SET (operands[0], unspecv));
> > + DONE;
> > + }
> > + else if (MEM_P (operands[0]))
> > + {
> > + /* It helps to split constant loading and memory access
> > + early, so that the LDI/LDI32 instructions can be hoisted
> > + outside a loop body. */
> > + operands[1] = force_reg (<MODE>mode, operands[1]);
> > + }
> > })
> >
> > ;; Keep a single pattern for 32 bit MOV operations. LRA requires that the
> > @@ -546,6 +609,35 @@ (define_insn "ashr<mode>3_single"
> >
> > (include "alu-zext.md")
> >
> > +;; Patterns for accessing the R30/R31 I/O registers.
> > +
> > +(define_insn "*regio_readsi"
> > + [(set (match_operand:SI 0 "register_operand" "=r")
> > + (unspec_volatile:SI
> > + [(match_operand:SI 1 "regio_operand" "Rrio")]
> > + UNSPECV_REGIO_READ))]
> > + ""
> > + "mov\\t%0, %1"
> > + [(set_attr "type" "alu")])
> > +
> > +(define_insn "*regio_nozext_writesi"
> > + [(set (match_operand:SI 0 "regio_operand" "=Rrio")
> > + (unspec_volatile:SI
> > + [(match_operand:SI 1 "register_operand" "r")]
> > + UNSPECV_REGIO_WRITE))]
> > + ""
> > + "mov\\t%0, %1"
> > + [(set_attr "type" "alu")])
> > +
> > +(define_insn "*regio_zext_write_r30<EQS0:mode>"
> > + [(set (match_operand:SI 0 "regio_operand" "=Rrio")
> > + (unspec_volatile:SI
> > + [(zero_extend:SI (match_operand:EQS0 1 "register_operand" "r"))]
> > + UNSPECV_REGIO_WRITE))]
> > + ""
> > + "mov\\t%0, %1"
> > + [(set_attr "type" "alu")])
> > +
> > ;; DI logical ops could be automatically split into WORD-mode ops in
> > ;; expand_binop(). But then we'll miss an opportunity to use SI mode
> > ;; operations, since WORD mode for PRU is QI.
> > diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> > index 8b324a097a4..d9adb8ae2c5 100644
> > --- a/gcc/doc/extend.texi
> > +++ b/gcc/doc/extend.texi
> > @@ -1406,7 +1406,7 @@ As an extension, GNU C supports named address spaces as
> > defined in the N1275 draft of ISO/IEC DTR 18037. Support for named
> > address spaces in GCC will evolve as the draft technical report
> > changes. Calling conventions for any target might also change. At
> > -present, only the AVR, M32C, RL78, and x86 targets support
> > +present, only the AVR, M32C, PRU, RL78, and x86 targets support
> > address spaces other than the generic address space.
> >
> > Address space identifiers may be used exactly like any other C type
> > @@ -1586,6 +1586,23 @@ order to access memory beyond the first 64@tie{}Ki bytes. If
> > @code{__far} is used with the M32CM or M32C CPU variants, it has no
> > effect.
> >
> > +@subsection PRU Named Address Spaces
> > +@cindex @code{__regio_symbol} PRU Named Address Spaces
> > +
> > +On the PRU target, variables qualified with @code{__regio_symbol} are
> > +aliases used to access the special I/O CPU registers. They must be
> > +declared as @code{extern} because such variables will not be allocated in
> > +any data memory. They must also be marked as @code{volatile}, and can
> > +only be 32-bit integer types. The only names those variables can have
> > +are @code{__R30} and @code{__R31}, representing respectively the
> > +@code{R30} and @code{R31} special I/O CPU registers. Hence the following
> > +example is the only valid usage of @code{__regio_symbol}:
> > +
> > +@smallexample
> > +extern volatile __regio_symbol uint32_t __R30;
> > +extern volatile __regio_symbol uint32_t __R31;
> > +@end smallexample
> > +
> > @subsection RL78 Named Address Spaces
> > @cindex @code{__far} RL78 Named Address Spaces
> >
> > diff --git a/gcc/testsuite/gcc.target/pru/regio-as-pointer.c b/gcc/testsuite/gcc.target/pru/regio-as-pointer.c
> > new file mode 100644
> > index 00000000000..885464f498d
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/pru/regio-as-pointer.c
> > @@ -0,0 +1,11 @@
> > +/* Test __regio_symbol invalid attempt to get regio variable address. */
> > +
> > +/* { dg-do compile } */
> > +/* { dg-options "-O0" } */
> > +
> > +#include "regio.h"
> > +
> > +uint32_t *test(void)
> > +{
> > + return &__R31; /* { dg-error "return from pointer to non-enclosed address space" } */
> > +}
> > diff --git a/gcc/testsuite/gcc.target/pru/regio-as-pointer2.c b/gcc/testsuite/gcc.target/pru/regio-as-pointer2.c
> > new file mode 100644
> > index 00000000000..c85bb564677
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/pru/regio-as-pointer2.c
> > @@ -0,0 +1,11 @@
> > +/* Test __regio_symbol invalid attempt to get regio variable address. */
> > +
> > +/* { dg-do compile } */
> > +/* { dg-options "-O0" } */
> > +
> > +#include "regio.h"
> > +
> > +uint32_t test(void)
> > +{
> > + return *(&__R31+1); /* { dg-error "invalid access to '__regio_symbol' address space" } */
> > +}
> > diff --git a/gcc/testsuite/gcc.target/pru/regio-decl-2.c b/gcc/testsuite/gcc.target/pru/regio-decl-2.c
> > new file mode 100644
> > index 00000000000..a76cb4700c6
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/pru/regio-decl-2.c
> > @@ -0,0 +1,13 @@
> > +/* Test __regio_symbol diagnostics for wrong declarations. */
> > +
> > +/* { dg-do compile } */
> > +/* { dg-options "-O1" } */
> > +
> > +#include <stdint.h>
> > +
> > +extern volatile __regio_symbol
> > +uint32_t __R30[10]; /* { dg-error "aggregate types are prohibited in '__regio_symbol' address space" } */
> > +
> > +/* { dg-warning "'__R31' initialized and declared 'extern'" "" { target *-*-* } 0 } */
> > +extern volatile __regio_symbol
> > +uint32_t __R31 = 2; /* { dg-error "variables in '__regio_symbol' address space cannot have initial value" } */
> > diff --git a/gcc/testsuite/gcc.target/pru/regio-decl-3.c b/gcc/testsuite/gcc.target/pru/regio-decl-3.c
> > new file mode 100644
> > index 00000000000..f2b0b7fe0d5
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/pru/regio-decl-3.c
> > @@ -0,0 +1,19 @@
> > +/* Test __regio_symbol diagnostics for wrong declarations. */
> > +
> > +/* { dg-do compile } */
> > +/* { dg-options "-O1" } */
> > +
> > +#include <stdint.h>
> > +
> > +uint32_t __regio_symbol *test1(void); /* { dg-error "pointers to '__regio_symbol' address space are prohibited" } */
> > +
> > +void test2(uint32_t __regio_symbol __R30); /* { dg-error "'__regio_symbol' specified for parameter '__R30'" } */
> > +
> > +void test3(uint32_t __regio_symbol *__R30); /* { dg-error "pointers to '__regio_symbol' address space are prohibited" } */
> > +
> > +typedef volatile uint32_t __regio_symbol * regio_type1_t; /* { dg-error "pointers to '__regio_symbol' address space are prohibited" } */
> > +
> > +struct A {
> > + uint32_t __regio_symbol *__R30; /* { dg-error "pointers to '__regio_symbol' address space are prohibited" } */
> > + uint32_t __regio_symbol __R31; /* { dg-error "__regio_symbol' specified for structure field '__R31'" } */
> > +};
> > diff --git a/gcc/testsuite/gcc.target/pru/regio-decl-4.c b/gcc/testsuite/gcc.target/pru/regio-decl-4.c
> > new file mode 100644
> > index 00000000000..de2e8689c76
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/pru/regio-decl-4.c
> > @@ -0,0 +1,17 @@
> > +/* Test __regio_symbol diagnostics for wrong access. */
> > +
> > +/* { dg-do compile } */
> > +/* { dg-options "-O1" } */
> > +
> > +#include <stdint.h>
> > +
> > +extern volatile uint32_t __regio_symbol *__R30;
> > +uint32_t test_r(void)
> > +{
> > + return *__R30; /* { dg-error "invalid access to '__regio_symbol' address space" } */
> > +}
> > +
> > +void test_w(uint32_t a)
> > +{
> > + *__R30 = a; /* { dg-error "invalid access to '__regio_symbol' address space" } */
> > +}
> > diff --git a/gcc/testsuite/gcc.target/pru/regio-decl.c b/gcc/testsuite/gcc.target/pru/regio-decl.c
> > new file mode 100644
> > index 00000000000..a4e8822c528
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/pru/regio-decl.c
> > @@ -0,0 +1,15 @@
> > +/* Test __regio_symbol diagnostics for wrong declarations. */
> > +
> > +/* { dg-do compile } */
> > +/* { dg-options "-O1" } */
> > +
> > +#include <stdint.h>
> > +
> > +volatile __regio_symbol
> > +uint32_t __R30; /* { dg-error "variables in '__regio_symbol' address space must be declared 'extern'" } */
> > +
> > +extern __regio_symbol
> > +uint32_t __R31; /* { dg-error "variables in '__regio_symbol' address space must be declared 'volatile'" } */
> > +
> > +extern volatile
> > +__regio_symbol uint32_t __R32; /* { dg-error "register name '__R32' not recognized in '__regio_symbol' address space" } */
> > diff --git a/gcc/testsuite/gcc.target/pru/regio-di.c b/gcc/testsuite/gcc.target/pru/regio-di.c
> > new file mode 100644
> > index 00000000000..a4226274fc1
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/pru/regio-di.c
> > @@ -0,0 +1,9 @@
> > +/* Test __regio_symbol invalid access diagnostic for DImode. */
> > +
> > +/* { dg-do compile } */
> > +/* { dg-options "-O1" } */
> > +
> > +#include <stdint.h>
> > +
> > +extern volatile
> > +__regio_symbol uint64_t __R31; /* { dg-error "only 32-bit access is supported for '__regio_symbol' address space" } */
> > diff --git a/gcc/testsuite/gcc.target/pru/regio-hi.c b/gcc/testsuite/gcc.target/pru/regio-hi.c
> > new file mode 100644
> > index 00000000000..5b89e8cea96
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/pru/regio-hi.c
> > @@ -0,0 +1,9 @@
> > +/* Test __regio_symbol invalid access diagnostic for HImode. */
> > +
> > +/* { dg-do compile } */
> > +/* { dg-options "-O1" } */
> > +
> > +#include <stdint.h>
> > +
> > +extern volatile __regio_symbol
> > +uint16_t __R31; /* { dg-error "only 32-bit access is supported for '__regio_symbol' address space" } */
> > diff --git a/gcc/testsuite/gcc.target/pru/regio-qi.c b/gcc/testsuite/gcc.target/pru/regio-qi.c
> > new file mode 100644
> > index 00000000000..a3f63062b06
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/pru/regio-qi.c
> > @@ -0,0 +1,9 @@
> > +/* Test __regio_symbol invalid access diagnostic for QImode. */
> > +
> > +/* { dg-do compile } */
> > +/* { dg-options "-O1" } */
> > +
> > +#include <stdint.h>
> > +
> > +extern volatile __regio_symbol
> > +uint8_t __R31; /* { dg-error "only 32-bit access is supported for '__regio_symbol' address space" } */
> > diff --git a/gcc/testsuite/gcc.target/pru/regio.c b/gcc/testsuite/gcc.target/pru/regio.c
> > new file mode 100644
> > index 00000000000..2f01263b902
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/pru/regio.c
> > @@ -0,0 +1,58 @@
> > +/* __regio_symbol operations. */
> > +
> > +/* { dg-do compile } */
> > +/* { dg-options "-Os" } */
> > +
> > +#include "regio.h"
> > +
> > +void
> > +test_r30_w_const (void)
> > +{
> > + /* { dg-final { scan-assembler "mov\\tr30, r\[012\]\[0-9\]?" } } */
> > + __R30 = 1;
> > +}
> > +
> > +void
> > +test_r31_w_zext_qi (unsigned char val1)
> > +{
> > + /* { dg-final { scan-assembler "mov\\tr31, r14.b0" } } */
> > + __R31 = val1;
> > +}
> > +
> > +void
> > +test_r31_w_zext_hi (unsigned short val1)
> > +{
> > + /* { dg-final { scan-assembler "mov\\tr31, r14.w0" } } */
> > + __R31 = val1;
> > +}
> > +
> > +void
> > +test_r31_w (unsigned int val1)
> > +{
> > + /* { dg-final { scan-assembler "mov\\tr31, r14" } } */
> > + __R31 = val1;
> > +}
> > +
> > +uint32_t
> > +test_r30_r (void)
> > +{
> > + /* { dg-final { scan-assembler "mov\\tr14, r30" } } */
> > + return __R30;
> > +}
> > +
> > +void
> > +test_r30_rw (void)
> > +{
> > + /* { dg-final { scan-assembler "mov\\tr\[012\]\[0-9\]?, r30" } } */
> > + /* { dg-final { scan-assembler "mov\\tr30, r\[012\]\[0-9\]?" } } */
> > + __R30 = __R30;
> > +}
> > +
> > +void
> > +test_r31_rw (void)
> > +{
> > + /* { dg-final { scan-assembler "mov\\tr\[012\]\[0-9\]?, r31" } } */
> > + /* { dg-final { scan-assembler "mov\\tr31, r\[012\]\[0-9\]?" } } */
> > + __R31 |= 101;
> > +}
> > +
> > diff --git a/gcc/testsuite/gcc.target/pru/regio.h b/gcc/testsuite/gcc.target/pru/regio.h
> > new file mode 100644
> > index 00000000000..3a120c1d2d1
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/pru/regio.h
> > @@ -0,0 +1,7 @@
> > +
> > +#include <stdint.h>
> > +
> > +/* Declare the I/O registers. */
> > +extern volatile __regio_symbol uint32_t __R30;
> > +extern volatile __regio_symbol uint32_t __R31;
> > +
> > --
> > 2.31.1
> >
prev parent reply other threads:[~2021-09-15 19:04 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-09-14 21:13 Dimitar Dimitrov
2021-09-15 9:12 ` Richard Biener
2021-09-15 19:04 ` Dimitar Dimitrov [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=YUJD0uGuroNOMWvr@kendros \
--to=dimitar@dinux.eu \
--cc=gcc-patches@gcc.gnu.org \
--cc=richard.guenther@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).