public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
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
> >

      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).