diff options
Diffstat (limited to 'gcc-4.8/gcc/config/microblaze/microblaze.c')
-rw-r--r-- | gcc-4.8/gcc/config/microblaze/microblaze.c | 146 |
1 files changed, 103 insertions, 43 deletions
diff --git a/gcc-4.8/gcc/config/microblaze/microblaze.c b/gcc-4.8/gcc/config/microblaze/microblaze.c index c121c2bae..914246bd5 100644 --- a/gcc-4.8/gcc/config/microblaze/microblaze.c +++ b/gcc-4.8/gcc/config/microblaze/microblaze.c @@ -1609,21 +1609,28 @@ static int microblaze_version_to_int (const char *version) { const char *p, *v; - const char *tmpl = "vX.YY.Z"; + const char *tmpl = "vXX.YY.Z"; int iver = 0; p = version; v = tmpl; - while (*v) + while (*p) { if (*v == 'X') { /* Looking for major */ + if (*p == '.') + { + *v++; + } + else + { if (!(*p >= '0' && *p <= '9')) return -1; iver += (int) (*p - '0'); iver *= 10; } + } else if (*v == 'Y') { /* Looking for minor */ if (!(*p >= '0' && *p <= '9')) @@ -3064,6 +3071,73 @@ expand_pic_symbol_ref (enum machine_mode mode ATTRIBUTE_UNUSED, rtx op) return result; } +static void +microblaze_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, + HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, + tree function) +{ + rtx this_rtx, insn, funexp; + + reload_completed = 1; + epilogue_completed = 1; + + /* Mark the end of the (empty) prologue. */ + emit_note (NOTE_INSN_PROLOGUE_END); + + /* Find the "this" pointer. If the function returns a structure, + the structure return pointer is in MB_ABI_FIRST_ARG_REGNUM. */ + if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) + this_rtx = gen_rtx_REG (Pmode, (MB_ABI_FIRST_ARG_REGNUM + 1)); + else + this_rtx = gen_rtx_REG (Pmode, MB_ABI_FIRST_ARG_REGNUM); + + /* Apply the constant offset, if required. */ + if (delta) + emit_insn (gen_addsi3 (this_rtx, this_rtx, GEN_INT (delta))); + + /* Apply the offset from the vtable, if required. */ + if (vcall_offset) + { + rtx vcall_offset_rtx = GEN_INT (vcall_offset); + rtx temp1 = gen_rtx_REG (Pmode, MB_ABI_TEMP1_REGNUM); + + emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx)); + + rtx loc = gen_rtx_PLUS (Pmode, temp1, vcall_offset_rtx); + emit_move_insn (temp1, gen_rtx_MEM (Pmode, loc)); + + emit_insn (gen_addsi3 (this_rtx, this_rtx, temp1)); + } + + /* Generate a tail call to the target function. */ + if (!TREE_USED (function)) + { + assemble_external (function); + TREE_USED (function) = 1; + } + + funexp = XEXP (DECL_RTL (function), 0); + rtx temp2 = gen_rtx_REG (Pmode, MB_ABI_TEMP2_REGNUM); + + if (flag_pic) + emit_move_insn (temp2, expand_pic_symbol_ref (Pmode, funexp)); + else + emit_move_insn (temp2, funexp); + + emit_insn (gen_indirect_jump (temp2)); + + /* Run just enough of rest_of_compilation. This sequence was + "borrowed" from rs6000.c. */ + insn = get_insns (); + shorten_branches (insn); + final_start_function (insn, file, 1); + final (insn, file, 1); + final_end_function (); + + reload_completed = 0; + epilogue_completed = 0; +} + bool microblaze_expand_move (enum machine_mode mode, rtx operands[]) { @@ -3234,65 +3308,45 @@ microblaze_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) emit_move_insn (mem, fnaddr); } -/* Emit instruction to perform compare. - cmp is (compare_op op0 op1). */ -static rtx -microblaze_emit_compare (enum machine_mode mode, rtx cmp, enum rtx_code *cmp_code) +/* Generate conditional branch -- first, generate test condition, + second, generate correct branch instruction. */ + +void +microblaze_expand_conditional_branch (enum machine_mode mode, rtx operands[]) { - rtx cmp_op0 = XEXP (cmp, 0); - rtx cmp_op1 = XEXP (cmp, 1); + enum rtx_code code = GET_CODE (operands[0]); + rtx cmp_op0 = operands[1]; + rtx cmp_op1 = operands[2]; + rtx label1 = operands[3]; rtx comp_reg = gen_reg_rtx (SImode); - enum rtx_code code = *cmp_code; + rtx condition; gcc_assert ((GET_CODE (cmp_op0) == REG) || (GET_CODE (cmp_op0) == SUBREG)); /* If comparing against zero, just test source reg. */ if (cmp_op1 == const0_rtx) - return cmp_op0; + { + comp_reg = cmp_op0; + condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx); + emit_jump_insn (gen_condjump (condition, label1)); + } - if (code == EQ || code == NE) + else if (code == EQ || code == NE) { /* Use xor for equal/not-equal comparison. */ emit_insn (gen_xorsi3 (comp_reg, cmp_op0, cmp_op1)); + condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx); + emit_jump_insn (gen_condjump (condition, label1)); } - else if (code == GT || code == GTU || code == LE || code == LEU) - { - /* MicroBlaze compare is not symmetrical. */ - /* Swap argument order. */ - cmp_op1 = force_reg (mode, cmp_op1); - if (code == GT || code == LE) - emit_insn (gen_signed_compare (comp_reg, cmp_op0, cmp_op1)); else - emit_insn (gen_unsigned_compare (comp_reg, cmp_op0, cmp_op1)); - /* Translate test condition. */ - *cmp_code = swap_condition (code); - } - else /* if (code == GE || code == GEU || code == LT || code == LTU) */ { + /* Generate compare and branch in single instruction. */ cmp_op1 = force_reg (mode, cmp_op1); - if (code == GE || code == LT) - emit_insn (gen_signed_compare (comp_reg, cmp_op1, cmp_op0)); - else - emit_insn (gen_unsigned_compare (comp_reg, cmp_op1, cmp_op0)); + condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1); + emit_jump_insn (gen_branch_compare(condition, cmp_op0, cmp_op1, label1)); } - - return comp_reg; } -/* Generate conditional branch -- first, generate test condition, - second, generate correct branch instruction. */ - -void -microblaze_expand_conditional_branch (enum machine_mode mode, rtx operands[]) -{ - enum rtx_code code = GET_CODE (operands[0]); - rtx comp; - rtx condition; - - comp = microblaze_emit_compare (mode, operands[0], &code); - condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp, const0_rtx); - emit_jump_insn (gen_condjump (condition, operands[3])); -} void microblaze_expand_conditional_branch_sf (rtx operands[]) @@ -3501,6 +3555,12 @@ microblaze_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x #undef TARGET_SECONDARY_RELOAD #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload +#undef TARGET_ASM_OUTPUT_MI_THUNK +#define TARGET_ASM_OUTPUT_MI_THUNK microblaze_asm_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 + #undef TARGET_SCHED_ADJUST_COST #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost |