|
|
1.1 root 1: /* Subroutines for insn-output.c for Hitachi H8/300. 1.1.1.2 ! root 2: Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. ! 3: Contributed by Steve Chamberlain ([email protected]), ! 4: Jim Wilson ([email protected]), and Doug Evans ([email protected]). 1.1 root 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 "flags.h" 34: #include "recog.h" 35: #include "expr.h" 36: #include "tree.h" 37: 38: /* Forward declarations. */ 39: void print_operand_address (); 40: char *index (); 41: 1.1.1.2 ! root 42: /* CPU_TYPE, says what cpu we're compiling for. */ ! 43: int cpu_type; ! 44: 1.1 root 45: /* True if a #pragma interrupt has been seen for the current function. */ 46: int pragma_interrupt; 47: 48: /* True if a #pragma saveall has been seen for the current function. */ 49: int pragma_saveall; 50: 1.1.1.2 ! root 51: static char *names_big[] = ! 52: {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7"}; ! 53: ! 54: static char *names_extended[] = ! 55: {"er0", "er1", "er2", "er3", "er4", "er5", "er6", "er7"}; ! 56: ! 57: static char *names_upper_extended[] = ! 58: {"e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7"}; ! 59: ! 60: /* Points to one of the above. */ ! 61: /* ??? The above could be put in an array indexed by CPU_TYPE. */ ! 62: char **h8_reg_names; ! 63: ! 64: /* Various operations needed by the following, indexed by CPU_TYPE. */ ! 65: /* ??? The h8/300 assembler doesn't understand pop.w (yet). */ ! 66: ! 67: static char *h8_push_ops[2] = ! 68: {"push", "push.l"}; ! 69: static char *h8_pop_ops[2] = ! 70: {"pop", "pop.l"}; ! 71: static char *h8_mov_ops[2] = ! 72: {"mov.w", "mov.l"}; ! 73: ! 74: char *h8_push_op, *h8_pop_op, *h8_mov_op; ! 75: ! 76: /* Initialize various cpu specific globals at start up. */ ! 77: ! 78: void ! 79: h8300_init_once () ! 80: { ! 81: if (TARGET_H8300) ! 82: { ! 83: cpu_type = (int) CPU_H8300; ! 84: h8_reg_names = names_big; ! 85: } ! 86: else ! 87: { ! 88: cpu_type = (int) CPU_H8300H; ! 89: h8_reg_names = names_extended; ! 90: } ! 91: h8_push_op = h8_push_ops[cpu_type]; ! 92: h8_pop_op = h8_pop_ops[cpu_type]; ! 93: h8_mov_op = h8_mov_ops[cpu_type]; ! 94: } 1.1 root 95: 96: char * 97: byte_reg (x, b) 98: rtx x; 99: int b; 100: { 1.1.1.2 ! root 101: static char *names_small[] = ! 102: {"r0l", "r0h", "r1l", "r1h", "r2l", "r2h", "r3l", "r3h", ! 103: "r4l", "r4h", "r5l", "r5h", "r6l", "r6h", "r7lBAD", "r7hBAD"}; 1.1 root 104: 105: return names_small[REGNO (x) * 2 + b]; 106: } 107: 108: /* REGNO must be saved/restored across calls if this macro is true. */ 1.1.1.2 ! root 109: ! 110: #define WORD_REG_USED(regno) \ ! 111: (regno < 7 && \ ! 112: (pragma_interrupt \ ! 113: || pragma_saveall \ ! 114: || (regno == FRAME_POINTER_REGNUM && regs_ever_live[regno]) \ ! 115: || (regs_ever_live[regno] & !call_used_regs[regno]))) 1.1 root 116: 117: /* Output assembly language to FILE for the operation OP with operand size 1.1.1.2 ! root 118: SIZE to adjust the stack pointer. */ ! 119: /* ??? FPED is currently unused. */ ! 120: 1.1 root 121: static void 122: dosize (file, op, size, fped) 123: FILE *file; 124: char *op; 125: unsigned int size; 126: int fped; 127: { 128: switch (size) 129: { 130: case 4: 1.1.1.2 ! root 131: /* ??? TARGET_H8300H can do this in one insn. */ 1.1 root 132: case 3: 133: fprintf (file, "\t%ss\t#%d,sp\n", op, 2); 134: size -= 2; 135: /* Fall through... */ 136: case 2: 137: case 1: 138: fprintf (file, "\t%ss\t#%d,sp\n", op, size); 139: size = 0; 140: break; 141: case 0: 142: break; 143: default: 1.1.1.2 ! root 144: if (TARGET_H8300) ! 145: fprintf (file, "\tmov.w\t#%d,r3\n\t%s.w\tr3,sp\n", size, op); ! 146: else ! 147: fprintf (file, "\t%s\t#%d,sp\n", op, size); 1.1 root 148: size = 0; 149: break; 150: } 151: } 152: 153: /* Output assembly language code for the function prologue. */ 1.1.1.2 ! root 154: static int push_order[FIRST_PSEUDO_REGISTER] = ! 155: {6, 5, 4, 3, 2, 1, 0, -1, -1}; ! 156: static int pop_order[FIRST_PSEUDO_REGISTER] = ! 157: {0, 1, 2, 3, 4, 5, 6, -1, -1}; 1.1 root 158: 159: /* This is what the stack looks like after the prolog of 160: a function with a frame has been set up: 161: 1.1.1.2 ! root 162: <args> ! 163: PC ! 164: FP <- fp ! 165: <locals> ! 166: <saved registers> <- sp 1.1 root 167: 168: This is what the stack looks like after the prolog of 169: a function which doesn't have a frame: 170: 1.1.1.2 ! root 171: <args> ! 172: PC ! 173: <locals> ! 174: <saved registers> <- sp 1.1 root 175: */ 176: 1.1.1.2 ! root 177: int current_function_anonymous_args; ! 178: ! 179: /* Extra arguments to pop, in words (IE: 2 bytes for 300, 4 for 300h */ ! 180: static int extra_pop; ! 181: 1.1 root 182: void 183: function_prologue (file, size) 184: FILE *file; 185: int size; 186: { 187: register int mask = 0; 1.1.1.2 ! root 188: int fsize = (size + STACK_BOUNDARY / 8 - 1) & -STACK_BOUNDARY / 8; 1.1 root 189: int idx; 1.1.1.2 ! root 190: extra_pop = 0; ! 191: ! 192: if (current_function_anonymous_args && TARGET_QUICKCALL) ! 193: { ! 194: /* Push regs as if done by caller, and move around return address. */ ! 195: ! 196: switch (current_function_args_info.nbytes / UNITS_PER_WORD) ! 197: { ! 198: case 0: ! 199: /* get ret addr */ ! 200: fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[3]); ! 201: fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[2]); ! 202: fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[1]); ! 203: fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[0]); ! 204: /* push it again */ ! 205: fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[3]); ! 206: extra_pop = 3; ! 207: break; ! 208: case 1: ! 209: /* get ret addr */ ! 210: fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[3]); ! 211: fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[2]); ! 212: fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[1]); ! 213: /* push it again */ ! 214: fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[3]); ! 215: extra_pop = 2; ! 216: break; ! 217: case 2: ! 218: /* get ret addr */ ! 219: fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[3]); ! 220: fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[2]); ! 221: /* push it again */ ! 222: fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[3]); ! 223: extra_pop = 1; ! 224: break; ! 225: default: ! 226: fprintf (file, "; varargs\n"); ! 227: break; ! 228: } ! 229: } 1.1 root 230: 231: if (frame_pointer_needed) 232: { 1.1.1.2 ! root 233: /* Push fp */ ! 234: fprintf (file, "\t%s\t%s\n", h8_push_op, ! 235: h8_reg_names[FRAME_POINTER_REGNUM]); ! 236: fprintf (file, "\t%s\t%s,%s\n", h8_mov_op, ! 237: h8_reg_names[STACK_POINTER_REGNUM], ! 238: h8_reg_names[FRAME_POINTER_REGNUM]); 1.1 root 239: 1.1.1.2 ! root 240: /* leave room for locals */ 1.1 root 241: dosize (file, "sub", fsize, 1); 242: 1.1.1.2 ! root 243: /* Push the rest of the registers */ ! 244: for (idx = 0; idx < FIRST_PSEUDO_REGISTER; idx++) 1.1 root 245: { 246: int regno = push_order[idx]; 247: 1.1.1.2 ! root 248: if (regno >= 0 && WORD_REG_USED (regno) && regno != FRAME_POINTER_REGNUM) ! 249: fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[regno]); 1.1 root 250: } 251: } 252: else 253: { 254: dosize (file, "sub", fsize, 0); 255: for (idx = 0; idx < FIRST_PSEUDO_REGISTER; idx++) 256: { 257: int regno = push_order[idx]; 258: 1.1.1.2 ! root 259: if (regno >= 0 && WORD_REG_USED (regno)) ! 260: fprintf (file, "\t%s\t%s\n", h8_push_op, h8_reg_names[regno]); 1.1 root 261: } 262: } 263: } 264: 265: /* Output assembly language code for the function epilogue. */ 266: 267: void 268: function_epilogue (file, size) 269: FILE *file; 270: int size; 271: { 272: register int regno; 273: register int mask = 0; 1.1.1.2 ! root 274: int fsize = (size + STACK_BOUNDARY / 8 - 1) & -STACK_BOUNDARY / 8; 1.1 root 275: int nregs; 276: int offset; 277: int idx; 278: rtx insn = get_last_insn (); 279: 280: /* If the last insn was a BARRIER, we don't have to write any code. */ 281: if (GET_CODE (insn) == NOTE) 282: insn = prev_nonnote_insn (insn); 283: if (insn && GET_CODE (insn) == BARRIER) 284: return; 285: 286: nregs = 0; 287: 288: if (frame_pointer_needed) 289: { 1.1.1.2 ! root 290: /* Pop saved registers */ 1.1 root 291: for (idx = 0; idx < FIRST_PSEUDO_REGISTER; idx++) 292: { 293: regno = pop_order[idx]; 1.1.1.2 ! root 294: if (regno >= 0 && regno != FRAME_POINTER_REGNUM && WORD_REG_USED (regno)) ! 295: fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[regno]); 1.1 root 296: } 1.1.1.2 ! root 297: /* deallocate locals */ 1.1 root 298: dosize (file, "add", fsize, 1); 1.1.1.2 ! root 299: /* pop frame pointer */ ! 300: fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[FRAME_POINTER_REGNUM]); 1.1 root 301: } 302: else 303: { 1.1.1.2 ! root 304: /* pop saved registers */ 1.1 root 305: for (idx = 0; idx < FIRST_PSEUDO_REGISTER; idx++) 306: { 307: regno = pop_order[idx]; 1.1.1.2 ! root 308: if (regno >= 0 && WORD_REG_USED (regno)) ! 309: fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[regno]); 1.1 root 310: } 1.1.1.2 ! root 311: /* deallocate locals */ 1.1 root 312: dosize (file, "add", fsize, 0); 313: } 1.1.1.2 ! root 314: ! 315: if (extra_pop) ! 316: { ! 317: fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[3]); ! 318: while (extra_pop) ! 319: { ! 320: fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[2]); ! 321: extra_pop--; ! 322: } ! 323: fprintf (file, "\tjmp @%s\n", h8_reg_names[3]); ! 324: } 1.1 root 325: else 1.1.1.2 ! root 326: { ! 327: if (pragma_interrupt) ! 328: fprintf (file, "\trte\n"); ! 329: else ! 330: fprintf (file, "\trts\n"); ! 331: } 1.1 root 332: 333: pragma_interrupt = 0; 334: pragma_saveall = 0; 1.1.1.2 ! root 335: ! 336: current_function_anonymous_args = 0; ! 337: } ! 338: ! 339: /* Output assembly code for the start of the file. */ ! 340: ! 341: asm_file_start (file) ! 342: FILE *file; ! 343: { ! 344: fprintf (file, ";\tGCC For the Hitachi H8/300\n"); ! 345: fprintf (file, ";\tBy Hitachi America Ltd and Cygnus Support\n"); ! 346: fprintf (file, ";\trelease F-1\n"); ! 347: if (optimize) ! 348: fprintf (file, "; -O%d\n", optimize); ! 349: if (TARGET_H8300H) ! 350: fprintf (file, "\n\t.h8300h\n"); ! 351: else ! 352: fprintf (file, "\n\n"); ! 353: output_file_directive (file, main_input_filename); ! 354: } ! 355: ! 356: /* Output assembly language code for the end of file. */ ! 357: ! 358: void ! 359: asm_file_end (file) ! 360: FILE *file; ! 361: { ! 362: fprintf (file, "\t.end\n"); 1.1 root 363: } 364: 1.1.1.2 ! root 365: /* Return true if VALUE is a valid constant for constraint 'P'. ! 366: IE: VALUE is a power of two <= 2**15. */ 1.1 root 367: 368: int 1.1.1.2 ! root 369: small_power_of_two (value) ! 370: int value; 1.1 root 371: { 372: switch (value) 373: { 374: case 1: 375: case 2: 376: case 4: 377: case 8: 378: case 16: 379: case 32: 380: case 64: 381: case 128: 382: case 256: 383: case 512: 384: case 1024: 385: case 2048: 386: case 4096: 387: case 8192: 388: case 16384: 389: case 32768: 390: return 1; 391: } 392: return 0; 393: } 394: 1.1.1.2 ! root 395: /* Return true if VALUE is a valid constant for constraint 'O', which ! 396: means that the constant would be ok to use as a bit for a bclr ! 397: instruction. */ ! 398: ! 399: int ! 400: ok_for_bclr (value) ! 401: int value; ! 402: { ! 403: return small_power_of_two ((~value) & 0xff); ! 404: } ! 405: 1.1 root 406: /* Return true is OP is a valid source operand for an integer move 407: instruction. */ 1.1.1.2 ! root 408: 1.1 root 409: int 410: general_operand_src (op, mode) 411: rtx op; 412: enum machine_mode mode; 413: { 1.1.1.2 ! root 414: if (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == POST_INC) ! 415: return 1; 1.1 root 416: return general_operand (op, mode); 417: } 418: 419: /* Return true if OP is a valid destination operand for an integer move 420: instruction. */ 1.1.1.2 ! root 421: 1.1 root 422: int 423: general_operand_dst (op, mode) 424: rtx op; 425: enum machine_mode mode; 426: { 1.1.1.2 ! root 427: if (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == PRE_DEC) ! 428: return 1; 1.1 root 429: return general_operand (op, mode); 430: } 1.1.1.2 ! root 431: ! 432: /* Return true if OP is a const valid for a bit clear instruction. */ ! 433: ! 434: int ! 435: o_operand (operand, mode) ! 436: rtx operand; ! 437: enum machine_mode mode; ! 438: { ! 439: return (GET_CODE (operand) == CONST_INT ! 440: && CONST_OK_FOR_O (INTVAL (operand))); ! 441: } ! 442: ! 443: /* Return true if OP is a const valid for a bit set or bit xor instruction. */ ! 444: ! 445: int ! 446: p_operand (operand, mode) ! 447: rtx operand; ! 448: enum machine_mode mode; ! 449: { ! 450: return (GET_CODE (operand) == CONST_INT ! 451: && CONST_OK_FOR_P (INTVAL (operand))); ! 452: } ! 453: ! 454: /* Return true if OP is a valid call operand. */ ! 455: ! 456: int ! 457: call_insn_operand (op, mode) ! 458: rtx op; ! 459: enum machine_mode mode; ! 460: { ! 461: if (GET_CODE (op) == MEM) ! 462: { ! 463: rtx inside = XEXP (op, 0); ! 464: if (register_operand (inside, Pmode)) ! 465: return 1; ! 466: if (CONSTANT_ADDRESS_P (inside)) ! 467: return 1; ! 468: } ! 469: return 0; ! 470: } ! 471: ! 472: /* Return true if OP is a valid jump operand. */ ! 473: ! 474: int ! 475: jump_address_operand (op, mode) ! 476: rtx op; ! 477: enum machine_mode mode; ! 478: { ! 479: if (GET_CODE (op) == REG) ! 480: return mode == Pmode; ! 481: ! 482: if (GET_CODE (op) == MEM) ! 483: { ! 484: rtx inside = XEXP (op, 0); ! 485: if (register_operand (inside, Pmode)) ! 486: return 1; ! 487: if (CONSTANT_ADDRESS_P (inside)) ! 488: return 1; ! 489: } ! 490: return 0; ! 491: } ! 492: ! 493: /* Recognize valid operands for bitfield instructions. */ ! 494: ! 495: extern int rtx_equal_function_value_matters; ! 496: ! 497: int ! 498: bit_operand (op, mode) ! 499: rtx op; ! 500: enum machine_mode mode; ! 501: { ! 502: /* We can except any general operand, expept that MEM operands must ! 503: be limited to those that use addresses valid for the 'U' constraint. */ ! 504: if (!general_operand (op, mode)) ! 505: return 0; ! 506: ! 507: /* Accept any mem during RTL generation. Otherwise, the code that does ! 508: insv and extzv will think that we can not handle memory. However, ! 509: to avoid reload problems, we only accept 'U' MEM operands after RTL ! 510: generation. This means that any named pattern which uses this predicate ! 511: must force its operands to match 'U' before emitting RTL. */ ! 512: ! 513: if (GET_CODE (op) == REG) ! 514: return 1; ! 515: if (GET_CODE (op) == SUBREG) ! 516: return 1; ! 517: if (!rtx_equal_function_value_matters) ! 518: { ! 519: /* We're building rtl */ ! 520: return GET_CODE (op) == MEM; ! 521: } ! 522: else ! 523: { ! 524: return (GET_CODE (op) == MEM ! 525: && EXTRA_CONSTRAINT (op, 'U')); ! 526: } ! 527: } ! 528: ! 529: /* Recognize valid operators for bit test. */ ! 530: ! 531: int ! 532: eq_operator (x, mode) ! 533: rtx x; ! 534: enum machine_mode mode; ! 535: { ! 536: return (GET_CODE (x) == EQ || GET_CODE (x) == NE); ! 537: } ! 538: 1.1 root 539: /* Handle machine specific pragmas for compatibility with existing 1.1.1.2 ! root 540: compilers for the H8/300. 1.1 root 541: 542: pragma saveall generates prolog/epilog code which saves and 543: restores all the registers on function entry. 1.1.1.2 ! root 544: 1.1 root 545: pragma interrupt saves and restores all registers, and exits with 546: an rte instruction rather than an rts. A pointer to a function 547: with this attribute may be safely used in an interrupt vector. */ 1.1.1.2 ! root 548: 1.1 root 549: int 550: handle_pragma (file) 551: FILE *file; 552: { 553: int c; 554: char pbuf[20]; 1.1.1.2 ! root 555: int psize = 0; 1.1 root 556: 557: c = getc (file); 558: while (c == ' ' || c == '\t') 559: c = getc (file); 560: 561: if (c == '\n' || c == EOF) 562: return c; 563: 1.1.1.2 ! root 564: /* The only pragmas we understand are interrupt and saveall. */ ! 565: while (psize < sizeof (pbuf) - 1 ! 566: && isalpha (c)) 1.1 root 567: { 1.1.1.2 ! root 568: pbuf[psize++] = c; 1.1 root 569: c = getc (file); 570: } 571: pbuf[psize] = 0; 572: 573: if (strcmp (pbuf, "interrupt") == 0) 574: pragma_interrupt = 1; 575: 576: if (strcmp (pbuf, "saveall") == 0) 577: pragma_saveall = 1; 578: 1.1.1.2 ! root 579: /* ??? This is deprecated. Use section attributes. */ ! 580: if (strcmp (pbuf, "section") == 0) ! 581: { ! 582: while (c && !isalpha (c)) ! 583: c = getc (file); ! 584: psize = 0; ! 585: while (psize < sizeof (pbuf) - 1 ! 586: && isalpha (c) || isdigit (c) || c == '_') ! 587: { ! 588: pbuf[psize++] = c; ! 589: c = getc (file); ! 590: } ! 591: pbuf[psize] = 0; ! 592: named_section (pbuf); ! 593: } ! 594: ungetc (c, file); 1.1 root 595: return c; 596: } 597: 598: /* If the next arg with MODE and TYPE is to be passed in a register, return 599: the rtx to represent where it is passed. CUM represents the state after 600: the last argument. NAMED is not used. */ 601: 1.1.1.2 ! root 602: static char *hand_list[] = ! 603: { ! 604: "__main", ! 605: "__cmpsi2", ! 606: "__divhi3", ! 607: "__modhi3", ! 608: "__udivhi3", ! 609: "__umodhi3", ! 610: "__divsi3", ! 611: "__modsi3", ! 612: "__udivsi3", ! 613: "__umodsi3", ! 614: "__mulhi3", ! 615: "__mulsi3", ! 616: "__reg_memcpy", ! 617: "__reg_memset", ! 618: "__ucmpsi2", ! 619: 0, ! 620: }; ! 621: ! 622: /* Return an RTX to represent where a value with mode MODE will be returned ! 623: from a function. If the result is 0, the argument is pushed. */ ! 624: 1.1 root 625: rtx 626: function_arg (cum, mode, type, named) 627: CUMULATIVE_ARGS *cum; 628: enum machine_mode mode; 629: tree type; 630: int named; 631: { 632: rtx result = 0; 1.1.1.2 ! root 633: char *fname; ! 634: int regpass = 0; ! 635: ! 636: /* Pass 3 regs worth of data in regs when user asked on the command line. */ ! 637: if (TARGET_QUICKCALL) ! 638: regpass = 3; ! 639: ! 640: /* If calling hand written assembler, use 4 regs of args. */ ! 641: ! 642: if (cum->libcall) ! 643: { ! 644: char **p; ! 645: ! 646: fname = XSTR (cum->libcall, 0); ! 647: ! 648: /* See if this libcall is one of the hand coded ones. */ 1.1 root 649: 1.1.1.2 ! root 650: for (p = hand_list; *p && strcmp (*p, fname) != 0; p++) ! 651: ; 1.1 root 652: 1.1.1.2 ! root 653: if (*p) ! 654: regpass = 4; ! 655: } ! 656: ! 657: if (regpass) ! 658: { ! 659: int size; ! 660: ! 661: if (mode == BLKmode) ! 662: size = int_size_in_bytes (type); ! 663: else ! 664: size = GET_MODE_SIZE (mode); ! 665: ! 666: if (size + cum->nbytes > regpass * UNITS_PER_WORD) ! 667: { ! 668: result = 0; ! 669: } ! 670: else ! 671: { ! 672: switch (cum->nbytes / UNITS_PER_WORD) ! 673: { ! 674: case 0: ! 675: result = gen_rtx (REG, mode, 0); ! 676: break; ! 677: case 1: ! 678: result = gen_rtx (REG, mode, 1); ! 679: break; ! 680: case 2: ! 681: result = gen_rtx (REG, mode, 2); ! 682: break; ! 683: case 3: ! 684: result = gen_rtx (REG, mode, 3); ! 685: break; ! 686: default: ! 687: result = 0; ! 688: } ! 689: } ! 690: } 1.1 root 691: 1.1.1.2 ! root 692: return result; ! 693: } ! 694: ! 695: /* Return the cost of the rtx R with code CODE. */ 1.1 root 696: 1.1.1.2 ! root 697: int ! 698: const_costs (r, c) ! 699: rtx r; ! 700: enum rtx_code c; ! 701: { ! 702: switch (c) 1.1 root 703: { 1.1.1.2 ! root 704: case CONST_INT: ! 705: switch (INTVAL (r)) 1.1 root 706: { 707: case 0: 1.1.1.2 ! root 708: case 1: 1.1 root 709: case 2: 1.1.1.2 ! root 710: case -1: ! 711: case -2: 1.1 root 712: return 0; 1.1.1.2 ! root 713: default: ! 714: return 1; 1.1 root 715: } 1.1.1.2 ! root 716: ! 717: case CONST: ! 718: case LABEL_REF: ! 719: case SYMBOL_REF: ! 720: return 3; ! 721: ! 722: case CONST_DOUBLE: ! 723: return 20; ! 724: ! 725: default: ! 726: return 4; 1.1 root 727: } 728: } 1.1.1.2 ! root 729: 1.1 root 730: /* Documentation for the machine specific operand escapes: 731: 1.1.1.2 ! root 732: 'A' print rn in h8/300 mode, erN in H8/300H mode 1.1 root 733: 'C' print (operand - 2). 1.1.1.2 ! root 734: 'E' like s but negative. ! 735: 'F' like t but negative. ! 736: 'G' constant just the negative 1.1 root 737: 'L' fake label, changed after used twice. 738: 'M' turn a 'M' constant into its negative mod 2. 1.1.1.2 ! root 739: 'P' if operand is incing/decing sp, print .w, otherwise .b. ! 740: 'S' print operand as a long word 1.1 root 741: 'T' print operand as a word 1.1.1.2 ! root 742: 'U' if operand is incing/decing sp, print l, otherwise nothing. ! 743: 'V' find the set bit, and print its number. ! 744: 'W' find the clear bit, and print its number. ! 745: 'X' print operand as a byte 1.1 root 746: 'Y' print either l or h depending on whether last 'Z' operand < 8 or >= 8. 1.1.1.2 ! root 747: 'Z' print int & 7. ! 748: 'b' print the bit opcode ! 749: 'c' print the ibit opcode ! 750: 'd' bcc if EQ, bcs if NE ! 751: 'e' first word of 32 bit value - if reg, then least reg. if mem ! 752: then least. if const then most sig word ! 753: 'f' second word of 32 bit value - if reg, then biggest reg. if mem ! 754: then +2. if const then least sig word ! 755: 'g' bcs if EQ, bcc if NE 1.1 root 756: 'j' print operand as condition code. 757: 'k' print operand as reverse condition code. 1.1.1.2 ! root 758: 's' print as low byte of 16 bit value ! 759: 't' print as high byte of 16 bit value ! 760: 'w' print as low byte of 32 bit value ! 761: 'x' print as 2nd byte of 32 bit value ! 762: 'y' print as 3rd byte of 32 bit value ! 763: 'z' print as msb of 32 bit value ! 764: */ 1.1 root 765: 766: /* Return assembly language string which identifies a comparison type. */ 767: 1.1.1.2 ! root 768: static char * 1.1 root 769: cond_string (code) 770: enum rtx_code code; 771: { 772: switch (code) 773: { 774: case NE: 1.1.1.2 ! root 775: if (cc_prev_status.flags & CC_DONE_CBIT) ! 776: return "cs"; 1.1 root 777: return "ne"; 778: case EQ: 1.1.1.2 ! root 779: if (cc_prev_status.flags & CC_DONE_CBIT) ! 780: return "cc"; 1.1 root 781: return "eq"; 782: case GE: 783: return "ge"; 784: case GT: 785: return "gt"; 786: case LE: 787: return "le"; 788: case LT: 789: return "lt"; 790: case GEU: 791: return "hs"; 792: case GTU: 793: return "hi"; 794: case LEU: 795: return "ls"; 796: case LTU: 797: return "lo"; 798: default: 799: abort (); 800: } 801: } 802: 803: /* Print operand X using operand code CODE to assembly language output file 804: FILE. */ 805: 806: void 807: print_operand (file, x, code) 808: FILE *file; 809: rtx x; 810: int code; 811: { 812: /* This is used to general unique labels for the 'L' code. */ 813: static int lab = 1000; 814: 815: /* This is used for communication between the 'P' and 'U' codes. */ 816: static char *last_p; 817: 818: /* This is used for communication between the 'Z' and 'Y' codes. */ 1.1.1.2 ! root 819: /* ??? 'V' and 'W' use it too. */ 1.1 root 820: static int bitint; 821: 822: switch (code) 823: { 1.1.1.2 ! root 824: case 'A': 1.1 root 825: if (GET_CODE (x) == REG) 1.1.1.2 ! root 826: fprintf (file, "%s", h8_reg_names[REGNO (x)]); 1.1 root 827: else 828: goto def; 829: break; 1.1.1.2 ! root 830: case 'C': ! 831: fprintf (file, "#%d", INTVAL (x) - 2); ! 832: break; ! 833: case 'E': ! 834: switch (GET_CODE (x)) ! 835: { ! 836: case REG: ! 837: fprintf (file, "%sl", names_big[REGNO (x)]); ! 838: break; ! 839: case CONST_INT: ! 840: fprintf (file, "#%d", (-INTVAL (x)) & 0xff); ! 841: break; ! 842: default: ! 843: abort (); ! 844: } ! 845: break; ! 846: case 'F': ! 847: switch (GET_CODE (x)) ! 848: { ! 849: case REG: ! 850: fprintf (file, "%sh", names_big[REGNO (x)]); ! 851: break; ! 852: case CONST_INT: ! 853: fprintf (file, "#%d", ((-INTVAL (x)) & 0xff00) >> 8); ! 854: break; ! 855: default: ! 856: abort (); ! 857: } ! 858: break; 1.1 root 859: case 'G': 860: if (GET_CODE (x) != CONST_INT) 861: abort (); 862: fprintf (file, "#%d", 0xff & (-INTVAL (x))); 863: break; 1.1.1.2 ! root 864: case 'L': ! 865: /* 'L' must always be used twice in a single pattern. It generates ! 866: the same lable twice, and then will generate a unique label the ! 867: next time it is used. */ ! 868: asm_fprintf (file, "tl%d", (lab++) / 2); 1.1 root 869: break; 1.1.1.2 ! root 870: case 'M': ! 871: /* For 3/-3 and 4/-4, the other 2 is handled separately. */ ! 872: switch (INTVAL (x)) ! 873: { ! 874: case 2: ! 875: case 4: ! 876: case -2: ! 877: case -4: ! 878: fprintf (file, "#2"); ! 879: break; ! 880: case 1: ! 881: case 3: ! 882: case -1: ! 883: case -3: ! 884: fprintf (file, "#1"); ! 885: break; ! 886: default: ! 887: abort (); ! 888: } 1.1 root 889: break; 1.1.1.2 ! root 890: case 'P': ! 891: if (REGNO (XEXP (XEXP (x, 0), 0)) == STACK_POINTER_REGNUM) ! 892: { ! 893: last_p = ""; ! 894: fprintf (file, ".w"); ! 895: } 1.1 root 896: else 1.1.1.2 ! root 897: { ! 898: last_p = "l"; ! 899: fprintf (file, ".b"); ! 900: } 1.1 root 901: break; 1.1.1.2 ! root 902: case 'S': ! 903: if (GET_CODE (x) == REG) ! 904: fprintf (file, "%s", names_extended[REGNO (x)]); 1.1 root 905: else 1.1.1.2 ! root 906: goto def; 1.1 root 907: break; 1.1.1.2 ! root 908: case 'T': ! 909: if (GET_CODE (x) == REG) ! 910: fprintf (file, "%s", names_big[REGNO (x)]); 1.1 root 911: else 1.1.1.2 ! root 912: goto def; 1.1 root 913: break; 1.1.1.2 ! root 914: case 'U': ! 915: fprintf (file, "%s%s", names_big[REGNO (x)], last_p); 1.1 root 916: break; 1.1.1.2 ! root 917: case 'V': ! 918: bitint = exact_log2 (INTVAL (x)); ! 919: if (bitint == -1) 1.1 root 920: abort (); 921: fprintf (file, "#%d", bitint & 7); 922: break; 1.1.1.2 ! root 923: case 'W': 1.1 root 924: bitint = exact_log2 ((~INTVAL (x)) & 0xff); 925: if (bitint == -1) 926: abort (); 927: fprintf (file, "#%d", bitint & 7); 928: break; 1.1.1.2 ! root 929: case 'X': ! 930: if (GET_CODE (x) == REG) ! 931: fprintf (file, "%s", byte_reg (x, 0)); ! 932: else ! 933: goto def; ! 934: break; ! 935: case 'Y': 1.1 root 936: if (bitint == -1) 937: abort (); 1.1.1.2 ! root 938: if (GET_CODE (x) == REG) ! 939: fprintf (file, "%s%c", names_big[REGNO (x)], bitint > 7 ? 'h' : 'l'); ! 940: else ! 941: print_operand (file, x, 0); ! 942: bitint = -1; ! 943: break; ! 944: case 'Z': ! 945: bitint = INTVAL (x); 1.1 root 946: fprintf (file, "#%d", bitint & 7); 947: break; 1.1.1.2 ! root 948: case 'b': ! 949: switch (GET_CODE (x)) 1.1 root 950: { 1.1.1.2 ! root 951: case IOR: ! 952: fprintf (file, "bor"); ! 953: break; ! 954: case XOR: ! 955: fprintf (file, "bxor"); ! 956: break; ! 957: case AND: ! 958: fprintf (file, "band"); ! 959: break; 1.1 root 960: } 1.1.1.2 ! root 961: break; ! 962: case 'c': ! 963: switch (GET_CODE (x)) 1.1 root 964: { 1.1.1.2 ! root 965: case IOR: ! 966: fprintf (file, "bior"); ! 967: break; ! 968: case XOR: ! 969: fprintf (file, "bixor"); ! 970: break; ! 971: case AND: ! 972: fprintf (file, "biand"); ! 973: break; 1.1 root 974: } 975: break; 1.1.1.2 ! root 976: case 'd': ! 977: switch (GET_CODE (x)) 1.1 root 978: { 1.1.1.2 ! root 979: case EQ: ! 980: fprintf (file, "bcc"); 1.1 root 981: break; 1.1.1.2 ! root 982: case NE: ! 983: fprintf (file, "bcs"); 1.1 root 984: break; 985: default: 986: abort (); 987: } 988: break; 989: case 'e': 990: switch (GET_CODE (x)) 991: { 992: case REG: 1.1.1.2 ! root 993: if (TARGET_H8300) ! 994: fprintf (file, "%s", names_big[REGNO (x)]); ! 995: else ! 996: fprintf (file, "%s", names_upper_extended[REGNO (x)]); 1.1 root 997: break; 998: case MEM: 999: x = adj_offsettable_operand (x, 0); 1000: print_operand (file, x, 0); 1001: break; 1002: case CONST_INT: 1003: fprintf (file, "#%d", ((INTVAL (x) >> 16) & 0xffff)); 1004: break; 1005: default: 1006: abort (); 1007: break; 1008: } 1009: break; 1010: case 'f': 1011: switch (GET_CODE (x)) 1012: { 1013: case REG: 1.1.1.2 ! root 1014: if (TARGET_H8300) ! 1015: fprintf (file, "%s", names_big[REGNO (x) + 1]); ! 1016: else ! 1017: fprintf (file, "%s", names_big[REGNO (x)]); 1.1 root 1018: break; 1019: case MEM: 1020: x = adj_offsettable_operand (x, 2); 1021: print_operand (file, x, 0); 1022: break; 1023: case CONST_INT: 1024: fprintf (file, "#%d", INTVAL (x) & 0xffff); 1025: break; 1026: default: 1027: abort (); 1028: } 1029: break; 1.1.1.2 ! root 1030: case 'g': 1.1 root 1031: switch (GET_CODE (x)) 1032: { 1.1.1.2 ! root 1033: case NE: ! 1034: fprintf (file, "bcc"); 1.1 root 1035: break; 1.1.1.2 ! root 1036: case EQ: ! 1037: fprintf (file, "bcs"); 1.1 root 1038: break; 1039: default: 1040: abort (); 1041: } 1042: break; 1043: case 'j': 1044: asm_fprintf (file, cond_string (GET_CODE (x))); 1045: break; 1046: case 'k': 1047: asm_fprintf (file, cond_string (reverse_condition (GET_CODE (x)))); 1048: break; 1.1.1.2 ! root 1049: case 's': ! 1050: if (GET_CODE (x) == CONST_INT) ! 1051: fprintf (file, "#%d", (INTVAL (x)) & 0xff); ! 1052: else ! 1053: fprintf (file, "%s", byte_reg (x, 0)); ! 1054: break; ! 1055: case 't': ! 1056: if (GET_CODE (x) == CONST_INT) ! 1057: fprintf (file, "#%d", (INTVAL (x) >> 8) & 0xff); ! 1058: else ! 1059: fprintf (file, "%s", byte_reg (x, 1)); ! 1060: break; ! 1061: case 'u': ! 1062: if (GET_CODE (x) != CONST_INT) ! 1063: abort (); ! 1064: fprintf (file, "%d", INTVAL (x)); ! 1065: break; ! 1066: case 'w': ! 1067: if (GET_CODE (x) == CONST_INT) ! 1068: fprintf (file, "#%d", INTVAL (x) & 0xff); ! 1069: else ! 1070: fprintf (file, "%s", byte_reg (x, TARGET_H8300 ? 2 : 0)); ! 1071: break; ! 1072: case 'x': ! 1073: if (GET_CODE (x) == CONST_INT) ! 1074: fprintf (file, "#%d", (INTVAL (x) >> 8) & 0xff); ! 1075: else ! 1076: fprintf (file, "%s", byte_reg (x, TARGET_H8300 ? 3 : 1)); ! 1077: break; ! 1078: case 'y': ! 1079: if (GET_CODE (x) == CONST_INT) ! 1080: fprintf (file, "#%d", (INTVAL (x) >> 16) & 0xff); ! 1081: else ! 1082: fprintf (file, "%s", byte_reg (x, 0)); ! 1083: break; ! 1084: case 'z': ! 1085: if (GET_CODE (x) == CONST_INT) ! 1086: fprintf (file, "#%d", (INTVAL (x) >> 24) & 0xff); ! 1087: else ! 1088: fprintf (file, "%s", byte_reg (x, 1)); ! 1089: break; ! 1090: 1.1 root 1091: default: 1.1.1.2 ! root 1092: def: 1.1 root 1093: switch (GET_CODE (x)) 1094: { 1095: case REG: 1.1.1.2 ! root 1096: switch (GET_MODE (x)) ! 1097: { ! 1098: case QImode: ! 1099: #if 0 /* Is it asm ("mov.b %0,r2l", ...) */ ! 1100: fprintf (file, "%s", byte_reg (x, 0)); ! 1101: #else /* ... or is it asm ("mov.b %0l,r2l", ...) */ ! 1102: fprintf (file, "%s", names_big[REGNO (x)]); ! 1103: #endif ! 1104: break; ! 1105: case HImode: ! 1106: fprintf (file, "%s", names_big[REGNO (x)]); ! 1107: break; ! 1108: case SImode: ! 1109: case SFmode: ! 1110: fprintf (file, "%s", names_extended[REGNO (x)]); ! 1111: break; ! 1112: default: ! 1113: abort (); ! 1114: } 1.1 root 1115: break; 1116: 1117: case MEM: 1118: fprintf (file, "@"); 1119: output_address (XEXP (x, 0)); 1120: break; 1121: 1122: case CONST_INT: 1123: case SYMBOL_REF: 1124: case CONST: 1125: case LABEL_REF: 1126: fprintf (file, "#"); 1127: print_operand_address (file, x); 1128: break; 1129: } 1130: } 1131: } 1132: 1133: /* Output assembly language output for the address ADDR to FILE. */ 1134: 1135: void 1136: print_operand_address (file, addr) 1137: FILE *file; 1138: rtx addr; 1139: { 1140: switch (GET_CODE (addr)) 1141: { 1142: case REG: 1.1.1.2 ! root 1143: fprintf (file, "%s", h8_reg_names[REGNO (addr)]); 1.1 root 1144: break; 1145: 1146: case PRE_DEC: 1.1.1.2 ! root 1147: fprintf (file, "-%s", h8_reg_names[REGNO (XEXP (addr, 0))]); 1.1 root 1148: break; 1149: 1150: case POST_INC: 1.1.1.2 ! root 1151: fprintf (file, "%s+", h8_reg_names[REGNO (XEXP (addr, 0))]); 1.1 root 1152: break; 1153: 1154: case PLUS: 1155: fprintf (file, "("); 1156: if (GET_CODE (XEXP (addr, 0)) == REG) 1157: { 1158: /* reg,foo */ 1159: print_operand_address (file, XEXP (addr, 1)); 1160: fprintf (file, ","); 1161: print_operand_address (file, XEXP (addr, 0)); 1162: } 1163: else 1164: { 1165: /* foo+k */ 1166: print_operand_address (file, XEXP (addr, 0)); 1167: fprintf (file, "+"); 1168: print_operand_address (file, XEXP (addr, 1)); 1169: } 1170: fprintf (file, ")"); 1171: break; 1172: 1173: case CONST_INT: 1.1.1.2 ! root 1174: { ! 1175: /* Since the h8/300 only has 16 bit pointers, negative values are also ! 1176: those >= 32768. This happens for example with pointer minus a ! 1177: constant. We don't want to turn (char *p - 2) into ! 1178: (char *p + 65534) because loop unrolling can build upon this ! 1179: (IE: char *p + 131068). */ ! 1180: int n = INTVAL (addr); ! 1181: if (TARGET_H8300) ! 1182: n = (int) (short) n; ! 1183: if (n < 0) ! 1184: /* ??? Why the special case for -ve values? */ ! 1185: fprintf (file, "-%d", -n); ! 1186: else ! 1187: fprintf (file, "%d", n); ! 1188: break; ! 1189: } 1.1 root 1190: 1191: default: 1192: output_addr_const (file, addr); 1193: break; 1194: } 1195: } 1196: 1197: /* Output all insn addresses and their sizes into the assembly language 1198: output file. This is helpful for debugging whether the length attributes 1199: in the md file are correct. This is not meant to be a user selectable 1200: option. */ 1201: 1202: void 1203: final_prescan_insn (insn, operand, num_operands) 1204: rtx insn, *operand; 1205: int num_operands; 1206: { 1207: /* This holds the last insn address. */ 1208: static int last_insn_address = 0; 1209: 1210: int uid = INSN_UID (insn); 1211: 1.1.1.2 ! root 1212: if (TARGET_RTL_DUMP) ! 1213: { ! 1214: fprintf (asm_out_file, "\n****************"); ! 1215: print_rtl (asm_out_file, PATTERN (insn)); ! 1216: fprintf (asm_out_file, "\n"); ! 1217: } ! 1218: 1.1 root 1219: if (TARGET_ADDRESSES) 1220: { 1.1.1.2 ! root 1221: fprintf (asm_out_file, "; 0x%x %d\n", insn_addresses[uid], 1.1 root 1222: insn_addresses[uid] - last_insn_address); 1223: last_insn_address = insn_addresses[uid]; 1224: } 1225: } 1226: 1.1.1.2 ! root 1227: /* Prepare for an SI sized move. */ ! 1228: ! 1229: int ! 1230: do_movsi (operands) ! 1231: rtx operands[]; ! 1232: { ! 1233: rtx src = operands[1]; ! 1234: rtx dst = operands[0]; ! 1235: if (!reload_in_progress && !reload_completed) ! 1236: { ! 1237: if (!register_operand (dst, GET_MODE (dst))) ! 1238: { ! 1239: rtx tmp = gen_reg_rtx (GET_MODE (dst)); ! 1240: emit_move_insn (tmp, src); ! 1241: operands[1] = tmp; ! 1242: } ! 1243: } ! 1244: return 0; ! 1245: } ! 1246: ! 1247: /* Function for INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET). ! 1248: Define the offset between two registers, one to be eliminated, and the other ! 1249: its replacement, at the start of a routine. */ ! 1250: ! 1251: int ! 1252: initial_offset (from, to) 1.1 root 1253: { 1.1.1.2 ! root 1254: int offset = 0; 1.1 root 1255: 1.1.1.2 ! root 1256: if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM) ! 1257: offset = UNITS_PER_WORD + frame_pointer_needed * UNITS_PER_WORD; ! 1258: else 1.1 root 1259: { 1.1.1.2 ! root 1260: int regno; ! 1261: ! 1262: for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) ! 1263: if ((regs_ever_live[regno] ! 1264: && (!call_used_regs[regno] || regno == FRAME_POINTER_REGNUM))) ! 1265: offset += UNITS_PER_WORD; ! 1266: ! 1267: /* See the comments for get_frame_size. We need to round it up to ! 1268: STACK_BOUNDARY. */ ! 1269: ! 1270: offset += ((get_frame_size () + STACK_BOUNDARY / BITS_PER_UNIT - 1) ! 1271: & ~(STACK_BOUNDARY / BITS_PER_UNIT - 1)); ! 1272: ! 1273: if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM) ! 1274: offset += UNITS_PER_WORD; /* Skip saved PC */ 1.1 root 1275: } 1.1.1.2 ! root 1276: return offset; ! 1277: } 1.1 root 1278: 1.1.1.2 ! root 1279: /* Update the condition code from the insn. */ ! 1280: ! 1281: int ! 1282: notice_update_cc (body, insn) ! 1283: rtx body; ! 1284: rtx insn; ! 1285: { ! 1286: switch (get_attr_cc (insn)) ! 1287: { ! 1288: case CC_NONE: ! 1289: /* Insn does not affect the CC at all */ ! 1290: break; ! 1291: ! 1292: case CC_NONE_0HIT: ! 1293: /* Insn does not change the CC, but the 0't operand has been changed. */ ! 1294: ! 1295: if (cc_status.value1 != 0 ! 1296: && reg_overlap_mentioned_p (recog_operand[0], cc_status.value1)) ! 1297: cc_status.value1 = 0; ! 1298: ! 1299: if (cc_status.value2 != 0 ! 1300: && reg_overlap_mentioned_p (recog_operand[0], cc_status.value2)) ! 1301: cc_status.value2 = 0; ! 1302: ! 1303: break; ! 1304: ! 1305: case CC_SET: ! 1306: /* Insn sets CC to recog_operand[0], but overflow is impossible. */ ! 1307: CC_STATUS_INIT; ! 1308: cc_status.flags |= CC_NO_OVERFLOW; ! 1309: cc_status.value1 = recog_operand[0]; ! 1310: break; ! 1311: ! 1312: case CC_COMPARE: ! 1313: /* The insn is a compare instruction */ ! 1314: CC_STATUS_INIT; ! 1315: cc_status.value1 = SET_SRC (body); ! 1316: break; ! 1317: ! 1318: case CC_CBIT: ! 1319: CC_STATUS_INIT; ! 1320: cc_status.flags |= CC_DONE_CBIT; ! 1321: cc_status.value1 = 0; ! 1322: break; ! 1323: ! 1324: case CC_WHOOPS: ! 1325: case CC_CLOBBER: ! 1326: /* Insn clobbers CC. */ ! 1327: CC_STATUS_INIT; ! 1328: break; ! 1329: } 1.1 root 1330: } 1331: 1.1.1.2 ! root 1332: /* Recognize valid operators for bit instructions */ ! 1333: 1.1 root 1334: int 1.1.1.2 ! root 1335: bit_operator (x, mode) ! 1336: rtx x; ! 1337: enum machine_mode mode; ! 1338: { ! 1339: enum rtx_code code = GET_CODE (x); ! 1340: ! 1341: return (code == XOR ! 1342: || code == AND ! 1343: || code == IOR); ! 1344: } ! 1345: ! 1346: /* Shifts. ! 1347: ! 1348: We devote a fair bit of code to getting efficient shifts since we can only ! 1349: shift one bit at a time. See the .md file for more comments. ! 1350: ! 1351: Here are some thoughts on what the absolutely positively best code is. ! 1352: "Best" here means some rational trade-off between code size and speed, ! 1353: where speed is more preferred but not at the expense of generating 20 insns. ! 1354: ! 1355: H8/300 QImode shifts ! 1356: 1-4 - do them inline ! 1357: 5-6 - ASHIFT | LSHIFTRT: rotate, mask off other bits ! 1358: ASHIFTRT: loop ! 1359: 7 - ASHIFT | LSHIFTRT: rotate, mask off other bits ! 1360: ASHIFTRT: shll, subx (propagate carry bit to all bits) ! 1361: ! 1362: H8/300 HImode shifts ! 1363: 1-4 - do them inline ! 1364: 5-6 - loop ! 1365: 7 - shift other way once, move byte into place, move carry bit into place ! 1366: 8 - move byte, zero (ASHIFT | LSHIFTRT) or sign extend other (ASHIFTRT) ! 1367: 9 - inline shift 1-4, move byte, set other byte ! 1368: 13-14 - ASHIFT | LSHIFTRT: rotate 3/2, mask, move byte, set other byte to 0 ! 1369: - ASHIFTRT: loop ! 1370: 15 - ASHIFT | LSHIFTRT: rotate 1, mask, move byte, set other byte to 0 ! 1371: - ASHIFTRT: shll, subx, set other byte ! 1372: ! 1373: H8/300 SImode shifts ! 1374: 1-2 - do them inline ! 1375: 3-6 - loop ! 1376: 7 - shift other way once, move bytes into place, ! 1377: move carry into place (possibly with sign extension) ! 1378: 8 - move bytes into place, zero or sign extend other ! 1379: 9-14 - loop ! 1380: 15 - shift other way once, move word into place, move carry into place ! 1381: 16 - move word, zero or sign extend other ! 1382: 17-23 - loop ! 1383: 24 - move bytes into place, zero or sign extend other ! 1384: 25-27 - loop ! 1385: 28-30 - ASHIFT | LSHIFTRT: rotate top byte, mask, move byte into place, ! 1386: zero others ! 1387: ASHIFTRT: loop ! 1388: 31 - ASHIFT | LSHIFTRT: rotate top byte, mask, byte byte into place, ! 1389: zero others ! 1390: ASHIFTRT: shll top byte, subx, copy to other bytes ! 1391: ! 1392: H8/300H QImode shifts ! 1393: - same as H8/300 ! 1394: ! 1395: H8/300H HImode shifts ! 1396: - same as H8/300 ! 1397: ! 1398: H8/300H SImode shifts ! 1399: (These are complicated by the fact that we don't have byte level access to ! 1400: the top word.) ! 1401: A word is: bytes 3,2,1,0 (msb -> lsb), word 1,0 (msw -> lsw) ! 1402: 1-4 - do them inline ! 1403: 5-14 - loop ! 1404: 15 - shift other way once, move word into place, move carry into place ! 1405: (with sign extension for ASHIFTRT) ! 1406: 16 - move word into place, zero or sign extend other ! 1407: 17-23 - loop ! 1408: 24 - ASHIFT: move byte 0(msb) to byte 1, zero byte 0, ! 1409: move word 0 to word 1, zero word 0 ! 1410: LSHIFTRT: move word 1 to word 0, move byte 1 to byte 0, ! 1411: zero word 1, zero byte 1 ! 1412: ASHIFTRT: move word 1 to word 0, move byte 1 to byte 0, ! 1413: sign extend byte 0, sign extend word 0 ! 1414: 25-27 - either loop, or ! 1415: do 24 bit shift, inline rest ! 1416: 28-30 - ASHIFT: rotate 4/3/2, mask ! 1417: LSHIFTRT: rotate 4/3/2, mask ! 1418: ASHIFTRT: loop ! 1419: 31 - shll, subx byte 0, sign extend byte 0, sign extend word 0 ! 1420: ! 1421: Don't Panic!!! ! 1422: ! 1423: All of these haven't been implemented. I've just documented them and ! 1424: provided hooks so they can be. ! 1425: */ ! 1426: ! 1427: int ! 1428: nshift_operator (x, mode) ! 1429: rtx x; ! 1430: enum machine_mode mode; ! 1431: { ! 1432: switch (GET_CODE (x)) ! 1433: { ! 1434: case ASHIFTRT: ! 1435: case LSHIFTRT: ! 1436: case ASHIFT: ! 1437: return 1; ! 1438: ! 1439: default: ! 1440: return 0; ! 1441: } ! 1442: } ! 1443: ! 1444: /* Called from the .md file to emit code to do shifts. ! 1445: Returns a boolean indicating success ! 1446: (currently this is always TRUE). */ ! 1447: ! 1448: int ! 1449: expand_a_shift (mode, code, operands) ! 1450: enum machine_mode mode; 1.1 root 1451: int code; 1452: rtx operands[]; 1453: { 1454: extern int rtx_equal_function_value_matters; 1455: 1456: emit_move_insn (operands[0], operands[1]); 1457: 1.1.1.2 ! root 1458: /* need a loop to get all the bits we want - we generate the ! 1459: code at emit time, but need to allocate a scratch reg now */ 1.1 root 1460: 1.1.1.2 ! root 1461: emit_insn (gen_rtx ! 1462: (PARALLEL, VOIDmode, ! 1463: gen_rtvec (2, ! 1464: gen_rtx (SET, VOIDmode, operands[0], ! 1465: gen_rtx (code, mode, operands[0], operands[2])), ! 1466: gen_rtx (CLOBBER, VOIDmode, gen_rtx (SCRATCH, QImode, 0))))); ! 1467: ! 1468: return 1; ! 1469: } 1.1 root 1470: 1.1.1.2 ! root 1471: /* Shift algorithm determination. 1.1 root 1472: 1.1.1.2 ! root 1473: There are various ways of doing a shift: ! 1474: SHIFT_INLINE: If the amount is small enough, just generate as many one-bit ! 1475: shifts as we need. ! 1476: SHIFT_ROT_AND: If the amount is large but close to either end, rotate the ! 1477: necessary bits into position and then set the rest to zero. ! 1478: SHIFT_SPECIAL: Hand crafted assembler. ! 1479: SHIFT_LOOP: If the above methods fail, just loop. */ ! 1480: ! 1481: enum shift_alg ! 1482: { ! 1483: SHIFT_INLINE, ! 1484: SHIFT_ROT_AND, ! 1485: SHIFT_SPECIAL, ! 1486: SHIFT_LOOP, ! 1487: SHIFT_MAX ! 1488: }; ! 1489: ! 1490: /* Symbols of the various shifts which can be used as indices. */ ! 1491: ! 1492: enum shift_type ! 1493: { ! 1494: SHIFT_ASHIFT, SHIFT_LSHIFTRT, SHIFT_ASHIFTRT ! 1495: }; ! 1496: ! 1497: /* Symbols of the various modes which can be used as indices. */ ! 1498: ! 1499: enum shift_mode ! 1500: { ! 1501: QIshift, HIshift, SIshift ! 1502: }; ! 1503: ! 1504: /* For single bit shift insns, record assembler and whether the condition code ! 1505: is valid afterwards. */ ! 1506: ! 1507: struct shift_insn ! 1508: { ! 1509: char *assembler; ! 1510: int cc_valid; ! 1511: }; ! 1512: ! 1513: /* Assembler instruction shift table. ! 1514: ! 1515: These tables are used to look up the basic shifts. ! 1516: They are indexed by cpu, shift_type, and mode. ! 1517: */ ! 1518: ! 1519: static const struct shift_insn shift_one[2][3][3] = ! 1520: { ! 1521: /* H8/300 */ ! 1522: { ! 1523: /* SHIFT_ASHIFT */ ! 1524: { ! 1525: { "shal %X0", 1 }, ! 1526: { "add.w %T0,%T0\t; shal.w", 1 }, ! 1527: { "add.w %f0,%f0\t; shal.l\n\taddx %y0,%y0\n\taddx %z0,%z0\t; end shal.l", 0 } ! 1528: }, ! 1529: /* SHIFT_LSHIFTRT */ ! 1530: { ! 1531: { "shlr %X0", 1 }, ! 1532: { "shlr %t0\t; shlr.w\n\trotxr %s0\t; end shlr.w", 0 }, ! 1533: { "shlr %z0\t; shlr.l\n\trotxr %y0\n\trotxr %x0\n\trotxr %w0\t; end shlr.l", 0 } ! 1534: }, ! 1535: /* SHIFT_ASHIFTRT */ ! 1536: { ! 1537: { "shar %X0", 1 }, ! 1538: { "shar %t0\t; shar.w\n\trotxr %s0\t; end shar.w", 0 }, ! 1539: { "shar %z0\t; shar.l\n\trotxr %y0\n\trotxr %x0\n\trotxr %w0\t; end shar.l", 0 } 1.1 root 1540: } 1.1.1.2 ! root 1541: }, ! 1542: /* H8/300H */ ! 1543: { ! 1544: /* SHIFT_ASHIFT */ ! 1545: { ! 1546: { "shal.b %X0", 1 }, ! 1547: { "shal.w %T0", 1 }, ! 1548: { "shal.l %S0", 1 } ! 1549: }, ! 1550: /* SHIFT_LSHIFTRT */ 1.1 root 1551: { 1.1.1.2 ! root 1552: { "shlr.b %X0", 1 }, ! 1553: { "shlr.w %T0", 1 }, ! 1554: { "shlr.l %S0", 1 } ! 1555: }, ! 1556: /* SHIFT_ASHIFTRT */ ! 1557: { ! 1558: { "shar.b %X0", 1 }, ! 1559: { "shar.w %T0", 1 }, ! 1560: { "shar.l %S0", 1 } ! 1561: } ! 1562: } ! 1563: }; 1.1 root 1564: 1.1.1.2 ! root 1565: /* Rotates are organized by which shift they'll be used in implementing. ! 1566: There's no need to record whether the cc is valid afterwards because ! 1567: it is the AND insn that will decide this. */ 1.1 root 1568: 1.1.1.2 ! root 1569: static const char *const rotate_one[2][3][3] = ! 1570: { ! 1571: /* H8/300 */ ! 1572: { ! 1573: /* SHIFT_ASHIFT */ ! 1574: { ! 1575: "rotr %X0", ! 1576: "shlr %t0\t; rotr.w\n\trotxr %s0\n\tbst #7,%t0\t; end rotr.w", ! 1577: 0 ! 1578: }, ! 1579: /* SHIFT_LSHIFTRT */ ! 1580: { ! 1581: "rotl %X0", ! 1582: "shll %s0\t; rotl.w\n\trotxl %t0\n\tbst #0,%s0\t; end rotl.w", ! 1583: 0 ! 1584: }, ! 1585: /* SHIFT_ASHIFTRT */ ! 1586: { ! 1587: "rotl %X0", ! 1588: "shll %s0\t; rotl.w\n\trotxl %t0\n\tbst #0,%s0\t; end rotl.w", ! 1589: 0 ! 1590: } ! 1591: }, ! 1592: /* H8/300H */ ! 1593: { ! 1594: /* SHIFT_ASHIFT */ ! 1595: { ! 1596: "rotr.b %X0", ! 1597: "rotr.w %T0", ! 1598: "rotr.l %S0" ! 1599: }, ! 1600: /* SHIFT_LSHIFTRT */ ! 1601: { ! 1602: "rotl.b %X0", ! 1603: "rotl.w %T0", ! 1604: "rotl.l %S0" ! 1605: }, ! 1606: /* SHIFT_ASHIFTRT */ ! 1607: { ! 1608: "rotl.b %X0", ! 1609: "rotl.w %T0", ! 1610: "rotl.l %S0" ! 1611: } ! 1612: } ! 1613: }; ! 1614: ! 1615: /* Given CPU, MODE, SHIFT_TYPE, and shift count COUNT, determine the best ! 1616: algorithm for doing the shift. The assembler code is stored in ASSEMBLER. ! 1617: We don't achieve maximum efficiency in all cases, but the hooks are here ! 1618: to do so. ! 1619: ! 1620: For now we just use lots of switch statements. Since we don't even come ! 1621: close to supporting all the cases, this is simplest. If this function ever ! 1622: gets too big, perhaps resort to a more table based lookup. Of course, ! 1623: at this point you may just wish to do it all in rtl. ! 1624: ! 1625: WARNING: The constraints on insns shiftbyn_QI/HI/SI assume shifts of ! 1626: 1,2,3,4 will be inlined (1,2 for SI). */ ! 1627: ! 1628: static enum shift_alg ! 1629: get_shift_alg (cpu, shift_type, mode, count, assembler_p, cc_valid_p) ! 1630: enum attr_cpu cpu; ! 1631: enum shift_type shift_type; ! 1632: enum machine_mode mode; ! 1633: int count; ! 1634: const char **assembler_p; ! 1635: int *cc_valid_p; ! 1636: { ! 1637: /* The default is to loop. */ ! 1638: enum shift_alg alg = SHIFT_LOOP; ! 1639: enum shift_mode shift_mode; ! 1640: ! 1641: /* We don't handle negative shifts or shifts greater than the word size, ! 1642: they should have been handled already. */ ! 1643: ! 1644: if (count < 0 || count > GET_MODE_BITSIZE (mode)) ! 1645: abort (); ! 1646: ! 1647: switch (mode) ! 1648: { ! 1649: case QImode: ! 1650: shift_mode = QIshift; ! 1651: break; ! 1652: case HImode: ! 1653: shift_mode = HIshift; ! 1654: break; ! 1655: case SImode: ! 1656: shift_mode = SIshift; ! 1657: break; ! 1658: default: ! 1659: abort (); ! 1660: } ! 1661: ! 1662: /* Assume either SHIFT_LOOP or SHIFT_INLINE. ! 1663: It is up to the caller to know that looping clobbers cc. */ ! 1664: *assembler_p = shift_one[cpu][shift_type][shift_mode].assembler; ! 1665: *cc_valid_p = shift_one[cpu][shift_type][shift_mode].cc_valid; ! 1666: ! 1667: /* Now look for cases we want to optimize. */ ! 1668: ! 1669: switch (shift_mode) ! 1670: { ! 1671: case QIshift: ! 1672: if (count <= 4) ! 1673: return SHIFT_INLINE; ! 1674: else if (count <= 6) ! 1675: { ! 1676: if (shift_type == SHIFT_ASHIFTRT) ! 1677: { ! 1678: return SHIFT_LOOP; ! 1679: } ! 1680: else ! 1681: { ! 1682: *assembler_p = rotate_one[cpu][shift_type][shift_mode]; ! 1683: *cc_valid_p = 0; ! 1684: return SHIFT_ROT_AND; ! 1685: } ! 1686: } ! 1687: else if (count == 7) ! 1688: { ! 1689: if (shift_type == SHIFT_ASHIFTRT) ! 1690: { ! 1691: *assembler_p = "shll %X0\t; shar.b(7)\n\tsubx %X0,%X0\t; end shar.b(7)"; ! 1692: *cc_valid_p = 0; ! 1693: return SHIFT_SPECIAL; ! 1694: } ! 1695: else ! 1696: { ! 1697: *assembler_p = rotate_one[cpu][shift_type][shift_mode]; ! 1698: *cc_valid_p = 0; ! 1699: return SHIFT_ROT_AND; ! 1700: } ! 1701: } ! 1702: break; ! 1703: case HIshift: ! 1704: if (count <= 4) ! 1705: return SHIFT_INLINE; ! 1706: else if (count == 8) ! 1707: { ! 1708: switch (shift_type) ! 1709: { ! 1710: case SHIFT_ASHIFT: ! 1711: *assembler_p = "mov.b %s0,%t0\t; shal.w(8)\n\tsub.b %s0,%s0\t; end shal.w(8)"; ! 1712: *cc_valid_p = 0; ! 1713: return SHIFT_SPECIAL; ! 1714: case SHIFT_LSHIFTRT: ! 1715: *assembler_p = "mov.b %t0,%s0\t; shlr.w(8)\n\tsub.b %t0,%t0\t; end shlr.w(8)"; ! 1716: *cc_valid_p = 0; ! 1717: return SHIFT_SPECIAL; ! 1718: case SHIFT_ASHIFTRT: ! 1719: if (cpu == CPU_H8300) ! 1720: *assembler_p = "mov.b %t0,%s0\t; shar.w(8)\n\tshll %t0\n\tsubx %t0,%t0\t; end shar.w(8)"; ! 1721: else ! 1722: *assembler_p = "mov.b %t0,%s0\t; shar.w(8)\n\texts.w %T0\t; end shar.w(8)"; ! 1723: *cc_valid_p = 0; ! 1724: return SHIFT_SPECIAL; ! 1725: } ! 1726: abort (); 1.1 root 1727: } 1.1.1.2 ! root 1728: else if (count == 15) 1.1 root 1729: { 1.1.1.2 ! root 1730: if (shift_type == SHIFT_ASHIFTRT) ! 1731: { ! 1732: *assembler_p = "shll %t0,%t0\t; shar.w(15)\n\tsubx %t0,%t0\n\tmov.b %t0,%s0\t; end shar.w(15)"; ! 1733: *cc_valid_p = 0; ! 1734: return SHIFT_SPECIAL; ! 1735: } ! 1736: else ! 1737: { ! 1738: *assembler_p = rotate_one[cpu][shift_type][shift_mode]; ! 1739: *cc_valid_p = 0; ! 1740: return SHIFT_ROT_AND; ! 1741: } ! 1742: } ! 1743: break; ! 1744: case SIshift: ! 1745: if (count <= (cpu == CPU_H8300 ? 2 : 4)) ! 1746: return SHIFT_INLINE; ! 1747: else if (count == 8) ! 1748: { ! 1749: if (cpu == CPU_H8300) ! 1750: { ! 1751: switch (shift_type) ! 1752: { ! 1753: case SHIFT_ASHIFT: ! 1754: *assembler_p = "mov.b %y0,%z0\t; shal.l(8)\n\tmov.b %x0,%y0\n\tmov.b %w0,%x0\n\tsub.b %w0,%w0\t; end shal.l(8)"; ! 1755: *cc_valid_p = 0; ! 1756: return SHIFT_SPECIAL; ! 1757: case SHIFT_LSHIFTRT: ! 1758: *assembler_p = "mov.b %x0,%w0\t; shlr.l(8)\n\tmov.b %y0,%x0\n\tmov.b %z0,%y0\n\tsub.b %z0,%z0\t; end shlr.l(8)"; ! 1759: *cc_valid_p = 0; ! 1760: return SHIFT_SPECIAL; ! 1761: case SHIFT_ASHIFTRT: ! 1762: *assembler_p = "mov.b %x0,%w0\t; shar.l(8)\n\tmov.b %y0,%x0\n\tmov.b %z0,%y0\n\tshll %z0\n\tsubx %z0,%z0; end shar.l(8)"; ! 1763: *cc_valid_p = 0; ! 1764: return SHIFT_SPECIAL; ! 1765: } ! 1766: } ! 1767: else /* CPU_H8300H */ ! 1768: /* We don't have byte level access to the high word so this isn't ! 1769: easy to do. For now, just loop. */ ! 1770: ; ! 1771: } ! 1772: else if (count == 16) ! 1773: { ! 1774: switch (shift_type) ! 1775: { ! 1776: case SHIFT_ASHIFT: ! 1777: *assembler_p = "mov.w %f0,%e0\t; shal.l(16)\n\tsub.w %f0,%f0\t; end shal.l(16)"; ! 1778: *cc_valid_p = 0; ! 1779: return SHIFT_SPECIAL; ! 1780: case SHIFT_LSHIFTRT: ! 1781: *assembler_p = "mov.w %e0,%f0\t; shlr.l(16)\n\tsub.w %e0,%e0\t; end shlr.l(16)"; ! 1782: *cc_valid_p = 0; ! 1783: return SHIFT_SPECIAL; ! 1784: case SHIFT_ASHIFTRT: ! 1785: if (cpu == CPU_H8300) ! 1786: *assembler_p = "mov.w %e0,%f0\t; shar.l(16)\n\tshll %z0\n\tsubx %z0,%z0\n\tmov.b %z0,%y0\t; end shar.l(16)"; ! 1787: else ! 1788: *assembler_p = "mov.w %e0,%f0\t; shar.l(16)\n\texts.l %S0\t; end shar.l(16)"; ! 1789: *cc_valid_p = 0; ! 1790: return SHIFT_SPECIAL; ! 1791: } ! 1792: } ! 1793: else if (count >= 28 && count <= 30) ! 1794: { ! 1795: if (shift_type == SHIFT_ASHIFTRT) ! 1796: { ! 1797: return SHIFT_LOOP; ! 1798: } ! 1799: else ! 1800: { ! 1801: if (cpu == CPU_H8300) ! 1802: return SHIFT_LOOP; ! 1803: else ! 1804: { ! 1805: *assembler_p = rotate_one[cpu][shift_type][shift_mode]; ! 1806: *cc_valid_p = 0; ! 1807: return SHIFT_ROT_AND; ! 1808: } ! 1809: } ! 1810: } ! 1811: else if (count == 31) ! 1812: { ! 1813: if (shift_type == SHIFT_ASHIFTRT) ! 1814: { ! 1815: if (cpu == CPU_H8300) ! 1816: *assembler_p = "shll %z0\t; shar.l(31)\n\tsubx %w0,%w0\n\tmov.b %w0,%x0\n\tmov.w %f0,%e0\t; end shar.l(31)"; ! 1817: else ! 1818: *assembler_p = "shll %e0\t; shar.l(31)\n\tsubx %w0,%w0\n\tmov.b %w0,%x0\n\tmov.w %f0,%e0\t; end shar.l(31)"; ! 1819: *cc_valid_p = 0; ! 1820: return SHIFT_SPECIAL; ! 1821: } ! 1822: else ! 1823: { ! 1824: if (cpu == CPU_H8300) ! 1825: { ! 1826: if (shift_type == SHIFT_ASHIFT) ! 1827: *assembler_p = "sub.w %e0,%e0\t; shal.l(31)\n\tshlr %w0\n\tmov.w %e0,%f0\n\trotxr %z0\t; end shal.l(31)"; ! 1828: else ! 1829: *assembler_p = "sub.w %f0,%f0\t; shlr.l(31)\n\tshll %z0\n\tmov.w %f0,%e0\n\trotxl %w0\t; end shlr.l(31)"; ! 1830: *cc_valid_p = 0; ! 1831: return SHIFT_SPECIAL; ! 1832: } ! 1833: else ! 1834: { ! 1835: *assembler_p = rotate_one[cpu][shift_type][shift_mode]; ! 1836: *cc_valid_p = 0; ! 1837: return SHIFT_ROT_AND; ! 1838: } ! 1839: } 1.1 root 1840: } 1.1.1.2 ! root 1841: break; ! 1842: default: ! 1843: abort (); 1.1 root 1844: } 1.1.1.2 ! root 1845: ! 1846: return alg; 1.1 root 1847: } 1848: 1.1.1.2 ! root 1849: /* Emit the assembler code for doing shifts. */ ! 1850: ! 1851: char * ! 1852: emit_a_shift (insn, operands) ! 1853: rtx insn; ! 1854: rtx *operands; 1.1 root 1855: { 1.1.1.2 ! root 1856: static int loopend_lab; ! 1857: char *assembler; ! 1858: int cc_valid; ! 1859: rtx inside = PATTERN (insn); ! 1860: rtx shift = operands[3]; ! 1861: enum machine_mode mode = GET_MODE (shift); ! 1862: enum rtx_code code = GET_CODE (shift); ! 1863: enum shift_type shift_type; ! 1864: enum shift_mode shift_mode; ! 1865: ! 1866: loopend_lab++; 1.1 root 1867: 1.1.1.2 ! root 1868: switch (mode) 1.1 root 1869: { 1.1.1.2 ! root 1870: case QImode: ! 1871: shift_mode = QIshift; ! 1872: break; ! 1873: case HImode: ! 1874: shift_mode = HIshift; ! 1875: break; ! 1876: case SImode: ! 1877: shift_mode = SIshift; ! 1878: break; ! 1879: default: ! 1880: abort (); ! 1881: } 1.1 root 1882: 1.1.1.2 ! root 1883: switch (code) ! 1884: { ! 1885: case ASHIFTRT: ! 1886: shift_type = SHIFT_ASHIFTRT; ! 1887: break; ! 1888: case LSHIFTRT: ! 1889: shift_type = SHIFT_LSHIFTRT; ! 1890: break; ! 1891: case ASHIFT: ! 1892: shift_type = SHIFT_ASHIFT; ! 1893: break; ! 1894: default: ! 1895: abort (); ! 1896: } ! 1897: ! 1898: if (GET_CODE (operands[2]) != CONST_INT) ! 1899: { ! 1900: /* Indexing by reg, so have to loop and test at top */ ! 1901: output_asm_insn ("mov.b %X2,%X4", operands); ! 1902: fprintf (asm_out_file, "\tble .Lle%d\n", loopend_lab); ! 1903: ! 1904: /* Get the assembler code to do one shift. */ ! 1905: get_shift_alg (cpu_type, shift_type, mode, 1, &assembler, &cc_valid); ! 1906: } ! 1907: else ! 1908: { ! 1909: int n = INTVAL (operands[2]); ! 1910: enum shift_alg alg; ! 1911: ! 1912: /* If the count is negative, make it 0. */ ! 1913: if (n < 0) ! 1914: n = 0; ! 1915: /* If the count is too big, truncate it. ! 1916: ANSI says shifts of GET_MODE_BITSIZE are undefined - we choose to ! 1917: do the intuitive thing. */ ! 1918: else if (n > GET_MODE_BITSIZE (mode)) ! 1919: n = GET_MODE_BITSIZE (mode); ! 1920: ! 1921: alg = get_shift_alg (cpu_type, shift_type, mode, n, &assembler, &cc_valid); ! 1922: ! 1923: switch (alg) ! 1924: { ! 1925: case SHIFT_INLINE: ! 1926: while (--n >= 0) ! 1927: output_asm_insn (assembler, operands); ! 1928: if (cc_valid) ! 1929: cc_status.value1 = operands[0]; ! 1930: return ""; ! 1931: case SHIFT_ROT_AND: ! 1932: { ! 1933: int m = GET_MODE_BITSIZE (mode) - n; ! 1934: int mask = (shift_type == SHIFT_ASHIFT ! 1935: ? ((1 << GET_MODE_BITSIZE (mode) - n) - 1) << n ! 1936: : (1 << GET_MODE_BITSIZE (mode) - n) - 1); ! 1937: char insn_buf[200]; ! 1938: /* Not all possibilities of rotate are supported. They shouldn't ! 1939: be generated, but let's watch for 'em. */ ! 1940: if (assembler == 0) ! 1941: abort (); ! 1942: while (--m >= 0) ! 1943: output_asm_insn (assembler, operands); ! 1944: if (TARGET_H8300) ! 1945: { ! 1946: switch (mode) ! 1947: { ! 1948: case QImode: ! 1949: sprintf (insn_buf, "and #%d,%%X0\t; end shift %d via rotate+and", ! 1950: mask, n); ! 1951: cc_status.value1 = operands[0]; ! 1952: break; ! 1953: case HImode: ! 1954: sprintf (insn_buf, "and #%d,%%s0\n\tand #%d,%%t0\t; end shift %d via rotate+and", ! 1955: mask & 255, mask >> 8, n); ! 1956: break; ! 1957: case SImode: ! 1958: abort (); ! 1959: } ! 1960: } ! 1961: else ! 1962: { ! 1963: sprintf (insn_buf, "and.%c #%d,%%%c0", ! 1964: "bwl"[shift_mode], mask, ! 1965: mode == QImode ? 'X' : mode == HImode ? 'T' : 'S'); ! 1966: cc_status.value1 = operands[0]; ! 1967: } ! 1968: output_asm_insn (insn_buf, operands); ! 1969: return ""; ! 1970: } ! 1971: case SHIFT_SPECIAL: ! 1972: output_asm_insn (assembler, operands); ! 1973: return ""; 1.1 root 1974: } 1.1.1.2 ! root 1975: ! 1976: /* Need a loop, move limit to tmp reg */ ! 1977: fprintf (asm_out_file, "\tmov.b #%d,%sl\n", n, names_big[REGNO (operands[4])]); 1.1 root 1978: } 1.1.1.2 ! root 1979: ! 1980: fprintf (asm_out_file, ".Llt%d:\n", loopend_lab); ! 1981: output_asm_insn (assembler, operands); ! 1982: output_asm_insn ("add #0xff,%X4", operands); ! 1983: fprintf (asm_out_file, "\tbne .Llt%d\n", loopend_lab); ! 1984: fprintf (asm_out_file, ".Lle%d:\n", loopend_lab); ! 1985: ! 1986: return ""; 1.1 root 1987: } 1.1.1.2 ! root 1988: ! 1989: /* Fix the operands of a gen_xxx so that it could become a bit ! 1990: operating insn. */ 1.1 root 1991: 1992: int 1.1.1.2 ! root 1993: fix_bit_operand (operands, what, type) ! 1994: rtx *operands; ! 1995: char what; ! 1996: enum rtx_code type; 1.1 root 1997: { 1.1.1.2 ! root 1998: /* The bit_operand predicate accepts any memory durint RTL generation, but ! 1999: only 'U' memory afterwards, so if this is a MEM operand, we must force ! 2000: it to be valid for 'U' by reloading the address. */ 1.1 root 2001: 1.1.1.2 ! root 2002: if (GET_CODE (operands[2]) == CONST_INT) 1.1 root 2003: { 1.1.1.2 ! root 2004: if (CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), what)) ! 2005: { ! 2006: /* Ok to have a memory dest. */ ! 2007: if (GET_CODE (operands[0]) == MEM && !EXTRA_CONSTRAINT (operands[0], 'U')) ! 2008: { ! 2009: rtx mem; ! 2010: mem = gen_rtx (MEM, GET_MODE (operands[0]), ! 2011: copy_to_mode_reg (Pmode, XEXP (operands[0], 0))); ! 2012: RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (operands[0]); ! 2013: MEM_IN_STRUCT_P (mem) = MEM_IN_STRUCT_P (operands[0]); ! 2014: MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[0]); ! 2015: operands[0] = mem; ! 2016: } ! 2017: ! 2018: if (GET_CODE (operands[1]) == MEM && !EXTRA_CONSTRAINT (operands[1], 'U')) ! 2019: { ! 2020: rtx mem; ! 2021: mem = gen_rtx (MEM, GET_MODE (operands[1]), ! 2022: copy_to_mode_reg (Pmode, XEXP (operands[1], 0))); ! 2023: RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (operands[1]); ! 2024: MEM_IN_STRUCT_P (mem) = MEM_IN_STRUCT_P (operands[1]); ! 2025: MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[1]); ! 2026: operands[1] = mem; ! 2027: } ! 2028: return 0; ! 2029: } ! 2030: } 1.1 root 2031: 1.1.1.2 ! root 2032: /* Dest and src op must be register. */ 1.1 root 2033: 1.1.1.2 ! root 2034: operands[1] = force_reg (QImode, operands[1]); ! 2035: { ! 2036: rtx res = gen_reg_rtx (QImode); ! 2037: emit_insn (gen_rtx (SET, VOIDmode, res, gen_rtx (type, QImode, operands[1], operands[2]))); ! 2038: emit_insn (gen_rtx (SET, VOIDmode, operands[0], res)); ! 2039: } ! 2040: return 1; 1.1 root 2041: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.