📄 mmix.c
字号:
}/* PRINT_OPERAND_PUNCT_VALID_P. */intmmix_print_operand_punct_valid_p (code) int code ATTRIBUTE_UNUSED;{ /* A '+' is used for branch prediction, similar to other ports. */ return code == '+' /* A '.' is used for the %d in the POP %d,0 return insn. */ || code == '.';}/* PRINT_OPERAND_ADDRESS. */voidmmix_print_operand_address (stream, x) FILE *stream; rtx x;{ if (REG_P (x)) { /* I find the generated assembly code harder to read without the ",0". */ fprintf (stream, "%s,0", reg_names[MMIX_OUTPUT_REGNO (REGNO (x))]); return; } else if (GET_CODE (x) == PLUS) { rtx x1 = XEXP (x, 0); rtx x2 = XEXP (x, 1); if (REG_P (x1)) { fprintf (stream, "%s,", reg_names[MMIX_OUTPUT_REGNO (REGNO (x1))]); if (REG_P (x2)) { fprintf (stream, "%s", reg_names[MMIX_OUTPUT_REGNO (REGNO (x2))]); return; } else if (GET_CODE (x2) == CONST_INT && CONST_OK_FOR_LETTER_P (INTVAL (x2), 'I')) { output_addr_const (stream, x2); return; } } } if (TARGET_BASE_ADDRESSES && mmix_legitimate_constant_p (x)) { output_addr_const (stream, x); return; } fatal_insn ("MMIX Internal: This is not a recognized address", x);}/* ASM_OUTPUT_REG_PUSH. */voidmmix_asm_output_reg_push (stream, regno) FILE * stream; int regno;{ fprintf (stream, "\tSUBU %s,%s,8\n\tSTOU %s,%s,0\n", reg_names[MMIX_STACK_POINTER_REGNUM], reg_names[MMIX_STACK_POINTER_REGNUM], reg_names[MMIX_OUTPUT_REGNO (regno)], reg_names[MMIX_STACK_POINTER_REGNUM]);}/* ASM_OUTPUT_REG_POP. */voidmmix_asm_output_reg_pop (stream, regno) FILE * stream; int regno;{ fprintf (stream, "\tLDOU %s,%s,0\n\tINCL %s,8\n", reg_names[MMIX_OUTPUT_REGNO (regno)], reg_names[MMIX_STACK_POINTER_REGNUM], reg_names[MMIX_STACK_POINTER_REGNUM]);}/* ASM_OUTPUT_ADDR_DIFF_ELT. */voidmmix_asm_output_addr_diff_elt (stream, body, value, rel) FILE *stream; rtx body ATTRIBUTE_UNUSED; int value; int rel;{ fprintf (stream, "\tTETRA L%d-L%d\n", value, rel);}/* ASM_OUTPUT_ADDR_VEC_ELT. */voidmmix_asm_output_addr_vec_elt (stream, value) FILE *stream; int value;{ fprintf (stream, "\tOCTA L:%d\n", value);}/* ASM_OUTPUT_SKIP. */voidmmix_asm_output_skip (stream, nbytes) FILE *stream; int nbytes;{ fprintf (stream, "\tLOC @+%d\n", nbytes);}/* ASM_OUTPUT_ALIGN. */voidmmix_asm_output_align (stream, power) FILE *stream; int power;{ /* We need to record the needed alignment of this section in the object, so we have to output an alignment directive. Use a .p2align (not .align) so people will never have to wonder about whether the argument is in number of bytes or the log2 thereof. We do it in addition to the LOC directive, so nothing needs tweaking when copy-pasting assembly into mmixal. */ fprintf (stream, "\t.p2align %d\n", power); fprintf (stream, "\tLOC @+(%d-@)&%d\n", 1 << power, (1 << power) - 1);}/* DBX_REGISTER_NUMBER. */intmmix_dbx_register_number (regno) int regno;{ /* Adjust the register number to the one it will be output as, dammit. It'd be nice if we could check the assumption that we're filling a gap, but every register between the last saved register and parameter registers might be a valid parameter register. */ regno = MMIX_OUTPUT_REGNO (regno); /* We need to renumber registers to get the number of the return address register in the range 0..255. It is also space-saving if registers mentioned in the call-frame information (which uses this function by defaulting DWARF_FRAME_REGNUM to DBX_REGISTER_NUMBER) are numbered 0 .. 63. So map 224 .. 256+15 -> 0 .. 47 and 0 .. 223 -> 48..223+48. */ return regno >= 224 ? (regno - 224) : (regno + 48);}/* End of target macro support functions. Now MMIX's own functions. First the exported ones. *//* Wrapper for get_hard_reg_initial_val since integrate.h isn't included from insn-emit.c. */rtxmmix_get_hard_reg_initial_val (mode, regno) enum machine_mode mode; int regno;{ return get_hard_reg_initial_val (mode, regno);}/* Nonzero when the function epilogue is simple enough that a single "POP %d,0" should be used even within the function. */intmmix_use_simple_return (){ int regno; int stack_space_to_allocate = (current_function_outgoing_args_size + current_function_pretend_args_size + get_frame_size () + 7) & ~7; if (!TARGET_USE_RETURN_INSN || !reload_completed) return 0; for (regno = 255; regno >= MMIX_FIRST_GLOBAL_REGNUM; regno--) /* Note that we assume that the frame-pointer-register is one of these registers, in which case we don't count it here. */ if ((((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed) && regs_ever_live[regno] && !call_used_regs[regno])) || IS_MMIX_EH_RETURN_DATA_REG (regno)) return 0; if (frame_pointer_needed) stack_space_to_allocate += 8; if (MMIX_CFUN_HAS_LANDING_PAD) stack_space_to_allocate += 16; else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS) stack_space_to_allocate += 8; return stack_space_to_allocate == 0;}/* Expands the function prologue into RTX. */voidmmix_expand_prologue (){ HOST_WIDE_INT locals_size = get_frame_size (); int regno; HOST_WIDE_INT stack_space_to_allocate = (current_function_outgoing_args_size + current_function_pretend_args_size + locals_size + 7) & ~7; HOST_WIDE_INT offset = -8; /* Add room needed to save global non-register-stack registers. */ for (regno = 255; regno >= MMIX_FIRST_GLOBAL_REGNUM; regno--) /* Note that we assume that the frame-pointer-register is one of these registers, in which case we don't count it here. */ if ((((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed) && regs_ever_live[regno] && !call_used_regs[regno])) || IS_MMIX_EH_RETURN_DATA_REG (regno)) stack_space_to_allocate += 8; /* If we do have a frame-pointer, add room for it. */ if (frame_pointer_needed) stack_space_to_allocate += 8; /* If we have a non-local label, we need to be able to unwind to it, so store the current register stack pointer. Also store the return address if we do that. */ if (MMIX_CFUN_HAS_LANDING_PAD) stack_space_to_allocate += 16; else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS) /* If we do have a saved return-address slot, add room for it. */ stack_space_to_allocate += 8; /* Make sure we don't get an unaligned stack. */ if ((stack_space_to_allocate % 8) != 0) internal_error ("stack frame not a multiple of 8 bytes: %d", stack_space_to_allocate); if (current_function_pretend_args_size) { int mmix_first_vararg_reg = (MMIX_FIRST_INCOMING_ARG_REGNUM + (MMIX_MAX_ARGS_IN_REGS - current_function_pretend_args_size / 8)); for (regno = MMIX_FIRST_INCOMING_ARG_REGNUM + MMIX_MAX_ARGS_IN_REGS - 1; regno >= mmix_first_vararg_reg; regno--) { if (offset < 0) { HOST_WIDE_INT stack_chunk = stack_space_to_allocate > (256 - 8) ? (256 - 8) : stack_space_to_allocate; mmix_emit_sp_add (-stack_chunk); offset += stack_chunk; stack_space_to_allocate -= stack_chunk; } /* These registers aren't actually saved (as in "will be restored"), so don't tell DWARF2 they're saved. */ emit_move_insn (gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, offset)), gen_rtx_REG (DImode, regno)); offset -= 8; } } /* Store the frame-pointer. */ if (frame_pointer_needed) { rtx insn; if (offset < 0) { /* Get 8 less than otherwise, since we need to reach offset + 8. */ HOST_WIDE_INT stack_chunk = stack_space_to_allocate > (256 - 8 - 8) ? (256 - 8 - 8) : stack_space_to_allocate; mmix_emit_sp_add (-stack_chunk); offset += stack_chunk; stack_space_to_allocate -= stack_chunk; } insn = emit_move_insn (gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, offset)), hard_frame_pointer_rtx); RTX_FRAME_RELATED_P (insn) = 1; insn = emit_insn (gen_adddi3 (hard_frame_pointer_rtx, stack_pointer_rtx, GEN_INT (offset + 8))); RTX_FRAME_RELATED_P (insn) = 1; offset -= 8; } if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS) { rtx tmpreg, retreg; rtx insn; /* Store the return-address, if one is needed on the stack. We usually store it in a register when needed, but that doesn't work with -fexceptions. */ if (offset < 0) { /* Get 8 less than otherwise, since we need to reach offset + 8. */ HOST_WIDE_INT stack_chunk = stack_space_to_allocate > (256 - 8 - 8) ? (256 - 8 - 8) : stack_space_to_allocate; mmix_emit_sp_add (-stack_chunk); offset += stack_chunk; stack_space_to_allocate -= stack_chunk; } tmpreg = gen_rtx_REG (DImode, 255); retreg = gen_rtx_REG (DImode, MMIX_rJ_REGNUM); /* Dwarf2 code is confused by the use of a temporary register for storing the return address, so we have to express it as a note, which we attach to the actual store insn. */ emit_move_insn (tmpreg, retreg); insn = emit_move_insn (gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, offset)), tmpreg); RTX_FRAME_RELATED_P (insn) = 1; REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, gen_rtx_SET (VOIDmode, gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, offset)), retreg), REG_NOTES (insn)); offset -= 8; } else if (MMIX_CFUN_HAS_LANDING_PAD) offset -= 8; if (MMIX_CFUN_HAS_LANDING_PAD) { /* Store the register defining the numbering of local registers, so we know how long to unwind the register stack. */ if (offset < 0) { /* Get 8 less than otherwise, since we need to reach offset + 8. */ HOST_WIDE_INT stack_chunk = stack_space_to_allocate > (256 - 8 - 8) ? (256 - 8 - 8) : stack_space_to_allocate; mmix_emit_sp_add (-stack_chunk); offset += stack_chunk; stack_space_to_allocate -= stack_chunk; } /* We don't tell dwarf2 about this one; we just have it to unwind the register stack at landing pads. FIXME: It's a kludge because we can't describe the effect of the PUSHJ and PUSHGO insns on the register stack at the moment. Best thing would be to handle it like stack-pointer offsets. Better: some hook into dwarf2out.c to produce DW_CFA_expression:s that specify the increment of rO, and unwind it at eh_return (preferred) or at the landing pad. Then saves to $0..$G-1 could be specified through that register. */ emit_move_insn (gen_rtx_REG (DImode, 255), gen_rtx_REG (DImode, MMIX_rO_REGNUM)); emit_move_insn (gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, offset)), gen_rtx_REG (DImode, 255)); offset -= 8; } /* After the return-address and the frame-pointer, we have the local variables. They're the ones that may have an "unaligned" size. */ offset -= (locals_size + 7) & ~7; /* Now store all registers that are global, i.e. not saved by the register file machinery. It is assumed that the frame-pointer is one of these registers, so it is explicitly excluded in the count. */ for (regno = 255; regno >= MMIX_FIRST_GLOBAL_REGNUM; regno--) if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed) && regs_ever_live[regno] && ! call_used_regs[regno]) || IS_MMIX_EH_RETURN_DATA_REG (regno)) { rtx insn; if (offset < 0) { HOST_WIDE_INT stack_chunk = (stack_space_to_allocate > (256 - offset - 8) ? (256 - offset - 8) : stack_space_to_allocate); mmix_emit_sp_add (-stack_chunk); offset += stack_chunk; stack_space_to_allocate -= stack_chunk; } insn = emit_move_insn (gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, offset)), gen_rtx_REG (DImode, regno)); RTX_FRAME_RELATED_P (insn) = 1; offset -= 8; } /* Finally, allocate room for outgoing args and local vars if room wasn't allocated above. */ if (stack_space_to_allocate) mmix_emit_sp_add (-stack_space_to_allocate);}/* Expands the function epilogue into RTX. */voidmmix_expand_epilogue (){ HOST_WIDE_INT locals_size = get_frame_size (); int regno; HOST_WIDE_INT stack_space_to_deallocate = (curren
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -