📄 mn10200.c
字号:
/* Subroutines for insn-output.c for Matsushita MN10200 series Copyright (C) 1997 Free Software Foundation, Inc. Contributed by Jeff Law (law@cygnus.com).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 2, 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, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. */#include "config.h"#include <stdio.h>#include "rtl.h"#include "regs.h"#include "hard-reg-set.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "insn-flags.h"#include "output.h"#include "insn-attr.h"#include "flags.h"#include "recog.h"#include "expr.h"#include "tree.h"#include "obstack.h"/* Global registers known to hold the value zero. Normally we'd depend on CSE and combine to put zero into a register and re-use it. However, on the mn10x00 processors we implicitly use the constant zero in tst instructions, so we might be able to do better by loading the value into a register in the prologue, then re-useing that register throughout the function. We could perform similar optimizations for other constants, but with gcse due soon, it doesn't seem worth the effort. These variables hold a rtx for a register known to hold the value zero throughout the entire function, or NULL if no register of the appropriate class has such a value throughout the life of the function. */rtx zero_dreg;rtx zero_areg;/* Note whether or not we need an out of line epilogue. */static int out_of_line_epilogue;/* Indicate this file was compiled by gcc and what optimization level was used. */voidasm_file_start (file) FILE *file;{ fprintf (file, "#\tGCC For the Matsushita MN10200\n"); if (optimize) fprintf (file, "# -O%d\n", optimize); else fprintf (file, "\n\n"); output_file_directive (file, main_input_filename);}/* Print operand X using operand code CODE to assembly language output file FILE. */voidprint_operand (file, x, code) FILE *file; rtx x; int code;{ switch (code) { case 'b': case 'B': /* These are normal and reversed branches. */ switch (code == 'b' ? GET_CODE (x) : reverse_condition (GET_CODE (x))) { case NE: fprintf (file, "ne"); break; case EQ: fprintf (file, "eq"); break; case GE: fprintf (file, "ge"); break; case GT: fprintf (file, "gt"); break; case LE: fprintf (file, "le"); break; case LT: fprintf (file, "lt"); break; case GEU: fprintf (file, "cc"); break; case GTU: fprintf (file, "hi"); break; case LEU: fprintf (file, "ls"); break; case LTU: fprintf (file, "cs"); break; default: abort (); } break; case 'C': /* This is used for the operand to a call instruction; if it's a REG, enclose it in parens, else output the operand normally. */ if (GET_CODE (x) == REG) { fputc ('(', file); print_operand (file, x, 0); fputc (')', file); } else print_operand (file, x, 0); break; /* These are the least significant word in a 32bit value. 'o' allows us to sign extend a constant if doing so makes for more compact code. */ case 'L': case 'o': switch (GET_CODE (x)) { case MEM: fputc ('(', file); output_address (XEXP (x, 0)); fputc (')', file); break; case REG: fprintf (file, "%s", reg_names[REGNO (x)]); break; case SUBREG: fprintf (file, "%s", reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)]); break; case CONST_DOUBLE: if (code == 'L') { long val; REAL_VALUE_TYPE rv; REAL_VALUE_FROM_CONST_DOUBLE (rv, x); REAL_VALUE_TO_TARGET_SINGLE (rv, val); print_operand_address (file, GEN_INT (val & 0xffff)); } else { long val; REAL_VALUE_TYPE rv; REAL_VALUE_FROM_CONST_DOUBLE (rv, x); REAL_VALUE_TO_TARGET_SINGLE (rv, val); val &= 0xffff; val = (((val) & 0xffff) ^ (~0x7fff)) + 0x8000; print_operand_address (file, GEN_INT (val)); } break; case CONST_INT: if (code == 'L') print_operand_address (file, GEN_INT ((INTVAL (x) & 0xffff))); else { unsigned int val = INTVAL (x) & 0xffff; val = (((val) & 0xffff) ^ (~0x7fff)) + 0x8000; print_operand_address (file, GEN_INT (val)); } break; default: abort (); } break; /* Similarly, but for the most significant word. */ case 'H': case 'h': switch (GET_CODE (x)) { case MEM: fputc ('(', file); x = adj_offsettable_operand (x, 2); output_address (XEXP (x, 0)); fputc (')', file); break; case REG: fprintf (file, "%s", reg_names[REGNO (x) + 1]); break; case SUBREG: fprintf (file, "%s", reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)] + 1); break; case CONST_DOUBLE: if (code == 'H') { long val; REAL_VALUE_TYPE rv; REAL_VALUE_FROM_CONST_DOUBLE (rv, x); REAL_VALUE_TO_TARGET_SINGLE (rv, val); print_operand_address (file, GEN_INT ((val >> 16) & 0xffff)); } else { long val; REAL_VALUE_TYPE rv; REAL_VALUE_FROM_CONST_DOUBLE (rv, x); REAL_VALUE_TO_TARGET_SINGLE (rv, val); val = (val >> 16) & 0xffff; val = (((val) & 0xffff) ^ (~0x7fff)) + 0x8000; print_operand_address (file, GEN_INT (val)); } break; case CONST_INT: if (code == 'H') print_operand_address (file, GEN_INT ((INTVAL (x) >> 16) & 0xffff)); else { unsigned int val = (INTVAL (x) >> 16) & 0xffff; val = (((val) & 0xffff) ^ (~0x7fff)) + 0x8000; print_operand_address (file, GEN_INT (val)); } break; default: abort (); } break; /* Output ~CONST_INT. */ case 'N': if (GET_CODE (x) != CONST_INT) abort (); fprintf (file, "%d", ~INTVAL (x)); break; /* An address which can not be register indirect, if it is register indirect, then turn it into reg + disp. */ case 'A': if (GET_CODE (x) != MEM) abort (); if (GET_CODE (XEXP (x, 0)) == REG) x = gen_rtx (PLUS, PSImode, XEXP (x, 0), GEN_INT (0)); else x = XEXP (x, 0); fputc ('(', file); output_address (x); fputc (')', file); break; case 'Z': print_operand (file, XEXP (x, 1), 0); break; /* More cases where we can sign-extend a CONST_INT if it results in more compact code. */ case 's': case 'S': if (GET_CODE (x) == CONST_INT) { int val = INTVAL (x); if (code == 's') x = GEN_INT (((val & 0xffff) ^ (~0x7fff)) + 0x8000); else x = GEN_INT (((val & 0xff) ^ (~0x7f)) + 0x80); } /* FALL THROUGH */ default: switch (GET_CODE (x)) { case MEM: fputc ('(', file); output_address (XEXP (x, 0)); fputc (')', file); break; case REG: fprintf (file, "%s", reg_names[REGNO (x)]); break; case SUBREG: fprintf (file, "%s", reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)]); break; case CONST_INT: case CONST_DOUBLE: case SYMBOL_REF: case CONST: case LABEL_REF: case CODE_LABEL: print_operand_address (file, x); break; default: abort (); } break; }}/* Output assembly language output for the address ADDR to FILE. */voidprint_operand_address (file, addr) FILE *file; rtx addr;{ switch (GET_CODE (addr)) { case REG: print_operand (file, addr, 0); break; case PLUS: { rtx base, index; /* The base and index could be in any order, so we have to figure out which is the base and which is the index. Uses the same code as GO_IF_LEGITIMATE_ADDRESS. */ if (REG_P (XEXP (addr, 0)) && REG_OK_FOR_BASE_P (XEXP (addr, 0))) base = XEXP (addr, 0), index = XEXP (addr, 1); else if (REG_P (XEXP (addr, 1)) && REG_OK_FOR_BASE_P (XEXP (addr, 1))) base = XEXP (addr, 1), index = XEXP (addr, 0); else abort (); print_operand (file, index, 0); fputc (',', file); print_operand (file, base, 0);; break; } case SYMBOL_REF: output_addr_const (file, addr); break; default: output_addr_const (file, addr); break; }}/* Count the number of tst insns which compare an address register with zero. */static void count_tst_insns (areg_countp) int *areg_countp;{ rtx insn; /* Assume no tst insns exist. */ *areg_countp = 0; /* If not optimizing, then quit now. */ if (!optimize) return; /* Walk through all the insns. */ for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) { rtx pat; /* Ignore anything that is not a normal INSN. */ if (GET_CODE (insn) != INSN) continue; /* Ignore anything that isn't a SET. */ pat = PATTERN (insn); if (GET_CODE (pat) != SET) continue; /* Check for a tst insn. */ if (SET_DEST (pat) == cc0_rtx && GET_CODE (SET_SRC (pat)) == REG && REGNO_REG_CLASS (REGNO (SET_SRC (pat))) == ADDRESS_REGS) (*areg_countp)++; }}/* Return the total size (in bytes) of the current function's frame. This is the size of the register save area + the size of locals, spills, etc. */inttotal_frame_size (){ unsigned int size = get_frame_size (); unsigned int outgoing_args_size = current_function_outgoing_args_size; int i; /* First figure out if we're going to use an out of line prologue, if so we have to make space for all the registers, even if we don't use them. */ if (optimize && !current_function_needs_context && !frame_pointer_needed) { int inline_count, outline_count; /* Compute how many bytes an inline prologue would take. Each address register store takes two bytes, each data register store takes three bytes. */ inline_count = 0; if (regs_ever_live[5]) inline_count += 2; if (regs_ever_live[6]) inline_count += 2; if (regs_ever_live[2]) inline_count += 3; if (regs_ever_live[3]) inline_count += 3; /* If this function has any stack, then the stack adjustment will take two (or more) bytes. */ if (size || outgoing_args_size || regs_ever_live[5] || regs_ever_live[6] || regs_ever_live[2] || regs_ever_live[3]) inline_count += 2; /* Multiply the current count by two and add one to account for the epilogue insns. */ inline_count = inline_count * 2 + 1; /* Now compute how many bytes an out of line sequence would take. */ /* A relaxed jsr will be three bytes. */ outline_count = 3; /* If there are outgoing arguments, then we will need a stack pointer adjustment after the call to the prologue, two more bytes. */ outline_count += (outgoing_args_size == 0 ? 0 : 2); /* If there is some local frame to allocate, it will need to be done before the call to the prologue, two more bytes. */ if (get_frame_size () != 0) outline_count += 2; /* Now account for the epilogue, multiply the base count by two, then deal with optimizing away the rts instruction. */ outline_count = outline_count * 2 + 1; if (get_frame_size () == 0 && outgoing_args_size == 0) outline_count -= 1; /* If an out of line prologue is smaller, use it. */ if (inline_count > outline_count) return size + outgoing_args_size + 16; } for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { if (regs_ever_live[i] && !call_used_regs[i] && ! fixed_regs[i] || (i == FRAME_POINTER_REGNUM && frame_pointer_needed)) size += 4; } return (size + outgoing_args_size);}/* Expand the prologue into RTL. */voidexpand_prologue (){ unsigned int size = total_frame_size (); unsigned int outgoing_args_size = current_function_outgoing_args_size; int offset, i; zero_areg = NULL_RTX; zero_dreg = NULL_RTX; /* If optimizing, see if we should do an out of line prologue/epilogue sequence. We don't support out of line prologues if the current function needs a context or frame pointer. */ if (optimize && !current_function_needs_context && !frame_pointer_needed) { int inline_count, outline_count, areg_count;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -