📄 mmix.c
字号:
length -= chunk_size; fprintf (stream, "\n"); }}/* ASM_OUTPUT_ALIGNED_COMMON. */voidmmix_asm_output_aligned_common (FILE *stream, const char *name, int size, int align){ /* This is mostly the elfos.h one. There doesn't seem to be a way to express this in a mmixal-compatible way. */ fprintf (stream, "\t.comm\t"); assemble_name (stream, name); fprintf (stream, ",%u,%u ! mmixal-incompatible COMMON\n", size, align / BITS_PER_UNIT);}/* ASM_OUTPUT_ALIGNED_LOCAL. */voidmmix_asm_output_aligned_local (FILE *stream, const char *name, int size, int align){ data_section (); ASM_OUTPUT_ALIGN (stream, exact_log2 (align/BITS_PER_UNIT)); assemble_name (stream, name); fprintf (stream, "\tLOC @+%d\n", size);}/* ASM_OUTPUT_LABEL. */voidmmix_asm_output_label (FILE *stream, const char *name){ assemble_name (stream, name); fprintf (stream, "\tIS @\n");}/* ASM_OUTPUT_INTERNAL_LABEL. */voidmmix_asm_output_internal_label (FILE *stream, const char *name){ assemble_name_raw (stream, name); fprintf (stream, "\tIS @\n");}/* ASM_DECLARE_REGISTER_GLOBAL. */voidmmix_asm_declare_register_global (FILE *stream ATTRIBUTE_UNUSED, tree decl ATTRIBUTE_UNUSED, int regno ATTRIBUTE_UNUSED, const char *name ATTRIBUTE_UNUSED){ /* Nothing to do here, but there *will* be, therefore the framework is here. */}/* ASM_WEAKEN_LABEL. */voidmmix_asm_weaken_label (FILE *stream ATTRIBUTE_UNUSED, const char *name ATTRIBUTE_UNUSED){ fprintf (stream, "\t.weak "); assemble_name (stream, name); fprintf (stream, " ! mmixal-incompatible\n");}/* MAKE_DECL_ONE_ONLY. */voidmmix_make_decl_one_only (tree decl){ DECL_WEAK (decl) = 1;}/* ASM_OUTPUT_LABELREF. Strip GCC's '*' and our own '@'. No order is assumed. */voidmmix_asm_output_labelref (FILE *stream, const char *name){ int is_extern = 1; for (; (*name == '@' || *name == '*'); name++) if (*name == '@') is_extern = 0; asm_fprintf (stream, "%s%U%s", is_extern && TARGET_TOPLEVEL_SYMBOLS ? ":" : "", name);}/* ASM_OUTPUT_DEF. */voidmmix_asm_output_def (FILE *stream, const char *name, const char *value){ assemble_name (stream, name); fprintf (stream, "\tIS "); assemble_name (stream, value); fputc ('\n', stream);}/* PRINT_OPERAND. */voidmmix_print_operand (FILE *stream, rtx x, int code){ /* When we add support for different codes later, we can, when needed, drop through to the main handler with a modified operand. */ rtx modified_x = x; int regno = x != NULL_RTX && REG_P (x) ? REGNO (x) : 0; switch (code) { /* Unrelated codes are in alphabetic order. */ case '+': /* For conditional branches, output "P" for a probable branch. */ if (TARGET_BRANCH_PREDICT) { x = find_reg_note (current_output_insn, REG_BR_PROB, 0); if (x && INTVAL (XEXP (x, 0)) > REG_BR_PROB_BASE / 2) putc ('P', stream); } return; case '.': /* For the %d in POP %d,0. */ fprintf (stream, "%d", MMIX_POP_ARGUMENT ()); return; case 'B': if (GET_CODE (x) != CONST_INT) fatal_insn ("MMIX Internal: Expected a CONST_INT, not this", x); fprintf (stream, "%d", (int) (INTVAL (x) & 0xff)); return; case 'H': /* Highpart. Must be general register, and not the last one, as that one cannot be part of a consecutive register pair. */ if (regno > MMIX_LAST_GENERAL_REGISTER - 1) internal_error ("MMIX Internal: Bad register: %d", regno); /* This is big-endian, so the high-part is the first one. */ fprintf (stream, "%s", reg_names[MMIX_OUTPUT_REGNO (regno)]); return; case 'L': /* Lowpart. Must be CONST_INT or general register, and not the last one, as that one cannot be part of a consecutive register pair. */ if (GET_CODE (x) == CONST_INT) { fprintf (stream, "#%lx", (unsigned long) (INTVAL (x) & ((unsigned int) 0x7fffffff * 2 + 1))); return; } if (GET_CODE (x) == SYMBOL_REF) { output_addr_const (stream, x); return; } if (regno > MMIX_LAST_GENERAL_REGISTER - 1) internal_error ("MMIX Internal: Bad register: %d", regno); /* This is big-endian, so the low-part is + 1. */ fprintf (stream, "%s", reg_names[MMIX_OUTPUT_REGNO (regno) + 1]); return; /* Can't use 'a' because that's a generic modifier for address output. */ case 'A': mmix_output_shiftvalue_op_from_str (stream, "ANDN", ~(unsigned HOST_WIDEST_INT) mmix_intval (x)); return; case 'i': mmix_output_shiftvalue_op_from_str (stream, "INC", (unsigned HOST_WIDEST_INT) mmix_intval (x)); return; case 'o': mmix_output_shiftvalue_op_from_str (stream, "OR", (unsigned HOST_WIDEST_INT) mmix_intval (x)); return; case 's': mmix_output_shiftvalue_op_from_str (stream, "SET", (unsigned HOST_WIDEST_INT) mmix_intval (x)); return; case 'd': case 'D': mmix_output_condition (stream, x, (code == 'D')); return; case 'e': /* Output an extra "e" to make fcmpe, fune. */ if (TARGET_FCMP_EPSILON) fprintf (stream, "e"); return; case 'm': /* Output the number minus 1. */ if (GET_CODE (x) != CONST_INT) { fatal_insn ("MMIX Internal: Bad value for 'm', not a CONST_INT", x); } fprintf (stream, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT) (mmix_intval (x) - 1)); return; case 'p': /* Store the number of registers we want to save. This was setup by the prologue. The actual operand contains the number of registers to pass, but we don't use it currently. Anyway, we need to output the number of saved registers here. */ fprintf (stream, "%d", cfun->machine->highest_saved_stack_register + 1); return; case 'r': /* Store the register to output a constant to. */ if (! REG_P (x)) fatal_insn ("MMIX Internal: Expected a register, not this", x); mmix_output_destination_register = MMIX_OUTPUT_REGNO (regno); return; case 'I': /* Output the constant. Note that we use this for floats as well. */ if (GET_CODE (x) != CONST_INT && (GET_CODE (x) != CONST_DOUBLE || (GET_MODE (x) != VOIDmode && GET_MODE (x) != DFmode && GET_MODE (x) != SFmode))) fatal_insn ("MMIX Internal: Expected a constant, not this", x); mmix_output_register_setting (stream, mmix_output_destination_register, mmix_intval (x), 0); return; case 'U': /* An U for unsigned, if TARGET_ZERO_EXTEND. Ignore the operand. */ if (TARGET_ZERO_EXTEND) putc ('U', stream); return; case 'v': mmix_output_shifted_value (stream, (HOST_WIDEST_INT) mmix_intval (x)); return; case 'V': mmix_output_shifted_value (stream, (HOST_WIDEST_INT) ~mmix_intval (x)); return; case 'W': if (GET_CODE (x) != CONST_INT) fatal_insn ("MMIX Internal: Expected a CONST_INT, not this", x); fprintf (stream, "#%x", (int) (INTVAL (x) & 0xffff)); return; case 0: /* Nothing to do. */ break; default: /* Presumably there's a missing case above if we get here. */ internal_error ("MMIX Internal: Missing %qc case in mmix_print_operand", code); } switch (GET_CODE (modified_x)) { case REG: regno = REGNO (modified_x); if (regno >= FIRST_PSEUDO_REGISTER) internal_error ("MMIX Internal: Bad register: %d", regno); fprintf (stream, "%s", reg_names[MMIX_OUTPUT_REGNO (regno)]); return; case MEM: output_address (XEXP (modified_x, 0)); return; case CONST_INT: /* For -2147483648, mmixal complains that the constant does not fit in 4 bytes, so let's output it as hex. Take care to handle hosts where HOST_WIDE_INT is longer than an int. Print small constants +-255 using decimal. */ if (INTVAL (modified_x) > -256 && INTVAL (modified_x) < 256) fprintf (stream, "%d", (int) (INTVAL (modified_x))); else fprintf (stream, "#%x", (int) (INTVAL (modified_x)) & (unsigned int) ~0); return; case CONST_DOUBLE: /* Do somewhat as CONST_INT. */ mmix_output_octa (stream, mmix_intval (modified_x), 0); return; case CONST: output_addr_const (stream, modified_x); return; default: /* No need to test for all strange things. Let output_addr_const do it for us. */ if (CONSTANT_P (modified_x) /* Strangely enough, this is not included in CONSTANT_P. FIXME: Ask/check about sanity here. */ || GET_CODE (modified_x) == CODE_LABEL) { output_addr_const (stream, modified_x); return; } /* We need the original here. */ fatal_insn ("MMIX Internal: Cannot decode this operand", x); }}/* PRINT_OPERAND_PUNCT_VALID_P. */intmmix_print_operand_punct_valid_p (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 (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 (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 (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 (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 (FILE *stream, int value){ fprintf (stream, "\tOCTA L:%d\n", value);}/* ASM_OUTPUT_SKIP. */voidmmix_asm_output_skip (FILE *stream, int nbytes)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -