private void processExprent(Exprent expr, SFormsFastMapDirect[] varmaparr, Statement stat, boolean calcLiveVars) {

    if (expr == null) {
      return;
    }


    VarExprent varassign = null;
    boolean finished = false;

    switch (expr.type) {
      case Exprent.EXPRENT_ASSIGNMENT -> {
        AssignmentExprent assexpr = (AssignmentExprent)expr;
        if (assexpr.getCondType() == AssignmentExprent.CONDITION_NONE) {
          Exprent dest = assexpr.getLeft();
          if (dest.type == Exprent.EXPRENT_VAR) {
            varassign = (VarExprent)dest;
          }
        }
      }
      case Exprent.EXPRENT_FUNCTION -> {
        FunctionExprent func = (FunctionExprent)expr;
        switch (func.getFuncType()) {
          case FunctionExprent.FUNCTION_IIF -> {
            processExprent(func.getLstOperands().get(0), varmaparr, stat, calcLiveVars);

            SFormsFastMapDirect varmapFalse;
            if (varmaparr[1] == null) {
              varmapFalse = new SFormsFastMapDirect(varmaparr[0]);
            }
            else {
              varmapFalse = varmaparr[1];
              varmaparr[1] = null;
            }

            processExprent(func.getLstOperands().get(1), varmaparr, stat, calcLiveVars);

            SFormsFastMapDirect[] varmaparrNeg = new SFormsFastMapDirect[]{varmapFalse, null};
            processExprent(func.getLstOperands().get(2), varmaparrNeg, stat, calcLiveVars);

            mergeMaps(varmaparr[0], varmaparrNeg[0]);
            varmaparr[1] = null;

            finished = true;
          }
          case FunctionExprent.FUNCTION_CADD -> {
            processExprent(func.getLstOperands().get(0), varmaparr, stat, calcLiveVars);

            SFormsFastMapDirect[] varmaparrAnd = new SFormsFastMapDirect[]{new SFormsFastMapDirect(varmaparr[0]), null};

            processExprent(func.getLstOperands().get(1), varmaparrAnd, stat, calcLiveVars);

            // false map
            varmaparr[1] = mergeMaps(varmaparr[varmaparr[1] == null ? 0 : 1], varmaparrAnd[varmaparrAnd[1] == null ? 0 : 1]);
            // true map
            varmaparr[0] = varmaparrAnd[0];

            finished = true;
          }
          case FunctionExprent.FUNCTION_COR -> {
            processExprent(func.getLstOperands().get(0), varmaparr, stat, calcLiveVars);

            SFormsFastMapDirect[] varmaparrOr =
              new SFormsFastMapDirect[]{new SFormsFastMapDirect(varmaparr[varmaparr[1] == null ? 0 : 1]), null};

            processExprent(func.getLstOperands().get(1), varmaparrOr, stat, calcLiveVars);

            // false map
            varmaparr[1] = varmaparrOr[varmaparrOr[1] == null ? 0 : 1];
            // true map
            varmaparr[0] = mergeMaps(varmaparr[0], varmaparrOr[0]);

            finished = true;
          }
        }
      }
    }

    if (!finished) {
      List<Exprent> lst = expr.getAllExprents();
      lst.remove(varassign);

      for (Exprent ex : lst) {
        processExprent(ex, varmaparr, stat, calcLiveVars);
      }
    }


    SFormsFastMapDirect varmap = varmaparr[0];

    // field access
    if (expr.type == Exprent.EXPRENT_FIELD) {

      int index;
      if (mapFieldVars.containsKey(expr.id)) {
        index = mapFieldVars.get(expr.id);
      }
      else {
        index = fieldvarcounter--;
        mapFieldVars.put(expr.id, index);

        // ssu graph
        ssuversions.createNode(new VarVersionPair(index, 1));
      }

      setCurrentVar(varmap, index, 1);
    }
    else if (expr.type == Exprent.EXPRENT_INVOCATION ||
             (expr.type == Exprent.EXPRENT_ASSIGNMENT && ((AssignmentExprent)expr).getLeft().type == Exprent.EXPRENT_FIELD) ||
             (expr.type == Exprent.EXPRENT_NEW && ((NewExprent)expr).getNewType().getType() == CodeConstants.TYPE_OBJECT) ||
             expr.type == Exprent.EXPRENT_FUNCTION) {

      boolean ismmpp = true;

      if (expr.type == Exprent.EXPRENT_FUNCTION) {

        ismmpp = false;

        FunctionExprent fexpr = (FunctionExprent)expr;
        if (fexpr.getFuncType() >= FunctionExprent.FUNCTION_IMM && fexpr.getFuncType() <= FunctionExprent.FUNCTION_PPI) {
          if (fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD) {
            ismmpp = true;
          }
        }
      }

      if (ismmpp) {
        varmap.removeAllFields();
      }
    }


    if (varassign != null) {

      Integer varindex = varassign.getIndex();

      if (varassign.getVersion() == 0) {
        // get next version
        Integer nextver = getNextFreeVersion(varindex, stat);

        // set version
        varassign.setVersion(nextver);

        // ssu graph
        ssuversions.createNode(new VarVersionPair(varindex, nextver));

        setCurrentVar(varmap, varindex, nextver);
      }
      else {
        if (calcLiveVars) {
          varMapToGraph(new VarVersionPair(varindex.intValue(), varassign.getVersion()), varmap);
        }
        setCurrentVar(varmap, varindex, varassign.getVersion());
      }
    }
    else if (expr.type == Exprent.EXPRENT_FUNCTION) { // MM or PP function
      FunctionExprent func = (FunctionExprent)expr;

      switch (func.getFuncType()) {
        case FunctionExprent.FUNCTION_IMM, FunctionExprent.FUNCTION_MMI, FunctionExprent.FUNCTION_IPP, FunctionExprent.FUNCTION_PPI -> {
          if (func.getLstOperands().get(0).type == Exprent.EXPRENT_VAR) {
            VarExprent var = (VarExprent)func.getLstOperands().get(0);
            Integer varindex = var.getIndex();
            VarVersionPair varpaar = new VarVersionPair(varindex.intValue(), var.getVersion());

            // ssu graph
            VarVersionPair phantomver = phantomppnodes.get(varpaar);
            if (phantomver == null) {
              // get next version
              Integer nextver = getNextFreeVersion(varindex, null);
              phantomver = new VarVersionPair(varindex, nextver);
              //ssuversions.createOrGetNode(phantomver);
              ssuversions.createNode(phantomver);

              VarVersionNode vernode = ssuversions.nodes.getWithKey(varpaar);

              FastSparseSet<Integer> vers = factory.spawnEmptySet();
              if (vernode.predecessors.size() == 1) {
                vers.add(vernode.predecessors.iterator().next().source.version);
              }
              else {
                for (VarVersionEdge edge : vernode.predecessors) {
                  vers.add(edge.source.predecessors.iterator().next().source.version);
                }
              }
              vers.add(nextver);
              createOrUpdatePhiNode(varpaar, vers, stat);
              phantomppnodes.put(varpaar, phantomver);
            }
            if (calcLiveVars) {
              varMapToGraph(varpaar, varmap);
            }
            setCurrentVar(varmap, varindex, var.getVersion());
          }
        }
      }
    }
    else if (expr.type == Exprent.EXPRENT_VAR) {

      VarExprent vardest = (VarExprent)expr;

      Integer varindex = vardest.getIndex();
      Integer current_vers = vardest.getVersion();

      FastSparseSet<Integer> vers = varmap.get(varindex);

      int cardinality = vers.getCardinality();
      if (cardinality == 1) { // size == 1
        if (current_vers != 0) {
          if (calcLiveVars) {
            varMapToGraph(new VarVersionPair(varindex, current_vers), varmap);
          }
          setCurrentVar(varmap, varindex, current_vers);
        }
        else {
          // split last version
          Integer usever = getNextFreeVersion(varindex, stat);

          // set version
          vardest.setVersion(usever);
          setCurrentVar(varmap, varindex, usever);

          // ssu graph
          Integer lastver = vers.iterator().next();
          VarVersionNode prenode = ssuversions.nodes.getWithKey(new VarVersionPair(varindex, lastver));
          VarVersionNode usenode = ssuversions.createNode(new VarVersionPair(varindex, usever));
          VarVersionEdge edge = new VarVersionEdge(VarVersionEdge.EDGE_GENERAL, prenode, usenode);
          prenode.addSuccessor(edge);
          usenode.addPredecessor(edge);
        }
      }
      else if (cardinality == 2) { // size > 1

        if (current_vers != 0) {
          if (calcLiveVars) {
            varMapToGraph(new VarVersionPair(varindex, current_vers), varmap);
          }
          setCurrentVar(varmap, varindex, current_vers);
        }
        else {
          // split version
          Integer usever = getNextFreeVersion(varindex, stat);
          // set version
          vardest.setVersion(usever);

          // ssu node
          ssuversions.createNode(new VarVersionPair(varindex, usever));

          setCurrentVar(varmap, varindex, usever);

          current_vers = usever;
        }

        createOrUpdatePhiNode(new VarVersionPair(varindex, current_vers), vers, stat);
      } // vers.size() == 0 means uninitialized variable, which is impossible
    }
  }
private void processExprent(Exprent expr, SFormsFastMapDirect[] varmaparr, Statement stat, boolean calcLiveVars)