Exemple #1
0
void LoopTreeOptimization::analyzeCurrentLoop(
    std::unique_ptr<LoopNestSummary> &CurrSummary, ReadSet &SafeReads) {
  WriteSet &MayWrites = CurrSummary->MayWrites;
  SILLoop *Loop = CurrSummary->Loop;
  DEBUG(llvm::dbgs() << " Analyzing accesses.\n");

  // Contains function calls in the loop, which only read from memory.
  SmallVector<ApplyInst *, 8> ReadOnlyApplies;

  for (auto *BB : Loop->getBlocks()) {
    for (auto &Inst : *BB) {
      // Ignore fix_lifetime instructions.
      if (isa<FixLifetimeInst>(&Inst))
        continue;

      // Collect loads.
      auto LI = dyn_cast<LoadInst>(&Inst);
      if (LI) {
        if (!mayWriteTo(AA, MayWrites, LI))
          SafeReads.insert(LI);
        continue;
      }
      if (auto *AI = dyn_cast<ApplyInst>(&Inst)) {
        // In contrast to load instructions, we first collect all read-only
        // function calls and add them later to SafeReads.
        SideEffectAnalysis::FunctionEffects E;
        SEA->getEffects(E, AI);

        auto MB = E.getMemBehavior(RetainObserveKind::ObserveRetains);
        if (MB <= SILInstruction::MemoryBehavior::MayRead)
          ReadOnlyApplies.push_back(AI);
      }
      if (Inst.mayHaveSideEffects()) {
        MayWrites.push_back(&Inst);
        // Remove clobbered loads we have seen before.
        removeWrittenTo(AA, SafeReads, &Inst);
      }
    }
  }
  for (auto *AI : ReadOnlyApplies) {
    if (!mayWriteTo(AA, SEA, MayWrites, AI))
      SafeReads.insert(AI);
  }
}
Exemple #2
0
// Analyzes current loop for hosting/sinking potential:
// Computes set of instructions we may be able to move out of the loop
// Important Note:
// We can't bail out of this method! we have to run it on all loops.
// We *need* to discover all MayWrites -
// even if the loop is otherwise skipped!
// This is because outer loops will depend on the inner loop's writes.
void LoopTreeOptimization::analyzeCurrentLoop(
    std::unique_ptr<LoopNestSummary> &CurrSummary) {
  WriteSet &MayWrites = CurrSummary->MayWrites;
  SILLoop *Loop = CurrSummary->Loop;
  LLVM_DEBUG(llvm::dbgs() << " Analyzing accesses.\n");

  // Contains function calls in the loop, which only read from memory.
  SmallVector<ApplyInst *, 8> ReadOnlyApplies;
  // Contains Loads inside the loop.
  SmallVector<LoadInst *, 8> Loads;
  // Contains fix_lifetime, we might be able to sink them.
  SmallVector<FixLifetimeInst *, 8> FixLifetimes;
  // Contains begin_access, we might be able to hoist them.
  SmallVector<BeginAccessInst *, 8> BeginAccesses;
  // Contains all applies - used for begin_access
  SmallVector<FullApplySite, 8> fullApplies;

  for (auto *BB : Loop->getBlocks()) {
    for (auto &Inst : *BB) {
      switch (Inst.getKind()) {
      case SILInstructionKind::FixLifetimeInst: {
        auto *FL = dyn_cast<FixLifetimeInst>(&Inst);
        assert(FL && "Expected a FixLifetime instruction");
        FixLifetimes.push_back(FL);
        // We can ignore the side effects of FixLifetimes
        break;
      }
      case SILInstructionKind::LoadInst: {
        auto *LI = dyn_cast<LoadInst>(&Inst);
        assert(LI && "Expected a Load instruction");
        Loads.push_back(LI);
        break;
      }
      case SILInstructionKind::BeginAccessInst: {
        auto *BI = dyn_cast<BeginAccessInst>(&Inst);
        assert(BI && "Expected a Begin Access");
        BeginAccesses.push_back(BI);
        checkSideEffects(Inst, MayWrites);
        break;
      }
      case SILInstructionKind::RefElementAddrInst: {
        auto *REA = static_cast<RefElementAddrInst *>(&Inst);
        SpecialHoist.push_back(REA);
        break;
      }
      case swift::SILInstructionKind::CondFailInst: {
        // We can (and must) hoist cond_fail instructions if the operand is
        // invariant. We must hoist them so that we preserve memory safety. A
        // cond_fail that would have protected (executed before) a memory access
        // must - after hoisting - also be executed before said access.
        HoistUp.insert(&Inst);
        checkSideEffects(Inst, MayWrites);
        break;
      }
      case SILInstructionKind::ApplyInst: {
        auto *AI = dyn_cast<ApplyInst>(&Inst);
        assert(AI && "Expected an Apply Instruction");
        if (isSafeReadOnlyApply(SEA, AI)) {
          ReadOnlyApplies.push_back(AI);
        }
        // check for array semantics and side effects - same as default
        LLVM_FALLTHROUGH;
      }
      default: {
        if (auto fullApply = FullApplySite::isa(&Inst)) {
          fullApplies.push_back(fullApply);
        }
        checkSideEffects(Inst, MayWrites);
        if (canHoistUpDefault(&Inst, Loop, DomTree, RunsOnHighLevelSIL)) {
          HoistUp.insert(&Inst);
        }
        break;
      }
      }
    }
  }

  auto *Preheader = Loop->getLoopPreheader();
  if (!Preheader) {
    // Can't hoist/sink instructions
    return;
  }
  for (auto *AI : ReadOnlyApplies) {
    if (!mayWriteTo(AA, SEA, MayWrites, AI)) {
      HoistUp.insert(AI);
    }
  }
  for (auto *LI : Loads) {
    if (!mayWriteTo(AA, MayWrites, LI)) {
      HoistUp.insert(LI);
    }
  }
  bool mayWritesMayRelease =
      std::any_of(MayWrites.begin(), MayWrites.end(),
                  [&](SILInstruction *W) { return W->mayRelease(); });
  for (auto *FL : FixLifetimes) {
    if (!DomTree->dominates(FL->getOperand()->getParentBlock(), Preheader)) {
      continue;
    }
    if (!mayWriteTo(AA, MayWrites, FL) || !mayWritesMayRelease) {
      SinkDown.push_back(FL);
    }
  }
  for (auto *BI : BeginAccesses) {
    if (!handledEndAccesses(BI, Loop)) {
      LLVM_DEBUG(llvm::dbgs() << "Skipping: " << *BI);
      LLVM_DEBUG(llvm::dbgs() << "Some end accesses can't be handled\n");
      continue;
    }
    if (analyzeBeginAccess(BI, BeginAccesses, fullApplies, MayWrites, ASA,
                           DomTree)) {
      SpecialHoist.push_back(BI);
    }
  }
}