static void spu_trampoline_init (rtx, tree, rtx);
static void spu_conditional_register_usage (void);
static bool spu_ref_may_alias_errno (ao_ref *);
+static void spu_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
+ HOST_WIDE_INT, tree);
/* Which instruction set architecture to use. */
int spu_arch;
#undef TARGET_REF_MAY_ALIAS_ERRNO
#define TARGET_REF_MAY_ALIAS_ERRNO spu_ref_may_alias_errno
+#undef TARGET_ASM_OUTPUT_MI_THUNK
+#define TARGET_ASM_OUTPUT_MI_THUNK spu_output_mi_thunk
+#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
+
struct gcc_target targetm = TARGET_INITIALIZER;
static void
return default_ref_may_alias_errno (ref);
}
+/* Output thunk to FILE that implements a C++ virtual function call (with
+ multiple inheritance) to FUNCTION. The thunk adjusts the this pointer
+ by DELTA, and unless VCALL_OFFSET is zero, applies an additional adjustment
+ stored at VCALL_OFFSET in the vtable whose address is located at offset 0
+ relative to the resulting this pointer. */
+
+static void
+spu_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
+ HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
+ tree function)
+{
+ rtx op[8];
+
+ /* Make sure unwind info is emitted for the thunk if needed. */
+ final_start_function (emit_barrier (), file, 1);
+
+ /* Operand 0 is the target function. */
+ op[0] = XEXP (DECL_RTL (function), 0);
+
+ /* Operand 1 is the 'this' pointer. */
+ if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
+ op[1] = gen_rtx_REG (Pmode, FIRST_ARG_REGNUM + 1);
+ else
+ op[1] = gen_rtx_REG (Pmode, FIRST_ARG_REGNUM);
+
+ /* Operands 2/3 are the low/high halfwords of delta. */
+ op[2] = GEN_INT (trunc_int_for_mode (delta, HImode));
+ op[3] = GEN_INT (trunc_int_for_mode (delta >> 16, HImode));
+
+ /* Operands 4/5 are the low/high halfwords of vcall_offset. */
+ op[4] = GEN_INT (trunc_int_for_mode (vcall_offset, HImode));
+ op[5] = GEN_INT (trunc_int_for_mode (vcall_offset >> 16, HImode));
+
+ /* Operands 6/7 are temporary registers. */
+ op[6] = gen_rtx_REG (Pmode, 79);
+ op[7] = gen_rtx_REG (Pmode, 78);
+
+ /* Add DELTA to this pointer. */
+ if (delta)
+ {
+ if (delta >= -0x200 && delta < 0x200)
+ output_asm_insn ("ai\t%1,%1,%2", op);
+ else if (delta >= -0x8000 && delta < 0x8000)
+ {
+ output_asm_insn ("il\t%6,%2", op);
+ output_asm_insn ("a\t%1,%1,%6", op);
+ }
+ else
+ {
+ output_asm_insn ("ilhu\t%6,%3", op);
+ output_asm_insn ("iohl\t%6,%2", op);
+ output_asm_insn ("a\t%1,%1,%6", op);
+ }
+ }
+
+ /* Perform vcall adjustment. */
+ if (vcall_offset)
+ {
+ output_asm_insn ("lqd\t%7,0(%1)", op);
+ output_asm_insn ("rotqby\t%7,%7,%1", op);
+
+ if (vcall_offset >= -0x200 && vcall_offset < 0x200)
+ output_asm_insn ("ai\t%7,%7,%4", op);
+ else if (vcall_offset >= -0x8000 && vcall_offset < 0x8000)
+ {
+ output_asm_insn ("il\t%6,%4", op);
+ output_asm_insn ("a\t%7,%7,%6", op);
+ }
+ else
+ {
+ output_asm_insn ("ilhu\t%6,%5", op);
+ output_asm_insn ("iohl\t%6,%4", op);
+ output_asm_insn ("a\t%7,%7,%6", op);
+ }
+
+ output_asm_insn ("lqd\t%6,0(%7)", op);
+ output_asm_insn ("rotqby\t%6,%6,%7", op);
+ output_asm_insn ("a\t%1,%1,%6", op);
+ }
+
+ /* Jump to target. */
+ output_asm_insn ("br\t%0", op);
+
+ final_end_function ();
+}
+
#include "gt-spu.h"