From b1b6774f67ee3760778596db91bbe5a6ce73a172 Mon Sep 17 00:00:00 2001 From: Georg-Johann Lay Date: Mon, 24 Oct 2016 11:02:51 +0000 Subject: [PATCH] re PR target/78093 ([avr] New variable attribute "absdata" and option "-mabsdata" to enable LDS / STS on Reduced Tiny) gcc/ PR target/78093 * doc/extend.texi (AVR Variable Attributes) [absdata]: Document it. * config/avr/avr.c (AVR_SYMBOL_FLAG_TINY_ABSDATA): New macro. (avr_address_tiny_absdata_p): New static function. (avr_legitimate_address_p, avr_legitimize_address) [AVR_TINY]: Use it to determine validity of constant addresses. (avr_attribute_table) [absdata]: New variable attribute... (avr_handle_absdata_attribute): ...and handler. (avr_decl_absdata_p): New static function. (avr_encode_section_info) [AVR_TINY]: Use it to add flag AVR_SYMBOL_FLAG_TINY_ABSDATA to respective symbols_refs. (avr_address_cost) [AVR_TINY]: absdata addresses cost 2. gcc/testsuite/ PR target/78093 * lib/target-supports.exp (check_effective_target_avr_tiny): New proc. * gcc.target/avr/torture/tiny-absdata-1.c: New test. From-SVN: r241468 --- gcc/ChangeLog | 15 +++ gcc/config/avr/avr.c | 109 ++++++++++++++++-- gcc/doc/extend.texi | 27 +++++ gcc/testsuite/ChangeLog | 6 + .../gcc.target/avr/torture/tiny-absdata-1.c | 70 +++++++++++ gcc/testsuite/lib/target-supports.exp | 18 +++ 6 files changed, 234 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/gcc.target/avr/torture/tiny-absdata-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a0c6c370564..291ef4507de 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2016-10-24 Georg-Johann Lay + + PR target/78093 + * doc/extend.texi (AVR Variable Attributes) [absdata]: Document it. + * config/avr/avr.c (AVR_SYMBOL_FLAG_TINY_ABSDATA): New macro. + (avr_address_tiny_absdata_p): New static function. + (avr_legitimate_address_p, avr_legitimize_address) [AVR_TINY]: Use + it to determine validity of constant addresses. + (avr_attribute_table) [absdata]: New variable attribute... + (avr_handle_absdata_attribute): ...and handler. + (avr_decl_absdata_p): New static function. + (avr_encode_section_info) [AVR_TINY]: Use it to add flag + AVR_SYMBOL_FLAG_TINY_ABSDATA to respective symbols_refs. + (avr_address_cost) [AVR_TINY]: absdata addresses cost 2. + 2016-10-24 Richard Biener PR tree-optimization/78076 diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index 3945122e2f3..1a49fdc0d96 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -85,6 +85,10 @@ #define AVR_SYMBOL_FLAG_TINY_PM \ (SYMBOL_FLAG_MACH_DEP << 7) +/* (AVR_TINY only): Symbol has attribute absdata */ +#define AVR_SYMBOL_FLAG_TINY_ABSDATA \ + (SYMBOL_FLAG_MACH_DEP << 8) + #define TINY_ADIW(REG1, REG2, I) \ "subi " #REG1 ",lo8(-(" #I "))" CR_TAB \ "sbci " #REG2 ",hi8(-(" #I "))" @@ -1791,6 +1795,28 @@ avr_mode_dependent_address_p (const_rtx addr ATTRIBUTE_UNUSED, addr_space_t as) } +/* Return true if rtx X is a CONST_INT, CONST or SYMBOL_REF + address with the `absdata' variable attribute, i.e. respective + data can be read / written by LDS / STS instruction. + This is used only for AVR_TINY. */ + +static bool +avr_address_tiny_absdata_p (rtx x, machine_mode mode) +{ + if (CONST == GET_CODE (x)) + x = XEXP (XEXP (x, 0), 0); + + if (SYMBOL_REF_P (x)) + return SYMBOL_REF_FLAGS (x) & AVR_SYMBOL_FLAG_TINY_ABSDATA; + + if (CONST_INT_P (x) + && IN_RANGE (INTVAL (x), 0, 0xc0 - GET_MODE_SIZE (mode))) + return true; + + return false; +} + + /* Helper function for `avr_legitimate_address_p'. */ static inline bool @@ -1875,8 +1901,7 @@ avr_legitimate_address_p (machine_mode mode, rtx x, bool strict) /* avrtiny's load / store instructions only cover addresses 0..0xbf: IN / OUT range is 0..0x3f and LDS / STS can access 0x40..0xbf. */ - ok = (CONST_INT_P (x) - && IN_RANGE (INTVAL (x), 0, 0xc0 - GET_MODE_SIZE (mode))); + ok = avr_address_tiny_absdata_p (x, mode); } if (avr_log.legitimate_address_p) @@ -1918,8 +1943,7 @@ avr_legitimize_address (rtx x, rtx oldx, machine_mode mode) if (AVR_TINY) { if (CONSTANT_ADDRESS_P (x) - && !(CONST_INT_P (x) - && IN_RANGE (INTVAL (x), 0, 0xc0 - GET_MODE_SIZE (mode)))) + && ! avr_address_tiny_absdata_p (x, mode)) { x = force_reg (Pmode, x); } @@ -9148,6 +9172,32 @@ avr_handle_fntype_attribute (tree *node, tree name, return NULL_TREE; } +static tree +avr_handle_absdata_attribute (tree *node, tree name, tree /* args */, + int /* flags */, bool *no_add) +{ + location_t loc = DECL_SOURCE_LOCATION (*node); + + if (AVR_TINY) + { + if (TREE_CODE (*node) != VAR_DECL + || (!TREE_STATIC (*node) && !DECL_EXTERNAL (*node))) + { + warning_at (loc, OPT_Wattributes, "%qE attribute only applies to" + " variables in static storage", name); + *no_add = true; + } + } + else + { + warning_at (loc, OPT_Wattributes, "%qE attribute only supported" + " for reduced Tiny cores", name); + *no_add = true; + } + + return NULL_TREE; +} + static tree avr_handle_addr_attribute (tree *node, tree name, tree args, int flags ATTRIBUTE_UNUSED, bool *no_add) @@ -9218,8 +9268,8 @@ avr_eval_addr_attrib (rtx x) if (SYMBOL_REF_FLAGS (x) & SYMBOL_FLAG_IO) { attr = lookup_attribute ("io", DECL_ATTRIBUTES (decl)); - if (!attr || !TREE_VALUE (attr)) - attr = lookup_attribute ("io_low", DECL_ATTRIBUTES (decl)); + if (!attr || !TREE_VALUE (attr)) + attr = lookup_attribute ("io_low", DECL_ATTRIBUTES (decl)); gcc_assert (attr); } if (!attr || !TREE_VALUE (attr)) @@ -9255,6 +9305,8 @@ avr_attribute_table[] = false }, { "address", 1, 1, false, false, false, avr_handle_addr_attribute, false }, + { "absdata", 0, 0, true, false, false, avr_handle_absdata_attribute, + false }, { NULL, 0, 0, false, false, false, NULL, false } }; @@ -9339,6 +9391,17 @@ avr_progmem_p (tree decl, tree attributes) } +/* Return true if DECL has attribute `absdata' set. This function should + only be used for AVR_TINY. */ + +static bool +avr_decl_absdata_p (tree decl, tree attributes) +{ + return (TREE_CODE (decl) == VAR_DECL + && NULL_TREE != lookup_attribute ("absdata", attributes)); +} + + /* Scan type TYP for pointer references to address space ASn. Return ADDR_SPACE_GENERIC (i.e. 0) if all pointers targeting the AS are also declared to be CONST. @@ -9694,6 +9757,8 @@ avr_section_type_flags (tree decl, const char *name, int reloc) static void avr_encode_section_info (tree decl, rtx rtl, int new_decl_p) { + tree addr_attr = NULL_TREE; + /* In avr_handle_progmem_attribute, DECL_INITIAL is not yet readily available, see PR34734. So we postpone the warning about uninitialized data in program memory section until here. */ @@ -9735,7 +9800,7 @@ avr_encode_section_info (tree decl, rtx rtl, int new_decl_p) tree io_low_attr = lookup_attribute ("io_low", attr); tree io_attr = lookup_attribute ("io", attr); - tree addr_attr; + if (io_low_attr && TREE_VALUE (io_low_attr) && TREE_VALUE (TREE_VALUE (io_low_attr))) addr_attr = io_attr; @@ -9763,14 +9828,32 @@ avr_encode_section_info (tree decl, rtx rtl, int new_decl_p) if (AVR_TINY && decl && VAR_DECL == TREE_CODE (decl) - && -1 == avr_progmem_p (decl, DECL_ATTRIBUTES (decl)) && MEM_P (rtl) && SYMBOL_REF_P (XEXP (rtl, 0))) { - /* Tag symbols for later addition of 0x4000 (AVR_TINY_PM_OFFSET). */ - rtx sym = XEXP (rtl, 0); - SYMBOL_REF_FLAGS (sym) |= AVR_SYMBOL_FLAG_TINY_PM; + + if (-1 == avr_progmem_p (decl, DECL_ATTRIBUTES (decl))) + { + // Tag symbols for later addition of 0x4000 (AVR_TINY_PM_OFFSET). + SYMBOL_REF_FLAGS (sym) |= AVR_SYMBOL_FLAG_TINY_PM; + } + + if (avr_decl_absdata_p (decl, DECL_ATTRIBUTES (decl)) + || (addr_attr + // If addr_attr is non-null, it has an argument. Peek into it. + && TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (addr_attr))) < 0xc0)) + { + // May be accessed by LDS / STS. + SYMBOL_REF_FLAGS (sym) |= AVR_SYMBOL_FLAG_TINY_ABSDATA; + } + + if (-1 == avr_progmem_p (decl, DECL_ATTRIBUTES (decl)) + && avr_decl_absdata_p (decl, DECL_ATTRIBUTES (decl))) + { + error ("%q+D has incompatible attributes %qs and %qs", + decl, "progmem", "absdata"); + } } } @@ -10900,6 +10983,10 @@ avr_address_cost (rtx x, machine_mode mode ATTRIBUTE_UNUSED, if (optimize > 0 && io_address_operand (x, QImode)) cost = 2; + + if (AVR_TINY + && avr_address_tiny_absdata_p (x, QImode)) + cost = 2; } if (avr_log.address_cost) diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 62a5f2963db..0669f7999be 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -5973,6 +5973,33 @@ memory-mapped peripherals that may lie outside the io address range. volatile int porta __attribute__((address (0x600))); @end smallexample +@item absdata +@cindex @code{absdata} variable attribute, AVR +Variables in static storage and with the @code{absdata} attribute can +be accessed by the @code{LDS} and @code{STS} instructions which take +absolute addresses. + +@itemize @bullet +@item +This attribute is only supported for the reduced AVR Tiny core +like ATtiny40. + +@item +You must make sure that respective data is located in the +address range @code{0x40}@dots{}@code{0xbf} accessible by +@code{LDS} and @code{STS}. One way to achieve this as an +appropriate linker description file. + +@item +If the location does not fit the address range of @code{LDS} +and @code{STS}, there is currently (Binutils 2.26) just an unspecific +warning like +@quotation +@code{module.c:(.text+0x1c): warning: internal error: out of range error} +@end quotation + +@end itemize + @end table @node Blackfin Variable Attributes diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d43a909a0dd..bc9bf676032 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2016-10-24 Georg-Johann Lay + + PR target/78093 + * lib/target-supports.exp (check_effective_target_avr_tiny): New proc. + * gcc.target/avr/torture/tiny-absdata-1.c: New test. + 2016-10-24 Andre Vieira * gcc.target/arm/pure-code/pure-code.exp: Restore saved globals. diff --git a/gcc/testsuite/gcc.target/avr/torture/tiny-absdata-1.c b/gcc/testsuite/gcc.target/avr/torture/tiny-absdata-1.c new file mode 100644 index 00000000000..c1c645fc7a6 --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/torture/tiny-absdata-1.c @@ -0,0 +1,70 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target avr_tiny } */ + +typedef struct +{ + char a, b, c; +} abc_t; + +extern char varA __attribute__((absdata)); +extern char varB __attribute__((absdata)); + +extern int arrayA[] __attribute__((absdata)); +extern int arrayB[] __attribute__((absdata)); +extern char arrayC[] __attribute__((address(0x80))); + +extern abc_t abc __attribute__((absdata)); + +char get_1 (void) +{ + return varA; +} + +int get_2 (void) +{ + return arrayA[3]; +} + +char get_3 (void) +{ + return abc.a + abc.b + abc.c; +} + + +void put_1 (char b) +{ + varB = b; +} + +void put_2 (int b) +{ + arrayB[3] = b; +} + +void put_3 (void) +{ + abc.a = abc.b = abc.c = 0; +} + +void put_4 (void) +{ + arrayC[0] = arrayC[1] = arrayC[2] = 0; +} + +/* { dg-final { scan-assembler "lds r\[0-9\]+,varA" } } */ +/* { dg-final { scan-assembler "lds r\[0-9\]+,arrayA\\+6" } } */ +/* { dg-final { scan-assembler "lds r\[0-9\]+,arrayA\\+6\\+1" } } */ +/* { dg-final { scan-assembler "lds r\[0-9\]+,abc" } } */ +/* { dg-final { scan-assembler "lds r\[0-9\]+,abc\\+1" } } */ +/* { dg-final { scan-assembler "lds r\[0-9\]+,abc\\+2" } } */ + +/* { dg-final { scan-assembler "sts varB," } } */ +/* { dg-final { scan-assembler "sts arrayB\\+6," } } */ +/* { dg-final { scan-assembler "sts arrayB\\+6\\+1," } } */ +/* { dg-final { scan-assembler "sts arrayC," } } */ +/* { dg-final { scan-assembler "sts arrayC\\+1," } } */ +/* { dg-final { scan-assembler "sts arrayC\\+2," } } */ + +/* { dg-final { scan-assembler "sts abc," } } */ +/* { dg-final { scan-assembler "sts abc\\+1," } } */ +/* { dg-final { scan-assembler "sts abc\\+2," } } */ diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 2394ac4a131..b5a9faab5a4 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -7784,6 +7784,24 @@ proc check_effective_target_aarch64_large { } { } } + +# Return 1 if this is a reduced AVR Tiny core. Such cores have different +# register set, instruction set, addressing capabilities and ABI. + +proc check_effective_target_avr_tiny { } { + if { [istarget avr*-*-*] } { + return [check_no_compiler_messages avr_tiny object { + #ifdef __AVR_TINY__ + int dummy; + #else + #error target not a reduced AVR Tiny core + #endif + }] + } else { + return 0 + } +} + # Return 1 if is available with all the standard IEEE # exceptions and floating-point exceptions are raised by arithmetic # operations. (If the target requires special options for "inexact" -- 2.30.2