home *** CD-ROM | disk | FTP | other *** search
/ Education Sampler 1992 [NeXTSTEP] / Education_1992_Sampler.iso / NeXT / GnuSource / cc-61.0.1 / cc / config / out-m68k.c < prev    next >
C/C++ Source or Header  |  1991-12-19  |  22KB  |  828 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 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20.  
  21. /* Some output-actions in m68k.md need these.  */
  22. #include <stdio.h>
  23. #include "config.h"
  24. #include "rtl.h"
  25. #include "regs.h"
  26. #include "hard-reg-set.h"
  27. #include "real.h"
  28. #include "insn-config.h"
  29. #include "conditions.h"
  30. #include "insn-flags.h"
  31. #include "output.h"
  32. #include "insn-attr.h"
  33.  
  34. /* Needed for use_return_insn.  */
  35. #include "flags.h"
  36.  
  37. /* Index into this array by (register number >> 3) to find the
  38.    smallest class which contains that register.  */
  39. enum reg_class regno_reg_class[]
  40.   = { DATA_REGS, ADDR_REGS, FP_REGS,
  41.       LO_FPA_REGS, LO_FPA_REGS, FPA_REGS, FPA_REGS };
  42.  
  43. static rtx find_addr_reg ();
  44.  
  45. /* This function generates the assembly code for function entry.
  46.    STREAM is a stdio stream to output the code to.
  47.    SIZE is an int: how many units of temporary storage to allocate.
  48.    Refer to the array `regs_ever_live' to determine which registers
  49.    to save; `regs_ever_live[I]' is nonzero if register number I
  50.    is ever used in the function.  This function is responsible for
  51.    knowing which registers should not be saved even if used.  */
  52.  
  53.  
  54. /* Note that the order of the bit mask for fmovem is the opposite
  55.    of the order for movem!  */
  56.  
  57.  
  58. void
  59. output_function_prologue (stream, size)
  60.      FILE *stream;
  61.      int size;
  62. {
  63.   register int regno;
  64.   register int mask = 0;
  65.   extern char call_used_regs[];
  66.   int fsize = (size + 3) & -4;
  67.   
  68.  
  69.   if (frame_pointer_needed)
  70.     {
  71.       if (TARGET_68020 || fsize < 0x8000)
  72.         asm_fprintf (stream, "\tlink %s,%I%d\n",
  73.              reg_names[FRAME_POINTER_REGNUM], -fsize);
  74.       else
  75.     asm_fprintf (stream, "\tlink %s,%I0\n\taddl %I%d,%Rsp\n",
  76.              reg_names[FRAME_POINTER_REGNUM], -fsize);
  77.     }
  78.   else if (fsize)
  79.     {
  80.       if (fsize + 4 < 0x8000)
  81.     asm_fprintf (stream, "\taddw %I%d,%Rsp\n", - (fsize + 4));
  82.       else
  83.     asm_fprintf (stream, "\taddl %I%d,%Rsp\n", - (fsize + 4));
  84.     }
  85.   for (regno = 24; regno < 56; regno++)
  86.     if (regs_ever_live[regno] && ! call_used_regs[regno])
  87.       asm_fprintf (stream, "\tfpmoved %s,%Rsp@-\n",
  88.            reg_names[regno]);
  89.   for (regno = 16; regno < 24; regno++)
  90.     if (regs_ever_live[regno] && ! call_used_regs[regno])
  91.        mask |= 1 << (regno - 16);
  92.   if ((mask & 0xff) != 0)
  93.     asm_fprintf (stream, "\tfmovem %I0x%x,%Rsp@-\n", mask & 0xff);
  94.   mask = 0;
  95.   for (regno = 0; regno < 16; regno++)
  96.     if (regs_ever_live[regno] && ! call_used_regs[regno])
  97.        mask |= 1 << (15 - regno);
  98.   if (frame_pointer_needed)
  99.     mask &= ~ (1 << (15 - FRAME_POINTER_REGNUM));
  100.   if (exact_log2 (mask) >= 0)
  101.     asm_fprintf (stream, "\tmovel %s,%Rsp@-\n",
  102.          reg_names[15 - exact_log2 (mask)]);
  103.   else if (mask)
  104.     asm_fprintf (stream, "\tmoveml %I0x%x,%Rsp@-\n", mask);
  105. }
  106.  
  107. /* Return true if this function's epilogue can be output as RTL.  */
  108.  
  109. int
  110. use_return_insn ()
  111. {
  112.   int regno;
  113.  
  114.   if (!reload_completed || frame_pointer_needed || get_frame_size () != 0)
  115.     return 0;
  116.   
  117.   /* Copied from output_function_epilogue ().  We should probably create a
  118.      separate layout routine to perform the common work.  */
  119.   
  120.   for (regno = 0 ; regno < 56 ; regno++)
  121.     if (regs_ever_live[regno] && ! call_used_regs[regno])
  122.       return 0;
  123.   
  124.   return 1;
  125. }
  126.  
  127. /* This function generates the assembly code for function exit,
  128.    on machines that need it.  Args are same as for FUNCTION_PROLOGUE.
  129.  
  130.    The function epilogue should not depend on the current stack pointer!
  131.    It should use the frame pointer only, if there is a frame pointer.
  132.    This is mandatory because of alloca; we also take advantage of it to
  133.    omit stack adjustments before returning.  */
  134.  
  135. void
  136. output_function_epilogue (stream, size)
  137.      FILE *stream;
  138.      int size;
  139. {
  140.   register int regno;
  141.   register int mask, fmask;
  142.   register int nregs;
  143.   int offset, foffset, fpoffset;
  144.   extern char call_used_regs[];
  145.   int fsize = (size + 3) & -4;
  146.   int big = 0;
  147.   rtx insn = get_last_insn ();
  148.   
  149.   /* If the last insn was a BARRIER, we don't have to write any code.  */
  150.   if (GET_CODE (insn) == NOTE)
  151.     insn = prev_nonnote_insn (insn);
  152.   if (insn && GET_CODE (insn) == BARRIER)
  153.     return;
  154.  
  155. #ifdef FUNCTION_EXTRA_EPILOGUE
  156.   FUNCTION_EXTRA_EPILOGUE (stream, size);
  157. #endif
  158.   nregs = 0;  fmask = 0; fpoffset = 0;
  159.   for (regno = 24 ; regno < 56 ; regno++)
  160.     if (regs_ever_live[regno] && ! call_used_regs[regno])
  161.       nregs++;
  162.   fpoffset = nregs * 8;
  163.   nregs = 0;
  164.   for (regno = 16; regno < 24; regno++)
  165.     if (regs_ever_live[regno] && ! call_used_regs[regno])
  166.       {
  167.         nregs++;
  168.     fmask |= 1 << (23 - regno);
  169.       }
  170.   foffset = fpoffset + nregs * 12;
  171.   nregs = 0;  mask = 0;
  172.   if (frame_pointer_needed)
  173.     regs_ever_live[FRAME_POINTER_REGNUM] = 0;
  174.   for (regno = 0; regno < 16; regno++)
  175.     if (regs_ever_live[regno] && ! call_used_regs[regno])
  176.       {
  177.         nregs++;
  178.     mask |= 1 << regno;
  179.       }
  180.   offset = foffset + nregs * 4;
  181.   if (offset + fsize >= 0x8000
  182.       && frame_pointer_needed
  183.       && (mask || fmask || fpoffset))
  184.     {
  185.       asm_fprintf (stream, "\tmovel %I%d,%Ra0\n", -fsize);
  186.       fsize = 0, big = 1;
  187.     }
  188.   if (exact_log2 (mask) >= 0)
  189.     {
  190.       if (big)
  191.     asm_fprintf (stream, "\tmovel %s@(-%d,%Ra0:l),%s\n",
  192.              reg_names[FRAME_POINTER_REGNUM],
  193.              offset + fsize, reg_names[exact_log2 (mask)]);
  194.       else if (! frame_pointer_needed)
  195.     asm_fprintf (stream, "\tmovel %Rsp@+,%s\n",
  196.              reg_names[exact_log2 (mask)]);
  197.       else
  198.     asm_fprintf (stream, "\tmovel %s@(-%d),%s\n",
  199.              reg_names[FRAME_POINTER_REGNUM],
  200.              offset + fsize, reg_names[exact_log2 (mask)]);
  201.     }
  202.   else if (mask)
  203.     {
  204.       if (big)
  205.     asm_fprintf (stream, "\tmoveml %s@(-%d,%Ra0:l),%I0x%x\n",
  206.              reg_names[FRAME_POINTER_REGNUM],
  207.              offset + fsize, mask);
  208.       else if (! frame_pointer_needed)
  209.     asm_fprintf (stream, "\tmoveml %Rsp@+,%I0x%x\n", mask);
  210.       else
  211.     asm_fprintf (stream, "\tmoveml %s@(-%d),%I0x%x\n",
  212.              reg_names[FRAME_POINTER_REGNUM],
  213.              offset + fsize, mask);
  214.     }
  215.   if (fmask)
  216.     {
  217.       if (big)
  218.     asm_fprintf (stream, "\tfmovem %s@(-%d,%Ra0:l),%I0x%x\n",
  219.              reg_names[FRAME_POINTER_REGNUM],
  220.              foffset + fsize, fmask);
  221.       else if (! frame_pointer_needed)
  222.     asm_fprintf (stream, "\tfmovem %Rsp@+,%I0x%x\n", fmask);
  223.       else
  224.     asm_fprintf (stream, "\tfmovem %s@(-%d),%I0x%x\n",
  225.              reg_names[FRAME_POINTER_REGNUM],
  226.              foffset + fsize, fmask);
  227.     }
  228.   if (fpoffset != 0)
  229.     for (regno = 55; regno >= 24; regno--)
  230.       if (regs_ever_live[regno] && ! call_used_regs[regno])
  231.         {
  232.       if (big)
  233.         asm_fprintf (stream, "\tfpmoved %s@(-%d,a0:l), %s\n",
  234.              reg_names[FRAME_POINTER_REGNUM],
  235.              fpoffset + fsize, reg_names[regno]);
  236.       else if (! frame_pointer_needed)
  237.         asm_fprintf (stream, "\tfpmoved sp@+, %s\n",
  238.              reg_names[regno]);
  239.       else
  240.         asm_fprintf (stream, "\tfpmoved %s@(-%d), %s\n",
  241.              reg_names[FRAME_POINTER_REGNUM],
  242.              fpoffset + fsize, reg_names[regno]);
  243.       fpoffset -= 8;
  244.     }
  245.   if (frame_pointer_needed)
  246.     fprintf (stream, "\tunlk %s\n",
  247.          reg_names[FRAME_POINTER_REGNUM]);
  248.   else if (fsize)
  249.     {
  250.       if (fsize + 4 < 0x8000)
  251.         asm_fprintf (stream, "\taddw %I%d,%Rsp\n", fsize + 4);
  252.       else
  253.         asm_fprintf (stream, "\taddl %I%d,%Rsp\n", fsize + 4);
  254.     }
  255.   if (current_function_pops_args)
  256.     asm_fprintf (stream, "\trtd %I%d\n", current_function_pops_args);
  257.   else
  258.     fprintf (stream, "\trts\n");
  259. }
  260.  
  261. /* Similar to general_operand, but exclude stack_pointer_rtx.  */
  262.  
  263. int
  264. not_sp_operand (op, mode)
  265.      register rtx op;
  266.      enum machine_mode mode;
  267. {
  268.   return op != stack_pointer_rtx && general_operand (op, mode);
  269. }
  270.  
  271. char *
  272. output_btst (operands, countop, dataop, insn, signpos)
  273.      rtx *operands;
  274.      rtx countop, dataop;
  275.      rtx insn;
  276.      int signpos;
  277. {
  278.   operands[0] = countop;
  279.   operands[1] = dataop;
  280.  
  281.   if (GET_CODE (countop) == CONST_INT)
  282.     {
  283.       register int count = INTVAL (countop);
  284.       /* If COUNT is bigger than size of storage unit in use,
  285.      advance to the containing unit of same size.  */
  286.       if (count > signpos)
  287.     {
  288.       int offset = (count & ~signpos) / 8;
  289.       count = count & signpos;
  290.       operands[1] = dataop = adj_offsettable_operand (dataop, offset);
  291.     }
  292.       if (count == signpos)
  293.     cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N;
  294.       else
  295.     cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N;
  296.  
  297.       /* These three statements used to use next_insns_test_no...
  298.      but it appears that this should do the same job.  */
  299.       if (count == 31
  300.       && next_insn_tests_no_inequality (insn))
  301.     return "tst%.l %1";
  302.       if (count == 15
  303.       && next_insn_tests_no_inequality (insn))
  304.     return "tst%.w %1";
  305.       if (count == 7
  306.       && next_insn_tests_no_inequality (insn))
  307.     return "tst%.b %1";
  308.  
  309.       cc_status.flags = CC_NOT_NEGATIVE;
  310.     }
  311.   return "btst %0,%1";
  312. }
  313.  
  314. /* Return the best assembler insn template
  315.    for moving operands[1] into operands[0] as a fullword.  */
  316.  
  317. static char *
  318. singlemove_string (operands)
  319.      rtx *operands;
  320. {
  321.   if (FPA_REG_P (operands[0]) || FPA_REG_P (operands[1]))
  322.     return "fpmoves %1,%0";
  323.   if (operands[1] != const0_rtx)
  324.     return "move%.l %1,%0";
  325.   if (! ADDRESS_REG_P (operands[0]))
  326.     return "clr%.l %0";
  327.   return "sub%.l %0,%0";
  328. }
  329.  
  330. /* Output assembler code to perform a doubleword move insn
  331.    with operands OPERANDS.  */
  332.  
  333. char *
  334. output_move_double (operands)
  335.      rtx *operands;
  336. {
  337.   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  338.   rtx latehalf[2];
  339.   rtx addreg0 = 0, addreg1 = 0;
  340.  
  341.   /* First classify both operands.  */
  342.  
  343.   if (REG_P (operands[0]))
  344.     optype0 = REGOP;
  345.   else if (offsettable_memref_p (operands[0]))
  346.     optype0 = OFFSOP;
  347.   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
  348.     optype0 = POPOP;
  349.   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
  350.     optype0 = PUSHOP;
  351.   else if (GET_CODE (operands[0]) == MEM)
  352.     optype0 = MEMOP;
  353.   else
  354.     optype0 = RNDOP;
  355.  
  356.   if (REG_P (operands[1]))
  357.     optype1 = REGOP;
  358.   else if (CONSTANT_P (operands[1]))
  359.     optype1 = CNSTOP;
  360.   else if (offsettable_memref_p (operands[1]))
  361.     optype1 = OFFSOP;
  362.   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
  363.     optype1 = POPOP;
  364.   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
  365.     optype1 = PUSHOP;
  366.   else if (GET_CODE (operands[1]) == MEM)
  367.     optype1 = MEMOP;
  368.   else
  369.     optype1 = RNDOP;
  370.  
  371.   /* Check for the cases that the operand constraints are not
  372.      supposed to allow to happen.  Abort if we get one,
  373.      because generating code for these cases is painful.  */
  374.  
  375.   if (optype0 == RNDOP || optype1 == RNDOP)
  376.     abort ();
  377.  
  378.   /* If one operand is decrementing and one is incrementing
  379.      decrement the former register explicitly
  380.      and change that operand into ordinary indexing.  */
  381.  
  382.   if (optype0 == PUSHOP && optype1 == POPOP)
  383.     {
  384.       operands[0] = XEXP (XEXP (operands[0], 0), 0);
  385.       output_asm_insn ("subq%.l %#8,%0", operands);
  386.       operands[0] = gen_rtx (MEM, DImode, operands[0]);
  387.       optype0 = OFFSOP;
  388.     }
  389.   if (optype0 == POPOP && optype1 == PUSHOP)
  390.     {
  391.       operands[1] = XEXP (XEXP (operands[1], 0), 0);
  392.       output_asm_insn ("subq%.l %#8,%1", operands);
  393.       operands[1] = gen_rtx (MEM, DImode, operands[1]);
  394.       optype1 = OFFSOP;
  395.     }
  396.  
  397.   /* If an operand is an unoffsettable memory ref, find a register
  398.      we can increment temporarily to make it refer to the second word.  */
  399.  
  400.   if (optype0 == MEMOP)
  401.     addreg0 = find_addr_reg (XEXP (operands[0], 0));
  402.  
  403.   if (optype1 == MEMOP)
  404.     addreg1 = find_addr_reg (XEXP (operands[1], 0));
  405.  
  406.   /* Ok, we can do one word at a time.
  407.      Normally we do the low-numbered word first,
  408.      but if either operand is autodecrementing then we
  409.      do the high-numbered word first.
  410.  
  411.      In either case, set up in LATEHALF the operands to use
  412.      for the high-numbered word and in some cases alter the
  413.      operands in OPERANDS to be suitable for the low-numbered word.  */
  414.  
  415.   if (optype0 == REGOP)
  416.     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
  417.   else if (optype0 == OFFSOP)
  418.     latehalf[0] = adj_offsettable_operand (operands[0], 4);
  419.   else
  420.     latehalf[0] = operands[0];
  421.  
  422.   if (optype1 == REGOP)
  423.     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
  424.   else if (optype1 == OFFSOP)
  425.     latehalf[1] = adj_offsettable_operand (operands[1], 4);
  426.   else if (optype1 == CNSTOP)
  427.     split_double (operands[1], &operands[1], &latehalf[1]);
  428.   else
  429.     latehalf[1] = operands[1];
  430.  
  431.   /* If insn is effectively movd N(sp),-(sp) then we will do the
  432.      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
  433.      for the low word as well, to compensate for the first decrement of sp.  */
  434.   if (optype0 == PUSHOP
  435.       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
  436.       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
  437.     operands[1] = latehalf[1];
  438.  
  439.   /* If one or both operands autodecrementing,
  440.      do the two words, high-numbered first.  */
  441.  
  442.   /* Likewise,  the first move would clobber the source of the second one,
  443.      do them in the other order.  This happens only for registers;
  444.      such overlap can't happen in memory unless the user explicitly
  445.      sets it up, and that is an undefined circumstance.  */
  446.  
  447.   if (optype0 == PUSHOP || optype1 == PUSHOP
  448.       || (optype0 == REGOP && optype1 == REGOP
  449.       && REGNO (operands[0]) == REGNO (latehalf[1])))
  450.     {
  451.       /* Make any unoffsettable addresses point at high-numbered word.  */
  452.       if (addreg0)
  453.     output_asm_insn ("addql %#4,%0", &addreg0);
  454.       if (addreg1)
  455.     output_asm_insn ("addql %#4,%0", &addreg1);
  456.  
  457.       /* Do that word.  */
  458.       output_asm_insn (singlemove_string (latehalf), latehalf);
  459.  
  460.       /* Undo the adds we just did.  */
  461.       if (addreg0)
  462.     output_asm_insn ("subql %#4,%0", &addreg0);
  463.       if (addreg1)
  464.     output_asm_insn ("subql %#4,%0", &addreg1);
  465.  
  466.       /* Do low-numbered word.  */
  467.       return singlemove_string (operands);
  468.     }
  469.  
  470.   /* Normal case: do the two words, low-numbered first.  */
  471.  
  472.   output_asm_insn (singlemove_string (operands), operands);
  473.  
  474.   /* Make any unoffsettable addresses point at high-numbered word.  */
  475.   if (addreg0)
  476.     output_asm_insn ("addql %#4,%0", &addreg0);
  477.   if (addreg1)
  478.     output_asm_insn ("addql %#4,%0", &addreg1);
  479.  
  480.   /* Do that word.  */
  481.   output_asm_insn (singlemove_string (latehalf), latehalf);
  482.  
  483.   /* Undo the adds we just did.  */
  484.   if (addreg0)
  485.     output_asm_insn ("subql %#4,%0", &addreg0);
  486.   if (addreg1)
  487.     output_asm_insn ("subql %#4,%0", &addreg1);
  488.  
  489.   return "";
  490. }
  491.  
  492. /* Return a REG that occurs in ADDR with coefficient 1.
  493.    ADDR can be effectively incremented by incrementing REG.  */
  494.  
  495. static rtx
  496. find_addr_reg (addr)
  497.      rtx addr;
  498. {
  499.   while (GET_CODE (addr) == PLUS)
  500.     {
  501.       if (GET_CODE (XEXP (addr, 0)) == REG)
  502.     addr = XEXP (addr, 0);
  503.       else if (GET_CODE (XEXP (addr, 1)) == REG)
  504.     addr = XEXP (addr, 1);
  505.       else if (CONSTANT_P (XEXP (addr, 0)))
  506.     addr = XEXP (addr, 1);
  507.       else if (CONSTANT_P (XEXP (addr, 1)))
  508.     addr = XEXP (addr, 0);
  509.       else
  510.     abort ();
  511.     }
  512.   if (GET_CODE (addr) == REG)
  513.     return addr;
  514.   abort ();
  515. }
  516.  
  517. char *
  518. output_move_const_double (operands)
  519.      rtx *operands;
  520. {
  521.   if (TARGET_FPA && FPA_REG_P(operands[0]))
  522.     {
  523.       int code = standard_sun_fpa_constant_p (operands[1]);
  524.  
  525.       if (code != 0)
  526.     {
  527.       static char buf[40];
  528.  
  529.       sprintf (buf, "fpmove%%.d %%%%%d,%%0", code & 0x1ff);
  530.       return buf;
  531.     }
  532.       return "fpmove%.d %1,%0";
  533.     }
  534.   else
  535.     {
  536.       int code = standard_68881_constant_p (operands[1]);
  537.  
  538.       if (code != 0)
  539.     {
  540.       static char buf[40];
  541.  
  542.       sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff);
  543.       return buf;
  544.     }
  545.       return "fmove%.d %1,%0";
  546.     }
  547. }
  548.  
  549. char *
  550. output_move_const_single (operands)
  551.      rtx *operands;
  552. {
  553.   if (TARGET_FPA)
  554.     {
  555.       int code = standard_sun_fpa_constant_p (operands[1]);
  556.  
  557.       if (code != 0)
  558.     {
  559.       static char buf[40];
  560.  
  561.       sprintf (buf, "fpmove%%.s %%%%%d,%%0", code & 0x1ff);
  562.       return buf;
  563.     }
  564.       return "fpmove%.s %1,%0";
  565.     }
  566.   else
  567.     {
  568.       int code = standard_68881_constant_p (operands[1]);
  569.  
  570.       if (code != 0)
  571.     {
  572.       static char buf[40];
  573.  
  574.       sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff);
  575.       return buf;
  576.     }
  577.       return "fmove%.s %f1,%0";
  578.     }
  579. }
  580.  
  581. /* Return nonzero if X, a CONST_DOUBLE, has a value that we can get
  582.    from the "fmovecr" instruction.
  583.    The value, anded with 0xff, gives the code to use in fmovecr
  584.    to get the desired constant.  */
  585.  
  586. /* ??? This code should be fixed for cross-compilation. */
  587.  
  588. int
  589. standard_68881_constant_p (x)
  590.      rtx x;
  591. {
  592.   union {double d; int i[2];} u;
  593.   register double d;
  594.  
  595.   /* fmovecr must be emulated on the 68040, so it shoudn't be used at all. */
  596.   if (TARGET_68040)
  597.     return 0;
  598.  
  599. #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
  600.   if (! flag_pretend_float)
  601.     return 0;
  602. #endif
  603.  
  604. #ifdef HOST_WORDS_BIG_ENDIAN
  605.   u.i[0] = CONST_DOUBLE_LOW (x);
  606.   u.i[1] = CONST_DOUBLE_HIGH (x);
  607. #else
  608.   u.i[0] = CONST_DOUBLE_HIGH (x);
  609.   u.i[1] = CONST_DOUBLE_LOW (x);
  610. #endif 
  611.   d = u.d;
  612.  
  613.   if (d == 0)
  614.     return 0x0f;
  615.   /* Note: there are various other constants available
  616.      but it is a nuisance to put in their values here.  */
  617.   if (d == 1)
  618.     return 0x32;
  619.   if (d == 10)
  620.     return 0x33;
  621.   if (d == 100)
  622.     return 0x34;
  623.   if (d == 10000)
  624.     return 0x35;
  625.   if (d == 1e8)
  626.     return 0x36;
  627.   if (GET_MODE (x) == SFmode)
  628.     return 0;
  629.   if (d == 1e16)
  630.     return 0x37;
  631.   /* larger powers of ten in the constants ram are not used
  632.      because they are not equal to a `double' C constant.  */
  633.   return 0;
  634. }
  635.  
  636. /* If X is a floating-point constant, return the logarithm of X base 2,
  637.    or 0 if X is not a power of 2.  */
  638.  
  639. int
  640. floating_exact_log2 (x)
  641.      rtx x;
  642. {
  643.   union {double d; int i[2];} u;
  644.   register double d, d1;
  645.   int i;
  646.  
  647. #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
  648.   if (! flag_pretend_float)
  649.     return 0;
  650. #endif
  651.  
  652. #ifdef HOST_WORDS_BIG_ENDIAN
  653.   u.i[0] = CONST_DOUBLE_LOW (x);
  654.   u.i[1] = CONST_DOUBLE_HIGH (x);
  655. #else
  656.   u.i[0] = CONST_DOUBLE_HIGH (x);
  657.   u.i[1] = CONST_DOUBLE_LOW (x);
  658. #endif 
  659.   d = u.d;
  660.  
  661.   if (! (d > 0))
  662.     return 0;
  663.  
  664.   for (d1 = 1.0, i = 0; d1 < d; d1 *= 2.0, i++)
  665.     ;
  666.  
  667.   if (d == d1)
  668.     return i;
  669.  
  670.   return 0;
  671. }
  672.  
  673. /* Return nonzero if X, a CONST_DOUBLE, has a value that we can get
  674.    from the Sun FPA's constant RAM.
  675.    The value returned, anded with 0x1ff, gives the code to use in fpmove
  676.    to get the desired constant. */
  677. #define S_E (2.718281745910644531)
  678. #define D_E (2.718281828459045091)
  679. #define S_PI (3.141592741012573242)
  680. #define D_PI (3.141592653589793116)
  681. #define S_SQRT2 (1.414213538169860840)
  682. #define D_SQRT2 (1.414213562373095145)
  683. #define S_LOG2ofE (1.442695021629333496)
  684. #define D_LOG2ofE (1.442695040888963387)
  685. #define S_LOG2of10 (3.321928024291992188)
  686. #define D_LOG2of10 (3.321928024887362182)
  687. #define S_LOGEof2 (0.6931471824645996094)
  688. #define D_LOGEof2 (0.6931471805599452862)
  689. #define S_LOGEof10 (2.302585124969482442)
  690. #define D_LOGEof10 (2.302585092994045901)
  691. #define S_LOG10of2 (0.3010300099849700928)
  692. #define D_LOG10of2 (0.3010299956639811980)
  693. #define S_LOG10ofE (0.4342944920063018799)
  694. #define D_LOG10ofE (0.4342944819032518167)
  695.  
  696. /* This code should be fixed for cross-compilation. */
  697.  
  698. int
  699. standard_sun_fpa_constant_p (x)
  700.      rtx x;
  701. {
  702.   union {double d; int i[2];} u;
  703.   register double d;
  704.  
  705. #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
  706.   if (! flag_pretend_float)
  707.     return 0;
  708. #endif
  709.  
  710.  
  711.   u.i[0] = CONST_DOUBLE_LOW (x);
  712.   u.i[1] = CONST_DOUBLE_HIGH (x);
  713.   d = u.d;
  714.  
  715.   if (d == 0.0)
  716.     return 0x200;        /* 0 once 0x1ff is anded with it */
  717.   if (d == 1.0)
  718.     return 0xe;
  719.   if (d == 0.5)
  720.     return 0xf;
  721.   if (d == -1.0)
  722.     return 0x10;
  723.   if (d == 2.0)
  724.     return 0x11;
  725.   if (d == 3.0)
  726.     return 0xB1;
  727.   if (d == 4.0)
  728.     return 0x12;
  729.   if (d == 8.0)
  730.     return 0x13;
  731.   if (d == 0.25)
  732.     return 0x15;
  733.   if (d == 0.125)
  734.     return 0x16;
  735.   if (d == 10.0)
  736.     return 0x17;
  737.   if (d == -(1.0/2.0))
  738.     return 0x2E;
  739.  
  740. /*
  741.  * Stuff that looks different if it's single or double
  742.  */
  743.   if (GET_MODE(x) == SFmode)
  744.     {
  745.       if (d == S_E)
  746.     return 0x8;
  747.       if (d == (2*S_PI))
  748.     return 0x9;
  749.       if (d == S_PI)
  750.     return 0xA;
  751.       if (d == (S_PI / 2.0))
  752.     return 0xB;
  753.       if (d == S_SQRT2)
  754.     return 0xC;
  755.       if (d == (1.0 / S_SQRT2))
  756.     return 0xD;
  757.       /* Large powers of 10 in the constant 
  758.      ram are not used because they are
  759.      not equal to a C double constant  */
  760.       if (d == -(S_PI / 2.0))
  761.     return 0x27;
  762.       if (d == S_LOG2ofE)
  763.     return 0x28;
  764.       if (d == S_LOG2of10)
  765.     return 0x29;
  766.       if (d == S_LOGEof2)
  767.     return 0x2A;
  768.       if (d == S_LOGEof10)
  769.     return 0x2B;
  770.       if (d == S_LOG10of2)
  771.     return 0x2C;
  772.       if (d == S_LOG10ofE)
  773.     return 0x2D;
  774.     }
  775.   else
  776.     {
  777.       if (d == D_E)
  778.     return 0x8;
  779.       if (d == (2*D_PI))
  780.     return 0x9;
  781.       if (d == D_PI)
  782.     return 0xA;
  783.       if (d == (D_PI / 2.0))
  784.     return 0xB;
  785.       if (d == D_SQRT2)
  786.     return 0xC;
  787.       if (d == (1.0 / D_SQRT2))
  788.     return 0xD;
  789.       /* Large powers of 10 in the constant 
  790.      ram are not used because they are
  791.      not equal to a C double constant  */
  792.       if (d == -(D_PI / 2.0))
  793.     return 0x27;
  794.       if (d == D_LOG2ofE)
  795.     return 0x28;
  796.       if (d == D_LOG2of10)
  797.     return 0x29;
  798.       if (d == D_LOGEof2)
  799.     return 0x2A;
  800.       if (d == D_LOGEof10)
  801.     return 0x2B;
  802.       if (d == D_LOG10of2)
  803.     return 0x2C;
  804.       if (d == D_LOG10ofE)
  805.     return 0x2D;
  806.     }
  807.   return 0x0;
  808. }
  809.  
  810. #undef S_E 
  811. #undef D_E 
  812. #undef S_PI 
  813. #undef D_PI 
  814. #undef S_SQRT2 
  815. #undef D_SQRT2 
  816. #undef S_LOG2ofE 
  817. #undef D_LOG2ofE 
  818. #undef S_LOG2of10 
  819. #undef D_LOG2of10 
  820. #undef S_LOGEof2 
  821. #undef D_LOGEof2 
  822. #undef S_LOGEof10 
  823. #undef D_LOGEof10 
  824. #undef S_LOG10of2 
  825. #undef D_LOG10of2 
  826. #undef S_LOG10ofE 
  827. #undef D_LOG10ofE
  828.