Commit b1b6774f by Georg-Johann Lay Committed by Georg-Johann Lay

re PR target/78093 ([avr] New variable attribute "absdata" and option…

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
parent 06d1ff90
2016-10-24 Georg-Johann Lay <avr@gjlay.de>
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 <rguenther@suse.de> 2016-10-24 Richard Biener <rguenther@suse.de>
PR tree-optimization/78076 PR tree-optimization/78076
......
...@@ -85,6 +85,10 @@ ...@@ -85,6 +85,10 @@
#define AVR_SYMBOL_FLAG_TINY_PM \ #define AVR_SYMBOL_FLAG_TINY_PM \
(SYMBOL_FLAG_MACH_DEP << 7) (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) \ #define TINY_ADIW(REG1, REG2, I) \
"subi " #REG1 ",lo8(-(" #I "))" CR_TAB \ "subi " #REG1 ",lo8(-(" #I "))" CR_TAB \
"sbci " #REG2 ",hi8(-(" #I "))" "sbci " #REG2 ",hi8(-(" #I "))"
...@@ -1791,6 +1795,28 @@ avr_mode_dependent_address_p (const_rtx addr ATTRIBUTE_UNUSED, addr_space_t as) ...@@ -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'. */ /* Helper function for `avr_legitimate_address_p'. */
static inline bool static inline bool
...@@ -1875,8 +1901,7 @@ avr_legitimate_address_p (machine_mode mode, rtx x, bool strict) ...@@ -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: /* avrtiny's load / store instructions only cover addresses 0..0xbf:
IN / OUT range is 0..0x3f and LDS / STS can access 0x40..0xbf. */ IN / OUT range is 0..0x3f and LDS / STS can access 0x40..0xbf. */
ok = (CONST_INT_P (x) ok = avr_address_tiny_absdata_p (x, mode);
&& IN_RANGE (INTVAL (x), 0, 0xc0 - GET_MODE_SIZE (mode)));
} }
if (avr_log.legitimate_address_p) if (avr_log.legitimate_address_p)
...@@ -1918,8 +1943,7 @@ avr_legitimize_address (rtx x, rtx oldx, machine_mode mode) ...@@ -1918,8 +1943,7 @@ avr_legitimize_address (rtx x, rtx oldx, machine_mode mode)
if (AVR_TINY) if (AVR_TINY)
{ {
if (CONSTANT_ADDRESS_P (x) if (CONSTANT_ADDRESS_P (x)
&& !(CONST_INT_P (x) && ! avr_address_tiny_absdata_p (x, mode))
&& IN_RANGE (INTVAL (x), 0, 0xc0 - GET_MODE_SIZE (mode))))
{ {
x = force_reg (Pmode, x); x = force_reg (Pmode, x);
} }
...@@ -9149,6 +9173,32 @@ avr_handle_fntype_attribute (tree *node, tree name, ...@@ -9149,6 +9173,32 @@ avr_handle_fntype_attribute (tree *node, tree name,
} }
static 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, avr_handle_addr_attribute (tree *node, tree name, tree args,
int flags ATTRIBUTE_UNUSED, bool *no_add) int flags ATTRIBUTE_UNUSED, bool *no_add)
{ {
...@@ -9255,6 +9305,8 @@ avr_attribute_table[] = ...@@ -9255,6 +9305,8 @@ avr_attribute_table[] =
false }, false },
{ "address", 1, 1, false, false, false, avr_handle_addr_attribute, { "address", 1, 1, false, false, false, avr_handle_addr_attribute,
false }, false },
{ "absdata", 0, 0, true, false, false, avr_handle_absdata_attribute,
false },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false }
}; };
...@@ -9339,6 +9391,17 @@ avr_progmem_p (tree decl, tree attributes) ...@@ -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. /* Scan type TYP for pointer references to address space ASn.
Return ADDR_SPACE_GENERIC (i.e. 0) if all pointers targeting Return ADDR_SPACE_GENERIC (i.e. 0) if all pointers targeting
the AS are also declared to be CONST. the AS are also declared to be CONST.
...@@ -9694,6 +9757,8 @@ avr_section_type_flags (tree decl, const char *name, int reloc) ...@@ -9694,6 +9757,8 @@ avr_section_type_flags (tree decl, const char *name, int reloc)
static void 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)
{ {
tree addr_attr = NULL_TREE;
/* In avr_handle_progmem_attribute, DECL_INITIAL is not yet /* In avr_handle_progmem_attribute, DECL_INITIAL is not yet
readily available, see PR34734. So we postpone the warning readily available, see PR34734. So we postpone the warning
about uninitialized data in program memory section until here. */ 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) ...@@ -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_low_attr = lookup_attribute ("io_low", attr);
tree io_attr = lookup_attribute ("io", attr); tree io_attr = lookup_attribute ("io", attr);
tree addr_attr;
if (io_low_attr if (io_low_attr
&& TREE_VALUE (io_low_attr) && TREE_VALUE (TREE_VALUE (io_low_attr))) && TREE_VALUE (io_low_attr) && TREE_VALUE (TREE_VALUE (io_low_attr)))
addr_attr = io_attr; addr_attr = io_attr;
...@@ -9763,15 +9828,33 @@ avr_encode_section_info (tree decl, rtx rtl, int new_decl_p) ...@@ -9763,15 +9828,33 @@ avr_encode_section_info (tree decl, rtx rtl, int new_decl_p)
if (AVR_TINY if (AVR_TINY
&& decl && decl
&& VAR_DECL == TREE_CODE (decl) && VAR_DECL == TREE_CODE (decl)
&& -1 == avr_progmem_p (decl, DECL_ATTRIBUTES (decl))
&& MEM_P (rtl) && MEM_P (rtl)
&& SYMBOL_REF_P (XEXP (rtl, 0))) && SYMBOL_REF_P (XEXP (rtl, 0)))
{ {
/* Tag symbols for later addition of 0x4000 (AVR_TINY_PM_OFFSET). */
rtx sym = XEXP (rtl, 0); rtx sym = XEXP (rtl, 0);
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; 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, ...@@ -10900,6 +10983,10 @@ avr_address_cost (rtx x, machine_mode mode ATTRIBUTE_UNUSED,
if (optimize > 0 if (optimize > 0
&& io_address_operand (x, QImode)) && io_address_operand (x, QImode))
cost = 2; cost = 2;
if (AVR_TINY
&& avr_address_tiny_absdata_p (x, QImode))
cost = 2;
} }
if (avr_log.address_cost) if (avr_log.address_cost)
......
...@@ -5973,6 +5973,33 @@ memory-mapped peripherals that may lie outside the io address range. ...@@ -5973,6 +5973,33 @@ memory-mapped peripherals that may lie outside the io address range.
volatile int porta __attribute__((address (0x600))); volatile int porta __attribute__((address (0x600)));
@end smallexample @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 @end table
@node Blackfin Variable Attributes @node Blackfin Variable Attributes
......
2016-10-24 Georg-Johann Lay <avr@gjlay.de>
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 <andre.simoesdiasvieira@arm.com> 2016-10-24 Andre Vieira <andre.simoesdiasvieira@arm.com>
* gcc.target/arm/pure-code/pure-code.exp: Restore saved globals. * gcc.target/arm/pure-code/pure-code.exp: Restore saved globals.
......
/* { 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," } } */
...@@ -7784,6 +7784,24 @@ proc check_effective_target_aarch64_large { } { ...@@ -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 <fenv.h> is available with all the standard IEEE # Return 1 if <fenv.h> is available with all the standard IEEE
# exceptions and floating-point exceptions are raised by arithmetic # exceptions and floating-point exceptions are raised by arithmetic
# operations. (If the target requires special options for "inexact" # operations. (If the target requires special options for "inexact"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment