summaryrefslogtreecommitdiff
path: root/gcc/config/spu
diff options
context:
space:
mode:
authoruweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4>2011-05-05 09:41:53 +0000
committeruweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4>2011-05-05 09:41:53 +0000
commitf17d2d13e03e71b846b9b035e0e1c8c6a3eae6d4 (patch)
tree7fdec05d3cf8c9e9099bbb164bbe34a42a9b7aa5 /gcc/config/spu
parentb82b45b4705a1e56ce3a70005a7e9197b810d1bf (diff)
downloadgcc-f17d2d13e03e71b846b9b035e0e1c8c6a3eae6d4.tar.gz
* config/spu/spu.c (TARGET_ASM_OUTPUT_MI_THUNK): Define.
(TARGET_ASM_CAN_OUTPUT_MI_THUNK): Likewise. (spu_output_mi_thunk): New function. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@173420 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/spu')
-rw-r--r--gcc/config/spu/spu.c93
1 files changed, 93 insertions, 0 deletions
diff --git a/gcc/config/spu/spu.c b/gcc/config/spu/spu.c
index a6c76581b33..ca065ca44de 100644
--- a/gcc/config/spu/spu.c
+++ b/gcc/config/spu/spu.c
@@ -232,6 +232,8 @@ static rtx spu_expand_load (rtx, rtx, rtx, int);
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;
@@ -502,6 +504,11 @@ static const struct attribute_spec spu_attribute_table[] =
#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
@@ -7192,4 +7199,90 @@ spu_ref_may_alias_errno (ao_ref *ref)
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"