home *** CD-ROM | disk | FTP | other *** search
/ Education Sampler 1992 [NeXTSTEP] / Education_1992_Sampler.iso / NeXT / GnuSource / cc-61.0.1 / cc / config / out-ns32k.c < prev    next >
C/C++ Source or Header  |  1991-06-03  |  16KB  |  623 lines

  1. /* Subroutines for assembler code output on the NS32000.
  2.    Copyright (C) 1988 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. /* Some output-actions in ns32k.md need these.  */
  21. #include <stdio.h>
  22. #include "config.h"
  23. #include "rtl.h"
  24. #include "regs.h"
  25. #include "hard-reg-set.h"
  26. #include "real.h"
  27. #include "insn-config.h"
  28. #include "conditions.h"
  29. #include "insn-flags.h"
  30. #include "output.h"
  31. #include "insn-attr.h"
  32.  
  33. #define FP_REG_P(X)  (GET_CODE (X) == REG && REGNO (X) > 7 && REGNO (X) < 16)
  34.  
  35. /* Generate the rtx that comes from an address expression in the md file */
  36. /* The expression to be build is BASE[INDEX:SCALE].  To recognize this,
  37.    scale must be converted from an exponent (from ASHIFT) to a
  38.    muliplier (for MULT). */
  39. rtx
  40. gen_indexed_expr (base, index, scale)
  41.      rtx base, index, scale;
  42. {
  43.   rtx addr;
  44.  
  45.   /* This generates an illegal addressing mode, if BASE is
  46.      fp or sp.  This is handled by PRINT_OPERAND_ADDRESS.  */
  47.   if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT)
  48.     base = gen_rtx (MEM, SImode, base);
  49.   addr = gen_rtx (MULT, SImode, index,
  50.           gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (scale)));
  51.   addr = gen_rtx (PLUS, SImode, base, addr);
  52.   return addr;
  53. }
  54.  
  55. /* Return 1 if OP is a valid operand of mode MODE.  This
  56.    predicate rejects operands which do not have a mode
  57.    (such as CONST_INT which are VOIDmode).  */
  58. int
  59. reg_or_mem_operand (op, mode)
  60.      register rtx op;
  61.      enum machine_mode mode;
  62. {
  63.   return (GET_MODE (op) == mode
  64.       && (GET_CODE (op) == REG
  65.           || GET_CODE (op) == SUBREG
  66.           || GET_CODE (op) == MEM));
  67. }
  68.  
  69. /* Return the best assembler insn template
  70.    for moving operands[1] into operands[0] as a fullword.  */
  71.  
  72. static char *
  73. singlemove_string (operands)
  74.      rtx *operands;
  75. {
  76.   if (GET_CODE (operands[1]) == CONST_INT
  77.       && INTVAL (operands[1]) <= 7
  78.       && INTVAL (operands[1]) >= -8)
  79.     return "movqd %1,%0";
  80.   return "movd %1,%0";
  81. }
  82.  
  83. char *
  84. output_move_double (operands)
  85.      rtx *operands;
  86. {
  87.   enum anon1 { REGOP, OFFSOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  88.   rtx latehalf[2];
  89.  
  90.   /* First classify both operands.  */
  91.  
  92.   if (REG_P (operands[0]))
  93.     optype0 = REGOP;
  94.   else if (offsettable_memref_p (operands[0]))
  95.     optype0 = OFFSOP;
  96.   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
  97.     optype0 = POPOP;
  98.   else
  99.     optype0 = RNDOP;
  100.  
  101.   if (REG_P (operands[1]))
  102.     optype1 = REGOP;
  103.   else if (CONSTANT_ADDRESS_P (operands[1])
  104.        || GET_CODE (operands[1]) == CONST_DOUBLE)
  105.     optype1 = CNSTOP;
  106.   else if (offsettable_memref_p (operands[1]))
  107.     optype1 = OFFSOP;
  108.   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
  109.     optype1 = POPOP;
  110.   else
  111.     optype1 = RNDOP;
  112.  
  113.   /* Check for the cases that the operand constraints are not
  114.      supposed to allow to happen.  Abort if we get one,
  115.      because generating code for these cases is painful.  */
  116.  
  117.   if (optype0 == RNDOP || optype1 == RNDOP)
  118.     abort ();
  119.  
  120.   /* Ok, we can do one word at a time.
  121.      Normally we do the low-numbered word first,
  122.      but if either operand is autodecrementing then we
  123.      do the high-numbered word first.
  124.  
  125.      In either case, set up in LATEHALF the operands to use
  126.      for the high-numbered word and in some cases alter the
  127.      operands in OPERANDS to be suitable for the low-numbered word.  */
  128.  
  129.   if (optype0 == REGOP)
  130.     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
  131.   else if (optype0 == OFFSOP)
  132.     latehalf[0] = adj_offsettable_operand (operands[0], 4);
  133.   else
  134.     latehalf[0] = operands[0];
  135.  
  136.   if (optype1 == REGOP)
  137.     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
  138.   else if (optype1 == OFFSOP)
  139.     latehalf[1] = adj_offsettable_operand (operands[1], 4);
  140.   else if (optype1 == CNSTOP)
  141.     {
  142.       if (CONSTANT_ADDRESS_P (operands[1]))
  143.     latehalf[1] = const0_rtx;
  144.       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
  145.     split_double (operands[1], &operands[1], &latehalf[1]);
  146.     }
  147.   else
  148.     latehalf[1] = operands[1];
  149.  
  150.   /* If one or both operands autodecrementing,
  151.      do the two words, high-numbered first.  */
  152.  
  153.   if (optype0 == POPOP || optype1 == POPOP)
  154.     {
  155.       output_asm_insn (singlemove_string (latehalf), latehalf);
  156.       return singlemove_string (operands);
  157.     }
  158.  
  159.   /* Not autodecrementing.  Do the two words, low-numbered first.  */
  160.  
  161.   output_asm_insn (singlemove_string (operands), operands);
  162.  
  163.   operands[0] = latehalf[0];
  164.   operands[1] = latehalf[1];
  165.   return singlemove_string (operands);
  166. }
  167.  
  168. int
  169. check_reg (oper, reg)
  170.      rtx oper;
  171.      int reg;
  172. {
  173.   register int i;
  174.  
  175.   if (oper == 0)
  176.     return 0;
  177.   switch (GET_CODE(oper))
  178.     {
  179.     case REG:
  180.       return (REGNO(oper) == reg) ? 1 : 0;
  181.     case MEM:
  182.       return check_reg(XEXP(oper, 0), reg);
  183.     case PLUS:
  184.     case MULT:
  185.       return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg);
  186.     }
  187.   return 0;
  188. }
  189.  
  190. /* PRINT_OPERAND_ADDRESS is defined to call this function,
  191.    which is easier to debug than putting all the code in
  192.    a macro definition in tm-ns32k.h .  */
  193.  
  194. /* Nonzero if we have printed a base register.
  195.    If zero, on some systems, it means `(sb)' must be printed.  */
  196. int paren_base_reg_printed = 0;
  197.  
  198. /* This function can call itself. We can't have disp(@disp) but we can
  199.  * have disp(disp(sb)) which is the same thing. Setting memory_relative
  200.  * to non zero implies the second form
  201.  */
  202. static int memory_relative = 0;
  203.  
  204. print_operand_address (file, addr)
  205.      register FILE *file;
  206.      register rtx addr;
  207. {
  208.   register rtx reg1, reg2, breg, ireg;
  209.   rtx offset;
  210.   static char scales[] = { 'b', 'w', 'd', 0, 'q', };
  211.  
  212.  retry:
  213.   switch (GET_CODE (addr))
  214.     {
  215.     case MEM:
  216.       addr = XEXP (addr, 0);
  217.       if (GET_CODE (addr) == REG)
  218.     if (REGNO (addr) == STACK_POINTER_REGNUM)
  219.       { fprintf (file, "tos"); break; }
  220.     else
  221.       {
  222.         fprintf (stderr, "** Dodgy 1 reached**\n"); /*  Is this ever done? */
  223.         fprintf (file, "0(%s)", reg_names[REGNO (addr)]); break;
  224.       }
  225.       else if (CONSTANT_P (addr))
  226.     {
  227.       if (!memory_relative)
  228.         PUT_ABSOLUTE_PREFIX(file);
  229.       output_addr_const (file, addr);
  230.       if (memory_relative)
  231.         fprintf(file, "(sb)");
  232.       break;
  233.     }
  234.       else if (GET_CODE (addr) == MULT)
  235.     { fprintf (file, "0"); ireg = addr; goto print_index; }
  236.       else if (GET_CODE (addr) == MEM)
  237.     {
  238.       addr = XEXP (addr, 0);
  239.       fprintf (stderr, "** Dodgy 2 reached**\n"); /*  Is this ever done? */
  240.       if (GET_CODE (addr) == PLUS)
  241.         {
  242.           offset = XEXP (addr, 1);
  243.           addr = XEXP (addr, 0);
  244.         }
  245.       else
  246.         {
  247.           offset = const0_rtx;
  248.         }
  249.       output_addr_const (file, offset);
  250.       fprintf (file, "(%s)", reg_names[REGNO (addr)]);
  251.       break;
  252.     }
  253.  
  254.       if (GET_CODE (addr) != PLUS)
  255.     abort ();
  256.  
  257.     /* (MEM (PLUS ... )) */
  258.       fprintf (file, "0(");
  259.       memory_relative = 1;
  260.       output_address (addr);
  261.       memory_relative = 0;
  262.       fprintf (file, ")");
  263.       break;
  264.  
  265.     case REG:
  266.       if (REGNO (addr) == STACK_POINTER_REGNUM)
  267.     fprintf (file, "tos");
  268.       else
  269.     fprintf (file, "0(%s)", reg_names[REGNO (addr)]);
  270.       break;
  271.  
  272.     case PRE_DEC:
  273.     case POST_INC:
  274.       fprintf (file, "tos");
  275.       break;
  276.  
  277.     case MULT:
  278.       fprintf (file, "0");
  279.       ireg = addr; /* [rX:Y] */
  280.       goto print_index;
  281.       break;
  282.  
  283.     case PLUS:
  284.       reg1 = 0;    reg2 = 0;
  285.       ireg = 0;    breg = 0;
  286.       offset = const0_rtx;
  287.       if (CONSTANT_ADDRESS_P (XEXP (addr, 0)))
  288.     {
  289.       offset = XEXP (addr, 0);
  290.       addr = XEXP (addr, 1);
  291.     }
  292.       else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)))
  293.     {
  294.       offset = XEXP (addr, 1);
  295.       addr = XEXP (addr, 0);
  296.     }
  297.       if (GET_CODE (addr) != PLUS) ;
  298.       else if (GET_CODE (XEXP (addr, 0)) == MULT)
  299.     {
  300.       reg1 = XEXP (addr, 0);
  301.       addr = XEXP (addr, 1);
  302.     }
  303.       else if (GET_CODE (XEXP (addr, 1)) == MULT)
  304.     {
  305.       reg1 = XEXP (addr, 1);
  306.       addr = XEXP (addr, 0);
  307.     }
  308.       /* The case for memory is somewhat tricky:  to get
  309.      a MEM here, the only RTX formats that could
  310.      get here are either (modulo commutativity)
  311.        (PLUS (PLUS (REG *MEM)) CONST) -or-
  312.        (PLUS (PLUS (CONST REG/MULT)) *MEM)
  313.      We take advantage of that knowledge here.  */
  314.       else if (GET_CODE (XEXP (addr, 0)) == MEM
  315.            || GET_CODE (XEXP (addr, 1)) == MEM)
  316.     {
  317.       rtx temp;
  318.  
  319.       if (GET_CODE (XEXP (addr, 0)) == MEM)
  320.         {
  321.           temp = XEXP (addr, 1);
  322.           addr = XEXP (addr, 0);
  323.         }
  324.       else
  325.         {
  326.           temp = XEXP (addr, 0);
  327.           addr = XEXP (addr, 1);
  328.         }
  329.  
  330.       if (GET_CODE (temp) == REG)
  331.         {
  332.           reg1 = temp;
  333.         }
  334.       else
  335.         {
  336.           if (GET_CODE (temp) != PLUS)
  337.         abort ();
  338.  
  339.           if (GET_CODE (XEXP (temp, 0)) == MULT)
  340.         {
  341.           reg1 = XEXP (temp, 0);
  342.           offset = XEXP (temp, 1);
  343.         }
  344.           if (GET_CODE (XEXP (temp, 1)) == MULT)
  345.         {
  346.           reg1 = XEXP (temp, 1);
  347.           offset = XEXP (temp, 0);
  348.         }
  349.           else
  350.         abort ();
  351.         }
  352.     }
  353.       else if (GET_CODE (XEXP (addr, 0)) == REG
  354.            || GET_CODE (XEXP (addr, 1)) == REG)
  355.     {
  356.       rtx temp;
  357.  
  358.       if (GET_CODE (XEXP (addr, 0)) == REG)
  359.         {
  360.           temp = XEXP (addr, 0);
  361.           addr = XEXP (addr, 1);
  362.         }
  363.       else
  364.         {
  365.           temp = XEXP (addr, 1);
  366.           addr = XEXP (addr, 0);
  367.         }
  368.  
  369.       if (GET_CODE (addr) == REG)
  370.         {
  371.           if (REGNO (temp) >= FRAME_POINTER_REGNUM)
  372.         { reg1 = addr; addr = temp; }
  373.           else
  374.         { reg1 = temp; }
  375.         }
  376.       else if (CONSTANT_P (addr))
  377.         {
  378.           if (GET_CODE (offset) == CONST_INT
  379.           && INTVAL (offset))
  380.         offset = plus_constant (addr, INTVAL (offset));
  381.           addr = temp;
  382.         }
  383.       else if (GET_CODE (addr) != PLUS)
  384.         abort ();
  385.       else
  386.         {
  387.           if (CONSTANT_ADDRESS_P (XEXP (addr, 0)))
  388.         {
  389.           offset = XEXP (addr, 0);
  390.           addr = XEXP (addr, 1);
  391.         }
  392.           else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)))
  393.         {
  394.           offset = XEXP (addr, 1);
  395.           addr = XEXP (addr, 0);
  396.         }
  397.           else abort ();
  398.  
  399.           if (GET_CODE (addr) == REG)
  400.         {
  401.           if (REGNO (temp) >= FRAME_POINTER_REGNUM)
  402.             { reg1 = addr; addr = temp; }
  403.           else
  404.             { reg1 = temp; }
  405.         }
  406.           else
  407.         reg1 = temp;
  408.         }
  409.     }
  410.  
  411.       if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
  412.     { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; }
  413.       if (addr != 0)
  414.     {
  415.       if (CONSTANT_P (addr) && reg1)
  416.         {
  417.           /* OFFSET comes second, to prevent outputting
  418.          operands of the form INT+SYMBOL+INT.
  419.          The Genix assembler dies on them.  */
  420.           PUT_ABSOLUTE_PREFIX(file);
  421.           output_addr_const (file, addr);
  422.           if (offset != const0_rtx)
  423.         {
  424.           putc ('+', file);
  425.           output_addr_const (file, offset);
  426.         }
  427.           ireg = reg1;
  428.           goto print_index;
  429.         }
  430.       else if (GET_CODE (addr) != MEM)
  431.         abort ();
  432.  
  433.       output_addr_const (file, offset);
  434. #ifndef SEQUENT_ADDRESS_BUG
  435.       putc ('(', file);
  436.       paren_base_reg_printed = 0;
  437.       if (GET_CODE(addr) == MEM)
  438.         {
  439.           memory_relative = 1;
  440.           output_address (XEXP(addr,0));
  441.           memory_relative = 0;
  442.         }
  443.       else if (GET_CODE(addr) == REG)
  444.         fprintf (file, "%s", reg_names[REGNO(addr)]);
  445.       else
  446.         {
  447.           fprintf(stderr,"Attempt to create an illegal mode\n");
  448.           abort();
  449.         }
  450. #ifdef SEQUENT_BASE_REGS
  451.       if (!paren_base_reg_printed)
  452.         fprintf (file, "(sb)");
  453. #endif
  454.       putc (')', file);
  455. #else /* SEQUENT_ADDRESS_BUG */
  456.       if ((GET_CODE (offset) == SYMBOL_REF
  457.            || GET_CODE (offset) == CONST)
  458.           && GET_CODE (addr) == REG)
  459.         {
  460.           if (reg1) abort ();
  461.           fprintf (file, "[%s:b]", reg_names[REGNO (addr)]);
  462.         }
  463.       else
  464.         {
  465.           putc ('(', file);
  466.           paren_base_reg_printed = 0;
  467. #ifndef SEQUENT_BASE_REGS
  468.           memory_relative = 1;
  469.           output_address (addr);
  470.           memory_relative = 0;
  471. #else
  472.           output_address (addr);
  473.           if (!paren_base_reg_printed)
  474.             fprintf (file, "(sb)");
  475. #endif
  476.           putc (')', file);
  477.         }
  478. #endif /* SEQUENT_ADDRESS_BUG */
  479.       ireg = reg1;
  480.       goto print_index;
  481.     }
  482.       else addr = offset;
  483.       if (reg1 && GET_CODE (reg1) == MULT)
  484.     { breg = reg2; ireg = reg1; }
  485.       else if (reg2 && GET_CODE (reg2) == MULT)
  486.     { breg = reg1; ireg = reg2; }
  487.       else if (reg2 || GET_CODE (addr) == MEM)
  488.     { breg = reg2; ireg = reg1; }
  489.       else
  490.     { breg = reg1; ireg = reg2; }
  491.       if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF)
  492.         {
  493.       int scale;
  494.       if (GET_CODE (ireg) == MULT)
  495.         {
  496.           scale = INTVAL (XEXP (ireg, 1)) >> 1;
  497.           ireg = XEXP (ireg, 0);
  498.         }
  499.       else
  500.         scale = 0;
  501.       PUT_ABSOLUTE_PREFIX(file);
  502.       output_asm_label (addr);
  503.       fprintf (file, "[%s:%c]",
  504.            reg_names[REGNO (ireg)], scales[scale]);
  505.       break;
  506.     }
  507.       if (ireg && breg && offset == const0_rtx)
  508.     /*
  509.       Here we should output rn[rm:scale] instead of
  510.       0(rn)[rm:scale] since it is equivalent and faster. -IWD-
  511.      */
  512.     if (MEM_REG(breg))
  513.       fprintf (file, "0(%s)", reg_names[REGNO (breg)]);
  514.     else
  515.       fprintf (file, "%s", reg_names[REGNO (breg)]);
  516.       else
  517.     {
  518.       if (addr != 0)
  519.         {
  520. /*
  521.           if (ireg != 0 && breg == 0
  522.           && GET_CODE (offset) == CONST_INT)
  523. */
  524.           if (ireg != 0 && breg == 0)
  525.         PUT_ABSOLUTE_PREFIX(file);
  526.           output_addr_const (file, offset);
  527.         }
  528.       if (breg != 0)
  529.         {
  530.           if (GET_CODE (breg) != REG) abort ();
  531. #ifndef SEQUENT_ADDRESS_BUG
  532.           fprintf (file, "(%s)", reg_names[REGNO (breg)]);
  533.           paren_base_reg_printed = -1;
  534. #else
  535.           if (GET_CODE (offset) == SYMBOL_REF || GET_CODE (offset) == CONST)
  536.         {
  537.           if (ireg) abort ();
  538.           fprintf (file, "[%s:b]", reg_names[REGNO (breg)]);
  539.         }
  540.           else
  541.         {
  542.           fprintf (file, "(%s)", reg_names[REGNO (breg)]);
  543.           paren_base_reg_printed = -1;
  544.         }
  545. #endif
  546.         }
  547.     }
  548.   print_index:
  549.       if (ireg != 0)
  550.     {
  551.       int scale;
  552.       if (GET_CODE (ireg) == MULT)
  553.         {
  554.           scale = INTVAL (XEXP (ireg, 1)) >> 1;
  555.           ireg = XEXP (ireg, 0);
  556.         }
  557.       else scale = 0;
  558.       if (GET_CODE (ireg) != REG) abort ();
  559.       fprintf (file, "[%s:%c]",
  560.            reg_names[REGNO (ireg)],
  561.            scales[scale]);
  562.     }
  563.       break;
  564.     default:
  565.       if (!memory_relative)
  566.     PUT_ABSOLUTE_PREFIX(file);
  567.       output_addr_const (file, addr);
  568.       if (memory_relative)
  569.     fprintf(file, "(sb)");
  570.     }
  571. }
  572.  
  573. /* National 32032 shifting is so bad that we can get
  574.    better performance in many common cases by using other
  575.    techniques.  */
  576. char *
  577. output_shift_insn (operands)
  578.      rtx *operands;
  579. {
  580.   if (GET_CODE (operands[2]) == CONST_INT
  581.       && INTVAL (operands[2]) > 0
  582.       && INTVAL (operands[2]) <= 3)
  583.     if (GET_CODE (operands[0]) == REG)
  584.       {
  585.     if (GET_CODE (operands[1]) == REG)
  586.       {
  587.         if (REGNO (operands[0]) == REGNO (operands[1]))
  588.           {
  589.         if (operands[2] == const1_rtx)
  590.           return "addd %0,%0";
  591.         else if (INTVAL (operands[2]) == 2)
  592.           return "addd %0,%0\n\taddd %0,%0";
  593.           }
  594.         if (operands[2] == const1_rtx)
  595.           return "movd %1,%0\n\taddd %0,%0";
  596.  
  597.         operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
  598.         return "addr %a1,%0";
  599.       }
  600.     if (operands[2] == const1_rtx)
  601.       return "movd %1,%0\n\taddd %0,%0";
  602.       }
  603.     else if (GET_CODE (operands[1]) == REG)
  604.       {
  605.     operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
  606.     return "addr %a1,%0";
  607.       }
  608.     else if (INTVAL (operands[2]) == 1
  609.          && GET_CODE (operands[1]) == MEM
  610.          && rtx_equal_p (operands [0], operands[1]))
  611.       {
  612.     rtx temp = XEXP (operands[1], 0);
  613.  
  614.     if (GET_CODE (temp) == REG
  615.         || (GET_CODE (temp) == PLUS
  616.         && GET_CODE (XEXP (temp, 0)) == REG
  617.         && GET_CODE (XEXP (temp, 1)) == CONST_INT))
  618.       return "addd %0,%0";
  619.       }
  620.     else return "ashd %2,%0";
  621.   return "ashd %2,%0";
  622. }
  623.