1*61768Sbostic /* Subroutines for insn-output.c for MIPS 2*61768Sbostic Contributed by A. Lichnewsky, lich@inria.inria.fr. 3*61768Sbostic Changes by Michael Meissner, meissner@osf.org. 4*61768Sbostic Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc. 5*61768Sbostic 6*61768Sbostic This file is part of GNU CC. 7*61768Sbostic 8*61768Sbostic GNU CC is free software; you can redistribute it and/or modify 9*61768Sbostic it under the terms of the GNU General Public License as published by 10*61768Sbostic the Free Software Foundation; either version 2, or (at your option) 11*61768Sbostic any later version. 12*61768Sbostic 13*61768Sbostic GNU CC is distributed in the hope that it will be useful, 14*61768Sbostic but WITHOUT ANY WARRANTY; without even the implied warranty of 15*61768Sbostic MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*61768Sbostic GNU General Public License for more details. 17*61768Sbostic 18*61768Sbostic You should have received a copy of the GNU General Public License 19*61768Sbostic along with GNU CC; see the file COPYING. If not, write to 20*61768Sbostic the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ 21*61768Sbostic 22*61768Sbostic #include "config.h" 23*61768Sbostic #include "rtl.h" 24*61768Sbostic #include "regs.h" 25*61768Sbostic #include "hard-reg-set.h" 26*61768Sbostic #include "real.h" 27*61768Sbostic #include "insn-config.h" 28*61768Sbostic #include "conditions.h" 29*61768Sbostic #include "insn-flags.h" 30*61768Sbostic #include "insn-attr.h" 31*61768Sbostic #include "insn-codes.h" 32*61768Sbostic #include "recog.h" 33*61768Sbostic #include "output.h" 34*61768Sbostic 35*61768Sbostic #undef MAX /* sys/param.h may also define these */ 36*61768Sbostic #undef MIN 37*61768Sbostic 38*61768Sbostic #include <stdio.h> 39*61768Sbostic #include <signal.h> 40*61768Sbostic #include <sys/types.h> 41*61768Sbostic #include <sys/file.h> 42*61768Sbostic #include <ctype.h> 43*61768Sbostic #include "tree.h" 44*61768Sbostic #include "expr.h" 45*61768Sbostic #include "flags.h" 46*61768Sbostic 47*61768Sbostic #ifndef R_OK 48*61768Sbostic #define R_OK 4 49*61768Sbostic #define W_OK 2 50*61768Sbostic #define X_OK 1 51*61768Sbostic #endif 52*61768Sbostic 53*61768Sbostic #if defined(USG) || defined(NO_STAB_H) 54*61768Sbostic #include "gstab.h" /* If doing DBX on sysV, use our own stab.h. */ 55*61768Sbostic #else 56*61768Sbostic #include <stab.h> /* On BSD, use the system's stab.h. */ 57*61768Sbostic #endif /* not USG */ 58*61768Sbostic 59*61768Sbostic #ifdef __GNU_STAB__ 60*61768Sbostic #define STAB_CODE_TYPE enum __stab_debug_code 61*61768Sbostic #else 62*61768Sbostic #define STAB_CODE_TYPE int 63*61768Sbostic #endif 64*61768Sbostic 65*61768Sbostic extern void abort (); 66*61768Sbostic extern int atoi (); 67*61768Sbostic extern char *getenv (); 68*61768Sbostic extern char *mktemp (); 69*61768Sbostic 70*61768Sbostic extern rtx adj_offsettable_operand (); 71*61768Sbostic extern rtx copy_to_reg (); 72*61768Sbostic extern void error (); 73*61768Sbostic extern void fatal (); 74*61768Sbostic extern tree lookup_name (); 75*61768Sbostic extern void pfatal_with_name (); 76*61768Sbostic extern void warning (); 77*61768Sbostic 78*61768Sbostic extern tree current_function_decl; 79*61768Sbostic extern FILE *asm_out_file; 80*61768Sbostic 81*61768Sbostic /* Enumeration for all of the relational tests, so that we can build 82*61768Sbostic arrays indexed by the test type, and not worry about the order 83*61768Sbostic of EQ, NE, etc. */ 84*61768Sbostic 85*61768Sbostic enum internal_test { 86*61768Sbostic ITEST_EQ, 87*61768Sbostic ITEST_NE, 88*61768Sbostic ITEST_GT, 89*61768Sbostic ITEST_GE, 90*61768Sbostic ITEST_LT, 91*61768Sbostic ITEST_LE, 92*61768Sbostic ITEST_GTU, 93*61768Sbostic ITEST_GEU, 94*61768Sbostic ITEST_LTU, 95*61768Sbostic ITEST_LEU, 96*61768Sbostic ITEST_MAX 97*61768Sbostic }; 98*61768Sbostic 99*61768Sbostic /* Global variables for machine-dependent things. */ 100*61768Sbostic 101*61768Sbostic /* Threshold for data being put into the small data/bss area, instead 102*61768Sbostic of the normal data area (references to the small data/bss area take 103*61768Sbostic 1 instruction, and use the global pointer, references to the normal 104*61768Sbostic data area takes 2 instructions). */ 105*61768Sbostic int mips_section_threshold = -1; 106*61768Sbostic 107*61768Sbostic /* Count the number of .file directives, so that .loc is up to date. */ 108*61768Sbostic int num_source_filenames = 0; 109*61768Sbostic 110*61768Sbostic /* Count the number of sdb related labels are generated (to find block 111*61768Sbostic start and end boundaries). */ 112*61768Sbostic int sdb_label_count = 0; 113*61768Sbostic 114*61768Sbostic /* Next label # for each statment for Silicon Graphics IRIS systems. */ 115*61768Sbostic int sym_lineno = 0; 116*61768Sbostic 117*61768Sbostic /* Non-zero if inside of a function, because the stupid MIPS asm can't 118*61768Sbostic handle .files inside of functions. */ 119*61768Sbostic int inside_function = 0; 120*61768Sbostic 121*61768Sbostic /* Files to separate the text and the data output, so that all of the data 122*61768Sbostic can be emitted before the text, which will mean that the assembler will 123*61768Sbostic generate smaller code, based on the global pointer. */ 124*61768Sbostic FILE *asm_out_data_file; 125*61768Sbostic FILE *asm_out_text_file; 126*61768Sbostic 127*61768Sbostic /* Linked list of all externals that are to be emitted when optimizing 128*61768Sbostic for the global pointer if they haven't been declared by the end of 129*61768Sbostic the program with an appropriate .comm or initialization. */ 130*61768Sbostic 131*61768Sbostic struct extern_list { 132*61768Sbostic struct extern_list *next; /* next external */ 133*61768Sbostic char *name; /* name of the external */ 134*61768Sbostic int size; /* size in bytes */ 135*61768Sbostic } *extern_head = 0; 136*61768Sbostic 137*61768Sbostic /* Name of the file containing the current function. */ 138*61768Sbostic char *current_function_file = ""; 139*61768Sbostic 140*61768Sbostic /* Warning given that Mips ECOFF can't support changing files 141*61768Sbostic within a function. */ 142*61768Sbostic int file_in_function_warning = FALSE; 143*61768Sbostic 144*61768Sbostic /* Whether to suppress issuing .loc's because the user attempted 145*61768Sbostic to change the filename within a function. */ 146*61768Sbostic int ignore_line_number = FALSE; 147*61768Sbostic 148*61768Sbostic /* Number of nested .set noreorder, noat, nomacro, and volatile requests. */ 149*61768Sbostic int set_noreorder; 150*61768Sbostic int set_noat; 151*61768Sbostic int set_nomacro; 152*61768Sbostic int set_volatile; 153*61768Sbostic 154*61768Sbostic /* The next branch instruction is a branch likely, not branch normal. */ 155*61768Sbostic int mips_branch_likely; 156*61768Sbostic 157*61768Sbostic /* Count of delay slots and how many are filled. */ 158*61768Sbostic int dslots_load_total; 159*61768Sbostic int dslots_load_filled; 160*61768Sbostic int dslots_jump_total; 161*61768Sbostic int dslots_jump_filled; 162*61768Sbostic 163*61768Sbostic /* # of nops needed by previous insn */ 164*61768Sbostic int dslots_number_nops; 165*61768Sbostic 166*61768Sbostic /* Number of 1/2/3 word references to data items (ie, not jal's). */ 167*61768Sbostic int num_refs[3]; 168*61768Sbostic 169*61768Sbostic /* registers to check for load delay */ 170*61768Sbostic rtx mips_load_reg, mips_load_reg2, mips_load_reg3, mips_load_reg4; 171*61768Sbostic 172*61768Sbostic /* Cached operands, and operator to compare for use in set/branch on 173*61768Sbostic condition codes. */ 174*61768Sbostic rtx branch_cmp[2]; 175*61768Sbostic 176*61768Sbostic /* what type of branch to use */ 177*61768Sbostic enum cmp_type branch_type; 178*61768Sbostic 179*61768Sbostic /* Number of previously seen half-pic pointers and references. */ 180*61768Sbostic static int prev_half_pic_ptrs = 0; 181*61768Sbostic static int prev_half_pic_refs = 0; 182*61768Sbostic 183*61768Sbostic /* which cpu are we scheduling for */ 184*61768Sbostic enum processor_type mips_cpu; 185*61768Sbostic 186*61768Sbostic /* which instruction set architecture to use. */ 187*61768Sbostic int mips_isa; 188*61768Sbostic 189*61768Sbostic /* Strings to hold which cpu and instruction set architecture to use. */ 190*61768Sbostic char *mips_cpu_string; /* for -mcpu=<xxx> */ 191*61768Sbostic char *mips_isa_string; /* for -mips{1,2,3} */ 192*61768Sbostic 193*61768Sbostic /* Array to RTX class classification. At present, we care about 194*61768Sbostic whether the operator is an add-type operator, or a divide/modulus, 195*61768Sbostic and if divide/modulus, whether it is unsigned. This is for the 196*61768Sbostic peephole code. */ 197*61768Sbostic char mips_rtx_classify[NUM_RTX_CODE]; 198*61768Sbostic 199*61768Sbostic /* Array giving truth value on whether or not a given hard register 200*61768Sbostic can support a given mode. */ 201*61768Sbostic char mips_hard_regno_mode_ok[(int)MAX_MACHINE_MODE][FIRST_PSEUDO_REGISTER]; 202*61768Sbostic 203*61768Sbostic /* Current frame information calculated by compute_frame_size. */ 204*61768Sbostic struct mips_frame_info current_frame_info; 205*61768Sbostic 206*61768Sbostic /* Zero structure to initialize current_frame_info. */ 207*61768Sbostic struct mips_frame_info zero_frame_info; 208*61768Sbostic 209*61768Sbostic /* Temporary filename used to buffer .text until end of program 210*61768Sbostic for -mgpopt. */ 211*61768Sbostic static char *temp_filename; 212*61768Sbostic 213*61768Sbostic /* List of all MIPS punctuation characters used by print_operand. */ 214*61768Sbostic char mips_print_operand_punct[256]; 215*61768Sbostic 216*61768Sbostic /* Map GCC register number to debugger register number. */ 217*61768Sbostic int mips_dbx_regno[FIRST_PSEUDO_REGISTER]; 218*61768Sbostic 219*61768Sbostic /* Buffer to use to enclose a load/store operation with %{ %} to 220*61768Sbostic turn on .set volatile. */ 221*61768Sbostic static char volatile_buffer[60]; 222*61768Sbostic 223*61768Sbostic /* Hardware names for the registers. If -mrnames is used, this 224*61768Sbostic will be overwritten with mips_sw_reg_names. */ 225*61768Sbostic 226*61768Sbostic char mips_reg_names[][8] = 227*61768Sbostic { 228*61768Sbostic "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", 229*61768Sbostic "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", 230*61768Sbostic "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", 231*61768Sbostic "$24", "$25", "$26", "$27", "$28", "$sp", "$fp", "$31", 232*61768Sbostic "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", 233*61768Sbostic "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", 234*61768Sbostic "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", 235*61768Sbostic "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", 236*61768Sbostic "hi", "lo", "$fcr31" 237*61768Sbostic }; 238*61768Sbostic 239*61768Sbostic /* Mips software names for the registers, used to overwrite the 240*61768Sbostic mips_reg_names array. */ 241*61768Sbostic 242*61768Sbostic char mips_sw_reg_names[][8] = 243*61768Sbostic { 244*61768Sbostic "$0", "at", "v0", "v1", "a0", "a1", "a2", "a3", 245*61768Sbostic "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", 246*61768Sbostic "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", 247*61768Sbostic "t8", "t9", "k0", "k1", "gp", "sp", "$fp", "ra", 248*61768Sbostic "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", 249*61768Sbostic "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", 250*61768Sbostic "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", 251*61768Sbostic "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", 252*61768Sbostic "hi", "lo", "$fcr31" 253*61768Sbostic }; 254*61768Sbostic 255*61768Sbostic /* Map hard register number to register class */ 256*61768Sbostic enum reg_class mips_regno_to_class[] = 257*61768Sbostic { 258*61768Sbostic GR_REGS, GR_REGS, GR_REGS, GR_REGS, 259*61768Sbostic GR_REGS, GR_REGS, GR_REGS, GR_REGS, 260*61768Sbostic GR_REGS, GR_REGS, GR_REGS, GR_REGS, 261*61768Sbostic GR_REGS, GR_REGS, GR_REGS, GR_REGS, 262*61768Sbostic GR_REGS, GR_REGS, GR_REGS, GR_REGS, 263*61768Sbostic GR_REGS, GR_REGS, GR_REGS, GR_REGS, 264*61768Sbostic GR_REGS, GR_REGS, GR_REGS, GR_REGS, 265*61768Sbostic GR_REGS, GR_REGS, GR_REGS, GR_REGS, 266*61768Sbostic FP_REGS, FP_REGS, FP_REGS, FP_REGS, 267*61768Sbostic FP_REGS, FP_REGS, FP_REGS, FP_REGS, 268*61768Sbostic FP_REGS, FP_REGS, FP_REGS, FP_REGS, 269*61768Sbostic FP_REGS, FP_REGS, FP_REGS, FP_REGS, 270*61768Sbostic FP_REGS, FP_REGS, FP_REGS, FP_REGS, 271*61768Sbostic FP_REGS, FP_REGS, FP_REGS, FP_REGS, 272*61768Sbostic FP_REGS, FP_REGS, FP_REGS, FP_REGS, 273*61768Sbostic FP_REGS, FP_REGS, FP_REGS, FP_REGS, 274*61768Sbostic HI_REG, LO_REG, ST_REGS 275*61768Sbostic }; 276*61768Sbostic 277*61768Sbostic /* Map register constraint character to register class. */ 278*61768Sbostic enum reg_class mips_char_to_class[256] = 279*61768Sbostic { 280*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 281*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 282*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 283*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 284*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 285*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 286*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 287*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 288*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 289*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 290*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 291*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 292*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 293*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 294*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 295*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 296*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 297*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 298*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 299*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 300*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 301*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 302*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 303*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 304*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 305*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 306*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 307*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 308*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 309*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 310*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 311*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 312*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 313*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 314*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 315*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 316*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 317*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 318*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 319*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 320*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 321*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 322*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 323*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 324*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 325*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 326*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 327*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 328*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 329*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 330*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 331*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 332*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 333*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 334*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 335*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 336*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 337*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 338*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 339*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 340*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 341*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 342*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 343*61768Sbostic NO_REGS, NO_REGS, NO_REGS, NO_REGS, 344*61768Sbostic }; 345*61768Sbostic 346*61768Sbostic 347*61768Sbostic /* Return truth value of whether OP can be used as an operands 348*61768Sbostic where a register or 16 bit unsigned integer is needed. */ 349*61768Sbostic 350*61768Sbostic int 351*61768Sbostic uns_arith_operand (op, mode) 352*61768Sbostic rtx op; 353*61768Sbostic enum machine_mode mode; 354*61768Sbostic { 355*61768Sbostic if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (op)) 356*61768Sbostic return TRUE; 357*61768Sbostic 358*61768Sbostic return register_operand (op, mode); 359*61768Sbostic } 360*61768Sbostic 361*61768Sbostic /* Return truth value of whether OP can be used as an operands 362*61768Sbostic where a 16 bit integer is needed */ 363*61768Sbostic 364*61768Sbostic int 365*61768Sbostic arith_operand (op, mode) 366*61768Sbostic rtx op; 367*61768Sbostic enum machine_mode mode; 368*61768Sbostic { 369*61768Sbostic if (GET_CODE (op) == CONST_INT && SMALL_INT (op)) 370*61768Sbostic return TRUE; 371*61768Sbostic 372*61768Sbostic return register_operand (op, mode); 373*61768Sbostic } 374*61768Sbostic 375*61768Sbostic /* Return truth value of whether OP can be used as an operand in a two 376*61768Sbostic address arithmetic insn (such as set 123456,%o4) of mode MODE. */ 377*61768Sbostic 378*61768Sbostic int 379*61768Sbostic arith32_operand (op, mode) 380*61768Sbostic rtx op; 381*61768Sbostic enum machine_mode mode; 382*61768Sbostic { 383*61768Sbostic if (GET_CODE (op) == CONST_INT) 384*61768Sbostic return TRUE; 385*61768Sbostic 386*61768Sbostic return register_operand (op, mode); 387*61768Sbostic } 388*61768Sbostic 389*61768Sbostic /* Return truth value of whether OP is a integer which fits in 16 bits */ 390*61768Sbostic 391*61768Sbostic int 392*61768Sbostic small_int (op, mode) 393*61768Sbostic rtx op; 394*61768Sbostic enum machine_mode mode; 395*61768Sbostic { 396*61768Sbostic return (GET_CODE (op) == CONST_INT && SMALL_INT (op)); 397*61768Sbostic } 398*61768Sbostic 399*61768Sbostic /* Return truth value of whether OP is an integer which is too big to 400*61768Sbostic be loaded with one instruction. */ 401*61768Sbostic 402*61768Sbostic int 403*61768Sbostic large_int (op, mode) 404*61768Sbostic rtx op; 405*61768Sbostic enum machine_mode mode; 406*61768Sbostic { 407*61768Sbostic HOST_WIDE_INT value; 408*61768Sbostic 409*61768Sbostic if (GET_CODE (op) != CONST_INT) 410*61768Sbostic return FALSE; 411*61768Sbostic 412*61768Sbostic value = INTVAL (op); 413*61768Sbostic if ((value & ~0x0000ffff) == 0) /* ior reg,$r0,value */ 414*61768Sbostic return FALSE; 415*61768Sbostic 416*61768Sbostic if (((unsigned long)(value + 32768)) <= 32767) /* subu reg,$r0,value */ 417*61768Sbostic return FALSE; 418*61768Sbostic 419*61768Sbostic if ((value & 0xffff0000) == value) /* lui reg,value>>16 */ 420*61768Sbostic return FALSE; 421*61768Sbostic 422*61768Sbostic return TRUE; 423*61768Sbostic } 424*61768Sbostic 425*61768Sbostic /* Return truth value of whether OP is a register or the constant 0. */ 426*61768Sbostic 427*61768Sbostic int 428*61768Sbostic reg_or_0_operand (op, mode) 429*61768Sbostic rtx op; 430*61768Sbostic enum machine_mode mode; 431*61768Sbostic { 432*61768Sbostic switch (GET_CODE (op)) 433*61768Sbostic { 434*61768Sbostic default: 435*61768Sbostic break; 436*61768Sbostic 437*61768Sbostic case CONST_INT: 438*61768Sbostic return (INTVAL (op) == 0); 439*61768Sbostic 440*61768Sbostic case CONST_DOUBLE: 441*61768Sbostic if (CONST_DOUBLE_HIGH (op) != 0 || CONST_DOUBLE_LOW (op) != 0) 442*61768Sbostic return FALSE; 443*61768Sbostic 444*61768Sbostic return TRUE; 445*61768Sbostic 446*61768Sbostic case REG: 447*61768Sbostic case SUBREG: 448*61768Sbostic return register_operand (op, mode); 449*61768Sbostic } 450*61768Sbostic 451*61768Sbostic return FALSE; 452*61768Sbostic } 453*61768Sbostic 454*61768Sbostic /* Return truth value of whether OP is one of the special multiply/divide 455*61768Sbostic registers (hi, lo). */ 456*61768Sbostic 457*61768Sbostic int 458*61768Sbostic md_register_operand (op, mode) 459*61768Sbostic rtx op; 460*61768Sbostic enum machine_mode mode; 461*61768Sbostic { 462*61768Sbostic return (GET_MODE_CLASS (mode) == MODE_INT 463*61768Sbostic && GET_CODE (op) == REG 464*61768Sbostic && MD_REG_P (REGNO (op))); 465*61768Sbostic } 466*61768Sbostic 467*61768Sbostic /* Return truth value of whether OP is the FP status register. */ 468*61768Sbostic 469*61768Sbostic int 470*61768Sbostic fpsw_register_operand (op, mode) 471*61768Sbostic rtx op; 472*61768Sbostic enum machine_mode mode; 473*61768Sbostic { 474*61768Sbostic return (GET_CODE (op) == REG && ST_REG_P (REGNO (op))); 475*61768Sbostic } 476*61768Sbostic 477*61768Sbostic /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */ 478*61768Sbostic 479*61768Sbostic int 480*61768Sbostic mips_const_double_ok (op, mode) 481*61768Sbostic rtx op; 482*61768Sbostic enum machine_mode mode; 483*61768Sbostic { 484*61768Sbostic if (GET_CODE (op) != CONST_DOUBLE) 485*61768Sbostic return FALSE; 486*61768Sbostic 487*61768Sbostic if (mode == DImode) 488*61768Sbostic return TRUE; 489*61768Sbostic 490*61768Sbostic if (mode != SFmode && mode != DFmode) 491*61768Sbostic return FALSE; 492*61768Sbostic 493*61768Sbostic if (CONST_DOUBLE_HIGH (op) == 0 && CONST_DOUBLE_LOW (op) == 0) 494*61768Sbostic return TRUE; 495*61768Sbostic 496*61768Sbostic #if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT 497*61768Sbostic if (TARGET_MIPS_AS) /* gas doesn't like li.d/li.s yet */ 498*61768Sbostic { 499*61768Sbostic union { double d; int i[2]; } u; 500*61768Sbostic double d; 501*61768Sbostic 502*61768Sbostic u.i[0] = CONST_DOUBLE_LOW (op); 503*61768Sbostic u.i[1] = CONST_DOUBLE_HIGH (op); 504*61768Sbostic d = u.d; 505*61768Sbostic 506*61768Sbostic if (d != d) 507*61768Sbostic return FALSE; /* NAN */ 508*61768Sbostic 509*61768Sbostic if (d < 0.0) 510*61768Sbostic d = - d; 511*61768Sbostic 512*61768Sbostic /* Rather than trying to get the accuracy down to the last bit, 513*61768Sbostic just use approximate ranges. */ 514*61768Sbostic 515*61768Sbostic if (mode == DFmode && d > 1.0e-300 && d < 1.0e300) 516*61768Sbostic return TRUE; 517*61768Sbostic 518*61768Sbostic if (mode == SFmode && d > 1.0e-38 && d < 1.0e+38) 519*61768Sbostic return TRUE; 520*61768Sbostic } 521*61768Sbostic #endif 522*61768Sbostic 523*61768Sbostic return FALSE; 524*61768Sbostic } 525*61768Sbostic 526*61768Sbostic /* Return truth value if a memory operand fits in a single instruction 527*61768Sbostic (ie, register + small offset). */ 528*61768Sbostic 529*61768Sbostic int 530*61768Sbostic simple_memory_operand (op, mode) 531*61768Sbostic rtx op; 532*61768Sbostic enum machine_mode mode; 533*61768Sbostic { 534*61768Sbostic rtx addr, plus0, plus1; 535*61768Sbostic 536*61768Sbostic /* Eliminate non-memory operations */ 537*61768Sbostic if (GET_CODE (op) != MEM) 538*61768Sbostic return FALSE; 539*61768Sbostic 540*61768Sbostic /* dword operations really put out 2 instructions, so eliminate them. */ 541*61768Sbostic if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4)) 542*61768Sbostic return FALSE; 543*61768Sbostic 544*61768Sbostic /* Decode the address now. */ 545*61768Sbostic addr = XEXP (op, 0); 546*61768Sbostic switch (GET_CODE (addr)) 547*61768Sbostic { 548*61768Sbostic default: 549*61768Sbostic break; 550*61768Sbostic 551*61768Sbostic case REG: 552*61768Sbostic return TRUE; 553*61768Sbostic 554*61768Sbostic case CONST_INT: 555*61768Sbostic return SMALL_INT (op); 556*61768Sbostic 557*61768Sbostic case PLUS: 558*61768Sbostic plus0 = XEXP (addr, 0); 559*61768Sbostic plus1 = XEXP (addr, 1); 560*61768Sbostic if (GET_CODE (plus0) == REG 561*61768Sbostic && GET_CODE (plus1) == CONST_INT 562*61768Sbostic && SMALL_INT (plus1)) 563*61768Sbostic return TRUE; 564*61768Sbostic 565*61768Sbostic else if (GET_CODE (plus1) == REG 566*61768Sbostic && GET_CODE (plus0) == CONST_INT 567*61768Sbostic && SMALL_INT (plus0)) 568*61768Sbostic return TRUE; 569*61768Sbostic 570*61768Sbostic else 571*61768Sbostic return FALSE; 572*61768Sbostic 573*61768Sbostic #if 0 574*61768Sbostic /* We used to allow small symbol refs here (ie, stuff in .sdata 575*61768Sbostic or .sbss), but this causes some bugs in G++. Also, it won't 576*61768Sbostic interfere if the MIPS linker rewrites the store instruction 577*61768Sbostic because the function is PIC. */ 578*61768Sbostic 579*61768Sbostic case LABEL_REF: /* never gp relative */ 580*61768Sbostic break; 581*61768Sbostic 582*61768Sbostic case CONST: 583*61768Sbostic /* If -G 0, we can never have a GP relative memory operation. 584*61768Sbostic Also, save some time if not optimizing. */ 585*61768Sbostic if (mips_section_threshold == 0 || !optimize || !TARGET_GP_OPT) 586*61768Sbostic return FALSE; 587*61768Sbostic 588*61768Sbostic { 589*61768Sbostic rtx offset = const0_rtx; 590*61768Sbostic addr = eliminate_constant_term (addr, &offset); 591*61768Sbostic if (GET_CODE (op) != SYMBOL_REF) 592*61768Sbostic return FALSE; 593*61768Sbostic 594*61768Sbostic /* let's be paranoid.... */ 595*61768Sbostic if (INTVAL (offset) < 0 || INTVAL (offset) > 0xffff) 596*61768Sbostic return FALSE; 597*61768Sbostic } 598*61768Sbostic /* fall through */ 599*61768Sbostic 600*61768Sbostic case SYMBOL_REF: 601*61768Sbostic return SYMBOL_REF_FLAG (addr); 602*61768Sbostic #endif 603*61768Sbostic } 604*61768Sbostic 605*61768Sbostic return FALSE; 606*61768Sbostic } 607*61768Sbostic 608*61768Sbostic /* Return true if the code of this rtx pattern is EQ or NE. */ 609*61768Sbostic 610*61768Sbostic int 611*61768Sbostic equality_op (op, mode) 612*61768Sbostic rtx op; 613*61768Sbostic enum machine_mode mode; 614*61768Sbostic { 615*61768Sbostic if (mode != GET_MODE (op)) 616*61768Sbostic return FALSE; 617*61768Sbostic 618*61768Sbostic return (classify_op (op, mode) & CLASS_EQUALITY_OP) != 0; 619*61768Sbostic } 620*61768Sbostic 621*61768Sbostic /* Return true if the code is a relational operations (EQ, LE, etc.) */ 622*61768Sbostic 623*61768Sbostic int 624*61768Sbostic cmp_op (op, mode) 625*61768Sbostic rtx op; 626*61768Sbostic enum machine_mode mode; 627*61768Sbostic { 628*61768Sbostic if (mode != GET_MODE (op)) 629*61768Sbostic return FALSE; 630*61768Sbostic 631*61768Sbostic return (classify_op (op, mode) & CLASS_CMP_OP) != 0; 632*61768Sbostic } 633*61768Sbostic 634*61768Sbostic 635*61768Sbostic /* Genrecog does not take the type of match_operator into consideration, 636*61768Sbostic and would complain about two patterns being the same if the same 637*61768Sbostic function is used, so make it believe they are different. */ 638*61768Sbostic 639*61768Sbostic int 640*61768Sbostic cmp2_op (op, mode) 641*61768Sbostic rtx op; 642*61768Sbostic enum machine_mode mode; 643*61768Sbostic { 644*61768Sbostic if (mode != GET_MODE (op)) 645*61768Sbostic return FALSE; 646*61768Sbostic 647*61768Sbostic return (classify_op (op, mode) & CLASS_CMP_OP) != 0; 648*61768Sbostic } 649*61768Sbostic 650*61768Sbostic /* Return true if the code is an unsigned relational operations (LEU, etc.) */ 651*61768Sbostic 652*61768Sbostic int 653*61768Sbostic uns_cmp_op (op,mode) 654*61768Sbostic rtx op; 655*61768Sbostic enum machine_mode mode; 656*61768Sbostic { 657*61768Sbostic if (mode != GET_MODE (op)) 658*61768Sbostic return FALSE; 659*61768Sbostic 660*61768Sbostic return (classify_op (op, mode) & CLASS_UNS_CMP_OP) == CLASS_UNS_CMP_OP; 661*61768Sbostic } 662*61768Sbostic 663*61768Sbostic /* Return true if the code is a relational operation FP can use. */ 664*61768Sbostic 665*61768Sbostic int 666*61768Sbostic fcmp_op (op, mode) 667*61768Sbostic rtx op; 668*61768Sbostic enum machine_mode mode; 669*61768Sbostic { 670*61768Sbostic if (mode != GET_MODE (op)) 671*61768Sbostic return FALSE; 672*61768Sbostic 673*61768Sbostic return (classify_op (op, mode) & CLASS_FCMP_OP) != 0; 674*61768Sbostic } 675*61768Sbostic 676*61768Sbostic 677*61768Sbostic /* Return true if the operand is either the PC or a label_ref. */ 678*61768Sbostic 679*61768Sbostic int 680*61768Sbostic pc_or_label_operand (op, mode) 681*61768Sbostic rtx op; 682*61768Sbostic enum machine_mode mode; 683*61768Sbostic { 684*61768Sbostic if (op == pc_rtx) 685*61768Sbostic return TRUE; 686*61768Sbostic 687*61768Sbostic if (GET_CODE (op) == LABEL_REF) 688*61768Sbostic return TRUE; 689*61768Sbostic 690*61768Sbostic return FALSE; 691*61768Sbostic } 692*61768Sbostic 693*61768Sbostic 694*61768Sbostic /* Return an operand string if the given instruction's delay slot or 695*61768Sbostic wrap it in a .set noreorder section. This is for filling delay 696*61768Sbostic slots on load type instructions under GAS, which does no reordering 697*61768Sbostic on its own. For the MIPS assembler, all we do is update the filled 698*61768Sbostic delay slot statistics. 699*61768Sbostic 700*61768Sbostic We assume that operands[0] is the target register that is set. 701*61768Sbostic 702*61768Sbostic In order to check the next insn, most of this functionality is moved 703*61768Sbostic to FINAL_PRESCAN_INSN, and we just set the global variables that 704*61768Sbostic it needs. */ 705*61768Sbostic 706*61768Sbostic char * 707*61768Sbostic mips_fill_delay_slot (ret, type, operands, cur_insn) 708*61768Sbostic char *ret; /* normal string to return */ 709*61768Sbostic enum delay_type type; /* type of delay */ 710*61768Sbostic rtx operands[]; /* operands to use */ 711*61768Sbostic rtx cur_insn; /* current insn */ 712*61768Sbostic { 713*61768Sbostic register rtx set_reg; 714*61768Sbostic register enum machine_mode mode; 715*61768Sbostic register rtx next_insn = (cur_insn) ? NEXT_INSN (cur_insn) : (rtx)0; 716*61768Sbostic register int num_nops; 717*61768Sbostic 718*61768Sbostic if (type == DELAY_LOAD || type == DELAY_FCMP) 719*61768Sbostic num_nops = 1; 720*61768Sbostic 721*61768Sbostic else if (type == DELAY_HILO) 722*61768Sbostic num_nops = 2; 723*61768Sbostic 724*61768Sbostic else 725*61768Sbostic num_nops = 0; 726*61768Sbostic 727*61768Sbostic /* Make sure that we don't put nop's after labels. */ 728*61768Sbostic next_insn = NEXT_INSN (cur_insn); 729*61768Sbostic while (next_insn != (rtx)0 && GET_CODE (next_insn) == NOTE) 730*61768Sbostic next_insn = NEXT_INSN (next_insn); 731*61768Sbostic 732*61768Sbostic dslots_load_total += num_nops; 733*61768Sbostic if (TARGET_DEBUG_F_MODE 734*61768Sbostic || !optimize 735*61768Sbostic || type == DELAY_NONE 736*61768Sbostic || operands == (rtx *)0 737*61768Sbostic || cur_insn == (rtx)0 738*61768Sbostic || next_insn == (rtx)0 739*61768Sbostic || GET_CODE (next_insn) == CODE_LABEL 740*61768Sbostic || (set_reg = operands[0]) == (rtx)0) 741*61768Sbostic { 742*61768Sbostic dslots_number_nops = 0; 743*61768Sbostic mips_load_reg = (rtx)0; 744*61768Sbostic mips_load_reg2 = (rtx)0; 745*61768Sbostic mips_load_reg3 = (rtx)0; 746*61768Sbostic mips_load_reg4 = (rtx)0; 747*61768Sbostic return ret; 748*61768Sbostic } 749*61768Sbostic 750*61768Sbostic set_reg = operands[0]; 751*61768Sbostic if (set_reg == (rtx)0) 752*61768Sbostic return ret; 753*61768Sbostic 754*61768Sbostic while (GET_CODE (set_reg) == SUBREG) 755*61768Sbostic set_reg = SUBREG_REG (set_reg); 756*61768Sbostic 757*61768Sbostic mode = GET_MODE (set_reg); 758*61768Sbostic dslots_number_nops = num_nops; 759*61768Sbostic mips_load_reg = set_reg; 760*61768Sbostic mips_load_reg2 = (mode == DImode || mode == DFmode) 761*61768Sbostic ? gen_rtx (REG, SImode, REGNO (set_reg) + 1) 762*61768Sbostic : (rtx)0; 763*61768Sbostic 764*61768Sbostic if (type == DELAY_HILO) 765*61768Sbostic { 766*61768Sbostic mips_load_reg3 = gen_rtx (REG, SImode, MD_REG_FIRST); 767*61768Sbostic mips_load_reg4 = gen_rtx (REG, SImode, MD_REG_FIRST+1); 768*61768Sbostic } 769*61768Sbostic else 770*61768Sbostic { 771*61768Sbostic mips_load_reg3 = 0; 772*61768Sbostic mips_load_reg4 = 0; 773*61768Sbostic } 774*61768Sbostic 775*61768Sbostic if (TARGET_GAS && set_noreorder++ == 0) 776*61768Sbostic fputs ("\t.set\tnoreorder\n", asm_out_file); 777*61768Sbostic 778*61768Sbostic return ret; 779*61768Sbostic } 780*61768Sbostic 781*61768Sbostic 782*61768Sbostic /* Determine whether a memory reference takes one (based off of the GP pointer), 783*61768Sbostic two (normal), or three (label + reg) instructions, and bump the appropriate 784*61768Sbostic counter for -mstats. */ 785*61768Sbostic 786*61768Sbostic void 787*61768Sbostic mips_count_memory_refs (op, num) 788*61768Sbostic rtx op; 789*61768Sbostic int num; 790*61768Sbostic { 791*61768Sbostic int additional = 0; 792*61768Sbostic int n_words = 0; 793*61768Sbostic rtx addr, plus0, plus1; 794*61768Sbostic enum rtx_code code0, code1; 795*61768Sbostic int looping; 796*61768Sbostic 797*61768Sbostic if (TARGET_DEBUG_B_MODE) 798*61768Sbostic { 799*61768Sbostic fprintf (stderr, "\n========== mips_count_memory_refs:\n"); 800*61768Sbostic debug_rtx (op); 801*61768Sbostic } 802*61768Sbostic 803*61768Sbostic /* Skip MEM if passed, otherwise handle movsi of address. */ 804*61768Sbostic addr = (GET_CODE (op) != MEM) ? op : XEXP (op, 0); 805*61768Sbostic 806*61768Sbostic /* Loop, going through the address RTL */ 807*61768Sbostic do 808*61768Sbostic { 809*61768Sbostic looping = FALSE; 810*61768Sbostic switch (GET_CODE (addr)) 811*61768Sbostic { 812*61768Sbostic default: 813*61768Sbostic break; 814*61768Sbostic 815*61768Sbostic case REG: 816*61768Sbostic case CONST_INT: 817*61768Sbostic break; 818*61768Sbostic 819*61768Sbostic case PLUS: 820*61768Sbostic plus0 = XEXP (addr, 0); 821*61768Sbostic plus1 = XEXP (addr, 1); 822*61768Sbostic code0 = GET_CODE (plus0); 823*61768Sbostic code1 = GET_CODE (plus1); 824*61768Sbostic 825*61768Sbostic if (code0 == REG) 826*61768Sbostic { 827*61768Sbostic additional++; 828*61768Sbostic addr = plus1; 829*61768Sbostic looping = TRUE; 830*61768Sbostic continue; 831*61768Sbostic } 832*61768Sbostic 833*61768Sbostic if (code0 == CONST_INT) 834*61768Sbostic { 835*61768Sbostic addr = plus1; 836*61768Sbostic looping = TRUE; 837*61768Sbostic continue; 838*61768Sbostic } 839*61768Sbostic 840*61768Sbostic if (code1 == REG) 841*61768Sbostic { 842*61768Sbostic additional++; 843*61768Sbostic addr = plus0; 844*61768Sbostic looping = TRUE; 845*61768Sbostic continue; 846*61768Sbostic } 847*61768Sbostic 848*61768Sbostic if (code1 == CONST_INT) 849*61768Sbostic { 850*61768Sbostic addr = plus0; 851*61768Sbostic looping = TRUE; 852*61768Sbostic continue; 853*61768Sbostic } 854*61768Sbostic 855*61768Sbostic if (code0 == SYMBOL_REF || code0 == LABEL_REF || code0 == CONST) 856*61768Sbostic { 857*61768Sbostic addr = plus0; 858*61768Sbostic looping = TRUE; 859*61768Sbostic continue; 860*61768Sbostic } 861*61768Sbostic 862*61768Sbostic if (code1 == SYMBOL_REF || code1 == LABEL_REF || code1 == CONST) 863*61768Sbostic { 864*61768Sbostic addr = plus1; 865*61768Sbostic looping = TRUE; 866*61768Sbostic continue; 867*61768Sbostic } 868*61768Sbostic 869*61768Sbostic break; 870*61768Sbostic 871*61768Sbostic case LABEL_REF: 872*61768Sbostic n_words = 2; /* always 2 words */ 873*61768Sbostic break; 874*61768Sbostic 875*61768Sbostic case CONST: 876*61768Sbostic addr = XEXP (addr, 0); 877*61768Sbostic looping = TRUE; 878*61768Sbostic continue; 879*61768Sbostic 880*61768Sbostic case SYMBOL_REF: 881*61768Sbostic n_words = SYMBOL_REF_FLAG (addr) ? 1 : 2; 882*61768Sbostic break; 883*61768Sbostic } 884*61768Sbostic } 885*61768Sbostic while (looping); 886*61768Sbostic 887*61768Sbostic if (n_words == 0) 888*61768Sbostic return; 889*61768Sbostic 890*61768Sbostic n_words += additional; 891*61768Sbostic if (n_words > 3) 892*61768Sbostic n_words = 3; 893*61768Sbostic 894*61768Sbostic num_refs[n_words-1] += num; 895*61768Sbostic } 896*61768Sbostic 897*61768Sbostic 898*61768Sbostic /* Return the appropriate instructions to move one operand to another. */ 899*61768Sbostic 900*61768Sbostic char * 901*61768Sbostic mips_move_1word (operands, insn, unsignedp) 902*61768Sbostic rtx operands[]; 903*61768Sbostic rtx insn; 904*61768Sbostic int unsignedp; 905*61768Sbostic { 906*61768Sbostic char *ret = 0; 907*61768Sbostic rtx op0 = operands[0]; 908*61768Sbostic rtx op1 = operands[1]; 909*61768Sbostic enum rtx_code code0 = GET_CODE (op0); 910*61768Sbostic enum rtx_code code1 = GET_CODE (op1); 911*61768Sbostic enum machine_mode mode = GET_MODE (op0); 912*61768Sbostic int subreg_word0 = 0; 913*61768Sbostic int subreg_word1 = 0; 914*61768Sbostic enum delay_type delay = DELAY_NONE; 915*61768Sbostic 916*61768Sbostic while (code0 == SUBREG) 917*61768Sbostic { 918*61768Sbostic subreg_word0 += SUBREG_WORD (op0); 919*61768Sbostic op0 = SUBREG_REG (op0); 920*61768Sbostic code0 = GET_CODE (op0); 921*61768Sbostic } 922*61768Sbostic 923*61768Sbostic while (code1 == SUBREG) 924*61768Sbostic { 925*61768Sbostic subreg_word1 += SUBREG_WORD (op1); 926*61768Sbostic op1 = SUBREG_REG (op1); 927*61768Sbostic code1 = GET_CODE (op1); 928*61768Sbostic } 929*61768Sbostic 930*61768Sbostic if (code0 == REG) 931*61768Sbostic { 932*61768Sbostic int regno0 = REGNO (op0) + subreg_word0; 933*61768Sbostic 934*61768Sbostic if (code1 == REG) 935*61768Sbostic { 936*61768Sbostic int regno1 = REGNO (op1) + subreg_word1; 937*61768Sbostic 938*61768Sbostic /* Just in case, don't do anything for assigning a register 939*61768Sbostic to itself, unless we are filling a delay slot. */ 940*61768Sbostic if (regno0 == regno1 && set_nomacro == 0) 941*61768Sbostic ret = ""; 942*61768Sbostic 943*61768Sbostic else if (GP_REG_P (regno0)) 944*61768Sbostic { 945*61768Sbostic if (GP_REG_P (regno1)) 946*61768Sbostic ret = "move\t%0,%1"; 947*61768Sbostic 948*61768Sbostic else if (MD_REG_P (regno1)) 949*61768Sbostic { 950*61768Sbostic delay = DELAY_HILO; 951*61768Sbostic ret = "mf%1\t%0"; 952*61768Sbostic } 953*61768Sbostic 954*61768Sbostic else 955*61768Sbostic { 956*61768Sbostic delay = DELAY_LOAD; 957*61768Sbostic if (FP_REG_P (regno1)) 958*61768Sbostic ret = "mfc1\t%0,%1"; 959*61768Sbostic 960*61768Sbostic else if (regno1 == FPSW_REGNUM) 961*61768Sbostic ret = "cfc1\t%0,$31"; 962*61768Sbostic } 963*61768Sbostic } 964*61768Sbostic 965*61768Sbostic else if (FP_REG_P (regno0)) 966*61768Sbostic { 967*61768Sbostic if (GP_REG_P (regno1)) 968*61768Sbostic { 969*61768Sbostic delay = DELAY_LOAD; 970*61768Sbostic ret = "mtc1\t%1,%0"; 971*61768Sbostic } 972*61768Sbostic 973*61768Sbostic if (FP_REG_P (regno1)) 974*61768Sbostic ret = "mov.s\t%0,%1"; 975*61768Sbostic } 976*61768Sbostic 977*61768Sbostic else if (MD_REG_P (regno0)) 978*61768Sbostic { 979*61768Sbostic if (GP_REG_P (regno1)) 980*61768Sbostic { 981*61768Sbostic delay = DELAY_HILO; 982*61768Sbostic ret = "mt%0\t%1"; 983*61768Sbostic } 984*61768Sbostic } 985*61768Sbostic 986*61768Sbostic else if (regno0 == FPSW_REGNUM) 987*61768Sbostic { 988*61768Sbostic if (GP_REG_P (regno1)) 989*61768Sbostic { 990*61768Sbostic delay = DELAY_LOAD; 991*61768Sbostic ret = "ctc1\t%0,$31"; 992*61768Sbostic } 993*61768Sbostic } 994*61768Sbostic } 995*61768Sbostic 996*61768Sbostic else if (code1 == MEM) 997*61768Sbostic { 998*61768Sbostic delay = DELAY_LOAD; 999*61768Sbostic 1000*61768Sbostic if (TARGET_STATS) 1001*61768Sbostic mips_count_memory_refs (op1, 1); 1002*61768Sbostic 1003*61768Sbostic if (GP_REG_P (regno0)) 1004*61768Sbostic { 1005*61768Sbostic /* For loads, use the mode of the memory item, instead of the 1006*61768Sbostic target, so zero/sign extend can use this code as well. */ 1007*61768Sbostic switch (GET_MODE (op1)) 1008*61768Sbostic { 1009*61768Sbostic default: break; 1010*61768Sbostic case SFmode: ret = "lw\t%0,%1"; break; 1011*61768Sbostic case SImode: ret = "lw\t%0,%1"; break; 1012*61768Sbostic case HImode: ret = (unsignedp) ? "lhu\t%0,%1" : "lh\t%0,%1"; break; 1013*61768Sbostic case QImode: ret = (unsignedp) ? "lbu\t%0,%1" : "lb\t%0,%1"; break; 1014*61768Sbostic } 1015*61768Sbostic } 1016*61768Sbostic 1017*61768Sbostic else if (FP_REG_P (regno0) && (mode == SImode || mode == SFmode)) 1018*61768Sbostic ret = "l.s\t%0,%1"; 1019*61768Sbostic 1020*61768Sbostic if (ret != (char *)0 && MEM_VOLATILE_P (op1)) 1021*61768Sbostic { 1022*61768Sbostic int i = strlen (ret); 1023*61768Sbostic if (i > sizeof (volatile_buffer) - sizeof ("%{%}")) 1024*61768Sbostic abort (); 1025*61768Sbostic 1026*61768Sbostic sprintf (volatile_buffer, "%%{%s%%}", ret); 1027*61768Sbostic ret = volatile_buffer; 1028*61768Sbostic } 1029*61768Sbostic } 1030*61768Sbostic 1031*61768Sbostic else if (code1 == CONST_INT) 1032*61768Sbostic { 1033*61768Sbostic if (INTVAL (op1) == 0) 1034*61768Sbostic { 1035*61768Sbostic if (GP_REG_P (regno0)) 1036*61768Sbostic ret = "move\t%0,%z1"; 1037*61768Sbostic 1038*61768Sbostic else if (FP_REG_P (regno0)) 1039*61768Sbostic { 1040*61768Sbostic delay = DELAY_LOAD; 1041*61768Sbostic ret = "mtc1\t%z1,%0"; 1042*61768Sbostic } 1043*61768Sbostic } 1044*61768Sbostic 1045*61768Sbostic else if (GP_REG_P (regno0)) 1046*61768Sbostic ret = (INTVAL (op1) < 0) ? "li\t%0,%1\t\t\t# %X1" : "li\t%0,%X1\t\t# %1"; 1047*61768Sbostic } 1048*61768Sbostic 1049*61768Sbostic else if (code1 == CONST_DOUBLE && mode == SFmode) 1050*61768Sbostic { 1051*61768Sbostic if (CONST_DOUBLE_HIGH (op1) == 0 && CONST_DOUBLE_LOW (op1) == 0) 1052*61768Sbostic { 1053*61768Sbostic if (GP_REG_P (regno0)) 1054*61768Sbostic ret = "move\t%0,%."; 1055*61768Sbostic 1056*61768Sbostic else if (FP_REG_P (regno0)) 1057*61768Sbostic { 1058*61768Sbostic delay = DELAY_LOAD; 1059*61768Sbostic ret = "mtc1\t%.,%0"; 1060*61768Sbostic } 1061*61768Sbostic } 1062*61768Sbostic 1063*61768Sbostic else 1064*61768Sbostic { 1065*61768Sbostic delay = DELAY_LOAD; 1066*61768Sbostic ret = "li.s\t%0,%1"; 1067*61768Sbostic } 1068*61768Sbostic } 1069*61768Sbostic 1070*61768Sbostic else if (code1 == LABEL_REF) 1071*61768Sbostic { 1072*61768Sbostic if (TARGET_STATS) 1073*61768Sbostic mips_count_memory_refs (op1, 1); 1074*61768Sbostic 1075*61768Sbostic ret = "la\t%0,%a1"; 1076*61768Sbostic } 1077*61768Sbostic 1078*61768Sbostic else if (code1 == SYMBOL_REF || code1 == CONST) 1079*61768Sbostic { 1080*61768Sbostic if (HALF_PIC_P () && CONSTANT_P (op1) && HALF_PIC_ADDRESS_P (op1)) 1081*61768Sbostic { 1082*61768Sbostic rtx offset = const0_rtx; 1083*61768Sbostic 1084*61768Sbostic if (GET_CODE (op1) == CONST) 1085*61768Sbostic op1 = eliminate_constant_term (XEXP (op1, 0), &offset); 1086*61768Sbostic 1087*61768Sbostic if (GET_CODE (op1) == SYMBOL_REF) 1088*61768Sbostic { 1089*61768Sbostic operands[2] = HALF_PIC_PTR (op1); 1090*61768Sbostic 1091*61768Sbostic if (TARGET_STATS) 1092*61768Sbostic mips_count_memory_refs (operands[2], 1); 1093*61768Sbostic 1094*61768Sbostic if (INTVAL (offset) == 0) 1095*61768Sbostic { 1096*61768Sbostic delay = DELAY_LOAD; 1097*61768Sbostic ret = "lw\t%0,%2"; 1098*61768Sbostic } 1099*61768Sbostic else 1100*61768Sbostic { 1101*61768Sbostic dslots_load_total++; 1102*61768Sbostic operands[3] = offset; 1103*61768Sbostic ret = (SMALL_INT (offset)) 1104*61768Sbostic ? "lw\t%0,%2%#\n\tadd\t%0,%0,%3" 1105*61768Sbostic : "lw\t%0,%2%#\n\t%[li\t%@,%3\n\tadd\t%0,%0,%@%]"; 1106*61768Sbostic } 1107*61768Sbostic } 1108*61768Sbostic } 1109*61768Sbostic else 1110*61768Sbostic { 1111*61768Sbostic if (TARGET_STATS) 1112*61768Sbostic mips_count_memory_refs (op1, 1); 1113*61768Sbostic 1114*61768Sbostic ret = "la\t%0,%a1"; 1115*61768Sbostic } 1116*61768Sbostic } 1117*61768Sbostic 1118*61768Sbostic else if (code1 == PLUS) 1119*61768Sbostic { 1120*61768Sbostic rtx add_op0 = XEXP (op1, 0); 1121*61768Sbostic rtx add_op1 = XEXP (op1, 1); 1122*61768Sbostic 1123*61768Sbostic if (GET_CODE (XEXP (op1, 1)) == REG && GET_CODE (XEXP (op1, 0)) == CONST_INT) 1124*61768Sbostic { 1125*61768Sbostic add_op0 = XEXP (op1, 1); /* reverse operands */ 1126*61768Sbostic add_op1 = XEXP (op1, 0); 1127*61768Sbostic } 1128*61768Sbostic 1129*61768Sbostic operands[2] = add_op0; 1130*61768Sbostic operands[3] = add_op1; 1131*61768Sbostic ret = "add%:\t%0,%2,%3"; 1132*61768Sbostic } 1133*61768Sbostic } 1134*61768Sbostic 1135*61768Sbostic else if (code0 == MEM) 1136*61768Sbostic { 1137*61768Sbostic if (TARGET_STATS) 1138*61768Sbostic mips_count_memory_refs (op0, 1); 1139*61768Sbostic 1140*61768Sbostic if (code1 == REG) 1141*61768Sbostic { 1142*61768Sbostic int regno1 = REGNO (op1) + subreg_word1; 1143*61768Sbostic 1144*61768Sbostic if (GP_REG_P (regno1)) 1145*61768Sbostic { 1146*61768Sbostic switch (mode) 1147*61768Sbostic { 1148*61768Sbostic default: break; 1149*61768Sbostic case SFmode: ret = "sw\t%1,%0"; break; 1150*61768Sbostic case SImode: ret = "sw\t%1,%0"; break; 1151*61768Sbostic case HImode: ret = "sh\t%1,%0"; break; 1152*61768Sbostic case QImode: ret = "sb\t%1,%0"; break; 1153*61768Sbostic } 1154*61768Sbostic } 1155*61768Sbostic 1156*61768Sbostic else if (FP_REG_P (regno1) && (mode == SImode || mode == SFmode)) 1157*61768Sbostic ret = "s.s\t%1,%0"; 1158*61768Sbostic } 1159*61768Sbostic 1160*61768Sbostic else if (code1 == CONST_INT && INTVAL (op1) == 0) 1161*61768Sbostic { 1162*61768Sbostic switch (mode) 1163*61768Sbostic { 1164*61768Sbostic default: break; 1165*61768Sbostic case SFmode: ret = "sw\t%z1,%0"; break; 1166*61768Sbostic case SImode: ret = "sw\t%z1,%0"; break; 1167*61768Sbostic case HImode: ret = "sh\t%z1,%0"; break; 1168*61768Sbostic case QImode: ret = "sb\t%z1,%0"; break; 1169*61768Sbostic } 1170*61768Sbostic } 1171*61768Sbostic 1172*61768Sbostic else if (code1 == CONST_DOUBLE && CONST_DOUBLE_HIGH (op1) == 0 && CONST_DOUBLE_LOW (op1) == 0) 1173*61768Sbostic { 1174*61768Sbostic switch (mode) 1175*61768Sbostic { 1176*61768Sbostic default: break; 1177*61768Sbostic case SFmode: ret = "sw\t%.,%0"; break; 1178*61768Sbostic case SImode: ret = "sw\t%.,%0"; break; 1179*61768Sbostic case HImode: ret = "sh\t%.,%0"; break; 1180*61768Sbostic case QImode: ret = "sb\t%.,%0"; break; 1181*61768Sbostic } 1182*61768Sbostic } 1183*61768Sbostic 1184*61768Sbostic if (ret != (char *)0 && MEM_VOLATILE_P (op0)) 1185*61768Sbostic { 1186*61768Sbostic int i = strlen (ret); 1187*61768Sbostic if (i > sizeof (volatile_buffer) - sizeof ("%{%}")) 1188*61768Sbostic abort (); 1189*61768Sbostic 1190*61768Sbostic sprintf (volatile_buffer, "%%{%s%%}", ret); 1191*61768Sbostic ret = volatile_buffer; 1192*61768Sbostic } 1193*61768Sbostic } 1194*61768Sbostic 1195*61768Sbostic if (ret == (char *)0) 1196*61768Sbostic { 1197*61768Sbostic abort_with_insn (insn, "Bad move"); 1198*61768Sbostic return 0; 1199*61768Sbostic } 1200*61768Sbostic 1201*61768Sbostic if (delay != DELAY_NONE) 1202*61768Sbostic return mips_fill_delay_slot (ret, delay, operands, insn); 1203*61768Sbostic 1204*61768Sbostic return ret; 1205*61768Sbostic } 1206*61768Sbostic 1207*61768Sbostic 1208*61768Sbostic /* Return the appropriate instructions to move 2 words */ 1209*61768Sbostic 1210*61768Sbostic char * 1211*61768Sbostic mips_move_2words (operands, insn) 1212*61768Sbostic rtx operands[]; 1213*61768Sbostic rtx insn; 1214*61768Sbostic { 1215*61768Sbostic char *ret = 0; 1216*61768Sbostic rtx op0 = operands[0]; 1217*61768Sbostic rtx op1 = operands[1]; 1218*61768Sbostic enum rtx_code code0 = GET_CODE (operands[0]); 1219*61768Sbostic enum rtx_code code1 = GET_CODE (operands[1]); 1220*61768Sbostic int subreg_word0 = 0; 1221*61768Sbostic int subreg_word1 = 0; 1222*61768Sbostic enum delay_type delay = DELAY_NONE; 1223*61768Sbostic 1224*61768Sbostic while (code0 == SUBREG) 1225*61768Sbostic { 1226*61768Sbostic subreg_word0 += SUBREG_WORD (op0); 1227*61768Sbostic op0 = SUBREG_REG (op0); 1228*61768Sbostic code0 = GET_CODE (op0); 1229*61768Sbostic } 1230*61768Sbostic 1231*61768Sbostic while (code1 == SUBREG) 1232*61768Sbostic { 1233*61768Sbostic subreg_word1 += SUBREG_WORD (op1); 1234*61768Sbostic op1 = SUBREG_REG (op1); 1235*61768Sbostic code1 = GET_CODE (op1); 1236*61768Sbostic } 1237*61768Sbostic 1238*61768Sbostic if (code0 == REG) 1239*61768Sbostic { 1240*61768Sbostic int regno0 = REGNO (op0) + subreg_word0; 1241*61768Sbostic 1242*61768Sbostic if (code1 == REG) 1243*61768Sbostic { 1244*61768Sbostic int regno1 = REGNO (op1) + subreg_word1; 1245*61768Sbostic 1246*61768Sbostic /* Just in case, don't do anything for assigning a register 1247*61768Sbostic to itself, unless we are filling a delay slot. */ 1248*61768Sbostic if (regno0 == regno1 && set_nomacro == 0) 1249*61768Sbostic ret = ""; 1250*61768Sbostic 1251*61768Sbostic else if (FP_REG_P (regno0)) 1252*61768Sbostic { 1253*61768Sbostic if (FP_REG_P (regno1)) 1254*61768Sbostic ret = "mov.d\t%0,%1"; 1255*61768Sbostic 1256*61768Sbostic else 1257*61768Sbostic { 1258*61768Sbostic delay = DELAY_LOAD; 1259*61768Sbostic ret = (TARGET_FLOAT64) 1260*61768Sbostic ? "dmtc1\t%1,%0" 1261*61768Sbostic : "mtc1\t%L1,%0\n\tmtc1\t%M1,%D0"; 1262*61768Sbostic } 1263*61768Sbostic } 1264*61768Sbostic 1265*61768Sbostic else if (FP_REG_P (regno1)) 1266*61768Sbostic { 1267*61768Sbostic delay = DELAY_LOAD; 1268*61768Sbostic ret = (TARGET_FLOAT64) 1269*61768Sbostic ? "dmfc1\t%0,%1" 1270*61768Sbostic : "mfc1\t%L0,%1\n\tmfc1\t%M0,%D1"; 1271*61768Sbostic } 1272*61768Sbostic 1273*61768Sbostic else if (MD_REG_P (regno0) && GP_REG_P (regno1)) 1274*61768Sbostic { 1275*61768Sbostic delay = DELAY_HILO; 1276*61768Sbostic ret = "mthi\t%M1\n\tmtlo\t%L1"; 1277*61768Sbostic } 1278*61768Sbostic 1279*61768Sbostic else if (GP_REG_P (regno0) && MD_REG_P (regno1)) 1280*61768Sbostic { 1281*61768Sbostic delay = DELAY_HILO; 1282*61768Sbostic ret = "mfhi\t%M0\n\tmflo\t%L0"; 1283*61768Sbostic } 1284*61768Sbostic 1285*61768Sbostic else if (regno0 != (regno1+1)) 1286*61768Sbostic ret = "move\t%0,%1\n\tmove\t%D0,%D1"; 1287*61768Sbostic 1288*61768Sbostic else 1289*61768Sbostic ret = "move\t%D0,%D1\n\tmove\t%0,%1"; 1290*61768Sbostic } 1291*61768Sbostic 1292*61768Sbostic else if (code1 == CONST_DOUBLE) 1293*61768Sbostic { 1294*61768Sbostic if (CONST_DOUBLE_HIGH (op1) != 0 || CONST_DOUBLE_LOW (op1) != 0) 1295*61768Sbostic { 1296*61768Sbostic if (GET_MODE (op1) == DFmode) 1297*61768Sbostic { 1298*61768Sbostic delay = DELAY_LOAD; 1299*61768Sbostic ret = "li.d\t%0,%1"; 1300*61768Sbostic } 1301*61768Sbostic 1302*61768Sbostic else 1303*61768Sbostic { 1304*61768Sbostic operands[2] = GEN_INT (CONST_DOUBLE_LOW (op1)); 1305*61768Sbostic operands[3] = GEN_INT (CONST_DOUBLE_HIGH (op1)); 1306*61768Sbostic ret = "li\t%M0,%3\n\tli\t%L0,%2"; 1307*61768Sbostic } 1308*61768Sbostic } 1309*61768Sbostic 1310*61768Sbostic else 1311*61768Sbostic { 1312*61768Sbostic if (GP_REG_P (regno0)) 1313*61768Sbostic ret = "move\t%0,%.\n\tmove\t%D0,%."; 1314*61768Sbostic 1315*61768Sbostic else if (FP_REG_P (regno0)) 1316*61768Sbostic { 1317*61768Sbostic delay = DELAY_LOAD; 1318*61768Sbostic ret = (TARGET_FLOAT64) 1319*61768Sbostic ? "dmtc1\t%.,%0" 1320*61768Sbostic : "mtc1\t%.,%0\n\tmtc1\t%.,%D0"; 1321*61768Sbostic } 1322*61768Sbostic } 1323*61768Sbostic } 1324*61768Sbostic 1325*61768Sbostic else if (code1 == CONST_INT && INTVAL (op1) == 0) 1326*61768Sbostic { 1327*61768Sbostic if (GP_REG_P (regno0)) 1328*61768Sbostic ret = "move\t%0,%.\n\tmove\t%D0,%."; 1329*61768Sbostic 1330*61768Sbostic else if (FP_REG_P (regno0)) 1331*61768Sbostic { 1332*61768Sbostic delay = DELAY_LOAD; 1333*61768Sbostic ret = (TARGET_FLOAT64) 1334*61768Sbostic ? "dmtc1\t%.,%0" 1335*61768Sbostic : "mtc1\t%.,%0\n\tmtc1\t%.,%D0"; 1336*61768Sbostic } 1337*61768Sbostic } 1338*61768Sbostic 1339*61768Sbostic else if (code1 == CONST_INT && GET_MODE (op0) == DImode && GP_REG_P (regno0)) 1340*61768Sbostic { 1341*61768Sbostic operands[2] = GEN_INT (INTVAL (operands[1]) >= 0 ? 0 : -1); 1342*61768Sbostic ret = "li\t%M0,%2\n\tli\t%L0,%1"; 1343*61768Sbostic } 1344*61768Sbostic 1345*61768Sbostic else if (code1 == MEM) 1346*61768Sbostic { 1347*61768Sbostic delay = DELAY_LOAD; 1348*61768Sbostic 1349*61768Sbostic if (TARGET_STATS) 1350*61768Sbostic mips_count_memory_refs (op1, 2); 1351*61768Sbostic 1352*61768Sbostic if (FP_REG_P (regno0)) 1353*61768Sbostic ret = "l.d\t%0,%1"; 1354*61768Sbostic 1355*61768Sbostic else if (offsettable_address_p (1, DFmode, XEXP (op1, 0))) 1356*61768Sbostic { 1357*61768Sbostic operands[2] = adj_offsettable_operand (op1, 4); 1358*61768Sbostic if (reg_mentioned_p (op0, op1)) 1359*61768Sbostic ret = "lw\t%D0,%2\n\tlw\t%0,%1"; 1360*61768Sbostic else 1361*61768Sbostic ret = "lw\t%0,%1\n\tlw\t%D0,%2"; 1362*61768Sbostic } 1363*61768Sbostic 1364*61768Sbostic if (ret != (char *)0 && MEM_VOLATILE_P (op1)) 1365*61768Sbostic { 1366*61768Sbostic int i = strlen (ret); 1367*61768Sbostic if (i > sizeof (volatile_buffer) - sizeof ("%{%}")) 1368*61768Sbostic abort (); 1369*61768Sbostic 1370*61768Sbostic sprintf (volatile_buffer, "%%{%s%%}", ret); 1371*61768Sbostic ret = volatile_buffer; 1372*61768Sbostic } 1373*61768Sbostic } 1374*61768Sbostic } 1375*61768Sbostic 1376*61768Sbostic else if (code0 == MEM) 1377*61768Sbostic { 1378*61768Sbostic if (code1 == REG) 1379*61768Sbostic { 1380*61768Sbostic int regno1 = REGNO (op1) + subreg_word1; 1381*61768Sbostic 1382*61768Sbostic if (FP_REG_P (regno1)) 1383*61768Sbostic ret = "s.d\t%1,%0"; 1384*61768Sbostic 1385*61768Sbostic else if (offsettable_address_p (1, DFmode, XEXP (op0, 0))) 1386*61768Sbostic { 1387*61768Sbostic operands[2] = adj_offsettable_operand (op0, 4); 1388*61768Sbostic ret = "sw\t%1,%0\n\tsw\t%D1,%2"; 1389*61768Sbostic } 1390*61768Sbostic } 1391*61768Sbostic 1392*61768Sbostic else if (code1 == CONST_DOUBLE 1393*61768Sbostic && CONST_DOUBLE_HIGH (op1) == 0 1394*61768Sbostic && CONST_DOUBLE_LOW (op1) == 0 1395*61768Sbostic && offsettable_address_p (1, DFmode, XEXP (op0, 0))) 1396*61768Sbostic { 1397*61768Sbostic if (TARGET_FLOAT64) 1398*61768Sbostic ret = "sd\t%.,%0"; 1399*61768Sbostic else 1400*61768Sbostic { 1401*61768Sbostic operands[2] = adj_offsettable_operand (op0, 4); 1402*61768Sbostic ret = "sw\t%.,%0\n\tsw\t%.,%2"; 1403*61768Sbostic } 1404*61768Sbostic } 1405*61768Sbostic 1406*61768Sbostic if (TARGET_STATS) 1407*61768Sbostic mips_count_memory_refs (op0, 2); 1408*61768Sbostic 1409*61768Sbostic if (ret != (char *)0 && MEM_VOLATILE_P (op0)) 1410*61768Sbostic { 1411*61768Sbostic int i = strlen (ret); 1412*61768Sbostic if (i > sizeof (volatile_buffer) - sizeof ("%{%}")) 1413*61768Sbostic abort (); 1414*61768Sbostic 1415*61768Sbostic sprintf (volatile_buffer, "%%{%s%%}", ret); 1416*61768Sbostic ret = volatile_buffer; 1417*61768Sbostic } 1418*61768Sbostic } 1419*61768Sbostic 1420*61768Sbostic if (ret == (char *)0) 1421*61768Sbostic { 1422*61768Sbostic abort_with_insn (insn, "Bad move"); 1423*61768Sbostic return 0; 1424*61768Sbostic } 1425*61768Sbostic 1426*61768Sbostic if (delay != DELAY_NONE) 1427*61768Sbostic return mips_fill_delay_slot (ret, delay, operands, insn); 1428*61768Sbostic 1429*61768Sbostic return ret; 1430*61768Sbostic } 1431*61768Sbostic 1432*61768Sbostic 1433*61768Sbostic /* Provide the costs of an addressing mode that contains ADDR. 1434*61768Sbostic If ADDR is not a valid address, its cost is irrelevant. */ 1435*61768Sbostic 1436*61768Sbostic int 1437*61768Sbostic mips_address_cost (addr) 1438*61768Sbostic rtx addr; 1439*61768Sbostic { 1440*61768Sbostic switch (GET_CODE (addr)) 1441*61768Sbostic { 1442*61768Sbostic default: 1443*61768Sbostic break; 1444*61768Sbostic 1445*61768Sbostic case LO_SUM: 1446*61768Sbostic case HIGH: 1447*61768Sbostic return 1; 1448*61768Sbostic 1449*61768Sbostic case LABEL_REF: 1450*61768Sbostic return 2; 1451*61768Sbostic 1452*61768Sbostic case CONST: 1453*61768Sbostic { 1454*61768Sbostic rtx offset = const0_rtx; 1455*61768Sbostic addr = eliminate_constant_term (addr, &offset); 1456*61768Sbostic if (GET_CODE (addr) == LABEL_REF) 1457*61768Sbostic return 2; 1458*61768Sbostic 1459*61768Sbostic if (GET_CODE (addr) != SYMBOL_REF) 1460*61768Sbostic return 4; 1461*61768Sbostic 1462*61768Sbostic if (INTVAL (offset) < -32768 || INTVAL (offset) > 32767) 1463*61768Sbostic return 2; 1464*61768Sbostic } 1465*61768Sbostic /* fall through */ 1466*61768Sbostic 1467*61768Sbostic case SYMBOL_REF: 1468*61768Sbostic return SYMBOL_REF_FLAG (addr) ? 1 : 2; 1469*61768Sbostic 1470*61768Sbostic case PLUS: 1471*61768Sbostic { 1472*61768Sbostic register rtx plus0 = XEXP (addr, 0); 1473*61768Sbostic register rtx plus1 = XEXP (addr, 1); 1474*61768Sbostic 1475*61768Sbostic if (GET_CODE (plus0) != REG && GET_CODE (plus1) == REG) 1476*61768Sbostic { 1477*61768Sbostic plus0 = XEXP (addr, 1); 1478*61768Sbostic plus1 = XEXP (addr, 0); 1479*61768Sbostic } 1480*61768Sbostic 1481*61768Sbostic if (GET_CODE (plus0) != REG) 1482*61768Sbostic break; 1483*61768Sbostic 1484*61768Sbostic switch (GET_CODE (plus1)) 1485*61768Sbostic { 1486*61768Sbostic default: 1487*61768Sbostic break; 1488*61768Sbostic 1489*61768Sbostic case CONST_INT: 1490*61768Sbostic { 1491*61768Sbostic int value = INTVAL (plus1); 1492*61768Sbostic return (value < -32768 || value > 32767) ? 2 : 1; 1493*61768Sbostic } 1494*61768Sbostic 1495*61768Sbostic case CONST: 1496*61768Sbostic case SYMBOL_REF: 1497*61768Sbostic case LABEL_REF: 1498*61768Sbostic case HIGH: 1499*61768Sbostic case LO_SUM: 1500*61768Sbostic return mips_address_cost (plus1) + 1; 1501*61768Sbostic } 1502*61768Sbostic } 1503*61768Sbostic } 1504*61768Sbostic 1505*61768Sbostic return 4; 1506*61768Sbostic } 1507*61768Sbostic 1508*61768Sbostic 1509*61768Sbostic /* Make normal rtx_code into something we can index from an array */ 1510*61768Sbostic 1511*61768Sbostic static enum internal_test 1512*61768Sbostic map_test_to_internal_test (test_code) 1513*61768Sbostic enum rtx_code test_code; 1514*61768Sbostic { 1515*61768Sbostic enum internal_test test = ITEST_MAX; 1516*61768Sbostic 1517*61768Sbostic switch (test_code) 1518*61768Sbostic { 1519*61768Sbostic default: break; 1520*61768Sbostic case EQ: test = ITEST_EQ; break; 1521*61768Sbostic case NE: test = ITEST_NE; break; 1522*61768Sbostic case GT: test = ITEST_GT; break; 1523*61768Sbostic case GE: test = ITEST_GE; break; 1524*61768Sbostic case LT: test = ITEST_LT; break; 1525*61768Sbostic case LE: test = ITEST_LE; break; 1526*61768Sbostic case GTU: test = ITEST_GTU; break; 1527*61768Sbostic case GEU: test = ITEST_GEU; break; 1528*61768Sbostic case LTU: test = ITEST_LTU; break; 1529*61768Sbostic case LEU: test = ITEST_LEU; break; 1530*61768Sbostic } 1531*61768Sbostic 1532*61768Sbostic return test; 1533*61768Sbostic } 1534*61768Sbostic 1535*61768Sbostic 1536*61768Sbostic /* Generate the code to compare two integer values. The return value is: 1537*61768Sbostic (reg:SI xx) The pseudo register the comparison is in 1538*61768Sbostic (rtx)0 No register, generate a simple branch. */ 1539*61768Sbostic 1540*61768Sbostic rtx 1541*61768Sbostic gen_int_relational (test_code, result, cmp0, cmp1, p_invert) 1542*61768Sbostic enum rtx_code test_code; /* relational test (EQ, etc) */ 1543*61768Sbostic rtx result; /* result to store comp. or 0 if branch */ 1544*61768Sbostic rtx cmp0; /* first operand to compare */ 1545*61768Sbostic rtx cmp1; /* second operand to compare */ 1546*61768Sbostic int *p_invert; /* NULL or ptr to hold whether branch needs */ 1547*61768Sbostic /* to reverse its test */ 1548*61768Sbostic { 1549*61768Sbostic struct cmp_info { 1550*61768Sbostic enum rtx_code test_code; /* code to use in instruction (LT vs. LTU) */ 1551*61768Sbostic int const_low; /* low bound of constant we can accept */ 1552*61768Sbostic int const_high; /* high bound of constant we can accept */ 1553*61768Sbostic int const_add; /* constant to add (convert LE -> LT) */ 1554*61768Sbostic int reverse_regs; /* reverse registers in test */ 1555*61768Sbostic int invert_const; /* != 0 if invert value if cmp1 is constant */ 1556*61768Sbostic int invert_reg; /* != 0 if invert value if cmp1 is register */ 1557*61768Sbostic int unsignedp; /* != 0 for unsigned comparisons. */ 1558*61768Sbostic }; 1559*61768Sbostic 1560*61768Sbostic static struct cmp_info info[ (int)ITEST_MAX ] = { 1561*61768Sbostic 1562*61768Sbostic { XOR, 0, 65535, 0, 0, 0, 0, 0 }, /* EQ */ 1563*61768Sbostic { XOR, 0, 65535, 0, 0, 1, 1, 0 }, /* NE */ 1564*61768Sbostic { LT, -32769, 32766, 1, 1, 1, 0, 0 }, /* GT */ 1565*61768Sbostic { LT, -32768, 32767, 0, 0, 1, 1, 0 }, /* GE */ 1566*61768Sbostic { LT, -32768, 32767, 0, 0, 0, 0, 0 }, /* LT */ 1567*61768Sbostic { LT, -32769, 32766, 1, 1, 0, 1, 0 }, /* LE */ 1568*61768Sbostic { LTU, -32769, 32766, 1, 1, 1, 0, 1 }, /* GTU */ 1569*61768Sbostic { LTU, -32768, 32767, 0, 0, 1, 1, 1 }, /* GEU */ 1570*61768Sbostic { LTU, -32768, 32767, 0, 0, 0, 0, 1 }, /* LTU */ 1571*61768Sbostic { LTU, -32769, 32766, 1, 1, 0, 1, 1 }, /* LEU */ 1572*61768Sbostic }; 1573*61768Sbostic 1574*61768Sbostic enum internal_test test; 1575*61768Sbostic struct cmp_info *p_info; 1576*61768Sbostic int branch_p; 1577*61768Sbostic int eqne_p; 1578*61768Sbostic int invert; 1579*61768Sbostic rtx reg; 1580*61768Sbostic rtx reg2; 1581*61768Sbostic 1582*61768Sbostic test = map_test_to_internal_test (test_code); 1583*61768Sbostic if (test == ITEST_MAX) 1584*61768Sbostic abort (); 1585*61768Sbostic 1586*61768Sbostic p_info = &info[ (int)test ]; 1587*61768Sbostic eqne_p = (p_info->test_code == XOR); 1588*61768Sbostic 1589*61768Sbostic /* Eliminate simple branches */ 1590*61768Sbostic branch_p = (result == (rtx)0); 1591*61768Sbostic if (branch_p) 1592*61768Sbostic { 1593*61768Sbostic if (GET_CODE (cmp0) == REG || GET_CODE (cmp0) == SUBREG) 1594*61768Sbostic { 1595*61768Sbostic /* Comparisons against zero are simple branches */ 1596*61768Sbostic if (GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) == 0) 1597*61768Sbostic return (rtx)0; 1598*61768Sbostic 1599*61768Sbostic /* Test for beq/bne. */ 1600*61768Sbostic if (eqne_p) 1601*61768Sbostic return (rtx)0; 1602*61768Sbostic } 1603*61768Sbostic 1604*61768Sbostic /* allocate a pseudo to calculate the value in. */ 1605*61768Sbostic result = gen_reg_rtx (SImode); 1606*61768Sbostic } 1607*61768Sbostic 1608*61768Sbostic /* Make sure we can handle any constants given to us. */ 1609*61768Sbostic if (GET_CODE (cmp0) == CONST_INT) 1610*61768Sbostic cmp0 = force_reg (SImode, cmp0); 1611*61768Sbostic 1612*61768Sbostic if (GET_CODE (cmp1) == CONST_INT) 1613*61768Sbostic { 1614*61768Sbostic HOST_WIDE_INT value = INTVAL (cmp1); 1615*61768Sbostic if (value < p_info->const_low || value > p_info->const_high) 1616*61768Sbostic cmp1 = force_reg (SImode, cmp1); 1617*61768Sbostic } 1618*61768Sbostic 1619*61768Sbostic /* See if we need to invert the result. */ 1620*61768Sbostic invert = (GET_CODE (cmp1) == CONST_INT) 1621*61768Sbostic ? p_info->invert_const 1622*61768Sbostic : p_info->invert_reg; 1623*61768Sbostic 1624*61768Sbostic if (p_invert != (int *)0) 1625*61768Sbostic { 1626*61768Sbostic *p_invert = invert; 1627*61768Sbostic invert = FALSE; 1628*61768Sbostic } 1629*61768Sbostic 1630*61768Sbostic /* Comparison to constants, may involve adding 1 to change a LT into LE. 1631*61768Sbostic Comparison between two registers, may involve switching operands. */ 1632*61768Sbostic if (GET_CODE (cmp1) == CONST_INT) 1633*61768Sbostic { 1634*61768Sbostic if (p_info->const_add != 0) 1635*61768Sbostic { 1636*61768Sbostic HOST_WIDE_INT new = INTVAL (cmp1) + p_info->const_add; 1637*61768Sbostic /* If modification of cmp1 caused overflow, 1638*61768Sbostic we would get the wrong answer if we follow the usual path; 1639*61768Sbostic thus, x > 0xffffffffu would turn into x > 0u. */ 1640*61768Sbostic if ((p_info->unsignedp 1641*61768Sbostic ? (unsigned HOST_WIDE_INT) new > INTVAL (cmp1) 1642*61768Sbostic : new > INTVAL (cmp1)) 1643*61768Sbostic != (p_info->const_add > 0)) 1644*61768Sbostic /* 1 is the right value in the LE and LEU case. 1645*61768Sbostic In the GT and GTU case, *p_invert is already set, 1646*61768Sbostic so this is effectively 0. */ 1647*61768Sbostic return force_reg (SImode, const1_rtx); 1648*61768Sbostic else 1649*61768Sbostic cmp1 = GEN_INT (new); 1650*61768Sbostic } 1651*61768Sbostic } 1652*61768Sbostic else if (p_info->reverse_regs) 1653*61768Sbostic { 1654*61768Sbostic rtx temp = cmp0; 1655*61768Sbostic cmp0 = cmp1; 1656*61768Sbostic cmp1 = temp; 1657*61768Sbostic } 1658*61768Sbostic 1659*61768Sbostic if (test == ITEST_NE && GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) == 0) 1660*61768Sbostic reg = cmp0; 1661*61768Sbostic else 1662*61768Sbostic { 1663*61768Sbostic reg = (invert || eqne_p) ? gen_reg_rtx (SImode) : result; 1664*61768Sbostic emit_move_insn (reg, gen_rtx (p_info->test_code, SImode, cmp0, cmp1)); 1665*61768Sbostic } 1666*61768Sbostic 1667*61768Sbostic if (test == ITEST_NE) 1668*61768Sbostic { 1669*61768Sbostic emit_move_insn (result, gen_rtx (GTU, SImode, reg, const0_rtx)); 1670*61768Sbostic invert = FALSE; 1671*61768Sbostic } 1672*61768Sbostic 1673*61768Sbostic else if (test == ITEST_EQ) 1674*61768Sbostic { 1675*61768Sbostic reg2 = (invert) ? gen_reg_rtx (SImode) : result; 1676*61768Sbostic emit_move_insn (reg2, gen_rtx (LTU, SImode, reg, const1_rtx)); 1677*61768Sbostic reg = reg2; 1678*61768Sbostic } 1679*61768Sbostic 1680*61768Sbostic if (invert) 1681*61768Sbostic emit_move_insn (result, gen_rtx (XOR, SImode, reg, const1_rtx)); 1682*61768Sbostic 1683*61768Sbostic return result; 1684*61768Sbostic } 1685*61768Sbostic 1686*61768Sbostic 1687*61768Sbostic /* Emit the common code for doing conditional branches. 1688*61768Sbostic operand[0] is the label to jump to. 1689*61768Sbostic The comparison operands are saved away by cmp{si,sf,df}. */ 1690*61768Sbostic 1691*61768Sbostic void 1692*61768Sbostic gen_conditional_branch (operands, test_code) 1693*61768Sbostic rtx operands[]; 1694*61768Sbostic enum rtx_code test_code; 1695*61768Sbostic { 1696*61768Sbostic static enum machine_mode mode_map[(int)CMP_MAX][(int)ITEST_MAX] = { 1697*61768Sbostic { /* CMP_SI */ 1698*61768Sbostic SImode, /* eq */ 1699*61768Sbostic SImode, /* ne */ 1700*61768Sbostic SImode, /* gt */ 1701*61768Sbostic SImode, /* ge */ 1702*61768Sbostic SImode, /* lt */ 1703*61768Sbostic SImode, /* le */ 1704*61768Sbostic SImode, /* gtu */ 1705*61768Sbostic SImode, /* geu */ 1706*61768Sbostic SImode, /* ltu */ 1707*61768Sbostic SImode, /* leu */ 1708*61768Sbostic }, 1709*61768Sbostic { /* CMP_SF */ 1710*61768Sbostic CC_FPmode, /* eq */ 1711*61768Sbostic CC_REV_FPmode, /* ne */ 1712*61768Sbostic CC_FPmode, /* gt */ 1713*61768Sbostic CC_FPmode, /* ge */ 1714*61768Sbostic CC_FPmode, /* lt */ 1715*61768Sbostic CC_FPmode, /* le */ 1716*61768Sbostic VOIDmode, /* gtu */ 1717*61768Sbostic VOIDmode, /* geu */ 1718*61768Sbostic VOIDmode, /* ltu */ 1719*61768Sbostic VOIDmode, /* leu */ 1720*61768Sbostic }, 1721*61768Sbostic { /* CMP_DF */ 1722*61768Sbostic CC_FPmode, /* eq */ 1723*61768Sbostic CC_REV_FPmode, /* ne */ 1724*61768Sbostic CC_FPmode, /* gt */ 1725*61768Sbostic CC_FPmode, /* ge */ 1726*61768Sbostic CC_FPmode, /* lt */ 1727*61768Sbostic CC_FPmode, /* le */ 1728*61768Sbostic VOIDmode, /* gtu */ 1729*61768Sbostic VOIDmode, /* geu */ 1730*61768Sbostic VOIDmode, /* ltu */ 1731*61768Sbostic VOIDmode, /* leu */ 1732*61768Sbostic }, 1733*61768Sbostic }; 1734*61768Sbostic 1735*61768Sbostic enum machine_mode mode; 1736*61768Sbostic enum cmp_type type = branch_type; 1737*61768Sbostic rtx cmp0 = branch_cmp[0]; 1738*61768Sbostic rtx cmp1 = branch_cmp[1]; 1739*61768Sbostic rtx label1 = gen_rtx (LABEL_REF, VOIDmode, operands[0]); 1740*61768Sbostic rtx label2 = pc_rtx; 1741*61768Sbostic rtx reg = (rtx)0; 1742*61768Sbostic int invert = 0; 1743*61768Sbostic enum internal_test test = map_test_to_internal_test (test_code); 1744*61768Sbostic 1745*61768Sbostic if (test == ITEST_MAX) 1746*61768Sbostic { 1747*61768Sbostic mode = SImode; 1748*61768Sbostic goto fail; 1749*61768Sbostic } 1750*61768Sbostic 1751*61768Sbostic /* Get the machine mode to use (CCmode, CC_EQmode, CC_FPmode, or CC_REV_FPmode). */ 1752*61768Sbostic mode = mode_map[(int)type][(int)test]; 1753*61768Sbostic if (mode == VOIDmode) 1754*61768Sbostic goto fail; 1755*61768Sbostic 1756*61768Sbostic switch (branch_type) 1757*61768Sbostic { 1758*61768Sbostic default: 1759*61768Sbostic goto fail; 1760*61768Sbostic 1761*61768Sbostic case CMP_SI: 1762*61768Sbostic reg = gen_int_relational (test_code, (rtx)0, cmp0, cmp1, &invert); 1763*61768Sbostic if (reg != (rtx)0) 1764*61768Sbostic { 1765*61768Sbostic cmp0 = reg; 1766*61768Sbostic cmp1 = const0_rtx; 1767*61768Sbostic test_code = NE; 1768*61768Sbostic } 1769*61768Sbostic 1770*61768Sbostic /* Make sure not non-zero constant if ==/!= */ 1771*61768Sbostic else if (GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) != 0) 1772*61768Sbostic cmp1 = force_reg (SImode, cmp1); 1773*61768Sbostic 1774*61768Sbostic break; 1775*61768Sbostic 1776*61768Sbostic case CMP_DF: 1777*61768Sbostic case CMP_SF: 1778*61768Sbostic { 1779*61768Sbostic rtx reg = gen_rtx (REG, mode, FPSW_REGNUM); 1780*61768Sbostic emit_insn (gen_rtx (SET, VOIDmode, reg, gen_rtx (test_code, mode, cmp0, cmp1))); 1781*61768Sbostic cmp0 = reg; 1782*61768Sbostic cmp1 = const0_rtx; 1783*61768Sbostic test_code = NE; 1784*61768Sbostic } 1785*61768Sbostic break; 1786*61768Sbostic } 1787*61768Sbostic 1788*61768Sbostic /* Generate the jump */ 1789*61768Sbostic if (invert) 1790*61768Sbostic { 1791*61768Sbostic label2 = label1; 1792*61768Sbostic label1 = pc_rtx; 1793*61768Sbostic } 1794*61768Sbostic 1795*61768Sbostic emit_jump_insn (gen_rtx (SET, VOIDmode, 1796*61768Sbostic pc_rtx, 1797*61768Sbostic gen_rtx (IF_THEN_ELSE, VOIDmode, 1798*61768Sbostic gen_rtx (test_code, mode, cmp0, cmp1), 1799*61768Sbostic label1, 1800*61768Sbostic label2))); 1801*61768Sbostic 1802*61768Sbostic return; 1803*61768Sbostic 1804*61768Sbostic fail: 1805*61768Sbostic abort_with_insn (gen_rtx (test_code, mode, cmp0, cmp1), "bad test"); 1806*61768Sbostic } 1807*61768Sbostic 1808*61768Sbostic 1809*61768Sbostic #define UNITS_PER_SHORT (SHORT_TYPE_SIZE / BITS_PER_UNIT) 1810*61768Sbostic 1811*61768Sbostic /* Internal code to generate the load and store of one word/short/byte. 1812*61768Sbostic The load is emitted directly, and the store insn is returned. */ 1813*61768Sbostic 1814*61768Sbostic #if 0 1815*61768Sbostic static rtx 1816*61768Sbostic block_move_load_store (dest_reg, src_reg, p_bytes, p_offset, align, orig_src) 1817*61768Sbostic rtx src_reg; /* register holding source memory address */ 1818*61768Sbostic rtx dest_reg; /* register holding dest. memory address */ 1819*61768Sbostic int *p_bytes; /* pointer to # bytes remaining */ 1820*61768Sbostic int *p_offset; /* pointer to current offset */ 1821*61768Sbostic int align; /* alignment */ 1822*61768Sbostic rtx orig_src; /* original source for making a reg note */ 1823*61768Sbostic { 1824*61768Sbostic int bytes; /* # bytes remaining */ 1825*61768Sbostic int offset; /* offset to use */ 1826*61768Sbostic int size; /* size in bytes of load/store */ 1827*61768Sbostic enum machine_mode mode; /* mode to use for load/store */ 1828*61768Sbostic rtx reg; /* temporary register */ 1829*61768Sbostic rtx src_addr; /* source address */ 1830*61768Sbostic rtx dest_addr; /* destination address */ 1831*61768Sbostic rtx insn; /* insn of the load */ 1832*61768Sbostic rtx orig_src_addr; /* original source address */ 1833*61768Sbostic rtx (*load_func)(); /* function to generate load insn */ 1834*61768Sbostic rtx (*store_func)(); /* function to generate destination insn */ 1835*61768Sbostic 1836*61768Sbostic bytes = *p_bytes; 1837*61768Sbostic if (bytes <= 0 || align <= 0) 1838*61768Sbostic abort (); 1839*61768Sbostic 1840*61768Sbostic if (bytes >= UNITS_PER_WORD && align >= UNITS_PER_WORD) 1841*61768Sbostic { 1842*61768Sbostic mode = SImode; 1843*61768Sbostic size = UNITS_PER_WORD; 1844*61768Sbostic load_func = gen_movsi; 1845*61768Sbostic store_func = gen_movsi; 1846*61768Sbostic } 1847*61768Sbostic 1848*61768Sbostic #if 0 1849*61768Sbostic /* Don't generate unligned moves here, rather defer those to the 1850*61768Sbostic general movestrsi_internal pattern. */ 1851*61768Sbostic else if (bytes >= UNITS_PER_WORD) 1852*61768Sbostic { 1853*61768Sbostic mode = SImode; 1854*61768Sbostic size = UNITS_PER_WORD; 1855*61768Sbostic load_func = gen_movsi_ulw; 1856*61768Sbostic store_func = gen_movsi_usw; 1857*61768Sbostic } 1858*61768Sbostic #endif 1859*61768Sbostic 1860*61768Sbostic else if (bytes >= UNITS_PER_SHORT && align >= UNITS_PER_SHORT) 1861*61768Sbostic { 1862*61768Sbostic mode = HImode; 1863*61768Sbostic size = UNITS_PER_SHORT; 1864*61768Sbostic load_func = gen_movhi; 1865*61768Sbostic store_func = gen_movhi; 1866*61768Sbostic } 1867*61768Sbostic 1868*61768Sbostic else 1869*61768Sbostic { 1870*61768Sbostic mode = QImode; 1871*61768Sbostic size = 1; 1872*61768Sbostic load_func = gen_movqi; 1873*61768Sbostic store_func = gen_movqi; 1874*61768Sbostic } 1875*61768Sbostic 1876*61768Sbostic offset = *p_offset; 1877*61768Sbostic *p_offset = offset + size; 1878*61768Sbostic *p_bytes = bytes - size; 1879*61768Sbostic 1880*61768Sbostic if (offset == 0) 1881*61768Sbostic { 1882*61768Sbostic src_addr = src_reg; 1883*61768Sbostic dest_addr = dest_reg; 1884*61768Sbostic } 1885*61768Sbostic else 1886*61768Sbostic { 1887*61768Sbostic src_addr = gen_rtx (PLUS, Pmode, src_reg, GEN_INT (offset)); 1888*61768Sbostic dest_addr = gen_rtx (PLUS, Pmode, dest_reg, GEN_INT (offset)); 1889*61768Sbostic } 1890*61768Sbostic 1891*61768Sbostic reg = gen_reg_rtx (mode); 1892*61768Sbostic insn = emit_insn ((*load_func) (reg, gen_rtx (MEM, mode, src_addr))); 1893*61768Sbostic orig_src_addr = XEXP (orig_src, 0); 1894*61768Sbostic if (CONSTANT_P (orig_src_addr)) 1895*61768Sbostic REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUIV, 1896*61768Sbostic plus_constant (orig_src_addr, offset), 1897*61768Sbostic REG_NOTES (insn)); 1898*61768Sbostic 1899*61768Sbostic return (*store_func) (gen_rtx (MEM, mode, dest_addr), reg); 1900*61768Sbostic } 1901*61768Sbostic #endif 1902*61768Sbostic 1903*61768Sbostic 1904*61768Sbostic /* Write a series of loads/stores to move some bytes. Generate load/stores as follows: 1905*61768Sbostic 1906*61768Sbostic load 1 1907*61768Sbostic load 2 1908*61768Sbostic load 3 1909*61768Sbostic store 1 1910*61768Sbostic load 4 1911*61768Sbostic store 2 1912*61768Sbostic load 5 1913*61768Sbostic store 3 1914*61768Sbostic ... 1915*61768Sbostic 1916*61768Sbostic This way, no NOP's are needed, except at the end, and only 1917*61768Sbostic two temp registers are needed. Two delay slots are used 1918*61768Sbostic in deference to the R4000. */ 1919*61768Sbostic 1920*61768Sbostic #if 0 1921*61768Sbostic static void 1922*61768Sbostic block_move_sequence (dest_reg, src_reg, bytes, align, orig_src) 1923*61768Sbostic rtx dest_reg; /* register holding destination address */ 1924*61768Sbostic rtx src_reg; /* register holding source address */ 1925*61768Sbostic int bytes; /* # bytes to move */ 1926*61768Sbostic int align; /* max alignment to assume */ 1927*61768Sbostic rtx orig_src; /* original source for making a reg note */ 1928*61768Sbostic { 1929*61768Sbostic int offset = 0; 1930*61768Sbostic rtx prev2_store = (rtx)0; 1931*61768Sbostic rtx prev_store = (rtx)0; 1932*61768Sbostic rtx cur_store = (rtx)0; 1933*61768Sbostic 1934*61768Sbostic while (bytes > 0) 1935*61768Sbostic { 1936*61768Sbostic /* Is there a store to do? */ 1937*61768Sbostic if (prev2_store) 1938*61768Sbostic emit_insn (prev2_store); 1939*61768Sbostic 1940*61768Sbostic prev2_store = prev_store; 1941*61768Sbostic prev_store = cur_store; 1942*61768Sbostic cur_store = block_move_load_store (dest_reg, src_reg, 1943*61768Sbostic &bytes, &offset, 1944*61768Sbostic align, orig_src); 1945*61768Sbostic } 1946*61768Sbostic 1947*61768Sbostic /* Finish up last three stores. */ 1948*61768Sbostic if (prev2_store) 1949*61768Sbostic emit_insn (prev2_store); 1950*61768Sbostic 1951*61768Sbostic if (prev_store) 1952*61768Sbostic emit_insn (prev_store); 1953*61768Sbostic 1954*61768Sbostic if (cur_store) 1955*61768Sbostic emit_insn (cur_store); 1956*61768Sbostic } 1957*61768Sbostic #endif 1958*61768Sbostic 1959*61768Sbostic 1960*61768Sbostic /* Write a loop to move a constant number of bytes. Generate load/stores as follows: 1961*61768Sbostic 1962*61768Sbostic do { 1963*61768Sbostic temp1 = src[0]; 1964*61768Sbostic temp2 = src[1]; 1965*61768Sbostic ... 1966*61768Sbostic temp<last> = src[MAX_MOVE_REGS-1]; 1967*61768Sbostic dest[0] = temp1; 1968*61768Sbostic dest[1] = temp2; 1969*61768Sbostic ... 1970*61768Sbostic dest[MAX_MOVE_REGS-1] = temp<last>; 1971*61768Sbostic src += MAX_MOVE_REGS; 1972*61768Sbostic dest += MAX_MOVE_REGS; 1973*61768Sbostic } while (src != final); 1974*61768Sbostic 1975*61768Sbostic This way, no NOP's are needed, and only MAX_MOVE_REGS+3 temp 1976*61768Sbostic registers are needed. 1977*61768Sbostic 1978*61768Sbostic Aligned moves move MAX_MOVE_REGS*4 bytes every (2*MAX_MOVE_REGS)+3 1979*61768Sbostic cycles, unaligned moves move MAX_MOVE_REGS*4 bytes every 1980*61768Sbostic (4*MAX_MOVE_REGS)+3 cycles, assuming no cache misses. */ 1981*61768Sbostic 1982*61768Sbostic #define MAX_MOVE_REGS 4 1983*61768Sbostic #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD) 1984*61768Sbostic 1985*61768Sbostic static void 1986*61768Sbostic block_move_loop (dest_reg, src_reg, bytes, align, orig_src) 1987*61768Sbostic rtx dest_reg; /* register holding destination address */ 1988*61768Sbostic rtx src_reg; /* register holding source address */ 1989*61768Sbostic int bytes; /* # bytes to move */ 1990*61768Sbostic int align; /* alignment */ 1991*61768Sbostic rtx orig_src; /* original source for making a reg note */ 1992*61768Sbostic { 1993*61768Sbostic rtx dest_mem = gen_rtx (MEM, BLKmode, dest_reg); 1994*61768Sbostic rtx src_mem = gen_rtx (MEM, BLKmode, src_reg); 1995*61768Sbostic rtx align_rtx = GEN_INT (align); 1996*61768Sbostic rtx label; 1997*61768Sbostic rtx final_src; 1998*61768Sbostic rtx bytes_rtx; 1999*61768Sbostic int leftover; 2000*61768Sbostic 2001*61768Sbostic if (bytes < 2*MAX_MOVE_BYTES) 2002*61768Sbostic abort (); 2003*61768Sbostic 2004*61768Sbostic leftover = bytes % MAX_MOVE_BYTES; 2005*61768Sbostic bytes -= leftover; 2006*61768Sbostic 2007*61768Sbostic label = gen_label_rtx (); 2008*61768Sbostic final_src = gen_reg_rtx (Pmode); 2009*61768Sbostic bytes_rtx = GEN_INT (bytes); 2010*61768Sbostic 2011*61768Sbostic if (bytes > 0x7fff) 2012*61768Sbostic { 2013*61768Sbostic emit_insn (gen_movsi (final_src, bytes_rtx)); 2014*61768Sbostic emit_insn (gen_addsi3 (final_src, final_src, src_reg)); 2015*61768Sbostic } 2016*61768Sbostic else 2017*61768Sbostic emit_insn (gen_addsi3 (final_src, src_reg, bytes_rtx)); 2018*61768Sbostic 2019*61768Sbostic emit_label (label); 2020*61768Sbostic 2021*61768Sbostic bytes_rtx = GEN_INT (MAX_MOVE_BYTES); 2022*61768Sbostic emit_insn (gen_movstrsi_internal (dest_mem, src_mem, bytes_rtx, align_rtx)); 2023*61768Sbostic emit_insn (gen_addsi3 (src_reg, src_reg, bytes_rtx)); 2024*61768Sbostic emit_insn (gen_addsi3 (dest_reg, dest_reg, bytes_rtx)); 2025*61768Sbostic emit_insn (gen_cmpsi (src_reg, final_src)); 2026*61768Sbostic emit_jump_insn (gen_bne (label)); 2027*61768Sbostic 2028*61768Sbostic if (leftover) 2029*61768Sbostic emit_insn (gen_movstrsi_internal (dest_mem, src_mem, 2030*61768Sbostic GEN_INT (leftover), 2031*61768Sbostic align_rtx)); 2032*61768Sbostic } 2033*61768Sbostic 2034*61768Sbostic 2035*61768Sbostic /* Use a library function to move some bytes. */ 2036*61768Sbostic 2037*61768Sbostic static void 2038*61768Sbostic block_move_call (dest_reg, src_reg, bytes_rtx) 2039*61768Sbostic rtx dest_reg; 2040*61768Sbostic rtx src_reg; 2041*61768Sbostic rtx bytes_rtx; 2042*61768Sbostic { 2043*61768Sbostic #ifdef TARGET_MEM_FUNCTIONS 2044*61768Sbostic emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0, 2045*61768Sbostic VOIDmode, 3, 2046*61768Sbostic dest_reg, Pmode, 2047*61768Sbostic src_reg, Pmode, 2048*61768Sbostic bytes_rtx, SImode); 2049*61768Sbostic #else 2050*61768Sbostic emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), 0, 2051*61768Sbostic VOIDmode, 3, 2052*61768Sbostic src_reg, Pmode, 2053*61768Sbostic dest_reg, Pmode, 2054*61768Sbostic bytes_rtx, SImode); 2055*61768Sbostic #endif 2056*61768Sbostic } 2057*61768Sbostic 2058*61768Sbostic 2059*61768Sbostic /* Expand string/block move operations. 2060*61768Sbostic 2061*61768Sbostic operands[0] is the pointer to the destination. 2062*61768Sbostic operands[1] is the pointer to the source. 2063*61768Sbostic operands[2] is the number of bytes to move. 2064*61768Sbostic operands[3] is the alignment. */ 2065*61768Sbostic 2066*61768Sbostic void 2067*61768Sbostic expand_block_move (operands) 2068*61768Sbostic rtx operands[]; 2069*61768Sbostic { 2070*61768Sbostic rtx bytes_rtx = operands[2]; 2071*61768Sbostic rtx align_rtx = operands[3]; 2072*61768Sbostic int constp = (GET_CODE (bytes_rtx) == CONST_INT); 2073*61768Sbostic int bytes = (constp ? INTVAL (bytes_rtx) : 0); 2074*61768Sbostic int align = INTVAL (align_rtx); 2075*61768Sbostic rtx orig_src = operands[1]; 2076*61768Sbostic rtx src_reg; 2077*61768Sbostic rtx dest_reg; 2078*61768Sbostic 2079*61768Sbostic if (constp && bytes <= 0) 2080*61768Sbostic return; 2081*61768Sbostic 2082*61768Sbostic if (align > UNITS_PER_WORD) 2083*61768Sbostic align = UNITS_PER_WORD; 2084*61768Sbostic 2085*61768Sbostic /* Move the address into scratch registers. */ 2086*61768Sbostic dest_reg = copy_addr_to_reg (XEXP (operands[0], 0)); 2087*61768Sbostic src_reg = copy_addr_to_reg (XEXP (orig_src, 0)); 2088*61768Sbostic 2089*61768Sbostic if (TARGET_MEMCPY) 2090*61768Sbostic block_move_call (dest_reg, src_reg, bytes_rtx); 2091*61768Sbostic 2092*61768Sbostic #if 0 2093*61768Sbostic else if (constp && bytes <= 3*align) 2094*61768Sbostic block_move_sequence (dest_reg, src_reg, bytes, align, orig_src); 2095*61768Sbostic #endif 2096*61768Sbostic 2097*61768Sbostic else if (constp && bytes <= 2*MAX_MOVE_BYTES) 2098*61768Sbostic emit_insn (gen_movstrsi_internal (gen_rtx (MEM, BLKmode, dest_reg), 2099*61768Sbostic gen_rtx (MEM, BLKmode, src_reg), 2100*61768Sbostic bytes_rtx, align_rtx)); 2101*61768Sbostic 2102*61768Sbostic else if (constp && align >= UNITS_PER_WORD && optimize) 2103*61768Sbostic block_move_loop (dest_reg, src_reg, bytes, align, orig_src); 2104*61768Sbostic 2105*61768Sbostic else if (constp && optimize) 2106*61768Sbostic { 2107*61768Sbostic /* If the alignment is not word aligned, generate a test at 2108*61768Sbostic runtime, to see whether things wound up aligned, and we 2109*61768Sbostic can use the faster lw/sw instead ulw/usw. */ 2110*61768Sbostic 2111*61768Sbostic rtx temp = gen_reg_rtx (Pmode); 2112*61768Sbostic rtx aligned_label = gen_label_rtx (); 2113*61768Sbostic rtx join_label = gen_label_rtx (); 2114*61768Sbostic int leftover = bytes % MAX_MOVE_BYTES; 2115*61768Sbostic 2116*61768Sbostic bytes -= leftover; 2117*61768Sbostic 2118*61768Sbostic emit_insn (gen_iorsi3 (temp, src_reg, dest_reg)); 2119*61768Sbostic emit_insn (gen_andsi3 (temp, temp, GEN_INT (UNITS_PER_WORD-1))); 2120*61768Sbostic emit_insn (gen_cmpsi (temp, const0_rtx)); 2121*61768Sbostic emit_jump_insn (gen_beq (aligned_label)); 2122*61768Sbostic 2123*61768Sbostic /* Unaligned loop. */ 2124*61768Sbostic block_move_loop (dest_reg, src_reg, bytes, 1, orig_src); 2125*61768Sbostic emit_jump_insn (gen_jump (join_label)); 2126*61768Sbostic emit_barrier (); 2127*61768Sbostic 2128*61768Sbostic /* Aligned loop. */ 2129*61768Sbostic emit_label (aligned_label); 2130*61768Sbostic block_move_loop (dest_reg, src_reg, bytes, UNITS_PER_WORD, orig_src); 2131*61768Sbostic emit_label (join_label); 2132*61768Sbostic 2133*61768Sbostic /* Bytes at the end of the loop. */ 2134*61768Sbostic if (leftover) 2135*61768Sbostic { 2136*61768Sbostic #if 0 2137*61768Sbostic if (leftover <= 3*align) 2138*61768Sbostic block_move_sequence (dest_reg, src_reg, leftover, align, orig_src); 2139*61768Sbostic 2140*61768Sbostic else 2141*61768Sbostic #endif 2142*61768Sbostic emit_insn (gen_movstrsi_internal (gen_rtx (MEM, BLKmode, dest_reg), 2143*61768Sbostic gen_rtx (MEM, BLKmode, src_reg), 2144*61768Sbostic GEN_INT (leftover), 2145*61768Sbostic GEN_INT (align))); 2146*61768Sbostic } 2147*61768Sbostic } 2148*61768Sbostic 2149*61768Sbostic else 2150*61768Sbostic block_move_call (dest_reg, src_reg, bytes_rtx); 2151*61768Sbostic } 2152*61768Sbostic 2153*61768Sbostic 2154*61768Sbostic /* Emit load/stores for a small constant block_move. 2155*61768Sbostic 2156*61768Sbostic operands[0] is the memory address of the destination. 2157*61768Sbostic operands[1] is the memory address of the source. 2158*61768Sbostic operands[2] is the number of bytes to move. 2159*61768Sbostic operands[3] is the alignment. 2160*61768Sbostic operands[4] is a temp register. 2161*61768Sbostic operands[5] is a temp register. 2162*61768Sbostic ... 2163*61768Sbostic operands[3+num_regs] is the last temp register. 2164*61768Sbostic 2165*61768Sbostic The block move type can be one of the following: 2166*61768Sbostic BLOCK_MOVE_NORMAL Do all of the block move. 2167*61768Sbostic BLOCK_MOVE_NOT_LAST Do all but the last store. 2168*61768Sbostic BLOCK_MOVE_LAST Do just the last store. */ 2169*61768Sbostic 2170*61768Sbostic char * 2171*61768Sbostic output_block_move (insn, operands, num_regs, move_type) 2172*61768Sbostic rtx insn; 2173*61768Sbostic rtx operands[]; 2174*61768Sbostic int num_regs; 2175*61768Sbostic enum block_move_type move_type; 2176*61768Sbostic { 2177*61768Sbostic rtx dest_reg = XEXP (operands[0], 0); 2178*61768Sbostic rtx src_reg = XEXP (operands[1], 0); 2179*61768Sbostic int bytes = INTVAL (operands[2]); 2180*61768Sbostic int align = INTVAL (operands[3]); 2181*61768Sbostic int num = 0; 2182*61768Sbostic int offset = 0; 2183*61768Sbostic int use_lwl_lwr = FALSE; 2184*61768Sbostic int last_operand = num_regs+4; 2185*61768Sbostic int i; 2186*61768Sbostic rtx xoperands[10]; 2187*61768Sbostic 2188*61768Sbostic struct { 2189*61768Sbostic char *load; /* load insn without nop */ 2190*61768Sbostic char *load_nop; /* load insn with trailing nop */ 2191*61768Sbostic char *store; /* store insn */ 2192*61768Sbostic char *final; /* if last_store used: NULL or swr */ 2193*61768Sbostic char *last_store; /* last store instruction */ 2194*61768Sbostic int offset; /* current offset */ 2195*61768Sbostic enum machine_mode mode; /* mode to use on (MEM) */ 2196*61768Sbostic } load_store[4]; 2197*61768Sbostic 2198*61768Sbostic /* Detect a bug in GCC, where it can give us a register 2199*61768Sbostic the same as one of the addressing registers. */ 2200*61768Sbostic for (i = 4; i < last_operand; i++) 2201*61768Sbostic { 2202*61768Sbostic if (reg_mentioned_p (operands[i], operands[0]) 2203*61768Sbostic || reg_mentioned_p (operands[i], operands[1])) 2204*61768Sbostic { 2205*61768Sbostic abort_with_insn (insn, "register passed as address and temp register to block move"); 2206*61768Sbostic } 2207*61768Sbostic } 2208*61768Sbostic 2209*61768Sbostic /* If we are given global or static addresses, and we would be 2210*61768Sbostic emitting a few instructions, try to save time by using a 2211*61768Sbostic temporary register for the pointer. */ 2212*61768Sbostic if (bytes > 2*align || move_type != BLOCK_MOVE_NORMAL) 2213*61768Sbostic { 2214*61768Sbostic if (CONSTANT_P (src_reg)) 2215*61768Sbostic { 2216*61768Sbostic if (TARGET_STATS) 2217*61768Sbostic mips_count_memory_refs (operands[1], 1); 2218*61768Sbostic 2219*61768Sbostic src_reg = operands[ 3 + num_regs-- ]; 2220*61768Sbostic if (move_type != BLOCK_MOVE_LAST) 2221*61768Sbostic { 2222*61768Sbostic xoperands[1] = operands[1]; 2223*61768Sbostic xoperands[0] = src_reg; 2224*61768Sbostic output_asm_insn ("la\t%0,%1", xoperands); 2225*61768Sbostic } 2226*61768Sbostic } 2227*61768Sbostic 2228*61768Sbostic if (CONSTANT_P (dest_reg)) 2229*61768Sbostic { 2230*61768Sbostic if (TARGET_STATS) 2231*61768Sbostic mips_count_memory_refs (operands[0], 1); 2232*61768Sbostic 2233*61768Sbostic dest_reg = operands[ 3 + num_regs-- ]; 2234*61768Sbostic if (move_type != BLOCK_MOVE_LAST) 2235*61768Sbostic { 2236*61768Sbostic xoperands[1] = operands[0]; 2237*61768Sbostic xoperands[0] = dest_reg; 2238*61768Sbostic output_asm_insn ("la\t%0,%1", xoperands); 2239*61768Sbostic } 2240*61768Sbostic } 2241*61768Sbostic } 2242*61768Sbostic 2243*61768Sbostic if (num_regs > (sizeof (load_store) / sizeof (load_store[0]))) 2244*61768Sbostic num_regs = (sizeof (load_store) / sizeof (load_store[0])); 2245*61768Sbostic 2246*61768Sbostic else if (num_regs < 1) 2247*61768Sbostic abort (); 2248*61768Sbostic 2249*61768Sbostic if (TARGET_GAS && move_type != BLOCK_MOVE_LAST && set_noreorder++ == 0) 2250*61768Sbostic output_asm_insn (".set\tnoreorder", operands); 2251*61768Sbostic 2252*61768Sbostic while (bytes > 0) 2253*61768Sbostic { 2254*61768Sbostic load_store[num].offset = offset; 2255*61768Sbostic 2256*61768Sbostic if (bytes >= UNITS_PER_WORD && align >= UNITS_PER_WORD) 2257*61768Sbostic { 2258*61768Sbostic load_store[num].load = "lw\t%0,%1"; 2259*61768Sbostic load_store[num].load_nop = "lw\t%0,%1%#"; 2260*61768Sbostic load_store[num].store = "sw\t%0,%1"; 2261*61768Sbostic load_store[num].last_store = "sw\t%0,%1"; 2262*61768Sbostic load_store[num].final = (char *)0; 2263*61768Sbostic load_store[num].mode = SImode; 2264*61768Sbostic offset += UNITS_PER_WORD; 2265*61768Sbostic bytes -= UNITS_PER_WORD; 2266*61768Sbostic } 2267*61768Sbostic 2268*61768Sbostic else if (bytes >= UNITS_PER_WORD) 2269*61768Sbostic { 2270*61768Sbostic #if BYTES_BIG_ENDIAN 2271*61768Sbostic load_store[num].load = "lwl\t%0,%1\n\tlwr\t%0,%2"; 2272*61768Sbostic load_store[num].load_nop = "lwl\t%0,%1\n\tlwr\t%0,%2%#"; 2273*61768Sbostic load_store[num].store = "swl\t%0,%1\n\tswr\t%0,%2"; 2274*61768Sbostic load_store[num].last_store = "swr\t%0,%2"; 2275*61768Sbostic load_store[num].final = "swl\t%0,%1"; 2276*61768Sbostic #else 2277*61768Sbostic load_store[num].load = "lwl\t%0,%2\n\tlwr\t%0,%1"; 2278*61768Sbostic load_store[num].load_nop = "lwl\t%0,%2\n\tlwr\t%0,%1%#"; 2279*61768Sbostic load_store[num].store = "swl\t%0,%2\n\tswr\t%0,%1"; 2280*61768Sbostic load_store[num].last_store = "swr\t%0,%1"; 2281*61768Sbostic load_store[num].final = "swl\t%0,%2"; 2282*61768Sbostic #endif 2283*61768Sbostic load_store[num].mode = SImode; 2284*61768Sbostic offset += UNITS_PER_WORD; 2285*61768Sbostic bytes -= UNITS_PER_WORD; 2286*61768Sbostic use_lwl_lwr = TRUE; 2287*61768Sbostic } 2288*61768Sbostic 2289*61768Sbostic else if (bytes >= UNITS_PER_SHORT && align >= UNITS_PER_SHORT) 2290*61768Sbostic { 2291*61768Sbostic load_store[num].load = "lh\t%0,%1"; 2292*61768Sbostic load_store[num].load_nop = "lh\t%0,%1%#"; 2293*61768Sbostic load_store[num].store = "sh\t%0,%1"; 2294*61768Sbostic load_store[num].last_store = "sh\t%0,%1"; 2295*61768Sbostic load_store[num].final = (char *)0; 2296*61768Sbostic load_store[num].offset = offset; 2297*61768Sbostic load_store[num].mode = HImode; 2298*61768Sbostic offset += UNITS_PER_SHORT; 2299*61768Sbostic bytes -= UNITS_PER_SHORT; 2300*61768Sbostic } 2301*61768Sbostic 2302*61768Sbostic else 2303*61768Sbostic { 2304*61768Sbostic load_store[num].load = "lb\t%0,%1"; 2305*61768Sbostic load_store[num].load_nop = "lb\t%0,%1%#"; 2306*61768Sbostic load_store[num].store = "sb\t%0,%1"; 2307*61768Sbostic load_store[num].last_store = "sb\t%0,%1"; 2308*61768Sbostic load_store[num].final = (char *)0; 2309*61768Sbostic load_store[num].mode = QImode; 2310*61768Sbostic offset++; 2311*61768Sbostic bytes--; 2312*61768Sbostic } 2313*61768Sbostic 2314*61768Sbostic if (TARGET_STATS && move_type != BLOCK_MOVE_LAST) 2315*61768Sbostic { 2316*61768Sbostic dslots_load_total++; 2317*61768Sbostic dslots_load_filled++; 2318*61768Sbostic 2319*61768Sbostic if (CONSTANT_P (src_reg)) 2320*61768Sbostic mips_count_memory_refs (src_reg, 1); 2321*61768Sbostic 2322*61768Sbostic if (CONSTANT_P (dest_reg)) 2323*61768Sbostic mips_count_memory_refs (dest_reg, 1); 2324*61768Sbostic } 2325*61768Sbostic 2326*61768Sbostic /* Emit load/stores now if we have run out of registers or are 2327*61768Sbostic at the end of the move. */ 2328*61768Sbostic 2329*61768Sbostic if (++num == num_regs || bytes == 0) 2330*61768Sbostic { 2331*61768Sbostic /* If only load/store, we need a NOP after the load. */ 2332*61768Sbostic if (num == 1) 2333*61768Sbostic { 2334*61768Sbostic load_store[0].load = load_store[0].load_nop; 2335*61768Sbostic if (TARGET_STATS && move_type != BLOCK_MOVE_LAST) 2336*61768Sbostic dslots_load_filled--; 2337*61768Sbostic } 2338*61768Sbostic 2339*61768Sbostic if (move_type != BLOCK_MOVE_LAST) 2340*61768Sbostic { 2341*61768Sbostic for (i = 0; i < num; i++) 2342*61768Sbostic { 2343*61768Sbostic int offset; 2344*61768Sbostic 2345*61768Sbostic if (!operands[i+4]) 2346*61768Sbostic abort (); 2347*61768Sbostic 2348*61768Sbostic if (GET_MODE (operands[i+4]) != load_store[i].mode) 2349*61768Sbostic operands[i+4] = gen_rtx (REG, load_store[i].mode, REGNO (operands[i+4])); 2350*61768Sbostic 2351*61768Sbostic offset = load_store[i].offset; 2352*61768Sbostic xoperands[0] = operands[i+4]; 2353*61768Sbostic xoperands[1] = gen_rtx (MEM, load_store[i].mode, 2354*61768Sbostic plus_constant (src_reg, offset)); 2355*61768Sbostic 2356*61768Sbostic if (use_lwl_lwr) 2357*61768Sbostic xoperands[2] = gen_rtx (MEM, load_store[i].mode, 2358*61768Sbostic plus_constant (src_reg, UNITS_PER_WORD-1+offset)); 2359*61768Sbostic 2360*61768Sbostic output_asm_insn (load_store[i].load, xoperands); 2361*61768Sbostic } 2362*61768Sbostic } 2363*61768Sbostic 2364*61768Sbostic for (i = 0; i < num; i++) 2365*61768Sbostic { 2366*61768Sbostic int last_p = (i == num-1 && bytes == 0); 2367*61768Sbostic int offset = load_store[i].offset; 2368*61768Sbostic 2369*61768Sbostic xoperands[0] = operands[i+4]; 2370*61768Sbostic xoperands[1] = gen_rtx (MEM, load_store[i].mode, 2371*61768Sbostic plus_constant (dest_reg, offset)); 2372*61768Sbostic 2373*61768Sbostic 2374*61768Sbostic if (use_lwl_lwr) 2375*61768Sbostic xoperands[2] = gen_rtx (MEM, load_store[i].mode, 2376*61768Sbostic plus_constant (dest_reg, UNITS_PER_WORD-1+offset)); 2377*61768Sbostic 2378*61768Sbostic if (move_type == BLOCK_MOVE_NORMAL) 2379*61768Sbostic output_asm_insn (load_store[i].store, xoperands); 2380*61768Sbostic 2381*61768Sbostic else if (move_type == BLOCK_MOVE_NOT_LAST) 2382*61768Sbostic { 2383*61768Sbostic if (!last_p) 2384*61768Sbostic output_asm_insn (load_store[i].store, xoperands); 2385*61768Sbostic 2386*61768Sbostic else if (load_store[i].final != (char *)0) 2387*61768Sbostic output_asm_insn (load_store[i].final, xoperands); 2388*61768Sbostic } 2389*61768Sbostic 2390*61768Sbostic else if (last_p) 2391*61768Sbostic output_asm_insn (load_store[i].last_store, xoperands); 2392*61768Sbostic } 2393*61768Sbostic 2394*61768Sbostic num = 0; /* reset load_store */ 2395*61768Sbostic use_lwl_lwr = FALSE; /* reset whether or not we used lwl/lwr */ 2396*61768Sbostic } 2397*61768Sbostic } 2398*61768Sbostic 2399*61768Sbostic if (TARGET_GAS && move_type != BLOCK_MOVE_LAST && --set_noreorder == 0) 2400*61768Sbostic output_asm_insn (".set\treorder", operands); 2401*61768Sbostic 2402*61768Sbostic return ""; 2403*61768Sbostic } 2404*61768Sbostic 2405*61768Sbostic 2406*61768Sbostic /* Argument support functions. */ 2407*61768Sbostic 2408*61768Sbostic /* Initialize CUMULATIVE_ARGS for a function. */ 2409*61768Sbostic 2410*61768Sbostic void 2411*61768Sbostic init_cumulative_args (cum, fntype, libname) 2412*61768Sbostic CUMULATIVE_ARGS *cum; /* argument info to initialize */ 2413*61768Sbostic tree fntype; /* tree ptr for function decl */ 2414*61768Sbostic rtx libname; /* SYMBOL_REF of library name or 0 */ 2415*61768Sbostic { 2416*61768Sbostic static CUMULATIVE_ARGS zero_cum; 2417*61768Sbostic tree param, next_param; 2418*61768Sbostic 2419*61768Sbostic if (TARGET_DEBUG_E_MODE) 2420*61768Sbostic { 2421*61768Sbostic fprintf (stderr, "\ninit_cumulative_args, fntype = 0x%.8lx", (long)fntype); 2422*61768Sbostic if (!fntype) 2423*61768Sbostic fputc ('\n', stderr); 2424*61768Sbostic 2425*61768Sbostic else 2426*61768Sbostic { 2427*61768Sbostic tree ret_type = TREE_TYPE (fntype); 2428*61768Sbostic fprintf (stderr, ", fntype code = %s, ret code = %s\n", 2429*61768Sbostic tree_code_name[ (int)TREE_CODE (fntype) ], 2430*61768Sbostic tree_code_name[ (int)TREE_CODE (ret_type) ]); 2431*61768Sbostic } 2432*61768Sbostic } 2433*61768Sbostic 2434*61768Sbostic *cum = zero_cum; 2435*61768Sbostic 2436*61768Sbostic /* Determine if this function has variable arguments. This is 2437*61768Sbostic indicated by the last argument being 'void_type_mode' if there 2438*61768Sbostic are no variable arguments. The standard MIPS calling sequence 2439*61768Sbostic passes all arguments in the general purpose registers in this 2440*61768Sbostic case. */ 2441*61768Sbostic 2442*61768Sbostic for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0; 2443*61768Sbostic param != (tree)0; 2444*61768Sbostic param = next_param) 2445*61768Sbostic { 2446*61768Sbostic next_param = TREE_CHAIN (param); 2447*61768Sbostic if (next_param == (tree)0 && TREE_VALUE (param) != void_type_node) 2448*61768Sbostic cum->gp_reg_found = 1; 2449*61768Sbostic } 2450*61768Sbostic } 2451*61768Sbostic 2452*61768Sbostic /* Advance the argument to the next argument position. */ 2453*61768Sbostic 2454*61768Sbostic void 2455*61768Sbostic function_arg_advance (cum, mode, type, named) 2456*61768Sbostic CUMULATIVE_ARGS *cum; /* current arg information */ 2457*61768Sbostic enum machine_mode mode; /* current arg mode */ 2458*61768Sbostic tree type; /* type of the argument or 0 if lib support */ 2459*61768Sbostic int named; /* whether or not the argument was named */ 2460*61768Sbostic { 2461*61768Sbostic if (TARGET_DEBUG_E_MODE) 2462*61768Sbostic fprintf (stderr, 2463*61768Sbostic "function_adv( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d )\n\n", 2464*61768Sbostic cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode), 2465*61768Sbostic type, named); 2466*61768Sbostic 2467*61768Sbostic cum->arg_number++; 2468*61768Sbostic switch (mode) 2469*61768Sbostic { 2470*61768Sbostic default: 2471*61768Sbostic error ("Illegal mode given to function_arg_advance"); 2472*61768Sbostic break; 2473*61768Sbostic 2474*61768Sbostic case VOIDmode: 2475*61768Sbostic break; 2476*61768Sbostic 2477*61768Sbostic case BLKmode: 2478*61768Sbostic cum->gp_reg_found = 1; 2479*61768Sbostic cum->arg_words += (int_size_in_bytes (type) + 3) / 4; 2480*61768Sbostic break; 2481*61768Sbostic 2482*61768Sbostic case SFmode: 2483*61768Sbostic cum->arg_words++; 2484*61768Sbostic break; 2485*61768Sbostic 2486*61768Sbostic case DFmode: 2487*61768Sbostic cum->arg_words += 2; 2488*61768Sbostic break; 2489*61768Sbostic 2490*61768Sbostic case DImode: 2491*61768Sbostic cum->gp_reg_found = 1; 2492*61768Sbostic cum->arg_words += 2; 2493*61768Sbostic break; 2494*61768Sbostic 2495*61768Sbostic case QImode: 2496*61768Sbostic case HImode: 2497*61768Sbostic case SImode: 2498*61768Sbostic cum->gp_reg_found = 1; 2499*61768Sbostic cum->arg_words++; 2500*61768Sbostic break; 2501*61768Sbostic } 2502*61768Sbostic } 2503*61768Sbostic 2504*61768Sbostic /* Return a RTL expression containing the register for the given mode, 2505*61768Sbostic or 0 if the argument is too be passed on the stack. */ 2506*61768Sbostic 2507*61768Sbostic struct rtx_def * 2508*61768Sbostic function_arg (cum, mode, type, named) 2509*61768Sbostic CUMULATIVE_ARGS *cum; /* current arg information */ 2510*61768Sbostic enum machine_mode mode; /* current arg mode */ 2511*61768Sbostic tree type; /* type of the argument or 0 if lib support */ 2512*61768Sbostic int named; /* != 0 for normal args, == 0 for ... args */ 2513*61768Sbostic { 2514*61768Sbostic rtx ret; 2515*61768Sbostic int regbase = -1; 2516*61768Sbostic int bias = 0; 2517*61768Sbostic int struct_p = ((type != (tree)0) 2518*61768Sbostic && (TREE_CODE (type) == RECORD_TYPE 2519*61768Sbostic || TREE_CODE (type) == UNION_TYPE)); 2520*61768Sbostic 2521*61768Sbostic if (TARGET_DEBUG_E_MODE) 2522*61768Sbostic fprintf (stderr, 2523*61768Sbostic "function_arg( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d ) = ", 2524*61768Sbostic cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode), 2525*61768Sbostic type, named); 2526*61768Sbostic 2527*61768Sbostic switch (mode) 2528*61768Sbostic { 2529*61768Sbostic default: 2530*61768Sbostic error ("Illegal mode given to function_arg"); 2531*61768Sbostic break; 2532*61768Sbostic 2533*61768Sbostic case SFmode: 2534*61768Sbostic if (cum->gp_reg_found || cum->arg_number >= 2) 2535*61768Sbostic regbase = GP_ARG_FIRST; 2536*61768Sbostic else { 2537*61768Sbostic regbase = (TARGET_SOFT_FLOAT) ? GP_ARG_FIRST : FP_ARG_FIRST; 2538*61768Sbostic if (cum->arg_words == 1) /* first arg was float */ 2539*61768Sbostic bias = 1; /* use correct reg */ 2540*61768Sbostic } 2541*61768Sbostic 2542*61768Sbostic break; 2543*61768Sbostic 2544*61768Sbostic case DFmode: 2545*61768Sbostic cum->arg_words += (cum->arg_words & 1); 2546*61768Sbostic regbase = (cum->gp_reg_found || TARGET_SOFT_FLOAT) 2547*61768Sbostic ? GP_ARG_FIRST 2548*61768Sbostic : FP_ARG_FIRST; 2549*61768Sbostic break; 2550*61768Sbostic 2551*61768Sbostic case BLKmode: 2552*61768Sbostic if (type != (tree)0 && TYPE_ALIGN (type) > BITS_PER_WORD) 2553*61768Sbostic cum->arg_words += (cum->arg_words & 1); 2554*61768Sbostic 2555*61768Sbostic regbase = GP_ARG_FIRST; 2556*61768Sbostic break; 2557*61768Sbostic 2558*61768Sbostic case VOIDmode: 2559*61768Sbostic case QImode: 2560*61768Sbostic case HImode: 2561*61768Sbostic case SImode: 2562*61768Sbostic regbase = GP_ARG_FIRST; 2563*61768Sbostic break; 2564*61768Sbostic 2565*61768Sbostic case DImode: 2566*61768Sbostic cum->arg_words += (cum->arg_words & 1); 2567*61768Sbostic regbase = GP_ARG_FIRST; 2568*61768Sbostic } 2569*61768Sbostic 2570*61768Sbostic if (cum->arg_words >= MAX_ARGS_IN_REGISTERS) 2571*61768Sbostic { 2572*61768Sbostic if (TARGET_DEBUG_E_MODE) 2573*61768Sbostic fprintf (stderr, "<stack>%s\n", struct_p ? ", [struct]" : ""); 2574*61768Sbostic 2575*61768Sbostic ret = (rtx)0; 2576*61768Sbostic } 2577*61768Sbostic else 2578*61768Sbostic { 2579*61768Sbostic if (regbase == -1) 2580*61768Sbostic abort (); 2581*61768Sbostic 2582*61768Sbostic ret = gen_rtx (REG, mode, regbase + cum->arg_words + bias); 2583*61768Sbostic 2584*61768Sbostic if (TARGET_DEBUG_E_MODE) 2585*61768Sbostic fprintf (stderr, "%s%s\n", reg_names[regbase + cum->arg_words + bias], 2586*61768Sbostic struct_p ? ", [struct]" : ""); 2587*61768Sbostic 2588*61768Sbostic /* The following is a hack in order to pass 1 byte structures 2589*61768Sbostic the same way that the MIPS compiler does (namely by passing 2590*61768Sbostic the structure in the high byte or half word of the register). 2591*61768Sbostic This also makes varargs work. If we have such a structure, 2592*61768Sbostic we save the adjustment RTL, and the call define expands will 2593*61768Sbostic emit them. For the VOIDmode argument (argument after the 2594*61768Sbostic last real argument, pass back a parallel vector holding each 2595*61768Sbostic of the adjustments. */ 2596*61768Sbostic 2597*61768Sbostic if (struct_p && (mode == QImode || mode == HImode)) 2598*61768Sbostic { 2599*61768Sbostic rtx amount = GEN_INT (BITS_PER_WORD - GET_MODE_BITSIZE (mode)); 2600*61768Sbostic rtx reg = gen_rtx (REG, SImode, regbase + cum->arg_words + bias); 2601*61768Sbostic cum->adjust[ cum->num_adjusts++ ] = gen_ashlsi3 (reg, reg, amount); 2602*61768Sbostic } 2603*61768Sbostic } 2604*61768Sbostic 2605*61768Sbostic if (mode == VOIDmode && cum->num_adjusts > 0) 2606*61768Sbostic ret = gen_rtx (PARALLEL, VOIDmode, gen_rtvec_v (cum->num_adjusts, cum->adjust)); 2607*61768Sbostic 2608*61768Sbostic return ret; 2609*61768Sbostic } 2610*61768Sbostic 2611*61768Sbostic 2612*61768Sbostic int 2613*61768Sbostic function_arg_partial_nregs (cum, mode, type, named) 2614*61768Sbostic CUMULATIVE_ARGS *cum; /* current arg information */ 2615*61768Sbostic enum machine_mode mode; /* current arg mode */ 2616*61768Sbostic tree type; /* type of the argument or 0 if lib support */ 2617*61768Sbostic int named; /* != 0 for normal args, == 0 for ... args */ 2618*61768Sbostic { 2619*61768Sbostic if (mode == BLKmode && cum->arg_words < MAX_ARGS_IN_REGISTERS) 2620*61768Sbostic { 2621*61768Sbostic int words = (int_size_in_bytes (type) + 3) / 4; 2622*61768Sbostic 2623*61768Sbostic if (words + cum->arg_words < MAX_ARGS_IN_REGISTERS) 2624*61768Sbostic return 0; /* structure fits in registers */ 2625*61768Sbostic 2626*61768Sbostic if (TARGET_DEBUG_E_MODE) 2627*61768Sbostic fprintf (stderr, "function_arg_partial_nregs = %d\n", 2628*61768Sbostic MAX_ARGS_IN_REGISTERS - cum->arg_words); 2629*61768Sbostic 2630*61768Sbostic return MAX_ARGS_IN_REGISTERS - cum->arg_words; 2631*61768Sbostic } 2632*61768Sbostic 2633*61768Sbostic else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS-1) 2634*61768Sbostic { 2635*61768Sbostic if (TARGET_DEBUG_E_MODE) 2636*61768Sbostic fprintf (stderr, "function_arg_partial_nregs = 1\n"); 2637*61768Sbostic 2638*61768Sbostic return 1; 2639*61768Sbostic } 2640*61768Sbostic 2641*61768Sbostic return 0; 2642*61768Sbostic } 2643*61768Sbostic 2644*61768Sbostic 2645*61768Sbostic /* Print the options used in the assembly file. */ 2646*61768Sbostic 2647*61768Sbostic static struct {char *name; int value;} target_switches [] 2648*61768Sbostic = TARGET_SWITCHES; 2649*61768Sbostic 2650*61768Sbostic void 2651*61768Sbostic print_options (out) 2652*61768Sbostic FILE *out; 2653*61768Sbostic { 2654*61768Sbostic int line_len; 2655*61768Sbostic int len; 2656*61768Sbostic int j; 2657*61768Sbostic char **p; 2658*61768Sbostic int mask = TARGET_DEFAULT; 2659*61768Sbostic 2660*61768Sbostic /* Allow assembly language comparisons with -mdebug eliminating the 2661*61768Sbostic compiler version number and switch lists. */ 2662*61768Sbostic 2663*61768Sbostic if (TARGET_DEBUG_MODE) 2664*61768Sbostic return; 2665*61768Sbostic 2666*61768Sbostic fprintf (out, "\n # %s %s", language_string, version_string); 2667*61768Sbostic #ifdef TARGET_VERSION_INTERNAL 2668*61768Sbostic TARGET_VERSION_INTERNAL (out); 2669*61768Sbostic #endif 2670*61768Sbostic #ifdef __GNUC__ 2671*61768Sbostic fprintf (out, " compiled by GNU C\n\n"); 2672*61768Sbostic #else 2673*61768Sbostic fprintf (out, " compiled by CC\n\n"); 2674*61768Sbostic #endif 2675*61768Sbostic 2676*61768Sbostic fprintf (out, " # Cc1 defaults:"); 2677*61768Sbostic line_len = 32767; 2678*61768Sbostic for (j = 0; j < sizeof target_switches / sizeof target_switches[0]; j++) 2679*61768Sbostic { 2680*61768Sbostic if (target_switches[j].name[0] != '\0' 2681*61768Sbostic && target_switches[j].value > 0 2682*61768Sbostic && (target_switches[j].value & mask) == target_switches[j].value) 2683*61768Sbostic { 2684*61768Sbostic mask &= ~ target_switches[j].value; 2685*61768Sbostic len = strlen (target_switches[j].name) + 1; 2686*61768Sbostic if (len + line_len > 79) 2687*61768Sbostic { 2688*61768Sbostic line_len = 2; 2689*61768Sbostic fputs ("\n #", out); 2690*61768Sbostic } 2691*61768Sbostic fprintf (out, " -m%s", target_switches[j].name); 2692*61768Sbostic line_len += len; 2693*61768Sbostic } 2694*61768Sbostic } 2695*61768Sbostic 2696*61768Sbostic fprintf (out, "\n\n # Cc1 arguments (-G value = %d, Cpu = %s, ISA = %d):", 2697*61768Sbostic mips_section_threshold, mips_cpu_string, mips_isa); 2698*61768Sbostic 2699*61768Sbostic line_len = 32767; 2700*61768Sbostic for (p = &save_argv[1]; *p != (char *)0; p++) 2701*61768Sbostic { 2702*61768Sbostic char *arg = *p; 2703*61768Sbostic if (*arg == '-') 2704*61768Sbostic { 2705*61768Sbostic len = strlen (arg) + 1; 2706*61768Sbostic if (len + line_len > 79) 2707*61768Sbostic { 2708*61768Sbostic line_len = 2; 2709*61768Sbostic fputs ("\n #", out); 2710*61768Sbostic } 2711*61768Sbostic fprintf (out, " %s", *p); 2712*61768Sbostic line_len += len; 2713*61768Sbostic } 2714*61768Sbostic } 2715*61768Sbostic 2716*61768Sbostic fputs ("\n\n", out); 2717*61768Sbostic } 2718*61768Sbostic 2719*61768Sbostic 2720*61768Sbostic /* Abort after printing out a specific insn. */ 2721*61768Sbostic 2722*61768Sbostic void 2723*61768Sbostic abort_with_insn (insn, reason) 2724*61768Sbostic rtx insn; 2725*61768Sbostic char *reason; 2726*61768Sbostic { 2727*61768Sbostic error (reason); 2728*61768Sbostic debug_rtx (insn); 2729*61768Sbostic abort (); 2730*61768Sbostic } 2731*61768Sbostic 2732*61768Sbostic /* Write a message to stderr (for use in macros expanded in files that do not 2733*61768Sbostic include stdio.h). */ 2734*61768Sbostic 2735*61768Sbostic void 2736*61768Sbostic trace (s, s1, s2) 2737*61768Sbostic char *s, *s1, *s2; 2738*61768Sbostic { 2739*61768Sbostic fprintf (stderr, s, s1, s2); 2740*61768Sbostic } 2741*61768Sbostic 2742*61768Sbostic 2743*61768Sbostic #ifdef SIGINFO 2744*61768Sbostic 2745*61768Sbostic static void 2746*61768Sbostic siginfo (signo) 2747*61768Sbostic int signo; 2748*61768Sbostic { 2749*61768Sbostic fprintf (stderr, "compiling '%s' in '%s'\n", 2750*61768Sbostic (current_function_name != (char *)0) ? current_function_name : "<toplevel>", 2751*61768Sbostic (current_function_file != (char *)0) ? current_function_file : "<no file>"); 2752*61768Sbostic fflush (stderr); 2753*61768Sbostic } 2754*61768Sbostic #endif /* SIGINFO */ 2755*61768Sbostic 2756*61768Sbostic 2757*61768Sbostic /* Set up the threshold for data to go into the small data area, instead 2758*61768Sbostic of the normal data area, and detect any conflicts in the switches. */ 2759*61768Sbostic 2760*61768Sbostic void 2761*61768Sbostic override_options () 2762*61768Sbostic { 2763*61768Sbostic register int i, start; 2764*61768Sbostic register int regno; 2765*61768Sbostic register enum machine_mode mode; 2766*61768Sbostic 2767*61768Sbostic if (g_switch_set) 2768*61768Sbostic mips_section_threshold = g_switch_value; 2769*61768Sbostic 2770*61768Sbostic else 2771*61768Sbostic mips_section_threshold = (TARGET_MIPS_AS) ? 8 : 0; 2772*61768Sbostic 2773*61768Sbostic /* Identify the processor type */ 2774*61768Sbostic if (mips_cpu_string == (char *)0 2775*61768Sbostic || !strcmp (mips_cpu_string, "default") 2776*61768Sbostic || !strcmp (mips_cpu_string, "DEFAULT")) 2777*61768Sbostic { 2778*61768Sbostic mips_cpu_string = "default"; 2779*61768Sbostic mips_cpu = PROCESSOR_DEFAULT; 2780*61768Sbostic } 2781*61768Sbostic 2782*61768Sbostic else 2783*61768Sbostic { 2784*61768Sbostic char *p = mips_cpu_string; 2785*61768Sbostic 2786*61768Sbostic if (*p == 'r' || *p == 'R') 2787*61768Sbostic p++; 2788*61768Sbostic 2789*61768Sbostic /* Since there is no difference between a R2000 and R3000 in 2790*61768Sbostic terms of the scheduler, we collapse them into just an R3000. */ 2791*61768Sbostic 2792*61768Sbostic mips_cpu = PROCESSOR_DEFAULT; 2793*61768Sbostic switch (*p) 2794*61768Sbostic { 2795*61768Sbostic case '2': 2796*61768Sbostic if (!strcmp (p, "2000") || !strcmp (p, "2k") || !strcmp (p, "2K")) 2797*61768Sbostic mips_cpu = PROCESSOR_R3000; 2798*61768Sbostic break; 2799*61768Sbostic 2800*61768Sbostic case '3': 2801*61768Sbostic if (!strcmp (p, "3000") || !strcmp (p, "3k") || !strcmp (p, "3K")) 2802*61768Sbostic mips_cpu = PROCESSOR_R3000; 2803*61768Sbostic break; 2804*61768Sbostic 2805*61768Sbostic case '4': 2806*61768Sbostic if (!strcmp (p, "4000") || !strcmp (p, "4k") || !strcmp (p, "4K")) 2807*61768Sbostic mips_cpu = PROCESSOR_R4000; 2808*61768Sbostic break; 2809*61768Sbostic 2810*61768Sbostic case '6': 2811*61768Sbostic if (!strcmp (p, "6000") || !strcmp (p, "6k") || !strcmp (p, "6K")) 2812*61768Sbostic mips_cpu = PROCESSOR_R6000; 2813*61768Sbostic break; 2814*61768Sbostic } 2815*61768Sbostic 2816*61768Sbostic if (mips_cpu == PROCESSOR_DEFAULT) 2817*61768Sbostic { 2818*61768Sbostic error ("bad value (%s) for -mcpu= switch", mips_cpu_string); 2819*61768Sbostic mips_cpu_string = "default"; 2820*61768Sbostic } 2821*61768Sbostic } 2822*61768Sbostic 2823*61768Sbostic /* Now get the architectural level. */ 2824*61768Sbostic if (mips_isa_string == (char *)0) 2825*61768Sbostic mips_isa = 1; 2826*61768Sbostic 2827*61768Sbostic else if (isdigit (*mips_isa_string)) 2828*61768Sbostic mips_isa = atoi (mips_isa_string); 2829*61768Sbostic 2830*61768Sbostic else 2831*61768Sbostic { 2832*61768Sbostic error ("bad value (%s) for -mips switch", mips_isa_string); 2833*61768Sbostic mips_isa = 1; 2834*61768Sbostic } 2835*61768Sbostic 2836*61768Sbostic if (mips_isa < 0 || mips_isa > 3) 2837*61768Sbostic error ("-mips%d not supported", mips_isa); 2838*61768Sbostic 2839*61768Sbostic else if (mips_isa > 1 2840*61768Sbostic && (mips_cpu == PROCESSOR_DEFAULT || mips_cpu == PROCESSOR_R3000)) 2841*61768Sbostic error ("-mcpu=%s does not support -mips%d", mips_cpu_string, mips_isa); 2842*61768Sbostic 2843*61768Sbostic else if (mips_cpu == PROCESSOR_R6000 && mips_isa > 2) 2844*61768Sbostic error ("-mcpu=%s does not support -mips%d", mips_cpu_string, mips_isa); 2845*61768Sbostic 2846*61768Sbostic /* make sure sizes of ints/longs/etc. are ok */ 2847*61768Sbostic if (mips_isa < 3) 2848*61768Sbostic { 2849*61768Sbostic if (TARGET_INT64) 2850*61768Sbostic fatal ("Only the r4000 can support 64 bit ints"); 2851*61768Sbostic 2852*61768Sbostic else if (TARGET_LONG64) 2853*61768Sbostic fatal ("Only the r4000 can support 64 bit longs"); 2854*61768Sbostic 2855*61768Sbostic else if (TARGET_LLONG128) 2856*61768Sbostic fatal ("Only the r4000 can support 128 bit long longs"); 2857*61768Sbostic 2858*61768Sbostic else if (TARGET_FLOAT64) 2859*61768Sbostic fatal ("Only the r4000 can support 64 bit fp registers"); 2860*61768Sbostic } 2861*61768Sbostic else if (TARGET_INT64 || TARGET_LONG64 || TARGET_LLONG128 || TARGET_FLOAT64) 2862*61768Sbostic warning ("r4000 64/128 bit types not yet supported"); 2863*61768Sbostic 2864*61768Sbostic /* Tell halfpic.c that we have half-pic code if we do. */ 2865*61768Sbostic if (TARGET_HALF_PIC) 2866*61768Sbostic HALF_PIC_INIT (); 2867*61768Sbostic 2868*61768Sbostic /* -mrnames says to use the MIPS software convention for register 2869*61768Sbostic names instead of the hardware names (ie, a0 instead of $4). 2870*61768Sbostic We do this by switching the names in mips_reg_names, which the 2871*61768Sbostic reg_names points into via the REGISTER_NAMES macro. */ 2872*61768Sbostic 2873*61768Sbostic if (TARGET_NAME_REGS) 2874*61768Sbostic { 2875*61768Sbostic if (TARGET_GAS) 2876*61768Sbostic { 2877*61768Sbostic target_flags &= ~ MASK_NAME_REGS; 2878*61768Sbostic error ("Gas does not support the MIPS software register name convention."); 2879*61768Sbostic } 2880*61768Sbostic else 2881*61768Sbostic bcopy ((char *) mips_sw_reg_names, (char *) mips_reg_names, sizeof (mips_reg_names)); 2882*61768Sbostic } 2883*61768Sbostic 2884*61768Sbostic /* If this is OSF/1, set up a SIGINFO handler so we can see what function 2885*61768Sbostic is currently being compiled. */ 2886*61768Sbostic #ifdef SIGINFO 2887*61768Sbostic if (getenv ("GCC_SIGINFO") != (char *)0) 2888*61768Sbostic { 2889*61768Sbostic struct sigaction action; 2890*61768Sbostic action.sa_handler = siginfo; 2891*61768Sbostic action.sa_mask = 0; 2892*61768Sbostic action.sa_flags = SA_RESTART; 2893*61768Sbostic sigaction (SIGINFO, &action, (struct sigaction *)0); 2894*61768Sbostic } 2895*61768Sbostic #endif 2896*61768Sbostic 2897*61768Sbostic #if defined(_IOLBF) 2898*61768Sbostic #if defined(ultrix) || defined(__ultrix) || defined(__OSF1__) || defined(__osf__) || defined(osf) 2899*61768Sbostic /* If -mstats and -quiet, make stderr line buffered. */ 2900*61768Sbostic if (quiet_flag && TARGET_STATS) 2901*61768Sbostic setvbuf (stderr, (char *)0, _IOLBF, BUFSIZ); 2902*61768Sbostic #endif 2903*61768Sbostic #endif 2904*61768Sbostic 2905*61768Sbostic /* Set up the classification arrays now. */ 2906*61768Sbostic mips_rtx_classify[(int)PLUS] = CLASS_ADD_OP; 2907*61768Sbostic mips_rtx_classify[(int)MINUS] = CLASS_ADD_OP; 2908*61768Sbostic mips_rtx_classify[(int)DIV] = CLASS_DIVMOD_OP; 2909*61768Sbostic mips_rtx_classify[(int)MOD] = CLASS_DIVMOD_OP; 2910*61768Sbostic mips_rtx_classify[(int)UDIV] = CLASS_DIVMOD_OP | CLASS_UNSIGNED_OP; 2911*61768Sbostic mips_rtx_classify[(int)UMOD] = CLASS_DIVMOD_OP | CLASS_UNSIGNED_OP; 2912*61768Sbostic mips_rtx_classify[(int)EQ] = CLASS_CMP_OP | CLASS_EQUALITY_OP | CLASS_FCMP_OP; 2913*61768Sbostic mips_rtx_classify[(int)NE] = CLASS_CMP_OP | CLASS_EQUALITY_OP | CLASS_FCMP_OP; 2914*61768Sbostic mips_rtx_classify[(int)GT] = CLASS_CMP_OP | CLASS_FCMP_OP; 2915*61768Sbostic mips_rtx_classify[(int)GE] = CLASS_CMP_OP | CLASS_FCMP_OP; 2916*61768Sbostic mips_rtx_classify[(int)LT] = CLASS_CMP_OP | CLASS_FCMP_OP; 2917*61768Sbostic mips_rtx_classify[(int)LE] = CLASS_CMP_OP | CLASS_FCMP_OP; 2918*61768Sbostic mips_rtx_classify[(int)GTU] = CLASS_CMP_OP | CLASS_UNSIGNED_OP; 2919*61768Sbostic mips_rtx_classify[(int)GEU] = CLASS_CMP_OP | CLASS_UNSIGNED_OP; 2920*61768Sbostic mips_rtx_classify[(int)LTU] = CLASS_CMP_OP | CLASS_UNSIGNED_OP; 2921*61768Sbostic mips_rtx_classify[(int)LEU] = CLASS_CMP_OP | CLASS_UNSIGNED_OP; 2922*61768Sbostic 2923*61768Sbostic mips_print_operand_punct['?'] = TRUE; 2924*61768Sbostic mips_print_operand_punct['#'] = TRUE; 2925*61768Sbostic mips_print_operand_punct['&'] = TRUE; 2926*61768Sbostic mips_print_operand_punct['!'] = TRUE; 2927*61768Sbostic mips_print_operand_punct['*'] = TRUE; 2928*61768Sbostic mips_print_operand_punct['@'] = TRUE; 2929*61768Sbostic mips_print_operand_punct['.'] = TRUE; 2930*61768Sbostic mips_print_operand_punct['('] = TRUE; 2931*61768Sbostic mips_print_operand_punct[')'] = TRUE; 2932*61768Sbostic mips_print_operand_punct['['] = TRUE; 2933*61768Sbostic mips_print_operand_punct[']'] = TRUE; 2934*61768Sbostic mips_print_operand_punct['<'] = TRUE; 2935*61768Sbostic mips_print_operand_punct['>'] = TRUE; 2936*61768Sbostic mips_print_operand_punct['{'] = TRUE; 2937*61768Sbostic mips_print_operand_punct['}'] = TRUE; 2938*61768Sbostic 2939*61768Sbostic mips_char_to_class['d'] = GR_REGS; 2940*61768Sbostic mips_char_to_class['f'] = ((TARGET_HARD_FLOAT) ? FP_REGS : NO_REGS); 2941*61768Sbostic mips_char_to_class['h'] = HI_REG; 2942*61768Sbostic mips_char_to_class['l'] = LO_REG; 2943*61768Sbostic mips_char_to_class['x'] = MD_REGS; 2944*61768Sbostic mips_char_to_class['y'] = GR_REGS; 2945*61768Sbostic mips_char_to_class['z'] = ST_REGS; 2946*61768Sbostic 2947*61768Sbostic /* Set up array to map GCC register number to debug register number. 2948*61768Sbostic Ignore the special purpose register numbers. */ 2949*61768Sbostic 2950*61768Sbostic for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 2951*61768Sbostic mips_dbx_regno[i] = -1; 2952*61768Sbostic 2953*61768Sbostic start = GP_DBX_FIRST - GP_REG_FIRST; 2954*61768Sbostic for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++) 2955*61768Sbostic mips_dbx_regno[i] = i + start; 2956*61768Sbostic 2957*61768Sbostic start = FP_DBX_FIRST - FP_REG_FIRST; 2958*61768Sbostic for (i = FP_REG_FIRST; i <= FP_REG_LAST; i++) 2959*61768Sbostic mips_dbx_regno[i] = i + start; 2960*61768Sbostic 2961*61768Sbostic /* Set up array giving whether a given register can hold a given mode. 2962*61768Sbostic At present, restrict ints from being in FP registers, because reload 2963*61768Sbostic is a little enthusiastic about storing extra values in FP registers, 2964*61768Sbostic and this is not good for things like OS kernels. Also, due to the 2965*61768Sbostic mandatory delay, it is as fast to load from cached memory as to move 2966*61768Sbostic from the FP register. */ 2967*61768Sbostic 2968*61768Sbostic for (mode = VOIDmode; 2969*61768Sbostic mode != MAX_MACHINE_MODE; 2970*61768Sbostic mode = (enum machine_mode)((int)mode + 1)) 2971*61768Sbostic { 2972*61768Sbostic register int size = GET_MODE_SIZE (mode); 2973*61768Sbostic register enum mode_class class = GET_MODE_CLASS (mode); 2974*61768Sbostic 2975*61768Sbostic for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) 2976*61768Sbostic { 2977*61768Sbostic register int temp; 2978*61768Sbostic 2979*61768Sbostic if (mode == CC_FPmode || mode == CC_REV_FPmode) 2980*61768Sbostic temp = (regno == FPSW_REGNUM); 2981*61768Sbostic 2982*61768Sbostic else if (GP_REG_P (regno)) 2983*61768Sbostic temp = ((regno & 1) == 0 || (size <= UNITS_PER_WORD)); 2984*61768Sbostic 2985*61768Sbostic else if (FP_REG_P (regno)) 2986*61768Sbostic temp = ((TARGET_FLOAT64 || ((regno & 1) == 0)) 2987*61768Sbostic && (class == MODE_FLOAT 2988*61768Sbostic || class == MODE_COMPLEX_FLOAT 2989*61768Sbostic || (TARGET_DEBUG_H_MODE && class == MODE_INT))); 2990*61768Sbostic 2991*61768Sbostic else if (MD_REG_P (regno)) 2992*61768Sbostic temp = (mode == SImode || (regno == MD_REG_FIRST && mode == DImode)); 2993*61768Sbostic 2994*61768Sbostic else 2995*61768Sbostic temp = FALSE; 2996*61768Sbostic 2997*61768Sbostic mips_hard_regno_mode_ok[(int)mode][regno] = temp; 2998*61768Sbostic } 2999*61768Sbostic } 3000*61768Sbostic } 3001*61768Sbostic 3002*61768Sbostic 3003*61768Sbostic /* 3004*61768Sbostic * The MIPS debug format wants all automatic variables and arguments 3005*61768Sbostic * to be in terms of the virtual frame pointer (stack pointer before 3006*61768Sbostic * any adjustment in the function), while the MIPS 3.0 linker wants 3007*61768Sbostic * the frame pointer to be the stack pointer after the initial 3008*61768Sbostic * adjustment. So, we do the adjustment here. The arg pointer (which 3009*61768Sbostic * is eliminated) points to the virtual frame pointer, while the frame 3010*61768Sbostic * pointer (which may be eliminated) points to the stack pointer after 3011*61768Sbostic * the initial adjustments. 3012*61768Sbostic */ 3013*61768Sbostic 3014*61768Sbostic int 3015*61768Sbostic mips_debugger_offset (addr, offset) 3016*61768Sbostic rtx addr; 3017*61768Sbostic int offset; 3018*61768Sbostic { 3019*61768Sbostic rtx offset2 = const0_rtx; 3020*61768Sbostic rtx reg = eliminate_constant_term (addr, &offset2); 3021*61768Sbostic 3022*61768Sbostic if (!offset) 3023*61768Sbostic offset = INTVAL (offset2); 3024*61768Sbostic 3025*61768Sbostic if (reg == stack_pointer_rtx || reg == frame_pointer_rtx) 3026*61768Sbostic { 3027*61768Sbostic int frame_size = (!current_frame_info.initialized) 3028*61768Sbostic ? compute_frame_size (get_frame_size ()) 3029*61768Sbostic : current_frame_info.total_size; 3030*61768Sbostic 3031*61768Sbostic offset = offset - frame_size; 3032*61768Sbostic } 3033*61768Sbostic /* sdbout_parms does not want this to crash for unrecognized cases. */ 3034*61768Sbostic #if 0 3035*61768Sbostic else if (reg != arg_pointer_rtx) 3036*61768Sbostic abort_with_insn (addr, "mips_debugger_offset called with non stack/frame/arg pointer."); 3037*61768Sbostic #endif 3038*61768Sbostic 3039*61768Sbostic return offset; 3040*61768Sbostic } 3041*61768Sbostic 3042*61768Sbostic 3043*61768Sbostic /* A C compound statement to output to stdio stream STREAM the 3044*61768Sbostic assembler syntax for an instruction operand X. X is an RTL 3045*61768Sbostic expression. 3046*61768Sbostic 3047*61768Sbostic CODE is a value that can be used to specify one of several ways 3048*61768Sbostic of printing the operand. It is used when identical operands 3049*61768Sbostic must be printed differently depending on the context. CODE 3050*61768Sbostic comes from the `%' specification that was used to request 3051*61768Sbostic printing of the operand. If the specification was just `%DIGIT' 3052*61768Sbostic then CODE is 0; if the specification was `%LTR DIGIT' then CODE 3053*61768Sbostic is the ASCII code for LTR. 3054*61768Sbostic 3055*61768Sbostic If X is a register, this macro should print the register's name. 3056*61768Sbostic The names can be found in an array `reg_names' whose type is 3057*61768Sbostic `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'. 3058*61768Sbostic 3059*61768Sbostic When the machine description has a specification `%PUNCT' (a `%' 3060*61768Sbostic followed by a punctuation character), this macro is called with 3061*61768Sbostic a null pointer for X and the punctuation character for CODE. 3062*61768Sbostic 3063*61768Sbostic The MIPS specific codes are: 3064*61768Sbostic 3065*61768Sbostic 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x", 3066*61768Sbostic 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x", 3067*61768Sbostic 'd' output integer constant in decimal, 3068*61768Sbostic 'z' if the operand is 0, use $0 instead of normal operand. 3069*61768Sbostic 'D' print second register of double-word register operand. 3070*61768Sbostic 'L' print low-order register of double-word register operand. 3071*61768Sbostic 'M' print high-order register of double-word register operand. 3072*61768Sbostic 'C' print part of opcode for a branch condition. 3073*61768Sbostic 'N' print part of opcode for a branch condition, inverted. 3074*61768Sbostic '(' Turn on .set noreorder 3075*61768Sbostic ')' Turn on .set reorder 3076*61768Sbostic '[' Turn on .set noat 3077*61768Sbostic ']' Turn on .set at 3078*61768Sbostic '<' Turn on .set nomacro 3079*61768Sbostic '>' Turn on .set macro 3080*61768Sbostic '{' Turn on .set volatile (not GAS) 3081*61768Sbostic '}' Turn on .set novolatile (not GAS) 3082*61768Sbostic '&' Turn on .set noreorder if filling delay slots 3083*61768Sbostic '*' Turn on both .set noreorder and .set nomacro if filling delay slots 3084*61768Sbostic '!' Turn on .set nomacro if filling delay slots 3085*61768Sbostic '#' Print nop if in a .set noreorder section. 3086*61768Sbostic '?' Print 'l' if we are to use a branch likely instead of normal branch. 3087*61768Sbostic '@' Print the name of the assembler temporary register (at or $1). 3088*61768Sbostic '.' Print the name of the register with a hard-wired zero (zero or $0). */ 3089*61768Sbostic 3090*61768Sbostic void 3091*61768Sbostic print_operand (file, op, letter) 3092*61768Sbostic FILE *file; /* file to write to */ 3093*61768Sbostic rtx op; /* operand to print */ 3094*61768Sbostic int letter; /* %<letter> or 0 */ 3095*61768Sbostic { 3096*61768Sbostic register enum rtx_code code; 3097*61768Sbostic 3098*61768Sbostic if (PRINT_OPERAND_PUNCT_VALID_P (letter)) 3099*61768Sbostic { 3100*61768Sbostic switch (letter) 3101*61768Sbostic { 3102*61768Sbostic default: 3103*61768Sbostic error ("PRINT_OPERAND: Unknown punctuation '%c'", letter); 3104*61768Sbostic break; 3105*61768Sbostic 3106*61768Sbostic case '?': 3107*61768Sbostic if (mips_branch_likely) 3108*61768Sbostic putc ('l', file); 3109*61768Sbostic break; 3110*61768Sbostic 3111*61768Sbostic case '@': 3112*61768Sbostic fputs (reg_names [GP_REG_FIRST + 1], file); 3113*61768Sbostic break; 3114*61768Sbostic 3115*61768Sbostic case '.': 3116*61768Sbostic fputs (reg_names [GP_REG_FIRST + 0], file); 3117*61768Sbostic break; 3118*61768Sbostic 3119*61768Sbostic case '&': 3120*61768Sbostic if (final_sequence != 0 && set_noreorder++ == 0) 3121*61768Sbostic fputs (".set\tnoreorder\n\t", file); 3122*61768Sbostic break; 3123*61768Sbostic 3124*61768Sbostic case '*': 3125*61768Sbostic if (final_sequence != 0) 3126*61768Sbostic { 3127*61768Sbostic if (set_noreorder++ == 0) 3128*61768Sbostic fputs (".set\tnoreorder\n\t", file); 3129*61768Sbostic 3130*61768Sbostic if (set_nomacro++ == 0) 3131*61768Sbostic fputs (".set\tnomacro\n\t", file); 3132*61768Sbostic } 3133*61768Sbostic break; 3134*61768Sbostic 3135*61768Sbostic case '!': 3136*61768Sbostic if (final_sequence != 0 && set_nomacro++ == 0) 3137*61768Sbostic fputs ("\n\t.set\tnomacro", file); 3138*61768Sbostic break; 3139*61768Sbostic 3140*61768Sbostic case '#': 3141*61768Sbostic if (set_noreorder != 0) 3142*61768Sbostic fputs ("\n\tnop", file); 3143*61768Sbostic 3144*61768Sbostic else if (TARGET_GAS || TARGET_STATS) 3145*61768Sbostic fputs ("\n\t#nop", file); 3146*61768Sbostic 3147*61768Sbostic break; 3148*61768Sbostic 3149*61768Sbostic case '(': 3150*61768Sbostic if (set_noreorder++ == 0) 3151*61768Sbostic fputs (".set\tnoreorder\n\t", file); 3152*61768Sbostic break; 3153*61768Sbostic 3154*61768Sbostic case ')': 3155*61768Sbostic if (set_noreorder == 0) 3156*61768Sbostic error ("internal error: %%) found without a %%( in assembler pattern"); 3157*61768Sbostic 3158*61768Sbostic else if (--set_noreorder == 0) 3159*61768Sbostic fputs ("\n\t.set\treorder", file); 3160*61768Sbostic 3161*61768Sbostic break; 3162*61768Sbostic 3163*61768Sbostic case '[': 3164*61768Sbostic if (set_noat++ == 0) 3165*61768Sbostic fputs (".set\tnoat\n\t", file); 3166*61768Sbostic break; 3167*61768Sbostic 3168*61768Sbostic case ']': 3169*61768Sbostic if (set_noat == 0) 3170*61768Sbostic error ("internal error: %%] found without a %%[ in assembler pattern"); 3171*61768Sbostic 3172*61768Sbostic else if (--set_noat == 0) 3173*61768Sbostic fputs ("\n\t.set\tat", file); 3174*61768Sbostic 3175*61768Sbostic break; 3176*61768Sbostic 3177*61768Sbostic case '<': 3178*61768Sbostic if (set_nomacro++ == 0) 3179*61768Sbostic fputs (".set\tnomacro\n\t", file); 3180*61768Sbostic break; 3181*61768Sbostic 3182*61768Sbostic case '>': 3183*61768Sbostic if (set_nomacro == 0) 3184*61768Sbostic error ("internal error: %%> found without a %%< in assembler pattern"); 3185*61768Sbostic 3186*61768Sbostic else if (--set_nomacro == 0) 3187*61768Sbostic fputs ("\n\t.set\tmacro", file); 3188*61768Sbostic 3189*61768Sbostic break; 3190*61768Sbostic 3191*61768Sbostic case '{': 3192*61768Sbostic if (set_volatile++ == 0) 3193*61768Sbostic fprintf (file, "%s.set\tvolatile\n\t", (TARGET_MIPS_AS) ? "" : "#"); 3194*61768Sbostic break; 3195*61768Sbostic 3196*61768Sbostic case '}': 3197*61768Sbostic if (set_volatile == 0) 3198*61768Sbostic error ("internal error: %%} found without a %%{ in assembler pattern"); 3199*61768Sbostic 3200*61768Sbostic else if (--set_volatile == 0) 3201*61768Sbostic fprintf (file, "\n\t%s.set\tnovolatile", (TARGET_MIPS_AS) ? "" : "#"); 3202*61768Sbostic 3203*61768Sbostic break; 3204*61768Sbostic } 3205*61768Sbostic return; 3206*61768Sbostic } 3207*61768Sbostic 3208*61768Sbostic if (! op) 3209*61768Sbostic { 3210*61768Sbostic error ("PRINT_OPERAND null pointer"); 3211*61768Sbostic return; 3212*61768Sbostic } 3213*61768Sbostic 3214*61768Sbostic code = GET_CODE (op); 3215*61768Sbostic if (letter == 'C') 3216*61768Sbostic switch (code) 3217*61768Sbostic { 3218*61768Sbostic case EQ: fputs ("eq", file); break; 3219*61768Sbostic case NE: fputs ("ne", file); break; 3220*61768Sbostic case GT: fputs ("gt", file); break; 3221*61768Sbostic case GE: fputs ("ge", file); break; 3222*61768Sbostic case LT: fputs ("lt", file); break; 3223*61768Sbostic case LE: fputs ("le", file); break; 3224*61768Sbostic case GTU: fputs ("gtu", file); break; 3225*61768Sbostic case GEU: fputs ("geu", file); break; 3226*61768Sbostic case LTU: fputs ("ltu", file); break; 3227*61768Sbostic case LEU: fputs ("leu", file); break; 3228*61768Sbostic 3229*61768Sbostic default: 3230*61768Sbostic abort_with_insn (op, "PRINT_OPERAND, illegal insn for %%C"); 3231*61768Sbostic } 3232*61768Sbostic 3233*61768Sbostic else if (letter == 'N') 3234*61768Sbostic switch (code) 3235*61768Sbostic { 3236*61768Sbostic case EQ: fputs ("ne", file); break; 3237*61768Sbostic case NE: fputs ("eq", file); break; 3238*61768Sbostic case GT: fputs ("le", file); break; 3239*61768Sbostic case GE: fputs ("lt", file); break; 3240*61768Sbostic case LT: fputs ("ge", file); break; 3241*61768Sbostic case LE: fputs ("gt", file); break; 3242*61768Sbostic case GTU: fputs ("leu", file); break; 3243*61768Sbostic case GEU: fputs ("ltu", file); break; 3244*61768Sbostic case LTU: fputs ("geu", file); break; 3245*61768Sbostic case LEU: fputs ("gtu", file); break; 3246*61768Sbostic 3247*61768Sbostic default: 3248*61768Sbostic abort_with_insn (op, "PRINT_OPERAND, illegal insn for %%N"); 3249*61768Sbostic } 3250*61768Sbostic 3251*61768Sbostic else if (code == REG) 3252*61768Sbostic { 3253*61768Sbostic register int regnum = REGNO (op); 3254*61768Sbostic 3255*61768Sbostic if (letter == 'M') 3256*61768Sbostic regnum += MOST_SIGNIFICANT_WORD; 3257*61768Sbostic 3258*61768Sbostic else if (letter == 'L') 3259*61768Sbostic regnum += LEAST_SIGNIFICANT_WORD; 3260*61768Sbostic 3261*61768Sbostic else if (letter == 'D') 3262*61768Sbostic regnum++; 3263*61768Sbostic 3264*61768Sbostic fprintf (file, "%s", reg_names[regnum]); 3265*61768Sbostic } 3266*61768Sbostic 3267*61768Sbostic else if (code == MEM) 3268*61768Sbostic output_address (XEXP (op, 0)); 3269*61768Sbostic 3270*61768Sbostic else if (code == CONST_DOUBLE) 3271*61768Sbostic { 3272*61768Sbostic #if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT 3273*61768Sbostic union { double d; int i[2]; } u; 3274*61768Sbostic u.i[0] = CONST_DOUBLE_LOW (op); 3275*61768Sbostic u.i[1] = CONST_DOUBLE_HIGH (op); 3276*61768Sbostic if (GET_MODE (op) == SFmode) 3277*61768Sbostic { 3278*61768Sbostic float f; 3279*61768Sbostic f = u.d; 3280*61768Sbostic u.d = f; 3281*61768Sbostic } 3282*61768Sbostic fprintf (file, "%.20e", u.d); 3283*61768Sbostic #else 3284*61768Sbostic fatal ("CONST_DOUBLE found in cross compilation"); 3285*61768Sbostic #endif 3286*61768Sbostic } 3287*61768Sbostic 3288*61768Sbostic else if ((letter == 'x') && (GET_CODE(op) == CONST_INT)) 3289*61768Sbostic fprintf (file, "0x%04x", 0xffff & (INTVAL(op))); 3290*61768Sbostic 3291*61768Sbostic else if ((letter == 'X') && (GET_CODE(op) == CONST_INT)) 3292*61768Sbostic fprintf (file, "0x%08x", INTVAL(op)); 3293*61768Sbostic 3294*61768Sbostic else if ((letter == 'd') && (GET_CODE(op) == CONST_INT)) 3295*61768Sbostic fprintf (file, "%d", (INTVAL(op))); 3296*61768Sbostic 3297*61768Sbostic else if (letter == 'z' 3298*61768Sbostic && (GET_CODE (op) == CONST_INT) 3299*61768Sbostic && INTVAL (op) == 0) 3300*61768Sbostic fputs (reg_names[GP_REG_FIRST], file); 3301*61768Sbostic 3302*61768Sbostic else if (letter == 'd' || letter == 'x' || letter == 'X') 3303*61768Sbostic fatal ("PRINT_OPERAND: letter %c was found & insn was not CONST_INT", letter); 3304*61768Sbostic 3305*61768Sbostic else 3306*61768Sbostic output_addr_const (file, op); 3307*61768Sbostic } 3308*61768Sbostic 3309*61768Sbostic 3310*61768Sbostic /* A C compound statement to output to stdio stream STREAM the 3311*61768Sbostic assembler syntax for an instruction operand that is a memory 3312*61768Sbostic reference whose address is ADDR. ADDR is an RTL expression. 3313*61768Sbostic 3314*61768Sbostic On some machines, the syntax for a symbolic address depends on 3315*61768Sbostic the section that the address refers to. On these machines, 3316*61768Sbostic define the macro `ENCODE_SECTION_INFO' to store the information 3317*61768Sbostic into the `symbol_ref', and then check for it here. */ 3318*61768Sbostic 3319*61768Sbostic void 3320*61768Sbostic print_operand_address (file, addr) 3321*61768Sbostic FILE *file; 3322*61768Sbostic rtx addr; 3323*61768Sbostic { 3324*61768Sbostic if (!addr) 3325*61768Sbostic error ("PRINT_OPERAND_ADDRESS, null pointer"); 3326*61768Sbostic 3327*61768Sbostic else 3328*61768Sbostic switch (GET_CODE (addr)) 3329*61768Sbostic { 3330*61768Sbostic default: 3331*61768Sbostic abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, illegal insn #1"); 3332*61768Sbostic break; 3333*61768Sbostic 3334*61768Sbostic case REG: 3335*61768Sbostic if (REGNO (addr) == ARG_POINTER_REGNUM) 3336*61768Sbostic abort_with_insn (addr, "Arg pointer not eliminated."); 3337*61768Sbostic 3338*61768Sbostic fprintf (file, "0(%s)", reg_names [REGNO (addr)]); 3339*61768Sbostic break; 3340*61768Sbostic 3341*61768Sbostic case PLUS: 3342*61768Sbostic { 3343*61768Sbostic register rtx reg = (rtx)0; 3344*61768Sbostic register rtx offset = (rtx)0; 3345*61768Sbostic register rtx arg0 = XEXP (addr, 0); 3346*61768Sbostic register rtx arg1 = XEXP (addr, 1); 3347*61768Sbostic 3348*61768Sbostic if (GET_CODE (arg0) == REG) 3349*61768Sbostic { 3350*61768Sbostic reg = arg0; 3351*61768Sbostic offset = arg1; 3352*61768Sbostic if (GET_CODE (offset) == REG) 3353*61768Sbostic abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, 2 regs"); 3354*61768Sbostic } 3355*61768Sbostic else if (GET_CODE (arg1) == REG) 3356*61768Sbostic { 3357*61768Sbostic reg = arg1; 3358*61768Sbostic offset = arg0; 3359*61768Sbostic } 3360*61768Sbostic else if (CONSTANT_P (arg0) && CONSTANT_P (arg1)) 3361*61768Sbostic { 3362*61768Sbostic output_addr_const (file, addr); 3363*61768Sbostic break; 3364*61768Sbostic } 3365*61768Sbostic else 3366*61768Sbostic abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, no regs"); 3367*61768Sbostic 3368*61768Sbostic if (!CONSTANT_P (offset)) 3369*61768Sbostic abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, illegal insn #2"); 3370*61768Sbostic 3371*61768Sbostic if (REGNO (reg) == ARG_POINTER_REGNUM) 3372*61768Sbostic abort_with_insn (addr, "Arg pointer not eliminated."); 3373*61768Sbostic 3374*61768Sbostic output_addr_const (file, offset); 3375*61768Sbostic fprintf (file, "(%s)", reg_names [REGNO (reg)]); 3376*61768Sbostic } 3377*61768Sbostic break; 3378*61768Sbostic 3379*61768Sbostic case LABEL_REF: 3380*61768Sbostic case SYMBOL_REF: 3381*61768Sbostic case CONST_INT: 3382*61768Sbostic case CONST: 3383*61768Sbostic output_addr_const (file, addr); 3384*61768Sbostic break; 3385*61768Sbostic } 3386*61768Sbostic } 3387*61768Sbostic 3388*61768Sbostic 3389*61768Sbostic /* If optimizing for the global pointer, keep track of all of 3390*61768Sbostic the externs, so that at the end of the file, we can emit 3391*61768Sbostic the appropriate .extern declaration for them, before writing 3392*61768Sbostic out the text section. We assume that all names passed to 3393*61768Sbostic us are in the permanent obstack, so that they will be valid 3394*61768Sbostic at the end of the compilation. 3395*61768Sbostic 3396*61768Sbostic If we have -G 0, or the extern size is unknown, don't bother 3397*61768Sbostic emitting the .externs. */ 3398*61768Sbostic 3399*61768Sbostic int 3400*61768Sbostic mips_output_external (file, decl, name) 3401*61768Sbostic FILE *file; 3402*61768Sbostic tree decl; 3403*61768Sbostic char *name; 3404*61768Sbostic { 3405*61768Sbostic register struct extern_list *p; 3406*61768Sbostic int len; 3407*61768Sbostic 3408*61768Sbostic if (TARGET_GP_OPT 3409*61768Sbostic && mips_section_threshold != 0 3410*61768Sbostic && ((TREE_CODE (decl)) != FUNCTION_DECL) 3411*61768Sbostic && ((len = int_size_in_bytes (TREE_TYPE (decl))) > 0)) 3412*61768Sbostic { 3413*61768Sbostic p = (struct extern_list *)permalloc ((long) sizeof (struct extern_list)); 3414*61768Sbostic p->next = extern_head; 3415*61768Sbostic p->name = name; 3416*61768Sbostic p->size = len; 3417*61768Sbostic extern_head = p; 3418*61768Sbostic } 3419*61768Sbostic return 0; 3420*61768Sbostic } 3421*61768Sbostic 3422*61768Sbostic 3423*61768Sbostic /* Compute a string to use as a temporary file name. */ 3424*61768Sbostic 3425*61768Sbostic static FILE * 3426*61768Sbostic make_temp_file () 3427*61768Sbostic { 3428*61768Sbostic FILE *stream; 3429*61768Sbostic char *base = getenv ("TMPDIR"); 3430*61768Sbostic int len; 3431*61768Sbostic 3432*61768Sbostic if (base == (char *)0) 3433*61768Sbostic { 3434*61768Sbostic #ifdef P_tmpdir 3435*61768Sbostic if (access (P_tmpdir, R_OK | W_OK) == 0) 3436*61768Sbostic base = P_tmpdir; 3437*61768Sbostic else 3438*61768Sbostic #endif 3439*61768Sbostic if (access ("/usr/tmp", R_OK | W_OK) == 0) 3440*61768Sbostic base = "/usr/tmp/"; 3441*61768Sbostic else 3442*61768Sbostic base = "/tmp/"; 3443*61768Sbostic } 3444*61768Sbostic 3445*61768Sbostic len = strlen (base); 3446*61768Sbostic temp_filename = (char *) alloca (len + sizeof("/ccXXXXXX")); 3447*61768Sbostic strcpy (temp_filename, base); 3448*61768Sbostic if (len > 0 && temp_filename[len-1] != '/') 3449*61768Sbostic temp_filename[len++] = '/'; 3450*61768Sbostic 3451*61768Sbostic strcpy (temp_filename + len, "ccXXXXXX"); 3452*61768Sbostic mktemp (temp_filename); 3453*61768Sbostic 3454*61768Sbostic stream = fopen (temp_filename, "w+"); 3455*61768Sbostic if (!stream) 3456*61768Sbostic pfatal_with_name (temp_filename); 3457*61768Sbostic 3458*61768Sbostic unlink (temp_filename); 3459*61768Sbostic return stream; 3460*61768Sbostic } 3461*61768Sbostic 3462*61768Sbostic 3463*61768Sbostic /* Emit a new filename to a stream. If this is MIPS ECOFF, watch out 3464*61768Sbostic for .file's that start within a function. If we are smuggling stabs, try to 3465*61768Sbostic put out a MIPS ECOFF file and a stab. */ 3466*61768Sbostic 3467*61768Sbostic void 3468*61768Sbostic mips_output_filename (stream, name) 3469*61768Sbostic FILE *stream; 3470*61768Sbostic char *name; 3471*61768Sbostic { 3472*61768Sbostic static int first_time = TRUE; 3473*61768Sbostic char ltext_label_name[100]; 3474*61768Sbostic 3475*61768Sbostic if (first_time) 3476*61768Sbostic { 3477*61768Sbostic first_time = FALSE; 3478*61768Sbostic SET_FILE_NUMBER (); 3479*61768Sbostic current_function_file = name; 3480*61768Sbostic fprintf (stream, "\t.file\t%d \"%s\"\n", num_source_filenames, name); 3481*61768Sbostic if (!TARGET_GAS && write_symbols == DBX_DEBUG) 3482*61768Sbostic fprintf (stream, "\t#@stabs\n"); 3483*61768Sbostic } 3484*61768Sbostic 3485*61768Sbostic else if (!TARGET_GAS && write_symbols == DBX_DEBUG) 3486*61768Sbostic { 3487*61768Sbostic ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0); 3488*61768Sbostic fprintf (stream, "%s \"%s\",%d,0,0,%s\n", ASM_STABS_OP, 3489*61768Sbostic name, N_SOL, <ext_label_name[1]); 3490*61768Sbostic } 3491*61768Sbostic 3492*61768Sbostic else if (name != current_function_file 3493*61768Sbostic && strcmp (name, current_function_file) != 0) 3494*61768Sbostic { 3495*61768Sbostic if (inside_function && !TARGET_GAS) 3496*61768Sbostic { 3497*61768Sbostic if (!file_in_function_warning) 3498*61768Sbostic { 3499*61768Sbostic file_in_function_warning = TRUE; 3500*61768Sbostic ignore_line_number = TRUE; 3501*61768Sbostic warning ("MIPS ECOFF format does not allow changing filenames within functions with #line"); 3502*61768Sbostic } 3503*61768Sbostic 3504*61768Sbostic fprintf (stream, "\t#.file\t%d \"%s\"\n", num_source_filenames, name); 3505*61768Sbostic } 3506*61768Sbostic 3507*61768Sbostic else 3508*61768Sbostic { 3509*61768Sbostic SET_FILE_NUMBER (); 3510*61768Sbostic current_function_file = name; 3511*61768Sbostic fprintf (stream, "\t.file\t%d \"%s\"\n", num_source_filenames, name); 3512*61768Sbostic } 3513*61768Sbostic } 3514*61768Sbostic } 3515*61768Sbostic 3516*61768Sbostic 3517*61768Sbostic /* Emit a linenumber. For encapsulated stabs, we need to put out a stab 3518*61768Sbostic as well as a .loc, since it is possible that MIPS ECOFF might not be 3519*61768Sbostic able to represent the location for inlines that come from a different 3520*61768Sbostic file. */ 3521*61768Sbostic 3522*61768Sbostic void 3523*61768Sbostic mips_output_lineno (stream, line) 3524*61768Sbostic FILE *stream; 3525*61768Sbostic int line; 3526*61768Sbostic { 3527*61768Sbostic if (!TARGET_GAS && write_symbols == DBX_DEBUG) 3528*61768Sbostic { 3529*61768Sbostic ++sym_lineno; 3530*61768Sbostic fprintf (stream, "$LM%d:\n\t%s %d,0,%d,$LM%d\n", 3531*61768Sbostic sym_lineno, ASM_STABN_OP, N_SLINE, line, sym_lineno); 3532*61768Sbostic } 3533*61768Sbostic 3534*61768Sbostic else 3535*61768Sbostic { 3536*61768Sbostic fprintf (stream, "\n\t%s.loc\t%d %d\n", 3537*61768Sbostic (ignore_line_number) ? "#" : "", 3538*61768Sbostic num_source_filenames, line); 3539*61768Sbostic 3540*61768Sbostic LABEL_AFTER_LOC (stream); 3541*61768Sbostic } 3542*61768Sbostic } 3543*61768Sbostic 3544*61768Sbostic 3545*61768Sbostic /* If defined, a C statement to be executed just prior to the 3546*61768Sbostic output of assembler code for INSN, to modify the extracted 3547*61768Sbostic operands so they will be output differently. 3548*61768Sbostic 3549*61768Sbostic Here the argument OPVEC is the vector containing the operands 3550*61768Sbostic extracted from INSN, and NOPERANDS is the number of elements of 3551*61768Sbostic the vector which contain meaningful data for this insn. The 3552*61768Sbostic contents of this vector are what will be used to convert the 3553*61768Sbostic insn template into assembler code, so you can change the 3554*61768Sbostic assembler output by changing the contents of the vector. 3555*61768Sbostic 3556*61768Sbostic We use it to check if the current insn needs a nop in front of it 3557*61768Sbostic because of load delays, and also to update the delay slot 3558*61768Sbostic statistics. */ 3559*61768Sbostic 3560*61768Sbostic void 3561*61768Sbostic final_prescan_insn (insn, opvec, noperands) 3562*61768Sbostic rtx insn; 3563*61768Sbostic rtx opvec[]; 3564*61768Sbostic int noperands; 3565*61768Sbostic { 3566*61768Sbostic if (dslots_number_nops > 0) 3567*61768Sbostic { 3568*61768Sbostic rtx pattern = PATTERN (insn); 3569*61768Sbostic int length = get_attr_length (insn); 3570*61768Sbostic 3571*61768Sbostic /* Do we need to emit a NOP? */ 3572*61768Sbostic if (length == 0 3573*61768Sbostic || (mips_load_reg != (rtx)0 && reg_mentioned_p (mips_load_reg, pattern)) 3574*61768Sbostic || (mips_load_reg2 != (rtx)0 && reg_mentioned_p (mips_load_reg2, pattern)) 3575*61768Sbostic || (mips_load_reg3 != (rtx)0 && reg_mentioned_p (mips_load_reg3, pattern)) 3576*61768Sbostic || (mips_load_reg4 != (rtx)0 && reg_mentioned_p (mips_load_reg4, pattern))) 3577*61768Sbostic fputs ((set_noreorder) ? "\tnop\n" : "\t#nop\n", asm_out_file); 3578*61768Sbostic 3579*61768Sbostic else 3580*61768Sbostic dslots_load_filled++; 3581*61768Sbostic 3582*61768Sbostic while (--dslots_number_nops > 0) 3583*61768Sbostic fputs ((set_noreorder) ? "\tnop\n" : "\t#nop\n", asm_out_file); 3584*61768Sbostic 3585*61768Sbostic mips_load_reg = (rtx)0; 3586*61768Sbostic mips_load_reg2 = (rtx)0; 3587*61768Sbostic mips_load_reg3 = (rtx)0; 3588*61768Sbostic mips_load_reg4 = (rtx)0; 3589*61768Sbostic 3590*61768Sbostic if (set_noreorder && --set_noreorder == 0) 3591*61768Sbostic fputs ("\t.set\treorder\n", asm_out_file); 3592*61768Sbostic } 3593*61768Sbostic 3594*61768Sbostic if (TARGET_STATS) 3595*61768Sbostic { 3596*61768Sbostic enum rtx_code code = GET_CODE (insn); 3597*61768Sbostic if (code == JUMP_INSN || code == CALL_INSN) 3598*61768Sbostic dslots_jump_total++; 3599*61768Sbostic } 3600*61768Sbostic } 3601*61768Sbostic 3602*61768Sbostic 3603*61768Sbostic /* Output at beginning of assembler file. 3604*61768Sbostic If we are optimizing to use the global pointer, create a temporary 3605*61768Sbostic file to hold all of the text stuff, and write it out to the end. 3606*61768Sbostic This is needed because the MIPS assembler is evidently one pass, 3607*61768Sbostic and if it hasn't seen the relevant .comm/.lcomm/.extern/.sdata 3608*61768Sbostic declaration when the code is processed, it generates a two 3609*61768Sbostic instruction sequence. */ 3610*61768Sbostic 3611*61768Sbostic void 3612*61768Sbostic mips_asm_file_start (stream) 3613*61768Sbostic FILE *stream; 3614*61768Sbostic { 3615*61768Sbostic ASM_OUTPUT_SOURCE_FILENAME (stream, main_input_filename); 3616*61768Sbostic 3617*61768Sbostic /* Versions of the MIPS assembler before 2.20 generate errors 3618*61768Sbostic if a branch inside of a .set noreorder section jumps to a 3619*61768Sbostic label outside of the .set noreorder section. Revision 2.20 3620*61768Sbostic just set nobopt silently rather than fixing the bug. */ 3621*61768Sbostic 3622*61768Sbostic if (TARGET_MIPS_AS && optimize && flag_delayed_branch) 3623*61768Sbostic fprintf (stream, "\t.set\tnobopt\n"); 3624*61768Sbostic 3625*61768Sbostic /* Generate the pseudo ops that the Pyramid based System V.4 wants. */ 3626*61768Sbostic if (TARGET_ABICALLS) 3627*61768Sbostic fprintf (stream, "\t.abicalls\n"); 3628*61768Sbostic 3629*61768Sbostic if (TARGET_GP_OPT) 3630*61768Sbostic { 3631*61768Sbostic asm_out_data_file = stream; 3632*61768Sbostic asm_out_text_file = make_temp_file (); 3633*61768Sbostic } 3634*61768Sbostic else 3635*61768Sbostic asm_out_data_file = asm_out_text_file = stream; 3636*61768Sbostic 3637*61768Sbostic if (TARGET_NAME_REGS) 3638*61768Sbostic fprintf (asm_out_file, "#include <regdef.h>\n"); 3639*61768Sbostic 3640*61768Sbostic print_options (stream); 3641*61768Sbostic } 3642*61768Sbostic 3643*61768Sbostic 3644*61768Sbostic /* If we are optimizing the global pointer, emit the text section now 3645*61768Sbostic and any small externs which did not have .comm, etc that are 3646*61768Sbostic needed. Also, give a warning if the data area is more than 32K and 3647*61768Sbostic -pic because 3 instructions are needed to reference the data 3648*61768Sbostic pointers. */ 3649*61768Sbostic 3650*61768Sbostic void 3651*61768Sbostic mips_asm_file_end (file) 3652*61768Sbostic FILE *file; 3653*61768Sbostic { 3654*61768Sbostic char buffer[8192]; 3655*61768Sbostic tree name_tree; 3656*61768Sbostic struct extern_list *p; 3657*61768Sbostic int len; 3658*61768Sbostic 3659*61768Sbostic if (HALF_PIC_P ()) 3660*61768Sbostic HALF_PIC_FINISH (file); 3661*61768Sbostic 3662*61768Sbostic if (TARGET_GP_OPT) 3663*61768Sbostic { 3664*61768Sbostic if (extern_head) 3665*61768Sbostic fputs ("\n", file); 3666*61768Sbostic 3667*61768Sbostic for (p = extern_head; p != 0; p = p->next) 3668*61768Sbostic { 3669*61768Sbostic name_tree = get_identifier (p->name); 3670*61768Sbostic 3671*61768Sbostic /* Positively ensure only one .extern for any given symbol. */ 3672*61768Sbostic if (! TREE_ASM_WRITTEN (name_tree)) 3673*61768Sbostic { 3674*61768Sbostic TREE_ASM_WRITTEN (name_tree) = 1; 3675*61768Sbostic fputs ("\t.extern\t", file); 3676*61768Sbostic assemble_name (file, p->name); 3677*61768Sbostic fprintf (file, ", %d\n", p->size); 3678*61768Sbostic } 3679*61768Sbostic } 3680*61768Sbostic 3681*61768Sbostic fprintf (file, "\n\t.text\n"); 3682*61768Sbostic rewind (asm_out_text_file); 3683*61768Sbostic if (ferror (asm_out_text_file)) 3684*61768Sbostic fatal_io_error (temp_filename); 3685*61768Sbostic 3686*61768Sbostic while ((len = fread (buffer, 1, sizeof (buffer), asm_out_text_file)) > 0) 3687*61768Sbostic if (fwrite (buffer, 1, len, file) != len) 3688*61768Sbostic pfatal_with_name (asm_file_name); 3689*61768Sbostic 3690*61768Sbostic if (len < 0) 3691*61768Sbostic pfatal_with_name (temp_filename); 3692*61768Sbostic 3693*61768Sbostic if (fclose (asm_out_text_file) != 0) 3694*61768Sbostic pfatal_with_name (temp_filename); 3695*61768Sbostic } 3696*61768Sbostic } 3697*61768Sbostic 3698*61768Sbostic 3699*61768Sbostic /* Emit either a label, .comm, or .lcomm directive, and mark 3700*61768Sbostic that the symbol is used, so that we don't emit an .extern 3701*61768Sbostic for it in mips_asm_file_end. */ 3702*61768Sbostic 3703*61768Sbostic void 3704*61768Sbostic mips_declare_object (stream, name, init_string, final_string, size) 3705*61768Sbostic FILE *stream; 3706*61768Sbostic char *name; 3707*61768Sbostic char *init_string; 3708*61768Sbostic char *final_string; 3709*61768Sbostic int size; 3710*61768Sbostic { 3711*61768Sbostic fputs (init_string, stream); /* "", "\t.comm\t", or "\t.lcomm\t" */ 3712*61768Sbostic assemble_name (stream, name); 3713*61768Sbostic fprintf (stream, final_string, size); /* ":\n", ",%u\n", ",%u\n" */ 3714*61768Sbostic 3715*61768Sbostic if (TARGET_GP_OPT && mips_section_threshold != 0) 3716*61768Sbostic { 3717*61768Sbostic tree name_tree = get_identifier (name); 3718*61768Sbostic TREE_ASM_WRITTEN (name_tree) = 1; 3719*61768Sbostic } 3720*61768Sbostic } 3721*61768Sbostic 3722*61768Sbostic 3723*61768Sbostic /* Output a double precision value to the assembler. If both the 3724*61768Sbostic host and target are IEEE, emit the values in hex. */ 3725*61768Sbostic 3726*61768Sbostic void 3727*61768Sbostic mips_output_double (stream, value) 3728*61768Sbostic FILE *stream; 3729*61768Sbostic REAL_VALUE_TYPE value; 3730*61768Sbostic { 3731*61768Sbostic #ifdef REAL_VALUE_TO_TARGET_DOUBLE 3732*61768Sbostic long value_long[2]; 3733*61768Sbostic REAL_VALUE_TO_TARGET_DOUBLE (value, value_long); 3734*61768Sbostic 3735*61768Sbostic fprintf (stream, "\t.word\t0x%08lx\t\t# %.20g\n\t.word\t0x%08lx\n", 3736*61768Sbostic value_long[0], value, value_long[1]); 3737*61768Sbostic #else 3738*61768Sbostic fprintf (stream, "\t.double\t%.20g\n", value); 3739*61768Sbostic #endif 3740*61768Sbostic } 3741*61768Sbostic 3742*61768Sbostic 3743*61768Sbostic /* Output a single precision value to the assembler. If both the 3744*61768Sbostic host and target are IEEE, emit the values in hex. */ 3745*61768Sbostic 3746*61768Sbostic void 3747*61768Sbostic mips_output_float (stream, value) 3748*61768Sbostic FILE *stream; 3749*61768Sbostic REAL_VALUE_TYPE value; 3750*61768Sbostic { 3751*61768Sbostic #ifdef REAL_VALUE_TO_TARGET_SINGLE 3752*61768Sbostic long value_long; 3753*61768Sbostic REAL_VALUE_TO_TARGET_SINGLE (value, value_long); 3754*61768Sbostic 3755*61768Sbostic fprintf (stream, "\t.word\t0x%08lx\t\t# %.12g (float)\n", value_long, value); 3756*61768Sbostic #else 3757*61768Sbostic fprintf (stream, "\t.float\t%.12g\n", value); 3758*61768Sbostic #endif 3759*61768Sbostic } 3760*61768Sbostic 3761*61768Sbostic 3762*61768Sbostic /* Return TRUE if any register used in the epilogue is used. This to insure 3763*61768Sbostic any insn put into the epilogue delay slots is safe. */ 3764*61768Sbostic 3765*61768Sbostic int 3766*61768Sbostic epilogue_reg_mentioned_p (insn) 3767*61768Sbostic rtx insn; 3768*61768Sbostic { 3769*61768Sbostic register char *fmt; 3770*61768Sbostic register int i; 3771*61768Sbostic register enum rtx_code code; 3772*61768Sbostic register int regno; 3773*61768Sbostic 3774*61768Sbostic if (insn == (rtx)0) 3775*61768Sbostic return 0; 3776*61768Sbostic 3777*61768Sbostic if (GET_CODE (insn) == LABEL_REF) 3778*61768Sbostic return 0; 3779*61768Sbostic 3780*61768Sbostic code = GET_CODE (insn); 3781*61768Sbostic switch (code) 3782*61768Sbostic { 3783*61768Sbostic case REG: 3784*61768Sbostic regno = REGNO (insn); 3785*61768Sbostic if (regno == STACK_POINTER_REGNUM) 3786*61768Sbostic return 1; 3787*61768Sbostic 3788*61768Sbostic if (regno == FRAME_POINTER_REGNUM && frame_pointer_needed) 3789*61768Sbostic return 1; 3790*61768Sbostic 3791*61768Sbostic if (!call_used_regs[regno]) 3792*61768Sbostic return 1; 3793*61768Sbostic 3794*61768Sbostic if (regno != MIPS_TEMP1_REGNUM && regno != MIPS_TEMP2_REGNUM) 3795*61768Sbostic return 0; 3796*61768Sbostic 3797*61768Sbostic if (!current_frame_info.initialized) 3798*61768Sbostic compute_frame_size (get_frame_size ()); 3799*61768Sbostic 3800*61768Sbostic return (current_frame_info.total_size >= 32768); 3801*61768Sbostic 3802*61768Sbostic case SCRATCH: 3803*61768Sbostic case CC0: 3804*61768Sbostic case PC: 3805*61768Sbostic case CONST_INT: 3806*61768Sbostic case CONST_DOUBLE: 3807*61768Sbostic return 0; 3808*61768Sbostic } 3809*61768Sbostic 3810*61768Sbostic fmt = GET_RTX_FORMAT (code); 3811*61768Sbostic for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) 3812*61768Sbostic { 3813*61768Sbostic if (fmt[i] == 'E') 3814*61768Sbostic { 3815*61768Sbostic register int j; 3816*61768Sbostic for (j = XVECLEN (insn, i) - 1; j >= 0; j--) 3817*61768Sbostic if (epilogue_reg_mentioned_p (XVECEXP (insn, i, j))) 3818*61768Sbostic return 1; 3819*61768Sbostic } 3820*61768Sbostic else if (fmt[i] == 'e' && epilogue_reg_mentioned_p (XEXP (insn, i))) 3821*61768Sbostic return 1; 3822*61768Sbostic } 3823*61768Sbostic 3824*61768Sbostic return 0; 3825*61768Sbostic } 3826*61768Sbostic 3827*61768Sbostic 3828*61768Sbostic /* Return the bytes needed to compute the frame pointer from the current 3829*61768Sbostic stack pointer. 3830*61768Sbostic 3831*61768Sbostic Mips stack frames look like: 3832*61768Sbostic 3833*61768Sbostic Before call After call 3834*61768Sbostic +-----------------------+ +-----------------------+ 3835*61768Sbostic high | | | | 3836*61768Sbostic mem. | | | | 3837*61768Sbostic | caller's temps. | | caller's temps. | 3838*61768Sbostic | | | | 3839*61768Sbostic +-----------------------+ +-----------------------+ 3840*61768Sbostic | | | | 3841*61768Sbostic | arguments on stack. | | arguments on stack. | 3842*61768Sbostic | | | | 3843*61768Sbostic +-----------------------+ +-----------------------+ 3844*61768Sbostic | 4 words to save | | 4 words to save | 3845*61768Sbostic | arguments passed | | arguments passed | 3846*61768Sbostic | in registers, even | | in registers, even | 3847*61768Sbostic SP->| if not passed. | FP->| if not passed. | 3848*61768Sbostic +-----------------------+ +-----------------------+ 3849*61768Sbostic | | 3850*61768Sbostic | GP save for V.4 abi | 3851*61768Sbostic | | 3852*61768Sbostic +-----------------------+ 3853*61768Sbostic | | 3854*61768Sbostic | fp register save | 3855*61768Sbostic | | 3856*61768Sbostic +-----------------------+ 3857*61768Sbostic | | 3858*61768Sbostic | gp register save | 3859*61768Sbostic | | 3860*61768Sbostic +-----------------------+ 3861*61768Sbostic | | 3862*61768Sbostic | local variables | 3863*61768Sbostic | | 3864*61768Sbostic +-----------------------+ 3865*61768Sbostic | | 3866*61768Sbostic | alloca allocations | 3867*61768Sbostic | | 3868*61768Sbostic +-----------------------+ 3869*61768Sbostic | | 3870*61768Sbostic | arguments on stack | 3871*61768Sbostic | | 3872*61768Sbostic +-----------------------+ 3873*61768Sbostic | 4 words to save | 3874*61768Sbostic | arguments passed | 3875*61768Sbostic | in registers, even | 3876*61768Sbostic low SP->| if not passed. | 3877*61768Sbostic memory +-----------------------+ 3878*61768Sbostic 3879*61768Sbostic */ 3880*61768Sbostic 3881*61768Sbostic long 3882*61768Sbostic compute_frame_size (size) 3883*61768Sbostic int size; /* # of var. bytes allocated */ 3884*61768Sbostic { 3885*61768Sbostic int regno; 3886*61768Sbostic long total_size; /* # bytes that the entire frame takes up */ 3887*61768Sbostic long var_size; /* # bytes that variables take up */ 3888*61768Sbostic long args_size; /* # bytes that outgoing arguments take up */ 3889*61768Sbostic long extra_size; /* # extra bytes */ 3890*61768Sbostic long gp_reg_rounded; /* # bytes needed to store gp after rounding */ 3891*61768Sbostic long gp_reg_size; /* # bytes needed to store gp regs */ 3892*61768Sbostic long fp_reg_size; /* # bytes needed to store fp regs */ 3893*61768Sbostic long mask; /* mask of saved gp registers */ 3894*61768Sbostic long fmask; /* mask of saved fp registers */ 3895*61768Sbostic int fp_inc; /* 1 or 2 depending on the size of fp regs */ 3896*61768Sbostic long fp_bits; /* bitmask to use for each fp register */ 3897*61768Sbostic 3898*61768Sbostic gp_reg_size = 0; 3899*61768Sbostic fp_reg_size = 0; 3900*61768Sbostic mask = 0; 3901*61768Sbostic fmask = 0; 3902*61768Sbostic extra_size = MIPS_STACK_ALIGN (((TARGET_ABICALLS) ? UNITS_PER_WORD : 0)); 3903*61768Sbostic var_size = MIPS_STACK_ALIGN (size); 3904*61768Sbostic args_size = MIPS_STACK_ALIGN (current_function_outgoing_args_size); 3905*61768Sbostic 3906*61768Sbostic /* The MIPS 3.0 linker does not like functions that dynamically 3907*61768Sbostic allocate the stack and have 0 for STACK_DYNAMIC_OFFSET, since it 3908*61768Sbostic looks like we are trying to create a second frame pointer to the 3909*61768Sbostic function, so allocate some stack space to make it happy. */ 3910*61768Sbostic 3911*61768Sbostic if (args_size == 0 && current_function_calls_alloca) 3912*61768Sbostic args_size = 4*UNITS_PER_WORD; 3913*61768Sbostic 3914*61768Sbostic total_size = var_size + args_size + extra_size; 3915*61768Sbostic 3916*61768Sbostic /* Calculate space needed for gp registers. */ 3917*61768Sbostic for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) 3918*61768Sbostic { 3919*61768Sbostic if (MUST_SAVE_REGISTER (regno)) 3920*61768Sbostic { 3921*61768Sbostic gp_reg_size += UNITS_PER_WORD; 3922*61768Sbostic mask |= 1L << (regno - GP_REG_FIRST); 3923*61768Sbostic } 3924*61768Sbostic } 3925*61768Sbostic 3926*61768Sbostic /* Calculate space needed for fp registers. */ 3927*61768Sbostic if (TARGET_FLOAT64) 3928*61768Sbostic { 3929*61768Sbostic fp_inc = 1; 3930*61768Sbostic fp_bits = 1; 3931*61768Sbostic } 3932*61768Sbostic else 3933*61768Sbostic { 3934*61768Sbostic fp_inc = 2; 3935*61768Sbostic fp_bits = 3; 3936*61768Sbostic } 3937*61768Sbostic 3938*61768Sbostic for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno += fp_inc) 3939*61768Sbostic { 3940*61768Sbostic if (regs_ever_live[regno] && !call_used_regs[regno]) 3941*61768Sbostic { 3942*61768Sbostic fp_reg_size += 2*UNITS_PER_WORD; 3943*61768Sbostic fmask |= fp_bits << (regno - FP_REG_FIRST); 3944*61768Sbostic } 3945*61768Sbostic } 3946*61768Sbostic 3947*61768Sbostic gp_reg_rounded = MIPS_STACK_ALIGN (gp_reg_size); 3948*61768Sbostic total_size += gp_reg_rounded + fp_reg_size; 3949*61768Sbostic 3950*61768Sbostic if (total_size == extra_size) 3951*61768Sbostic total_size = extra_size = 0; 3952*61768Sbostic 3953*61768Sbostic /* Save other computed information. */ 3954*61768Sbostic current_frame_info.total_size = total_size; 3955*61768Sbostic current_frame_info.var_size = var_size; 3956*61768Sbostic current_frame_info.args_size = args_size; 3957*61768Sbostic current_frame_info.extra_size = extra_size; 3958*61768Sbostic current_frame_info.gp_reg_size = gp_reg_size; 3959*61768Sbostic current_frame_info.fp_reg_size = fp_reg_size; 3960*61768Sbostic current_frame_info.mask = mask; 3961*61768Sbostic current_frame_info.fmask = fmask; 3962*61768Sbostic current_frame_info.initialized = reload_completed; 3963*61768Sbostic current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD; 3964*61768Sbostic current_frame_info.num_fp = fp_reg_size / (2*UNITS_PER_WORD); 3965*61768Sbostic 3966*61768Sbostic if (mask) 3967*61768Sbostic { 3968*61768Sbostic unsigned long offset = args_size + var_size + gp_reg_size - UNITS_PER_WORD; 3969*61768Sbostic current_frame_info.gp_sp_offset = offset; 3970*61768Sbostic current_frame_info.gp_save_offset = offset - total_size; 3971*61768Sbostic } 3972*61768Sbostic else 3973*61768Sbostic { 3974*61768Sbostic current_frame_info.gp_sp_offset = 0; 3975*61768Sbostic current_frame_info.gp_save_offset = 0; 3976*61768Sbostic } 3977*61768Sbostic 3978*61768Sbostic 3979*61768Sbostic if (fmask) 3980*61768Sbostic { 3981*61768Sbostic unsigned long offset = args_size + var_size + gp_reg_rounded + fp_reg_size - 2*UNITS_PER_WORD; 3982*61768Sbostic current_frame_info.fp_sp_offset = offset; 3983*61768Sbostic current_frame_info.fp_save_offset = offset - total_size + UNITS_PER_WORD; 3984*61768Sbostic } 3985*61768Sbostic else 3986*61768Sbostic { 3987*61768Sbostic current_frame_info.fp_sp_offset = 0; 3988*61768Sbostic current_frame_info.fp_save_offset = 0; 3989*61768Sbostic } 3990*61768Sbostic 3991*61768Sbostic /* Ok, we're done. */ 3992*61768Sbostic return total_size; 3993*61768Sbostic } 3994*61768Sbostic 3995*61768Sbostic 3996*61768Sbostic /* Common code to emit the insns (or to write the instructions to a file) 3997*61768Sbostic to save/restore registers. 3998*61768Sbostic 3999*61768Sbostic Other parts of the code assume that MIPS_TEMP1_REGNUM (aka large_reg) 4000*61768Sbostic is not modified within save_restore_insns. */ 4001*61768Sbostic 4002*61768Sbostic #define BITSET_P(value,bit) (((value) & (1L << (bit))) != 0) 4003*61768Sbostic 4004*61768Sbostic static void 4005*61768Sbostic save_restore_insns (store_p, large_reg, large_offset, file) 4006*61768Sbostic int store_p; /* true if this is prologue */ 4007*61768Sbostic rtx large_reg; /* register holding large offset constant or NULL */ 4008*61768Sbostic long large_offset; /* large constant offset value */ 4009*61768Sbostic FILE *file; /* file to write instructions to instead of making RTL */ 4010*61768Sbostic { 4011*61768Sbostic long mask = current_frame_info.mask; 4012*61768Sbostic long fmask = current_frame_info.fmask; 4013*61768Sbostic int regno; 4014*61768Sbostic rtx base_reg_rtx; 4015*61768Sbostic long base_offset; 4016*61768Sbostic long gp_offset; 4017*61768Sbostic long fp_offset; 4018*61768Sbostic long end_offset; 4019*61768Sbostic 4020*61768Sbostic if (frame_pointer_needed && !BITSET_P (mask, FRAME_POINTER_REGNUM - GP_REG_FIRST)) 4021*61768Sbostic abort (); 4022*61768Sbostic 4023*61768Sbostic if (mask == 0 && fmask == 0) 4024*61768Sbostic return; 4025*61768Sbostic 4026*61768Sbostic /* Save registers starting from high to low. The debuggers prefer 4027*61768Sbostic at least the return register be stored at func+4, and also it 4028*61768Sbostic allows us not to need a nop in the epilog if at least one 4029*61768Sbostic register is reloaded in addition to return address. */ 4030*61768Sbostic 4031*61768Sbostic /* Save GP registers if needed. */ 4032*61768Sbostic if (mask) 4033*61768Sbostic { 4034*61768Sbostic /* Pick which pointer to use as a base register. For small 4035*61768Sbostic frames, just use the stack pointer. Otherwise, use a 4036*61768Sbostic temporary register. Save 2 cycles if the save area is near 4037*61768Sbostic the end of a large frame, by reusing the constant created in 4038*61768Sbostic the prologue/epilogue to adjust the stack frame. */ 4039*61768Sbostic 4040*61768Sbostic gp_offset = current_frame_info.gp_sp_offset; 4041*61768Sbostic end_offset = gp_offset - (current_frame_info.gp_reg_size - UNITS_PER_WORD); 4042*61768Sbostic 4043*61768Sbostic if (gp_offset < 0 || end_offset < 0) 4044*61768Sbostic fatal ("gp_offset (%ld) or end_offset (%ld) is less than zero.", 4045*61768Sbostic gp_offset, end_offset); 4046*61768Sbostic 4047*61768Sbostic else if (gp_offset < 32768) 4048*61768Sbostic { 4049*61768Sbostic base_reg_rtx = stack_pointer_rtx; 4050*61768Sbostic base_offset = 0; 4051*61768Sbostic } 4052*61768Sbostic 4053*61768Sbostic else if (large_reg != (rtx)0 4054*61768Sbostic && (((unsigned long)(large_offset - gp_offset)) < 32768) 4055*61768Sbostic && (((unsigned long)(large_offset - end_offset)) < 32768)) 4056*61768Sbostic { 4057*61768Sbostic base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM); 4058*61768Sbostic base_offset = large_offset; 4059*61768Sbostic if (file == (FILE *)0) 4060*61768Sbostic emit_insn (gen_addsi3 (base_reg_rtx, large_reg, stack_pointer_rtx)); 4061*61768Sbostic else 4062*61768Sbostic fprintf (file, "\taddu\t%s,%s,%s\n", 4063*61768Sbostic reg_names[MIPS_TEMP2_REGNUM], 4064*61768Sbostic reg_names[REGNO (large_reg)], 4065*61768Sbostic reg_names[STACK_POINTER_REGNUM]); 4066*61768Sbostic } 4067*61768Sbostic 4068*61768Sbostic else 4069*61768Sbostic { 4070*61768Sbostic base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM); 4071*61768Sbostic base_offset = gp_offset; 4072*61768Sbostic if (file == (FILE *)0) 4073*61768Sbostic { 4074*61768Sbostic emit_move_insn (base_reg_rtx, GEN_INT (gp_offset)); 4075*61768Sbostic emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx, stack_pointer_rtx)); 4076*61768Sbostic } 4077*61768Sbostic else 4078*61768Sbostic fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n\taddu\t%s,%s,%s\n", 4079*61768Sbostic reg_names[MIPS_TEMP2_REGNUM], 4080*61768Sbostic (long)base_offset, 4081*61768Sbostic (long)base_offset, 4082*61768Sbostic reg_names[MIPS_TEMP2_REGNUM], 4083*61768Sbostic reg_names[MIPS_TEMP2_REGNUM], 4084*61768Sbostic reg_names[STACK_POINTER_REGNUM]); 4085*61768Sbostic } 4086*61768Sbostic 4087*61768Sbostic for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--) 4088*61768Sbostic { 4089*61768Sbostic if (BITSET_P (mask, regno - GP_REG_FIRST)) 4090*61768Sbostic { 4091*61768Sbostic if (file == (FILE *)0) 4092*61768Sbostic { 4093*61768Sbostic rtx reg_rtx = gen_rtx (REG, Pmode, regno); 4094*61768Sbostic rtx mem_rtx = gen_rtx (MEM, Pmode, 4095*61768Sbostic gen_rtx (PLUS, Pmode, base_reg_rtx, 4096*61768Sbostic GEN_INT (gp_offset - base_offset))); 4097*61768Sbostic 4098*61768Sbostic if (store_p) 4099*61768Sbostic emit_move_insn (mem_rtx, reg_rtx); 4100*61768Sbostic else 4101*61768Sbostic emit_move_insn (reg_rtx, mem_rtx); 4102*61768Sbostic } 4103*61768Sbostic else 4104*61768Sbostic fprintf (file, "\t%s\t%s,%ld(%s)\n", 4105*61768Sbostic (store_p) ? "sw" : "lw", 4106*61768Sbostic reg_names[regno], 4107*61768Sbostic gp_offset - base_offset, 4108*61768Sbostic reg_names[REGNO(base_reg_rtx)]); 4109*61768Sbostic 4110*61768Sbostic gp_offset -= UNITS_PER_WORD; 4111*61768Sbostic } 4112*61768Sbostic } 4113*61768Sbostic } 4114*61768Sbostic else 4115*61768Sbostic { 4116*61768Sbostic base_reg_rtx = (rtx)0; /* Make sure these are initialzed */ 4117*61768Sbostic base_offset = 0; 4118*61768Sbostic } 4119*61768Sbostic 4120*61768Sbostic /* Save floating point registers if needed. */ 4121*61768Sbostic if (fmask) 4122*61768Sbostic { 4123*61768Sbostic int fp_inc = (TARGET_FLOAT64) ? 1 : 2; 4124*61768Sbostic 4125*61768Sbostic /* Pick which pointer to use as a base register. */ 4126*61768Sbostic fp_offset = current_frame_info.fp_sp_offset; 4127*61768Sbostic end_offset = fp_offset - (current_frame_info.fp_reg_size - UNITS_PER_WORD); 4128*61768Sbostic 4129*61768Sbostic if (fp_offset < 0 || end_offset < 0) 4130*61768Sbostic fatal ("fp_offset (%ld) or end_offset (%ld) is less than zero.", 4131*61768Sbostic fp_offset, end_offset); 4132*61768Sbostic 4133*61768Sbostic else if (fp_offset < 32768) 4134*61768Sbostic { 4135*61768Sbostic base_reg_rtx = stack_pointer_rtx; 4136*61768Sbostic base_offset = 0; 4137*61768Sbostic } 4138*61768Sbostic 4139*61768Sbostic else if (base_reg_rtx != (rtx)0 4140*61768Sbostic && (((unsigned long)(base_offset - fp_offset)) < 32768) 4141*61768Sbostic && (((unsigned long)(base_offset - end_offset)) < 32768)) 4142*61768Sbostic { 4143*61768Sbostic ; /* already set up for gp registers above */ 4144*61768Sbostic } 4145*61768Sbostic 4146*61768Sbostic else if (large_reg != (rtx)0 4147*61768Sbostic && (((unsigned long)(large_offset - fp_offset)) < 32768) 4148*61768Sbostic && (((unsigned long)(large_offset - end_offset)) < 32768)) 4149*61768Sbostic { 4150*61768Sbostic base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM); 4151*61768Sbostic base_offset = large_offset; 4152*61768Sbostic if (file == (FILE *)0) 4153*61768Sbostic emit_insn (gen_addsi3 (base_reg_rtx, large_reg, stack_pointer_rtx)); 4154*61768Sbostic else 4155*61768Sbostic fprintf (file, "\taddu\t%s,%s,%s\n", 4156*61768Sbostic reg_names[MIPS_TEMP2_REGNUM], 4157*61768Sbostic reg_names[REGNO (large_reg)], 4158*61768Sbostic reg_names[STACK_POINTER_REGNUM]); 4159*61768Sbostic } 4160*61768Sbostic 4161*61768Sbostic else 4162*61768Sbostic { 4163*61768Sbostic base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM); 4164*61768Sbostic base_offset = fp_offset; 4165*61768Sbostic if (file == (FILE *)0) 4166*61768Sbostic { 4167*61768Sbostic emit_move_insn (base_reg_rtx, GEN_INT (fp_offset)); 4168*61768Sbostic emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx, stack_pointer_rtx)); 4169*61768Sbostic } 4170*61768Sbostic else 4171*61768Sbostic fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n\taddu\t%s,%s,%s\n", 4172*61768Sbostic reg_names[MIPS_TEMP2_REGNUM], 4173*61768Sbostic (long)base_offset, 4174*61768Sbostic (long)base_offset, 4175*61768Sbostic reg_names[MIPS_TEMP2_REGNUM], 4176*61768Sbostic reg_names[MIPS_TEMP2_REGNUM], 4177*61768Sbostic reg_names[STACK_POINTER_REGNUM]); 4178*61768Sbostic } 4179*61768Sbostic 4180*61768Sbostic for (regno = FP_REG_LAST-1; regno >= FP_REG_FIRST; regno -= fp_inc) 4181*61768Sbostic { 4182*61768Sbostic if (BITSET_P (fmask, regno - FP_REG_FIRST)) 4183*61768Sbostic { 4184*61768Sbostic if (file == (FILE *)0) 4185*61768Sbostic { 4186*61768Sbostic rtx reg_rtx = gen_rtx (REG, DFmode, regno); 4187*61768Sbostic rtx mem_rtx = gen_rtx (MEM, DFmode, 4188*61768Sbostic gen_rtx (PLUS, Pmode, base_reg_rtx, 4189*61768Sbostic GEN_INT (fp_offset - base_offset))); 4190*61768Sbostic 4191*61768Sbostic if (store_p) 4192*61768Sbostic emit_move_insn (mem_rtx, reg_rtx); 4193*61768Sbostic else 4194*61768Sbostic emit_move_insn (reg_rtx, mem_rtx); 4195*61768Sbostic } 4196*61768Sbostic else 4197*61768Sbostic fprintf (file, "\t%s\t%s,%ld(%s)\n", 4198*61768Sbostic (store_p) ? "s.d" : "l.d", 4199*61768Sbostic reg_names[regno], 4200*61768Sbostic fp_offset - base_offset, 4201*61768Sbostic reg_names[REGNO(base_reg_rtx)]); 4202*61768Sbostic 4203*61768Sbostic 4204*61768Sbostic fp_offset -= 2*UNITS_PER_WORD; 4205*61768Sbostic } 4206*61768Sbostic } 4207*61768Sbostic } 4208*61768Sbostic } 4209*61768Sbostic 4210*61768Sbostic 4211*61768Sbostic /* Set up the stack and frame (if desired) for the function. */ 4212*61768Sbostic 4213*61768Sbostic void 4214*61768Sbostic function_prologue (file, size) 4215*61768Sbostic FILE *file; 4216*61768Sbostic int size; 4217*61768Sbostic { 4218*61768Sbostic long tsize = current_frame_info.total_size; 4219*61768Sbostic 4220*61768Sbostic ASM_OUTPUT_SOURCE_FILENAME (file, DECL_SOURCE_FILE (current_function_decl)); 4221*61768Sbostic 4222*61768Sbostic if (debug_info_level != DINFO_LEVEL_TERSE) 4223*61768Sbostic ASM_OUTPUT_SOURCE_LINE (file, DECL_SOURCE_LINE (current_function_decl)); 4224*61768Sbostic 4225*61768Sbostic inside_function = 1; 4226*61768Sbostic fputs ("\t.ent\t", file); 4227*61768Sbostic assemble_name (file, current_function_name); 4228*61768Sbostic fputs ("\n", file); 4229*61768Sbostic 4230*61768Sbostic assemble_name (file, current_function_name); 4231*61768Sbostic fputs (":\n", file); 4232*61768Sbostic 4233*61768Sbostic if (TARGET_ABICALLS) 4234*61768Sbostic fprintf (file, 4235*61768Sbostic "\t.set\tnoreorder\n\t.cpload\t%s\n\t.set\treorder\n", 4236*61768Sbostic reg_names[ GP_REG_FIRST + 25 ]); 4237*61768Sbostic 4238*61768Sbostic tsize = current_frame_info.total_size; 4239*61768Sbostic if (tsize > 0 && TARGET_ABICALLS) 4240*61768Sbostic fprintf (file, "\t.cprestore %d\n", tsize + STARTING_FRAME_OFFSET); 4241*61768Sbostic 4242*61768Sbostic fprintf (file, "\t.frame\t%s,%d,%s\t\t# vars= %d, regs= %d/%d, args = %d, extra= %d\n", 4243*61768Sbostic reg_names[ (frame_pointer_needed) ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM ], 4244*61768Sbostic tsize, 4245*61768Sbostic reg_names[31 + GP_REG_FIRST], 4246*61768Sbostic current_frame_info.var_size, 4247*61768Sbostic current_frame_info.num_gp, 4248*61768Sbostic current_frame_info.num_fp, 4249*61768Sbostic current_function_outgoing_args_size, 4250*61768Sbostic current_frame_info.extra_size); 4251*61768Sbostic 4252*61768Sbostic fprintf (file, "\t.mask\t0x%08lx,%d\n\t.fmask\t0x%08lx,%d\n", 4253*61768Sbostic current_frame_info.mask, 4254*61768Sbostic current_frame_info.gp_save_offset, 4255*61768Sbostic current_frame_info.fmask, 4256*61768Sbostic current_frame_info.fp_save_offset); 4257*61768Sbostic } 4258*61768Sbostic 4259*61768Sbostic 4260*61768Sbostic /* Expand the prologue into a bunch of separate insns. */ 4261*61768Sbostic 4262*61768Sbostic void 4263*61768Sbostic mips_expand_prologue () 4264*61768Sbostic { 4265*61768Sbostic int regno; 4266*61768Sbostic long tsize; 4267*61768Sbostic rtx tmp_rtx = (rtx)0; 4268*61768Sbostic char *arg_name = (char *)0; 4269*61768Sbostic tree fndecl = current_function_decl; 4270*61768Sbostic tree fntype = TREE_TYPE (fndecl); 4271*61768Sbostic tree fnargs = (TREE_CODE (fntype) != METHOD_TYPE) 4272*61768Sbostic ? DECL_ARGUMENTS (fndecl) 4273*61768Sbostic : 0; 4274*61768Sbostic rtx next_arg_reg; 4275*61768Sbostic int i; 4276*61768Sbostic tree next_arg; 4277*61768Sbostic tree cur_arg; 4278*61768Sbostic CUMULATIVE_ARGS args_so_far; 4279*61768Sbostic 4280*61768Sbostic /* Determine the last argument, and get its name. */ 4281*61768Sbostic 4282*61768Sbostic INIT_CUMULATIVE_ARGS (args_so_far, fntype, (rtx)0); 4283*61768Sbostic regno = GP_ARG_FIRST; 4284*61768Sbostic 4285*61768Sbostic for (cur_arg = fnargs; cur_arg != (tree)0; cur_arg = next_arg) 4286*61768Sbostic { 4287*61768Sbostic tree type = DECL_ARG_TYPE (cur_arg); 4288*61768Sbostic enum machine_mode passed_mode = TYPE_MODE (type); 4289*61768Sbostic rtx entry_parm = FUNCTION_ARG (args_so_far, 4290*61768Sbostic passed_mode, 4291*61768Sbostic DECL_ARG_TYPE (cur_arg), 4292*61768Sbostic 1); 4293*61768Sbostic 4294*61768Sbostic if (entry_parm) 4295*61768Sbostic { 4296*61768Sbostic int words; 4297*61768Sbostic 4298*61768Sbostic /* passed in a register, so will get homed automatically */ 4299*61768Sbostic if (GET_MODE (entry_parm) == BLKmode) 4300*61768Sbostic words = (int_size_in_bytes (type) + 3) / 4; 4301*61768Sbostic else 4302*61768Sbostic words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4; 4303*61768Sbostic 4304*61768Sbostic regno = REGNO (entry_parm) + words - 1; 4305*61768Sbostic } 4306*61768Sbostic else 4307*61768Sbostic { 4308*61768Sbostic regno = GP_ARG_LAST+1; 4309*61768Sbostic break; 4310*61768Sbostic } 4311*61768Sbostic 4312*61768Sbostic FUNCTION_ARG_ADVANCE (args_so_far, 4313*61768Sbostic passed_mode, 4314*61768Sbostic DECL_ARG_TYPE (cur_arg), 4315*61768Sbostic 1); 4316*61768Sbostic 4317*61768Sbostic next_arg = TREE_CHAIN (cur_arg); 4318*61768Sbostic if (next_arg == (tree)0) 4319*61768Sbostic { 4320*61768Sbostic if (DECL_NAME (cur_arg)) 4321*61768Sbostic arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg)); 4322*61768Sbostic 4323*61768Sbostic break; 4324*61768Sbostic } 4325*61768Sbostic } 4326*61768Sbostic 4327*61768Sbostic /* In order to pass small structures by value in registers 4328*61768Sbostic compatibly with the MIPS compiler, we need to shift the value 4329*61768Sbostic into the high part of the register. Function_arg has encoded a 4330*61768Sbostic PARALLEL rtx, holding a vector of adjustments to be made as the 4331*61768Sbostic next_arg_reg variable, so we split up the insns, and emit them 4332*61768Sbostic separately. */ 4333*61768Sbostic 4334*61768Sbostic next_arg_reg = FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1); 4335*61768Sbostic if (next_arg_reg != (rtx)0 && GET_CODE (next_arg_reg) == PARALLEL) 4336*61768Sbostic { 4337*61768Sbostic rtvec adjust = XVEC (next_arg_reg, 0); 4338*61768Sbostic int num = GET_NUM_ELEM (adjust); 4339*61768Sbostic 4340*61768Sbostic for (i = 0; i < num; i++) 4341*61768Sbostic { 4342*61768Sbostic rtx pattern = RTVEC_ELT (adjust, i); 4343*61768Sbostic if (GET_CODE (pattern) != SET 4344*61768Sbostic || GET_CODE (SET_SRC (pattern)) != ASHIFT) 4345*61768Sbostic abort_with_insn (pattern, "Insn is not a shift"); 4346*61768Sbostic 4347*61768Sbostic PUT_CODE (SET_SRC (pattern), ASHIFTRT); 4348*61768Sbostic emit_insn (pattern); 4349*61768Sbostic } 4350*61768Sbostic } 4351*61768Sbostic 4352*61768Sbostic /* If this function is a varargs function, store any registers that 4353*61768Sbostic would normally hold arguments ($4 - $7) on the stack. */ 4354*61768Sbostic if ((TYPE_ARG_TYPES (fntype) != 0 4355*61768Sbostic && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node)) 4356*61768Sbostic || (arg_name != (char *)0 4357*61768Sbostic && ((arg_name[0] == '_' && strcmp (arg_name, "__builtin_va_alist") == 0) 4358*61768Sbostic || (arg_name[0] == 'v' && strcmp (arg_name, "va_alist") == 0)))) 4359*61768Sbostic { 4360*61768Sbostic for (; regno <= GP_ARG_LAST; regno++) 4361*61768Sbostic { 4362*61768Sbostic rtx ptr = stack_pointer_rtx; 4363*61768Sbostic if (regno != GP_ARG_FIRST) 4364*61768Sbostic ptr = gen_rtx (PLUS, Pmode, ptr, 4365*61768Sbostic GEN_INT ((regno - GP_ARG_FIRST) * UNITS_PER_WORD)); 4366*61768Sbostic 4367*61768Sbostic emit_move_insn (gen_rtx (MEM, Pmode, ptr), gen_rtx (REG, Pmode, regno)); 4368*61768Sbostic } 4369*61768Sbostic } 4370*61768Sbostic 4371*61768Sbostic tsize = compute_frame_size (get_frame_size ()); 4372*61768Sbostic if (tsize > 0) 4373*61768Sbostic { 4374*61768Sbostic rtx tsize_rtx = GEN_INT (tsize); 4375*61768Sbostic 4376*61768Sbostic if (tsize > 32767) 4377*61768Sbostic { 4378*61768Sbostic tmp_rtx = gen_rtx (REG, SImode, MIPS_TEMP1_REGNUM); 4379*61768Sbostic emit_move_insn (tmp_rtx, tsize_rtx); 4380*61768Sbostic tsize_rtx = tmp_rtx; 4381*61768Sbostic } 4382*61768Sbostic 4383*61768Sbostic emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tsize_rtx)); 4384*61768Sbostic 4385*61768Sbostic save_restore_insns (TRUE, tmp_rtx, tsize, (FILE *)0); 4386*61768Sbostic 4387*61768Sbostic if (frame_pointer_needed) 4388*61768Sbostic emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx)); 4389*61768Sbostic } 4390*61768Sbostic 4391*61768Sbostic /* If we are profiling, make sure no instructions are scheduled before 4392*61768Sbostic the call to mcount. */ 4393*61768Sbostic 4394*61768Sbostic if (profile_flag || profile_block_flag) 4395*61768Sbostic emit_insn (gen_blockage ()); 4396*61768Sbostic } 4397*61768Sbostic 4398*61768Sbostic 4399*61768Sbostic /* Do any necessary cleanup after a function to restore stack, frame, and regs. */ 4400*61768Sbostic 4401*61768Sbostic void 4402*61768Sbostic function_epilogue (file, size) 4403*61768Sbostic FILE *file; 4404*61768Sbostic int size; 4405*61768Sbostic { 4406*61768Sbostic long tsize; 4407*61768Sbostic char *sp_str = reg_names[STACK_POINTER_REGNUM]; 4408*61768Sbostic char *t1_str = reg_names[MIPS_TEMP1_REGNUM]; 4409*61768Sbostic rtx epilogue_delay = current_function_epilogue_delay_list; 4410*61768Sbostic int noreorder = !TARGET_MIPS_AS || (epilogue_delay != 0); 4411*61768Sbostic int noepilogue = FALSE; 4412*61768Sbostic int load_nop = FALSE; 4413*61768Sbostic int load_only_r31; 4414*61768Sbostic rtx tmp_rtx = (rtx)0; 4415*61768Sbostic rtx restore_rtx; 4416*61768Sbostic int i; 4417*61768Sbostic 4418*61768Sbostic /* The epilogue does not depend on any registers, but the stack 4419*61768Sbostic registers, so we assume that if we have 1 pending nop, it can be 4420*61768Sbostic ignored, and 2 it must be filled (2 nops occur for integer 4421*61768Sbostic multiply and divide). */ 4422*61768Sbostic 4423*61768Sbostic if (dslots_number_nops > 0) 4424*61768Sbostic { 4425*61768Sbostic if (dslots_number_nops == 1) 4426*61768Sbostic { 4427*61768Sbostic dslots_number_nops = 0; 4428*61768Sbostic dslots_load_filled++; 4429*61768Sbostic } 4430*61768Sbostic else 4431*61768Sbostic { 4432*61768Sbostic while (--dslots_number_nops > 0) 4433*61768Sbostic fputs ((set_noreorder) ? "\tnop\n" : "\t#nop\n", asm_out_file); 4434*61768Sbostic } 4435*61768Sbostic 4436*61768Sbostic if (set_noreorder > 0 && --set_noreorder == 0) 4437*61768Sbostic fputs ("\t.set\treorder\n", file); 4438*61768Sbostic } 4439*61768Sbostic 4440*61768Sbostic if (set_noat != 0) 4441*61768Sbostic { 4442*61768Sbostic set_noat = 0; 4443*61768Sbostic fputs ("\t.set\tat\n", file); 4444*61768Sbostic error ("internal gcc error: .set noat left on in epilogue"); 4445*61768Sbostic } 4446*61768Sbostic 4447*61768Sbostic if (set_nomacro != 0) 4448*61768Sbostic { 4449*61768Sbostic set_nomacro = 0; 4450*61768Sbostic fputs ("\t.set\tmacro\n", file); 4451*61768Sbostic error ("internal gcc error: .set nomacro left on in epilogue"); 4452*61768Sbostic } 4453*61768Sbostic 4454*61768Sbostic if (set_noreorder != 0) 4455*61768Sbostic { 4456*61768Sbostic set_noreorder = 0; 4457*61768Sbostic fputs ("\t.set\treorder\n", file); 4458*61768Sbostic error ("internal gcc error: .set noreorder left on in epilogue"); 4459*61768Sbostic } 4460*61768Sbostic 4461*61768Sbostic if (set_volatile != 0) 4462*61768Sbostic { 4463*61768Sbostic set_volatile = 0; 4464*61768Sbostic fprintf (file, "\t#.set\tnovolatile\n", (TARGET_MIPS_AS) ? "" : "#"); 4465*61768Sbostic error ("internal gcc error: .set volatile left on in epilogue"); 4466*61768Sbostic } 4467*61768Sbostic 4468*61768Sbostic size = MIPS_STACK_ALIGN (size); 4469*61768Sbostic tsize = (!current_frame_info.initialized) 4470*61768Sbostic ? compute_frame_size (size) 4471*61768Sbostic : current_frame_info.total_size; 4472*61768Sbostic 4473*61768Sbostic if (tsize == 0 && epilogue_delay == 0) 4474*61768Sbostic { 4475*61768Sbostic rtx insn = get_last_insn (); 4476*61768Sbostic 4477*61768Sbostic /* If the last insn was a BARRIER, we don't have to write any code 4478*61768Sbostic because a jump (aka return) was put there. */ 4479*61768Sbostic if (GET_CODE (insn) == NOTE) 4480*61768Sbostic insn = prev_nonnote_insn (insn); 4481*61768Sbostic if (insn && GET_CODE (insn) == BARRIER) 4482*61768Sbostic noepilogue = TRUE; 4483*61768Sbostic 4484*61768Sbostic noreorder = FALSE; 4485*61768Sbostic } 4486*61768Sbostic 4487*61768Sbostic if (!noepilogue) 4488*61768Sbostic { 4489*61768Sbostic /* In the reload sequence, we don't need to fill the load delay 4490*61768Sbostic slots for most of the loads, also see if we can fill the final 4491*61768Sbostic delay slot if not otherwise filled by the reload sequence. */ 4492*61768Sbostic 4493*61768Sbostic if (noreorder) 4494*61768Sbostic fprintf (file, "\t.set\tnoreorder\n"); 4495*61768Sbostic 4496*61768Sbostic if (tsize > 32767) 4497*61768Sbostic { 4498*61768Sbostic fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n", t1_str, (long)tsize, (long)tsize); 4499*61768Sbostic tmp_rtx = gen_rtx (REG, Pmode, MIPS_TEMP1_REGNUM); 4500*61768Sbostic } 4501*61768Sbostic 4502*61768Sbostic if (frame_pointer_needed) 4503*61768Sbostic fprintf (file, "\tmove\t%s,%s\t\t\t# sp not trusted here\n", 4504*61768Sbostic sp_str, reg_names[FRAME_POINTER_REGNUM]); 4505*61768Sbostic 4506*61768Sbostic save_restore_insns (FALSE, tmp_rtx, tsize, file); 4507*61768Sbostic 4508*61768Sbostic load_only_r31 = (current_frame_info.mask == (1 << 31) 4509*61768Sbostic && current_frame_info.fmask == 0); 4510*61768Sbostic 4511*61768Sbostic if (noreorder) 4512*61768Sbostic { 4513*61768Sbostic /* If the only register saved is the return address, we need a 4514*61768Sbostic nop, unless we have an instruction to put into it. Otherwise 4515*61768Sbostic we don't since reloading multiple registers doesn't reference 4516*61768Sbostic the register being loaded. */ 4517*61768Sbostic 4518*61768Sbostic if (load_only_r31) 4519*61768Sbostic { 4520*61768Sbostic if (epilogue_delay) 4521*61768Sbostic final_scan_insn (XEXP (epilogue_delay, 0), 4522*61768Sbostic file, 4523*61768Sbostic 1, /* optimize */ 4524*61768Sbostic -2, /* prescan */ 4525*61768Sbostic 1); /* nopeepholes */ 4526*61768Sbostic else 4527*61768Sbostic { 4528*61768Sbostic fprintf (file, "\tnop\n"); 4529*61768Sbostic load_nop = TRUE; 4530*61768Sbostic } 4531*61768Sbostic } 4532*61768Sbostic 4533*61768Sbostic fprintf (file, "\tj\t%s\n", reg_names[GP_REG_FIRST + 31]); 4534*61768Sbostic 4535*61768Sbostic if (tsize > 32767) 4536*61768Sbostic fprintf (file, "\taddu\t%s,%s,%s\n", sp_str, sp_str, t1_str); 4537*61768Sbostic 4538*61768Sbostic else if (tsize > 0) 4539*61768Sbostic fprintf (file, "\taddu\t%s,%s,%d\n", sp_str, sp_str, tsize); 4540*61768Sbostic 4541*61768Sbostic else if (!load_only_r31 && epilogue_delay != 0) 4542*61768Sbostic final_scan_insn (XEXP (epilogue_delay, 0), 4543*61768Sbostic file, 4544*61768Sbostic 1, /* optimize */ 4545*61768Sbostic -2, /* prescan */ 4546*61768Sbostic 1); /* nopeepholes */ 4547*61768Sbostic 4548*61768Sbostic fprintf (file, "\t.set\treorder\n"); 4549*61768Sbostic } 4550*61768Sbostic 4551*61768Sbostic else 4552*61768Sbostic { 4553*61768Sbostic if (tsize > 32767) 4554*61768Sbostic fprintf (file, "\taddu\t%s,%s,%s\n", sp_str, sp_str, t1_str); 4555*61768Sbostic 4556*61768Sbostic else if (tsize > 0) 4557*61768Sbostic fprintf (file, "\taddu\t%s,%s,%d\n", sp_str, sp_str, tsize); 4558*61768Sbostic 4559*61768Sbostic fprintf (file, "\tj\t%s\n", reg_names[GP_REG_FIRST + 31]); 4560*61768Sbostic } 4561*61768Sbostic } 4562*61768Sbostic 4563*61768Sbostic fputs ("\t.end\t", file); 4564*61768Sbostic assemble_name (file, current_function_name); 4565*61768Sbostic fputs ("\n", file); 4566*61768Sbostic 4567*61768Sbostic if (TARGET_STATS) 4568*61768Sbostic { 4569*61768Sbostic int num_gp_regs = current_frame_info.gp_reg_size / 4; 4570*61768Sbostic int num_fp_regs = current_frame_info.fp_reg_size / 8; 4571*61768Sbostic int num_regs = num_gp_regs + num_fp_regs; 4572*61768Sbostic char *name = current_function_name; 4573*61768Sbostic 4574*61768Sbostic if (name[0] == '*') 4575*61768Sbostic name++; 4576*61768Sbostic 4577*61768Sbostic dslots_load_total += num_regs; 4578*61768Sbostic 4579*61768Sbostic if (!noepilogue) 4580*61768Sbostic dslots_jump_total++; 4581*61768Sbostic 4582*61768Sbostic if (noreorder) 4583*61768Sbostic { 4584*61768Sbostic dslots_load_filled += num_regs; 4585*61768Sbostic 4586*61768Sbostic /* If the only register saved is the return register, we 4587*61768Sbostic can't fill this register's delay slot. */ 4588*61768Sbostic 4589*61768Sbostic if (load_only_r31 && epilogue_delay == 0) 4590*61768Sbostic dslots_load_filled--; 4591*61768Sbostic 4592*61768Sbostic if (tsize > 0 || (!load_only_r31 && epilogue_delay != 0)) 4593*61768Sbostic dslots_jump_filled++; 4594*61768Sbostic } 4595*61768Sbostic 4596*61768Sbostic fprintf (stderr, 4597*61768Sbostic "%-20s fp=%c leaf=%c alloca=%c setjmp=%c stack=%4ld arg=%3ld reg=%2d/%d delay=%3d/%3dL %3d/%3dJ refs=%3d/%3d/%3d", 4598*61768Sbostic name, 4599*61768Sbostic (frame_pointer_needed) ? 'y' : 'n', 4600*61768Sbostic ((current_frame_info.mask & (1 << 31)) != 0) ? 'n' : 'y', 4601*61768Sbostic (current_function_calls_alloca) ? 'y' : 'n', 4602*61768Sbostic (current_function_calls_setjmp) ? 'y' : 'n', 4603*61768Sbostic (long)current_frame_info.total_size, 4604*61768Sbostic (long)current_function_outgoing_args_size, 4605*61768Sbostic num_gp_regs, num_fp_regs, 4606*61768Sbostic dslots_load_total, dslots_load_filled, 4607*61768Sbostic dslots_jump_total, dslots_jump_filled, 4608*61768Sbostic num_refs[0], num_refs[1], num_refs[2]); 4609*61768Sbostic 4610*61768Sbostic if (HALF_PIC_NUMBER_PTRS > prev_half_pic_ptrs) 4611*61768Sbostic { 4612*61768Sbostic fprintf (stderr, " half-pic=%3d", HALF_PIC_NUMBER_PTRS - prev_half_pic_ptrs); 4613*61768Sbostic prev_half_pic_ptrs = HALF_PIC_NUMBER_PTRS; 4614*61768Sbostic } 4615*61768Sbostic 4616*61768Sbostic if (HALF_PIC_NUMBER_REFS > prev_half_pic_refs) 4617*61768Sbostic { 4618*61768Sbostic fprintf (stderr, " pic-ref=%3d", HALF_PIC_NUMBER_REFS - prev_half_pic_refs); 4619*61768Sbostic prev_half_pic_refs = HALF_PIC_NUMBER_REFS; 4620*61768Sbostic } 4621*61768Sbostic 4622*61768Sbostic fputc ('\n', stderr); 4623*61768Sbostic } 4624*61768Sbostic 4625*61768Sbostic /* Reset state info for each function. */ 4626*61768Sbostic inside_function = FALSE; 4627*61768Sbostic ignore_line_number = FALSE; 4628*61768Sbostic dslots_load_total = 0; 4629*61768Sbostic dslots_jump_total = 0; 4630*61768Sbostic dslots_load_filled = 0; 4631*61768Sbostic dslots_jump_filled = 0; 4632*61768Sbostic num_refs[0] = 0; 4633*61768Sbostic num_refs[1] = 0; 4634*61768Sbostic num_refs[2] = 0; 4635*61768Sbostic mips_load_reg = (rtx)0; 4636*61768Sbostic mips_load_reg2 = (rtx)0; 4637*61768Sbostic current_frame_info = zero_frame_info; 4638*61768Sbostic 4639*61768Sbostic /* Restore the output file if optimizing the GP (optimizing the GP causes 4640*61768Sbostic the text to be diverted to a tempfile, so that data decls come before 4641*61768Sbostic references to the data). */ 4642*61768Sbostic 4643*61768Sbostic if (TARGET_GP_OPT) 4644*61768Sbostic asm_out_file = asm_out_data_file; 4645*61768Sbostic } 4646*61768Sbostic 4647*61768Sbostic 4648*61768Sbostic /* Expand the epilogue into a bunch of separate insns. */ 4649*61768Sbostic 4650*61768Sbostic void 4651*61768Sbostic mips_expand_epilogue () 4652*61768Sbostic { 4653*61768Sbostic long tsize = current_frame_info.total_size; 4654*61768Sbostic rtx tsize_rtx = GEN_INT (tsize); 4655*61768Sbostic rtx tmp_rtx = (rtx)0; 4656*61768Sbostic 4657*61768Sbostic if (tsize > 32767) 4658*61768Sbostic { 4659*61768Sbostic tmp_rtx = gen_rtx (REG, SImode, MIPS_TEMP1_REGNUM); 4660*61768Sbostic emit_move_insn (tmp_rtx, tsize_rtx); 4661*61768Sbostic tsize_rtx = tmp_rtx; 4662*61768Sbostic } 4663*61768Sbostic 4664*61768Sbostic if (tsize > 0) 4665*61768Sbostic { 4666*61768Sbostic if (frame_pointer_needed) 4667*61768Sbostic emit_insn (gen_movsi (stack_pointer_rtx, frame_pointer_rtx)); 4668*61768Sbostic 4669*61768Sbostic save_restore_insns (FALSE, tmp_rtx, tsize, (FILE *)0); 4670*61768Sbostic 4671*61768Sbostic emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, tsize_rtx)); 4672*61768Sbostic } 4673*61768Sbostic 4674*61768Sbostic emit_jump_insn (gen_return_internal (gen_rtx (REG, Pmode, GP_REG_FIRST+31))); 4675*61768Sbostic } 4676*61768Sbostic 4677*61768Sbostic 4678*61768Sbostic /* Define the number of delay slots needed for the function epilogue. 4679*61768Sbostic 4680*61768Sbostic On the mips, we need a slot if either no stack has been allocated, 4681*61768Sbostic or the only register saved is the return register. */ 4682*61768Sbostic 4683*61768Sbostic int 4684*61768Sbostic mips_epilogue_delay_slots () 4685*61768Sbostic { 4686*61768Sbostic if (!current_frame_info.initialized) 4687*61768Sbostic (void) compute_frame_size (get_frame_size ()); 4688*61768Sbostic 4689*61768Sbostic if (current_frame_info.total_size == 0) 4690*61768Sbostic return 1; 4691*61768Sbostic 4692*61768Sbostic if (current_frame_info.mask == (1 << 31) && current_frame_info.fmask == 0) 4693*61768Sbostic return 1; 4694*61768Sbostic 4695*61768Sbostic return 0; 4696*61768Sbostic } 4697*61768Sbostic 4698*61768Sbostic 4699*61768Sbostic /* Return true if this function is known to have a null epilogue. 4700*61768Sbostic This allows the optimizer to omit jumps to jumps if no stack 4701*61768Sbostic was created. */ 4702*61768Sbostic 4703*61768Sbostic int 4704*61768Sbostic simple_epilogue_p () 4705*61768Sbostic { 4706*61768Sbostic if (!reload_completed) 4707*61768Sbostic return 0; 4708*61768Sbostic 4709*61768Sbostic if (current_frame_info.initialized) 4710*61768Sbostic return current_frame_info.total_size == 0; 4711*61768Sbostic 4712*61768Sbostic return (compute_frame_size (get_frame_size ())) == 0; 4713*61768Sbostic } 4714