#include "function.h"
#include "toplev.h"
#include "optabs.h"
+#include "output.h"
#include "libfuncs.h"
+#include "ggc.h"
#include "target.h"
#include "target-def.h"
#define LARGEST_MOVE_RATIO 15
/* Define the structure for the machine field in struct function. */
-struct machine_function
+struct machine_function GTY(())
{
int accesses_prev_frame;
};
NO_REGS, NO_REGS, NO_REGS, NO_REGS,
};
+static int b4const_or_zero PARAMS ((int));
+static enum internal_test map_test_to_internal_test PARAMS ((enum rtx_code));
+static rtx gen_int_relational PARAMS ((enum rtx_code, rtx, rtx, int *));
+static rtx gen_float_relational PARAMS ((enum rtx_code, rtx, rtx));
+static rtx gen_conditional_move PARAMS ((rtx));
+static rtx fixup_subreg_mem PARAMS ((rtx x));
+static enum machine_mode xtensa_find_mode_for_size PARAMS ((unsigned));
+static struct machine_function * xtensa_init_machine_status PARAMS ((void));
+static void printx PARAMS ((FILE *, signed int));
+static void xtensa_select_rtx_section PARAMS ((enum machine_mode, rtx,
+ unsigned HOST_WIDE_INT));
+static void xtensa_encode_section_info PARAMS ((tree, int));
+
+static rtx frame_size_const;
+static int current_function_arg_words;
+static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
+ REG_ALLOC_ORDER;
+\f
/* This macro generates the assembly code for function entry.
FILE is a stdio stream to output the code to.
SIZE is an int: how many units of temporary storage to allocate.
#undef TARGET_ASM_ALIGNED_SI_OP
#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
-struct gcc_target targetm = TARGET_INITIALIZER;
-
-static int b4const_or_zero PARAMS ((int));
-static enum internal_test map_test_to_internal_test PARAMS ((enum rtx_code));
-static rtx gen_int_relational PARAMS ((enum rtx_code, rtx, rtx, int *));
-static rtx gen_float_relational PARAMS ((enum rtx_code, rtx, rtx));
-static rtx gen_conditional_move PARAMS ((rtx));
-static rtx fixup_subreg_mem PARAMS ((rtx x));
-static enum machine_mode xtensa_find_mode_for_size PARAMS ((unsigned));
-static void xtensa_init_machine_status PARAMS ((struct function *p));
-static void xtensa_free_machine_status PARAMS ((struct function *p));
-static void printx PARAMS ((FILE *, signed int));
-static rtx frame_size_const;
-static int current_function_arg_words;
-static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
- REG_ALLOC_ORDER;
+#undef TARGET_ASM_SELECT_RTX_SECTION
+#define TARGET_ASM_SELECT_RTX_SECTION xtensa_select_rtx_section
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO xtensa_encode_section_info
+struct gcc_target targetm = TARGET_INITIALIZER;
+\f
/*
* Functions to test Xtensa immediate operand validity.
if (!ACC_REG_P (dst_regnum))
return true;
}
- else if (register_operand (operands[1], mode))
+ if (register_operand (operands[1], mode))
{
int src_regnum = xt_true_regnum (operands[1]);
if (!ACC_REG_P (src_regnum))
if (num_pieces >= move_ratio)
return 0;
- /* make sure the memory addresses are valid */
+ /* make sure the memory addresses are valid */
operands[0] = validize_mem (dest);
operands[1] = validize_mem (src);
}
-static void
-xtensa_init_machine_status (p)
- struct function *p;
+static struct machine_function *
+xtensa_init_machine_status ()
{
- p->machine = (struct machine_function *)
- xcalloc (1, sizeof (struct machine_function));
-}
-
-
-static void
-xtensa_free_machine_status (p)
- struct function *p;
-{
- free (p->machine);
- p->machine = NULL;
+ return ggc_alloc_cleared (sizeof (struct machine_function));
}
int callop;
rtx *operands;
{
- char *result = (char *) malloc (64);
+ static char result[64];
rtx tgt = operands[callop];
if (GET_CODE (tgt) == CONST_INT)
}
init_machine_status = xtensa_init_machine_status;
- free_machine_status = xtensa_free_machine_status;
/* Check PIC settings. There's no need for -fPIC on Xtensa and
some targets need to always use PIC. */
}
case MEM:
- /*
- * For a volatile memory reference, emit a MEMW before the
- * load or store.
- */
+ /* For a volatile memory reference, emit a MEMW before the
+ load or store. */
if (letter == 'v')
{
if (MEM_VOLATILE_P (op) && TARGET_SERIALIZE_VOLATILE)
break;
}
else if (letter == 'N')
- op = adjust_address (op, GET_MODE (op), 4);
+ {
+ enum machine_mode mode;
+ switch (GET_MODE (op))
+ {
+ case DFmode: mode = SFmode; break;
+ case DImode: mode = SImode; break;
+ default: abort ();
+ }
+ op = adjust_address (op, mode, 4);
+ }
output_address (XEXP (op, 0));
break;
/* A C compound statement to output to stdio stream STREAM the
assembler syntax for an instruction operand that is a memory
- reference whose address is ADDR. ADDR is an RTL expression.
-
- On some machines, the syntax for a symbolic address depends on
- the section that the address refers to. On these machines,
- define the macro 'ENCODE_SECTION_INFO' to store the information
- into the 'symbol_ref', and then check for it here. */
+ reference whose address is ADDR. ADDR is an RTL expression. */
void
print_operand_address (file, addr)
tree f_stk, stk;
tree f_reg, reg;
tree f_ndx, ndx;
- tree tmp, addr_tree;
- rtx array, orig_ndx, r, addr;
- HOST_WIDE_INT size, va_size;
+ tree tmp, addr_tree, type_size;
+ rtx array, orig_ndx, r, addr, size, va_size;
rtx lab_false, lab_over, lab_false2;
- size = int_size_in_bytes (type);
- va_size = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
-
f_stk = TYPE_FIELDS (va_list_type_node);
f_reg = TREE_CHAIN (f_stk);
f_ndx = TREE_CHAIN (f_reg);
reg = build (COMPONENT_REF, TREE_TYPE (f_reg), valist, f_reg);
ndx = build (COMPONENT_REF, TREE_TYPE (f_ndx), valist, f_ndx);
+ type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type));
+
+ va_size = gen_reg_rtx (SImode);
+ tmp = fold (build (MULT_EXPR, sizetype,
+ fold (build (TRUNC_DIV_EXPR, sizetype,
+ fold (build (PLUS_EXPR, sizetype,
+ type_size,
+ size_int (UNITS_PER_WORD - 1))),
+ size_int (UNITS_PER_WORD))),
+ size_int (UNITS_PER_WORD)));
+ r = expand_expr (tmp, va_size, SImode, EXPAND_NORMAL);
+ if (r != va_size)
+ emit_move_insn (va_size, r);
+
/* First align __va_ndx to a double word boundary if necessary for this arg:
if (r != orig_ndx)
emit_move_insn (orig_ndx, r);
- tmp = build (PLUS_EXPR, integer_type_node, ndx, build_int_2 (va_size, 0));
+ tmp = build (PLUS_EXPR, integer_type_node, ndx,
+ make_tree (intSI_type_node, va_size));
tmp = build (MODIFY_EXPR, integer_type_node, ndx, tmp);
TREE_SIDE_EFFECTS (tmp) = 1;
expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
/* Check if the argument is in registers:
- if ((AP).__va_ndx <= __MAX_ARGS_IN_REGISTERS * 4)
+ if ((AP).__va_ndx <= __MAX_ARGS_IN_REGISTERS * 4
+ && !MUST_PASS_IN_STACK (type))
__array = (AP).__va_reg;
*/
- lab_false = gen_label_rtx ();
- lab_over = gen_label_rtx ();
array = gen_reg_rtx (Pmode);
- emit_cmp_and_jump_insns (expand_expr (ndx, NULL_RTX, SImode, EXPAND_NORMAL),
- GEN_INT (MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD),
- GT, const1_rtx, SImode, 0, lab_false);
-
- r = expand_expr (reg, array, Pmode, EXPAND_NORMAL);
- if (r != array)
- emit_move_insn (array, r);
-
- emit_jump_insn (gen_jump (lab_over));
- emit_barrier ();
- emit_label (lab_false);
-
+ lab_over = NULL_RTX;
+ if (!MUST_PASS_IN_STACK (VOIDmode, type))
+ {
+ lab_false = gen_label_rtx ();
+ lab_over = gen_label_rtx ();
+
+ emit_cmp_and_jump_insns (expand_expr (ndx, NULL_RTX, SImode,
+ EXPAND_NORMAL),
+ GEN_INT (MAX_ARGS_IN_REGISTERS
+ * UNITS_PER_WORD),
+ GT, const1_rtx, SImode, 0, lab_false);
+
+ r = expand_expr (reg, array, Pmode, EXPAND_NORMAL);
+ if (r != array)
+ emit_move_insn (array, r);
+
+ emit_jump_insn (gen_jump (lab_over));
+ emit_barrier ();
+ emit_label (lab_false);
+ }
/* ...otherwise, the argument is on the stack (never split between
registers and the stack -- change __va_ndx if necessary):
GEN_INT (MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD),
GE, const1_rtx, SImode, 0, lab_false2);
- tmp = build_int_2 ((MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD) + va_size, 0);
+ tmp = build (PLUS_EXPR, sizetype, make_tree (intSI_type_node, va_size),
+ build_int_2 (MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD, 0));
tmp = build (MODIFY_EXPR, integer_type_node, ndx, tmp);
TREE_SIDE_EFFECTS (tmp) = 1;
expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
if (r != array)
emit_move_insn (array, r);
+ if (lab_over != NULL_RTX)
+ emit_label (lab_over);
+
/* Given the base array pointer (__array) and index to the subsequent
argument (__va_ndx), find the address:
- Big-endian:
- __array + (AP).__va_ndx - sizeof (TYPE)
-
- Little-endian:
- __array + (AP).__va_ndx - __va_size (TYPE)
+ __array + (AP).__va_ndx - (BYTES_BIG_ENDIAN && sizeof (TYPE) < 4
+ ? sizeof (TYPE)
+ : __va_size (TYPE))
The results are endian-dependent because values smaller than one word
are aligned differently.
*/
- emit_label (lab_over);
+ size = gen_reg_rtx (SImode);
+ emit_move_insn (size, va_size);
+
+ if (BYTES_BIG_ENDIAN)
+ {
+ rtx lab_use_va_size = gen_label_rtx ();
+
+ emit_cmp_and_jump_insns (expand_expr (type_size, NULL_RTX, SImode,
+ EXPAND_NORMAL),
+ GEN_INT (PARM_BOUNDARY / BITS_PER_UNIT),
+ GE, const1_rtx, SImode, 0, lab_use_va_size);
+
+ r = expand_expr (type_size, size, SImode, EXPAND_NORMAL);
+ if (r != size)
+ emit_move_insn (size, r);
+
+ emit_label (lab_use_va_size);
+ }
addr_tree = build (PLUS_EXPR, ptr_type_node,
make_tree (ptr_type_node, array),
ndx);
- addr_tree = build (PLUS_EXPR, ptr_type_node,
- addr_tree,
- build_int_2 (BYTES_BIG_ENDIAN
- && size < (PARM_BOUNDARY / BITS_PER_UNIT)
- ? -size
- : -va_size, -1));
+ addr_tree = build (MINUS_EXPR, ptr_type_node, addr_tree,
+ make_tree (intSI_type_node, size));
addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
addr = copy_to_reg (addr);
return addr;
return 0;
}
+
+/* The literal pool stays with the function. */
+
+static void
+xtensa_select_rtx_section (mode, x, align)
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+ rtx x ATTRIBUTE_UNUSED;
+ unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
+{
+ function_section (current_function_decl);
+}
+
+/* If we are referencing a function that is static, make the SYMBOL_REF
+ special so that we can generate direct calls to it even with -fpic. */
+
+static void
+xtensa_encode_section_info (decl, first)
+ tree decl;
+ int first ATTRIBUTE_UNUSED;
+{
+ if (TREE_CODE (decl) == FUNCTION_DECL && ! TREE_PUBLIC (decl))
+ SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
+}
+
+#include "gt-xtensa.h"