|
|
1.1 ! root 1: /* Subroutines for insn-output.c for Clipper ! 2: Copyright (C) 1987, 1988, 1991 Free Software Foundation, Inc. ! 3: ! 4: Contributed by Holger Teutsch ([email protected]) ! 5: ! 6: This file is part of GNU CC. ! 7: ! 8: GNU CC is free software; you can redistribute it and/or modify ! 9: it under the terms of the GNU General Public License as published by ! 10: the Free Software Foundation; either version 2, or (at your option) ! 11: any later version. ! 12: ! 13: GNU CC is distributed in the hope that it will be useful, ! 14: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 15: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 16: GNU General Public License for more details. ! 17: ! 18: You should have received a copy of the GNU General Public License ! 19: along with GNU CC; see the file COPYING. If not, write to ! 20: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 21: ! 22: #include <stdio.h> ! 23: #include "config.h" ! 24: #include "rtl.h" ! 25: #include "regs.h" ! 26: #include "hard-reg-set.h" ! 27: #include "real.h" ! 28: #include "insn-config.h" ! 29: #include "conditions.h" ! 30: #include "insn-flags.h" ! 31: #include "output.h" ! 32: #include "insn-attr.h" ! 33: #include "tree.h" ! 34: #include "c-tree.h" ! 35: #include "expr.h" ! 36: #include "flags.h" ! 37: #include "machmode.h" ! 38: ! 39: extern char regs_ever_live[]; ! 40: ! 41: extern int frame_pointer_needed; ! 42: ! 43: static int frame_size; ! 44: ! 45: /* ! 46: * compute size of a clipper stack frame where 'lsize' is the required ! 47: * space for local variables. ! 48: */ ! 49: ! 50: int ! 51: clipper_frame_size (lsize) ! 52: int lsize; ! 53: { ! 54: int i,size; /* total size of frame */ ! 55: int save_size; ! 56: save_size = 0; /* compute size for reg saves */ ! 57: ! 58: for (i = 16; i < 32; i++) ! 59: if (regs_ever_live[i] && !call_used_regs[i]) ! 60: save_size += 8; ! 61: ! 62: for (i = 0; i < 16; i++) ! 63: if (regs_ever_live[i] && !call_used_regs[i]) ! 64: save_size += 4; ! 65: ! 66: size = lsize + save_size; ! 67: ! 68: size = (size + 7) & ~7; /* align to 64 Bit */ ! 69: return size; ! 70: } ! 71: ! 72: /* ! 73: * prologue and epilogue output ! 74: * function is entered with pc pushed, i.e. stack is 32 bit aligned ! 75: * ! 76: * current_function_args_size == 0 means that the current function's args ! 77: * are passed totally in registers i.e fp is not used as ap. ! 78: * If frame_size is also 0 the current function does not push anything and ! 79: * can run with misaligned stack -> subq $4,sp / add $4,sp on entry and exit ! 80: * can be omitted. ! 81: * ! 82: */ ! 83: void ! 84: output_function_prologue (file, lsize) ! 85: FILE *file; ! 86: int lsize; /* size for locals */ ! 87: { ! 88: int i, offset; ! 89: int size; ! 90: ! 91: frame_size = size = clipper_frame_size (lsize); ! 92: ! 93: if (frame_pointer_needed) ! 94: { ! 95: fputs ("\tpushw fp,sp\n", file); ! 96: fputs ("\tmovw sp,fp\n", file); ! 97: } ! 98: else if (size != 0 || current_function_args_size != 0) ! 99: { ! 100: size += 4; /* keep stack aligned */ ! 101: frame_size = size; /* must push data or access args */ ! 102: } ! 103: ! 104: if (size) ! 105: { ! 106: if (size < 16) ! 107: fprintf (file, "\tsubq $%d,sp\n", size); ! 108: else ! 109: fprintf (file, "\tsubi $%d,sp\n", size); ! 110: ! 111: /* register save slots are relative to sp, because we have small positive ! 112: displacements and this works whether we have a frame pointer or not */ ! 113: ! 114: offset = 0; ! 115: for (i = 16; i < 32; i++) ! 116: if (regs_ever_live[i] && !call_used_regs[i]) ! 117: { ! 118: if (offset == 0) ! 119: fprintf (file, "\tstord f%d,(sp)\n", i-16); ! 120: else ! 121: fprintf (file, "\tstord f%d,%d(sp)\n", i-16, offset); ! 122: offset += 8; ! 123: } ! 124: ! 125: for (i = 0; i < 16; i++) ! 126: if (regs_ever_live[i] && !call_used_regs[i]) ! 127: { ! 128: if (offset == 0) ! 129: fprintf (file, "\tstorw r%d,(sp)\n", i); ! 130: else ! 131: fprintf (file, "\tstorw r%d,%d(sp)\n", i, offset); ! 132: offset += 4; ! 133: } ! 134: } ! 135: } ! 136: ! 137: void ! 138: output_function_epilogue (file, size) ! 139: FILE *file; ! 140: int size; /* ignored */ ! 141: { ! 142: int i, offset; ! 143: ! 144: if (frame_pointer_needed) ! 145: { ! 146: offset = -frame_size; ! 147: ! 148: for (i = 16; i < 32; i++) ! 149: if (regs_ever_live[i] && !call_used_regs[i]) ! 150: { ! 151: fprintf (file, "\tloadd %d(fp),f%d\n", offset, i-16); ! 152: offset += 8; ! 153: } ! 154: ! 155: for (i = 0; i < 16; i++) ! 156: if (regs_ever_live[i] && !call_used_regs[i]) ! 157: { ! 158: fprintf (file, "\tloadw %d(fp),r%d\n", offset, i); ! 159: offset += 4; ! 160: } ! 161: ! 162: fputs ("\tmovw fp,sp\n\tpopw sp,fp\n\tret sp\n", ! 163: file); ! 164: } ! 165: ! 166: else /* no frame pointer */ ! 167: { ! 168: offset = 0; ! 169: ! 170: for (i = 16; i < 32; i++) ! 171: if (regs_ever_live[i] && !call_used_regs[i]) ! 172: { ! 173: if (offset == 0) ! 174: fprintf (file, "\tloadd (sp),f%d\n", i-16); ! 175: else ! 176: fprintf (file, "\tloadd %d(sp),f%d\n", offset, i-16); ! 177: offset += 8; ! 178: } ! 179: ! 180: for (i = 0; i < 16; i++) ! 181: if (regs_ever_live[i] && !call_used_regs[i]) ! 182: { ! 183: if (offset == 0) ! 184: fprintf (file, "\tloadw (sp),r%d\n", i); ! 185: else ! 186: fprintf (file, "\tloadw %d(sp),r%d\n", offset, i); ! 187: offset += 4; ! 188: } ! 189: ! 190: if (frame_size > 0) ! 191: { ! 192: if (frame_size < 16) ! 193: fprintf (file, "\taddq $%d,sp\n", frame_size); ! 194: else ! 195: fprintf (file, "\taddi $%d,sp\n", frame_size); ! 196: } ! 197: ! 198: fputs ("\tret sp\n", file); ! 199: } ! 200: } ! 201: ! 202: /* ! 203: * blockmove ! 204: * ! 205: * clipper_movstr () ! 206: */ ! 207: void ! 208: clipper_movstr (operands) ! 209: rtx *operands; ! 210: { ! 211: rtx dst,src,cnt,tmp,top,bottom,xops[3]; ! 212: int align; ! 213: int fixed; ! 214: ! 215: extern FILE *asm_out_file; ! 216: ! 217: dst = operands[0]; ! 218: src = operands[1]; ! 219: /* don't change this operands[2]; gcc 2.3.3 doesn't honor clobber note */ ! 220: align = INTVAL (operands[3]); ! 221: tmp = operands[4]; ! 222: cnt = operands[5]; ! 223: ! 224: if (GET_CODE (operands[2]) == CONST_INT) /* fixed size move */ ! 225: { ! 226: if ((fixed = INTVAL (operands[2])) <= 0) ! 227: abort (); ! 228: ! 229: if (fixed <16) ! 230: output_asm_insn ("loadq %2,%5", operands); ! 231: else ! 232: output_asm_insn ("loadi %2,%5", operands); ! 233: } ! 234: else ! 235: { ! 236: fixed = 0; ! 237: bottom = (rtx)gen_label_rtx (); /* need a bottom label */ ! 238: xops[0] = cnt; xops[1] = bottom; ! 239: output_asm_insn ("movw %2,%5", operands); /* count is scratch reg 5 */ ! 240: output_asm_insn ("brle %l1", xops); ! 241: } ! 242: ! 243: ! 244: top = (rtx)gen_label_rtx (); /* top of loop label */ ! 245: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (top)); ! 246: ! 247: ! 248: xops[0] = src; xops[1] = tmp; xops[2] = dst; ! 249: ! 250: if (fixed && (align & 0x3) == 0) /* word aligned move with known size */ ! 251: { ! 252: if (fixed >= 4) ! 253: { ! 254: rtx xops1[2]; ! 255: output_asm_insn( ! 256: "loadw %a0,%1\n\taddq $4,%0\n\tstorw %1,%a2\n\taddq $4,%2", ! 257: xops); ! 258: ! 259: xops1[0] = cnt; xops1[1] = top; ! 260: output_asm_insn ("subq $4,%0\n\tbrgt %l1", xops1); ! 261: } ! 262: ! 263: if (fixed & 0x2) ! 264: { ! 265: output_asm_insn ("loadh %a0,%1\n\tstorh %1,%a2", xops); ! 266: if (fixed & 0x1) ! 267: output_asm_insn ("loadb 2%a0,%1\n\tstorb %1,2%a2", xops); ! 268: } ! 269: else ! 270: if (fixed & 0x1) ! 271: output_asm_insn ("loadb %a0,%1\n\tstorb %1,%a2", xops); ! 272: } ! 273: else ! 274: { ! 275: output_asm_insn( ! 276: "loadb %a0,%1\n\taddq $1,%0\n\tstorb %1,%a2\n\taddq $1,%2", ! 277: xops); ! 278: ! 279: xops[0] = cnt; xops[1] = top; ! 280: output_asm_insn ("subq $1,%0\n\tbrgt %l1", xops); ! 281: } ! 282: ! 283: if (fixed == 0) ! 284: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (bottom)); ! 285: } ! 286: ! 287: ! 288: print_operand_address (file, addr) ! 289: FILE *file; ! 290: register rtx addr; ! 291: { ! 292: rtx op0,op1; ! 293: ! 294: retry: ! 295: switch (GET_CODE (addr)) ! 296: { ! 297: case REG: ! 298: fprintf (file, "(%s)", reg_names[REGNO (addr)]); ! 299: break; ! 300: ! 301: case PLUS: ! 302: /* can be 'symbol + reg' or 'reg + reg' */ ! 303: ! 304: op0 = XEXP (addr, 0); ! 305: op1 = XEXP (addr, 1); ! 306: ! 307: if (GET_CODE (op0) == REG && GET_CODE (op1) == REG) ! 308: { ! 309: fprintf (file, "[%s](%s)", ! 310: reg_names[REGNO (op0)], reg_names[REGNO (op1)]); ! 311: break; ! 312: } ! 313: ! 314: if (GET_CODE (op0) == REG && CONSTANT_ADDRESS_P (op1)) ! 315: { ! 316: output_addr_const (file, op1); ! 317: fprintf (file, "(%s)", reg_names[REGNO (op0)]); ! 318: break; ! 319: } ! 320: ! 321: if (GET_CODE (op1) == REG && CONSTANT_ADDRESS_P (op0)) ! 322: { ! 323: output_addr_const (file, op0); ! 324: fprintf (file, "(%s)", reg_names[REGNO (op1)]); ! 325: break; ! 326: } ! 327: abort (); /* Oh no */ ! 328: ! 329: default: ! 330: output_addr_const (file, addr); ! 331: } ! 332: } ! 333: ! 334: ! 335: char * ! 336: rev_cond_name (op) ! 337: rtx op; ! 338: { ! 339: switch (GET_CODE (op)) ! 340: { ! 341: case EQ: ! 342: return "ne"; ! 343: case NE: ! 344: return "eq"; ! 345: case LT: ! 346: return "ge"; ! 347: case LE: ! 348: return "gt"; ! 349: case GT: ! 350: return "le"; ! 351: case GE: ! 352: return "lt"; ! 353: case LTU: ! 354: return "geu"; ! 355: case LEU: ! 356: return "gtu"; ! 357: case GTU: ! 358: return "leu"; ! 359: case GEU: ! 360: return "ltu"; ! 361: ! 362: default: ! 363: abort (); ! 364: } ! 365: } ! 366: ! 367: ! 368: /* Do what is necessary for `va_start'. The argument is ignored; ! 369: We fill in an initial va_list. A pointer to this constructor ! 370: is returned. */ ! 371: ! 372: ! 373: struct rtx_def * ! 374: clipper_builtin_saveregs (arglist) ! 375: tree arglist; ! 376: { ! 377: extern int current_function_varargs; ! 378: rtx block, addr, argsize, scratch, r0_addr,r1_addr,f0_addr,f1_addr; ! 379: ! 380: /* Allocate the va_list constructor + save area for r0,r1,f0,f1 */ ! 381: ! 382: block = assign_stack_local (BLKmode, ! 383: (6 + 6) * UNITS_PER_WORD, 2 * BITS_PER_WORD); ! 384: ! 385: RTX_UNCHANGING_P (block) = 1; ! 386: RTX_UNCHANGING_P (XEXP (block, 0)) = 1; ! 387: ! 388: addr = copy_to_reg (XEXP (block, 0)); ! 389: ! 390: f0_addr = gen_rtx (PLUS, Pmode, addr, gen_rtx (CONST_INT, Pmode, 24)); ! 391: f1_addr = gen_rtx (PLUS, Pmode, addr, gen_rtx (CONST_INT, Pmode, 32)); ! 392: r0_addr = gen_rtx (PLUS, Pmode, addr, gen_rtx (CONST_INT, Pmode, 40)); ! 393: r1_addr = gen_rtx (PLUS, Pmode, addr, gen_rtx (CONST_INT, Pmode, 44)); ! 394: ! 395: ! 396: /* Store float regs */ ! 397: ! 398: emit_move_insn (gen_rtx (MEM, DFmode, f0_addr), gen_rtx (REG, DFmode, 16)); ! 399: emit_move_insn (gen_rtx (MEM, DFmode, f1_addr), gen_rtx (REG, DFmode, 17)); ! 400: ! 401: /* Store int regs */ ! 402: ! 403: emit_move_insn (gen_rtx (MEM, SImode, r0_addr), gen_rtx (REG, SImode, 0)); ! 404: emit_move_insn (gen_rtx (MEM, SImode, r1_addr), gen_rtx (REG, SImode, 1)); ! 405: ! 406: /* Store the arg pointer in the __va_stk member. */ ! 407: ! 408: emit_move_insn (gen_rtx (MEM, SImode, addr), ! 409: copy_to_reg (virtual_incoming_args_rtx)); ! 410: ! 411: ! 412: /* now move addresses of the saved regs into the pointer array */ ! 413: ! 414: scratch = gen_reg_rtx (Pmode); ! 415: ! 416: emit_move_insn (scratch, r0_addr); ! 417: emit_move_insn (gen_rtx (MEM, SImode, ! 418: gen_rtx (PLUS, Pmode, addr, ! 419: gen_rtx (CONST_INT, Pmode, 4))), ! 420: scratch); ! 421: ! 422: emit_move_insn (scratch, f0_addr); ! 423: emit_move_insn (gen_rtx (MEM, SImode, ! 424: gen_rtx (PLUS, Pmode, addr, ! 425: gen_rtx (CONST_INT, Pmode, 8))), ! 426: scratch); ! 427: ! 428: emit_move_insn (scratch, r1_addr); ! 429: emit_move_insn (gen_rtx (MEM, SImode, ! 430: gen_rtx (PLUS, Pmode, addr, ! 431: gen_rtx (CONST_INT, Pmode, 12))), ! 432: scratch); ! 433: ! 434: emit_move_insn (scratch, f1_addr); ! 435: emit_move_insn (gen_rtx (MEM, SImode, ! 436: gen_rtx (PLUS, Pmode, addr, ! 437: gen_rtx (CONST_INT, Pmode, 16))), ! 438: scratch); ! 439: ! 440: /* Return the address of the va_list constructor, but don't put it in a ! 441: register. This fails when not optimizing and produces worse code when ! 442: optimizing. */ ! 443: ! 444: return XEXP (block, 0); ! 445: } ! 446: ! 447: ! 448: /* Return truth value of whether OP can be used as an word register ! 449: operand. Reject (SUBREG:SI (REG:SF )) */ ! 450: ! 451: int ! 452: int_reg_operand (op, mode) ! 453: rtx op; ! 454: enum machine_mode mode; ! 455: { ! 456: return (register_operand (op, mode) && ! 457: (GET_CODE (op) != SUBREG || ! 458: GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) == MODE_INT)); ! 459: } ! 460: ! 461: /* Return truth value of whether OP can be used as a float register ! 462: operand. Reject (SUBREG:SF (REG:SI )) )) */ ! 463: ! 464: int ! 465: fp_reg_operand (op, mode) ! 466: rtx op; ! 467: enum machine_mode mode; ! 468: { ! 469: return (register_operand (op, mode) && ! 470: (GET_CODE (op) != SUBREG || ! 471: GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) == MODE_FLOAT)); ! 472: } ! 473:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.