Exemplo n.º 1
0
static bool constantFoldTerminator(SILBasicBlock &BB,
                                   UnreachableUserCodeReportingState *State) {
  TermInst *TI = BB.getTerminator();

  // Process conditional branches with constant conditions.
  if (CondBranchInst *CBI = dyn_cast<CondBranchInst>(TI)) {
    SILValue V = CBI->getCondition();
    SILInstruction *CondI = dyn_cast<SILInstruction>(V);
    SILLocation Loc = CBI->getLoc();

    if (IntegerLiteralInst *ConstCond =
          dyn_cast_or_null<IntegerLiteralInst>(CondI)) {
      SILBuilderWithScope B(&BB, CBI);

      // Determine which of the successors is unreachable and create a new
      // terminator that only branches to the reachable successor.
      SILBasicBlock *UnreachableBlock = nullptr;
      bool CondIsTrue = false;
      if (ConstCond->getValue() == APInt(1, /*value*/ 0, false)) {
        B.createBranch(Loc, CBI->getFalseBB(), CBI->getFalseArgs());
        UnreachableBlock = CBI->getTrueBB();
      } else {
        assert(ConstCond->getValue() == APInt(1, /*value*/ 1, false) &&
               "Our representation of true/false does not match.");
        B.createBranch(Loc, CBI->getTrueBB(), CBI->getTrueArgs());
        UnreachableBlock = CBI->getFalseBB();
        CondIsTrue = true;
      }
      recursivelyDeleteTriviallyDeadInstructions(TI, true);
      NumInstructionsRemoved++;

      // Produce an unreachable code warning for this basic block if it
      // contains user code (only if we are not within an inlined function or a
      // template instantiation).
      // FIXME: Do not report if we are within a template instantiation.
      if (Loc.is<RegularLocation>() && State &&
          !State->PossiblyUnreachableBlocks.count(UnreachableBlock)) {
        // If this is the first time we see this unreachable block, store it
        // along with the folded branch info.
        State->PossiblyUnreachableBlocks.insert(UnreachableBlock);
        State->MetaMap.insert(
          std::pair<const SILBasicBlock*, UnreachableInfo>(
            UnreachableBlock,
            UnreachableInfo{UnreachableKind::FoldedBranch, Loc, CondIsTrue}));
      }

      NumTerminatorsFolded++;
      return true;
    }
  }

  // Constant fold switch enum.
  //   %1 = enum $Bool, #Bool.false!unionelt
  //   switch_enum %1 : $Bool, case #Bool.true!unionelt: bb1,
  //                            case #Bool.false!unionelt: bb2
  // =>
  //   br bb2
  if (SwitchEnumInst *SUI = dyn_cast<SwitchEnumInst>(TI)) {
    if (EnumInst *TheEnum = dyn_cast<EnumInst>(SUI->getOperand())) {
      const EnumElementDecl *TheEnumElem = TheEnum->getElement();
      SILBasicBlock *TheSuccessorBlock = nullptr;
      int ReachableBlockIdx = -1;
      for (unsigned Idx = 0; Idx < SUI->getNumCases(); ++Idx) {
        const EnumElementDecl *EI;
        SILBasicBlock *BI;
        std::tie(EI, BI) = SUI->getCase(Idx);
        if (EI == TheEnumElem) {
          TheSuccessorBlock = BI;
          ReachableBlockIdx = Idx;
          break;
        }
      }

      if (!TheSuccessorBlock)
        if (SUI->hasDefault()) {
          SILBasicBlock *DB= SUI->getDefaultBB();
          if (!isa<UnreachableInst>(DB->getTerminator())) {
            TheSuccessorBlock = DB;
            ReachableBlockIdx = SUI->getNumCases();
          }
        }

      // Not fully covered switches will be diagnosed later. SILGen represents
      // them with a Default basic block with an unrechable instruction.
      // We are going to produce an error on all unreachable instructions not
      // eliminated by DCE.
      if (!TheSuccessorBlock)
        return false;

      // Replace the switch with a branch to the TheSuccessorBlock.
      SILBuilderWithScope B(&BB, TI);
      SILLocation Loc = TI->getLoc();
      if (!TheSuccessorBlock->bbarg_empty()) {
        assert(TheEnum->hasOperand());
        B.createBranch(Loc, TheSuccessorBlock, TheEnum->getOperand());
      } else
        B.createBranch(Loc, TheSuccessorBlock);

      // Produce diagnostic info if we are not within an inlined function or
      // template instantiation.
      // FIXME: Do not report if we are within a template instantiation.
      assert(ReachableBlockIdx >= 0);
      if (Loc.is<RegularLocation>() && State) {
        // Find the first unreachable block in the switch so that we could use
        // it for better diagnostics.
        SILBasicBlock *UnreachableBlock = nullptr;
        if (SUI->getNumCases() > 1) {
          // More than one case.
          UnreachableBlock =
            (ReachableBlockIdx == 0) ? SUI->getCase(1).second:
                                       SUI->getCase(0).second;
        } else {
          if (SUI->getNumCases() == 1 && SUI->hasDefault()) {
            // One case and a default.
            UnreachableBlock =
              (ReachableBlockIdx == 0) ? SUI->getDefaultBB():
                                         SUI->getCase(0).second;
          }
        }

        // Generate diagnostic info.
        if (UnreachableBlock &&
            !State->PossiblyUnreachableBlocks.count(UnreachableBlock)) {
          State->PossiblyUnreachableBlocks.insert(UnreachableBlock);
          State->MetaMap.insert(
            std::pair<const SILBasicBlock*, UnreachableInfo>(
              UnreachableBlock,
              UnreachableInfo{UnreachableKind::FoldedSwitchEnum, Loc, true}));
        }
      }

      recursivelyDeleteTriviallyDeadInstructions(TI, true);
      NumTerminatorsFolded++;
      return true;
    }
  }

  // Constant fold switch int.
  //   %1 = integer_literal $Builtin.Int64, 2
  //   switch_value %1 : $Builtin.Int64, case 1: bb1, case 2: bb2
  // =>
  //   br bb2
  if (SwitchValueInst *SUI = dyn_cast<SwitchValueInst>(TI)) {
    if (IntegerLiteralInst *SwitchVal =
          dyn_cast<IntegerLiteralInst>(SUI->getOperand())) {
      SILBasicBlock *TheSuccessorBlock = 0;
      for (unsigned Idx = 0; Idx < SUI->getNumCases(); ++Idx) {
        APInt AI;
        SILValue EI;
        SILBasicBlock *BI;
        std::tie(EI, BI) = SUI->getCase(Idx);
        // TODO: Check that EI is really an IntegerLiteralInst
        AI = dyn_cast<IntegerLiteralInst>(EI)->getValue();
        if (AI == SwitchVal->getValue())
          TheSuccessorBlock = BI;
      }

      if (!TheSuccessorBlock)
        if (SUI->hasDefault())
          TheSuccessorBlock = SUI->getDefaultBB();

      // Add the branch instruction with the block.
      if (TheSuccessorBlock) {
        SILBuilderWithScope B(&BB, TI);
        B.createBranch(TI->getLoc(), TheSuccessorBlock);
        recursivelyDeleteTriviallyDeadInstructions(TI, true);
        NumTerminatorsFolded++;
        return true;
      }
      
      // TODO: Warn on unreachable user code here as well.
    }
  }

  return false;
}
Exemplo n.º 2
0
// Attempt to insert a new access in the loop preheader. If successful, insert
// the new access in DominatedAccessAnalysis so it can be used to dominate other
// accesses. Also convert the current access to static and update the current
// storageToDomMap since the access may already have been recorded (when it was
// still dynamic).
//
// This function cannot add or remove instructions in the current block, but
// may add instructions to the current loop's preheader.
//
// The required conditions for inserting a new dominating access are:
//
// 1. The new preheader access is not enclosed in another scope that doesn't
// also enclose the current scope.
//
// This is inferred from the loop structure; any scope that encloses the
// preheader must also enclose the entire loop.
//
// 2. The current access is not enclosed in another scope that doesn't also
// enclose the preheader.
//
// As before, it is sufficient to check this access' isInner flags in
// DominatedAccessAnalysis; if this access isn't enclosed by any scope within
// the function, then it can't be enclosed within a scope inside the loop.
//
// 3. The current header has no nested conflict within its scope.
//
// 4. The access' source operand is available in the loop preheader.
void DominatedAccessRemoval::tryInsertLoopPreheaderAccess(
    BeginAccessInst *BAI, DomAccessedStorage currAccessInfo) {
  // 2. the current access may be enclosed.
  if (currAccessInfo.isInner())
    return;

  // 3. the current access must be instantaneous.
  if (!BAI->hasNoNestedConflict())
    return;

  SILLoop *currLoop = loopInfo->getLoopFor(BAI->getParent());
  if (!currLoop)
    return;
  SILBasicBlock *preheader = currLoop->getLoopPreheader();
  if (!preheader)
    return;

  // 4. The source operand must be available in the preheader.
  auto sourceOperand = BAI->getOperand();
  auto *sourceBB = sourceOperand->getParentBlock();
  if (!domInfo->dominates(sourceBB, preheader))
    return;

  // Insert a new access scope immediately before the
  // preheader's terminator.
  TermInst *preheaderTerm = preheader->getTerminator();
  SILBuilderWithScope scopeBuilder(preheaderTerm);
  BeginAccessInst *newBegin = scopeBuilder.createBeginAccess(
      preheaderTerm->getLoc(), sourceOperand, BAI->getAccessKind(),
      SILAccessEnforcement::Dynamic, true /*no nested conflict*/,
      BAI->isFromBuiltin());
  scopeBuilder.createEndAccess(preheaderTerm->getLoc(), newBegin, false);
  LLVM_DEBUG(llvm::dbgs() << "Created loop preheader access: " << *newBegin
                          << "\n"
                          << "dominating: " << *BAI << "\n");
  BAI->setEnforcement(SILAccessEnforcement::Static);

  hasChanged = true;

  // Insert the new dominating instruction in both DominatedAccessAnalysis and
  // storageToDomMap if it has uniquely identifiable storage.
  if (!currAccessInfo.isUniquelyIdentifiedOrClass())
    return;

  AccessedStorage storage = static_cast<AccessedStorage>(currAccessInfo);
  storage.resetSubclassData();

  // Create a DomAccessedStorage for the new access with no flags set.
  DAA.accessMap.try_emplace(newBegin, DomAccessedStorage(storage));

  // Track the new access as long as no other accesses from the same storage are
  // already tracked. This also necessarily replaces the current access, which
  // was just made static.
  DominatingAccess newDomAccess(newBegin, domInfo->getNode(preheader));
  auto iterAndInserted = storageToDomMap.try_emplace(storage, newDomAccess);
  if (!iterAndInserted.second) {
    DominatingAccess &curDomAccess = iterAndInserted.first->second;
    if (curDomAccess.beginAccess == BAI)
      curDomAccess = newDomAccess;
  }
}