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