@Override
  public void applyTransferFunction(Instr i) {
    IRScope scope = problem.getScope();
    boolean scopeBindingHasEscaped = scope.bindingHasEscaped();

    // Right away, clear the variable defined by this instruction -- it doesn't have to be loaded!
    if (i instanceof ResultInstr) {
      reqdLoads.remove(((ResultInstr) i).getResult());
    }

    // Process closure accepting instrs specially -- these are the sites of binding loads!
    if (i instanceof ClosureAcceptingInstr) {
      Operand o = ((ClosureAcceptingInstr) i).getClosureArg();
      if (o != null && o instanceof WrappedIRClosure) {
        IRClosure cl = ((WrappedIRClosure) o).getClosure();

        // Variables defined in the closure do not need to be loaded anymore at
        // program points before the call, because they will be loaded after the
        // call completes to fetch the latest value.
        //
        // Allocate a new hash-set and modify it to get around ConcurrentModificationException on
        // reqdLoads
        Set<LocalVariable> newReqdLoads = new HashSet<LocalVariable>(reqdLoads);
        for (LocalVariable v : reqdLoads) {
          if (cl.definesLocalVariable(v)) newReqdLoads.remove(v);
        }
        reqdLoads = newReqdLoads;
      }

      // In this case, we are going to blindly load everything -- so, at the call site, pending
      // loads dont carry over!
      if (scopeBindingHasEscaped) {
        reqdLoads.clear();
      } else {
        // All variables not defined in the current scope have to be always loaded
        // because of multi-threading scenarios where some other scope
        // could update this variable concurrently.
        //
        // Allocate a new hash-set and modify it to get around ConcurrentModificationException on
        // reqdLoads
        Set<LocalVariable> newReqdLoads = new HashSet<LocalVariable>(reqdLoads);
        for (LocalVariable v : reqdLoads) {
          if (!scope.definesLocalVariable(v)) newReqdLoads.remove(v);
        }
        reqdLoads = newReqdLoads;
      }
    } else if (scopeBindingHasEscaped && (i.getOperation() == Operation.PUT_GLOBAL_VAR)) {
      // global-var tracing can execute closures set up in previous trace-var calls
      // in which case we would have the 'scopeBindingHasEscaped' flag set to true
      reqdLoads.clear();
    }

    if (i.getOperation() == Operation.BINDING_STORE) {
      LocalVariable lv = ((StoreLocalVarInstr) i).getLocalVar();
      if (!lv.isSelf()) reqdLoads.add(lv);
    } else {
      // The variables used as arguments will need to be loaded
      // %self is local to every scope and never crosses scope boundaries and need not be
      // spilled/refilled
      for (Variable x : i.getUsedVariables()) {
        if (x instanceof LocalVariable && !x.isSelf()) {
          reqdLoads.add((LocalVariable) x);
        }
      }
    }
  }
  public void addLoads(Map<Operand, Operand> varRenameMap) {
    IRScope scope = problem.getScope();
    boolean isEvalScript = scope instanceof IREvalScript;
    boolean scopeBindingHasEscaped = scope.bindingHasEscaped();

    List<Instr> instrs = basicBlock.getInstrs();
    ListIterator<Instr> it = instrs.listIterator(instrs.size());

    initSolution();
    while (it.hasPrevious()) {
      Instr i = it.previous();

      // Right away, clear the variable defined by this instruction -- it doesn't have to be loaded!
      if (i instanceof ResultInstr) reqdLoads.remove(((ResultInstr) i).getResult());

      // Process closure accepting instrs specially -- these are the sites of binding loads!
      if (i instanceof ClosureAcceptingInstr) {
        Operand o = ((ClosureAcceptingInstr) i).getClosureArg();
        if (o != null && o instanceof WrappedIRClosure) {
          IRClosure cl = ((WrappedIRClosure) o).getClosure();

          // Only those variables that are defined in the closure, and are in the required loads set
          // will need to be loaded from the binding after the call!  Rest can wait ..
          //
          // Allocate a new hash-set and modify it to get around ConcurrentModificationException on
          // reqdLoads
          Set<LocalVariable> newReqdLoads = new HashSet<LocalVariable>(reqdLoads);
          it.next();
          for (LocalVariable v : reqdLoads) {
            if (cl.definesLocalVariable(v)) {
              it.add(
                  new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
              it.previous();
              newReqdLoads.remove(v);
            }
          }
          it.previous();
          reqdLoads = newReqdLoads;
        }

        // In this case, we are going to blindly load everything
        if (scopeBindingHasEscaped) {
          it.next();
          for (LocalVariable v : reqdLoads) {
            it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
            it.previous();
          }
          it.previous();
          reqdLoads.clear();
        } else {
          // All variables not defined in the current scope have to be always loaded
          // because of multi-threading scenarios where some other scope
          // could update this variable concurrently.
          //
          // Allocate a new hash-set and modify it to get around ConcurrentModificationException on
          // reqdLoads
          Set<LocalVariable> newReqdLoads = new HashSet<LocalVariable>(reqdLoads);
          it.next();
          for (LocalVariable v : reqdLoads) {
            if (!scope.definesLocalVariable(v)) {
              it.add(
                  new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
              it.previous();
              newReqdLoads.remove(v);
            }
          }
          it.previous();
          reqdLoads = newReqdLoads;
        }
      } else if (scopeBindingHasEscaped && (i.getOperation() == Operation.PUT_GLOBAL_VAR)) {
        // global-var tracing can execute closures set up in previous trace-var calls
        // in which case we would have the 'scopeBindingHasEscaped' flag set to true
        it.next();
        for (LocalVariable v : reqdLoads) {
          it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
          it.previous();
        }
        it.previous();
        reqdLoads.clear();
      }

      if (i.getOperation() == Operation.BINDING_STORE) {
        LocalVariable lv = ((StoreLocalVarInstr) i).getLocalVar();
        if (!lv.isSelf()) {
          reqdLoads.add(lv);
          // SSS FIXME: Why is this reqd again?  Document with example
          // Make sure there is a replacement var for all local vars
          getLocalVarReplacement(lv, scope, varRenameMap);
        }
      } else {
        // The variables used as arguments will need to be loaded
        // %self is local to every scope and never crosses scope boundaries and need not be
        // spilled/refilled
        for (Variable v : i.getUsedVariables()) {
          if (!(v instanceof LocalVariable)) continue;

          LocalVariable lv = (LocalVariable) v;
          if (!lv.isSelf()) {
            reqdLoads.add(lv);
            // SSS FIXME: Why is this reqd again?  Document with example
            // Make sure there is a replacement var for all local vars
            getLocalVarReplacement(lv, scope, varRenameMap);
          }
        }
      }
    }

    // Add loads on entry of a rescue block.
    if (basicBlock.isRescueEntry()) {
      for (LocalVariable v : reqdLoads) {
        it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
      }
    }

    // Load first use of variables in closures
    if (scope instanceof IRClosure && basicBlock.isEntryBB()) {
      // System.out.println("\n[In Entry BB] For CFG " + getCFG() + ":");
      // System.out.println("\t--> Reqd loads   : " +
      // java.util.Arrays.toString(reqdLoads.toArray()));
      for (LocalVariable v : reqdLoads) {
        if (scope.usesLocalVariable(v) || scope.definesLocalVariable(v)) {
          if (isEvalScript
              || !(v instanceof ClosureLocalVariable)
              || (scope != ((ClosureLocalVariable) v).definingScope)) {
            it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
          }
        }
      }
    }
  }