1 /* Subroutines for assembler code output on the NS32000.
2 Copyright (C) 1988, 1994, 1995, 1996, 1997, 1998, 1999, 2000
3 Free Software Foundation, Inc.
5 This file is part of GNU CC.
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
26 #include "hard-reg-set.h"
28 #include "insn-config.h"
29 #include "conditions.h"
31 #include "insn-attr.h"
39 #include "target-def.h"
42 int ns32k_num_files = 0;
45 /* This duplicates reg_class_contents in reg_class.c, but maybe that isn't
46 initialized in time. Also this is more convenient as an array of ints.
47 We know that HARD_REG_SET fits in an unsigned int */
49 unsigned int ns32k_reg_class_contents[N_REG_CLASSES][1] = REG_CLASS_CONTENTS;
51 enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
53 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
54 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
55 FLOAT_REG0, LONG_FLOAT_REG0, FLOAT_REGS, FLOAT_REGS,
56 FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,
57 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
58 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
59 FRAME_POINTER_REG, STACK_POINTER_REG
62 const char *const ns32k_out_reg_names[] = OUTPUT_REGISTER_NAMES;
64 static rtx gen_indexed_expr PARAMS ((rtx, rtx, rtx));
65 static const char *singlemove_string PARAMS ((rtx *));
66 static void move_tail PARAMS ((rtx[], int, int));
67 static int ns32k_valid_type_attribute_p PARAMS ((tree, tree, tree, tree));
69 /* Initialize the GCC target structure. */
70 #undef TARGET_VALID_TYPE_ATTRIBUTE
71 #define TARGET_VALID_TYPE_ATTRIBUTE ns32k_valid_type_attribute_p
73 struct gcc_target target = TARGET_INITIALIZER;
75 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */
77 hard_regno_mode_ok (regno, mode)
79 enum machine_mode mode;
81 int size = GET_MODE_UNIT_SIZE (mode);
83 if (FLOAT_MODE_P (mode))
85 if (size == UNITS_PER_WORD && regno < L1_REGNUM)
87 if (size == UNITS_PER_WORD * 2
88 && (((regno & 1) == 0 && regno < FRAME_POINTER_REGNUM)))
92 if (size == UNITS_PER_WORD * 2
93 && (regno & 1) == 0 && regno < F0_REGNUM)
95 if (size <= UNITS_PER_WORD
96 && (regno < F0_REGNUM || regno == FRAME_POINTER_REGNUM
97 || regno == STACK_POINTER_REGNUM))
102 int register_move_cost (CLASS1, CLASS2)
103 enum reg_class CLASS1;
104 enum reg_class CLASS2;
106 if (CLASS1 == NO_REGS || CLASS2 == NO_REGS)
108 if ((SUBSET_P (CLASS1, FP_REGS) && !SUBSET_P (CLASS2, FP_REGS))
109 || (!SUBSET_P (CLASS1, FP_REGS) && SUBSET_P (CLASS2, FP_REGS)))
111 if (((CLASS1) == STACK_POINTER_REG && !SUBSET_P (CLASS2,GENERAL_REGS))
112 || ((CLASS2) == STACK_POINTER_REG && !SUBSET_P (CLASS1,GENERAL_REGS)))
114 if (((CLASS1) == FRAME_POINTER_REG && !SUBSET_P (CLASS2,GENERAL_REGS))
115 || ((CLASS2) == FRAME_POINTER_REG && !SUBSET_P (CLASS1,GENERAL_REGS)))
121 /* We made the insn definitions copy from floating point to general
122 registers via the stack. */
123 int secondary_memory_needed (CLASS1, CLASS2, M)
124 enum reg_class CLASS1;
125 enum reg_class CLASS2;
128 int ret = ((SUBSET_P (CLASS1, FP_REGS) && !SUBSET_P (CLASS2, FP_REGS))
129 || (!SUBSET_P (CLASS1, FP_REGS) && SUBSET_P (CLASS2, FP_REGS)));
135 /* ADDRESS_COST calls this. This function is not optimal
136 for the 32032 & 32332, but it probably is better than
140 calc_address_cost (operand)
145 if (GET_CODE (operand) == MEM)
147 if (GET_CODE (operand) == MULT)
149 switch (GET_CODE (operand))
158 if (INTVAL (operand) <= 7 && INTVAL (operand) >= -8)
160 if (INTVAL (operand) < 0x2000 && INTVAL (operand) >= -0x2000)
174 cost += calc_address_cost (XEXP (operand, 0));
178 for (i = 0; i < GET_RTX_LENGTH (GET_CODE (operand)); i++)
180 cost += calc_address_cost (XEXP (operand, i));
188 /* Return the register class of a scratch register needed to copy IN into
189 or out of a register in CLASS in MODE. If it can be done directly,
190 NO_REGS is returned. */
193 secondary_reload_class (class, mode, in)
194 enum reg_class class;
195 enum machine_mode mode ATTRIBUTE_UNUSED;
198 int regno = true_regnum (in);
200 if (regno >= FIRST_PSEUDO_REGISTER)
203 if ((class == FRAME_POINTER_REG && regno == STACK_POINTER_REGNUM)
204 || ( class == STACK_POINTER_REG && regno == FRAME_POINTER_REGNUM))
210 /* Generate the rtx that comes from an address expression in the md file */
211 /* The expression to be build is BASE[INDEX:SCALE]. To recognize this,
212 scale must be converted from an exponent (from ASHIFT) to a
213 multiplier (for MULT). */
216 gen_indexed_expr (base, index, scale)
217 rtx base, index, scale;
221 /* This generates an invalid addressing mode, if BASE is
222 fp or sp. This is handled by PRINT_OPERAND_ADDRESS. */
223 if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT)
224 base = gen_rtx_MEM (SImode, base);
225 addr = gen_rtx_MULT (SImode, index,
226 GEN_INT (1 << INTVAL (scale)));
227 addr = gen_rtx_PLUS (SImode, base, addr);
232 /* Split one or more DImode RTL references into pairs of SImode
233 references. The RTL can be REG, offsettable MEM, integer constant, or
234 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
235 split and "num" is its length. lo_half and hi_half are output arrays
236 that parallel "operands". */
239 split_di (operands, num, lo_half, hi_half)
242 rtx lo_half[], hi_half[];
246 if (GET_CODE (operands[num]) == REG)
248 lo_half[num] = gen_rtx_REG (SImode, REGNO (operands[num]));
249 hi_half[num] = gen_rtx_REG (SImode, REGNO (operands[num]) + 1);
251 else if (CONSTANT_P (operands[num]))
253 split_double (operands[num], &lo_half[num], &hi_half[num]);
255 else if (offsettable_memref_p (operands[num]))
257 lo_half[num] = operands[num];
258 hi_half[num] = adj_offsettable_operand (operands[num], 4);
265 /* Return the best assembler insn template
266 for moving operands[1] into operands[0] as a fullword. */
269 singlemove_string (operands)
272 if (GET_CODE (operands[1]) == CONST_INT
273 && INTVAL (operands[1]) <= 7
274 && INTVAL (operands[1]) >= -8)
275 return "movqd %1,%0";
280 output_move_double (operands)
283 enum anon1 { REGOP, OFFSOP, PUSHOP, CNSTOP, RNDOP } optype0, optype1;
286 /* First classify both operands. */
288 if (REG_P (operands[0]))
290 else if (offsettable_memref_p (operands[0]))
292 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
297 if (REG_P (operands[1]))
299 else if (CONSTANT_P (operands[1])
300 || GET_CODE (operands[1]) == CONST_DOUBLE)
302 else if (offsettable_memref_p (operands[1]))
304 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
309 /* Check for the cases that the operand constraints are not
310 supposed to allow to happen. Abort if we get one,
311 because generating code for these cases is painful. */
313 if (optype0 == RNDOP || optype1 == RNDOP)
316 /* Ok, we can do one word at a time.
317 Normally we do the low-numbered word first,
318 but if either operand is autodecrementing then we
319 do the high-numbered word first.
321 In either case, set up in LATEHALF the operands to use
322 for the high-numbered word and in some cases alter the
323 operands in OPERANDS to be suitable for the low-numbered word. */
325 if (optype0 == REGOP)
326 latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
327 else if (optype0 == OFFSOP)
328 latehalf[0] = adj_offsettable_operand (operands[0], 4);
330 latehalf[0] = operands[0];
332 if (optype1 == REGOP)
333 latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
334 else if (optype1 == OFFSOP)
335 latehalf[1] = adj_offsettable_operand (operands[1], 4);
336 else if (optype1 == CNSTOP)
337 split_double (operands[1], &operands[1], &latehalf[1]);
339 latehalf[1] = operands[1];
341 /* If insn is effectively movd N(sp),tos then we will do the
342 high word first. We should use the adjusted operand 1 (which is N+4(sp))
343 for the low word as well, to compensate for the first decrement of sp.
344 Given this, it doesn't matter which half we do "first". */
345 if (optype0 == PUSHOP
346 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
347 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
348 operands[1] = latehalf[1];
350 /* If one or both operands autodecrementing,
351 do the two words, high-numbered first. */
352 else if (optype0 == PUSHOP || optype1 == PUSHOP)
354 output_asm_insn (singlemove_string (latehalf), latehalf);
355 return singlemove_string (operands);
358 /* If the first move would clobber the source of the second one,
359 do them in the other order. */
361 /* Overlapping registers. */
362 if (optype0 == REGOP && optype1 == REGOP
363 && REGNO (operands[0]) == REGNO (latehalf[1]))
366 output_asm_insn (singlemove_string (latehalf), latehalf);
367 /* Do low-numbered word. */
368 return singlemove_string (operands);
370 /* Loading into a register which overlaps a register used in the address. */
371 else if (optype0 == REGOP && optype1 != REGOP
372 && reg_overlap_mentioned_p (operands[0], operands[1]))
374 if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
375 && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
377 /* If both halves of dest are used in the src memory address,
378 load the destination address into the low reg (operands[0]).
379 Then it works to load latehalf first. */
381 xops[0] = XEXP (operands[1], 0);
382 xops[1] = operands[0];
383 output_asm_insn ("addr %a0,%1", xops);
384 operands[1] = gen_rtx_MEM (DImode, operands[0]);
385 latehalf[1] = adj_offsettable_operand (operands[1], 4);
386 /* The first half has the overlap, Do the late half first. */
387 output_asm_insn (singlemove_string (latehalf), latehalf);
389 return singlemove_string (operands);
391 if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
393 /* The first half has the overlap, Do the late half first. */
394 output_asm_insn (singlemove_string (latehalf), latehalf);
396 return singlemove_string (operands);
400 /* Normal case. Do the two words, low-numbered first. */
402 output_asm_insn (singlemove_string (operands), operands);
404 operands[0] = latehalf[0];
405 operands[1] = latehalf[1];
406 return singlemove_string (operands);
410 #define MAX_UNALIGNED_COPY (32)
411 /* Expand string/block move operations.
413 operands[0] is the pointer to the destination.
414 operands[1] is the pointer to the source.
415 operands[2] is the number of bytes to move.
416 operands[3] is the alignment. */
419 move_tail (operands, bytes, offset)
427 dest = change_address (operands[0], HImode,
428 plus_constant (XEXP (operands[0], 0), offset));
429 src = change_address (operands[1], HImode,
430 plus_constant (XEXP (operands[1], 0), offset));
431 emit_move_insn (dest, src);
437 dest = change_address (operands[0], QImode,
438 plus_constant (XEXP (operands[0], 0), offset));
439 src = change_address (operands[1], QImode,
440 plus_constant (XEXP (operands[1], 0), offset));
441 emit_move_insn (dest, src);
446 expand_block_move (operands)
449 rtx bytes_rtx = operands[2];
450 rtx align_rtx = operands[3];
451 int constp = (GET_CODE (bytes_rtx) == CONST_INT);
452 int bytes = (constp ? INTVAL (bytes_rtx) : 0);
453 int align = INTVAL (align_rtx);
454 rtx src_reg = gen_rtx_REG (Pmode, 1);
455 rtx dest_reg = gen_rtx_REG (Pmode, 2);
456 rtx count_reg = gen_rtx_REG (SImode, 0);
458 if (constp && bytes <= 0)
461 if (constp && bytes < 20)
463 int words = bytes >> 2;
466 if (words < 3 || flag_unroll_loops)
469 for (; words; words--, offset += 4)
472 dest = change_address (operands[0], SImode,
473 plus_constant (XEXP (operands[0], 0), offset));
474 src = change_address (operands[1], SImode,
475 plus_constant (XEXP (operands[1], 0), offset));
476 emit_move_insn (dest, src);
481 /* Use movmd. It is slower than multiple movd's but more
482 compact. It is also slower than movsd for large copies
483 but causes less registers reloading so is better than movsd
486 dest = copy_addr_to_reg (XEXP (operands[0], 0));
487 src = copy_addr_to_reg (XEXP (operands[1], 0));
489 emit_insn (gen_movstrsi2(dest, src, GEN_INT (words)));
492 move_tail (operands, bytes & 3, bytes & ~3);
496 if (align > UNITS_PER_WORD)
497 align = UNITS_PER_WORD;
499 /* Move the address into scratch registers. */
500 emit_insn (gen_rtx_CLOBBER (VOIDmode, dest_reg));
501 emit_move_insn (dest_reg, XEXP (operands[0], 0));
502 operands[0] = gen_rtx_MEM (SImode, dest_reg);
503 emit_insn (gen_rtx_CLOBBER (VOIDmode, src_reg));
504 emit_move_insn (src_reg, XEXP (operands[1], 0));
505 operands[1] = gen_rtx_MEM (SImode, src_reg);
506 emit_insn (gen_rtx_CLOBBER (VOIDmode, count_reg));
508 if (constp && (align == UNITS_PER_WORD || bytes < MAX_UNALIGNED_COPY))
510 /* constant no of bytes and aligned or small enough copy to not bother
511 * aligning. Emit insns to copy by words.
515 emit_move_insn (count_reg, GEN_INT (bytes >> 2));
516 emit_insn (gen_movstrsi1 (GEN_INT (4)));
518 /* insns to copy rest */
519 move_tail (operands, bytes & 3, 0);
521 else if (align == UNITS_PER_WORD)
523 /* insns to copy by words */
524 emit_insn (gen_lshrsi3 (count_reg, bytes_rtx, GEN_INT (2)));
525 emit_insn (gen_movstrsi1 (GEN_INT (4)));
528 move_tail (operands, bytes & 3, 0);
532 /* insns to copy rest */
533 emit_insn (gen_andsi3 (count_reg, bytes_rtx, GEN_INT (3)));
534 emit_insn (gen_movstrsi1 (const1_rtx));
539 /* Not aligned and we may have a lot to copy so it is worth
542 rtx aligned_label = gen_label_rtx ();
545 bytes_reg = copy_to_mode_reg (SImode, bytes_rtx);
548 /* Emit insns to test and skip over the alignment if it is
549 * not worth it. This doubles as a test to ensure that the alignment
550 * operation can't copy too many bytes
552 emit_insn (gen_cmpsi (bytes_reg, GEN_INT (MAX_UNALIGNED_COPY)));
553 emit_jump_insn (gen_blt (aligned_label));
556 /* Emit insns to do alignment at run time */
557 emit_insn (gen_negsi2 (count_reg, src_reg));
558 emit_insn (gen_andsi3 (count_reg, count_reg, GEN_INT (3)));
559 emit_insn (gen_subsi3 (bytes_reg, bytes_reg, count_reg));
560 emit_insn (gen_movstrsi1 (const1_rtx));
562 emit_label (aligned_label);
564 /* insns to copy by words */
565 emit_insn (gen_lshrsi3 (count_reg, bytes_reg, GEN_INT (2)));
566 emit_insn (gen_movstrsi1 (GEN_INT (4)));
568 /* insns to copy rest */
569 emit_insn (gen_andsi3 (count_reg, bytes_reg, GEN_INT (3)));
570 emit_insn (gen_movstrsi1 (const1_rtx));
575 /* Returns 1 if OP contains a global symbol reference */
578 global_symbolic_reference_mentioned_p (op, f)
582 register const char *fmt;
585 if (GET_CODE (op) == SYMBOL_REF)
587 if (! SYMBOL_REF_FLAG (op))
592 else if (f && GET_CODE (op) != CONST)
595 fmt = GET_RTX_FORMAT (GET_CODE (op));
596 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
602 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
603 if (global_symbolic_reference_mentioned_p (XVECEXP (op, i, j), 0))
606 else if (fmt[i] == 'e'
607 && global_symbolic_reference_mentioned_p (XEXP (op, i), 0))
615 /* Returns 1 if OP contains a symbol reference */
618 symbolic_reference_mentioned_p (op)
621 register const char *fmt;
624 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
627 fmt = GET_RTX_FORMAT (GET_CODE (op));
628 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
634 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
635 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
638 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
645 /* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific
646 attribute for TYPE. The attributes in ATTRIBUTES have previously been
650 ns32k_valid_type_attribute_p (type, attributes, identifier, args)
652 tree attributes ATTRIBUTE_UNUSED;
656 if (TREE_CODE (type) != FUNCTION_TYPE
657 && TREE_CODE (type) != FIELD_DECL
658 && TREE_CODE (type) != TYPE_DECL)
661 /* Stdcall attribute says callee is responsible for popping arguments
662 if they are not variable. */
663 if (is_attribute_p ("stdcall", identifier))
664 return (args == NULL_TREE);
666 /* Cdecl attribute says the callee is a normal C declaration */
667 if (is_attribute_p ("cdecl", identifier))
668 return (args == NULL_TREE);
673 /* Return 0 if the attributes for two types are incompatible, 1 if they
674 are compatible, and 2 if they are nearly compatible (which causes a
675 warning to be generated). */
678 ns32k_comp_type_attributes (type1, type2)
679 tree type1 ATTRIBUTE_UNUSED;
680 tree type2 ATTRIBUTE_UNUSED;
686 /* Value is the number of bytes of arguments automatically
687 popped when returning from a subroutine call.
688 FUNDECL is the declaration node of the function (as a tree),
689 FUNTYPE is the data type of the function (as a tree),
690 or for a library call it is an identifier node for the subroutine name.
691 SIZE is the number of bytes of arguments passed on the stack.
693 On the ns32k, the RET insn may be used to pop them if the number
694 of args is fixed, but if the number is variable then the caller
695 must pop them all. RET can't be used for library calls now
696 because the library is compiled with the Unix compiler.
697 Use of RET is a selectable option, since it is incompatible with
698 standard Unix calling sequences. If the option is not selected,
699 the caller must always pop the args.
701 The attribute stdcall is equivalent to RET on a per module basis. */
704 ns32k_return_pops_args (fundecl, funtype, size)
705 tree fundecl ATTRIBUTE_UNUSED;
709 int rtd = TARGET_RTD;
711 if (TREE_CODE (funtype) == IDENTIFIER_NODE)
712 return rtd ? size : 0;
714 /* Cdecl functions override -mrtd, and never pop the stack */
715 if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype)))
718 /* Stdcall functions will pop the stack if not variable args */
719 if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
724 if (TYPE_ARG_TYPES (funtype) == NULL_TREE
725 || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))
732 /* PRINT_OPERAND is defined to call this function,
733 which is easier to debug than putting all the code in
734 a macro definition in ns32k.h. */
736 /* XXX time 12% of cpu time is in fprintf for non optimizing */
738 print_operand (file, x, code)
744 PUT_IMMEDIATE_PREFIX (file);
745 else if (code == '?')
746 PUT_EXTERNAL_PREFIX (file);
747 else if (GET_CODE (x) == REG)
748 fprintf (file, "%s", ns32k_out_reg_names[REGNO (x)]);
749 else if (GET_CODE (x) == MEM)
751 output_address (XEXP (x, 0));
753 else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode)
755 if (GET_MODE (x) == DFmode)
757 union { double d; int i[2]; } u;
758 u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
759 PUT_IMMEDIATE_PREFIX (file);
761 /* Sequent likes its floating point constants as integers */
762 fprintf (file, "0Dx%08x%08x", u.i[1], u.i[0]);
765 fprintf (file, "0f%.20e", u.d);
767 fprintf (file, "0d%.20e", u.d);
773 union { double d; int i[2]; } u;
774 u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
775 PUT_IMMEDIATE_PREFIX (file);
777 /* We have no way of winning if we can't get the bits
778 for a sequent floating point number. */
779 #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
783 union { float f; long l; } uu;
785 fprintf (file, "0Fx%08x", uu.l);
788 fprintf (file, "0f%.20e", u.d);
795 && GET_CODE (x) == CONST
796 && symbolic_reference_mentioned_p (x))
798 fprintf (stderr, "illegal constant for pic-mode: \n");
799 print_rtl (stderr, x);
800 fprintf (stderr, "\nGET_CODE (x) == %d, CONST == %d, symbolic_reference_mentioned_p (x) == %d\n",
801 GET_CODE (x), CONST, symbolic_reference_mentioned_p (x));
805 && (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
807 output_addr_const (file, x);
808 fprintf (file, "(sb)");
812 #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
813 if (GET_CODE (x) == CONST_INT)
815 PUT_IMMEDIATE_PREFIX (file);
816 output_addr_const (file, x);
821 /* PRINT_OPERAND_ADDRESS is defined to call this function,
822 which is easier to debug than putting all the code in
823 a macro definition in ns32k.h . */
825 /* Completely rewritten to get this to work with Gas for PC532 Mach.
826 This function didn't work and I just wasn't able (nor very willing) to
827 figure out how it worked.
828 90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */
831 print_operand_address (file, addr)
835 static char scales[] = { 'b', 'w', 'd', 0, 'q', };
836 rtx offset, base, indexexp, tmp;
840 if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
842 fprintf (file, "tos");
851 if (GET_CODE (addr) == PLUS)
853 if (GET_CODE (XEXP (addr, 0)) == PLUS)
855 tmp = XEXP (addr, 1);
856 addr = XEXP (addr, 0);
861 addr = XEXP (addr,1);
869 switch (GET_CODE (tmp))
883 if (REGNO (tmp) < F0_REGNUM)
903 if (flag_pic && ! CONSTANT_POOL_ADDRESS_P (tmp)
904 && ! SYMBOL_REF_FLAG (tmp))
916 if (flag_pic && GET_CODE (tmp) == CONST)
920 if (GET_CODE (tmp1) != PLUS)
924 if (GET_CODE (sym) != SYMBOL_REF)
931 if (GET_CODE (sym) == SYMBOL_REF)
933 if (GET_CODE (off) != CONST_INT)
936 if (CONSTANT_POOL_ADDRESS_P (sym)
937 || SYMBOL_REF_FLAG (sym))
939 SYMBOL_REF_FLAG (tmp) = 1;
963 offset = gen_rtx_PLUS (SImode, tmp, offset);
975 #ifndef INDEX_RATHER_THAN_BASE
976 && (flag_pic || TARGET_HIMEM)
977 && GET_CODE (base) != SYMBOL_REF
978 && GET_CODE (offset) != CONST_INT
980 /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix. */
982 && !indexexp && GET_CODE (base) == REG
983 && REG_OK_FOR_INDEX_P (base))
989 /* now, offset, base and indexexp are set */
990 #ifndef BASE_REG_NEEDED
993 #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)
994 if (GET_CODE (offset) == CONST_INT)
996 PUT_ABSOLUTE_PREFIX (file);
1000 output_addr_const (file, offset);
1001 if (base) /* base can be (REG ...) or (MEM ...) */
1002 switch (GET_CODE (base))
1004 /* now we must output base. Possible alternatives are:
1008 (pc) (REG ...) used for SYMBOL_REF and LABEL_REF, output
1009 (disp(fp)) (MEM ...) just before possible [rX:y]
1010 (disp(sp)) (MEM ...)
1011 (disp(sb)) (MEM ...)
1014 fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
1020 fprintf (file, "(");
1021 output_addr_const (file, base);
1022 fprintf (file, "(sb))");
1025 addr = XEXP (base,0);
1028 while (addr != NULL)
1030 if (GET_CODE (addr) == PLUS)
1032 if (GET_CODE (XEXP (addr, 0)) == PLUS)
1034 tmp = XEXP (addr, 1);
1035 addr = XEXP (addr, 0);
1039 tmp = XEXP (addr, 0);
1040 addr = XEXP (addr, 1);
1048 switch (GET_CODE (tmp))
1058 offset = gen_rtx_PLUS (SImode, tmp, offset);
1067 offset = const0_rtx;
1068 fprintf (file, "(");
1069 output_addr_const (file, offset);
1071 fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
1073 fprintf (file, "(sb)");
1076 fprintf (file, ")");
1082 else if (GET_CODE (offset) != CONST_INT)
1083 fprintf (file, "(pc)");
1084 #ifdef BASE_REG_NEEDED
1086 fprintf (file, "(sb)");
1090 #endif /* PC_RELATIVE */
1092 /* now print index if we have one */
1095 if (GET_CODE (indexexp) == MULT)
1097 scale = INTVAL (XEXP (indexexp, 1)) >> 1;
1098 indexexp = XEXP (indexexp, 0);
1102 if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= F0_REGNUM)
1106 fprintf (file, "[%c`%s]",
1108 ns32k_out_reg_names[REGNO (indexexp)]);
1110 fprintf (file, "[%s:%c]",
1111 ns32k_out_reg_names[REGNO (indexexp)],
1117 /* National 32032 shifting is so bad that we can get
1118 better performance in many common cases by using other
1121 output_shift_insn (operands)
1124 if (GET_CODE (operands[2]) == CONST_INT
1125 && INTVAL (operands[2]) > 0
1126 && INTVAL (operands[2]) <= 3)
1128 if (GET_CODE (operands[0]) == REG)
1130 if (GET_CODE (operands[1]) == REG)
1132 if (REGNO (operands[0]) == REGNO (operands[1]))
1134 if (operands[2] == const1_rtx)
1135 return "addd %0,%0";
1136 else if (INTVAL (operands[2]) == 2)
1137 return "addd %0,%0\n\taddd %0,%0";
1139 if (operands[2] == const1_rtx)
1140 return "movd %1,%0\n\taddd %0,%0";
1142 operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
1143 return "addr %a1,%0";
1145 if (operands[2] == const1_rtx)
1146 return "movd %1,%0\n\taddd %0,%0";
1148 else if (GET_CODE (operands[1]) == REG)
1150 operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
1151 return "addr %a1,%0";
1153 else if (INTVAL (operands[2]) == 1
1154 && GET_CODE (operands[1]) == MEM
1155 && rtx_equal_p (operands [0], operands[1]))
1157 rtx temp = XEXP (operands[1], 0);
1159 if (GET_CODE (temp) == REG
1160 || (GET_CODE (temp) == PLUS
1161 && GET_CODE (XEXP (temp, 0)) == REG
1162 && GET_CODE (XEXP (temp, 1)) == CONST_INT))
1163 return "addd %0,%0";
1165 else return "ashd %2,%0";
1167 return "ashd %2,%0";
1171 output_move_dconst (n, s)
1177 if (n > -9 && n < 8)
1178 strcpy (r, "movqd ");
1179 else if (n > 0 && n < 256)
1180 strcpy (r, "movzbd ");
1181 else if (n > 0 && n < 65536)
1182 strcpy (r, "movzwd ");
1183 else if (n < 0 && n > -129)
1184 strcpy (r, "movxbd ");
1185 else if (n < 0 && n > -32769)
1186 strcpy (r, "movxwd ");
1188 strcpy (r, "movd ");