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. */
/* 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);
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);
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
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));
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))
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,