Esempio n. 1
0
/// If \p Op has instructions in the instruction range (Start, End] which may
/// decrement it, return the first such instruction. Returns None
/// if no such instruction exists. We assume that Start and End are both in the
/// same basic block.
Optional<SILBasicBlock::iterator>
swift::
valueHasARCDecrementOrCheckInInstructionRange(SILValue Op,
                                              SILBasicBlock::iterator Start,
                                              SILBasicBlock::iterator End,
                                              AliasAnalysis *AA) {
  assert(Start->getParent() == End->getParent() &&
         "Start and End should be in the same basic block");

  // If Start == End, then we have an empty range, return nothing.
  if (Start == End)
    return None;

  // Otherwise, until Start != End.
  while (Start != End) {
    // Check if Start can decrement or check Op's ref count. If so, return
    // Start. Ref count checks do not have side effects, but are barriers for
    // retains.
    if (mayDecrementRefCount(&*Start, Op, AA) || mayCheckRefCount(&*Start))
      return Start;
    // Otherwise, increment our iterator.
    ++Start;
  }

  // If all such instructions cannot decrement Op, return nothing.
  return None;
}
Esempio n. 2
0
/// If \p Op has arc uses in the instruction range [Start, End), return the
/// first such instruction. Otherwise return None. We assume that
/// Start and End are both in the same basic block.
Optional<SILBasicBlock::iterator>
swift::
valueHasARCUsesInInstructionRange(SILValue Op,
                                  SILBasicBlock::iterator Start,
                                  SILBasicBlock::iterator End,
                                  AliasAnalysis *AA) {
  assert(Start->getParent() == End->getParent() &&
         "Start and End should be in the same basic block");

  // If Start == End, then we have an empty range, return false.
  if (Start == End)
    return None;

  // Otherwise, until Start != End.
  while (Start != End) {
    // Check if Start can use Op in an ARC relevant way. If so, return true.
    if (mayHaveSymmetricInterference(&*Start, Op, AA))
      return Start;

    // Otherwise, increment our iterator.
    ++Start;
  }

  // If all such instructions cannot use Op, return false.
  return None;
}
Esempio n. 3
0
/// If \p Op has arc uses in the instruction range (Start, End], return the
/// first such instruction. Otherwise return None. We assume that Start and End
/// are both in the same basic block.
Optional<SILBasicBlock::iterator>
swift::valueHasARCUsesInReverseInstructionRange(SILValue Op,
                                                SILBasicBlock::iterator Start,
                                                SILBasicBlock::iterator End,
                                                AliasAnalysis *AA) {
  assert(Start->getParent() == End->getParent() &&
         "Start and End should be in the same basic block");
  assert(End != End->getParent()->end() &&
         "End should be mapped to an actual instruction");

  // If Start == End, then we have an empty range, return false.
  if (Start == End)
    return None;

  // Otherwise, until End == Start.
  while (Start != End) {
    // Check if Start can use Op in an ARC relevant way. If so, return true.
    if (mayHaveSymmetricInterference(&*End, Op, AA))
      return End;

    // Otherwise, decrement our iterator.
    --End;
  }

  // If all such instructions cannot use Op, return false.
  return None;
}
Esempio n. 4
0
/// Perform outlining on the function and return any newly created outlined
/// functions.
bool tryOutline(SILOptFunctionBuilder &FuncBuilder, SILFunction *Fun,
                SmallVectorImpl<SILFunction *> &FunctionsAdded) {
  SmallPtrSet<SILBasicBlock *, 32> Visited;
  SmallVector<SILBasicBlock *, 128> Worklist;
  OutlinePatterns patterns(FuncBuilder);

  // Traverse the function.
  Worklist.push_back(&*Fun->begin());
  while (!Worklist.empty()) {

    SILBasicBlock *CurBlock = Worklist.pop_back_val();
    if (!Visited.insert(CurBlock).second) continue;

    SILBasicBlock::iterator CurInst = CurBlock->begin();

    // Go over the instructions trying to match and replace patterns.
    while (CurInst != CurBlock->end()) {
       if (OutlinePattern *match = patterns.tryToMatch(CurInst)) {
         SILFunction *F;
         SILBasicBlock::iterator LastInst;
         std::tie(F, LastInst) = match->outline(Fun->getModule());
         if (F)
           FunctionsAdded.push_back(F);
         CurInst = LastInst;
         assert(LastInst->getParent() == CurBlock);
       } else if (isa<TermInst>(CurInst)) {
         std::copy(CurBlock->succ_begin(), CurBlock->succ_end(),
                   std::back_inserter(Worklist));
         ++CurInst;
       } else {
         ++CurInst;
       }
    }
  }
  return false;
}
Esempio n. 5
0
/// Handle CSE of open_existential_ref instructions.
/// Returns true if uses of open_existential_ref can
/// be replaced by a dominating instruction.
/// \Inst is the open_existential_ref instruction
/// \V is the dominating open_existential_ref instruction
/// \I is the iterator referring to the current instruction.
bool CSE::processOpenExistentialRef(SILInstruction *Inst, ValueBase *V,
                                    SILBasicBlock::iterator &I) {
  assert(isa<OpenExistentialRefInst>(Inst));
  llvm::SmallSetVector<SILInstruction *, 16> Candidates;
  auto OldOpenedArchetype = getOpenedArchetypeOf(Inst);
  auto NewOpenedArchetype = getOpenedArchetypeOf(dyn_cast<SILInstruction>(V));
  TypeSubstitutionMap TypeSubstMap;
  TypeSubstMap[OldOpenedArchetype.getPointer()] = NewOpenedArchetype;
  // Collect all candidates that may contain opened archetypes
  // that need to be replaced.
  for (auto Use : Inst->getUses()) {
    auto User = Use->getUser();
    if (!User->getTypeDependentOperands().empty()) {
      if (canHandle(User)) {
        auto It = AvailableValues->begin(User);
        if (It != AvailableValues->end()) {
          return false;
        }
      }
      Candidates.insert(User);
    }
    if (!isa<TermInst>(User))
      continue;
    // The current use of the opened archetype is a terminator instruction.
    // Check if any of the successor BBs uses this opened archetype in the
    // types of its basic block arguments. If this is the case, replace
    // those uses by the new opened archetype.
    auto Successors = User->getParent()->getSuccessorBlocks();
    for (auto Successor : Successors) {
      if (Successor->bbarg_empty())
        continue;
      // If a BB has any arguments, update their types if necessary.
      updateBasicBlockArgTypes(Successor, TypeSubstMap);
    }
  }
  // Now process candidates.
  // TODO: Move it to CSE instance to avoid recreating it every time?
  SILOpenedArchetypesTracker OpenedArchetypesTracker(*Inst->getFunction());
  // Register the new archetype to be used.
  OpenedArchetypesTracker.registerOpenedArchetypes(dyn_cast<SILInstruction>(V));
  // Use a cloner. It makes copying the instruction and remapping of
  // opened archetypes trivial.
  InstructionCloner Cloner(I->getFunction());
  Cloner.registerOpenedExistentialRemapping(
      OldOpenedArchetype->castTo<ArchetypeType>(), NewOpenedArchetype);
  auto &Builder = Cloner.getBuilder();
  Builder.setOpenedArchetypesTracker(&OpenedArchetypesTracker);

  llvm::SmallPtrSet<SILInstruction *, 16> Processed;
  // Now clone each candidate and replace the opened archetype
  // by a dominating one.
  while (!Candidates.empty()) {
    auto Candidate = Candidates.pop_back_val();
    if (Processed.count(Candidate))
      continue;
    // True if a candidate depends on the old opened archetype.
    bool DependsOnOldOpenedArchetype = !Candidate->getTypeDependentOperands().empty();
    if (!Candidate->use_empty() &&
        Candidate->getType().getSwiftRValueType()->hasOpenedExistential()) {
      // Check if the result type of the candidate depends on the opened
      // existential in question.
      auto ResultDependsOnOldOpenedArchetype =
          Candidate->getType().getSwiftRValueType().findIf(
              [&OldOpenedArchetype](Type t) -> bool {
                if (t.getCanonicalTypeOrNull() == OldOpenedArchetype)
                  return true;
                return false;
              });
      if (ResultDependsOnOldOpenedArchetype) {
        DependsOnOldOpenedArchetype |= ResultDependsOnOldOpenedArchetype;
        // We need to update uses of this candidate, because their types
        // may be affected.
        for (auto Use : Candidate->getUses()) {
          Candidates.insert(Use->getUser());
        }
      }
    }
    // Remember that this candidate was processed already.
    Processed.insert(Candidate);

    // No need to clone if there is no dependency on the old opened archetype.
    if (!DependsOnOldOpenedArchetype)
      continue;

    Builder.getOpenedArchetypes().addOpenedArchetypeOperands(
        Candidate->getTypeDependentOperands());
    Builder.setInsertionPoint(Candidate);
    auto NewI = Cloner.clone(Candidate);
    // Result types of candidate's uses instructions may be using this archetype.
    // Thus, we need to try to replace it there.
    Candidate->replaceAllUsesWith(NewI);
    if (I == Candidate->getIterator())
      I = NewI->getIterator();
    eraseFromParentWithDebugInsts(Candidate, I);
  }
  return true;
}