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 )
59 if( (regno < 8) || (regno == 16) || (regno == 17) ) {
67 if( (regno < 8) && ((regno & 1) == 0) ) {
96 if( (regno & 1) == 0 ) {
133 fprintf( stderr, "cant match mode %d\n", mode );
139 /* ADDRESS_COST calls this. This function is not optimal
140 for the 32032 & 32332, but it probably is better than
144 calc_address_cost (operand)
150 if (GET_CODE (operand) == MEM)
152 if (GET_CODE (operand) == MULT)
155 if (GET_CODE (operand) == REG)
156 cost += 1; /* not really, but the documentation
157 says different amount of registers
158 shouldn't return the same costs */
160 switch (GET_CODE (operand))
174 for (i = 0; i < GET_RTX_LENGTH (GET_CODE (operand)); i++)
176 cost += calc_address_cost (XEXP (operand, i));
184 /* Return the register class of a scratch register needed to copy IN into
185 or out of a register in CLASS in MODE. If it can be done directly,
186 NO_REGS is returned. */
189 secondary_reload_class (class, mode, in)
190 enum reg_class class;
191 enum machine_mode mode;
194 int regno = true_regnum (in);
196 if (regno >= FIRST_PSEUDO_REGISTER)
199 /* We can place anything into GENERAL_REGS and can put GENERAL_REGS
201 if (class == GENERAL_REGS || (regno >= 0 && regno < 8))
204 /* Constants, memory, and FP registers can go into FP registers */
205 if ((regno == -1 || (regno >= 8 && regno < 16)) && (class == FLOAT_REGS))
208 /* Otherwise, we need GENERAL_REGS. */
211 /* Generate the rtx that comes from an address expression in the md file */
212 /* The expression to be build is BASE[INDEX:SCALE]. To recognize this,
213 scale must be converted from an exponent (from ASHIFT) to a
214 muliplier (for MULT). */
216 gen_indexed_expr (base, index, scale)
217 rtx base, index, scale;
221 /* This generates an illegal 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_rtx (CONST_INT, VOIDmode, 1 << INTVAL (scale)));
227 addr = gen_rtx (PLUS, SImode, base, addr);
231 /* Return 1 if OP is a valid operand of mode MODE. This
232 predicate rejects operands which do not have a mode
233 (such as CONST_INT which are VOIDmode). */
235 reg_or_mem_operand (op, mode)
237 enum machine_mode mode;
239 return (GET_MODE (op) == mode
240 && (GET_CODE (op) == REG
241 || GET_CODE (op) == SUBREG
242 || GET_CODE (op) == MEM));
245 /* Return the best assembler insn template
246 for moving operands[1] into operands[0] as a fullword. */
249 singlemove_string (operands)
252 if (GET_CODE (operands[1]) == CONST_INT
253 && INTVAL (operands[1]) <= 7
254 && INTVAL (operands[1]) >= -8)
255 return "movqd %1,%0";
260 output_move_double (operands)
263 enum anon1 { REGOP, OFFSOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
266 /* First classify both operands. */
268 if (REG_P (operands[0]))
270 else if (offsettable_memref_p (operands[0]))
272 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
277 if (REG_P (operands[1]))
279 else if (CONSTANT_ADDRESS_P (operands[1])
280 || GET_CODE (operands[1]) == CONST_DOUBLE)
282 else if (offsettable_memref_p (operands[1]))
284 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
289 /* Check for the cases that the operand constraints are not
290 supposed to allow to happen. Abort if we get one,
291 because generating code for these cases is painful. */
293 if (optype0 == RNDOP || optype1 == RNDOP)
296 /* Ok, we can do one word at a time.
297 Normally we do the low-numbered word first,
298 but if either operand is autodecrementing then we
299 do the high-numbered word first.
301 In either case, set up in LATEHALF the operands to use
302 for the high-numbered word and in some cases alter the
303 operands in OPERANDS to be suitable for the low-numbered word. */
305 if (optype0 == REGOP)
306 latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
307 else if (optype0 == OFFSOP)
308 latehalf[0] = adj_offsettable_operand (operands[0], 4);
310 latehalf[0] = operands[0];
312 if (optype1 == REGOP)
313 latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
314 else if (optype1 == OFFSOP)
315 latehalf[1] = adj_offsettable_operand (operands[1], 4);
316 else if (optype1 == CNSTOP)
318 if (CONSTANT_ADDRESS_P (operands[1]))
319 latehalf[1] = const0_rtx;
320 else if (GET_CODE (operands[1]) == CONST_DOUBLE)
321 split_double (operands[1], &operands[1], &latehalf[1]);
324 latehalf[1] = operands[1];
326 /* If one or both operands autodecrementing,
327 do the two words, high-numbered first. */
329 if (optype0 == POPOP || optype1 == POPOP)
331 output_asm_insn (singlemove_string (latehalf), latehalf);
332 return singlemove_string (operands);
335 /* Not autodecrementing. Do the two words, low-numbered first. */
337 output_asm_insn (singlemove_string (operands), operands);
339 operands[0] = latehalf[0];
340 operands[1] = latehalf[1];
341 return singlemove_string (operands);
345 check_reg (oper, reg)
353 switch (GET_CODE(oper))
356 return (REGNO(oper) == reg) ? 1 : 0;
358 return check_reg(XEXP(oper, 0), reg);
361 return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg);
366 /* PRINT_OPERAND is defined to call this function,
367 which is easier to debug than putting all the code in
368 a macro definition in ns32k.h. */
371 print_operand (file, x, code)
377 PUT_IMMEDIATE_PREFIX(file);
378 else if (code == '?')
379 PUT_EXTERNAL_PREFIX(file);
380 else if (GET_CODE (x) == REG)
381 fprintf (file, "%s", reg_names[REGNO (x)]);
382 else if (GET_CODE (x) == MEM)
383 output_address (XEXP (x, 0));
384 else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != DImode)
385 if (GET_MODE (x) == DFmode)
387 union { double d; int i[2]; } u;
388 u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
389 PUT_IMMEDIATE_PREFIX(file);
390 fprintf (file, "0d%.20e", u.d);
394 union { double d; int i[2]; } u;
395 u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
396 PUT_IMMEDIATE_PREFIX(file);
397 fprintf (file, "0f%.20e", u.d);
401 PUT_IMMEDIATE_PREFIX(file);
402 output_addr_const (file, x);
406 /* PRINT_OPERAND_ADDRESS is defined to call this function,
407 which is easier to debug than putting all the code in
408 a macro definition in ns32k.h . */
410 /* Completely rewritten to get this to work with Gas for PC532 Mach.
411 This function didn't work and I just wasn't able (nor very willing) to
412 figure out how it worked.
413 90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */
415 print_operand_address (file, addr)
419 static char scales[] = { 'b', 'w', 'd', 0, 'q', };
420 rtx offset, base, indexexp, tmp;
423 if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
425 fprintf (file, "tos");
434 if (GET_CODE (addr) == PLUS)
436 if (GET_CODE (XEXP (addr, 0)) == PLUS)
438 tmp = XEXP (addr, 1);
439 addr = XEXP (addr, 0);
444 addr = XEXP (addr,1);
452 switch (GET_CODE (tmp))
490 offset = gen_rtx (PLUS, SImode, tmp, offset);
500 /* now, offset, base and indexexp are set */
504 if (GET_CODE (offset) == LABEL_REF || GET_CODE (offset) == SYMBOL_REF)
508 PUT_ABSOLUTE_PREFIX (file);
513 output_addr_const (file,offset);
514 if (base) /* base can be (REG ...) or (MEM ...) */
515 switch (GET_CODE (base))
517 /* now we must output base. Possible alternatives are:
521 (pc) (REG ...) used for SYMBOL_REF and LABEL_REF, output
522 (disp(fp)) (MEM ...) just before possible [rX:y]
527 fprintf (file, "(%s)", reg_names[REGNO (base)]);
535 if (GET_CODE (addr) == PLUS)
537 if (GET_CODE (XEXP (addr, 0)) == PLUS)
539 tmp = XEXP (addr, 1);
540 addr = XEXP (addr, 0);
544 tmp = XEXP (addr, 0);
545 addr = XEXP (addr, 1);
553 switch (GET_CODE (tmp))
563 offset = gen_rtx (PLUS, SImode, tmp, offset);
574 output_addr_const (file, offset);
576 fprintf (file, "(%s)", reg_names[REGNO (base)]);
578 fprintf (file, "(sb)");
589 if (GET_CODE (offset) == LABEL_REF || GET_CODE (offset) == SYMBOL_REF)
590 fprintf (file, "(pc)");
592 #ifdef BASE_REG_NEEDED /* this is defined if the assembler always
593 needs a base register */
595 fprintf (file, "(sb)");
599 /* now print index if we have one */
602 if (GET_CODE (indexexp) == MULT)
604 scale = INTVAL (XEXP (indexexp, 1)) >> 1;
605 indexexp = XEXP (indexexp, 0);
609 if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= 8)
612 fprintf (file, "[%s:%c]",
613 reg_names[REGNO (indexexp)],
618 /* National 32032 shifting is so bad that we can get
619 better performance in many common cases by using other
622 output_shift_insn (operands)
625 if (GET_CODE (operands[2]) == CONST_INT
626 && INTVAL (operands[2]) > 0
627 && INTVAL (operands[2]) <= 3)
628 if (GET_CODE (operands[0]) == REG)
630 if (GET_CODE (operands[1]) == REG)
632 if (REGNO (operands[0]) == REGNO (operands[1]))
634 if (operands[2] == const1_rtx)
636 else if (INTVAL (operands[2]) == 2)
637 return "addd %0,%0\n\taddd %0,%0";
639 if (operands[2] == const1_rtx)
640 return "movd %1,%0\n\taddd %0,%0";
642 operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
643 return "addr %a1,%0";
645 if (operands[2] == const1_rtx)
646 return "movd %1,%0\n\taddd %0,%0";
648 else if (GET_CODE (operands[1]) == REG)
650 operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
651 return "addr %a1,%0";
653 else if (INTVAL (operands[2]) == 1
654 && GET_CODE (operands[1]) == MEM
655 && rtx_equal_p (operands [0], operands[1]))
657 rtx temp = XEXP (operands[1], 0);
659 if (GET_CODE (temp) == REG
660 || (GET_CODE (temp) == PLUS
661 && GET_CODE (XEXP (temp, 0)) == REG
662 && GET_CODE (XEXP (temp, 1)) == CONST_INT))
665 else return "ashd %2,%0";