From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-ej1-x62f.google.com (mail-ej1-x62f.google.com [IPv6:2a00:1450:4864:20::62f]) by sourceware.org (Postfix) with ESMTPS id 50AFD3858D39 for ; Wed, 15 Sep 2021 09:12:30 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 50AFD3858D39 Received: by mail-ej1-x62f.google.com with SMTP id h9so4667392ejs.4 for ; Wed, 15 Sep 2021 02:12:30 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=XAkxG/a69zguB4cfe0TrLvkWBuh3xIq8nj/URzvQR1M=; b=BAodEqJW8ziuYjfZ0Go+ZeKBnKNpkxnC1R/X2Pn/HZWEh6Hf5lFn+U8uUP/sAUR4nU mjdOzEywzg30TS7VfHlFI0kicsehupgCho56tYMQgxAeSqys9IuXFwAkHrItx5PL8CK3 M7B87X+IEkTLLtmAy/BfalXeVnJqc4W/xbBg+khcKMntba8Ly/9JY0KgV037Rel06DHz rw5ZHjRpSYBjuf3AP7JqrzjoCez4KyqBwXpWiuL3uYgbBBuEFKC6Z5m0UwRrjrfFHsXa +orZ4sqIiauHsU0S7QAEet8a2z7NG+6+QcCsbCcht8V8wQsrTkLad0OhM8Fu1uTj+O7B OEGg== X-Gm-Message-State: AOAM531A9cgmoSMPOLmFB33OdtC/yhDwQrYoLBDfdc7GanZ+KmhfhWzZ vh90f0SyR2tNTaahkR9bPeM3bEdGPH2kO3vGHmDUuNVF X-Google-Smtp-Source: ABdhPJzF2a0a1JGJJjB159IgkKvmGKkqIkFWLaCRmQkGcIIeDPGMHt2NYX1t4GP6Qcl/tETVasMO1JA0e32LrJBVUJM= X-Received: by 2002:a17:906:ece1:: with SMTP id qt1mr23337446ejb.281.1631697149048; Wed, 15 Sep 2021 02:12:29 -0700 (PDT) MIME-Version: 1.0 References: <20210914211315.1053529-1-dimitar@dinux.eu> In-Reply-To: <20210914211315.1053529-1-dimitar@dinux.eu> From: Richard Biener Date: Wed, 15 Sep 2021 11:12:18 +0200 Message-ID: Subject: Re: [PATCH][RFC] pru: Named address space for R30/R31 I/O access To: Dimitar Dimitrov Cc: GCC Patches Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-8.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, KAM_STOCKGEN, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, 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 09:12:34 -0000 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?). > 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? > 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 >