[ARC] Add 'aux' variable attribute.
authorClaudiu Zissulescu <claziss@synopsys.com>
Wed, 31 Jan 2018 10:01:48 +0000 (11:01 +0100)
committerClaudiu Zissulescu <claziss@gcc.gnu.org>
Wed, 31 Jan 2018 10:01:48 +0000 (11:01 +0100)
The 'aux' variable attribute is used to directly access the auxiliary
register space from C.

gcc/
2018-01-31  Claudiu Zissulescu  <claziss@synopsys.com>

        * config/arc/arc.c (arc_handle_aux_attribute): New function.
        (arc_attribute_table): Add 'aux' attribute.
        (arc_in_small_data_p): Consider aux like variables.
        (arc_is_aux_reg_p): New function.
        (arc_asm_output_aligned_decl_local): Ignore 'aux' like variables.
        (arc_get_aux_arg): New function.
        (prepare_move_operands): Handle aux-register access.
        (arc_handle_aux_attribute): New function.
        * doc/extend.texi (ARC Variable attributes): Add subsection.

testsuite/
2018-01-31  Claudiu Zissulescu  <claziss@synopsys.com>

        * gcc.target/arc/taux-1.c: New test.
        * gcc.target/arc/taux-2.c: Likewise.

From-SVN: r257223

gcc/ChangeLog
gcc/config/arc/arc.c
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/arc/taux-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arc/taux-2.c [new file with mode: 0644]

index 0b380db6b52b687c0da177600be20611af723ffc..db2c33536cee5e42d5e2b16bf0d31da9ed1f3eaf 100644 (file)
@@ -1,3 +1,15 @@
+2018-01-31  Claudiu Zissulescu  <claziss@synopsys.com>
+
+       * config/arc/arc.c (arc_handle_aux_attribute): New function.
+       (arc_attribute_table): Add 'aux' attribute.
+       (arc_in_small_data_p): Consider aux like variables.
+       (arc_is_aux_reg_p): New function.
+       (arc_asm_output_aligned_decl_local): Ignore 'aux' like variables.
+       (arc_get_aux_arg): New function.
+       (prepare_move_operands): Handle aux-register access.
+       (arc_handle_aux_attribute): New function.
+       * doc/extend.texi (ARC Variable attributes): Add subsection.
+
 2018-01-31  Claudiu Zissulescu  <claziss@synopsys.com>
 
        * config/arc/arc-protos.h (arc_is_uncached_mem_p): Function proto.
index 624404cf35a58d455d885b47507c435eb2f8451c..843defd4cda3344251bda4b6f2cb2a0cc1c81550 100644 (file)
@@ -228,6 +228,7 @@ static tree arc_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
 static tree arc_handle_jli_attribute (tree *, tree, tree, int, bool *);
 static tree arc_handle_secure_attribute (tree *, tree, tree, int, bool *);
 static tree arc_handle_uncached_attribute (tree *, tree, tree, int, bool *);
+static tree arc_handle_aux_attribute (tree *, tree, tree, int, bool *);
 
 /* Initialized arc_attribute_table to NULL since arc doesnot have any
    machine specific supported attributes.  */
@@ -264,6 +265,7 @@ const struct attribute_spec arc_attribute_table[] =
    /* Bypass caches using .di flag.  */
   { "uncached", 0, 0, false, true, false, false, arc_handle_uncached_attribute,
     NULL },
+  { "aux", 0, 1, true, false, false, false, arc_handle_aux_attribute, NULL },
   { NULL, 0, 0, false, false, false, false, NULL, NULL }
 };
 static int arc_comp_type_attributes (const_tree, const_tree);
@@ -8135,6 +8137,11 @@ arc_in_small_data_p (const_tree decl)
   if (lookup_attribute ("uncached", attr))
     return false;
 
+  /* and for aux regs.  */
+  attr = DECL_ATTRIBUTES (decl);
+  if (lookup_attribute ("aux", attr))
+    return false;
+
   if (DECL_SECTION_NAME (decl) != 0)
     {
       const char *name = DECL_SECTION_NAME (decl);
@@ -8302,6 +8309,35 @@ compact_sda_memory_operand (rtx op, machine_mode mode, bool short_p)
   return false;
 }
 
+/* Return TRUE if PAT is accessing an aux-reg.  */
+
+static bool
+arc_is_aux_reg_p (rtx pat)
+{
+  tree attrs = NULL_TREE;
+  tree addr;
+
+  if (!MEM_P (pat))
+    return false;
+
+  /* Get the memory attributes.  */
+  addr = MEM_EXPR (pat);
+  if (!addr)
+    return false;
+
+  /* Get the attributes.  */
+  if (TREE_CODE (addr) == VAR_DECL)
+    attrs = DECL_ATTRIBUTES (addr);
+  else if (TREE_CODE (addr) == MEM_REF)
+    attrs = TYPE_ATTRIBUTES (TREE_TYPE (TREE_OPERAND (addr, 0)));
+  else
+    return false;
+
+  if (lookup_attribute ("aux", attrs))
+    return true;
+  return false;
+}
+
 /* Implement ASM_OUTPUT_ALIGNED_DECL_LOCAL.  */
 
 void
@@ -8310,7 +8346,14 @@ arc_asm_output_aligned_decl_local (FILE * stream, tree decl, const char * name,
                                   unsigned HOST_WIDE_INT align,
                                   unsigned HOST_WIDE_INT globalize_p)
 {
-  int in_small_data =   arc_in_small_data_p (decl);
+  int in_small_data = arc_in_small_data_p (decl);
+  rtx mem = decl == NULL_TREE ? NULL_RTX : DECL_RTL (decl);
+
+  /* Don't output aux-reg symbols.  */
+  if (mem != NULL_RTX && MEM_P (mem)
+      && SYMBOL_REF_P (XEXP (mem, 0))
+      && arc_is_aux_reg_p (mem))
+    return;
 
   if (in_small_data)
     switch_to_section (get_named_section (NULL, ".sbss", 0));
@@ -8650,12 +8693,80 @@ arc_expand_movmem (rtx *operands)
   return true;
 }
 
+static bool
+arc_get_aux_arg (rtx pat, int *auxr)
+{
+  tree attr, addr = MEM_EXPR (pat);
+  if (TREE_CODE (addr) != VAR_DECL)
+    return false;
+
+  attr = DECL_ATTRIBUTES (addr);
+  if (lookup_attribute ("aux", attr))
+    {
+      tree arg = TREE_VALUE (attr);
+      if (arg)
+       {
+         *auxr = TREE_INT_CST_LOW (TREE_VALUE (arg));
+         return true;
+       }
+    }
+
+  return false;
+}
+
 /* Prepare operands for move in MODE.  Return true iff the move has
    been emitted.  */
 
 bool
 prepare_move_operands (rtx *operands, machine_mode mode)
 {
+  /* First handle aux attribute.  */
+  if (mode == SImode
+      && (MEM_P (operands[0]) || MEM_P (operands[1])))
+    {
+      rtx tmp;
+      int auxr = 0;
+      if (MEM_P (operands[0]) && arc_is_aux_reg_p (operands[0]))
+       {
+         /* Save operation.  */
+         if (arc_get_aux_arg (operands[0], &auxr))
+           {
+             tmp = gen_reg_rtx (SImode);
+             emit_move_insn (tmp, GEN_INT (auxr));
+           }
+         else
+           {
+             tmp = XEXP (operands[0], 0);
+           }
+
+         operands[1] = force_reg (SImode, operands[1]);
+         emit_insn (gen_rtx_UNSPEC_VOLATILE
+                    (VOIDmode, gen_rtvec (2, operands[1], tmp),
+                     VUNSPEC_ARC_SR));
+         return true;
+       }
+      if (MEM_P (operands[1]) && arc_is_aux_reg_p (operands[1]))
+       {
+         if (arc_get_aux_arg (operands[1], &auxr))
+           {
+             tmp = gen_reg_rtx (SImode);
+             emit_move_insn (tmp, GEN_INT (auxr));
+           }
+         else
+           {
+             tmp = XEXP (operands[1], 0);
+             gcc_assert (GET_CODE (tmp) == SYMBOL_REF);
+           }
+         /* Load operation.  */
+         gcc_assert (REG_P (operands[0]));
+         emit_insn (gen_rtx_SET (operands[0],
+                                 gen_rtx_UNSPEC_VOLATILE
+                                 (SImode, gen_rtvec (1, tmp),
+                                  VUNSPEC_ARC_LR)));
+         return true;
+       }
+    }
+
   /* We used to do this only for MODE_INT Modes, but addresses to floating
      point variables may well be in the small data section.  */
   if (!TARGET_NO_SDATA_SET && small_data_pattern (operands[0], Pmode))
@@ -11191,6 +11302,52 @@ arc_is_uncached_mem_p (rtx pat)
   return false;
 }
 
+/* Handle aux attribute.  The auxiliary registers are addressed using
+   special instructions lr and sr.  The attribute 'aux' indicates if a
+   variable refers to the aux-regs and what is the register number
+   desired.  */
+
+static tree
+arc_handle_aux_attribute (tree *node,
+                         tree name, tree args, int,
+                         bool *no_add_attrs)
+{
+  /* Isn't it better to use address spaces for the aux-regs?  */
+  if (DECL_P (*node))
+    {
+      if (TREE_CODE (*node) != VAR_DECL)
+       {
+         error ("%qE attribute only applies to variables",  name);
+         *no_add_attrs = true;
+       }
+      else if (args)
+       {
+         if (TREE_CODE (TREE_VALUE (args)) == NON_LVALUE_EXPR)
+           TREE_VALUE (args) = TREE_OPERAND (TREE_VALUE (args), 0);
+         tree arg = TREE_VALUE (args);
+         if (TREE_CODE (arg) != INTEGER_CST)
+           {
+             warning (0, "%qE attribute allows only an integer "
+                      "constant argument", name);
+             *no_add_attrs = true;
+           }
+         /* FIXME! add range check.  TREE_INT_CST_LOW (arg) */
+       }
+
+      if (TREE_CODE (*node) == VAR_DECL)
+       {
+         tree fntype = TREE_TYPE (*node);
+         if (fntype && TREE_CODE (fntype) == POINTER_TYPE)
+           {
+             tree attrs = tree_cons (get_identifier ("aux"), NULL_TREE,
+                                     TYPE_ATTRIBUTES (fntype));
+             TYPE_ATTRIBUTES (fntype) = attrs;
+           }
+       }
+    }
+  return NULL_TREE;
+}
+
 /* Implement TARGET_USE_ANCHORS_FOR_SYMBOL_P.  We don't want to use
    anchors for small data: the GP register acts as an anchor in that
    case.  We also don't want to use them for PC-relative accesses,
index 8eef2a492b361a28c476287c69dc1e4f633f3d68..cb9df971a5fa5bf87ee84a22345b3bba98a20222 100644 (file)
@@ -5894,6 +5894,7 @@ attributes.
 
 @menu
 * Common Variable Attributes::
+* ARC Variable Attributes::
 * AVR Variable Attributes::
 * Blackfin Variable Attributes::
 * H8/300 Variable Attributes::
@@ -6267,6 +6268,18 @@ The @code{weak} attribute is described in
 
 @end table
 
+@node ARC Variable Attributes
+@subsection ARC Variable Attributes
+
+@table @code
+@item aux
+@cindex @code{aux} variable attribute, ARC
+The @code{aux} attribute is used to directly access the ARC's
+auxiliary register space from C.  The auxilirary register number is
+given via attribute argument.
+
+@end table
+
 @node AVR Variable Attributes
 @subsection AVR Variable Attributes
 
index 9056519e8ce008ea4208834c47b367f7beef8f5c..d6bca32809648a7528795167c5ff7b232e90ca2d 100644 (file)
@@ -1,3 +1,8 @@
+2018-01-31  Claudiu Zissulescu  <claziss@synopsys.com>
+
+       * gcc.target/arc/taux-1.c: New test.
+       * gcc.target/arc/taux-2.c: Likewise.
+
 2018-01-31  Claudiu Zissulescu  <claziss@synopsys.com>
 
        * gcc.target/arc/uncached.c: New test.
diff --git a/gcc/testsuite/gcc.target/arc/taux-1.c b/gcc/testsuite/gcc.target/arc/taux-1.c
new file mode 100644 (file)
index 0000000..a2b7778
--- /dev/null
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 */
+
+
+#define __aux() __attribute__((aux))
+
+__aux() int *a_ptr;
+extern __aux() int a_var;
+
+/* Generates:
+   mov r0, @a_var
+   sr  10,[r0]
+*/
+void foo (void)
+{
+  a_var = 10;
+}
+
+/* Generates:
+   mov r0, @a_ptr
+   sr  a_var,[r0]
+*/
+void foo1 (void)
+{
+  a_ptr = &a_var;
+}
+
+/* Generates:
+   lr  %r1,[a_ptr]
+   sr  10,[%r1]
+*/
+void foo2 (void)
+{
+  *a_ptr = 10;
+}
+
+/* { dg-final { scan-assembler-times "sr" 3 } } */
+/* { dg-final { scan-assembler-times "lr" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arc/taux-2.c b/gcc/testsuite/gcc.target/arc/taux-2.c
new file mode 100644 (file)
index 0000000..5644bcd
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 */
+
+#define __aux(r) __attribute__((aux(r)))
+static volatile __aux(0x1000) int var;
+
+int foo (void)
+{
+  var++;
+}
+
+/* { dg-final { scan-assembler-times "sr" 1 } } */
+/* { dg-final { scan-assembler-times "lr" 1 } } */
+/* { dg-final { scan-assembler "4096" } } */
+/* { dg-final { scan-assembler-not "\\.type\tvar, @object" } } */