home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / program / 320 / compsrc2 / output-m.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-10-20  |  9.7 KB  |  337 lines

  1. /* Subroutines for insn-output.c for Motorola 68000 family.
  2.    Copyright (C) 1987 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU CC.
  5.  
  6. GNU CC is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY.  No author or distributor
  8. accepts responsibility to anyone for the consequences of using it
  9. or for whether it serves any particular purpose or works at all,
  10. unless he says so in writing.  Refer to the GNU CC General Public
  11. License for full details.
  12.  
  13. Everyone is granted permission to copy, modify and redistribute
  14. GNU CC, but only under the conditions described in the
  15. GNU CC General Public License.   A copy of this license is
  16. supposed to have been given to you along with GNU CC so you
  17. can know your rights and responsibilities.  It should be in a
  18. file named COPYING.  Among other things, the copyright notice
  19. and this notice must be preserved on all copies.  */
  20.  
  21.  
  22. /* Some output-actions in m68k.md need these.  */
  23. #include <stdio.h>
  24. extern FILE *asm_out_file;
  25.  
  26. static rtx find_addr_reg ();
  27.  
  28. char *
  29. output_btst (operands, countop, dataop, insn, signpos)
  30.      rtx *operands;
  31.      rtx countop, dataop;
  32.      rtx insn;
  33.      int signpos;
  34. {
  35.   operands[0] = countop;
  36.   operands[1] = dataop;
  37.   if (GET_CODE (countop) == CONST_INT)
  38.     {
  39.       register int count = INTVAL (countop);
  40.       if (count == signpos)
  41.     cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N;
  42.       else
  43.     cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N;
  44.  
  45.       if (count == 31
  46.       && next_insn_tests_no_inequality (insn))
  47.     return "tst%.l %1";
  48.       if (count == 15
  49.       && next_insn_tests_no_inequality (insn))
  50.     return "tst%.w %1";
  51.       if (count == 7
  52.       && next_insn_tests_no_inequality (insn))
  53.     return "tst%.b %1";
  54.  
  55.       cc_status.flags = CC_NOT_NEGATIVE;
  56.     }
  57.   return "btst %0,%1";
  58. }
  59.  
  60. /* Return the best assembler insn template
  61.    for moving operands[1] into operands[0] as a fullword.  */
  62.  
  63. static char *
  64. singlemove_string (operands)
  65.      rtx *operands;
  66. {
  67.   if (operands[1] != const0_rtx)
  68.     return "move%.l %1,%0";
  69.   if (! ADDRESS_REG_P (operands[0]))
  70.     return "clr%.l %0";
  71.   return "sub%.l %0,%0";
  72. }
  73.  
  74. /* Output assembler code to perform a doubleword move insn
  75.    with operands OPERANDS.  */
  76.  
  77. char *
  78. output_move_double (operands)
  79.      rtx *operands;
  80. {
  81.   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  82.   rtx latehalf[2];
  83.   rtx addreg0 = 0, addreg1 = 0;
  84.  
  85.   /* First classify both operands.  */
  86.  
  87.   if (REG_P (operands[0]))
  88.     optype0 = REGOP;
  89.   else if (offsetable_memref_p (operands[0]))
  90.     optype0 = OFFSOP;
  91.   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
  92.     optype0 = POPOP;
  93.   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
  94.     optype0 = PUSHOP;
  95.   else if (GET_CODE (operands[0]) == MEM)
  96.     optype0 = MEMOP;
  97.   else
  98.     optype0 = RNDOP;
  99.  
  100.   if (REG_P (operands[1]))
  101.     optype1 = REGOP;
  102.   else if (CONSTANT_P (operands[1])
  103.        || GET_CODE (operands[1]) == CONST_DOUBLE)
  104.     optype1 = CNSTOP;
  105.   else if (offsetable_memref_p (operands[1]))
  106.     optype1 = OFFSOP;
  107.   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
  108.     optype1 = POPOP;
  109.   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
  110.     optype1 = PUSHOP;
  111.   else if (GET_CODE (operands[1]) == MEM)
  112.     optype1 = MEMOP;
  113.   else
  114.     optype1 = RNDOP;
  115.  
  116.   /* Check for the cases that the operand constraints are not
  117.      supposed to allow to happen.  Abort if we get one,
  118.      because generating code for these cases is painful.  */
  119.  
  120.   if (optype0 == RNDOP || optype1 == RNDOP)
  121.     abort ();
  122.  
  123.   /* If one operand is decrementing and one is incrementing
  124.      decrement the former register explicitly
  125.      and change that operand into ordinary indexing.  */
  126.  
  127.   if (optype0 == PUSHOP && optype1 == POPOP)
  128.     {
  129.       operands[0] = XEXP (XEXP (operands[0], 0), 0);
  130.       output_asm_insn ("subq%.l %#8,%0", operands);
  131.       operands[0] = gen_rtx (MEM, DImode, operands[0]);
  132.       optype0 = OFFSOP;
  133.     }
  134.   if (optype0 == POPOP && optype1 == PUSHOP)
  135.     {
  136.       operands[1] = XEXP (XEXP (operands[1], 0), 0);
  137.       output_asm_insn ("subq%.l %#8,%1", operands);
  138.       operands[1] = gen_rtx (MEM, DImode, operands[1]);
  139.       optype1 = OFFSOP;
  140.     }
  141.  
  142.   /* If an operand is an unoffsettable memory ref, find a register
  143.      we can increment temporarily to make it refer to the second word.  */
  144.  
  145.   if (optype0 == MEMOP)
  146.     addreg0 = find_addr_reg (operands[0]);
  147.  
  148.   if (optype1 == MEMOP)
  149.     addreg1 = find_addr_reg (operands[1]);
  150.  
  151.   /* Ok, we can do one word at a time.
  152.      Normally we do the low-numbered word first,
  153.      but if either operand is autodecrementing then we
  154.      do the high-numbered word first.
  155.  
  156.      In either case, set up in LATEHALF the operands to use
  157.      for the high-numbered word and in some cases alter the
  158.      operands in OPERANDS to be suitable for the low-numbered word.  */
  159.  
  160.   if (optype0 == REGOP)
  161.     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
  162.   else if (optype0 == OFFSOP)
  163.     latehalf[0] = adj_offsetable_operand (operands[0], 4);
  164.   else
  165.     latehalf[0] = operands[0];
  166.  
  167.   if (optype1 == REGOP)
  168.     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
  169.   else if (optype1 == OFFSOP)
  170.     latehalf[1] = adj_offsetable_operand (operands[1], 4);
  171.   else if (optype1 == CNSTOP)
  172.     {
  173.       if (CONSTANT_P (operands[1]))
  174.     latehalf[1] = const0_rtx;
  175.       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
  176.     {
  177.       latehalf[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 1));
  178.       operands[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 0));
  179.     }
  180.     }
  181.   else
  182.     latehalf[1] = operands[1];
  183.  
  184.   /* If insn is effectively movd N(sp),-(sp) then we will do the
  185.      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
  186.      for the low word as well, to compensate for the first decrement of sp.  */
  187.   if (optype0 == PUSHOP
  188.       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
  189.       && reg_mentioned_p (XEXP (XEXP (operands[0], 0), 0), operands[1]))
  190.     operands[1] = latehalf[1];
  191.  
  192.   /* If one or both operands autodecrementing,
  193.      do the two words, high-numbered first.  */
  194.  
  195.   /* Likewise,  the first move would clobber the source of the second one,
  196.      do them in the other order.  This happens only for registers;
  197.      such overlap can't happen in memory unless the user explicitly
  198.      sets it up, and that is an undefined circumstance.  */
  199.  
  200.   if (optype0 == PUSHOP || optype1 == PUSHOP
  201.       || (optype0 == REGOP && optype1 == REGOP
  202.       && REGNO (operands[0]) == REGNO (latehalf[1])))
  203.     {
  204.       /* Make any unoffsetable addresses point at high-numbered word.  */
  205.       if (addreg0)
  206.     output_asm_insn ("addql %#4,%0", &addreg0);
  207.       if (addreg1)
  208.     output_asm_insn ("addql %#4,%0", &addreg1);
  209.  
  210.       /* Do that word.  */
  211.       output_asm_insn (singlemove_string (latehalf), latehalf);
  212.  
  213.       /* Undo the adds we just did.  */
  214.       if (addreg0)
  215.     output_asm_insn ("subql %#4,%0", &addreg0);
  216.       if (addreg1)
  217.     output_asm_insn ("subql %#4,%0", &addreg1);
  218.  
  219.       /* Do low-numbered word.  */
  220.       return singlemove_string (operands);
  221.     }
  222.  
  223.   /* Normal case: do the two words, low-numbered first.  */
  224.  
  225.   output_asm_insn (singlemove_string (operands), operands);
  226.  
  227.   /* Make any unoffsetable addresses point at high-numbered word.  */
  228.   if (addreg0)
  229.     output_asm_insn ("addql %#4,%0", &addreg0);
  230.   if (addreg1)
  231.     output_asm_insn ("addql %#4,%0", &addreg1);
  232.  
  233.   /* Do that word.  */
  234.   output_asm_insn (singlemove_string (latehalf), latehalf);
  235.  
  236.   /* Undo the adds we just did.  */
  237.   if (addreg0)
  238.     output_asm_insn ("subql %#4,%0", &addreg0);
  239.   if (addreg1)
  240.     output_asm_insn ("subql %#4,%0", &addreg1);
  241.  
  242.   return "";
  243. }
  244.  
  245. /* Return a REG that occurs in ADDR with coefficient 1.
  246.    ADDR can be effectively incremented by incrementing REG.  */
  247.  
  248. static rtx
  249. find_addr_reg (addr)
  250.      rtx addr;
  251. {
  252.   while (GET_CODE (addr) == PLUS)
  253.     {
  254.       if (GET_CODE (XEXP (addr, 0)) == REG)
  255.     addr = XEXP (addr, 0);
  256.       if (GET_CODE (XEXP (addr, 1)) == REG)
  257.     addr = XEXP (addr, 1);
  258.       if (CONSTANT_P (XEXP (addr, 0)))
  259.     addr = XEXP (addr, 1);
  260.       if (CONSTANT_P (XEXP (addr, 1)))
  261.     addr = XEXP (addr, 0);
  262.     }
  263.   if (GET_CODE (addr) == REG)
  264.     return addr;
  265.   return 0;
  266. }
  267.  
  268. char *
  269. output_move_const_double (operands)
  270.      rtx *operands;
  271. {
  272.   int code = standard_68881_constant_p (operands[1]);
  273.  
  274.   if (code != 0)
  275.     {
  276.       static char buf[40];
  277.  
  278.       sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff);
  279.       return buf;
  280.     }
  281.   return "fmove%.d %1,%0";
  282. }
  283.  
  284. char *
  285. output_move_const_single (operands)
  286.      rtx *operands;
  287. {
  288.   int code = standard_68881_constant_p (operands[1]);
  289.  
  290.   if (code != 0)
  291.     {
  292.       static char buf[40];
  293.  
  294.       sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff);
  295.       return buf;
  296.     }
  297.   return "fmove%.s %f1,%0";
  298. }
  299.  
  300. /* Return nonzero if X, a CONST_DOUBLE, has a value that we can get
  301.    from the "fmovecr" instruction.
  302.    The value, anded with 0xff, gives the code to use in fmovecr
  303.    to get the desired constant.  */
  304.  
  305. int
  306. standard_68881_constant_p (x)
  307.      rtx x;
  308. {
  309.   union {double d; int i[2];} u;
  310.   register double d;
  311.   u.i[0] = XINT (x, 0);
  312.   u.i[1] = XINT (x, 1);
  313.   d = u.d;
  314.  
  315.   if (d == 0)
  316.     return 0x0f;
  317.   /* Note: there are various other constants available
  318.      but it is a nuisance to put in their values here.  */
  319.   if (d == 1)
  320.     return 0x32;
  321.   if (d == 10)
  322.     return 0x33;
  323.   if (d == 100)
  324.     return 0x34;
  325.   if (d == 10000)
  326.     return 0x35;
  327.   if (d == 1e8)
  328.     return 0x36;
  329.   if (GET_MODE (x) == SFmode)
  330.     return 0;
  331.   if (d == 1e16)
  332.     return 0x37;
  333.   /* larger powers of ten in the constants ram are not used
  334.      because they are not equal to a `double' C constant.  */
  335.   return 0;
  336. }
  337.