// hasPredicatedRegion is true iff the block or its targets are predicated
  // (i.e. we enter, stay within or exit a predicated region).
  void PredicateTransferCmd(Expr p, Block src, List<Cmd> cmdSeq, TransferCmd cmd, out bool hasPredicatedRegion) {
    hasPredicatedRegion = predMap.ContainsKey(src);

    if (cmd is GotoCmd) {
      var gCmd = (GotoCmd)cmd;

      hasPredicatedRegion = hasPredicatedRegion ||
        gCmd.labelTargets.Cast<Block>().Any(b => predMap.ContainsKey(b));

      if (gCmd.labelTargets.Count == 1) {
        if (defMap.ContainsKey(gCmd.labelTargets[0])) {
          PredicateCmd(p, Expr.True, cmdSeq,
                       Cmd.SimpleAssign(Token.NoToken,
                                        Expr.Ident(predMap[gCmd.labelTargets[0]]), Expr.True));
        }
      } else {
        Debug.Assert(gCmd.labelTargets.Count > 1);
        Debug.Assert(gCmd.labelTargets.Cast<Block>().All(t => uni.IsUniform(impl.Name, t) ||
                                                              partInfo.ContainsKey(t)));
        foreach (Block target in gCmd.labelTargets) {
          if (!partInfo.ContainsKey(target))
            continue;

          // In this case we not only predicate with the current predicate p,
          // but also with the "part predicate"; this ensures that we do not
          // update a predicate twice when it occurs in both parts.
          var part = partInfo[target];
          if (defMap.ContainsKey(part.realDest)) {
            PredicateCmd(p == null ? part.pred : Expr.And(p, part.pred), Expr.True, cmdSeq,
                         Cmd.SimpleAssign(Token.NoToken,
                                          Expr.Ident(predMap[part.realDest]), part.pred));
          }
          var predsExitingLoop = new Dictionary<Block, List<Expr>>();
          foreach (Block exit in LoopsExited(src, target)) {
            List<Expr> predList;
            if (!predsExitingLoop.ContainsKey(exit))
              predList = predsExitingLoop[exit] = new List<Expr>();
            else
              predList = predsExitingLoop[exit];
            predList.Add(part.pred);
          }
          foreach (var pred in predsExitingLoop) {
            PredicateCmd(p == null ? part.pred : Expr.And(p, part.pred), Expr.True, cmdSeq,
                         Cmd.SimpleAssign(Token.NoToken,
                                          Expr.Ident(predMap[pred.Key]),
                                          Expr.Not(pred.Value.Aggregate(Expr.Or))));
          }
        }
      }
    } else if (cmd is ReturnCmd) {
      // Blocks which end in a return will never share a predicate with a block
      // which appears after it.  Furthermore, such a block cannot be part of a
      // loop.  So it is safe to do nothing here.
    } else {
      Console.WriteLine("Unsupported cmd: " + cmd.GetType().ToString());
    }
  }
        void PredicateTransferCmd(List<Cmd> cmdSeq, TransferCmd cmd)
        {
            if (cmd is GotoCmd) {
              var gCmd = (GotoCmd)cmd;
              var targets = new List<Expr>(
            gCmd.labelTargets.Cast<Block>().Select(b => blockIds[b]));
              if (targets.Count == 1) {
            PredicateCmd(cmdSeq, Cmd.SimpleAssign(Token.NoToken, cur, targets[0]));
              } else {
            PredicateCmd(cmdSeq, new HavocCmd(Token.NoToken,
                                          new List<IdentifierExpr> { cur }));
            PredicateCmd(cmdSeq, new AssumeCmd(Token.NoToken,
               targets.Select(t => (Expr)Expr.Eq(cur, t)).Aggregate(Expr.Or)));
              }

              foreach (Block b in gCmd.labelTargets) {
            if (blockGraph.Predecessors(b).Count() == 1) {
              if (!doneBlocks.Contains(b)) {
            var assumes = b.Cmds.Cast<Cmd>().TakeWhile(c => c is AssumeCmd);
            if (assumes.Count() > 0) {
              foreach (AssumeCmd aCmd in assumes) {
                cmdSeq.Add(new AssumeCmd(Token.NoToken,
                                         Expr.Imp(Expr.Eq(cur, blockIds[b]),
                                         aCmd.Expr)));
              }
              b.Cmds =
                new List<Cmd>(b.Cmds.Cast<Cmd>().Skip(assumes.Count()).ToArray());
            }
              }
            }
              }
            } else if (cmd is ReturnCmd) {
              PredicateCmd(cmdSeq, Cmd.SimpleAssign(Token.NoToken, cur, returnBlockId));
            } else {
              Console.WriteLine("Unsupported cmd: " + cmd.GetType().ToString());
            }
        }