home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 357_01 / cstar1.exe / G2.C < prev    next >
C/C++ Source or Header  |  1991-06-18  |  76KB  |  3,143 lines

  1. /*
  2.     C* -- Code generation -- Expression routines.
  3.  
  4.     source: g2.c
  5.     started: January 21, 1986
  6.     version:
  7.         February 20, 1987
  8.         March 7, 1989
  9.  
  10.     PUBLIC DOMAIN SOFTWARE
  11.  
  12.     The CSTAR program was placed in    the public domain on June 15, 1991,
  13.     by its author and sole owner,
  14.  
  15.         Edward K. Ream
  16.         1617 Monroe Street
  17.         Madison, WI 53711
  18.         (608) 257-0802
  19.  
  20.     CSTAR may be used for any commercial or non-commercial purpose.
  21.  
  22.     See cstar.h or cstar.c for a DISCLAIMER OF WARRANTIES.
  23. */
  24.  
  25. #include "cstar.h"
  26.  
  27. /*
  28.     NOTE:
  29.  
  30.     added argument on resolve(), sop_assnop, get_?temp, and
  31.     get_temp calls is eventually to be set to R_?? or -R_??
  32.     to serve as a hint to use or to avoid R_?? as a temporary.
  33. */
  34.  
  35. /*
  36.     CAUTION:
  37.  
  38.     Gotchas involving replacement operators and (areg)+ address modes.
  39.  
  40.     The form
  41.     (*p++) += 3;
  42.     is meaningful and is probably valid C.  However, it creates an
  43.     implicit LHS temporary involving p without mentioning p twice.
  44.  
  45.     The form
  46.     (*p++) = *p + 3;
  47.     is undefined as to its effect and we need not worry too much
  48.     about it, although it probably ought to do the side effect
  49.     exactly once.
  50.  
  51.     In coding replacement operators (ASSN_OP), the following
  52.     considerations apply when a has_effect() mode (areg)+ or -(areg)
  53.     is an operand:
  54.  
  55.     - The operator probably ought to do the side effect and not
  56.     return a node that still contains it.  If OPT_NONEED is in
  57.     effect it certainly ought to do it.
  58.  
  59.     - The operator had better not do the side effect and return a
  60.     node that still contains it.
  61.  
  62.     - The operator had better not do the side effect more than once.
  63.  
  64.     - The operator had better discard the node once a POST side effect
  65.     is done, since the node then no longer represents a good lvalue.
  66. */
  67.  
  68. /*
  69.     As much as possible, create and alter loc_nodes through
  70.     locn_chmod(), locn_reg(), etc. to facilitate future efforts
  71.     to limit proliferation by management of a set of commonly used
  72.     nodes.  WARNING: the manager will have to take care of types on
  73.     the s_stack, and this may severely reduce its utility.
  74.  
  75.     To modify a node, call locn_xdupl() so that a copy will be
  76.     made, e.g. if it is attached to something.  If it is known that
  77.     a copy is needed, call locn_dupl.
  78.  
  79.     To perform additive combination, call x_addpsi(); see x_addpsi()
  80.     for calling conditions!
  81. */
  82.  
  83. /*
  84.     CAUTION:
  85.  
  86.     The evaluation of a general expression involves alternating calls
  87.     to gen_e1 and gen_b1 by each other.  When gen_e1 runs out of
  88.     registers, it pushes a register onto the stack, thus raising
  89.     ss_bot.  Other (unpushed) registers appear as entries lying between
  90.     ss_bot and ss_count.  The assumption that NO TEMPORARY register
  91.     is duplicated between ANY two of these latter entries in any way
  92.     is fairly wired into the code.  For example, a composite
  93.     loc_node is often added up and loaded into a temporary, and that
  94.     temporary is usually drawn from the loc_node itself if that is
  95.     possible.  Such an operation is clearly nonsense if an additional
  96.     reference to that same temporary exists elsewhere in the ss_bot-to-
  97.     ss_count frame.  When an operand is discarded, free_temp() frees
  98.     the temporaries that appear in it; same comment.  The boolean
  99.     and ternary operators need to make the same assumption in order
  100.     to locate a place to save the flags or put the result (respectively)
  101.     in the event that stack restoration occurs.
  102.  
  103.     A set of sufficient conditions guaranteeing the truth of this 
  104.     assumption in practice is:
  105.  
  106.     1. get_temp()/get_dtemp()/get_atemp() does not return any register
  107.        contained within that frame.  This is true by the very intent
  108.        of get_temp.  (Get_temp may return a register that appears
  109.        below ss_bot that was pushed without combination, but that
  110.        doesn't matter, because those registers lie outside the frame.)
  111.  
  112.     2. operators that push without combination (see the exit portion
  113.        of gen_b1(), and sop_ternop()) clean up their own mess.  This
  114.        is the intent of the ss_restore calls at those operators.
  115.  
  116.     3. any operator that pushes more than one item onto the s_stack
  117.        pushes no duplicate temporaries.  If only one item is pushed
  118.        onto the stack, and if the temporaries in that item are
  119.        derived from DISCARDED operands or from get_temp(), then no
  120.        duplication can occur.  If operands are examined, and then
  121.        merely repushed, no duplication will be created that wasn't
  122.        already present.  I.e. some effort will be required in
  123.        order to create a problem.
  124. */
  125.  
  126. /*
  127.     WARNING:
  128.  
  129.     d5 = i + j; generates
  130.         dt = i;
  131.         dt += j;
  132.         d5 = dt;
  133.     rather than
  134.         d5 = i;
  135.         d5 += j;
  136.     since there is as yet no mechanism for passing a lhs temporary,
  137.     nor is there a peephole for removing a construction of this sort.
  138.     It may be that the peephole would be simpler.
  139. */
  140.  
  141. /*
  142.     NOTE: whether to disturb the upper portions of declared registers
  143.     or not is now a compile-time flag.  The choice has to do with
  144.     whether
  145.     mem = (long) d5w;
  146.     should be cast in d5 or cast elsewhere.  Probably in those cases
  147.     where it is critical that it be done elsewhere (e.g. an impending
  148.     X_SWAP) the programmer should use pseudo-ops.  The more rigorous
  149.     option is also available, but note that it often generates
  150.     terrible code.
  151. */
  152.  
  153. /*
  154.     Externally visible routines defined in this file:
  155. */
  156. void        gen_bool    (struct node *p,
  157.                 struct node *true_lab, struct node *false_lab);
  158. void        gen_expr    (struct node *p);
  159. void        gen_a0exp    (struct node *p);
  160. void        gen_d0exp    (struct node *p);
  161. struct node *    gen_dexpr    (struct node *p);
  162. void        gen_bpost    (struct node *p);
  163.  
  164. /* Forward declarations of static functions. */
  165. #define g_bra(p) g_1lab(X_BRA, p);
  166.  
  167. static void    gen_b1    (int must_pop, struct node *p,
  168.             struct node *true_lab, struct node *false_lab);
  169. static struct diop *
  170.         ops_bcc    (struct node *p,
  171.             int utcode, int tcode, int ufcode, int fcode,
  172.             int xutcode, int xtcode, int xufcode, int xfcode);
  173. static struct diop *
  174.         ops_xne    (struct node *p);
  175.  
  176. static void    i_gene1        (void);
  177. static void    gen_e1        (struct node *p);
  178. static unsigned long
  179.         gen_args    (register struct node *arg, int top);
  180. static void    gen_indir    (struct node *p);
  181. static struct node *
  182.         no_effect    (struct node *p);
  183. static unsigned long
  184.         aoffs        (unsigned int size, unsigned int *shift);
  185. void        g_2call        (struct node *loc1, struct node *loc2,
  186.                 char *string);
  187. static void    sop_add        (struct node *p, int op);
  188. static void    sop_adr        (struct node *p);
  189. static void    sop_arrow    (struct node *p);
  190. static void    sop_assnop    (struct node *p, int op, int hint);    
  191. static void    sop_call    (struct node *p);
  192. static void    sop_cast    (struct node *p);
  193. static int    sop_cmp        (struct node *p);
  194. static void    sop_comma    (struct node *p);
  195. static void    sop_dbinop    (struct node *p, int op);
  196. static void    sop_dot        (struct node *p);
  197. static void    sop_logical    (struct node *p, int op);
  198. static void    sop_not        (struct node *p);
  199. static void    sop_relop    (struct node *p, int op);
  200. static void    sop_sep        (struct node *p);
  201. static void    sop_ternop    (struct node *p);
  202. static void    sop_unop    (struct node *p, int op);
  203. static void    sop_ustar    (struct node *p);
  204. static void    sop_ppop    (struct node *p);
  205.  
  206. /*
  207.     Define pointer to the Local Code List (LCL) for arithmetic expressions.
  208. */
  209. static struct code_node * lcl_head;
  210. static struct code_node * lcl_tail;
  211.  
  212. /*
  213.     Access to register parameter, for unsigned extend in casts and
  214.     in pointer addition
  215. */
  216. extern int na_free;
  217. extern int nd_free;
  218. extern int ss_count, ss_forks, ss_bot;
  219.  
  220. /*
  221.     E N T R Y    P O I N T    R O U T I N E S
  222.  
  223.     All access to this module are via these routines:
  224.  
  225.     gen_bpost();    generate post operators of a boolean expression.
  226.  
  227.     gen_bool();    generate code for a boolean expression and branch
  228.             to either of two labels, depending on result.
  229.  
  230.     gen_expr();    generate code for an outer arithmetic expression.
  231.  
  232.     gen_a0exp();    generate code for an arithmetic expression and leave
  233.             the result in a0_loc or d0_loc.
  234.  
  235.     gen_dexpr();    generate code for an arithmetic expression and leave
  236.             the result as a value in a register.
  237.  
  238.     ALL of these directly call
  239.         i_gene1()
  240.  
  241.     ONLY gen_expr() and gen_dexpr() call 
  242.         gen_pp()
  243. */
  244.  
  245. /*
  246.     ENTRY POINT ROUTINE
  247.     Generate code for a boolean expression.
  248. */
  249. void            
  250. gen_bool(struct node *p, struct node *true_lab, struct node *false_lab)
  251. {
  252.     TRACEPB("gen_bool", printf("(%p, %p, %p)\n", 
  253.         p, true_lab, false_lab));
  254.  
  255.     i_gene1();        /* Phase 1 */
  256.  
  257.     TRACEP("gen_bool", printf("\n"); pr_expr(p); printf("\n"););
  258.  
  259.     gen_b1(0, p, true_lab, false_lab);
  260.  
  261.     TICKX("gen_bool");
  262. }
  263.  
  264. /*
  265.     ENTRY POINT ROUTINE
  266.     Generate code for an outer arithmetic expression.
  267.     Nothing is left on the s_stack.
  268. */
  269. void
  270. gen_expr(struct node *p)
  271. {
  272.     TRACEPB("gen_expr",
  273.         printf("(%p)\n", p);
  274.         pr_expr(p); printf("\n"));
  275.  
  276.     if (p == NULL) {
  277.         RETURN_VOID("gen_expr");
  278.     }
  279.     gen_pp(p);        /* Phase 0 */
  280.  
  281.     TRACEP("gen_expr", printf("\n"); pr_expr(p); printf("\n"););
  282.  
  283.     i_gene1();        /* Phase 1 */
  284.     gen_e1(p);
  285.     x_lookat(ss_pop());
  286.  
  287.     TICKX("gen_expr");
  288. }
  289.  
  290. /*
  291.     ENTRY POINT ROUTINE
  292.     Generate code for an outer expression returning a0/d0
  293.  
  294.     This is used for function returns.
  295. */
  296. void
  297. gen_a0exp(struct node *p)
  298. {
  299.     struct node *loc1;
  300.  
  301.     TRACEPB("gen_a0exp", printf("(%p)\n", p));
  302.  
  303.     gen_pp(p);        /* Phase 0 */
  304.     i_gene1();        /* Phase 1 */
  305.     gen_e1(p);
  306.  
  307.     loc1 = resolve(ss_pop());
  308.     if (!is_equiv(loc1, a0_loc)) {
  309.         a0_loc -> n_cltype = p -> n_cltype;
  310.         g_2l1(X_MOVE, loc1, a0_loc);
  311.     }
  312.  
  313.     TICKX("gen_a0exp");
  314. }
  315.  
  316. void
  317. gen_d0exp(struct node *p)
  318. {
  319.     struct node *loc1;
  320.  
  321.     TRACEPB("gen_d0exp", printf("(%p)\n", p));
  322.  
  323.     gen_pp(p);        /* Phase 0 */
  324.     i_gene1();        /* Phase 1 */
  325.     gen_e1(p);
  326.  
  327.     loc1 = resolve(ss_pop());
  328.     if (!is_equiv(loc1, d0_loc)) {
  329.         d0_loc -> n_cltype = p -> n_cltype;
  330.         g_qmove(loc1, d0_loc);
  331.     }
  332.  
  333.     TICKX("gen_d0exp");
  334. }
  335.  
  336. /*
  337.     ENTRY POINT ROUTINE
  338.     Generate code for an outer expression returning a value in
  339.     a D register regardless of type.  The D register may or may
  340.     not be a temporary.
  341.  
  342.     This is used by the switch statement in order to evaluate
  343.     its argument.
  344. */
  345. struct node *
  346. gen_dexpr(struct node *p)
  347. {
  348.     struct node *loc1, *loc3;
  349.  
  350.     TRACEPB("gen_dexpr", printf("(%p)\n", p));
  351.  
  352.     gen_pp(p);        /* Phase 0 */
  353.     i_gene1();        /* Phase 1 */
  354.     gen_e1(p);
  355.     loc1 = resolve(ss_pop());
  356.     if (!is_dloc(loc1)) {
  357.         loc3 = get_dtemp();
  358.         g_qmove(loc1, loc3);
  359.         loc3 -> n_cltype = loc1 -> n_cltype;
  360.  
  361.         TRACEP("gen_dexpr",
  362.             printf("return: ");
  363.             pr_loc(loc3); printf("\n"));
  364.  
  365.         RETURN_PTR("gen_dexpr", loc3);
  366.     }
  367.     else {
  368.         TRACEP("gen_dexpr",
  369.             printf("returns: ");
  370.             pr_loc(loc1); printf("\n"));
  371.  
  372.         RETURN_PTR("gen_dexpr", loc1);
  373.     }
  374. }
  375.  
  376. /*
  377.     ENTRY POINT ROUTINE
  378. */
  379. void
  380. gen_bpost(struct node *p)
  381. {
  382.     TRACEPB("gen_bpost", printf("(%p)\n", p));
  383.  
  384.     ;
  385.  
  386.     TICKX("gen_bpost");
  387. }
  388.  
  389. /*
  390.     CAUTION:  NO calls to i_gene1() should appear after this point!
  391. */
  392.  
  393. /*
  394.     Generate code to evaluate a boolean expression and to
  395.     jump to true_lab if true and false_lab if false.
  396.  
  397.     ONLY ONE of true_lab or false_lab should ever be FALL_THROUGH.
  398. */
  399. static void
  400. gen_b1(    int must_pop, struct node *p,
  401.     register struct node *true_lab, register struct node *false_lab)
  402. {
  403.     register int op;
  404.     register struct node * loc;
  405.     struct node *imm_lab;
  406.     register struct diop *ops;
  407.     int ssb_save, sf_save;
  408.  
  409.     TRACEPB("gen_b1", printf("(%d, %p, %p, %p) ", 
  410.         must_pop, p, true_lab, false_lab));
  411.  
  412.     op = p -> n_type;
  413.  
  414.     TRACEP("gen_b1", printf("op: %s\n", ps_tok(op)));
  415.  
  416.     if (p == NULL) {
  417.         /* There is not enough information to generate a branch! */
  418.         RETURN_VOID("gen_b1");
  419.     }
  420.  
  421.     /* operators that recurse simply return immediately */
  422.     switch(op) {
  423.     case NOT_TOK:
  424.         /* just exchange labels */
  425.         gen_b1(must_pop, p -> n_arg1, false_lab, true_lab);
  426.         RETURN_VOID("gen_b1");
  427.  
  428.     case LAND_TOK:
  429.         /* logical and/or creates branch points */
  430.         if (!must_pop) {
  431.             must_pop = 1;
  432.         }
  433.  
  434.         /* logical "and" fails directly to false_lab */
  435.         TRACEP("gen_b1", printf("logical and\n"));
  436.  
  437.         if (false_lab == FALL_THROUGH) {
  438.             /* fix an extra label so it falls through */
  439.             imm_lab = new_clabel();
  440.             gen_b1(must_pop, p -> n_arg1, FALL_THROUGH, imm_lab);
  441.             /* if arg1 is true, fall through to arg2 */
  442.             gen_b1(2, p -> n_arg2, true_lab, false_lab);
  443.             g_label(imm_lab);
  444.         }
  445.         else {
  446.             /* otherwise do what comes naturally */
  447.             gen_b1(must_pop, p -> n_arg1, FALL_THROUGH, false_lab);
  448.             gen_b1(2, p -> n_arg2, true_lab, false_lab);
  449.         }
  450.         RETURN_VOID("gen_b1");
  451.  
  452.     case LOR_TOK:
  453.         if (!must_pop) {
  454.             must_pop = 1;
  455.         }
  456.  
  457.         /* logical "or" succeeds directly to true_lab */
  458.         TRACEP("gen_b1", printf("logical or\n"));
  459.  
  460.         if (true_lab == FALL_THROUGH) {
  461.             /* arrange an extra label so it happens */
  462.             imm_lab = new_clabel();
  463.             gen_b1(must_pop, p -> n_arg1, imm_lab, FALL_THROUGH);
  464.             gen_b1(2, p -> n_arg2, true_lab, false_lab);
  465.             g_label(imm_lab);
  466.         }
  467.         else {
  468.             /* just do what comes naturally */
  469.             gen_b1(must_pop, p -> n_arg1, true_lab, FALL_THROUGH);
  470.             gen_b1(2, p -> n_arg2, true_lab, false_lab);
  471.         }
  472.         RETURN_VOID("gen_b1");
  473.     }
  474.     TRACEP("gen_b1", printf("arithmetical op: %s\n", ps_tok(op)););
  475.     
  476.     /* these generate arithmetical code */
  477.  
  478.     /* 
  479.         The following line gets us a place to put the flags if
  480.         we need to save them while restoring registers, (or if
  481.         we choose to save them during a post-op?); it should
  482.         generate code only in the first test branch--which is always
  483.         executed--and not anywhere else, so that the stack balance
  484.         will be the same at the end of all branches.
  485.  
  486.         This pseudo-reservation of a temp is only needed if we lie
  487.         under a branch point in the current boolean, that is,
  488.         must_pop > 0.
  489.  
  490.         As to how the reservation works, see the note under sop_ternop
  491.     */
  492.     if (must_pop && ss_count > ss_bot) {
  493.         free_temp(loc = get_dtemp());
  494.     }
  495.  
  496.     /* and we only need to actually save and restore in the right
  497.         branches, since the leftmost branch gets generated first
  498.             and is always executed */
  499.     if (must_pop >= 2) {
  500.         ssb_save = ss_bot;
  501.         sf_save = ss_forks;
  502.         ss_forks = ss_count;    /* pre-existing items save-and-restore */
  503.     }
  504.     
  505.     switch (op) {
  506.         /*
  507.             the operators form quasi-rings (no identity),
  508.             with true/false transformation and operand exchange
  509.             transformation as the two operations.
  510.  
  511.             actually, it's exactly an order-2 Rubik's cube!
  512.  
  513.             the true/false alternatives are mutually exclusive
  514.             and exactly cover the comparision possibilities
  515.             (which are of an underlying ternary nature); they
  516.             represent what happens if you exchange true_lab
  517.             with false_lab
  518.  
  519.             the exchange alternatives represent what happens
  520.             if you exchange the operands of the relop. note that
  521.             expressions transformed by changing just the relop
  522.             in this way are not mutually exclusive-- a <= b
  523.             is not mutually exclusive with a >= b.  this
  524.             transformation implements the conversion from a <= b
  525.             to b >= a --or a == b to b == a.
  526.         */
  527.  
  528.     case EQUAL_TOK:
  529.         ops = ops_bcc(p,   
  530.             X_BEQ, X_BEQ, X_BNE, X_BNE,    /* <-> true/false */
  531.             X_BEQ, X_BEQ, X_BNE, X_BNE);    /* exchange */
  532.         break;
  533.     case NE_TOK:
  534.         ops = ops_bcc(p,
  535.             X_BNE, X_BNE, X_BEQ, X_BEQ, 
  536.             X_BNE, X_BNE, X_BEQ, X_BEQ);
  537.         break;
  538.     case LT_TOK:
  539.         /* toks unsigned, signed */
  540.         ops = ops_bcc(p,
  541.             X_BLO, X_BLT, X_BHS, X_BGE,
  542.             X_BHI, X_BGT, X_BLS, X_BLE);
  543.         break;
  544.     case GT_TOK:
  545.         ops = ops_bcc(p,
  546.             X_BHI, X_BGT, X_BLS, X_BLE,    /* <-> true/false */
  547.             X_BLO, X_BLT, X_BHS, X_BGE);    /* exchange */
  548.         break;
  549.     case LE_TOK:
  550.         ops = ops_bcc(p,
  551.             X_BLS, X_BLE, X_BHI, X_BGT,
  552.             X_BHS, X_BGE, X_BLO, X_BLT);
  553.         break;
  554.     case GE_TOK:
  555.         ops = ops_bcc(p,
  556.             X_BHS, X_BGE, X_BLO, X_BLT,
  557.             X_BLS, X_BLE, X_BHI, X_BGT);
  558.         break;
  559.  
  560.     default:
  561.         /* Arithmetic op or ID_TOK */
  562.         ops = ops_xne(p);
  563.     }
  564.     /* WARNING:
  565.         this saves flags even if the popped items generate no
  566.         code...
  567.     */
  568.  
  569.     if (must_pop >= 2) {
  570.         if (ss_bot > ssb_save) {
  571.             g_2(X_MOVE, sr_loc, loc);
  572.             do {
  573.                 (void) ss_restore();
  574.             }
  575.             while (ss_bot > ssb_save); 
  576.             g_2(X_MOVE, loc, ccr_loc);
  577.         }
  578.         ss_forks = sf_save;
  579.     }
  580.  
  581.     /* generate the actual branch */
  582.     if (true_lab != FALL_THROUGH) {
  583.         g_1lab(ops -> o_true, true_lab);
  584.     }
  585.     if (false_lab != FALL_THROUGH) {
  586.         g_1lab(ops -> o_false, false_lab);
  587.     }
  588.  
  589.     TICKX("gen_b1");
  590. }
  591.  
  592. /*
  593.     Evaluate comparison followed by a branch.
  594.  
  595.     This code is really a piece of gen_b1 and shouldn't be used
  596.     elsewhere.
  597. */
  598. static struct diop *
  599. ops_bcc(struct node *p,
  600.     int utcode, int tcode, int ufcode, int fcode,
  601.     int xutcode, int xtcode, int xufcode, int xfcode)
  602. {
  603.     register struct type_node *t;
  604.     static struct diop ops;
  605.  
  606.     TRACEPB("ops_bcc", printf("(%p, %d, %d, %d, %d, %d, %d, %d, %d)\n", 
  607.         p, utcode, tcode, ufcode, fcode, xutcode, xtcode, xufcode, xfcode));
  608.  
  609.     t = p -> n_arg1 -> n_cltype;
  610.     if (t -> t_typtok != INT_TYPE || (t -> t_mclass & UNSIGNED_MOD)) {
  611.         /* unsigned pairs */
  612.         if (!sop_cmp(p)) {
  613.             ops . o_true = utcode;
  614.             ops . o_false = ufcode;
  615.         }
  616.         else {
  617.             /* operands in reverse order */
  618.             ops . o_true = xutcode;    /* exchange */
  619.             ops . o_false = xufcode;
  620.         }
  621.     }
  622.     else {
  623.         /* signed pairs */
  624.         if (!sop_cmp(p)) {
  625.             ops . o_true = tcode;
  626.             ops . o_false = fcode;
  627.         }
  628.         else {
  629.             /* operands in reverse order */
  630.             ops . o_true = xtcode;    /* exchange */
  631.             ops . o_false = xfcode;
  632.         }
  633.     }
  634.     TRACEP("ops_bcc",
  635.         printf("returns <%s, %s>\n",
  636.             xzp_tab[ops.o_true], xzp_tab[ops.o_false]));
  637.  
  638.     RETURN_PTR("ops_bcc", &ops);
  639. }
  640.  
  641. /*
  642.     Test for nonzero.
  643.  
  644.     Generate code for p.  If the result is not a constant,
  645.     generate a test instruction on the result, or otherwise
  646.     generate a flag for sure, and return a
  647.     BNE/BEQ pair for the ensuing code generation to use.
  648.  
  649.     Note that arithmetical operators may or may not set the flags,
  650.     and some operators call functions.
  651.  
  652.     If the result is a constant, return a suitable BRA/BRN
  653.     pair for the ensuing code generation to use.
  654.  
  655.     The idea is to present the peephole with unconditional branches
  656.     as much as possible.
  657. */
  658. static struct diop *
  659. ops_xne(struct node *p)
  660. {
  661.     register struct node *loc1, *loc2;
  662.     extern struct diop ops_true;
  663.     extern struct diop ops_false;
  664.     extern struct diop ops_cond;
  665.  
  666.     /* Bug fix:  loc nodes do not have an n_oflags field !!!! */
  667.  
  668.     TRACEPB("ops_xne", printf("(%p)\n", p));
  669.  
  670.     if (p -> n_type == ID_TOK) {
  671.         gen_e1(p);
  672.         loc1 = ss_pop();
  673.     }
  674.     else {
  675.         p -> n_oflags |= OPT_ZNEED;
  676.         gen_e1(p);    /* resolved and r-stack balanced */
  677.  
  678.         loc1 = ss_pop();
  679.  
  680.         if (p -> n_oflags & OPT_ZFLAG) {
  681.             /* code already generated that sets the flag for sure */
  682.             /* temps have been freed */
  683.             RETURN_PTR("ops_xne", &ops_cond);
  684.         }
  685.     }
  686.  
  687.     if (is_cloc(loc1)) {
  688.         g_help(p, "constant used as conditional");
  689.         RETURN_PTR("ops_xne", (loc1 -> n_const)? &ops_true : &ops_false); 
  690.     }
  691.     else {
  692.         if (is_aloc(loc1)) {
  693.             if (nd_free) {
  694.                 loc2 = get_dtemp();
  695.                 g_2l1(X_MOVE, loc1, loc2);
  696.                         /* move An, An won't set flags */
  697.                 free_temp(loc2);
  698.             }
  699.             else {
  700.                 g_2l2(X_CMPA, zero_loc, loc1);
  701.             }
  702.         }
  703.         else {
  704.             g_1l(X_TST, loc1);
  705.         }
  706.         free_temp(loc1);
  707.     }
  708.     RETURN_PTR("ops_xne", &ops_cond);
  709. }
  710.  
  711.  
  712. /*
  713.     Initialize this phase by clearing the LCL and S stack.
  714. */
  715. static void
  716. i_gene1(void)
  717. {
  718.     /* Initialize the local code list. */
  719.     TICKB("i_gene1");
  720.  
  721.     lcl_head = NULL;
  722.     lcl_tail = NULL;
  723.  
  724.     /* Free all available registers and set up s_stack. */
  725.     free_all();
  726.  
  727.     /* Save the global pointers to the code list. */
  728.     /* WARNING: not ready yet. */
  729.  
  730.     TICKX("i_gene1");
  731. }
  732.  
  733. /*
  734.     Return a no-effect node corresponding to a has_effect node
  735. */
  736. static struct node *
  737. no_effect(register struct node *loc)
  738. {
  739.     TRACEPB("no_effect", printf("(%p)\n", loc));
  740.  
  741.     if (has_effect(loc -> n_mode)) {
  742.         loc = locn_dupl(loc);    /* NOT locn_xdupl!!! */
  743.         loc -> n_mode = EA_MODE;
  744.     }
  745.     else {
  746.         RETURN_PTR("no_effect", loc);
  747.     }
  748.  
  749.     TICKX("no_effect");
  750. }
  751.  
  752. /*
  753.     Generate code from a parse tree.
  754. */
  755. static void
  756. gen_e1(register struct node *p)
  757. {
  758.     struct node *else_lab, *end_lab;
  759.     struct node *loc1;
  760.     register op, i;
  761.  
  762.     TRACEPB("gen_e1",
  763.         printf("(%p)\n", p);
  764.         pr_expr(p); printf("\n"));
  765.  
  766.     op = p -> n_type;
  767.     switch (op) {
  768.  
  769.     case ID_TOK:
  770.         ss_push(p);
  771.         RETURN_VOID("gen_e1");
  772.  
  773.     /* S P E C I A L   F O R M S. */
  774.  
  775.     case CALL_TOK:
  776.         /* Special form. */
  777.         sop_call(p);
  778.         RETURN_VOID("gen_e1");
  779.  
  780.     case COMMA_TOK:
  781.         /* Special form. */
  782.         sop_comma(p);
  783.         RETURN_VOID("gen_e1");
  784.  
  785.     case SEPARATOR_TOK:
  786.         /* Special form. */
  787.         sop_sep(p);
  788.         RETURN_VOID("gen_e1");
  789.  
  790.     case COLON_TOK:
  791.     case QUESTION_TOK:
  792.         /* Special form. */
  793.         sop_ternop(p);
  794.         RETURN_VOID("gen_e1");
  795.  
  796.     case NOT_TOK:
  797.         /* Special form. */
  798.         sop_not(p);
  799.         RETURN_VOID("gen_e1");
  800.  
  801.     case UAND_TOK:
  802.         /* Special form. */
  803.         sop_adr(p);
  804.         RETURN_VOID("gen_e1");
  805.  
  806.     case PLUS_TOK:        
  807.     case MINUS_TOK:
  808.         /* Special form. */
  809.         sop_add(p, op);
  810.         RETURN_VOID("gen_e1");
  811.  
  812.     case LAND_TOK:        
  813.     case LOR_TOK:
  814.         /* Special form. */
  815.         sop_logical(p, op);
  816.         RETURN_VOID("gen_e1");
  817.  
  818.     /* N O N - O R D I N A R Y    O P E R A T O R S. */
  819.     case USTAR_TOK:
  820.         /* Special form. */
  821.         sop_ustar(p);
  822.         RETURN_VOID("gen_e1");
  823.  
  824.     case DOT_TOK:
  825.         gen_e1(p -> n_arg2);
  826.         gen_e1(p -> n_arg1);
  827.         sop_dot(p);
  828.         RETURN_VOID("gen_e1");
  829.  
  830.     case ARROW_TOK:
  831.         gen_e1(p -> n_arg2);
  832.         gen_e1(p -> n_arg1);
  833.         sop_arrow(p);
  834.         RETURN_VOID("gen_e1");
  835.  
  836.     case CAST_TOK:
  837.         gen_e1(p -> n_arg1);
  838.         sop_cast(p);
  839.         RETURN_VOID("gen_e1");
  840.     }
  841.  
  842.     /* O R D I N A R Y    O P E R A T O R S. */
  843.  
  844.     if (is_unop(op)) {
  845.         gen_e1(p -> n_arg1);
  846.         switch(op) {
  847.         case PRE_INC_TOK:
  848.         case PRE_DEC_TOK:
  849.         case POST_INC_TOK:
  850.         case POST_DEC_TOK:
  851.             sop_ppop(p);
  852.             break;
  853.         default:
  854.             sop_unop(p, op);
  855.         }
  856.     }
  857.     else if (is_relop(op)) {
  858.         gen_e1(p -> n_arg2);
  859.         gen_e1(p -> n_arg1);
  860.         sop_relop(p, op);
  861.     }
  862.     else if (is_assnop(op)) {
  863.         /* special form */
  864.         sop_assnop(p, op, 0);
  865.     }
  866.     else if (is_binop(op)) {
  867.         /*
  868.             this sequence has to be maintained in order that
  869.             the stacking sequence work properly for non-
  870.             commutative operators; e.g. the divisor (second
  871.             argument) has to be pushed first so it will be
  872.             properly available if it gets converted to a
  873.             pop_loc. the stacking happens to work the same
  874.             for operators that execute a JSR.
  875.         */
  876.         gen_e1(p -> n_arg2);
  877.         gen_e1(p -> n_arg1);
  878.         sop_dbinop(p, op);
  879.     }
  880.     else {
  881.         g_error(p, "gen_e1: internal: bad operator");
  882.         printf("gen_e1: bad token %d %s\n", op, ps_tok(op));
  883.     }
  884.  
  885.     TICKX("gen_e1");
  886. }
  887.  
  888.  
  889. /*
  890.     S T A C K    M A C H I N E    O P E R A T O R S.
  891.  
  892.     All sop_xxx() routines take their operands on the S stack
  893.     and leave their results, generating machine code in the process.
  894.  
  895.     All sop_xxx() routines are called with the parse node of the intended
  896.     result as a parameter. This is useful for doing type checking.
  897.  
  898.     Most sop_xxx() routines assume that their operands have already been
  899.     evaluated by calling gen_e1(), but several "special forms" such as
  900.     the ternary operator, array references and function calls, must 
  901.     evaluate their arguments in a non-standard manner.
  902. */
  903.  
  904. /*
  905.     Generate code to compute * of an expression.
  906.  
  907.     Note that if result is of type array, nothing happens.
  908.  
  909.     CAUTION: sop_ustar is a special form. it exists only to perform a
  910.          test and do the post++ combination if possible.  if the
  911.          combination is not done, an extra temporary is generated
  912.          to hold the pre-++ value for later use. pre-ops do not
  913.          generate such a temporary, and we have not decided whether
  914.          they should be handled here or in peep_hole.
  915.  
  916.          gen_indir is called by sop_arrow
  917.          gen_indir does not evaluate its argument, which is
  918.          used only in order to attach the type (and might
  919.          be used in a call to g_error)
  920. */
  921. static void 
  922. sop_ustar(register struct node *p)
  923. {
  924.     register unsigned long scale;
  925.     register struct node *q;
  926.     register struct node *locp;
  927.  
  928.     TRACEPB("sop_ustar", printf("(%p)\n", p));
  929.  
  930.     switch (p -> n_arg1 -> n_type) {
  931.     case POST_INC_TOK:
  932.     case PRE_DEC_TOK:
  933.  
  934.         TRACEP("sop_ustar", printf("try special ++/--\n"));
  935.     
  936.         q = p -> n_arg1 -> n_arg1;
  937.         if (q -> n_cltype -> t_link) {
  938.             scale = q -> n_cltype -> t_link -> t_tsize;
  939.         }
  940.         else {
  941.             /* this ought not to happen */
  942.             g_error(p, "sop_ustar: internal: defective pointer type");
  943.             goto normal;
  944.         }
  945.         /*
  946.             NOTE: a similar optimization could occasionally arise
  947.             with ->.  However, the following test would still have
  948.             to be done, and it would rule out all but certain
  949.             rather pathological cases.  We do not recommend
  950.             adding such code to -> since it would, e.g. not
  951.             shorten C-Star by so much as one byte.
  952.         */
  953.         if (scale != p -> n_cltype -> t_tsize ||
  954.                 (scale != 1 && scale != 2 && scale != 4) ) {
  955.  
  956.             TRACEP("sop_ustar",
  957.                 printf("cancel special: scale = %ld\n", scale));
  958.  
  959.             goto normal;
  960.         }
  961.  
  962.         /* generate the location on which the --/++ operates */
  963.         gen_e1(q);
  964.         locp = ss_pop();
  965.         if (is_aloc(locp) && !is_atloc(locp)) {
  966.  
  967.             TRACEP("sop_ustar", printf("use special mode\n"));
  968.  
  969.             locp = locn_chmod(locp, 
  970.                 (p -> n_arg1 -> n_type == POST_INC_TOK)?
  971.                     EAPSI_MODE : EAPRD_MODE);
  972.             locp -> n_cltype = p -> n_cltype;
  973.             ss_push(locp);
  974.         }
  975.         else {
  976.             TRACEP("sop_ustar", printf("cancel special: not an aloc\n"));
  977.             /* do NOT fiddle with type of locp in this branch */
  978.             ss_push(locp);
  979.             sop_ppop(p -> n_arg1);
  980.             gen_indir(p);
  981.         }
  982.         break;
  983.  
  984.     default:
  985.     normal:
  986.         gen_e1(p -> n_arg1);
  987.         gen_indir(p);
  988.     }
  989.     RETURN_VOID("sop_ustar");
  990. }
  991.  
  992. static void
  993. gen_indir(struct node *p)
  994. {
  995.     register struct node *loc1, *loc3;
  996.     register int reg, op;
  997.  
  998.     TRACEPB("gen_indir", printf("(%p)\n", p));
  999.  
  1000.     loc1 = loc3 = ss_pop();
  1001.  
  1002.     if (p -> n_cltype -> t_typtok == ARRAY_TYPE) {
  1003.         /* yet another wierd property of arrays... */
  1004.         /* do nothing */
  1005.     }
  1006.     else if (loc3 -> n_mode == VALUE_MODE) {
  1007.  
  1008.         TRACEP("gen_indir", printf("change to EA_MODE\n"));
  1009.  
  1010.         loc3 = locn_chmod(loc3, EA_MODE);
  1011.         loc3 = resolve(loc3);
  1012.     }
  1013.     else {
  1014.  
  1015.         TRACEP("gen_indir", printf("already EA_MODE\n"));
  1016.  
  1017.         /* must load the ea and set the mode */
  1018.         loc1 = resolve(loc1);
  1019.         if (reg = has_atreg(loc1)) {
  1020.             loc3 = locn_reg(reg);
  1021.         }
  1022.         else {
  1023.             loc3 = get_atemp();
  1024.         }
  1025.         g_2l1(X_MOVE, loc1, loc3);
  1026.         loc3 = locn_chmod(loc3, EA_MODE);
  1027.         free_xtemp(loc1, loc3);
  1028.     }
  1029.     loc3 -> n_cltype = p -> n_cltype;
  1030.     ss_push(loc3);
  1031.  
  1032.     TICKX("gen_indir");
  1033. }
  1034.  
  1035. /*
  1036.     Generate code for assignment operators.
  1037.  
  1038.     NOTE: this always returns a resolved loc_node, since it always
  1039.     computes a value that gets put somewhere.  That loc_node MAY or
  1040.     MAY NOT be the actual lvalue location.
  1041.  
  1042.     CAUTION: see note at file head about has_effect nodes!!!
  1043.  
  1044.     CAUTION: except for addition and sutraction, these operators
  1045.     are unprepared to accept an areg destination.  An atemp destination
  1046.     is of course impossible.  An areg destination will be prohibited
  1047.     by the typing mechanism unless areg ints are permitted.
  1048. */
  1049. #define SPECIAL_L (has_effect(loc1 -> n_mode) && !(p -> n_oflags & OPT_NONEED))
  1050.  
  1051. static void
  1052. sop_assnop(struct node *p, int op, int hint)
  1053. {
  1054.     register struct node *loc1, *loc2, *loc3, *loc4;
  1055.     register int x_op, mod;
  1056.  
  1057.     TRACEPB("sop_assnop",
  1058.         printf("(%p, %d = %s, %d)\n", p, op, ps_tok(op), hint));
  1059.  
  1060.     gen_e1(p -> n_arg2);
  1061.     loc2 = resolve(ss_pop());
  1062.                  /* we know we need a real source value */
  1063.     ss_push(loc2);
  1064.  
  1065.     gen_e1(p -> n_arg1);
  1066.     loc1 = resolve(ss_pop());        /* destination */
  1067.     loc2 = ss_pop();
  1068.  
  1069.     if (!is_storloc(loc1)) {
  1070.         g_error(p, "sop_assnop: bad destination");
  1071.         ss_push(loc1);
  1072.         RETURN_VOID("sop_assnop");
  1073.     }
  1074.  
  1075.     /* A temporary CANNOT be a valid C-LANGUAGE lvalue!!! */
  1076.     if (is_xtloc(loc1)) {
  1077.         g_error(p, "sop_assnop: destination is temporary!");
  1078.     }
  1079.  
  1080.     switch(op) {
  1081.     case ASSN_TOK: 
  1082.         /* Simple assignment operator, just a move */
  1083.         /* The buck stops here, so it's not quite so simple */
  1084.         /* 
  1085.             NOTE: A few further tests, e.g. for constant
  1086.             source, are possible.  Using a constant source
  1087.             may or may not pay if a temporary is available.
  1088.  
  1089.             Be aware of using no_effect() judiciously in
  1090.             any added tests.
  1091.         */
  1092.  
  1093.         if (p -> n_oflags & OPT_NONEED) {
  1094.             TRACEP("sop_assnop", printf("simple move\n"));
  1095.             g_qmove(loc2, loc1);
  1096.             /* side effects of loc1 already done... */
  1097.             /* don't let x_lookat do them again... */
  1098.             ss_push(no_effect(loc1));
  1099.             free_temp(loc2);
  1100.         }
  1101.         else {
  1102.             /* first try to pass on a register lvalue */
  1103.             if (is_xloc(loc1)) {
  1104.                 /* loc1 is of course not a temporary */
  1105.                 g_qmove(loc2, loc1);
  1106.                 ss_push(loc1);
  1107.                 free_temp(loc2);
  1108.             }
  1109.             else if (is_xloc(loc2)) {
  1110.                 g_2l2(X_MOVE, loc2, loc1);
  1111.                 ss_push(loc2);
  1112.                 loc2 -> n_cltype = p -> n_cltype;
  1113.                 free_temp(loc1);
  1114.             }
  1115.             /* otherwise pass thru a temporary if there is one */
  1116.             else {
  1117.                 if(
  1118.                 ((p->n_type == INT_TYPE)? nd_free : na_free)
  1119.                 ||
  1120.                 has_effect(loc1 -> n_mode)
  1121.                 ||
  1122.                 has_effect(loc2 -> n_mode)
  1123.                 ) {
  1124.                     ss_push(loc2);
  1125.                     loc3 = get_temp(loc1);
  1126.                     loc2 = ss_pop();
  1127.                     g_qmove(loc2, loc3);
  1128.                     g_2l2(X_MOVE, loc3, loc1);
  1129.                     loc3 -> n_cltype = p -> n_cltype;
  1130.                     ss_push(loc3);    
  1131.                     free_temp(loc1);
  1132.                     free_temp(loc2);
  1133.                 }
  1134.                 else {
  1135.                     g_qmove(loc2, loc1);
  1136.                     ss_push(loc1);
  1137.                     free_xtemp(loc2, loc1);
  1138.                 }
  1139.             }
  1140.         }
  1141.         RETURN_VOID("sop_assnop");
  1142.  
  1143.     case PLUS_ASSN_TOK:
  1144.         x_op = X_ADD;
  1145.         goto addop;
  1146.  
  1147.     case MINUS_ASSN_TOK:
  1148.         x_op = X_SUB;
  1149.  
  1150.     addop:
  1151.         if (p -> n_cltype -> t_typtok != INT_TYPE) {
  1152.             goto ptrop;
  1153.         }
  1154.         TRACEP("sop_assnop", printf("integer add/subtract\n"));
  1155.  
  1156.         /* loc1 is the destination */
  1157.         /* these ops have parallel widths */
  1158.         if (is_xloc(loc1)) {
  1159.             /* SPECIAL_L cannot be true */
  1160.             g_2l2(x_op, loc2, loc1);
  1161.         }
  1162.         else if ((is_dloc(loc2) || is_cloc(loc2) )) {
  1163.             if (SPECIAL_L) {
  1164.                 g_2l2(x_op, loc2, no_effect(loc1));
  1165.             }
  1166.             else {
  1167.                 g_2l2(x_op, loc2, loc1);
  1168.             }
  1169.         }
  1170.         else {
  1171.             /* operation won't fly without temporary */
  1172.             loc3 = get_dtemp();
  1173.             loc3 -> n_cltype = p -> n_cltype;
  1174.  
  1175.             g_2l1(X_MOVE, loc2, loc3);
  1176.             if (SPECIAL_L) {
  1177.                 g_2l2(x_op, loc3, no_effect(loc1)); 
  1178.             }
  1179.             else {
  1180.                 g_2l2(x_op, loc3, loc1); 
  1181.             }
  1182.             free_temp(loc3);
  1183.         }
  1184.         ss_push(loc1);
  1185.         free_temp(loc2);
  1186.         RETURN_VOID("sop_assnop");
  1187.  
  1188.     /* pointer version */
  1189.     ptrop:
  1190.         /* CAUTION: these tests assume pointers are LONG */
  1191.         TRACEP("sop_assnop", printf("pointer destination\n"));
  1192.         loc2 = x_scale(loc2, loc1 -> n_cltype -> t_link -> t_tsize);
  1193.         if (is_aloc(loc1)) {
  1194.         }
  1195.         else if (is_atloc(loc2) && x_op == X_ADD) {
  1196.             /* cannot add areg to memory */
  1197.             /* SHORTCUT */
  1198.             /* ABELIAN */
  1199.             g_2l1(X_ADD, no_effect(loc1), loc2);
  1200.             g_2l2(X_MOVE, loc2, loc1);
  1201.             ss_push(loc2);
  1202.             free_temp(loc1);
  1203.             RETURN_VOID("sop_assnop");
  1204.         }
  1205.         /* all entries now have !is_aloc(loc1) true, and must therefore
  1206.             ensure ensure a long loc2 prior to the addition */
  1207. #if EXCESSLENOK
  1208.         else if (is_dloc(loc2)) {
  1209.             if (loc2 -> n_cltype == int_type) {
  1210.                 loc2 -> n_cltype = long_type;
  1211.                 g_1l(X_EXT, loc2);
  1212.             }
  1213.         }
  1214. #else
  1215.         else if (is_dloc(loc2) && loc2 -> n_cltype == long_type) {
  1216.         }
  1217.         else if (is_dtloc(loc2) && loc2 -> n_cltype == int_type) {
  1218.             /* must make it long */
  1219.             loc2 -> n_cltype = long_type;
  1220.             g_1l(X_EXT, loc2);
  1221.         }
  1222. #endif
  1223.         else if (is_cloc(loc2)) {
  1224.             /* constant added to non-areg ptr must be long */
  1225.             loc2 -> n_cltype = long_type;
  1226.         }
  1227.         else {
  1228.             /* NOTE: an areg can't be added to an EA */
  1229.             /* that's why we don't get an atemp */
  1230.             ss_push(loc2);
  1231.             loc3 = get_dtemp();
  1232.             loc2 = ss_pop();
  1233.             loc3 -> n_cltype = long_type;
  1234.             g_2l1(X_MOVE, loc2, loc3);
  1235.             if (loc2 -> n_cltype != long_type) {
  1236.                 g_1l(X_EXT, loc3);
  1237.             }
  1238.             if (SPECIAL_L) {
  1239.                 g_2l2(x_op, loc3, no_effect(loc1));
  1240.             }
  1241.             else {
  1242.                 g_2l2(x_op, loc3, loc1);
  1243.             }
  1244.             free_temp(loc2);
  1245.             free_temp(loc3);
  1246.             ss_push(loc1);
  1247.             RETURN_VOID("sop_assnop");
  1248.         }
  1249.         /* perform the op by the type of loc2 (sic) */
  1250.         if (SPECIAL_L) {
  1251.             g_2l1(x_op, loc2, no_effect(loc1));
  1252.         }
  1253.         else {
  1254.             g_2l1(x_op, loc2, loc1);
  1255.         }
  1256.         ss_push(loc1);
  1257.         free_temp(loc2);
  1258.         RETURN_VOID("sop_assnop");
  1259.  
  1260.     case AND_ASSN_TOK:
  1261.         x_op = X_AND;
  1262.         goto genop;
  1263.  
  1264.     case OR_ASSN_TOK:    
  1265.         x_op = X_OR;
  1266.  
  1267.     genop:
  1268.         /* general ops do not allow areg source or dest */
  1269.  
  1270.         /* loc1 is the destination */
  1271.         if (is_dloc(loc1)) {
  1272.             /* SPECIAL_L is impossible */
  1273.             g_2l2(x_op, loc2, loc1);
  1274.             ss_push(loc1);
  1275.             free_temp(loc2);
  1276.         }
  1277.         else if (!is_aloc(loc1) && (is_dloc(loc2) || is_cloc(loc2) )) {
  1278.             if (SPECIAL_L) {
  1279.                 g_2l2(x_op, loc2, no_effect(loc1));
  1280.             }
  1281.             else {
  1282.                 g_2l2(x_op, loc2, loc1);
  1283.             }
  1284.         }
  1285.         else {
  1286.             loc3 = get_dtemp();
  1287.             loc3 -> n_cltype = p -> n_cltype;
  1288.  
  1289.             g_2l1(X_MOVE, loc2, loc3);
  1290.             if (SPECIAL_L) {
  1291.                 g_2l2(x_op, loc3, no_effect(loc1)); 
  1292.             }
  1293.             else {
  1294.                 g_2l2(x_op, loc3, loc1); 
  1295.             }
  1296.             free_temp(loc3);
  1297.         }
  1298.         free_temp(loc2);
  1299.         ss_push(loc1);
  1300.         RETURN_VOID("sop_assnop");
  1301.  
  1302.     case STAR_ASSN_TOK:
  1303.         /*
  1304.             destination of STAR, MOD, and DIV always ends up in
  1305.             a dreg, because of the hardware or the function call.
  1306.  
  1307.             so we always return that dreg as the result, and
  1308.             SPECIAL_L is never tested since the result is
  1309.             always valid.  we use no_effect to ensure that
  1310.             the first of two accesses to the lvalue does not
  1311.             cause side effects.
  1312.         */
  1313.         mod = loc1 -> n_cltype -> t_mclass;
  1314.         if (mod & UNSIGNED_MOD) {
  1315.             x_op = X_MULU;
  1316.         }
  1317.         else {
  1318.             x_op = X_MULS;
  1319.         }
  1320.         if (mod & LONG_MOD) {
  1321.             /* SHORTCUT */
  1322.             g_2call(no_effect(loc1), loc2,
  1323.                 (mod & UNSIGNED_MOD)? "lmulu" : "lmul");
  1324.             loc3 = d0_loc;
  1325.             loc3 -> n_cltype = p -> n_cltype;
  1326.             g_2l1(X_MOVE, d0_loc, loc1);
  1327.             ss_push(loc3); /* sic */
  1328.             RETURN_VOID("sop_assnop");
  1329.         }
  1330.         /* loc1 is the destination */
  1331. #if EXCESSLENOK 
  1332.         if (is_dloc(loc1)) {
  1333. #else
  1334.         if (is_dtloc(loc1)) {
  1335. #endif
  1336.             g_2(x_op, loc2, loc1);
  1337.             ss_push(loc1);
  1338.             free_temp(loc2);
  1339.         }
  1340.         else if (is_dtloc(loc2)) {
  1341.             g_2(x_op, no_effect(loc1), loc2);
  1342.             g_2l2(X_MOVE, loc2, loc1);
  1343.             ss_push(loc2);
  1344.             free_temp(loc1);
  1345.         }
  1346.         else {
  1347.             loc3 = get_dtemp();
  1348.             loc3 -> n_cltype = p -> n_cltype;
  1349.  
  1350.             g_2l1(X_MOVE, no_effect(loc1), loc3);
  1351.             g_2(x_op, loc2, loc3); 
  1352.             g_2l1(X_MOVE, loc3, loc1);
  1353.             ss_push(loc3);
  1354.             free_temp(loc1);
  1355.             free_temp(loc2);
  1356.         }
  1357.         RETURN_VOID("sop_assnop");
  1358.  
  1359.     case DIV_ASSN_TOK:
  1360.         mod = loc1 -> n_cltype -> t_mclass;
  1361.         if (mod & UNSIGNED_MOD) {
  1362.             x_op = X_DIVU;
  1363.         }
  1364.         else {
  1365.             x_op = X_DIVS;
  1366.         }
  1367.         if (mod & LONG_MOD) {
  1368.             /* SHORTCUT */
  1369.             g_2call(no_effect(loc1), loc2,
  1370.                 (mod & UNSIGNED_MOD)? "ldivu" : "ldiv");
  1371.             loc3 = d0_loc;
  1372.             loc3 -> n_cltype = p -> n_cltype;
  1373.             g_2l1(X_MOVE, d0_loc, loc1);
  1374.             ss_push(loc3); /* sic */
  1375.             RETURN_VOID("sop_assnop");
  1376.         }
  1377.         else if (mod & CHAR_MOD) {
  1378.             if (!is_cloc(loc2)) {
  1379.                 loc2 = x_cast(loc2, 1, mod, 2, EXCESSLENOK);
  1380.             }
  1381.         }
  1382.  
  1383.         /* loc1 is the intended destination */
  1384.         /* x_cast always returns a dreg */
  1385.         loc3 = x_cast(no_effect(loc1), mlen(loc1), mod, 4, EXCESSLENOK);
  1386.         loc3 -> n_cltype = p -> n_cltype;
  1387.         g_2(x_op, loc2, loc3); 
  1388.         if (!is_equiv(loc1, loc3)) {
  1389.             /* since x_cast always returns a dreg, any has_effect()
  1390.                version of loc1 cannot match loc3, so the side
  1391.                effects always get done here: */
  1392.             g_2l1(X_MOVE, loc3, loc1);
  1393.         }
  1394.         ss_push(loc3);
  1395.         free_temp(loc1);
  1396.         free_temp(loc2);
  1397.         RETURN_VOID("sop_assnop");
  1398.  
  1399.  
  1400.     case MOD_ASSN_TOK:
  1401.         mod = loc1 -> n_cltype -> t_mclass;
  1402.         if (mod & UNSIGNED_MOD) {
  1403.             x_op = X_DIVU;
  1404.         }
  1405.         else {
  1406.             x_op = X_DIVS;
  1407.         }
  1408.         if (mod & LONG_MOD) {
  1409.             /* SHORTCUT */
  1410.             g_2call(no_effect(loc1), loc2,
  1411.                 (mod & UNSIGNED_MOD)? "lremu" : "lrem");
  1412.             loc3 = d0_loc;
  1413.             loc3 -> n_cltype = p -> n_cltype;
  1414.             g_2l1(X_MOVE, d0_loc, loc1);
  1415.             ss_push(loc3); /* sic */
  1416.             RETURN_VOID("sop_assnop");
  1417.         }
  1418.         else if (mod & CHAR_MOD) {
  1419.             if (!is_cloc(loc2)) {
  1420.                 loc2 = x_cast(loc2, 1, mod, 2, EXCESSLENOK);
  1421.             }
  1422.         }
  1423.  
  1424.         loc3 = x_cast(no_effect(loc1), mlen(loc1), mod, 4, EXCESSLENOK);
  1425.         loc3 -> n_cltype = p -> n_cltype;
  1426.         g_2(x_op, loc2, loc3); 
  1427.         g_1(X_SWAP, loc3);
  1428.         if (!is_equiv(loc1, loc3)) {
  1429.             g_2l1(X_MOVE, loc3, loc1);
  1430.         }
  1431.         ss_push(loc3);
  1432.         free_temp(loc1);
  1433.         free_temp(loc2);
  1434.         RETURN_VOID("sop_assnop");
  1435.  
  1436.  
  1437.     case LSHIFT_ASSN_TOK:
  1438.         x_op = X_ASL;
  1439.         goto shift;
  1440.  
  1441.     case RSHIFT_ASSN_TOK:
  1442.         if (loc1 -> n_cltype -> t_mclass & UNSIGNED_MOD) {
  1443.             x_op = X_LSR;
  1444.         }
  1445.         else {
  1446.             x_op = X_ASR;
  1447.         }
  1448.     shift:
  1449.         /* loc1 is the destination */
  1450.         if (is_cloc(loc2) && !SPECIAL_L && !loc2 -> n_cid &&
  1451.                 loc2 -> n_const >= 0 && loc2 -> n_const <= 8) {
  1452.             if (loc2 -> n_const <= 1 && mlen(loc1) == 2) {
  1453.                 if (loc2 -> n_const) {
  1454.                     /* shift once */
  1455.                     g_1l(x_op, loc1);
  1456.                 }
  1457.                 /* else do nothing */
  1458.                 ss_push(loc1);
  1459.                 RETURN_VOID("sop_assnop");
  1460.             }
  1461.             loc4 = loc2;
  1462.         }
  1463.         else if (is_dloc(loc2)) {
  1464.             loc4 = loc2;
  1465.         }
  1466.         else {
  1467.             loc4 = get_dtemp();
  1468.             g_2l1(X_MOVE, loc2, loc4);
  1469.             free_temp(loc2);
  1470.         }
  1471.  
  1472.         /* operate on loc1 */
  1473.         if (is_dloc(loc1)) {
  1474.             g_2l2(x_op, loc4, loc1);
  1475.             ss_push(loc1);
  1476.         }
  1477.         else {
  1478.             loc3 = get_dtemp();
  1479.             loc3 -> n_cltype = p -> n_cltype;
  1480.             g_2l1(X_MOVE, no_effect(loc1), loc3);
  1481.             g_2l2(x_op, loc4, loc3);
  1482.             g_2l2(X_MOVE, loc3, loc1);
  1483.             ss_push(loc3);
  1484.         }
  1485.         free_temp(loc4);
  1486.         RETURN_VOID("sop_assnop");
  1487.  
  1488.  
  1489.     case XOR_ASSN_TOK:
  1490.         /* machine SOURCE must be dreg */
  1491.         if (is_dloc(loc2)) {
  1492.             g_2l2(X_EOR, loc2, no_effect(loc1));
  1493.         }
  1494.         else {
  1495.             loc3 = get_dtemp();
  1496.             loc3 -> n_cltype = p -> n_cltype;
  1497.             g_2l1(X_MOVE, loc2, loc3);
  1498.             g_2l2(X_EOR, loc3, no_effect(loc1));
  1499.             free_temp(loc3);
  1500.         }
  1501.         /* result must be taken from loc1 */
  1502.         ss_push(loc1);
  1503.         free_xtemp(loc2, loc1);
  1504.         RETURN_VOID("sop_assnop");
  1505.  
  1506.     default:
  1507.         g_error(NULL, "sop_assnop: shouldn't happen");
  1508.         printf("sop_assnop: bad op is %d %s\n", op, ps_tok(op));
  1509.         ss_push(loc1);
  1510.     }
  1511.     RETURN_VOID("sop_assnop");
  1512. }
  1513.  
  1514. /*
  1515.     generate two-argument call for a d0 function
  1516.     args are int or long size, see note in function
  1517.  
  1518.     loc2 must be the FIRST argument to actually be generated
  1519.     so that it will lie deeper on the s_stack, and therefore on
  1520.     the physical stack; if loc1 is pop_loc, than loc2 had better
  1521.     be pop_loc--but if loc1 is not pop_loc, loc2 may or may not be so
  1522.  
  1523.     the function-call order (last-to-first) mimics the instruction
  1524.     order insofar as our customary stack usage is concerned
  1525. */
  1526. void
  1527. g_2call(struct node *loc1, struct node *loc2, char *string)
  1528. {
  1529.     register int c_1arg;
  1530.     register struct node *lab;
  1531.  
  1532.     /* push registers EXCEPT those containing loc1 and loc2 */
  1533.     /* loc1 and loc2 will then be pushed last */
  1534.  
  1535.     TRACEPB("g_2call", printf("(%p, %p, %s)\n", 
  1536.         loc1, loc2, string));
  1537.  
  1538.     force_free(R_D0);
  1539.     push_scratch();
  1540.  
  1541.     if (ss_bot) {
  1542.         c_1arg = FALSE;
  1543.     }
  1544.     else {
  1545.         c_1arg = call_1arg;
  1546.     }
  1547.  
  1548.     if (is_equiv(loc1, pop_loc)) {
  1549.         if (is_equiv(loc2, pop_loc)) {
  1550.             c_1arg = FALSE;
  1551.         }
  1552.         else {
  1553.             fatal("g_2call: push out of sequence");
  1554.         }
  1555.     }
  1556.     else {
  1557.         if (is_equiv(loc2, pop_loc)) {
  1558.             c_1arg = FALSE;
  1559.         }
  1560.         else {
  1561.             g_2l1(X_MOVE, loc2, c_1arg? nopush_loc : push_loc);
  1562.         }
  1563.         g_2l1(X_MOVE, loc1, push_loc);
  1564.     }
  1565.     free_temp(loc2);
  1566.     free_temp(loc1);
  1567.     lab = new_culabel(string);
  1568.     lab -> c_labnum = 0;
  1569.     g_1lab(X_JSR, lab);
  1570.     (void) alloc_reg(R_D0);
  1571.     loc1 = locn_xconst(c_1arg? 4L : 8L);
  1572.     loc1 -> n_cltype = long_type;
  1573.     g_2l1(X_ADDQ, loc1, a7_loc);
  1574.  
  1575.     TICKX("g_2call");
  1576. }
  1577.  
  1578. /*
  1579.     alter shift for byte access, and return a commensurate address offset
  1580.     this is used for generating BTST type instructions
  1581. */
  1582. static unsigned long
  1583. aoffs(unsigned int size, unsigned int *shift)
  1584. {
  1585.     register int o;
  1586.  
  1587.     TRACEPB("aoffs", printf("(%u, %u)\n", size, shift));
  1588.  
  1589.     o = (int) (size - (*shift >> 3) - 1);
  1590.     if (o < 0) {
  1591.         o = 0;
  1592.         g_error(NULL, "shift constant too large");
  1593.     }
  1594.     *shift &= 7;
  1595.  
  1596.     RETURN_ULONG("aoffs", (unsigned long)(unsigned) o);
  1597. }
  1598.  
  1599. /*
  1600.     Generate code for ordinary non-assignment binary operator.
  1601.     Direct pointer arguments, e.g. pointer + int, should not
  1602.     appear, as they should have been taken care of by the caller.
  1603.     The results, therefore, always arrive in a D register.
  1604.  
  1605.     CAUTION: heed note at call point concerning evaluation order
  1606.     for arguments.  Also see note at g_2call().
  1607. */
  1608. static void
  1609. sop_dbinop(struct node *p, int op)
  1610. {
  1611.     struct node *loc1, *loc2, *loc3, *locx;
  1612.     register int mod, reg;
  1613.     int shift;
  1614.  
  1615.     TRACEPB("sop_dbinop", printf("(%p, %s)\n", p, ps_tok(op)));
  1616.  
  1617.     /* note on non-abelians: division, e.g. is (loc1 / loc2); etc. */
  1618.     loc1 = resolve(ss_pop());        
  1619.     loc2 = resolve(ss_pop());
  1620.  
  1621.     /* special-case binops, which means many of them */
  1622.     /* these cases either shortcut and exit, or else regularize the
  1623.         op so the following code can handle it */
  1624.     switch(op) {
  1625.     case XOR_TOK:
  1626.         /* EOR requires that the UNCHANGED operand be a dreg */
  1627.         /* SHORTCUT */
  1628.         /* get a place for the result */
  1629.         if (reg = has_dtreg(loc1)) {
  1630.             if (is_dtloc(loc1)) {
  1631.                 loc3 = loc1;
  1632.             }
  1633.             else {
  1634.                 loc3 = locn_reg(reg);
  1635.                 g_2l1(X_MOVE, loc1, loc3);
  1636.                 free_temp(loc1);
  1637.             }
  1638.         }
  1639.         else {
  1640.             ss_push(loc2);
  1641.             ss_push(loc1);
  1642.             loc3 = get_dtemp();
  1643.             loc1 = ss_pop();
  1644.             loc2 = ss_pop();
  1645.             g_qmove(loc1, loc3);
  1646.             free_temp(loc1);
  1647.             /* NOTE: loc3 could be a sort-of tos_loc if no
  1648.                 dtemp is readily at hand */
  1649.         }
  1650.         /* put the unchanged operand into a dreg */
  1651.         if (is_dloc(loc2)) {
  1652.             locx = loc2;
  1653.         }
  1654.         else if (reg = has_dtreg(loc2)) {
  1655.             locx = locn_reg(reg);
  1656.             g_2l1(X_MOVE, loc2, locx);
  1657.         }
  1658.         else {
  1659.             /* do NOT make loc3 available */
  1660.             locx = get_dtemp();
  1661.             g_qmove(loc2, locx);
  1662.         }
  1663.  
  1664.         loc3 -> n_cltype = p -> n_cltype;
  1665.         g_2l2(X_EOR, locx, loc3);
  1666.         ss_push(loc3);
  1667.         free_temp(loc2);
  1668.         RETURN_VOID("sop_dbinop");
  1669.  
  1670.     case STAR_TOK:
  1671.         mod = p -> n_cltype -> t_mclass;
  1672.         if (mod & LONG_MOD) {
  1673.             /* SHORTCUT */
  1674.             g_2call(loc1, loc2,
  1675.                 (mod & UNSIGNED_MOD)? "lmulu" : "lmul");
  1676.             loc3 = d0_loc;
  1677.             loc3 -> n_cltype = p -> n_cltype;
  1678.             ss_push(loc3);
  1679.             RETURN_VOID("sop_dbinop");
  1680.         }
  1681.         else if (mod & CHAR_MOD) {
  1682.             if (!is_cloc(loc2)) {
  1683.                 loc2 = x_cast(loc2, 1, mod, 1, EXCESSLENOK);
  1684.             }
  1685.             loc1 = x_cast(loc1, 1, mod, 1, FALSE);
  1686.             break;
  1687.         }
  1688.         else {
  1689.             break;
  1690.         }
  1691.  
  1692.     case DIV_TOK:
  1693.         mod = p -> n_cltype -> t_mclass;
  1694.         if (mod & LONG_MOD) {
  1695.             /* SHORTCUT */
  1696.             g_2call(loc1, loc2,
  1697.                 (mod & UNSIGNED_MOD)? "ldivu" : "ldiv");
  1698.             loc3 = d0_loc;
  1699.             loc3 -> n_cltype = p -> n_cltype;
  1700.             ss_push(loc3);
  1701.             RETURN_VOID("sop_dbinop");
  1702.         }
  1703.         goto dodiv;
  1704.  
  1705.     case MOD_TOK:
  1706.         mod = p -> n_cltype -> t_mclass;
  1707.         if (mod & LONG_MOD) {
  1708.             /* SHORTCUT */
  1709.             g_2call(loc1, loc2,
  1710.                 (mod & UNSIGNED_MOD)? "lremu" : "lrem");
  1711.             loc3 = d0_loc;
  1712.             loc3 -> n_cltype = p -> n_cltype;
  1713.             ss_push(loc3);
  1714.             RETURN_VOID("sop_dbinop");
  1715.         }
  1716.         /* FALLTHROUGH */
  1717.  
  1718.     dodiv:
  1719.         if (mod & CHAR_MOD) {
  1720.             if (!is_cloc(loc2)) {
  1721.                 loc2 = x_cast(loc2, 1, mod, 2, EXCESSLENOK);
  1722.             }
  1723.             ss_push(loc2);
  1724.             loc1 = x_cast(loc1, 1, mod, 4, FALSE);
  1725.             loc2 = ss_pop();
  1726.         }
  1727.         else {
  1728.             ss_push(loc2);
  1729.             loc1 = x_cast(loc1, 2, mod, 4, FALSE);
  1730.             loc2 = ss_pop();
  1731.         }
  1732.         break;
  1733.  
  1734.     case AND_TOK:
  1735.         if (p -> n_oflags & OPT_ZNEED) {
  1736.             if (
  1737.                 is_cloc(loc1) &&
  1738.                 (shift = x_shift(loc1 -> n_const)) >= 0 &&
  1739.                 !loc1 -> n_cid
  1740.                                 ) {
  1741.                 if (is_dloc(loc2)) {
  1742.                 }
  1743.                 else if (loc2 -> n_mode == EA_MODE) {
  1744.                     loc2 = locn_xdupl(loc2);
  1745.                     loc2 -> n_const += (long)
  1746.                         aoffs(
  1747.                         (unsigned) mlen(loc2),
  1748.                         (unsigned *) &shift);
  1749.                 }
  1750.                 else {
  1751.                     break;
  1752.                 }
  1753.  
  1754.                 g_2(X_BTST, locn_xconst((long)shift), loc2);
  1755.                 p -> n_oflags |= OPT_ZFLAG;
  1756.                 ss_push(loc1);
  1757.                 free_temp(loc2);
  1758.                 RETURN_VOID("sop_dbinop");
  1759.             }
  1760.             else if (
  1761.                 is_cloc(loc2) &&
  1762.                 (shift = x_shift(loc2 -> n_const)) >= 0 &&
  1763.                 !loc2 -> n_cid
  1764.                                 ) {
  1765.                 if (is_dloc(loc1)) {
  1766.                 }
  1767.                 else if (loc1 -> n_mode == EA_MODE) {
  1768.                     loc1 = locn_xdupl(loc1);
  1769.                     loc1 -> n_const += (long)
  1770.                         aoffs(
  1771.                         (unsigned) mlen(loc1),
  1772.                         (unsigned *) &shift);
  1773.                 }
  1774.                 else {
  1775.                     break;
  1776.                 }
  1777.  
  1778.                 g_2(X_BTST, locn_xconst((long)shift), loc1);
  1779.                 p -> n_oflags |= OPT_ZFLAG;
  1780.                 ss_push(loc2);
  1781.                 free_temp(loc1);
  1782.                 RETURN_VOID("sop_dbinop");
  1783.             }
  1784.         }
  1785.         break;
  1786.     }
  1787.  
  1788.     /* regular binary operators, meaning op <ea>, dn */
  1789.  
  1790.     /* make the destination a dtemp if it isn't already */
  1791.     if (reg = has_dtreg(loc1)) {
  1792.         if (is_dtloc(loc1)) {
  1793.             loc3 = loc1;
  1794.         }
  1795.         else {
  1796.             loc3 = locn_reg(reg);
  1797.             g_2l1(X_MOVE, loc1, loc3);
  1798.             free_temp(loc1);
  1799.         }
  1800.     }
  1801.     else if (is_abelian(op) && (reg = has_dtreg(loc2)) ) {
  1802.         if (is_dtloc(loc2)) {
  1803.             loc3 = loc2;
  1804.             loc2 = loc1;
  1805.         }
  1806.         else {
  1807.             loc3 = locn_reg(reg);
  1808.             g_2l1(X_MOVE, loc2, loc3);
  1809.             free_temp(loc2);
  1810.             loc2 = loc1;
  1811.         }
  1812.     }
  1813.     else {
  1814.         /*
  1815.             Pushing loc2 makes it available, if necessary,
  1816.             to get_dtemp.
  1817.         */
  1818.         ss_push(loc2);
  1819.         loc3 = get_dtemp();
  1820.         loc2 = ss_pop();
  1821.         g_qmove(loc1, loc3);
  1822.         free_temp(loc1);
  1823.     }
  1824.     loc3 -> n_cltype = p -> n_cltype;
  1825.  
  1826.     /* CAUTION: do not repush anything from abelian operators; operands
  1827.         may be flipped, so that s_stack will become a mess */
  1828.  
  1829.     /* CAUTION: in certain cases where loc2 is a constant, its type
  1830.         is wrong here */
  1831.  
  1832.     switch(op) {
  1833.     case PLUS_TOK:        g_2l2(X_ADD, loc2, loc3);    break;
  1834.     case MINUS_TOK:        g_2l2(X_SUB, loc2, loc3);    break;
  1835.     case AND_TOK:        g_2l2(X_AND, loc2, loc3);    break;
  1836.     case OR_TOK:        g_2l2(X_OR,  loc2, loc3);    break;
  1837.  
  1838.     case STAR_TOK:
  1839.         g_2((mod & UNSIGNED_MOD)? X_MULU : X_MULS, loc2, loc3);
  1840.         break;
  1841.     case DIV_TOK:
  1842.         g_2((mod & UNSIGNED_MOD)? X_DIVU : X_DIVS, loc2, loc3);
  1843.         break;
  1844.     case MOD_TOK:
  1845.         g_2((mod & UNSIGNED_MOD)? X_DIVU : X_DIVS, loc2, loc3);
  1846.         g_1(X_SWAP, loc3);
  1847.         break;
  1848.     case LSHIFT_TOK:
  1849.         if (is_dloc(loc2)) {
  1850.         }
  1851.         else if (is_cloc(loc2) && !loc2 -> n_cid &&
  1852.                 loc2 -> n_const >= 0 && loc2 -> n_const <= 8) {
  1853.         }
  1854.         else {
  1855.             loc1 = get_dtemp();    /* requires TWO temps */
  1856.             g_2l1(X_MOVE, loc2, loc1);
  1857.             free_temp(loc2);
  1858.             loc2 = loc1;
  1859.         }
  1860.         g_2l2(X_ASL, loc2, loc3);
  1861.         break;
  1862.     case RSHIFT_TOK:
  1863.         if (is_dloc(loc2)) {
  1864.         }
  1865.         else if (is_cloc(loc2) && !loc2 -> n_cid &&
  1866.                 loc2 -> n_const >= 0 && loc2 -> n_const <= 8) {
  1867.         }
  1868.         else {
  1869.             loc1 = get_dtemp();    /* requires TWO temps */
  1870.             g_2l1(X_MOVE, loc2, loc1);
  1871.             free_temp(loc2);
  1872.             loc2 = loc1;
  1873.         }
  1874.         g_2((mod & UNSIGNED_MOD)? X_LSR : X_ASR, loc2, loc3);
  1875.         break;
  1876.     default:
  1877.         g_error(NULL, "sop_dbinop: shouldn't happen");
  1878.         printf("sop_dbinop: bad op is %d %s\n", op, ps_tok(op));
  1879.     }
  1880.     free_xtemp(loc2, loc3);
  1881.     ss_push(loc3);    /* no physical push */
  1882.  
  1883.     TICKX("sop_dbinop");
  1884. }
  1885.  
  1886. /*
  1887.     Generate code for a cast operator.
  1888.  
  1889.     Compare the C type of the subtree with the C type of the root.
  1890.  
  1891.     Code is generated for widening casts and to move objects that
  1892.     can't be cast in place; e.g. a byte object can't be in an A
  1893.     register.
  1894.  
  1895.     CAUTION:
  1896.     Narrowing casts are NOT to return dual-register value nodes,
  1897.     since x_resolve(), x_sspush(), and so on assume that the first
  1898.     entry in a dual node is long.  See notes at head of x2.c.
  1899. */
  1900. static void
  1901. sop_cast(register struct node *p)
  1902. {
  1903.     struct node *locx, *locy;
  1904.     register struct node *loc1, *loc3;
  1905.     register struct type_node *t1, *t3;
  1906.     register int len1, len3;
  1907.     register int ptr1, ptr3;
  1908.     int reg, in_place, imod1;
  1909.  
  1910.     /* the first part selects what to do */
  1911.  
  1912.     TRACEPB("sop_cast", printf("(%p)\n", p));
  1913.  
  1914.     loc1 = ss_pop();
  1915.  
  1916.     t1 = loc1 -> n_cltype;
  1917.     t3 = p -> n_cltype;
  1918.     imod1 = t1 -> t_mclass;
  1919.  
  1920.     ptr1 = !(t1 -> t_typtok == INT_TYPE); 
  1921.     ptr3 = !(t3 -> t_typtok == INT_TYPE);
  1922.  
  1923.     TRACEP("sop_cast", pr_type(t1); pr_type(t3));
  1924.  
  1925.     if (ptr3) {
  1926.         if (t3 -> t_typtok == VOID_TYPE) {
  1927.             zero_loc -> n_cltype = long_type;
  1928.             ss_push(zero_loc);
  1929.             RETURN_VOID("sop_cast");
  1930.         }
  1931.         if (ptr1) {
  1932.             goto donothing;
  1933.         }
  1934.         else {
  1935.             len1 = (int) t1 -> t_tsize;
  1936.             if (len1 == 4) {
  1937.                 goto donothing;
  1938.             }
  1939.             len3 = 4;
  1940.             goto extend;
  1941.         }
  1942.     }
  1943.     else {
  1944.         len3 = (int)(t3 -> t_tsize);
  1945.         if (ptr1) {
  1946.             len1 = 4;
  1947.             if (len3 = 4) {
  1948.                 goto donothing;
  1949.             }
  1950.             else {
  1951.                 goto shrink;
  1952.             }
  1953.         }
  1954.         len1 = (int)(t1 -> t_tsize);
  1955.         if (len1 == len3) {
  1956.             if (len1 >= 2) {
  1957.                 goto donothing;
  1958.             }
  1959.             else {
  1960.                 goto makesame;
  1961.             }
  1962.         }
  1963.         else if (len1 > len3) {
  1964.             goto shrink;
  1965.         }
  1966.         else {
  1967.             goto extend;
  1968.         }
  1969.     }
  1970.  
  1971. /*
  1972.     the following sections do what was selected
  1973.  
  1974.     rules:
  1975.         they are not to branch into each other except that extend
  1976.         makes one further sub-selection of donothing.
  1977.  
  1978.     excuse for so many goto's:
  1979.         the other options only obfuscate the intent of the code;
  1980.         a switch enumeration adds complexity without clarity;
  1981.         the three implied functions have far too many parameters;
  1982.         replication of the code would be ad absurdum and make it
  1983.         almost impossible to make future alterations cleanly since
  1984.         it would be difficult to tell where they would need to
  1985.         be replicated.
  1986. */
  1987.  
  1988. extend:
  1989.     /*
  1990.         some of this code is highly parallel to, but different from,
  1991.         portions of x_scale
  1992.     */
  1993.     loc1 = resolve(loc1);
  1994.     if (is_cloc(loc1)) {
  1995.         goto donothing;
  1996.     }
  1997.     if (is_atloc(loc1) &&
  1998.         ((imod1 & LONG_MOD) || !(imod1 & (CHAR_MOD | UNSIGNED_MOD)))
  1999.                                     ) {
  2000.         /* anything long or signed in an atreg is 32 bits long already;
  2001.             there's no other way to get it in there, since we
  2002.                 eschew unbalanced EXG manipulations */
  2003.         goto donothing;
  2004.     }
  2005.  
  2006.     if (ptr3 && !ptr1 && (na_free || !nd_free) &&
  2007.                 !(imod1 & (UNSIGNED_MOD | CHAR_MOD))) {
  2008.         /* SHORTCUT via move to A reg */
  2009.         ss_push(loc1);
  2010.         loc3 = get_atemp();
  2011.         loc1 = ss_pop();
  2012.         g_2l1(X_MOVE, loc1, loc3);
  2013.         loc3 -> n_cltype = t3;
  2014.         free_temp(loc1);
  2015.         ss_push(loc3);
  2016.         RETURN_VOID("sop_cast");
  2017.     }
  2018.     if (ptr3 && is_dtloc(loc1) && (imod1 & CHAR_MOD)) {
  2019.         /* partial SHORTCUT via move to A reg */
  2020.         loc3 = get_atemp();
  2021.         loc1 = locn_xdupl(loc1);
  2022.         loc1 -> n_cltype = int_type;
  2023.         if (imod1 & UNSIGNED_MOD) {
  2024.             g_2l2(X_AND, locn_xconst(255L), loc1);
  2025.         }
  2026.         else {
  2027.             g_1l(X_EXT, loc1);
  2028.         }
  2029.         g_2l1(X_MOVE, loc1, loc3);
  2030.         loc3 -> n_cltype = t3;
  2031.         free_temp(loc1);
  2032.         ss_push(loc3);
  2033.         RETURN_VOID("sop_cast");
  2034.     }
  2035.  
  2036.     /* WARNING:
  2037.         the potential to generate an ext.l on a D reg and
  2038.         later move.l to an A reg still exists.  Also, the
  2039.         potential to do in-place an unsigned cast that would
  2040.         better be done with a temporary exists.  These may
  2041.         be detectable with peephole.
  2042.     */
  2043.     loc3 = x_cast(loc1, len1, imod1, len3, EXCESSLENOK);
  2044.     loc3 -> n_cltype = t3;
  2045.     free_xtemp(loc1, loc3);
  2046.     ss_push(loc3);
  2047.     RETURN_VOID("sop_cast");
  2048.  
  2049. shrink:
  2050.     loc1 = resolve(loc1);    /* eliminate dual-reg value nodes, etc */
  2051.                 /* see note at head of this function */
  2052.     switch(loc1 -> n_mode) {
  2053.     case EA_MODE:
  2054.         /* this is a 68000, so offset the address */
  2055.         /* this ought to always work, since if the large object is
  2056.            on a proper boundary, so should be the small; the
  2057.            converse, of course, is not necessarily so */
  2058.         loc3 = locn_xdupl(loc1);
  2059.         loc3 -> n_const += (long)(len1 - len3);
  2060.         loc3 -> n_cltype = t3;
  2061.         ss_push(loc3);
  2062.         RETURN_VOID("sop_cast");
  2063.  
  2064.     case EAPSI_MODE:
  2065.         if (is_atloc(loc1)) {
  2066.             g_error(p, "post increment has no effect");
  2067.         }
  2068.     case EAPRD_MODE:
  2069.         if (ptr3 && is_atreg(loc1 -> n_reg1)) {
  2070.             /* this case is not terribly likely */
  2071.             loc3 = locn_reg(loc1 -> n_reg1);
  2072.         }
  2073.         else {
  2074.             loc3 = get_temp(p);
  2075.         }
  2076.         g_2l1(X_MOVE, loc1, loc3);
  2077.         free_xtemp(loc1, loc3);
  2078.         loc3 -> n_cltype = t3;
  2079.         ss_push(loc3);
  2080.         RETURN_VOID("sop_cast");
  2081.  
  2082.     case VALUE_MODE:
  2083.         if (is_aloc(loc1) && len3 < 2) {
  2084.             /* there is no areg byte reference */
  2085.             loc3 = get_dtemp();
  2086.             loc3 -> n_cltype = int_type;
  2087.             g_2l1(X_MOVE, loc1, loc3);
  2088.             free_xtemp(loc1, loc3);
  2089.         }
  2090.         else {
  2091.             loc3 = locn_xdupl(loc1);
  2092.         }
  2093.         loc3 -> n_cltype = t3;
  2094.         ss_push(loc3);
  2095.         RETURN_VOID("sop_cast");
  2096.     }
  2097.     fatal("sop_cast: internal: bad mode");
  2098.  
  2099. makesame:
  2100.     /* move byte that is in areg */
  2101.     loc1 = resolve(loc1);
  2102.     if (is_aloc(loc1)) {
  2103.         ss_push(loc1);
  2104.         loc3 = get_dtemp();
  2105.         loc1 = ss_pop();
  2106.         loc3 -> n_cltype = int_type;
  2107.         g_2l2(X_MOVE, loc1, loc3);
  2108.         free_temp(loc1);
  2109.     }
  2110.     else {
  2111.         loc3 = locn_xdupl(loc1);
  2112.     }
  2113.     loc3 -> n_cltype = t3;
  2114.     ss_push(loc3);
  2115.     RETURN_VOID("sop_cast");
  2116.     
  2117. donothing:
  2118.     loc3 = locn_xdupl(loc1);
  2119.     loc3 -> n_cltype = t3;
  2120.     ss_push(loc3);
  2121.     RETURN_VOID("sop_cast");
  2122. }
  2123.  
  2124. /*
  2125.     Generate code to test the top two elements of the S stack
  2126.     and set the condition codes accordingly.
  2127.  
  2128.     Return TRUE if the order of the compare was reversed from normal
  2129.     unstacking order
  2130. */
  2131. static bool
  2132. sop_cmp(struct node *p)
  2133. {
  2134.     int exchange;
  2135.     struct node *loc1, *loc2, *loc3;
  2136.  
  2137.     /*
  2138.         if loc1 is ANY register, or else
  2139.         if loc2 is a constant then generate
  2140.                 cmp loc2, loc1
  2141.     
  2142.         otherwise, generate:
  2143.                         move loc1, temp_reg
  2144.             cmp  loc2, temp_reg
  2145.  
  2146.         this represents standard unstacking order.  if it is
  2147.         convenient and would not upset the stack, exchange
  2148.         the operands instead
  2149.     */
  2150.  
  2151.     TRACEPB("sop_cmp", printf("(%p)\n", p));
  2152.  
  2153.     gen_e1(p -> n_arg2);
  2154.     loc2 = resolve(ss_pop());
  2155.     ss_push(loc2);
  2156.     gen_e1(p -> n_arg1);
  2157.  
  2158.     loc1 = resolve(ss_pop());        /* destination */
  2159.     loc2 = ss_pop();
  2160.  
  2161.     if (is_xloc(loc1) || is_cloc(loc2) ||
  2162.       (has_effect(loc1 -> n_mode) && has_effect(loc2 -> n_mode)) ) {
  2163.         exchange = FALSE;
  2164.     }
  2165.     else {
  2166.         loc3 = loc1;
  2167.         loc1 = loc2;
  2168.         loc2 = loc3;
  2169.         /* not in unstacking order */
  2170.         exchange = TRUE;
  2171.     }
  2172.  
  2173.     if (is_aloc(loc1) && mlen(loc1) != 4) {
  2174.         goto dtemp;
  2175.     }
  2176.     else if (is_cloc(loc2) && !is_cloc(loc1)) {
  2177.         if (is_zloc(loc2) && !is_aloc(loc1)) {
  2178.             g_1l(X_TST, loc1);
  2179.         }
  2180.         else {
  2181.             g_2l1(X_CMP, loc2, loc1);
  2182.         }
  2183.     }
  2184.     else if (is_xloc(loc1)) {
  2185.         g_2l1(X_CMP, loc2, loc1);
  2186.     }
  2187.     else if (
  2188.             loc2 -> n_mode == EAPSI_MODE && 
  2189.             loc1 -> n_mode == EAPSI_MODE &&
  2190.             loc2 -> n_reg1 != loc1 -> n_reg1
  2191.         ) {
  2192.         /* I don't know for sure what happens if you try to
  2193.             compare top of stack to next on stack with
  2194.                 CMPM (a7)+,(a7)+, hence the third test */
  2195.         g_2l1(X_CMPM, loc2, loc1);
  2196.     }
  2197.     else {
  2198. dtemp:
  2199.         ss_push(loc2);    /* note: if both were pop, they're not
  2200.                         exchanged */
  2201.         ss_push(loc1);
  2202.         loc3 = get_dtemp(); /* NEVER atemp */
  2203.         loc1 = ss_pop();
  2204.         loc2 = ss_pop();
  2205.  
  2206.         g_2l1(X_MOVE, loc1, loc3);
  2207.         g_2l1(X_CMP, loc2, loc3);
  2208.         free_reg(loc3 -> n_reg1);
  2209.     }
  2210.  
  2211.     /* This sets condition codes but returns no value. */
  2212.     free_temp(loc2);
  2213.     free_temp(loc1);
  2214.  
  2215.     RETURN_BOOL("sop_cmp", exchange);
  2216. }
  2217.  
  2218. /*
  2219.     Generate code for the comma operator.
  2220.  
  2221.     This operator is a sort-of boolean whose left hand always
  2222.     succeeds.  Since there is no CONDITIONAL execution of anything,
  2223.     however, physical-stack balancing between the branches is unnecessary.
  2224.  
  2225.     It IS necessary to get rid of the left hand result thoroughly.
  2226. */
  2227. static void
  2228. sop_comma(register struct node *p)
  2229. {
  2230.     register struct node *loc1;
  2231.  
  2232.     /* Generate first subtree and discard. */
  2233.  
  2234.     TRACEPB("sop_comma", printf("(%p)\n", p));
  2235.  
  2236.     gen_e1(p -> n_arg1);
  2237.     loc1 = ss_pop();
  2238.     free_temp(loc1);
  2239.     x_lookat(loc1);    /* we have to reference this in case it is a
  2240.                 pop_loc form, in which case we adjust a7. */
  2241.  
  2242.     /* Generate second subtree and leave result on stack */
  2243.     gen_e1(p -> n_arg2);
  2244.  
  2245.     TICKX("sop_comma");
  2246. }
  2247.  
  2248.  
  2249. /*
  2250.     Generate code for the list separator.
  2251.     This is as for the comma operator, except the form of the
  2252.     node is slightly different because it is a cons node instead
  2253.     of a binop node.
  2254. */
  2255. static void
  2256. sop_sep(register struct node *p)
  2257. {
  2258.     register struct node *loc1;
  2259.  
  2260.     /* Generate first subtree and discard. */
  2261.  
  2262.     TRACEPB("sop_sep", printf("(%p)\n", p));
  2263.  
  2264.     gen_e1(p -> n_car);
  2265.     loc1 = ss_pop();
  2266.     free_temp(loc1);
  2267.     x_lookat(loc1);
  2268.  
  2269.     gen_e1(p -> n_next);
  2270.  
  2271.     TICKX("sop_sep");
  2272. }
  2273.  
  2274. /*
  2275.     Generate code for the inner (0/1) logical operators.
  2276.  
  2277.     This calls gen_b1 and inserts a load of 1 in one branch and 0
  2278.     in the other branch.  Do NOT confuse these two "branches", which
  2279.     correspond to true_lab and false_lab, with the other branches
  2280.     that execute or skip portions of what is written in the conditional
  2281.     expression itself.  There are substantial similarities between this
  2282.     operation and the ternary, but the comparison can be more confusing
  2283.     than helpful.
  2284. */
  2285. static void
  2286. sop_logical(register struct node *p, int op)
  2287. {
  2288.     register struct node *loc1;
  2289.     struct node *else_lab, *end_lab;
  2290.  
  2291.     TRACEPB("sop_logical", printf("(%p, %d)\n", p, op));
  2292.  
  2293.     else_lab  = new_clabel();
  2294.     end_lab = new_clabel();
  2295.  
  2296.     gen_b1(0, p, FALL_THROUGH, else_lab);
  2297.  
  2298.     /* NOW get the temp; it should get the temp reserved by gen_b1;
  2299.        if gen_b1 doesn't reserve a temp because there are no
  2300.        stacked registers showing, then there should be an available reg */
  2301.  
  2302.     if (!nd_free) {
  2303.         /* the branch stacks won't match after the convergence point */
  2304.         g_error(p, "internal: sop_logical: temp unavailable");
  2305.     }
  2306.     loc1 = get_dtemp();
  2307.     loc1 -> n_cltype = int_type;
  2308.  
  2309.     g_2l2(X_MOVE, one_loc, loc1);
  2310.     g_bra(end_lab = new_clabel());
  2311.     g_label(else_lab);
  2312.  
  2313.     g_1l(X_CLR, loc1);
  2314.     g_label(end_lab);
  2315.     ss_push(loc1);
  2316.  
  2317.     TICKX("sop_logical");
  2318. }
  2319.  
  2320. /*
  2321.     Generate code for unary "not" operator.
  2322. */
  2323. static void
  2324. sop_not(struct node *q)
  2325. {
  2326.     register struct node *loc1, *loc3;
  2327.     register struct node *p;
  2328.     register struct node *else_lab, *end_lab;
  2329.     register int flip, tok;
  2330.  
  2331.     TRACEPB("sop_not", printf("(%p)\n", q));
  2332.  
  2333.     flip = 0;
  2334.     p = q;
  2335.     while ((tok = p -> n_arg1 -> n_type) == NOT_TOK) {
  2336.         flip ^= 1;
  2337.         p = p -> n_arg1;
  2338.     }
  2339.     if (tok == LOR_TOK || tok == LAND_TOK) {
  2340.         else_lab  = new_clabel();
  2341.         end_lab = new_clabel();
  2342.  
  2343.         gen_b1(0, p -> n_arg1, FALL_THROUGH, else_lab);
  2344.  
  2345.         if (!nd_free) {
  2346.             g_error(p, "internal: sop_not: temp unavailable");
  2347.         }
  2348.         loc1 = get_dtemp();
  2349.         loc1 -> n_cltype = q -> n_cltype;
  2350.  
  2351.         if (flip) {
  2352.             g_2l2(X_MOVE, one_loc, loc1);
  2353.         }
  2354.         else {
  2355.             g_1l(X_CLR, loc1);
  2356.         }
  2357.  
  2358.         g_bra(end_lab = new_clabel());
  2359.         g_label(else_lab);
  2360.  
  2361.         if (flip) {
  2362.             g_1l(X_CLR, loc1);
  2363.         }
  2364.         else {
  2365.             g_2l2(X_MOVE, one_loc, loc1);
  2366.         }
  2367.         g_label(end_lab);
  2368.         ss_push(loc1);
  2369.     }
  2370.     else {
  2371.         gen_e1(p -> n_arg1);
  2372.         loc1 = ss_pop();
  2373.         if (is_aloc(loc1)) {
  2374.             g_2l2(X_CMPA, zero_loc, loc1);
  2375.         }
  2376.         else {
  2377.             g_1l(X_TST, loc1);
  2378.         }
  2379.  
  2380.         /* result is to wind up in a dtemp */
  2381.         if (is_dtloc(loc1)) {
  2382.             loc3 = loc1;
  2383.         }
  2384.         else {
  2385.             loc3 = get_dtemp();
  2386.         }
  2387.  
  2388.         if (flip) {
  2389.             g_1(X_SNE, loc3);
  2390.         }
  2391.         else {
  2392.             g_1(X_SEQ, loc3);
  2393.         }
  2394.         loc3 -> n_cltype = q -> n_cltype;
  2395.         g_2l2(X_AND, one_loc, loc3);
  2396.         ss_push(loc3);
  2397.     }
  2398.  
  2399.     TICKX("sop_not");
  2400. }
  2401.  
  2402. /*
  2403.     Add (or subtract) two loc_node references.
  2404.  
  2405.     NOTE: because of the s_stack, an argument must be fetched exactly
  2406.         once in all branches
  2407. */
  2408. static void
  2409. sop_add(struct node *p, int op)
  2410. {
  2411.     struct node *loci, *locp;
  2412.     register struct node *loc3;
  2413.     register int reg;
  2414.     register unsigned long scale;
  2415.  
  2416.     TRACEPB("sop_add", printf("(%p, %d)\n", p, op));
  2417.  
  2418.     if (p -> n_arg1 -> n_cltype -> t_typtok == INT_TYPE &&
  2419.             p -> n_arg2 -> n_cltype -> t_typtok == INT_TYPE) {
  2420.         /* must be ordinary integer operation */
  2421.         gen_e1(p -> n_arg2);
  2422.         gen_e1(p -> n_arg1);
  2423.         sop_dbinop(p, op);
  2424.         RETURN_VOID("sop_add");
  2425.     }
  2426.  
  2427.     /* operation involves at least one pointer */
  2428.     if (p -> n_arg1 -> n_cltype -> t_typtok == INT_TYPE) {
  2429.         locp = (void *) p -> n_arg2;
  2430.         gen_e1(p -> n_arg2);
  2431.         gen_e1(p -> n_arg1);    /* generates the int last */
  2432.     }
  2433.     else {
  2434.         locp = (void *) p -> n_arg1;
  2435.         gen_e1(p -> n_arg1);
  2436.         gen_e1(p -> n_arg2);    /* generates the int last */    
  2437.     }
  2438.     scale = locp -> n_cltype -> t_link -> t_tsize;
  2439.     loci = ss_pop();        /* integer loc_node */
  2440.     locp = ss_pop();
  2441.  
  2442.     TRACEP("sop_add", printf("pointer/array %s: p=%p i=%p\n",
  2443.         (op == MINUS_TOK)? "subtraction" : "addition",locp, loci));
  2444.     if (loci -> n_cltype -> t_typtok != INT_TYPE) {
  2445. #ifdef DEBUG
  2446.         if (op != MINUS_TOK) {
  2447.             g_error(p, "pointer plus pointer?");
  2448.             ss_push(locp);
  2449.             RETURN_VOID("sop_add");
  2450.         }
  2451. #endif /* DEBUG */
  2452.         locp = x_subp(locp, loci, scale);
  2453.         ss_push(locp);
  2454.         RETURN_VOID("sop_add");
  2455.     }
  2456.  
  2457.  
  2458.     /* WARNING: check for postponement of scaling... */
  2459.     loci = x_scale(loci, locp -> n_cltype -> t_link -> t_tsize);
  2460.     locp = x_addpsi(locp, loci, op);
  2461.     locp -> n_cltype = p -> n_cltype;
  2462.     ss_push(locp);
  2463.  
  2464.     TRACEPX("sop_add", printf("returns locp=%p\n", locp));
  2465.     return;
  2466. }
  2467.  
  2468. /*
  2469.     Generate code for a relational 0/1 operator.
  2470. */
  2471. static void
  2472. sop_relop(struct node *p, int op)
  2473. {
  2474.     register struct node *loc1, *loc2, *loc3;
  2475.     register struct type_node *t;
  2476.  
  2477.     TRACEPB("sop_relop", printf("(%p, %s)\n", p, ps_tok(op)));
  2478.  
  2479.     loc1 = resolve(ss_pop());
  2480.     loc2 = resolve(ss_pop());
  2481.  
  2482.     /* Avoid an extra move if at all possible. */
  2483.     if (is_xloc(loc2) || is_cloc(loc1)) {
  2484.         /* All is well. */
  2485.         loc3 = loc2;
  2486.     }
  2487.     else if (is_xloc(loc1) || is_cloc(loc2)) {
  2488.         /* exchange the operands and the compare. */
  2489.         /* Note: will work since they aren't both POP_LOC */
  2490.         loc3 = loc1;
  2491.         loc1 = loc2;
  2492.  
  2493.         switch(op) {
  2494.         /* symmetrical */
  2495.         case NE_TOK:
  2496.         case EQUAL_TOK:            break;
  2497.  
  2498.         case GE_TOK:    op = LE_TOK;    break;
  2499.         case GT_TOK:    op = LT_TOK;    break;
  2500.         case LE_TOK:    op = GE_TOK;    break;
  2501.         case LT_TOK:    op = GT_TOK;    break;
  2502.         }
  2503.     }
  2504.     else {
  2505.         /* Push loc2 so that get_temp() may change it. */
  2506.         ss_push(loc2);
  2507.         loc3 = get_temp(loc2);
  2508.         loc2 = ss_pop();
  2509.         g_2l1(X_MOVE, loc2, loc3);
  2510.         free_temp(loc2);
  2511.     }
  2512.     /* must NOT ss_push anything but final result now, since operands
  2513.             may be switched */
  2514.  
  2515.     /* Do the comparison. */
  2516.     g_2l1(X_CMP, loc1, loc3);
  2517.     t = loc1 -> n_cltype;
  2518.  
  2519.     /* Free everything */
  2520.     free_temp(loc1);
  2521.     free_temp(loc3);
  2522.  
  2523.     /* Get a D temporary for the result and make it an integer */
  2524.     /* If this D temporary is a register just freed, so be it */
  2525.     loc3 = get_dtemp();
  2526.     loc3 -> n_cltype = int_type;
  2527.  
  2528.     /* Generate an Sxx instruction. */
  2529.     if (t -> t_typtok != INT_TYPE || (t -> t_mclass & UNSIGNED_MOD)) {
  2530.  
  2531.         /* pointer/unsigned */
  2532.         switch(op) {
  2533.         case EQUAL_TOK:    g_1(X_SEQ, loc3);    break;
  2534.         case NE_TOK:    g_1(X_SNE, loc3);    break;
  2535.     
  2536.         /* exchanged forms since loc2 is generated first */
  2537.         case GE_TOK:    g_1(X_SLS, loc3);    break;
  2538.         case GT_TOK:    g_1(X_SLO, loc3);    break;
  2539.         case LE_TOK:    g_1(X_SHS, loc3);    break;
  2540.         case LT_TOK:    g_1(X_SHI, loc3);    break;
  2541.  
  2542.         }
  2543.     }
  2544.     else {
  2545.         /* signed */
  2546.         switch(op) {
  2547.         case EQUAL_TOK:    g_1(X_SEQ, loc3);    break;
  2548.         case NE_TOK:    g_1(X_SNE, loc3);    break;
  2549.  
  2550.         case GE_TOK:    g_1(X_SLE, loc3);    break;
  2551.         case GT_TOK:    g_1(X_SLT, loc3);    break;
  2552.         case LE_TOK:    g_1(X_SGE, loc3);    break;
  2553.         case LT_TOK:    g_1(X_SGT, loc3);    break;
  2554.         }
  2555.     }
  2556.  
  2557.     /* Mask off all but the last bit. */
  2558.     /* This result is DEFINED as int, so it has to be extended */
  2559.     g_2l2(X_AND, one_loc, loc3);
  2560.  
  2561.     ss_push(loc3);
  2562.     RETURN_VOID("sop_relop");
  2563. }
  2564.  
  2565. /*
  2566.     Generate code for ternary operator.
  2567.  
  2568.     Note that this involves machinations to get the stack balanced
  2569.     the same regardless of which branch gets executed!
  2570.  
  2571.     CAUTION: has_effect() loc_nodes involve postponed side effects.
  2572.     This code always loads both branches into a temporary.  If that
  2573.     eventually gets optimized away, keep in mind that has_effect()
  2574.     loc_nodes MUST be loaded at the end of the branch to get the
  2575.     side effects done, since ?: is a sequence operator.
  2576. */
  2577. static void
  2578. sop_ternop(register struct node *p)
  2579. {
  2580.     struct node *else_lab, *end_lab;
  2581.     register struct node *loc, *loc1, *loc2, *loc3;
  2582.     register int reg3, t_ok, is_t1, is_t2;
  2583.     int ssb_save, sf_save;
  2584.  
  2585.     /* Allocate label nodes. */
  2586.  
  2587.     TRACEPB("sop_ternop", printf("(%p)\n", p));
  2588.  
  2589.     else_lab = new_clabel();
  2590.     end_lab  = new_clabel();
  2591.  
  2592.     /*
  2593.         Identify a result temporary.  This identifies one
  2594.         register which will not get clobbered when we do the 
  2595.         balancing ss_restore() pop, since its push, if any,
  2596.         occurs right now before we log the ss_bot location.
  2597.  
  2598.         This register may in fact be used by one or both branches
  2599.         as a temporary, but it will be released by the end
  2600.         of each branch--or perhaps be the result itself.
  2601.  
  2602.         If ss_restore() actually pops something, then this
  2603.         register will be used as the result, since it is
  2604.         guaranteed not to be clobbered.  (This practice is
  2605.         excessively restrictive, but it will do for quite a
  2606.         while, since deep-lying ternaries aren't terribly
  2607.         common anyhow.)
  2608.     */
  2609.     loc3 = get_temp(p);    /* this will be our result */
  2610.     free_reg(reg3 = loc3 -> n_reg1);
  2611.     t_ok = TRUE;
  2612.  
  2613.     /* Generate the effective boolean */
  2614.     /* p -> n_arg1 is the TEST expression, not a branch */
  2615.     gen_b1(0, p -> n_arg1, FALL_THROUGH, else_lab);
  2616.  
  2617.     /* NOW record the s_stack pointers */
  2618.     ssb_save = ss_bot;
  2619.     sf_save = ss_forks;
  2620.     ss_forks = ss_count;    /* pre-existing items save-and-restore */
  2621.  
  2622.     /* p -> n_arg2 is the FIRST BRANCH */
  2623.     gen_e1(p -> n_arg2);
  2624.     loc1 = resolve(ss_pop());
  2625.     g_qmove(loc1, loc3);
  2626.     is_t1 = is_xtloc(loc1);
  2627.         
  2628.     free_temp(loc1);
  2629.  
  2630.     /* restore the s_stack and r_stack */
  2631.     while (ss_bot > ssb_save) {
  2632.         if (ss_restore()) {
  2633.             t_ok = FALSE;
  2634.         }    
  2635.     }
  2636.     g_bra(end_lab);
  2637.  
  2638.     /* p -> n_arg3 is the SECOND branch */
  2639.     g_label(else_lab);
  2640.     gen_e1(p -> n_arg3);
  2641.     loc2 = resolve(ss_pop());
  2642.     g_qmove(loc2, loc3);
  2643.  
  2644.     is_t2 = is_xtloc(loc2);
  2645.  
  2646.     free_temp(loc2);
  2647.     g_label(end_lab);
  2648.  
  2649.     /* again restore the s_stack and r_stack */
  2650.     while (ss_bot > ssb_save) {
  2651.         if (ss_restore()) {
  2652.             t_ok = FALSE;
  2653.         }
  2654.     }
  2655.  
  2656.     /* if a branch returns a temporary of the right sort, use it */
  2657.     if (!t_ok) {
  2658.     }
  2659.     else if (is_areg(reg3)) {
  2660.         if (is_t1 && is_areg(loc1 -> n_reg1)) {
  2661.             loc3 -> n_reg1 = loc1 -> n_reg1;
  2662.         }
  2663.         else if (is_t2 && is_areg(loc2 -> n_reg1)) {
  2664.             loc3 -> n_reg1 = loc2 -> n_reg1;
  2665.         }
  2666.     }
  2667.     else {
  2668.         /* dreg, since it came from get_temp */
  2669.         if (is_t1 && is_dreg(loc1 -> n_reg1)) {
  2670.             loc3 -> n_reg1 = loc1 -> n_reg1;
  2671.         }
  2672.         else if (is_t2 && is_dreg(loc2 -> n_reg1)) {
  2673.             loc3 -> n_reg1 = loc2 -> n_reg1;
  2674.         }
  2675.     }
  2676.     TRACE("gappend",
  2677.         if(reg3 != loc3 -> n_reg1) {
  2678.             printf("altering ternary temp reg to: ");
  2679.             pr_arg(loc3);
  2680.             printf("\n");
  2681.         }
  2682.     );
  2683.     TRACEP("sop_ternop",
  2684.         if(reg3 != loc3 -> n_reg1) {
  2685.             printf("altering ternary temp reg to: ");
  2686.             pr_loc(loc3);
  2687.             printf("\n");
  2688.         }
  2689.     );
  2690.  
  2691.     /* restore the forks threshold */
  2692.     ss_forks = sf_save;
  2693.     loc3 -> n_cltype = p -> n_cltype;
  2694.     (void) alloc_reg(loc3 -> n_reg1);
  2695.     ss_push(loc3);
  2696.  
  2697.     TICKX("sop_ternop");
  2698. }
  2699.  
  2700. /*
  2701.     Add a constant offset to the loc_node to produce a new one
  2702. */
  2703. static void
  2704. sop_dot(struct node *p)
  2705. {
  2706.     struct node *locp, *loci;
  2707.     register struct node *loc3;
  2708.  
  2709.     TRACEPB("sop_dot", printf("(%p)\n", p));
  2710.  
  2711.     locp = ss_pop();
  2712.     loci = ss_pop();
  2713.  
  2714.     if (loci = fix_cloc(loci)) {
  2715.         if (locp -> n_mode == EA_MODE) {
  2716.             if (!is_zloc(loci)) {
  2717.                 locp = locn_xdupl(locp);
  2718.                 locp -> n_mode = VALUE_MODE;
  2719.                 loci = x_scale(loci, 1L);
  2720.                 locp = x_addpsi(locp, loci, PLUS_TOK);
  2721.                 locp -> n_mode = EA_MODE;
  2722.             }
  2723.         }
  2724.         else {
  2725.             g_error(p, "sop_dot: structure not lvalue");
  2726.         }
  2727.     }
  2728.     else {
  2729.         g_error(p, "sop_dot: not constant");
  2730.     }
  2731.     locp -> n_cltype = p -> n_cltype;
  2732.     ss_push(locp);
  2733.  
  2734.     TICKX("sop_dot");
  2735. }
  2736.  
  2737. /*
  2738.     Add a constant offset to the pointer and perform indirection
  2739.  
  2740.     Before even THINKING about optimizing (p++) -> elt, read note
  2741.     in sop_ustar.
  2742. */
  2743. static void
  2744. sop_arrow(struct node *p)
  2745. {
  2746.     struct node *locp, *loci;
  2747.     register struct node *loc3;
  2748.     register int areg;
  2749.  
  2750.     TRACEPB("sop_arrow", printf("(%p)\n", p));
  2751.  
  2752.     locp = ss_pop();
  2753.     loci = ss_pop();
  2754.  
  2755.     if (loci = fix_cloc(loci)) {
  2756.         if (!is_zloc(loci)) {
  2757.             loci = x_scale(loci, 1L);
  2758.             locp = x_addpsi(locp, loci, PLUS_TOK);
  2759.         }
  2760.     }
  2761.     else {
  2762.         g_error(p, "sop_arrow: not constant");
  2763.     }
  2764.     ss_push(locp);
  2765.     gen_indir(p);    /* argument is for type only */
  2766.  
  2767.     TICKX("sop_arrow");
  2768. }
  2769.  
  2770. /*
  2771.     Generate code for the unary "address-of" operator
  2772.     and in other cases where an address is required.
  2773. */
  2774. static void
  2775. sop_adr(struct node *p)
  2776. {
  2777.     struct node *loc1, *loc3;
  2778.     struct node *p1;
  2779.     register int x;
  2780.  
  2781.     TRACEPB("sop_adr", printf("(%p)\n", p));
  2782.  
  2783.     p1 = p -> n_arg1;
  2784.  
  2785.     switch (p1 -> n_type) {
  2786.     case USTAR_TOK:
  2787.     case ARROW_TOK:
  2788.     case DOT_TOK:
  2789.     case ID_TOK:
  2790.         gen_e1(p1);
  2791.         loc3 = ss_pop();
  2792.     
  2793.         if (loc3 -> n_mode == EA_MODE) {
  2794.             loc3 = locn_chmod(loc3, VALUE_MODE);
  2795.         }
  2796.         else if (loc3 -> n_mode == VALUE_MODE && 
  2797.                 loc3 -> n_cltype -> t_typtok == ARRAY_TYPE) {
  2798.         }
  2799.         else {
  2800.             g_error(p, "argument doesn't have an address");
  2801.             loc3 = locn_xconst(0L);
  2802.         }
  2803.         break;
  2804.  
  2805.     case CAST_TOK:
  2806.         sop_adr(p1);
  2807.         loc3 = ss_pop();
  2808.         switch(loc3 -> n_cltype -> t_typtok) {
  2809.         case INT_TYPE:
  2810.         case POINTER_TYPE:
  2811.             x = mlen(p1 -> n_arg1) - mlen(p1); 
  2812.             if (x < 0) {
  2813.                 goto derror;
  2814.             }
  2815.             if (x > 0) {
  2816.                 g_help(p, "are you sure of what address you are asking for?");
  2817.                 loc1 = locn_xconst((long)x);
  2818.                 loc1 -> n_cltype = int_type;
  2819.                 loc3 = x_addpsi(loc3, loc1, PLUS_TOK);
  2820.             }
  2821.             break;
  2822.  
  2823.         default:
  2824.         derror:
  2825.             g_error(p,
  2826.              "cannot take address; highly dubious construction");
  2827.             loc3 = locn_xconst(0L);
  2828.         }
  2829.         break;
  2830.  
  2831.     default:
  2832.         TRACEP("sop_adr", printf("p1->n_type = %s\n",
  2833.             ps_tok(p1->n_type)));
  2834.  
  2835.         g_error(p, "this form could not possibly have an address");
  2836.         loc3 = locn_xconst(0L);
  2837.     }
  2838.  
  2839.     loc3 -> n_cltype = p -> n_cltype;
  2840.     ss_push(loc3);
  2841.     RETURN_VOID("sop_adr");
  2842. }
  2843.  
  2844. /*
  2845.     Generate code for ordinary unary operators.
  2846.  
  2847.     TILDE_TOK:    ~    1's complement.
  2848.     UMINUS_TOK:    -    2's complement.
  2849.     UPLUS_TOK:    +    do nothing.
  2850. */
  2851. static void
  2852. sop_unop(register struct node *p, int op)
  2853. {
  2854.     struct node *loc1, *loc2, *loc3;
  2855.  
  2856.     TRACEPB("sop_unop", printf("(%p, %s)\n", p, ps_tok(op)));
  2857.  
  2858.     if (op == UPLUS_TOK) {
  2859.         /* CAUTION: UPLUS is a meaningful ANSI operator */
  2860.         RETURN_VOID("sop_unop");
  2861.     }
  2862.     loc1 = ss_pop();
  2863.  
  2864.     /* result is to wind up in a dtemp */
  2865.     if (is_dtloc(loc1)) {
  2866.         loc3 = loc1;
  2867.     }
  2868.     else {
  2869.         loc3 = get_dtemp();
  2870.         g_qmove(loc1, loc3);
  2871.     }
  2872.  
  2873.     switch (op) {
  2874.     case TILDE_TOK:
  2875.         loc3 -> n_cltype = p -> n_cltype;
  2876.         g_1l(X_NOT, loc3);
  2877.         break;
  2878.  
  2879.     case UMINUS_TOK:
  2880.         loc3 -> n_cltype = p -> n_cltype;
  2881.         g_1l(X_NEG, loc3);
  2882.         break;
  2883.  
  2884.     default:
  2885.         g_error(p, "sop_unop: shouldn't happen");
  2886.         printf("sop_unop: bad op is %s\n", ps_tok(op));
  2887.     }
  2888.     ss_push(loc3);
  2889.  
  2890.     TICKX("sop_unop");
  2891. }
  2892.  
  2893. /*
  2894.     called by sop_ustar: NOT a special form
  2895.     increment or decrement
  2896. */
  2897. static void
  2898. sop_ppop(struct node *p)
  2899. {
  2900.     register struct node *loc1, *loc3;
  2901.     register struct type_node *t1;
  2902.     register unsigned long scale;
  2903.     int tok;
  2904.  
  2905.     TRACEPB("sop_ppop", printf("(%p)\n", p));
  2906.  
  2907.     loc1 = resolve(ss_pop());
  2908.     t1 = loc1 -> n_cltype;
  2909.     
  2910.     switch(p -> n_type) {
  2911.     case PRE_DEC_TOK:
  2912.         tok = X_SUB;
  2913.         goto dopre;
  2914.     case PRE_INC_TOK:
  2915.         tok = X_ADD;
  2916.         goto dopre;
  2917.     case POST_DEC_TOK:
  2918.         tok = X_SUB;
  2919.         goto dopost;
  2920.     case POST_INC_TOK:
  2921.         tok = X_ADD;
  2922.         goto dopost;
  2923.     }
  2924.  
  2925. dopre:
  2926.     switch(t1 -> t_typtok) {
  2927.  
  2928.     case POINTER_TYPE:
  2929.         /* yes, sooner or later we have to do the scale */
  2930.         scale = t1 -> t_link -> t_tsize;
  2931.         if (scale != 1) {
  2932.             g_2l2(tok, locn_xconst(scale), loc1);
  2933.         }
  2934.         else {
  2935.             g_2l2(tok, one_loc, loc1);
  2936.         }
  2937.         break;
  2938.  
  2939.     case INT_TYPE:
  2940.         g_2l2(tok, one_loc, loc1);
  2941.         break;
  2942.  
  2943.     default:
  2944.         if (tok == X_ADD) {
  2945.             g_error(p, "increment of non-scalar");
  2946.         }
  2947.         else {
  2948.             g_error(p, "decrement of non-scalar");
  2949.         }
  2950.     }
  2951.     ss_push(loc1);
  2952.     RETURN_VOID("sop_ppop");
  2953.     /* pre-exit */
  2954.  
  2955.     /* PLEASE no fallthrough here */
  2956.  
  2957. dopost:
  2958.     if (p -> n_oflags & OPT_NONEED) {
  2959.         /* feed it a fish to keep stacks balanced */
  2960.         loc3 = loc1;
  2961.     }
  2962.     else {
  2963.         /* draw a temporary to hold the old value */
  2964.         loc3 = get_temp(p);
  2965.         loc3 -> n_cltype = loc1 -> n_cltype;
  2966.         g_2l1(X_MOVE, loc1, loc3);
  2967.     }
  2968.  
  2969.     switch(t1 -> t_typtok) {
  2970.  
  2971.     case POINTER_TYPE:
  2972.         /* yes, sooner or later we have to do the scale */
  2973.         scale = t1 -> t_link -> t_tsize;
  2974.         if (scale != 1) {
  2975.             g_2l2(tok, locn_xconst(scale), loc1);
  2976.             break;
  2977.         }
  2978.         /* FALL_THROUGH */
  2979.  
  2980.     case INT_TYPE:
  2981.         g_2l2(tok, one_loc, loc1);
  2982.         break;
  2983.  
  2984.     default:
  2985.         if (tok == X_ADD) {
  2986.             g_error(p, "increment of non-scalar");
  2987.         }
  2988.         else {
  2989.             g_error(p, "decrement of non-scalar");
  2990.         }
  2991.     }
  2992.     ss_push(loc3);
  2993.     RETURN_VOID("sop_ppop");
  2994.     /* post-exit */
  2995. }
  2996.  
  2997. /*
  2998.     Generate code for function calls.
  2999. */
  3000. static void
  3001. sop_call(struct node *p)
  3002. {
  3003.     struct node *loc1, *loct;
  3004.     register unsigned long size;
  3005.     register int reg;
  3006.  
  3007.     /* Set up the loc_node representing the returned value */
  3008. #ifdef D0_ONLY
  3009.  
  3010.     TRACEPB("sop_call", printf("(%p)\n", p));
  3011.  
  3012.     loc1 = d0_loc;
  3013. #else
  3014.     if (p -> n_cltype -> t_typtok == INT_TYPE) {
  3015.         loc1 = d0_loc;
  3016.     }
  3017.     else {
  3018.         loc1 = a0_loc;
  3019.     }
  3020. #endif /* D0_ONLY */
  3021.  
  3022.     /*
  3023.         push the scratch registers and return scratch register NOW
  3024.         the items pushed cannot be part of the args, since the args
  3025.         aren't even generated yet; all the items are items that
  3026.         must survive the function call.
  3027.     */
  3028.     force_free(loc1 -> n_reg1);
  3029.     push_scratch();
  3030.  
  3031.     /* THEN generate the argument list */
  3032.     size = gen_args(p -> n_arg2, TRUE);
  3033.  
  3034.     /* Expression serving as function code locator */
  3035.     gen_e1(p -> n_arg1);
  3036.     loct = resolve(ss_pop());
  3037.     g_1(X_JSR, loct);
  3038.     free_temp(loct);
  3039.  
  3040.     /* Reset the stack pointer */
  3041.     if (size) {
  3042.         loct = locn_xconst(size);
  3043.         loct -> n_cltype = (size > INT_MAX)? long_type : int_type;
  3044.         g_2l1(X_ADDA, loct, a7_loc);
  3045.     }
  3046.  
  3047.     /*
  3048.         NOTE:
  3049.         in some cases, ensuing code might follow up the stack
  3050.         adjustment with a stack pre-decrement.  peep_hole()
  3051.         might fix this, or a global pointer could be kept to
  3052.         the most recent adjustment and then either used or
  3053.         cancelled at the next branch, rts, or stack pointer change.
  3054.     */
  3055.  
  3056.     /* allocate and return the result */
  3057.     (void) alloc_reg(loc1 -> n_reg1);
  3058.     loc1 -> n_cltype = p -> n_cltype;
  3059.     ss_push(loc1);
  3060.  
  3061.     TICKX("sop_call");
  3062. }
  3063.  
  3064.  
  3065. /*
  3066.     Push a series of call arguments and return a value to be used
  3067.     in the compensating addq instruction
  3068. */
  3069. static unsigned long
  3070. gen_args(register struct node *arg, int top)
  3071. {
  3072.     register unsigned long x;
  3073.     register struct node *loc1, *loc3;
  3074.     static unsigned int argdepth = 0;
  3075.     static unsigned int a7busy = 0;
  3076.  
  3077.     TRACEPB("gen_args", printf("(%p, %d)\n", arg, top));
  3078.  
  3079.     if (arg) {
  3080.         ++argdepth;
  3081.         if (arg -> /* BUG t_typtok */ n_type == SEPARATOR_TOK) {
  3082.             x = gen_args(arg -> n_next, top);
  3083.             x += gen_args(arg -> n_car, FALSE);
  3084.         }
  3085.         else {
  3086.             gen_e1(arg);
  3087.             loc1 = resolve(ss_pop());
  3088.             x = (unsigned long) (unsigned) mlen(loc1);
  3089.             if (x == 1) {
  3090.                 /* cast to int type using dreg */
  3091.                 if (!is_cloc(loc1)) {
  3092.                     loc1 =
  3093.                  x_cast(loc1, 1, loc1->n_cltype->t_mclass, 2,
  3094.                     TRUE /* 3/5/89 */);
  3095.                 }
  3096.                 loc1 = locn_xdupl(loc1);
  3097.                 loc1 -> n_cltype -> t_mclass &= ~CHAR_MOD;
  3098.                 loc1 -> n_cltype -> t_tsize = 2;
  3099.                 x = 2;
  3100.             }
  3101.             TRACEP("gen_args",
  3102.                 printf("push %p; top=%d; ss_bot=%d\n",
  3103.                     loc1, top, ss_bot));
  3104.  
  3105.             /* note: we can skip pushing at the top level only */
  3106.             if (!is_equiv(loc1, pop_loc)) {
  3107.                 if (top && call_1arg && !ss_bot && !a7busy) {
  3108.                     g_2l1(X_MOVE, loc1, nopush_loc);
  3109.                     a7busy = 1;
  3110.                     x = 0;
  3111.                 }
  3112.                 /* note: the assembler apparently can't 
  3113.                    generate a 4-byte PEA */
  3114.                 else if (is_cloc(loc1) &&
  3115.                     mlen(loc1) == 4 &&
  3116.                     !loc1 -> n_cid && 
  3117.                     loc1 -> n_const &&
  3118.                     loc1 -> n_const <= 32767 &&
  3119.                         loc1 -> n_const >= -32768) {
  3120.  
  3121.                     loc1 = locn_xdupl(loc1);
  3122.                     loc1 -> n_mode = EA_MODE;
  3123.                     loc1 -> n_scflag = X2_ABSW;
  3124.                     loc1 -> n_cltype = int_type;
  3125.                     g_1(X_PEA, loc1);
  3126.                 }
  3127.                 else {
  3128.                     g_2l1(X_MOVE, loc1, push_loc);
  3129.                 }
  3130.                 free_temp(loc1);
  3131.             }
  3132.         }
  3133.         --argdepth;
  3134.         if (argdepth == 0) {
  3135.             a7busy = 0;
  3136.         }
  3137.         RETURN_ULONG("gen_args", x);
  3138.     }
  3139.     else {
  3140.         RETURN_ULONG("gen_args", NULL);
  3141.     }
  3142. }
  3143.