1 /* Subroutines for assembler code output on the NS32000.
2 Copyright (C) 1988 Free Software Foundation, Inc.
4 This file is part of GNU CC.
6 GNU CC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU CC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20 /* Some output-actions in ns32k.md need these. */
25 #include "hard-reg-set.h"
27 #include "insn-config.h"
28 #include "conditions.h"
29 #include "insn-flags.h"
31 #include "insn-attr.h"
34 int ns32k_num_files = 0;
41 fprintf (stderr, s, s1, s2);
44 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */
47 hard_regno_mode_ok (regno, mode)
49 enum machine_mode mode;
60 if (regno < 8 || regno == 16 || regno == 17)
66 if (regno < 8 && (regno & 1) == 0)
111 /* Used to abort here, but simply saying "no" handles TImode
116 /* ADDRESS_COST calls this. This function is not optimal
117 for the 32032 & 32332, but it probably is better than
121 calc_address_cost (operand)
127 if (GET_CODE (operand) == MEM)
129 if (GET_CODE (operand) == MULT)
132 if (GET_CODE (operand) == REG)
133 cost += 1; /* not really, but the documentation
134 says different amount of registers
135 shouldn't return the same costs */
137 switch (GET_CODE (operand))
151 for (i = 0; i < GET_RTX_LENGTH (GET_CODE (operand)); i++)
153 cost += calc_address_cost (XEXP (operand, i));
161 /* Return the register class of a scratch register needed to copy IN into
162 or out of a register in CLASS in MODE. If it can be done directly,
163 NO_REGS is returned. */
166 secondary_reload_class (class, mode, in)
167 enum reg_class class;
168 enum machine_mode mode;
171 int regno = true_regnum (in);
173 if (regno >= FIRST_PSEUDO_REGISTER)
176 /* We can place anything into GENERAL_REGS and can put GENERAL_REGS
178 if (class == GENERAL_REGS || (regno >= 0 && regno < 8))
181 /* Constants, memory, and FP registers can go into FP registers. */
182 if ((regno == -1 || (regno >= 8 && regno < 16)) && (class == FLOAT_REGS))
185 #if 0 /* This isn't strictly true (can't move fp to sp or vice versa),
186 so it's cleaner to use PREFERRED_RELOAD_CLASS
187 to make the right things happen. */
188 if (regno >= 16 && class == GEN_AND_MEM_REGS)
192 /* Otherwise, we need GENERAL_REGS. */
195 /* Generate the rtx that comes from an address expression in the md file */
196 /* The expression to be build is BASE[INDEX:SCALE]. To recognize this,
197 scale must be converted from an exponent (from ASHIFT) to a
198 multiplier (for MULT). */
200 gen_indexed_expr (base, index, scale)
201 rtx base, index, scale;
205 /* This generates an illegal addressing mode, if BASE is
206 fp or sp. This is handled by PRINT_OPERAND_ADDRESS. */
207 if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT)
208 base = gen_rtx (MEM, SImode, base);
209 addr = gen_rtx (MULT, SImode, index,
210 gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (scale)));
211 addr = gen_rtx (PLUS, SImode, base, addr);
215 /* Return 1 if OP is a valid operand of mode MODE. This
216 predicate rejects operands which do not have a mode
217 (such as CONST_INT which are VOIDmode). */
219 reg_or_mem_operand (op, mode)
221 enum machine_mode mode;
223 return (GET_MODE (op) == mode
224 && (GET_CODE (op) == REG
225 || GET_CODE (op) == SUBREG
226 || GET_CODE (op) == MEM));
229 /* Return the best assembler insn template
230 for moving operands[1] into operands[0] as a fullword. */
233 singlemove_string (operands)
236 if (GET_CODE (operands[1]) == CONST_INT
237 && INTVAL (operands[1]) <= 7
238 && INTVAL (operands[1]) >= -8)
239 return "movqd %1,%0";
244 output_move_double (operands)
247 enum anon1 { REGOP, OFFSOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
250 /* First classify both operands. */
252 if (REG_P (operands[0]))
254 else if (offsettable_memref_p (operands[0]))
256 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
261 if (REG_P (operands[1]))
263 else if (CONSTANT_ADDRESS_P (operands[1])
264 || GET_CODE (operands[1]) == CONST_DOUBLE)
266 else if (offsettable_memref_p (operands[1]))
268 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
273 /* Check for the cases that the operand constraints are not
274 supposed to allow to happen. Abort if we get one,
275 because generating code for these cases is painful. */
277 if (optype0 == RNDOP || optype1 == RNDOP)
280 /* Ok, we can do one word at a time.
281 Normally we do the low-numbered word first,
282 but if either operand is autodecrementing then we
283 do the high-numbered word first.
285 In either case, set up in LATEHALF the operands to use
286 for the high-numbered word and in some cases alter the
287 operands in OPERANDS to be suitable for the low-numbered word. */
289 if (optype0 == REGOP)
290 latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
291 else if (optype0 == OFFSOP)
292 latehalf[0] = adj_offsettable_operand (operands[0], 4);
294 latehalf[0] = operands[0];
296 if (optype1 == REGOP)
297 latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
298 else if (optype1 == OFFSOP)
299 latehalf[1] = adj_offsettable_operand (operands[1], 4);
300 else if (optype1 == CNSTOP)
302 if (CONSTANT_ADDRESS_P (operands[1]))
303 latehalf[1] = const0_rtx;
304 else if (GET_CODE (operands[1]) == CONST_DOUBLE)
305 split_double (operands[1], &operands[1], &latehalf[1]);
308 latehalf[1] = operands[1];
310 /* If one or both operands autodecrementing,
311 do the two words, high-numbered first. */
313 if (optype0 == POPOP || optype1 == POPOP)
315 output_asm_insn (singlemove_string (latehalf), latehalf);
316 return singlemove_string (operands);
319 /* Not autodecrementing. Do the two words, low-numbered first. */
321 output_asm_insn (singlemove_string (operands), operands);
323 operands[0] = latehalf[0];
324 operands[1] = latehalf[1];
325 return singlemove_string (operands);
329 check_reg (oper, reg)
337 switch (GET_CODE(oper))
340 return (REGNO(oper) == reg) ? 1 : 0;
342 return check_reg(XEXP(oper, 0), reg);
345 return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg);
350 /* PRINT_OPERAND is defined to call this function,
351 which is easier to debug than putting all the code in
352 a macro definition in ns32k.h. */
355 print_operand (file, x, code)
361 PUT_IMMEDIATE_PREFIX (file);
362 else if (code == '?')
363 PUT_EXTERNAL_PREFIX (file);
364 else if (GET_CODE (x) == REG)
365 fprintf (file, "%s", reg_names[REGNO (x)]);
366 else if (GET_CODE (x) == MEM)
368 rtx tmp = XEXP (x, 0);
369 #if ! (defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC))
370 if (GET_CODE (tmp) != CONST_INT)
372 char *out = XSTR (tmp, 0);
375 PUT_ABSOLUTE_PREFIX (file);
376 fprintf (file, "%s", &out[1]);
379 ASM_OUTPUT_LABELREF (file, out);
383 output_address (XEXP (x, 0));
385 else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != DImode)
387 if (GET_MODE (x) == DFmode)
389 union { double d; int i[2]; } u;
390 u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
391 PUT_IMMEDIATE_PREFIX(file);
393 /* Sequent likes it's floating point constants as integers */
394 fprintf (file, "0Dx%08x%08x", u.i[1], u.i[0]);
397 fprintf (file, "0f%.20e", u.d);
399 fprintf (file, "0d%.20e", u.d);
405 union { double d; int i[2]; } u;
406 u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
407 PUT_IMMEDIATE_PREFIX (file);
409 /* We have no way of winning if we can't get the bits
410 for a sequent floating point number. */
411 #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
415 union { float f; long l; } uu;
417 fprintf (file, "0Fx%08x", uu.l);
420 fprintf (file, "0f%.20e", u.d);
426 #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
427 if (GET_CODE (x) == CONST_INT)
429 PUT_IMMEDIATE_PREFIX (file);
430 output_addr_const (file, x);
434 /* PRINT_OPERAND_ADDRESS is defined to call this function,
435 which is easier to debug than putting all the code in
436 a macro definition in ns32k.h . */
438 /* Completely rewritten to get this to work with Gas for PC532 Mach.
439 This function didn't work and I just wasn't able (nor very willing) to
440 figure out how it worked.
441 90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */
443 print_operand_address (file, addr)
447 static char scales[] = { 'b', 'w', 'd', 0, 'q', };
448 rtx offset, base, indexexp, tmp;
451 if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
453 fprintf (file, "tos");
462 if (GET_CODE (addr) == PLUS)
464 if (GET_CODE (XEXP (addr, 0)) == PLUS)
466 tmp = XEXP (addr, 1);
467 addr = XEXP (addr, 0);
472 addr = XEXP (addr,1);
480 switch (GET_CODE (tmp))
518 offset = gen_rtx (PLUS, SImode, tmp, offset);
529 #ifdef INDEX_RATHER_THAN_BASE
530 /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix. */
531 if (base && !indexexp && GET_CODE (base) == REG
532 && REG_OK_FOR_INDEX_P (base))
539 /* now, offset, base and indexexp are set */
542 #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)
543 if (GET_CODE (offset) == CONST_INT)
544 /* if (! (GET_CODE (offset) == LABEL_REF
545 || GET_CODE (offset) == SYMBOL_REF)) */
547 PUT_ABSOLUTE_PREFIX (file);
550 output_addr_const (file, offset);
551 if (base) /* base can be (REG ...) or (MEM ...) */
552 switch (GET_CODE (base))
554 /* now we must output base. Possible alternatives are:
558 (pc) (REG ...) used for SYMBOL_REF and LABEL_REF, output
559 (disp(fp)) (MEM ...) just before possible [rX:y]
564 fprintf (file, "(%s)", reg_names[REGNO (base)]);
572 if (GET_CODE (addr) == PLUS)
574 if (GET_CODE (XEXP (addr, 0)) == PLUS)
576 tmp = XEXP (addr, 1);
577 addr = XEXP (addr, 0);
581 tmp = XEXP (addr, 0);
582 addr = XEXP (addr, 1);
590 switch (GET_CODE (tmp))
600 offset = gen_rtx (PLUS, SImode, tmp, offset);
611 output_addr_const (file, offset);
613 fprintf (file, "(%s)", reg_names[REGNO (base)]);
614 #ifdef BASE_REG_NEEDED
616 fprintf (file, "(sb)");
628 if (GET_CODE (offset) == LABEL_REF || GET_CODE (offset) == SYMBOL_REF)
629 fprintf (file, "(pc)");
631 #ifdef BASE_REG_NEEDED /* this is defined if the assembler always
632 needs a base register */
634 fprintf (file, "(sb)");
638 /* now print index if we have one */
641 if (GET_CODE (indexexp) == MULT)
643 scale = INTVAL (XEXP (indexexp, 1)) >> 1;
644 indexexp = XEXP (indexexp, 0);
648 if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= 8)
652 fprintf (file, "[%c`%s]",
654 reg_names[REGNO (indexexp)]);
656 fprintf (file, "[%s:%c]",
657 reg_names[REGNO (indexexp)],
663 /* National 32032 shifting is so bad that we can get
664 better performance in many common cases by using other
667 output_shift_insn (operands)
670 if (GET_CODE (operands[2]) == CONST_INT
671 && INTVAL (operands[2]) > 0
672 && INTVAL (operands[2]) <= 3)
673 if (GET_CODE (operands[0]) == REG)
675 if (GET_CODE (operands[1]) == REG)
677 if (REGNO (operands[0]) == REGNO (operands[1]))
679 if (operands[2] == const1_rtx)
681 else if (INTVAL (operands[2]) == 2)
682 return "addd %0,%0\n\taddd %0,%0";
684 if (operands[2] == const1_rtx)
685 return "movd %1,%0\n\taddd %0,%0";
687 operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
688 return "addr %a1,%0";
690 if (operands[2] == const1_rtx)
691 return "movd %1,%0\n\taddd %0,%0";
693 else if (GET_CODE (operands[1]) == REG)
695 operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
696 return "addr %a1,%0";
698 else if (INTVAL (operands[2]) == 1
699 && GET_CODE (operands[1]) == MEM
700 && rtx_equal_p (operands [0], operands[1]))
702 rtx temp = XEXP (operands[1], 0);
704 if (GET_CODE (temp) == REG
705 || (GET_CODE (temp) == PLUS
706 && GET_CODE (XEXP (temp, 0)) == REG
707 && GET_CODE (XEXP (temp, 1)) == CONST_INT))
710 else return "ashd %2,%0";