|
|
1.1 root 1: /* Subroutines for insn-output.c for Sun SPARC.
2: Copyright (C) 1987 Free Software Foundation, Inc.
3: Contributed by Michael Tiemann ([email protected])
4:
5: This file is part of GNU CC.
6:
7: GNU CC is distributed in the hope that it will be useful,
8: but WITHOUT ANY WARRANTY. No author or distributor
9: accepts responsibility to anyone for the consequences of using it
10: or for whether it serves any particular purpose or works at all,
11: unless he says so in writing. Refer to the GNU CC General Public
12: License for full details.
13:
14: Everyone is granted permission to copy, modify and redistribute
15: GNU CC, but only under the conditions described in the
16: GNU CC General Public License. A copy of this license is
17: supposed to have been given to you along with GNU CC so you
18: can know your rights and responsibilities. It should be in a
19: file named COPYING. Among other things, the copyright notice
20: and this notice must be preserved on all copies. */
21:
22: /* Global variables for machine-dependend things. */
23:
24: /* This should go away if we pass floats to regs via
25: the stack instead of the frame. */
26: extern int frame_pointer_needed;
27:
28: static rtx find_addr_reg ();
29:
30: #if 0
31: /* RTL expressions that we will cache during the entire compilation. */
32: rtx reg_o0_rtx, reg_o1_rtx, reg_o2_rtx, reg_i7_rtx;
33:
34: void
35: init_emit_mdep ()
36: {
37: /* These may be freely shared. */
38: reg_o0_rtx = gen_rtx (REG, SImode, 8);
39: reg_o1_rtx = gen_rtx (REG, SImode, 9);
40: reg_o2_rtx = gen_rtx (REG, SImode, 10);
41: reg_i7_rtx = gen_rtx (REG, SImode, 31);
42: }
43: #endif
44:
45: int
46: arith_operand (op, mode)
47: rtx op;
48: enum machine_mode mode;
49: {
50: return (register_operand (op, mode)
51: || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
52: }
53:
54: int
55: arith32_operand (op, mode)
56: rtx op;
57: enum machine_mode mode;
58: {
59: return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
60: }
61:
1.1.1.3 ! root 62: int
! 63: small_int (op, mode)
! 64: rtx op;
! 65: enum machine_mode mode;
! 66: {
! 67: return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
! 68: }
! 69:
1.1 root 70: /* Return the best assembler insn template
71: for moving operands[1] into operands[0] as a fullword. */
72:
73: static char *
74: singlemove_string (operands)
75: rtx *operands;
76: {
77: if (GET_CODE (operands[0]) == MEM)
78: return "st %r1,%0";
79: if (GET_CODE (operands[1]) == MEM)
80: return "ld %1,%0";
1.1.1.3 ! root 81: return "mov %1,%0";
1.1 root 82: }
83:
84: /* Output assembler code to perform a doubleword move insn
85: with operands OPERANDS. */
86:
87: char *
88: output_move_double (operands)
89: rtx *operands;
90: {
91: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
92: rtx latehalf[2];
93: rtx addreg0 = 0, addreg1 = 0;
94:
95: /* First classify both operands. */
96:
97: if (REG_P (operands[0]))
98: optype0 = REGOP;
99: else if (offsetable_memref_p (operands[0]))
100: optype0 = OFFSOP;
101: else if (GET_CODE (operands[0]) == MEM)
102: optype0 = MEMOP;
103: else
104: optype0 = RNDOP;
105:
106: if (REG_P (operands[1]))
107: optype1 = REGOP;
108: else if (CONSTANT_P (operands[1])
109: || GET_CODE (operands[1]) == CONST_DOUBLE)
110: optype1 = CNSTOP;
111: else if (offsetable_memref_p (operands[1]))
112: optype1 = OFFSOP;
113: else if (GET_CODE (operands[1]) == MEM)
114: optype0 = MEMOP;
115: else
116: optype1 = RNDOP;
117:
118: /* Check for the cases that the operand constraints are not
119: supposed to allow to happen. Abort if we get one,
120: because generating code for these cases is painful. */
121:
122: if (optype0 == RNDOP || optype1 == RNDOP)
123: abort ();
124:
125: /* If an operand is an unoffsettable memory ref, find a register
126: we can increment temporarily to make it refer to the second word. */
127:
128: if (optype0 == MEMOP)
129: addreg0 = find_addr_reg (operands[0]);
130:
131: if (optype1 == MEMOP)
132: addreg1 = find_addr_reg (operands[1]);
133:
134: /* Ok, we can do one word at a time.
135: Normally we do the low-numbered word first,
136: but if either operand is autodecrementing then we
137: do the high-numbered word first.
138:
139: In either case, set up in LATEHALF the operands to use
140: for the high-numbered word and in some cases alter the
141: operands in OPERANDS to be suitable for the low-numbered word. */
142:
143: if (optype0 == REGOP)
144: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
145: else if (optype0 == OFFSOP)
146: latehalf[0] = adj_offsetable_operand (operands[0], 4);
147: else
148: latehalf[0] = operands[0];
149:
150: if (optype1 == REGOP)
151: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
152: else if (optype1 == OFFSOP)
153: latehalf[1] = adj_offsetable_operand (operands[1], 4);
154: else if (optype1 == CNSTOP)
155: {
156: if (CONSTANT_P (operands[1]))
157: latehalf[1] = const0_rtx;
158: else if (GET_CODE (operands[1]) == CONST_DOUBLE)
159: {
160: latehalf[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 1));
161: operands[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 0));
162: }
163: }
164: else
165: latehalf[1] = operands[1];
166:
167: /* If the first move would clobber the source of the second one,
1.1.1.3 ! root 168: do them in the other order.
! 169:
! 170: RMS says "This happens only for registers;
1.1 root 171: such overlap can't happen in memory unless the user explicitly
1.1.1.3 ! root 172: sets it up, and that is an undefined circumstance."
! 173:
! 174: but it happens on the sparc when loading parameter registers,
! 175: so I am going to define that circumstance, and make it work
! 176: as expected. */
! 177:
! 178: /* Easy case: try moving both words at once. */
! 179: if ((optype0 == REGOP && optype1 != REGOP
! 180: && (REGNO (operands[0]) & 1) == 0)
! 181: || (optype0 != REGOP && optype1 == REGOP
! 182: && (REGNO (operands[1]) & 1) == 0))
! 183: {
! 184: rtx op1, op2;
! 185: rtx base = 0, offset = const0_rtx;
1.1 root 186:
1.1.1.3 ! root 187: if (optype0 == REGOP)
! 188: op1 = operands[0], op2 = XEXP (operands[1], 0);
! 189: else
! 190: op1 = operands[1], op2 = XEXP (operands[0], 0);
! 191:
! 192: /* We know structs are properly aligned. */
! 193: if (operands[1]->in_struct)
! 194: return "ldd %1,%0";
! 195: if (operands[0]->in_struct)
! 196: return "std %1,%0";
! 197:
! 198: /* Otherwise, only trust global variables
! 199: and even offsets from the frame pointer. */
! 200: if (GET_CODE (op2) == SYMBOL_REF
! 201: || GET_CODE (op2) == CONST
! 202: || GET_CODE (op2) == REG)
! 203: base = op2;
! 204: else if (GET_CODE (op2) == PLUS)
! 205: if (GET_CODE (XEXP (op2, 0)) == REG)
! 206: base = XEXP (op2, 0),
! 207: offset = XEXP (op2, 1);
! 208: else if (GET_CODE (XEXP (op2, 1)) == REG)
! 209: base = XEXP (op2, 1),
! 210: offset = XEXP (op2, 0);
! 211:
! 212: if (base
! 213: && (GET_CODE (base) != REG
! 214: || (REGNO (base) == FRAME_POINTER_REGNUM
! 215: && GET_CODE (offset) == CONST_INT
! 216: && INTVAL (offset) & 0x7 == 0)))
! 217: if (op1 == operands[0])
! 218: return "ldd %1,%0";
! 219: else
! 220: return "std %1,%0";
! 221: }
! 222:
1.1 root 223: if (optype0 == REGOP && optype1 == REGOP
224: && REGNO (operands[0]) == REGNO (latehalf[1]))
225: {
226: /* Make any unoffsetable addresses point at high-numbered word. */
227: if (addreg0)
228: output_asm_insn ("add %0,0x4,%0", &addreg0);
229: if (addreg1)
230: output_asm_insn ("add %0,0x4,%0", &addreg1);
231:
232: /* Do that word. */
233: output_asm_insn (singlemove_string (latehalf), latehalf);
234:
235: /* Undo the adds we just did. */
236: if (addreg0)
237: output_asm_insn ("add %0,-0x4,%0", &addreg0);
238: if (addreg1)
239: output_asm_insn ("add %0,-0x4,%0", &addreg0);
240:
241: /* Do low-numbered word. */
242: return singlemove_string (operands);
243: }
1.1.1.3 ! root 244: else if (optype0 == REGOP && optype1 != REGOP
! 245: && reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
! 246: {
! 247: /* Do the late half first. */
! 248: output_asm_insn (singlemove_string (latehalf), latehalf);
! 249: /* Then clobber. */
! 250: return singlemove_string (operands);
! 251: }
1.1 root 252:
253: /* Normal case: do the two words, low-numbered first. */
254:
255: output_asm_insn (singlemove_string (operands), operands);
256:
257: /* Make any unoffsetable addresses point at high-numbered word. */
258: if (addreg0)
259: output_asm_insn ("add %0,0x4,%0", &addreg0);
260: if (addreg1)
261: output_asm_insn ("add %0,0x4,%0", &addreg1);
262:
263: /* Do that word. */
264: output_asm_insn (singlemove_string (latehalf), latehalf);
265:
266: /* Undo the adds we just did. */
267: if (addreg0)
268: output_asm_insn ("add %0,-0x4,%0", &addreg0);
269: if (addreg1)
270: output_asm_insn ("add %0,-0x4,%0", &addreg1);
271:
272: return "";
273: }
274:
275: static char *
276: output_fp_move_double (operands)
277: rtx *operands;
278: {
279: if (FP_REG_P (operands[0]))
280: {
281: if (FP_REG_P (operands[1]))
282: {
283: output_asm_insn ("fmovs %1,%0", operands);
284: operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
285: operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
286: return "fmovs %1,%0";
287: }
288: if (GET_CODE (operands[1]) == REG)
289: {
1.1.1.3 ! root 290: if ((REGNO (operands[1]) & 1) == 0)
! 291: return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0";
! 292: else
! 293: {
! 294: rtx xoperands[3];
! 295: xoperands[0] = operands[0];
! 296: xoperands[1] = operands[1];
! 297: xoperands[2] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
! 298: output_asm_insn ("st %2,[%%fp-4]\n\tst %1,[%%fp-8]\n\tldd [%%fp-8],%0", xoperands);
! 299: return "";
! 300: }
1.1 root 301: }
302: return "ldd %1,%0";
303: }
304: else if (FP_REG_P (operands[1]))
305: {
306: if (GET_CODE (operands[0]) == REG)
307: {
1.1.1.3 ! root 308: if ((REGNO (operands[0]) & 1) == 0)
! 309: return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0";
! 310: else
! 311: {
! 312: rtx xoperands[3];
! 313: xoperands[2] = operands[1];
! 314: xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
! 315: xoperands[0] = operands[0];
! 316: output_asm_insn ("std %2,[%%fp-8]\n\tld [%%fp-4],%1\n\tld [%%fp-8],%0", xoperands);
! 317: return "";
! 318: }
1.1 root 319: }
320: return "std %1,%0";
321: }
1.1.1.3 ! root 322: else abort ();
1.1 root 323: }
324:
325: /* Return a REG that occurs in ADDR with coefficient 1.
326: ADDR can be effectively incremented by incrementing REG. */
327:
328: static rtx
329: find_addr_reg (addr)
330: rtx addr;
331: {
332: while (GET_CODE (addr) == PLUS)
333: {
334: if (GET_CODE (XEXP (addr, 0)) == REG)
335: addr = XEXP (addr, 0);
336: if (GET_CODE (XEXP (addr, 1)) == REG)
337: addr = XEXP (addr, 1);
338: if (CONSTANT_P (XEXP (addr, 0)))
339: addr = XEXP (addr, 1);
340: if (CONSTANT_P (XEXP (addr, 1)))
341: addr = XEXP (addr, 0);
342: }
343: if (GET_CODE (addr) == REG)
344: return addr;
345: return 0;
346: }
347:
348: /* Load the address specified by OPERANDS[3] into the register
349: specified by OPERANDS[0].
350:
351: OPERANDS[3] may be the result of a sum, hence it could either be:
352:
353: (1) CONST
354: (2) REG
355: (2) REG + CONST_INT
356: (3) REG + REG + CONST_INT
357:
358: All cases are handled here. */
359:
360: void
361: output_load_address (operands)
362: rtx *operands;
363: {
364: rtx base, offset;
365:
366: if (CONSTANT_P (operands[3]))
367: {
368: output_asm_insn ("set %3,%0", operands);
369: return;
370: }
371:
372: if (REG_P (operands[3]))
373: {
374: if (REGNO (operands[0]) != REGNO (operands[3]))
375: output_asm_insn ("mov %3,%0", operands);
376: return;
377: }
378:
379: base = XEXP (operands[3], 0);
380: offset = XEXP (operands[3], 1);
381:
382: if (GET_CODE (base) == CONST_INT)
383: {
384: rtx tmp = base;
385: base = offset;
386: offset = tmp;
387: }
388:
389: if (GET_CODE (offset) != CONST_INT)
390: abort ();
391:
392: if (REG_P (base))
393: {
394: operands[6] = base;
395: operands[7] = offset;
396: if (SMALL_INT (offset))
397: output_asm_insn ("add %6,%7,%0", operands);
398: else
399: output_asm_insn ("set %7,%0\n\tadd %0,%6,%0", operands);
400: }
401: else
402: {
403: operands[6] = XEXP (base, 0);
404: operands[7] = XEXP (base, 1);
405: operands[8] = offset;
406:
407: if (SMALL_INT (offset))
408: output_asm_insn ("add %6,%7,%0\n\tadd %0,%8,%0", operands);
409: else
410: output_asm_insn ("set %8,%0\n\tadd %0,%6,%0\n\tadd %0,%7,%0", operands);
411: }
412: }
413:
414: char *
415: output_block_move (operands)
416: rtx *operands;
417: {
418: static int movstrsi_label = 0;
419: int align = 4;
420:
421: rtx xoperands[9];
422: int available[3];
423: int i, j;
424:
425: /* Since we clobber untold things, nix the condition codes. */
426: CC_STATUS_INIT;
427:
428: /* Get past the MEMs. */
429: operands[0] = XEXP (operands[0], 0);
430: operands[1] = XEXP (operands[1], 0);
431:
432: xoperands[0] = 0;
433: xoperands[1] = 0;
434: xoperands[2] = 0;
435:
436: available[0] = 1;
437: available[1] = 1;
438: available[2] = 1;
439: #if 1
440: /* Prepare to juggle registers if necessary. */
441: if (REG_P (operands[0]) && (unsigned) (REGNO (operands[0]) - 8) < 3)
442: {
443: xoperands[0] = operands[0];
444: available[REGNO (operands[0]) - 8] = 0;
445: }
446: if (REG_P (operands[1]) && (unsigned) (REGNO (operands[1]) - 8) < 3)
447: {
448: xoperands[1] = operands[1];
449: available[REGNO (operands[1]) - 8] = 0;
450: }
451: if (REG_P (operands[2]) && (unsigned) (REGNO (operands[2]) - 8) < 3)
452: {
453: xoperands[2] = operands[2];
454: available[REGNO (operands[2]) - 8] = 0;
455: }
456: for (i = 0; i < 3; i++)
457: {
458: if (xoperands[i])
459: continue;
460: if (available[0])
461: {
462: xoperands[i] = gen_rtx (REG, SImode, 8);
463: available[0] = 0;
464: continue;
465: }
466: if (available[1])
467: {
468: xoperands[i] = gen_rtx (REG, SImode, 9);
469: available[1] = 0;
470: continue;
471: }
472: xoperands[i] = gen_rtx (REG, SImode, 10);
473: available[2] = 0;
474: }
475: #endif
476:
477: /* First, figure out best alignment we may assume. */
478: if (REG_P (operands[2]))
479: {
480: xoperands[5] = operands[2];
481: output_asm_insn ("sub %5,0x1,%2", xoperands);
482: align = 1;
483: }
484: else
485: {
486: int i = INTVAL (operands[2]);
487:
488: if (i & 1)
489: align = 1;
490: else if (i & 3)
491: align = 2;
492:
493: /* predecrement count. */
494: i -= align;
495: if (i < 0) abort ();
496:
497: xoperands[5] = gen_rtx (CONST_INT, VOIDmode, i);
498:
499: output_asm_insn ("set %5,%2", xoperands);
500: }
501:
502: /* Now, set up for pipelined operation: dest must contain
503: a pre-incremented address, because its index is pre-decremented. */
504:
505: xoperands[3] = plus_constant (operands[0], align);
506: output_load_address (xoperands);
507:
508: xoperands[4] = operands[1];
509: output_load_address (xoperands+1);
510:
511: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
512: xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align);
513:
514: output_asm_insn ("\nLm%3:\n\tld [%1+%2],%%o7\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tst %%o7,[%0+%2]", xoperands);
515: return "";
516: }
517:
518: #define ABS(x) ((x) < 0 ? -(x) : x)
519:
520: char *
521: output_mul_by_constant (insn, operands, unsignedp)
522: rtx insn;
523: rtx *operands;
524: int unsignedp;
525: {
526: int c; /* Size of constant */
527: int shifts[BITS_PER_WORD]; /* Table of shifts */
528: int p, log; /* A power of two, and its log */
529: int d1, d2; /* Differences of c and p */
530: int first = 1; /* True if dst has unknown data in it */
531: int i;
532:
533: c = INTVAL (operands[2]);
534: if (c == 0)
535: {
536: /* should not happen. */
537: abort ();
538: if (GET_CODE (operands[0]) == MEM)
539: return "st %%g0,%0";
540: return "mov %%g0,%0";
541: }
542:
543: #if 0
544: printf ("open coding insn:\n");
545: debug_rtx (insn);
546: printf ("done.\n");
547: #endif
548:
549: output_asm_insn ("! start open coded multiply");
550:
551: /* Clear out the table of shifts. */
552: for (i = 0; i < BITS_PER_WORD; ++i)
553: shifts[i] = 0;
554:
555: while (c)
556: {
557: /* Find the power of two nearest ABS(c) */
558: p = 1, log = 0;
559: do
560: {
561: d1 = ABS(c) - p;
562: p *= 2;
563: ++log;
564: }
565: while (p < ABS(c));
566: d2 = p - ABS(c);
567:
568: /* Make an appropriate entry in shifts for p. */
569: if (d2 < d1)
570: {
571: shifts[log] = c < 0 ? -1 : 1;
572: c = c < 0 ? d2 : -d2;
573: }
574: else
575: {
576: shifts[log - 1] = c < 0 ? -1 : 1;
577: c = c < 0 ? -d1 : d1;
578: }
579: }
580:
581: /* For now, use a known clobberable register. This could
582: be improved by looking at insn, and seeing if we
583: have a dying register contained therein. */
584: regs_ever_live[15] = 1;
585: operands[3] = gen_rtx (REG, SImode, 15);
586:
587: /* Take care of the first insn in sequence.
588: We know we have at least one. */
589:
590: /* A value of -1 in shifts says to subtract that power of two, and a value
591: of 1 says to add that power of two. */
592: for (i = 0; ; i++)
593: if (shifts[i])
594: {
595: if (i)
596: {
597: operands[2] = gen_rtx (CONST_INT, VOIDmode, i);
598: output_asm_insn ("sll %1,%2,%3", operands);
599: }
600: else if (REGNO (operands[3]) == 15)
601: output_asm_insn ("mov %1,%3", operands);
602:
603: log = i;
604: if (shifts[i] < 0)
605: output_asm_insn ("sub %%g0,%3,%0", operands);
606: else
607: output_asm_insn ("mov %3,%0", operands);
608: break;
609: }
610:
611: /* A value of -1 in shifts says to subtract that power of two, and a value
612: of 1 says to add that power of two--continued. */
613: for (i += 1; i < BITS_PER_WORD; ++i)
614: if (shifts[i])
615: {
616: if (i - log > 0)
617: {
618: operands[2] = gen_rtx (CONST_INT, VOIDmode, i - log);
619: output_asm_insn ("sll %3,%2,%3", operands);
620: }
621: else
622: {
623: operands[2] = gen_rtx (CONST_INT, VOIDmode, log - i);
624: output_asm_insn ("sra %3,%2,%3", operands);
625: }
626: log = i;
627: if (shifts[i] < 0)
628: output_asm_insn ("sub %0,%3,%0", operands);
629: else
630: output_asm_insn ("add %0,%3,%0", operands);
631: }
632:
633: output_asm_insn ("! end open coded multiply");
634:
635: return "";
636: }
637:
638: char *
639: output_mul_insn (operands, unsignedp)
640: rtx *operands;
641: int unsignedp;
642: {
643: int lucky1 = ((unsigned)REGNO (operands[1]) - 8) <= 1;
644: int lucky2 = ((unsigned)REGNO (operands[2]) - 8) <= 1;
645:
646: if (lucky1)
647: if (lucky2)
648: output_asm_insn ("call .mul,2\n\tnop", operands);
649: else
650: {
651: rtx xoperands[2];
652: xoperands[0] = gen_rtx (REG, SImode,
653: 8 ^ (REGNO (operands[1]) == 8));
654: xoperands[1] = operands[2];
655: output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands);
656: }
657: else if (lucky2)
658: {
659: rtx xoperands[2];
660: xoperands[0] = gen_rtx (REG, SImode,
661: 8 ^ (REGNO (operands[2]) == 8));
662: xoperands[1] = operands[1];
663: output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands);
664: }
665: else
666: {
667: output_asm_insn ("mov %1,%%o0\n\tcall .mul,2\n\tmov %2,%%o1",
668: operands);
669: }
670:
671: if (REGNO (operands[0]) == 8)
672: return "";
673: return "mov %%o0,%0";
674: }
675:
676: #if 0
677: /* This function does not properly protect its operands. */
678: char *
679: output_arith_insn (operands, name)
680: rtx *operands;
681: char *name;
682: {
683: extern struct _iobuf *asm_out_file;
684:
685: /* Does not commute. */
686: rtx op1 = 0;
687: rtx op2 = 0;
688:
689: abort ();
690: if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == 8)
691: op1 = operands[1];
692: if (GET_CODE (operands[2]) == REG && REGNO (operands[2]) == 8)
693: op2 = operands[2];
694:
695: if (op1 && op2)
696: {
697: /* ?? should have been done earlier. */
698: abort ();
699: }
700: else
701: {
702: if (op2)
703: {
704: op1 = operands[1];
705: if (REG_P (op1) && REGNO (op1) == 9)
706: {
707: output_asm_insn ("mov %%o1,%%o2\n\tmov %%o0,%%o1", operands);
708: fprintf (asm_out_file, "\tcall %s,2\n", name);
709: output_asm_insn ("mov %%o2,%%o0", operands);
710: goto done;
711: }
712: output_asm_insn ("mov %%o0,%%o1", operands);
713: if (GET_CODE (op1) == CONST_INT && ! SMALL_INT (op1))
714: {
715: output_asm_insn ("sethi %%hi(%1),%%o0", operands);
716: fprintf (asm_out_file, "\tcall %s,2\n", name);
717: output_asm_insn ("add %%o0,%%lo(%1),%%o0", operands);
718: }
719: else
720: {
721: fprintf (asm_out_file, "\tcall %s,2\n", name);
722: if (GET_CODE (op1) == MEM)
723: output_asm_insn ("ld %1,%%o0", operands);
724: else
725: output_asm_insn ("mov %1,%%o0", operands);
726: }
727: }
728: else if (op1)
729: {
730: op2 = operands[2];
731: if (REG_P (op2) && REGNO (operands[1]) == 9)
732: {
733: fprintf (asm_out_file, "\tcall %s,2\n\tnop\n");
734: goto done;
735: }
736: if (GET_CODE (op2) == CONST_INT && ! SMALL_INT (op2))
737: {
738: output_asm_insn ("sethi %%hi(%2),%%o1", operands);
739: fprintf (asm_out_file, "\tcall %s,2\n", name);
740: output_asm_insn ("add %%o1,%%lo(%2),%%o1", operands);
741: }
742: else
743: {
744: fprintf (asm_out_file, "\tcall %s,2\n", name);
745: if (GET_CODE (op2) == MEM)
746: output_asm_insn ("ld %2,%%o1", operands);
747: else
748: output_asm_insn ("mov %2,%%o1", operands);
749: }
750: }
751: else
752: {
753: op1 = operands[1];
754: op2 = operands[2];
755:
756: if (! REG_P (op2) || REGNO (op2) != 9)
757: if (GET_CODE (op2) == MEM)
758: output_asm_insn ("ld %2,%%o1", operands);
759: else if (GET_CODE (op2) != CONST_INT || SMALL_INT (op2))
760: output_asm_insn ("mov %2,%%o1", operands);
761: else
762: output_asm_insn ("sethi %%hi(%2),%%o1\n\tadd %%o1,%%lo(%2),%%o1", operands);
763: if (GET_CODE (op1) == CONST_INT && ! SMALL_INT (op1))
764: {
765: output_asm_insn ("sethi %%hi(%1),%%o0", operands);
766: fprintf (asm_out_file, "\tcall %s,2\n", name);
767: output_asm_insn ("add %%o0,%%lo(%1),%%o0", operands);
768: }
769: else
770: {
771: fprintf (asm_out_file, "\tcall %s,2\n", name);
772: if (GET_CODE (op1) == MEM)
773: output_asm_insn ("ld %1,%%o0", operands);
774: else
775: output_asm_insn ("mov %1,%%o0", operands);
776: }
777: }
778: done:
779: if (REG_P (operands[0]) && REGNO (operands[0]) == 8)
780: return "";
781: if (GET_CODE (operands[0]) == MEM)
782: return "st %%o0,%0";
783: return "mov %%o0,%0";
784: }
785: }
786: #endif
787:
788: /* Make floating point register f0 contain 0.
789: SIZE is the number of registers (including f0)
790: which should contain 0. */
791:
792: void
793: make_f0_contain_0 (size)
794: int size;
795: {
796: if (size == 1)
1.1.1.3 ! root 797: output_asm_insn ("ld [%%fp-16],%%f0", 0);
1.1 root 798: else if (size == 2)
1.1.1.3 ! root 799: output_asm_insn ("ldd [%%fp-16],%%f0", 0);
1.1 root 800: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.