* Claudiu Zissulescu <claudiu.zissule...@synopsys.com> [2017-11-02 13:30:35 +0100]:
> From: claziss <claz...@synopsys.com> > > The 'aux' variable attribute is used to directly access the auxiliary > register space from C. > > gcc/ > 2017-07-25 Claudiu Zissulescu <claz...@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/ > 2017-07-25 Claudiu Zissulescu <claz...@synopsys.com> > > * gcc.target/arc/taux-1.c: New test. > * gcc.target/arc/taux-2.c: Likewise. Looks good. Sorry for the time taken to review this series. Thanks, Andrew > --- > gcc/config/arc/arc.c | 160 > +++++++++++++++++++++++++++++++++- > gcc/doc/extend.texi | 13 +++ > gcc/testsuite/gcc.target/arc/taux-1.c | 38 ++++++++ > gcc/testsuite/gcc.target/arc/taux-2.c | 15 ++++ > 4 files changed, 225 insertions(+), 1 deletion(-) > create mode 100644 gcc/testsuite/gcc.target/arc/taux-1.c > create mode 100644 gcc/testsuite/gcc.target/arc/taux-2.c > > diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c > index a397cbd..33f68ef 100644 > --- a/gcc/config/arc/arc.c > +++ b/gcc/config/arc/arc.c > @@ -223,6 +223,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. */ > @@ -257,6 +258,8 @@ const struct attribute_spec arc_attribute_table[] = > /* Bypass caches using .di flag. */ > { "uncached", 0, 0, false, true, false, arc_handle_uncached_attribute, > false }, > + /* Declare a variable as aux. */ > + { "aux", 0, 1, true, false, false, arc_handle_aux_attribute, false }, > { NULL, 0, 0, false, false, false, NULL, false } > }; > static int arc_comp_type_attributes (const_tree, const_tree); > @@ -8071,6 +8074,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); > @@ -8238,6 +8246,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 > @@ -8246,7 +8283,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)); > @@ -8586,12 +8630,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)) > @@ -11127,6 +11239,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, > diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi > index 0f8ba05..1f6ef4e 100644 > --- a/gcc/doc/extend.texi > +++ b/gcc/doc/extend.texi > @@ -5803,6 +5803,7 @@ attributes. > > @menu > * Common Variable Attributes:: > +* ARC Variable Attributes:: > * AVR Variable Attributes:: > * Blackfin Variable Attributes:: > * H8/300 Variable Attributes:: > @@ -6165,6 +6166,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 > > diff --git a/gcc/testsuite/gcc.target/arc/taux-1.c > b/gcc/testsuite/gcc.target/arc/taux-1.c > new file mode 100644 > index 0000000..a2b7778 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/arc/taux-1.c > @@ -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 > index 0000000..5644bcd > --- /dev/null > +++ b/gcc/testsuite/gcc.target/arc/taux-2.c > @@ -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" } } */ > -- > 1.9.1 >