From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from server28.superhosting.bg (server28.superhosting.bg [217.174.156.11]) by sourceware.org (Postfix) with ESMTPS id 16AAF3858C39 for ; Wed, 15 Sep 2021 19:04:57 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 16AAF3858C39 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=dinux.eu Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=dinux.eu DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=dinux.eu; s=default; h=In-Reply-To:Content-Type:MIME-Version:References:Message-ID: Subject:Cc:To:From:Date:Sender:Reply-To:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=F5Nc8smuI5+j4fqf31nwJPebyZZJt6bDb6F0LvdxHX8=; b=s6yv9zcrz+mJTFQvCtTDiUldqP p8iWW9Y30qWqBwH+D3yryueQgGPt5Nam8xCfi7nMFEu/JN2wVfOvmRjkI9fG3m4IkEkHlcEMNRBfR 04ABZx5A8Wq6Bl+9TIKDOrpXsoB2FAVsCvui5YItBHudtd3aQQGgZbQb5KBRPW7MruuwtKUW7rwiN TlFY0MRdAxaNOTnbEUBjImtNdcgsZxBc0eJzudqSj1jS1GWOolGugemDDt5l7GOSuOpfsAFPmJBD6 lsgidwTNlXwe0NlAff0J6U1nwohfrNoPg6luPvHMbpAMMWZD9DIrHFH3Y8kyxvbAI3te6rrYQhR7w ve+fo0cA==; Received: from [95.87.234.74] (port=40670 helo=localhost) by server28.superhosting.bg with esmtpsa (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1mQaDD-0006sN-2g; Wed, 15 Sep 2021 22:04:55 +0300 Date: Wed, 15 Sep 2021 22:04:50 +0300 From: Dimitar Dimitrov To: Richard Biener Cc: GCC Patches Subject: Re: [PATCH][RFC] pru: Named address space for R30/R31 I/O access Message-ID: References: <20210914211315.1053529-1-dimitar@dinux.eu> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: X-OutGoing-Spam-Status: No, score=-1.4 X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - server28.superhosting.bg X-AntiAbuse: Original Domain - gcc.gnu.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - dinux.eu X-Get-Message-Sender-Via: server28.superhosting.bg: authenticated_id: dimitar@dinux.eu X-Authenticated-Sender: server28.superhosting.bg: dimitar@dinux.eu X-Source: X-Source-Args: X-Source-Dir: X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, KAM_STOCKGEN, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 15 Sep 2021 19:05:03 -0000 On Wed, Sep 15, 2021 at 11:12:18AM +0200, Richard Biener wrote: > On Tue, Sep 14, 2021 at 11:13 PM Dimitar Dimitrov 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): 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 > > --- > > 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". */ > > + 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" 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)) > > + : ""; > > + 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 %"); > > + if (!TYPE_VOLATILE (typ)) > > + error ("variables in %<__regio_symbol%> address space " > > + "must be declared %"); > > + if (!DECL_EXTERNAL (node)) > > + error ("variables in %<__regio_symbol%> address space " > > + "must be declared %"); > > + 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" > > (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, 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 == 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, operands[1]); > > + > > + int regiono = pru_symref2ioregno (XEXP (operands[0], 0)); > > + gcc_assert (regiono >= 0); > > + rtx regio = gen_rtx_REG (mode, regiono); > > + rtx unspecv = gen_rtx_UNSPEC_VOLATILE (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 == 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, operands[0]); > > + > > + int regiono = pru_symref2ioregno (XEXP (operands[1], 0)); > > + gcc_assert (regiono >= 0); > > + rtx regio = gen_rtx_REG (mode, regiono); > > + rtx unspecv = gen_rtx_UNSPEC_VOLATILE (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, operands[1]); > > + } > > }) > > > > ;; Keep a single pattern for 32 bit MOV operations. LRA requires that the > > @@ -546,6 +609,35 @@ (define_insn "ashr3_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" > > + [(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 > > + > > +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 > > + > > +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 > > + > > +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 > > + > > +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 > > + > > +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 > > + > > +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 > > + > > +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 > > + > > +/* Declare the I/O registers. */ > > +extern volatile __regio_symbol uint32_t __R30; > > +extern volatile __regio_symbol uint32_t __R31; > > + > > -- > > 2.31.1 > >