From patchwork Sat Sep 25 14:38:23 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dimitar Dimitrov X-Patchwork-Id: 45435 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 1DBD0385802E for ; Sat, 25 Sep 2021 14:39:04 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from server28.superhosting.bg (server28.superhosting.bg [217.174.156.11]) by sourceware.org (Postfix) with ESMTPS id 70E853858403 for ; Sat, 25 Sep 2021 14:38:44 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 70E853858403 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=Content-Transfer-Encoding:MIME-Version:Message-Id:Date:Subject: Cc:To:From:Sender:Reply-To:Content-Type:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=o17scTqp00GkAabmozFAonES82MuZV7vH57LT2KKHTQ=; b=uAnk7X8on8FMCmGMbD+AOHehwK JEuB1vTw069BwJ++3c10thCSKCTUU2VNuaX4VIDXYb9FAf9VNJ8UFrfCzb5tm1hBJCYmbgol/RD3V xprlVw58irU3HZaB6hV3P8SqplLF508evzR2gOEvlybO6xazJqDgGmZO//FK0W5YDDJwcra06pGhl u7X0iGUYMSSbS1dsSx66uTU2fOpq8gv/PSc/ce0f1ORW6nU1AXDWPHJtQT26kkifATH75gIP2mEMc Wj9AavxqCoi2WniGmFyN1dcEX0LUrK6W+XFc9258J9zwXv7t5YeJfUdLAG1nxtM34EBjK3O65ZJGM 91B6P3Zg==; Received: from [95.87.234.74] (port=57280 helo=kendros.lan) by server28.superhosting.bg with esmtpsa (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1mU8p5-000Cfu-09; Sat, 25 Sep 2021 17:38:42 +0300 From: Dimitar Dimitrov To: gcc-patches@gcc.gnu.org Subject: [COMMITTED][PATCH v2] pru: Named address space for R30/R31 I/O access Date: Sat, 25 Sep 2021 17:38:23 +0300 Message-Id: <20210925143823.1535798-1-dimitar@dinux.eu> X-Mailer: git-send-email 2.31.1 MIME-Version: 1.0 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.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, HAS_X_OUTGOING_SPAM_STAT, 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: , Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" I have committed the below patch. I've made only cosmetic updates since version 1 (https://gcc.gnu.org/pipermail/gcc-patches/2021-September/579420.html). 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]. 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. 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-pointer-2.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 | 156 +++++++++++++++++- gcc/config/pru/pru.h | 5 + gcc/config/pru/pru.md | 102 +++++++++++- gcc/doc/extend.texi | 19 ++- .../gcc.target/pru/regio-as-pointer-2.c | 11 ++ .../gcc.target/pru/regio-as-pointer.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, 478 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/gcc.target/pru/regio-as-pointer-2.c create mode 100644 gcc/testsuite/gcc.target/pru/regio-as-pointer.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..9f264b4698d 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,117 @@ 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. + Much of this code was taken from the avr port. */ + +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 +3075,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 +3124,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 9501a60f20e..63be63f091a 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-2.c b/gcc/testsuite/gcc.target/pru/regio-as-pointer-2.c new file mode 100644 index 00000000000..06d9473e995 --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/regio-as-pointer-2.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 *(&__R30+1); /* { dg-error "invalid access to '__regio_symbol' address space" } */ +} 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-decl-2.c b/gcc/testsuite/gcc.target/pru/regio-decl-2.c new file mode 100644 index 00000000000..9a9338e4b42 --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/regio-decl-2.c @@ -0,0 +1,13 @@ +/* Test __regio_symbol diagnostics for unsupported 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..36fcd8ac730 --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/regio-decl-3.c @@ -0,0 +1,19 @@ +/* Test __regio_symbol diagnostics for unsupported 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..48c45a7c918 --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/regio-decl-4.c @@ -0,0 +1,17 @@ +/* Test __regio_symbol diagnostics for unsupported 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..a4962aa4495 --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/regio-decl.c @@ -0,0 +1,15 @@ +/* Test __regio_symbol diagnostics for unsupported 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; +