home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gcc-2.7.2.1-src.tgz / tar.out / fsf / gcc / config / fx80 / fx80.c next >
C/C++ Source or Header  |  1996-09-28  |  9KB  |  301 lines

  1. /* Subroutines for insn-output.c for Alliant FX computers.
  2.    Copyright (C) 1989,1991 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU CC.
  5.  
  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)
  9. any later version.
  10.  
  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.
  15.  
  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, 59 Temple Place - Suite 330,
  19. Boston, MA 02111-1307, USA.  */
  20.  
  21.  
  22. /* Some output-actions in alliant.md need these.  */
  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.  
  35. /* Index into this array by (register number >> 3) to find the
  36.    smallest class which contains that register.  */
  37. enum reg_class regno_reg_class[]
  38.   = { DATA_REGS, ADDR_REGS, FP_REGS };
  39.  
  40. static rtx find_addr_reg ();
  41.  
  42. char *
  43. output_btst (operands, countop, dataop, insn, signpos)
  44.      rtx *operands;
  45.      rtx countop, dataop;
  46.      rtx insn;
  47.      int signpos;
  48. {
  49.   operands[0] = countop;
  50.   operands[1] = dataop;
  51.  
  52.   if (GET_CODE (countop) == CONST_INT)
  53.     {
  54.       register int count = INTVAL (countop);
  55.       /* If COUNT is bigger than size of storage unit in use,
  56.      advance to the containing unit of same size.  */
  57.       if (count > signpos)
  58.     {
  59.       int offset = (count & ~signpos) / 8;
  60.       count = count & signpos;
  61.       operands[1] = dataop = adj_offsettable_operand (dataop, offset);
  62.     }
  63.       if (count == signpos)
  64.     cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N;
  65.       else
  66.     cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N;
  67.  
  68.       /* These three statements used to use next_insns_test_no...
  69.      but it appears that this should do the same job.  */
  70.       if (count == 31
  71.       && next_insn_tests_no_inequality (insn))
  72.     return "tst%.l %1";
  73.       if (count == 15
  74.       && next_insn_tests_no_inequality (insn))
  75.     return "tst%.w %1";
  76.       if (count == 7
  77.       && next_insn_tests_no_inequality (insn))
  78.     return "tst%.b %1";
  79.  
  80.       cc_status.flags = CC_NOT_NEGATIVE;
  81.     }
  82.   return "btst %0,%1";
  83. }
  84.  
  85. /* Return the best assembler insn template
  86.    for moving operands[1] into operands[0] as a fullword.  */
  87.  
  88. static char *
  89. singlemove_string (operands)
  90.      rtx *operands;
  91. {
  92.   if (operands[1] != const0_rtx)
  93.     return "mov%.l %1,%0";
  94.   if (! ADDRESS_REG_P (operands[0]))
  95.     return "clr%.l %0";
  96.   return "sub%.l %0,%0";
  97. }
  98.  
  99. /* Output assembler code to perform a doubleword move insn
  100.    with operands OPERANDS.  */
  101.  
  102. char *
  103. output_move_double (operands)
  104.      rtx *operands;
  105. {
  106.   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  107.   rtx latehalf[2];
  108.   rtx addreg0 = 0, addreg1 = 0;
  109.  
  110.   /* First classify both operands.  */
  111.  
  112.   if (REG_P (operands[0]))
  113.     optype0 = REGOP;
  114.   else if (offsettable_memref_p (operands[0]))
  115.     optype0 = OFFSOP;
  116.   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
  117.     optype0 = POPOP;
  118.   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
  119.     optype0 = PUSHOP;
  120.   else if (GET_CODE (operands[0]) == MEM)
  121.     optype0 = MEMOP;
  122.   else
  123.     optype0 = RNDOP;
  124.  
  125.   if (REG_P (operands[1]))
  126.     optype1 = REGOP;
  127.   else if (CONSTANT_P (operands[1]))
  128.     optype1 = CNSTOP;
  129.   else if (offsettable_memref_p (operands[1]))
  130.     optype1 = OFFSOP;
  131.   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
  132.     optype1 = POPOP;
  133.   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
  134.     optype1 = PUSHOP;
  135.   else if (GET_CODE (operands[1]) == MEM)
  136.     optype1 = MEMOP;
  137.   else
  138.     optype1 = RNDOP;
  139.  
  140.   /* Check for the cases that the operand constraints are not
  141.      supposed to allow to happen.  Abort if we get one,
  142.      because generating code for these cases is painful.  */
  143.  
  144.   if (optype0 == RNDOP || optype1 == RNDOP)
  145.     abort ();
  146.  
  147.   /* If one operand is decrementing and one is incrementing
  148.      decrement the former register explicitly
  149.      and change that operand into ordinary indexing.  */
  150.  
  151.   if (optype0 == PUSHOP && optype1 == POPOP)
  152.     {
  153.       operands[0] = XEXP (XEXP (operands[0], 0), 0);
  154.       output_asm_insn ("subq%.l %#8,%0", operands);
  155.       operands[0] = gen_rtx (MEM, DImode, operands[0]);
  156.       optype0 = OFFSOP;
  157.     }
  158.   if (optype0 == POPOP && optype1 == PUSHOP)
  159.     {
  160.       operands[1] = XEXP (XEXP (operands[1], 0), 0);
  161.       output_asm_insn ("subq%.l %#8,%1", operands);
  162.       operands[1] = gen_rtx (MEM, DImode, operands[1]);
  163.       optype1 = OFFSOP;
  164.     }
  165.  
  166.   /* If an operand is an unoffsettable memory ref, find a register
  167.      we can increment temporarily to make it refer to the second word.  */
  168.  
  169.   if (optype0 == MEMOP)
  170.     addreg0 = find_addr_reg (XEXP (operands[0], 0));
  171.  
  172.   if (optype1 == MEMOP)
  173.     addreg1 = find_addr_reg (XEXP (operands[1], 0));
  174.  
  175.   /* Ok, we can do one word at a time.
  176.      Normally we do the low-numbered word first,
  177.      but if either operand is autodecrementing then we
  178.      do the high-numbered word first.
  179.  
  180.      In either case, set up in LATEHALF the operands to use
  181.      for the high-numbered word and in some cases alter the
  182.      operands in OPERANDS to be suitable for the low-numbered word.  */
  183.  
  184.   if (optype0 == REGOP)
  185.     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
  186.   else if (optype0 == OFFSOP)
  187.     latehalf[0] = adj_offsettable_operand (operands[0], 4);
  188.   else
  189.     latehalf[0] = operands[0];
  190.  
  191.   if (optype1 == REGOP)
  192.     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
  193.   else if (optype1 == OFFSOP)
  194.     latehalf[1] = adj_offsettable_operand (operands[1], 4);
  195.   else if (optype1 == CNSTOP)
  196.     {
  197.       if (GET_CODE (operands[1]) == CONST_DOUBLE)
  198.     split_double (operands[1], &operands[1], &latehalf[1]);
  199.       else if (CONSTANT_P (operands[1]))
  200.     {
  201.       latehalf[1] = operands[1];
  202.       operands[1] = const0_rtx;
  203.     }
  204.     }
  205.   else
  206.     latehalf[1] = operands[1];
  207.  
  208.   /* If insn is effectively movd N(sp),-(sp) then we will do the
  209.      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
  210.      for the low word as well, to compensate for the first decrement of sp.  */
  211.   if (optype0 == PUSHOP
  212.       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
  213.       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
  214.     operands[1] = latehalf[1];
  215.  
  216.   /* If one or both operands autodecrementing,
  217.      do the two words, high-numbered first.  */
  218.  
  219.   /* Likewise,  the first move would clobber the source of the second one,
  220.      do them in the other order.  This happens only for registers;
  221.      such overlap can't happen in memory unless the user explicitly
  222.      sets it up, and that is an undefined circumstance.  */
  223.  
  224.   if (optype0 == PUSHOP || optype1 == PUSHOP
  225.       || (optype0 == REGOP && optype1 == REGOP
  226.       && REGNO (operands[0]) == REGNO (latehalf[1])))
  227.     {
  228.       /* Make any unoffsettable addresses point at high-numbered word.  */
  229.       if (addreg0)
  230.     output_asm_insn ("addql %#4,%0", &addreg0);
  231.       if (addreg1)
  232.     output_asm_insn ("addql %#4,%0", &addreg1);
  233.  
  234.       /* Do that word.  */
  235.       output_asm_insn (singlemove_string (latehalf), latehalf);
  236.  
  237.       /* Undo the adds we just did.  */
  238.       if (addreg0)
  239.     output_asm_insn ("subql %#4,%0", &addreg0);
  240.       if (addreg1)
  241.     output_asm_insn ("subql %#4,%0", &addreg1);
  242.  
  243.       /* Do low-numbered word.  */
  244.       return singlemove_string (operands);
  245.     }
  246.  
  247.   /* Normal case: do the two words, low-numbered first.  */
  248.  
  249.   output_asm_insn (singlemove_string (operands), operands);
  250.  
  251.   /* Make any unoffsettable addresses point at high-numbered word.  */
  252.   if (addreg0)
  253.     output_asm_insn ("addql %#4,%0", &addreg0);
  254.   if (addreg1)
  255.     output_asm_insn ("addql %#4,%0", &addreg1);
  256.  
  257.   /* Do that word.  */
  258.   output_asm_insn (singlemove_string (latehalf), latehalf);
  259.  
  260.   /* Undo the adds we just did.  */
  261.   if (addreg0)
  262.     output_asm_insn ("subql %#4,%0", &addreg0);
  263.   if (addreg1)
  264.     output_asm_insn ("subql %#4,%0", &addreg1);
  265.  
  266.   return "";
  267. }
  268.  
  269. /* Return a REG that occurs in ADDR with coefficient 1.
  270.    ADDR can be effectively incremented by incrementing REG.  */
  271.  
  272. static rtx
  273. find_addr_reg (addr)
  274.      rtx addr;
  275. {
  276.   while (GET_CODE (addr) == PLUS)
  277.     {
  278.       if (GET_CODE (XEXP (addr, 0)) == REG)
  279.     addr = XEXP (addr, 0);
  280.       else if (GET_CODE (XEXP (addr, 1)) == REG)
  281.     addr = XEXP (addr, 1);
  282.       else if (CONSTANT_P (XEXP (addr, 0)))
  283.     addr = XEXP (addr, 1);
  284.       else if (CONSTANT_P (XEXP (addr, 1)))
  285.     addr = XEXP (addr, 0);
  286.       else
  287.     abort ();
  288.     }
  289.   if (GET_CODE (addr) == REG)
  290.     return addr;
  291.   abort ();
  292. }
  293.  
  294. int
  295. standard_SunFPA_constant_p (x)
  296.      rtx x;
  297. {
  298.   return( 0 );
  299. }
  300.  
  301.