diff mbox

[avr] Introduce absdata attribute to allow LDS /STS on Tiny

Message ID 6be52088-1400-5031-e108-2767ca4675b6@gjlay.de
State New
Headers show

Commit Message

Georg-Johann Lay Oct. 12, 2016, 11:32 a.m. UTC
This patch introduces a new variable attribute "absdata".

Reduced Tiny cores have only a limited range of addresses 0x40..0xbf which can 
be handled by LDS / STS directly.  The attribute allows the user to assert that 
it is legitimate to use absolute addressing for such addresses and that there 
is no need for bulky load of address + indirect addressing.

Allowed addresses actually range from 0x0 to 0xbf because IN / OUT can handle 
absolute addresses in the lower range 0x0..0x3f.

Ok for trunk?

Johann


gcc/
	* 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/
	* lib/target-supports.exp (check_effective_target_avr_tiny): New proc.
	* gcc.target/avr/torture/tiny-absdata-1.c: New test.

Comments

Denis Chertykov Oct. 14, 2016, 3:08 p.m. UTC | #1
2016-10-12 14:32 GMT+03:00 Georg-Johann Lay <avr@gjlay.de>:
> This patch introduces a new variable attribute "absdata".
>
> Reduced Tiny cores have only a limited range of addresses 0x40..0xbf which
> can be handled by LDS / STS directly.  The attribute allows the user to
> assert that it is legitimate to use absolute addressing for such addresses
> and that there is no need for bulky load of address + indirect addressing.
>
> Allowed addresses actually range from 0x0 to 0xbf because IN / OUT can
> handle absolute addresses in the lower range 0x0..0x3f.
>
> Ok for trunk?
>

Approved.
Please apply.

> Johann
>
>
> gcc/
>         * 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/
>         * lib/target-supports.exp (check_effective_target_avr_tiny): New
> proc.
>         * gcc.target/avr/torture/tiny-absdata-1.c: New test.
diff mbox

Patch

Index: doc/extend.texi
===================================================================
--- doc/extend.texi	(revision 240915)
+++ doc/extend.texi	(working copy)
@@ -5973,6 +5973,33 @@  memory-mapped peripherals that may lie o
 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
Index: config/avr/avr.c
===================================================================
--- config/avr/avr.c	(revision 240966)
+++ config/avr/avr.c	(working copy)
@@ -84,6 +84,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 "))"
@@ -1790,6 +1794,28 @@  avr_mode_dependent_address_p (const_rtx
 }
 
 
+/* 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
@@ -1874,8 +1900,7 @@  avr_legitimate_address_p (machine_mode m
       /* 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)
@@ -1917,8 +1942,7 @@  avr_legitimize_address (rtx x, rtx oldx,
   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,
 }
 
 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)
 {
@@ -9217,8 +9267,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))
@@ -9254,6 +9304,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 }
 };
 
@@ -9338,6 +9390,17 @@  avr_progmem_p (tree decl, tree attribute
 }
 
 
+/* 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.
@@ -9693,6 +9756,8 @@  avr_section_type_flags (tree decl, const
 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.  */
@@ -9734,7 +9799,7 @@  avr_encode_section_info (tree decl, rtx
 
       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;
@@ -9762,14 +9827,32 @@  avr_encode_section_info (tree decl, rtx
   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");
+        }
     }
 }
 
@@ -10899,6 +10982,10 @@  avr_address_cost (rtx x, machine_mode mo
       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)
Index: testsuite/gcc.target/avr/torture/tiny-absdata-1.c
===================================================================
--- testsuite/gcc.target/avr/torture/tiny-absdata-1.c	(nonexistent)
+++ testsuite/gcc.target/avr/torture/tiny-absdata-1.c	(working copy)
@@ -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," } } */
Index: testsuite/lib/target-supports.exp
===================================================================
--- testsuite/lib/target-supports.exp	(revision 240915)
+++ testsuite/lib/target-supports.exp	(working copy)
@@ -7618,6 +7618,24 @@  proc check_effective_target_aarch64_larg
     }
 }
 
+
+# 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
 # exceptions and floating-point exceptions are raised by arithmetic
 # operations.  (If the target requires special options for "inexact"