# vcg_flow1 --- generate code for flow-of-control context operators



# flow --- handle IMF operators in 'flow' context

   ipointer function flow (expr, regs, cond, label)
   tpointer expr
   regset regs
   logical cond
   unsigned label

   include VCG_COMMON

   integer ad (ADDR_DESC_SIZE), branch

   ipointer seq, gen_mr, load, flow_seq, flow_if, flow_convert,
      flow_switch, gen_branch, flow_sand, flow_sor, flow_eq,
      flow_ge, flow_gt, flow_le, flow_lt, flow_ne, flow_not,
      flow_field

   if (expr == 0) {
      flow = 0
      regs = 0
      return
      }

   select (Tmem (expr))

      when (CONVERT_OP)
         flow = flow_convert (expr, regs, cond, label)
      when (EQ_OP)
         flow = flow_eq (expr, regs, cond, label)
      when (GE_OP)
         flow = flow_ge (expr, regs, cond, label)
      when (GT_OP)
         flow = flow_gt (expr, regs, cond, label)
      when (LE_OP)
         flow = flow_le (expr, regs, cond, label)
      when (LT_OP)
         flow = flow_lt (expr, regs, cond, label)
      when (NE_OP)
         flow = flow_ne (expr, regs, cond, label)
      when (NOT_OP)
         flow = flow_not (expr, regs, cond, label)
      when (IF_OP)
         flow = flow_if (expr, regs, cond, label)
      when (SAND_OP)
         flow = flow_sand (expr, regs, cond, label)
      when (SEQ_OP)
         flow = flow_seq (expr, regs, cond, label)
      when (SOR_OP)
         flow = flow_sor (expr, regs, cond, label)
      when (SWITCH_OP)
         flow = flow_switch (expr, regs, cond, label)
      when (FIELD_OP)
         flow = flow_field (expr, regs, cond, label)

      when (DECLARE_STAT_OP, DEFINE_DYNM_OP, DEFINE_STAT_OP,
         BREAK_OP, NEXT_OP, GOTO_OP, UNDEFINE_DYNM_OP, NULL_OP,
         LABEL_OP, DO_LOOP_OP, FOR_LOOP_OP, WHILE_LOOP_OP, RETURN_OP) {
         call warning ("*i: questionable operator in flow context*n"p,
            Tmem (expr))
         flow = load (expr, regs)
         AD_MODE (ad) = LABELED_AM
         AD_LABEL (ad) = label
         flow = seq (flow, gen_mr (JMP_INS, ad))
         }

      when (SELECT_OP, INDEX_OP, OBJECT_OP, PROC_CALL_OP, CONST_OP,
         COMPL_OP, DEREF_OP, NEG_OP, REFTO_OP, ADDAA_OP, ADD_OP,
         ANDAA_OP, AND_OP, ASSIGN_OP, DIVAA_OP, DIV_OP,
         LSHIFTAA_OP, LSHIFT_OP, MULAA_OP,
         MUL_OP, ORAA_OP, OR_OP, POSTDEC_OP, POSTINC_OP,
         PREDEC_OP, PREINC_OP, REMAA_OP, REM_OP, RSHIFTAA_OP,
         RSHIFT_OP, SUBAA_OP, SUB_OP, XORAA_OP,
         XOR_OP) {
         flow = load (expr, regs)
         select (Tmem (expr + 1))
            when (INT_MODE, UNS_MODE)
               if (cond)
                  branch = BNE_INS
               else
                  branch = BEQ_INS
            when (LONG_INT_MODE, LONG_UNS_MODE)
               if (cond)
                  branch = BLNE_INS
               else
                  branch = BLEQ_INS
            when (FLOAT_MODE, LONG_FLOAT_MODE)
               if (cond)
                  branch = BFNE_INS
               else
                  branch = BFEQ_INS
         else
            call panic ("*i: bogus operator data mode*n"p, Tmem (expr + 1))
         flow = seq (flow, gen_branch (branch, label))
         }

   else
      call panic ("*i:  bogus operator in flow*n"p, Tmem (expr))

   return
   end



# flow_convert --- branch on converted value

   ipointer function flow_convert (expr, regs, cond, label)
   tpointer expr
   regset regs
   logical cond
   unsigned label

   include VCG_COMMON

   ipointer load, gen_branch, seq

   integer branch

   flow_convert = load (expr, regs)

   select (Tmem (expr + 2))
      when (INT_MODE, UNS_MODE)
         if (cond)
            branch = BNE_INS
         else
            branch = BEQ_INS
      when (LONG_INT_MODE, LONG_UNS_MODE)
         if (cond)
            branch = BLNE_INS
         else
            branch = BLEQ_INS
      when (FLOAT_MODE, LONG_FLOAT_MODE)
         if (cond)
            branch = BFNE_INS
         else
            branch = BFEQ_INS
   else
      call panic ("*i:  bad convert destination mode in flow*n"p,
         Tmem (expr + 2))

   flow_convert = seq (flow_convert, gen_branch (branch, label))

   return
   end



# flow_if --- evaluate conditional expression, flow on result

   ipointer function flow_if (expr, regs, cond, label)
   tpointer expr
   regset regs
   logical cond
   unsigned label

   include VCG_COMMON

   ipointer flow, flow, gen_generic, gen_mr, gen_label, seq

   integer else_lab, exit_lab, ad (ADDR_DESC_SIZE)
   integer mklabel

   regset cregs, tregs, eregs

   if (Tmem (expr + 4) == 0) {         # no 'else' part
      exit_lab = mklabel (1)
      flow_if = seq (flow (Tmem (expr + 2), cregs, FALSE, exit_lab),
         flow (Tmem (expr + 3), tregs, cond, label),
         gen_label (exit_lab))
      eregs = 0
      }
   else if (Tmem (expr + 3) == 0) {    # no 'then' part
      exit_lab = mklabel (1)
      flow_if = seq (flow (Tmem (expr + 2), cregs, TRUE, exit_lab),
         flow (Tmem (expr + 4), eregs, cond, label),
         gen_label (exit_lab))
      tregs = 0
      }
   else {                              # general case
      else_lab = mklabel (1)
      exit_lab = mklabel (1)
      AD_MODE (ad) = LABELED_AM
      AD_LABEL (ad) = exit_lab
      flow_if = seq (flow (Tmem (expr + 2), cregs, FALSE, else_lab),
         flow (Tmem (expr + 3), tregs, cond, label),
         gen_mr (JMP_INS, ad), gen_generic (FIN_INS),
         gen_label (else_lab),
         flow (Tmem (expr + 4), eregs, cond, label),
         gen_label (exit_lab))
      }

   regs = or (cregs, or (tregs, eregs))

   return
   end



# flow_sand --- pass flow-of-control down a sequence of conjunctions

   ipointer function flow_sand (expr, regs, cond, label)
   tpointer expr
   regset regs
   logical cond
   unsigned label

   include VCG_COMMON

   ipointer flow, seq, gen_label

   integer lab
   integer mklabel

   regset lregs, rregs

   if (cond) {
      lab = mklabel (1)
      flow_sand = flow (Tmem (expr + 2), lregs, FALSE, lab)
      flow_sand = seq (flow_sand,
         flow (Tmem (expr + 3), rregs, TRUE, label),
         gen_label (lab))
      }
   else {
      flow_sand = flow (Tmem (expr + 2), lregs, FALSE, label)
      flow_sand = seq (flow_sand,
         flow (Tmem (expr + 3), rregs, FALSE, label))
      }

   regs = or (lregs, rregs)
   return
   end



# flow_seq --- pass control flow context down a sequence

   ipointer function flow_seq (expr, regs, cond, label)
   tpointer expr
   regset regs
   logical cond
   unsigned label

   include VCG_COMMON

   ipointer void, flow, seq

   regset lregs, rregs

   if (Tmem (expr + 2) ~= 0) {
      flow_seq = void (Tmem (expr + 1), lregs)
      flow_seq = seq (flow_seq, flow (Tmem (expr + 2), rregs, cond, label))
      regs = or (lregs, rregs)
      }
   else
      flow_seq = flow (Tmem (expr + 1), regs, cond, label)

   return
   end



# flow_sor --- pass flow-of-control down a sequence of disjunctions

   ipointer function flow_sor (expr, regs, cond, label)
   tpointer expr
   regset regs
   logical cond
   unsigned label

   include VCG_COMMON

   ipointer flow, seq, gen_label

   integer lab
   integer mklabel

   regset lregs, rregs

   if (cond) {
      flow_sor = flow (Tmem (expr + 2), lregs, TRUE, label)
      flow_sor = seq (flow_sor,
         flow (Tmem (expr + 3), rregs, TRUE, label))
      }
   else {
      lab = mklabel (1)
      flow_sor = flow (Tmem (expr + 2), lregs, TRUE, lab)
      flow_sor = seq (flow_sor,
         flow (Tmem (expr + 3), rregs, FALSE, label),
         gen_label (lab))
      }

   regs = or (lregs, rregs)
   return
   end



# flow_switch --- use multiway branch to determine control flow

   ipointer function flow_switch (expr, regs, cond, label)
   tpointer expr
   regset regs
   logical cond
   unsigned label

   include VCG_COMMON

   ipointer load, seq

   integer branch

   flow_switch = load (expr, regs)

   select (Tmem (expr + 1))
      when (INT_MODE, UNS_MODE)
         if (cond)
            branch = BNE_INS
         else
            branch = BEQ_INS
      when (LONG_INT_MODE, LONG_UNS_MODE)
         if (cond)
            branch = BLNE_INS
         else
            branch = BLEQ_INS
      when (FLOAT_MODE, LONG_FLOAT_MODE)
         if (cond)
            branch = BFNE_INS
         else
            branch = BFEQ_INS
   else
      call panic ("*i:  bad switch data mode in flow*n"p,
         Tmem (expr + 2))

   flow_switch = seq (flow_switch, gen_branch (branch, label))
   return
   end



# flow_eq --- branch on equality

   ipointer function flow_eq (expr, regs, cond, label)
   tpointer expr
   regset regs
   logical cond
   unsigned label

   include VCG_COMMON

   ipointer l, r
   ipointer seq, gen_mr, gen_branch, ld, st, reach, flow

   tpointer right_op, left_op

   integer subtract, branch, opsize, lres, rres, lad (ADDR_DESC_SIZE),
      rad (ADDR_DESC_SIZE), tad (ADDR_DESC_SIZE)

   regset lregs, rregs, opreg

   logical safe

   procedure p1 forward
   procedure p2 forward
   procedure p3 forward

   left_op = Tmem (expr + 2)
   right_op = Tmem (expr + 3)

   select (Tmem (expr + 1))
      when (INT_MODE, UNS_MODE) {
         if (Tmem (right_op) == CONST_OP && Tmem (right_op + 3) == 0)
            return (flow (left_op, regs, ~cond, label))
         if (Tmem (left_op) == CONST_OP && Tmem (left_op + 3) == 0)
            return (flow (right_op, regs, ~cond, label))
         subtract = SUB_INS
         opreg = A_REG
         opsize = 1
         }
      when (LONG_INT_MODE, LONG_UNS_MODE) {
         if (Tmem (right_op) == CONST_OP && Tmem (right_op + 3) == 0
           && Tmem (right_op + 4) == 0)
            return (flow (left_op, regs, ~cond, label))
         if (Tmem (left_op) == CONST_OP && Tmem (left_op + 3) == 0
           && Tmem (left_op + 4) == 0)
            return (flow (right_op, regs, ~cond, label))
         subtract = SBL_INS
         opreg = L_REG
         opsize = 2
         }
      when (FLOAT_MODE) {
         if (Tmem (right_op) == CONST_OP && Tmem (right_op + 3) == 0
           && Tmem (right_op + 4) == 0)
            return (flow (left_op, regs, ~cond, label))
         if (Tmem (left_op) == CONST_OP && Tmem (left_op + 3) == 0
           && Tmem (left_op + 4) == 0)
            return (flow (right_op, regs, ~cond, label))
         subtract = FSB_INS
         opreg = F_REG
         opsize = 2
         }
      when (LONG_FLOAT_MODE) {
         if (Tmem (right_op) == CONST_OP && Tmem (right_op + 3) == 0
           && Tmem (right_op + 4) == 0 && Tmem (right_op + 5) == 0
           && Tmem (right_op + 6) == 0)
            return (flow (left_op, regs, ~cond, label))
         if (Tmem (left_op) == CONST_OP && Tmem (left_op + 3) == 0
           && Tmem (left_op + 4) == 0 && Tmem (left_op + 5) == 0
           && Tmem (left_op + 6) == 0)
            return (flow (right_op, regs, ~cond, label))
         subtract = DFSB_INS
         opreg = LF_REG
         opsize = 4
         }
   else
      call panic ("*i: bad flow EQ data mode*n"p, Tmem (expr + 1))

   r = reach (Tmem (expr + 3), rregs, rres, rad)

   call alloc_temp (opsize, tad)

   l = reach (Tmem (expr + 2), lregs, lres, lad)

   select
      when (safe (opreg, lregs) && safe (opreg, rregs))
         p1
      when (safe (opreg, lregs) && ~safe (opreg, rregs))
         p2
      when (~safe (opreg, lregs) && safe (opreg, rregs))
         p1
   else
      p3

   call free_temp (tad)

   regs = or (opreg, or (lregs, rregs))
   return


   procedure p1 {
      select (Tmem (expr + 1))
         when (INT_MODE, LONG_INT_MODE)
            if (cond)
               branch = BCEQ_INS
            else
               branch = BCNE_INS
         when (UNS_MODE, LONG_UNS_MODE)
            if (cond)
               branch = BMEQ_INS
            else
               branch = BMNE_INS
         when (FLOAT_MODE, LONG_FLOAT_MODE)
            if (cond)
               branch = BFEQ_INS
            else
               branch = BFNE_INS
      flow_eq = seq (l, ld (opreg, lres, lad), r,
         gen_mr (subtract, rad), gen_branch (branch, label))
      }


   procedure p2 {
      select (Tmem (expr + 1))
         when (INT_MODE, LONG_INT_MODE)
            if (cond)
               branch = BCEQ_INS
            else
               branch = BCNE_INS
         when (UNS_MODE, LONG_UNS_MODE)
            if (cond)
               branch = BMEQ_INS
            else
               branch = BMNE_INS
         when (FLOAT_MODE, LONG_FLOAT_MODE)
            if (cond)
               branch = BFEQ_INS
            else
               branch = BFNE_INS
      flow_eq = seq (r, ld (opreg, rres, rad), l,
         gen_mr (subtract, lad), gen_branch (branch, label))
      }


   procedure p3 {
      select (Tmem (expr + 1))
         when (INT_MODE, LONG_INT_MODE)
            if (cond)
               branch = BCEQ_INS
            else
               branch = BCNE_INS
         when (UNS_MODE, LONG_UNS_MODE)
            if (cond)
               branch = BMEQ_INS
            else
               branch = BMNE_INS
         when (FLOAT_MODE, LONG_FLOAT_MODE)
            if (cond)
               branch = BFEQ_INS
            else
               branch = BFNE_INS
      flow_eq = seq (r, ld (opreg, rres, rad))
      flow_eq = seq (flow_eq, st (opreg, tad), l, ld (opreg, lres, lad),
         gen_mr (subtract, tad), gen_branch (branch, label))
      }


   end



# flow_ge --- branch on greater-or-equal

   ipointer function flow_ge (expr, regs, cond, label)
   tpointer expr
   regset regs
   logical cond
   unsigned label

   include VCG_COMMON

   ipointer l, r
   ipointer seq, gen_mr, gen_branch, ld, st, reach, flow, load, void

   integer subtract, branch, opsize, lres, rres, lad (ADDR_DESC_SIZE),
      rad (ADDR_DESC_SIZE), tad (ADDR_DESC_SIZE)

   regset lregs, rregs, opreg

   logical safe

   tpointer right_op, left_op

   procedure p1 forward
   procedure p2 forward
   procedure p3 forward

   left_op = Tmem (expr + 2)
   right_op = Tmem (expr + 3)

   select (Tmem (expr + 1))
      when (INT_MODE) {
         if (Tmem (right_op) == CONST_OP
           && Tmem (right_op + 3) == 0)
            if (cond)
            return (seq (load (left_op, regs), gen_branch (BGE_INS, label)))
            else
            return (seq (load (left_op, regs), gen_branch (BLT_INS, label)))
         if (Tmem (left_op) == CONST_OP
           && Tmem (left_op + 3) == 0)
            if (cond)
            return (seq (load (right_op, regs), gen_branch (BLE_INS, label)))
            else
            return (seq (load (right_op, regs), gen_branch (BGT_INS, label)))
         subtract = SUB_INS
         opreg = A_REG
         opsize = 1
         }
      when (UNS_MODE) {
         if (Tmem (right_op) == CONST_OP
           && Tmem (right_op + 3) == 0)
            if (cond) {
               AD_MODE (tad) = LABELED_AM
               AD_LABEL (tad) = label
               return (seq (void (left_op, regs), gen_mr (JMP_INS, tad)))
               }
            else
               return (void (left_op, regs))
         if (Tmem (left_op) == CONST_OP
           && Tmem (left_op + 3) == 0)
            if (cond)
            return (seq (load (right_op, regs), gen_branch (BEQ_INS, label)))
            else
            return (seq (load (right_op, regs), gen_branch (BNE_INS, label)))
         subtract = SUB_INS
         opreg = A_REG
         opsize = 1
         }
      when (LONG_INT_MODE) {
         if (Tmem (right_op) == CONST_OP
           && Tmem (right_op + 3) == 0 && Tmem (right_op + 4) == 0)
            if (cond)
            return (seq (load (left_op, regs), gen_branch (BLGE_INS, label)))
            else
            return (seq (load (left_op, regs), gen_branch (BLLT_INS, label)))
         if (Tmem (left_op) == CONST_OP
           && Tmem (left_op + 3) == 0 && Tmem (left_op + 4) == 0)
            if (cond)
            return (seq (load (right_op, regs), gen_branch (BLLE_INS, label)))
            else
            return (seq (load (right_op, regs), gen_branch (BLGT_INS, label)))
         subtract = SBL_INS
         opreg = L_REG
         opsize = 2
         }
      when (LONG_UNS_MODE) {
         if (Tmem (right_op) == CONST_OP
           && Tmem (right_op + 3) == 0 && Tmem (right_op + 4) == 0)
            if (cond) {
               AD_MODE (tad) = LABELED_AM
               AD_LABEL (tad) = label
               return (seq (void (left_op, regs), gen_mr (JMP_INS, tad)))
               }
            else
               return (void (left_op, regs))
         if (Tmem (left_op) == CONST_OP
           && Tmem (left_op + 3) == 0 && Tmem (left_op + 4) == 0)
            if (cond)
            return (seq (load (right_op, regs), gen_branch (BLEQ_INS, label)))
            else
            return (seq (load (right_op, regs), gen_branch (BLNE_INS, label)))
         subtract = SBL_INS
         opreg = L_REG
         opsize = 1
         }
      when (FLOAT_MODE) {
         if (Tmem (right_op) == CONST_OP
           && Tmem (right_op + 3) == 0 && Tmem (right_op + 4) == 0)
            if (cond)
            return (seq (load (left_op, regs), gen_branch (BFGE_INS, label)))
            else
            return (seq (load (left_op, regs), gen_branch (BFLT_INS, label)))
         if (Tmem (left_op) == CONST_OP
           && Tmem (left_op + 3) == 0 && Tmem (left_op + 4) == 0)
            if (cond)
            return (seq (load (right_op, regs), gen_branch (BFLE_INS, label)))
            else
            return (seq (load (right_op, regs), gen_branch (BFGT_INS, label)))
         subtract = FSB_INS
         opreg = F_REG
         opsize = 2
         }
      when (LONG_FLOAT_MODE) {
         if (Tmem (right_op) == CONST_OP
           && Tmem (right_op + 3) == 0 && Tmem (right_op + 4) == 0
           && Tmem (right_op + 5) == 0 && Tmem (right_op + 6) == 0)
            if (cond)
            return (seq (load (left_op, regs), gen_branch (BFGE_INS, label)))
            else
            return (seq (load (left_op, regs), gen_branch (BFLT_INS, label)))
         if (Tmem (left_op) == CONST_OP
           && Tmem (left_op + 3) == 0 && Tmem (left_op + 4) == 0
           && Tmem (left_op + 5) == 0 && Tmem (left_op + 6) == 0)
            if (cond)
            return (seq (load (right_op, regs), gen_branch (BFLE_INS, label)))
            else
            return (seq (load (right_op, regs), gen_branch (BFGT_INS, label)))
         subtract = DFSB_INS
         opreg = LF_REG
         opsize = 4
         }
   else
      call panic ("*i: bad flow GE data mode*n"p, Tmem (expr + 1))

   r = reach (Tmem (expr + 3), rregs, rres, rad)

   call alloc_temp (opsize, tad)

   l = reach (Tmem (expr + 2), lregs, lres, lad)

   select
      when (safe (opreg, lregs) && safe (opreg, rregs))
         p1
      when (safe (opreg, lregs) && ~safe (opreg, rregs))
         p2
      when (~safe (opreg, lregs) && safe (opreg, rregs))
         p1
   else
      p3

   call free_temp (tad)

   regs = or (opreg, or (lregs, rregs))
   return


   procedure p1 {
      select (Tmem (expr + 1))
         when (INT_MODE, LONG_INT_MODE)
            if (cond)
               branch = BCGE_INS
            else
               branch = BCLT_INS
         when (UNS_MODE, LONG_UNS_MODE)
            if (cond)
               branch = BMGE_INS
            else
               branch = BMLT_INS
         when (FLOAT_MODE, LONG_FLOAT_MODE)
            if (cond)
               branch = BFGE_INS
            else
               branch = BFLT_INS
      flow_ge = seq (l, ld (opreg, lres, lad), r,
         gen_mr (subtract, rad), gen_branch (branch, label))
      }


   procedure p2 {
      select (Tmem (expr + 1))
         when (INT_MODE, LONG_INT_MODE)
            if (cond)
               branch = BCLE_INS
            else
               branch = BCGT_INS
         when (UNS_MODE, LONG_UNS_MODE)
            if (cond)
               branch = BMLE_INS
            else
               branch = BMGT_INS
         when (FLOAT_MODE, LONG_FLOAT_MODE)
            if (cond)
               branch = BFLE_INS
            else
               branch = BFGT_INS
      flow_ge = seq (r, ld (opreg, rres, rad), l,
         gen_mr (subtract, lad), gen_branch (branch, label))
      }


   procedure p3 {
      select (Tmem (expr + 1))
         when (INT_MODE, LONG_INT_MODE)
            if (cond)
               branch = BCGE_INS
            else
               branch = BCLT_INS
         when (UNS_MODE, LONG_UNS_MODE)
            if (cond)
               branch = BMGE_INS
            else
               branch = BMLT_INS
         when (FLOAT_MODE, LONG_FLOAT_MODE)
            if (cond)
               branch = BFGE_INS
            else
               branch = BFLT_INS
      flow_ge = seq (r, ld (opreg, rres, rad))
      flow_ge = seq (flow_ge, st (opreg, tad), l, ld (opreg, lres, lad),
         gen_mr (subtract, tad), gen_branch (branch, label))
      }


   end
