Esempio n. 1
0
void MemMap::optimizeMemoryAccesses(Trace* trace) {
  StoreList tracking;

  for (IRInstruction* inst : trace->getInstructionList()) {
    // initialize each instruction as live
    inst->setId(LIVE);

    int offset = -1;
    Opcode op = inst->getOpcode();

    if (isLoad(op)) {
      if (op == LdProp) {
        offset = inst->getSrc(1)->getConstValAsInt();
      }

      optimizeLoad(inst, offset);
    } else if (isStore(op)) {
      if (op == StProp || op == StPropNT) {
        offset = inst->getSrc(1)->getConstValAsInt();
      }

      // if we see a store, first check if its last available access is a store
      // if it is, then the last access is a dead store
      IRInstruction* access = getLastAccess(inst->getSrc(0), offset);
      if (access != NULL && isStore(access->getOpcode())) {
        // if a dead St* is followed by a St*NT, then the second store needs to
        // now write in the type because the first store will be removed
        if (access->getOpcode() == StProp && op == StPropNT) {
          inst->setOpcode(StProp);
        } else if (access->getOpcode() == StLoc && op == StLocNT) {
          inst->setOpcode(StLoc);
        } else if (access->getOpcode() == StRef && op == StRefNT) {
          inst->setOpcode(StRef);
        }

        access->setId(DEAD);
      }

      // start tracking the current store
      tracking.push_back(std::make_pair(inst, std::vector<IRInstruction*>()));
    } else if (inst->mayRaiseError()) {
      // if the function has an exit edge that we don't know anything about
      // (raising an error), then all stores we're currently tracking need to
      // be erased. all stores already declared dead are untouched
      StoreList::iterator it, end;
      for (it = tracking.begin(), end = tracking.end(); it != end; ) {
        StoreList::iterator copy = it;
        ++it;
        if (copy->first->getId() != DEAD) {
          // XXX: t1779667
          tracking.erase(copy);
        }
      }
    }

    // if the current instruction is guarded, make sure all of our stores that
    // are not yet dead know about it
    if (inst->getLabel() != NULL) {
      for (auto& entry : tracking) {
        if (entry.first->getId() != DEAD) {
          entry.second.push_back(inst);
        }
      }
    }

    Simplifier::copyProp(inst);
    processInstruction(inst);
  }

  sinkStores(tracking);

  // kill the dead stores
  removeDeadInstructions(trace);
}
Esempio n. 2
0
void MemMap::optimizeMemoryAccesses(Trace* trace) {
  if (hasInternalFlow(trace)) {
    // This algorithm only works with linear traces.
    // TODO t2066994: reset state after each block, at least.
    return;
  }
  StoreList tracking;

  const Func* curFunc = nullptr;

  for (Block* block : trace->getBlocks()) {
    for (IRInstruction& inst : *block) {
      if (inst.getOpcode() == Marker) {
        curFunc = inst.getExtra<Marker>()->func;
      }
      // initialize each instruction as live
      setLive(inst, true);

      int offset = -1;
      Opcode op = inst.getOpcode();

      if (isLoad(op)) {
        if (op == LdProp) {
          offset = inst.getSrc(1)->getValInt();
        }
        // initialize each instruction as live
        setLive(inst, true);

        optimizeLoad(&inst, offset);
      } else if (isStore(op)) {
        if (op == StProp || op == StPropNT) {
          offset = inst.getSrc(1)->getValInt();
        }

        // if we see a store, first check if its last available access is a store
        // if it is, then the last access is a dead store
        auto access = inst.getOpcode() == StLoc || inst.getOpcode() == StLocNT
          ? lastLocalAccess(inst.getExtra<LocalId>()->locId)
          : getLastAccess(inst.getSrc(0), offset);
        if (access && isStore(access->getOpcode())) {
          // if a dead St* is followed by a St*NT, then the second store needs to
          // now write in the type because the first store will be removed
          if (access->getOpcode() == StProp && op == StPropNT) {
            inst.setOpcode(StProp);
          } else if (access->getOpcode() == StLoc && op == StLocNT) {
            inst.setOpcode(StLoc);
          } else if (access->getOpcode() == StRef && op == StRefNT) {
            inst.setOpcode(StRef);
          }

          setLive(*access, false);
        }

        // start tracking the current store
        tracking.push_back(std::make_pair(&inst, std::vector<IRInstruction*>()));
      } else if (inst.mayRaiseError()) {
        // if the function has an exit edge that we don't know anything about
        // (raising an error), then all stores we're currently tracking need to
        // be erased. all stores already declared dead are untouched
        StoreList::iterator it, end;
        for (it = tracking.begin(), end = tracking.end(); it != end; ) {
          StoreList::iterator copy = it;
          ++it;
          if (isLive(copy->first)) {
            // XXX: t1779667
            tracking.erase(copy);
          }
        }
      }

      // if the current instruction is guarded, make sure all of our stores that
      // are not yet dead know about it
      if (inst.getTaken()) {
        for (auto& entry : tracking) {
          if (isLive(entry.first)) {
            entry.second.push_back(&inst);
          }
        }
      }
      Simplifier::copyProp(&inst);
      processInstruction(&inst, curFunc && curFunc->isPseudoMain());
    }
  }

  sinkStores(tracking);

  // kill the dead stores
  removeDeadInstructions(trace, m_liveInsts);
}