From patchwork Tue Nov 29 17:04:00 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Georg-Johann Lay X-Patchwork-Id: 128304 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id BCF241007D9 for ; Wed, 30 Nov 2011 04:04:55 +1100 (EST) Received: (qmail 13281 invoked by alias); 29 Nov 2011 17:04:45 -0000 Received: (qmail 13219 invoked by uid 22791); 29 Nov 2011 17:04:38 -0000 X-SWARE-Spam-Status: No, hits=-1.4 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_NONE, TW_GM, TW_PG, T_FILL_THIS_FORM_SHORT X-Spam-Check-By: sourceware.org Received: from mo-p00-ob.rzone.de (HELO mo-p00-ob.rzone.de) (81.169.146.160) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 29 Nov 2011 17:04:19 +0000 X-RZG-AUTH: :LXoWVUeid/7A29J/hMvvT2k715jHQaJercGObUOFkj18odoYNahU4Q== X-RZG-CLASS-ID: mo00 Received: from [192.168.0.22] (business-188-111-022-002.static.arcor-ip.net [188.111.22.2]) by smtp.strato.de (jimi mo37) (RZmta 26.10 AUTH) with ESMTPA id 404854nATGQpSS ; Tue, 29 Nov 2011 18:04:01 +0100 (MET) Message-ID: <4ED51080.9090306@gjlay.de> Date: Tue, 29 Nov 2011 18:04:00 +0100 From: Georg-Johann Lay User-Agent: Thunderbird 2.0.0.24 (X11/20100302) MIME-Version: 1.0 To: gcc-patches@gcc.gnu.org CC: Ian Lance Taylor , Steven Bosscher , sean@depagnier.com, GCC Mailing List , Denis Chertykov Subject: [Patch,AVR] Was/Fix: error linking lto1 for target avr References: <4ED216F7.3070901@gjlay.de> <4ED27DF2.2080907@gjlay.de> <4ED383C3.5040402@gjlay.de> In-Reply-To: X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Ian Lance Taylor wrote: > Georg-Johann Lay writes: > >> So if a frontend can define address spaces and it is a generic feature, the >> question is how to get the name of an address space in a generic, language >> independent way. > > We could decide that all frontends that use address spaces must define a > printable name for each address space. That would mean changing the > middle-end address space interface to give a name to each address space. > The current middle-end address space interface does not require that > address spaces have a name. I was not involved in the addition of > address spaces to gcc, and I don't know why they followed the path they > did. > > Ian Presumably they chose that approach to keep it simple or it is even a performance issue to move the name around. I attached a patch but I fail to find the right configure options for gcc/binutils as the testsuite complains ./avr/bin/ld: bad -plugin option Configured gcc with --enable-lto and binutils 2.21 with --enable-plugin. Maybe the patch can be pre-approved so that the others can proceed with their work? Johann * config/avr/avr.h (ADDR_SPACE_PGM, ADDR_SPACE_PGM1, ADDR_SPACE_PGM2, ADDR_SPACE_PGM3, ADDR_SPACE_PGM4, ADDR_SPACE_PGM5, ADDR_SPACE_PGMX): Write as enum. (avr_addrspace_t): New typedef. (avr_addrspace[]): New declaration. * config/avr/avr-c.c (avr_toupper): New static function. (avr_register_target_pragmas, avr_cpu_cpp_builtins): Use avr_addrspace to get address space information. * config/avr/avr.c (avr_addrspace): New variable. (avr_out_lpm, avr_pgm_check_var_decl, avr_insert_attributes, avr_asm_named_section, avr_section_type_flags, avr_asm_select_section, avr_addr_space_address_mode, avr_addr_space_convert, avr_emit_movmemhi): Use it. (avr_addr_space_pointer_mode): Forward to avr_addr_space_address_mode. (avr_pgm_segment): Remove. Index: config/avr/avr-c.c =================================================================== --- config/avr/avr-c.c (revision 181773) +++ config/avr/avr-c.c (working copy) @@ -36,16 +36,39 @@ void avr_register_target_pragmas (void) { - c_register_addr_space ("__pgm", ADDR_SPACE_PGM); - c_register_addr_space ("__pgm1", ADDR_SPACE_PGM1); - c_register_addr_space ("__pgm2", ADDR_SPACE_PGM2); - c_register_addr_space ("__pgm3", ADDR_SPACE_PGM3); - c_register_addr_space ("__pgm4", ADDR_SPACE_PGM4); - c_register_addr_space ("__pgm5", ADDR_SPACE_PGM5); - c_register_addr_space ("__pgmx", ADDR_SPACE_PGMX); + int i; + + gcc_assert (ADDR_SPACE_GENERIC == ADDR_SPACE_RAM); + + /* Register address spaces. The order must be the same as in the respective + enum from avr.h (or designated initialized must be used in avr.c). */ + + for (i = 0; avr_addrspace[i].name; i++) + { + gcc_assert (i == avr_addrspace[i].id); + + if (!ADDR_SPACE_GENERIC_P (i)) + c_register_addr_space (avr_addrspace[i].name, avr_addrspace[i].id); + } } +/* Transorm LO into uppercase and write the result to UP. + You must provide enough space for UP. Return UP. */ + +static char* +avr_toupper (char *up, const char *lo) +{ + char *up0 = up; + + for (; *lo; lo++, up++) + *up = TOUPPER (*lo); + + *up = '\0'; + + return up0; +} + /* Worker function for TARGET_CPU_CPP_BUILTINS. */ void @@ -117,13 +140,17 @@ avr_cpu_cpp_builtins (struct cpp_reader if (!strcmp (lang_hooks.name, "GNU C")) { - cpp_define (pfile, "__PGM=__pgm"); - cpp_define (pfile, "__PGM1=__pgm1"); - cpp_define (pfile, "__PGM2=__pgm2"); - cpp_define (pfile, "__PGM3=__pgm3"); - cpp_define (pfile, "__PGM4=__pgm4"); - cpp_define (pfile, "__PGM5=__pgm5"); - cpp_define (pfile, "__PGMX=__pgmx"); + int i; + + for (i = 0; avr_addrspace[i].name; i++) + if (!ADDR_SPACE_GENERIC_P (i)) + { + const char *name = avr_addrspace[i].name; + char *Name = (char*) alloca (1 + strlen (name)); + + cpp_define_formatted (pfile, "%s=%s", + avr_toupper (Name, name), name); + } } /* Define builtin macros so that the user can Index: config/avr/avr.c =================================================================== --- config/avr/avr.c (revision 181773) +++ config/avr/avr.c (working copy) @@ -55,11 +55,39 @@ /* Return true if STR starts with PREFIX and false, otherwise. */ #define STR_PREFIX_P(STR,PREFIX) (0 == strncmp (STR, PREFIX, strlen (PREFIX))) -/* The 4 bits starting at SECTION_MACH_DEP are reverved to store - 1 + flash segment where progmem data is to be located. - For example, data with __pgm2 is stored as (1+2) * SECTION_MACH_DEP. */ +/* The 4 bits starting at SECTION_MACH_DEP are reserved to store the + address space where data is to be located. + As the only non-generic address spaces are all located in Flash, + this can be used to test if data shall go into some .progmem* section. + This must be the rightmost field of machine dependent section flags. */ #define AVR_SECTION_PROGMEM (0xf * SECTION_MACH_DEP) +/* Known address spaces. The order must be the same as in the respective + enum from avr.h (or designated initialized must be used). */ +const avr_addrspace_t avr_addrspace[] = +{ + { ADDR_SPACE_RAM, 0, 2, "" , 0 }, + { ADDR_SPACE_PGM, 1, 2, "__pgm", 0 }, + { ADDR_SPACE_PGM1, 1, 2, "__pgm1", 1 }, + { ADDR_SPACE_PGM2, 1, 2, "__pgm2", 2 }, + { ADDR_SPACE_PGM3, 1, 2, "__pgm3", 3 }, + { ADDR_SPACE_PGM4, 1, 2, "__pgm4", 4 }, + { ADDR_SPACE_PGM5, 1, 2, "__pgm5", 5 }, + { ADDR_SPACE_PGMX, 1, 3, "__pgmx", 0 }, + { 0 , 0, 0, NULL, 0 } +}; + +/* Map 64-k Flash segment to section prefix. */ +static const char* const progmem_section_prefix[6] = + { + ".progmem.data", + ".progmem1.data", + ".progmem2.data", + ".progmem3.data", + ".progmem4.data", + ".progmem5.data" + }; + /* Prototypes for local helper functions. */ @@ -132,19 +160,10 @@ const struct mcu_type_s *avr_current_dev /* Section to put switch tables in. */ static GTY(()) section *progmem_swtable_section; -/* Unnamed section associated to __attribute__((progmem)) aka. PROGMEM. */ +/* Unnamed sections associated to __attribute__((progmem)) aka. PROGMEM + or to address space __pgm*. */ static GTY(()) section *progmem_section[6]; -static const char * const progmem_section_prefix[6] = - { - ".progmem.data", - ".progmem1.data", - ".progmem2.data", - ".progmem3.data", - ".progmem4.data", - ".progmem5.data" - }; - /* To track if code will use .bss and/or .data. */ bool avr_need_clear_bss_p = false; bool avr_need_copy_data_p = false; @@ -462,29 +481,6 @@ avr_scalar_mode_supported_p (enum machin } -/* Return the segment number of pgm address space AS, i.e. - the 64k block it lives in. - Return -1 if unknown, i.e. 24-bit AS in flash. - Return -2 for anything else. */ - -static int -avr_pgm_segment (addr_space_t as) -{ - switch (as) - { - default: return -2; - - case ADDR_SPACE_PGMX: return -1; - case ADDR_SPACE_PGM: return 0; - case ADDR_SPACE_PGM1: return 1; - case ADDR_SPACE_PGM2: return 2; - case ADDR_SPACE_PGM3: return 3; - case ADDR_SPACE_PGM4: return 4; - case ADDR_SPACE_PGM5: return 5; - } -} - - /* Return TRUE if DECL is a VAR_DECL located in Flash and FALSE, otherwise. */ static bool @@ -2582,6 +2578,9 @@ avr_out_lpm (rtx insn, rtx *op, int *ple int n_bytes = GET_MODE_SIZE (GET_MODE (dest)); int regno_dest; int segment; + RTX_CODE code; + + addr_space_t as; if (plen) *plen = 0; @@ -2589,27 +2588,29 @@ avr_out_lpm (rtx insn, rtx *op, int *ple if (MEM_P (dest)) { warning (0, "writing to address space %qs not supported", - c_addr_space_name (MEM_ADDR_SPACE (dest))); + avr_addrspace[MEM_ADDR_SPACE (dest)].name); return ""; } - addr = XEXP (src, 0); - - segment = avr_pgm_segment (MEM_ADDR_SPACE (src)); + as = MEM_ADDR_SPACE (src); - gcc_assert (REG_P (dest) - && ((segment >= 0 - && (REG_P (addr) || POST_INC == GET_CODE (addr))) - || (GET_CODE (addr) == LO_SUM && segment == -1))); + addr = XEXP (src, 0); + code = GET_CODE (addr); - if (segment == -1) + gcc_assert (REG_P (dest)); + + if (as == ADDR_SPACE_PGMX) { /* We are called from avr_out_xload because someone wrote __pgmx on a device with just one flash segment. */ + gcc_assert (LO_SUM == code); + addr = XEXP (addr, 1); } + else + gcc_assert (REG == code || POST_INC == code); xop[0] = dest; xop[1] = addr; @@ -2619,11 +2620,10 @@ avr_out_lpm (rtx insn, rtx *op, int *ple regno_dest = REGNO (dest); - /* Cut down segment number to a number the device actually - supports. We do this late to preserve the address space's - name for diagnostics. */ + /* Cut down segment number to a number the device actually supports. + We do this late to preserve the address space's name for diagnostics. */ - segment %= avr_current_arch->n_segments; + segment = avr_addrspace[as].segment % avr_current_arch->n_segments; /* Set RAMPZ as needed. */ @@ -2652,14 +2652,17 @@ avr_out_lpm (rtx insn, rtx *op, int *ple } xop[4] = xstring_e; - } - if ((segment == 0 && !AVR_HAVE_LPMX) - || (segment != 0 && !AVR_HAVE_ELPMX)) + if (!AVR_HAVE_ELPMX) + return avr_out_lpm_no_lpmx (insn, xop, plen); + } + else if (!AVR_HAVE_LPMX) { return avr_out_lpm_no_lpmx (insn, xop, plen); } + /* We have [E]LPMX: Output reading from Flash the comfortable way. */ + switch (GET_CODE (addr)) { default: @@ -6919,10 +6922,10 @@ avr_pgm_check_var_decl (tree node) { if (TYPE_P (node)) error ("pointer targeting address space %qs must be const in %qT", - c_addr_space_name (as), node); + avr_addrspace[as].name, node); else error ("pointer targeting address space %qs must be const in %s %q+D", - c_addr_space_name (as), reason, node); + avr_addrspace[as].name, reason, node); } return reason == NULL; @@ -6959,7 +6962,7 @@ avr_insert_attributes (tree node, tree * const char *reason = "__attribute__((progmem))"; if (!ADDR_SPACE_GENERIC_P (as)) - reason = c_addr_space_name (as); + reason = avr_addrspace[as].name; if (avr_log.progmem) avr_edump ("\n%?: %t\n%t\n", node, node0); @@ -7136,7 +7139,8 @@ avr_asm_named_section (const char *name, { if (flags & AVR_SECTION_PROGMEM) { - int segment = (flags & AVR_SECTION_PROGMEM) / SECTION_MACH_DEP - 1; + addr_space_t as = (flags & AVR_SECTION_PROGMEM) / SECTION_MACH_DEP; + int segment = avr_addrspace[as].segment % avr_current_arch->n_segments; const char *old_prefix = ".rodata"; const char *new_prefix = progmem_section_prefix[segment]; const char *sname = new_prefix; @@ -7165,7 +7169,6 @@ avr_asm_named_section (const char *name, static unsigned int avr_section_type_flags (tree decl, const char *name, int reloc) { - int prog; unsigned int flags = default_section_type_flags (decl, name, reloc); if (STR_PREFIX_P (name, ".noinit")) @@ -7179,16 +7182,20 @@ avr_section_type_flags (tree decl, const } if (decl && DECL_P (decl) - && (prog = avr_progmem_p (decl, DECL_ATTRIBUTES (decl)), prog)) + && avr_progmem_p (decl, DECL_ATTRIBUTES (decl))) { - int segment = 0; + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (decl)); + + /* Attribute progmem puts data in generic address space. + Set section flags as if it was in __pgm to get the right + section prefix in the remainder. */ - if (prog == 1) - segment = avr_pgm_segment (TYPE_ADDR_SPACE (TREE_TYPE (decl))); + if (ADDR_SPACE_GENERIC_P (as)) + as = ADDR_SPACE_PGM; + flags |= as * SECTION_MACH_DEP; flags &= ~SECTION_WRITE; flags &= ~SECTION_BSS; - flags |= (1 + segment % avr_current_arch->n_segments) * SECTION_MACH_DEP; } return flags; @@ -7198,8 +7205,7 @@ avr_section_type_flags (tree decl, const /* Implement `TARGET_ENCODE_SECTION_INFO'. */ static void -avr_encode_section_info (tree decl, rtx rtl, - int new_decl_p) +avr_encode_section_info (tree decl, rtx rtl, int new_decl_p) { /* In avr_handle_progmem_attribute, DECL_INITIAL is not yet readily available, see PR34734. So we postpone the warning @@ -7224,19 +7230,13 @@ avr_encode_section_info (tree decl, rtx static section * avr_asm_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align) { - int prog; - section * sect = default_elf_select_section (decl, reloc, align); if (decl && DECL_P (decl) - && (prog = avr_progmem_p (decl, DECL_ATTRIBUTES (decl)), prog)) + && avr_progmem_p (decl, DECL_ATTRIBUTES (decl))) { - int segment = 0; - - if (prog == 1) - segment = avr_pgm_segment (TYPE_ADDR_SPACE (TREE_TYPE (decl))); - - segment %= avr_current_arch->n_segments; + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (decl)); + int segment = avr_addrspace[as].segment % avr_current_arch->n_segments; if (sect->common.flags & SECTION_NAMED) { @@ -9386,7 +9386,7 @@ avr_case_values_threshold (void) static enum machine_mode avr_addr_space_address_mode (addr_space_t as) { - return as == ADDR_SPACE_PGMX ? PSImode : HImode; + return avr_addrspace[as].pointer_size == 3 ? PSImode : HImode; } @@ -9395,7 +9395,7 @@ avr_addr_space_address_mode (addr_space_ static enum machine_mode avr_addr_space_pointer_mode (addr_space_t as) { - return as == ADDR_SPACE_PGMX ? PSImode : HImode; + return avr_addr_space_address_mode (as); } @@ -9573,7 +9573,7 @@ avr_addr_space_convert (rtx src, tree ty } else { - int segment = avr_pgm_segment (as_from) % n_segments; + int segment = avr_addrspace[as_from].segment % n_segments; new_src = gen_reg_rtx (PSImode); emit_insn (gen_n_extendhipsi2 (new_src, GEN_INT (segment), src)); @@ -9642,15 +9642,12 @@ avr_emit_movmemhi (rtx *xop) } else { - int seg = avr_pgm_segment (as); + int segment = avr_addrspace[as].segment % avr_current_arch->n_segments; addr1 = a_src; - if (seg > 0 - && seg % avr_current_arch->n_segments > 0) - { - a_hi8 = GEN_INT (seg % avr_current_arch->n_segments); - } + if (segment) + a_hi8 = GEN_INT (segment); } if (a_hi8 Index: config/avr/avr.h =================================================================== --- config/avr/avr.h (revision 181772) +++ config/avr/avr.h (working copy) @@ -133,6 +133,40 @@ extern const struct mcu_type_s *avr_curr extern const struct mcu_type_s avr_mcu_types[]; extern const struct base_arch_s avr_arch_types[]; +typedef struct +{ + /* Id of the address space as used in c_register_addr_space */ + unsigned char id; + + /* Flavour of memory: 0 = RAM, 1 = Flash */ + int memory_class; + + /* Width of pointer (in bytes) */ + int pointer_size; + + /* Name of the address space as visible to the user */ + const char *name; + + /* Segment (i.e. 64k memory chunk) number. */ + int segment; +} avr_addrspace_t; + +extern const avr_addrspace_t avr_addrspace[]; + +/* Known address spaces */ + +enum + { + ADDR_SPACE_RAM, + ADDR_SPACE_PGM, + ADDR_SPACE_PGM1, + ADDR_SPACE_PGM2, + ADDR_SPACE_PGM3, + ADDR_SPACE_PGM4, + ADDR_SPACE_PGM5, + ADDR_SPACE_PGMX + }; + #define TARGET_CPU_CPP_BUILTINS() avr_cpu_cpp_builtins (pfile) #define AVR_HAVE_JMP_CALL (avr_current_arch->have_jmp_call && !TARGET_SHORT_CALLS) @@ -401,15 +435,6 @@ typedef struct avr_args { #define NO_FUNCTION_CSE - -#define ADDR_SPACE_PGM 1 -#define ADDR_SPACE_PGM1 2 -#define ADDR_SPACE_PGM2 3 -#define ADDR_SPACE_PGM3 4 -#define ADDR_SPACE_PGM4 5 -#define ADDR_SPACE_PGM5 6 -#define ADDR_SPACE_PGMX 7 - #define REGISTER_TARGET_PRAGMAS() \ do { \ avr_register_target_pragmas(); \