📄 out-mips.c
字号:
/* Subroutines for insn-output.c for MIPS Contributed by A. Lichnewsky, lich@inria.inria.fr. Changes by Michael Meissner, meissner@osf.org. Copyright (C) 1989, 1990 Free Software Foundation, Inc.This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 1, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */#include <stdio.h>#include <sys/types.h>#include <sys/file.h>#include "tree.h"#include "flags.h"#ifndef R_OK#define R_OK 4#define W_OK 2#define X_OK 1#endifextern void debug_rtx ();extern void abort_with_insn ();extern FILE *asm_out_file;extern tree current_function_decl;/* Global variables for machine-dependent things. */char *reg_numchar[] = REGISTER_NUMCHAR;/* Threshold for data being put into the small data/bss area, instead of the normal data area (references to the small data/bss area take 1 instruction, and use the global pointer, references to the normal data area takes 2 instructions). */int mips_section_threshold = -1;/* Count the number of .file directives, so that .loc is up to date. */int num_source_filenames = 0;/* Count the number of words that are pushed to pass arguments. */int stack_args_pushed = 0;/* # bytes for args preallocated by function_prolog. */int stack_args_preallocated = 0;/* Count of the number of functions created so far, in order to make unique labels for omitting the frame pointer. */int number_functions_processed = 0;/* Count the number of sdb related labels are generated (to find block start and end boundaries). */int sdb_label_count = 0;/* Next label # for each statment for Silicon Graphics IRIS systems. */int sym_lineno = 0;/* Non-zero if inside of a function, because the stupid MIPS asm can't handle .files inside of functions. */int inside_function = 0;/* String to be used for the unique name given to the difference between the stack pointer and frame pointer when the frame pointer is to be omitted. */char *sp_fp_difference = 0;/* Files to separate the text and the data output, so that all of the data can be emitted before the text, which will mean that the assembler will generate smaller code, based on the global pointer. */FILE *asm_out_data_file;FILE *asm_out_text_file;/* Linked list of all externals that are to be emitted when optimizing for the global pointer if they haven't been declared by the end of the program with an appropriate .comm or initialization. */struct extern_list { struct extern_list *next; /* next external */ char *name; /* name of the external */ int size; /* size in bytes */} *extern_head = 0;/* Name of the current function. */char *current_function_name;/* Size of the frame allocated for this function. */int current_function_total_framesize;/* Number of bytes used to hold saved registers. */int current_function_saved_reg_size;/* Return truth value of whether OP can be used as an operands where a register or 16 bit unsigned integer is needed. */intuns_arith_operand (op, mode) rtx op; enum machine_mode mode;{ return (register_operand (op, mode) || (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (op)));}/* Return truth value of whether OP can be used as an operands where a 16 bit integer is needed */intarith_operand (op, mode) rtx op; enum machine_mode mode;{ return (register_operand (op, mode) || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));}/* Return truth value of whether OP can be used as an operand in a two address arithmetic insn (such as set 123456,%o4) of mode MODE. */intarith32_operand (op, mode) rtx op; enum machine_mode mode;{ return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);}/* Return truth value of whether OP is a integer which fits in 16 bits */intsmall_int (op, mode) rtx op; enum machine_mode mode;{ return (GET_CODE (op) == CONST_INT && SMALL_INT (op));}/* Argument support functions. *//* Initialize CUMULATIVE_ARGS for a function. */voidinit_cumulative_args (cum, fntype) CUMULATIVE_ARGS cum; /* argument info to initialize */ tree fntype; /* tree ptr for function decl */{ tree param, next_param; if (TARGET_DEBUGE_MODE) { fprintf (stderr, "\ninit_cumulative_args\n"); if (fntype != (tree)0) { putc ('\n', stderr); debug_tree (fntype); putc ('\n', stderr); } } cum->gp_reg_found = 0; cum->arg_number = 0; cum->arg_words = 0; /* Determine if this function has variable arguments. This is indicated by the last argument being 'void_type_mode' if there are no variable arguments. The standard MIPS calling sequence passes all arguments in the general purpose registers in this case. */ for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0; param != (tree)0; param = next_param) { next_param = TREE_CHAIN (param); if (next_param == (tree)0 && TREE_VALUE (param) != void_type_node) cum->gp_reg_found = 1; } /* Determine if the function is returning a structure, if so, advance by one argument. */ if (fntype && (TREE_CODE (fntype) == FUNCTION_TYPE || TREE_CODE (fntype) == METHOD_TYPE) && TREE_TYPE (fntype) != 0) { tree ret_type = TREE_TYPE (fntype); enum tree_code ret_code = TREE_CODE (ret_type); if (ret_code == RECORD_TYPE || ret_code == UNION_TYPE) { cum->gp_reg_found = 1; cum->arg_number = 1; cum->arg_words = 1; } }}/* Advance the argument to the next argument position. */voidfunction_arg_advance (cum, mode, type, named) CUMULATIVE_ARGS cum; /* current arg information */ enum machine_mode mode; /* current arg mode */ tree type; /* type of the argument or 0 if lib support */{ if (TARGET_DEBUGE_MODE) fprintf (stderr, "function_adv( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d )\n", cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode), type, named); cum->arg_number++; switch (mode) { default: error ("Illegal mode given to function_arg_advance"); break; case VOIDmode: break; case BLKmode: cum->gp_reg_found = 1; cum->arg_words += (int_size_in_bytes (type) + 3) / 4; break; case SFmode: cum->arg_words++; break; case DFmode: cum->arg_words += 2; break; case DImode: cum->gp_reg_found = 1; cum->arg_words += 2; break; case QImode: case HImode: case SImode: cum->gp_reg_found = 1; cum->arg_words++; break; }}/* Return a RTL expression containing the register for the given mode, or 0 if the argument is too be passed on the stack. */struct rtx_def *function_arg (cum, mode, type, named) CUMULATIVE_ARGS cum; /* current arg information */ enum machine_mode mode; /* current arg mode */ tree type; /* type of the argument or 0 if lib support */ int named; /* != 0 for normal args, == 0 for ... args */{ int regbase = -1; int bias = 0; if (TARGET_DEBUGE_MODE) fprintf (stderr, "function_arg( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d ) = ", cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode), type, named); switch (mode) { default: error ("Illegal mode given to function_arg"); break; case SFmode: if (cum->gp_reg_found || cum->arg_number >= 2) regbase = GP_ARG_FIRST; else { regbase = FP_ARG_FIRST; if (cum->arg_words == 1) /* first arg was float */ bias = 1; /* use correct reg */ } break; case DFmode: cum->arg_words += (cum->arg_words & 1); regbase = (cum->gp_reg_found) ? GP_ARG_FIRST : FP_ARG_FIRST; break; case VOIDmode: case BLKmode: case QImode: case HImode: case SImode: case DImode: regbase = GP_ARG_FIRST; break; } if (cum->arg_words >= MAX_ARGS_IN_REGISTERS) { if (TARGET_DEBUGE_MODE) fprintf (stderr, "<stack>\n"); return 0; } if (regbase == -1) abort (); if (TARGET_DEBUGE_MODE) fprintf (stderr, "%s\n", reg_numchar[ regbase + cum->arg_number + bias ]); return gen_rtx (REG, mode, regbase + cum->arg_words + bias);}intfunction_arg_partial_nregs (cum, mode, type, named) CUMULATIVE_ARGS cum; /* current arg information */ enum machine_mode mode; /* current arg mode */ tree type; /* type of the argument or 0 if lib support */ int named; /* != 0 for normal args, == 0 for ... args */{ if (mode == BLKmode && cum->arg_words < MAX_ARGS_IN_REGISTERS) { int words = (int_size_in_bytes (type) + 3) / 4; if (words + cum->arg_words < MAX_ARGS_IN_REGISTERS) return 0; /* structure fits in registers */ if (TARGET_DEBUGE_MODE) fprintf (stderr, "function_arg_partial_nregs = %d\n", MAX_ARGS_IN_REGISTERS - cum->arg_words); return MAX_ARGS_IN_REGISTERS - cum->arg_words; } else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS-1) { if (TARGET_DEBUGE_MODE) fprintf (stderr, "function_arg_partial_nregs = 1\n"); return 1; } return 0;}/* Routines to merge the compare and branch operators into a single entity. */static rtx branch_cmp_op[2];static enum machine_mode branch_cmp_mode;/* Save the mode and operands on the current compare operator. */voidcompare_collect (mode, op0, op1) enum machine_mode mode; rtx op0; rtx op1;{ if (TARGET_DEBUGD_MODE) { fprintf (stderr, "compare_collect mode = %s, operands::", GET_MODE_NAME (mode)); debug_rtx (op0); debug_rtx (op1); } branch_cmp_op[0] = op0; branch_cmp_op[1] = op1; branch_cmp_mode = mode;}/* Return the mode and operands saved with compare_collect for use in a branch operator. */voidcompare_restore (operands, mode, insn) rtx *operands; enum machine_mode *mode; rtx insn;{ if (!branch_cmp_op[0] || !branch_cmp_op[1]) abort_with_insn (insn, "Compare_restore did not follow compare_collect"); if (TARGET_DEBUGD_MODE) { fprintf (stderr, "compare_restore returning mode = %s, operands:%X,%X:", GET_MODE_NAME (branch_cmp_mode), branch_cmp_op[0], branch_cmp_op[1]); debug_rtx (branch_cmp_op[0]); debug_rtx (branch_cmp_op[1]); } operands[0] = branch_cmp_op[0]; operands[1] = branch_cmp_op[1]; *mode = branch_cmp_mode; /* If the next insn is not a JUMP (after accounting for line numbers), zero out the branch_cmp_array. Switch statements implemented as if's tend to have multiple jumps. */ do { insn = NEXT_INSN (insn); } while (insn && GET_CODE (insn) == NOTE); if (!insn || GET_CODE (insn) != JUMP_INSN) { branch_cmp_op[0] = NULL; branch_cmp_op[1] = NULL; branch_cmp_mode = VOIDmode; }}/* Print the options used in the assembly file. */static struct {char *name; int value;} target_switches [] = TARGET_SWITCHES;voidprint_options (out) FILE *out;{ int line_len; int len; int j; char **p; int mask = TARGET_DEFAULT; extern char **save_argv; extern char *version_string, *language_string;#if 0 /* Allow assembly language comparisons with -mdebug eliminating the compiler version number and switch lists. */ if (!TARGET_DEBUG_MODE) { fprintf (out, "\n # %s %s", language_string, version_string);#ifdef TARGET_VERSION_INTERNAL TARGET_VERSION_INTERNAL (out);#endif#ifdef __GNUC__ fprintf (out, " compiled by GNU C\n\n");#else fprintf (out, " compiled by CC\n\n");#endif fprintf (out, " # Cc1 defaults:"); line_len = 32767; for (j = 0; j < sizeof target_switches / sizeof target_switches[0]; j++) if (target_switches[j].name[0] != '\0' && target_switches[j].value > 0 && (target_switches[j].value & mask) == target_switches[j].value) { len = strlen (target_switches[j].name) + 1; if (len + line_len > 79) { line_len = 2; fputs ("\n #", out); } fprintf (out, " -m%s", target_switches[j].name); line_len += len; } fprintf (out, "\n\n # Cc1 arguments (-G value = %d):", mips_section_threshold); line_len = 32767; for (p = &save_argv[1]; *p != (char *)0; p++) if (**p == '-') { len = strlen (*p) + 1; if (len + line_len > 79) { line_len = 2; fputs ("\n #", out); } fprintf (out, " %s", *p); line_len += len; } fputs ("\n\n", out); }#endif}/* Abort after printing out a specific insn. */voidabort_with_insn (insn, reason) rtx insn; char *reason;{ error (reason); debug_rtx (insn); abort ();}/* Write a message to stderr (for use in macros expanded in files that do not include stdio.h). */voidtrace (s, s1, s2) char *s, *s1, *s2;{ fprintf (stderr, s, s1, s2);}/* Set up the threshold for data to go into the small data area, instead of the normal data area, and detect any conflicts in the switches. */voidoveride_options (){ register int i; i = TARGET_GVALUE; if (i >= 6) i += 3; mips_section_threshold = (i != 0) ? 1 << i : 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -