bool SILArgument::getIncomingValues(llvm::SmallVectorImpl<SILValue> &OutArray) { SILBasicBlock *Parent = getParent(); if (Parent->pred_empty()) return false; unsigned Index = getIndex(); for (SILBasicBlock *Pred : getParent()->getPreds()) { TermInst *TI = Pred->getTerminator(); if (auto *BI = dyn_cast<BranchInst>(TI)) { OutArray.push_back(BI->getArg(Index)); continue; } if (auto *CBI = dyn_cast<CondBranchInst>(TI)) { OutArray.push_back(CBI->getArgForDestBB(getParent(), this)); continue; } if (auto *CCBI = dyn_cast<CheckedCastBranchInst>(TI)) { OutArray.push_back(CCBI->getOperand()); continue; } if (auto *SWEI = dyn_cast<SwitchEnumInst>(TI)) { OutArray.push_back(SWEI->getOperand()); continue; } return false; } return true; }
void ReleaseCodeMotionContext::convergeCodeMotionDataFlow() { // Process each basic block with the gen and kill set. Every time the // BBSetIn of a basic block changes, the optimization is rerun on its // predecessors. llvm::SmallVector<SILBasicBlock *, 16> WorkList; llvm::SmallPtrSet<SILBasicBlock *, 8> HandledBBs; // Push into reverse post order so that we can pop from the back and get // post order. for (SILBasicBlock *B : PO->getPostOrder()) { WorkList.push_back(B); HandledBBs.insert(B); } while (!WorkList.empty()) { SILBasicBlock *BB = WorkList.pop_back_val(); HandledBBs.erase(BB); if (processBBWithGenKillSet(BB)) { for (auto X : BB->getPredecessorBlocks()) { // We do not push basic block into the worklist if its already // in the worklist. if (HandledBBs.count(X)) continue; WorkList.push_back(X); } } } }
Condition SILGenFunction::emitCondition(SILValue V, SILLocation Loc, bool hasFalseCode, bool invertValue, ArrayRef<SILType> contArgs) { assert(B.hasValidInsertionPoint() && "emitting condition at unreachable point"); SILBasicBlock *ContBB = createBasicBlock(); for (SILType argTy : contArgs) { ContBB->createPHIArgument(argTy, ValueOwnershipKind::Owned); } SILBasicBlock *FalseBB, *FalseDestBB; if (hasFalseCode) { FalseBB = FalseDestBB = createBasicBlock(); } else { FalseBB = nullptr; FalseDestBB = ContBB; } SILBasicBlock *TrueBB = createBasicBlock(); if (invertValue) B.createCondBranch(Loc, V, FalseDestBB, TrueBB); else B.createCondBranch(Loc, V, TrueBB, FalseDestBB); return Condition(TrueBB, FalseBB, ContBB, Loc); }
/// Return a basic block suitable to be the destination block of a /// try_apply instruction. The block is implicitly emitted and filled in. SILBasicBlock * SILGenFunction::getTryApplyErrorDest(SILLocation loc, SILResultInfo exnResult, bool suppressErrorPath) { assert(exnResult.getConvention() == ResultConvention::Owned); // For now, don't try to re-use destination blocks for multiple // failure sites. SILBasicBlock *destBB = createBasicBlock(FunctionSection::Postmatter); SILValue exn = destBB->createPHIArgument(exnResult.getSILType(), ValueOwnershipKind::Owned); assert(B.hasValidInsertionPoint() && B.insertingAtEndOfBlock()); SavedInsertionPoint savedIP(*this, destBB, FunctionSection::Postmatter); // If we're suppressing error paths, just wrap it up as unreachable // and return. if (suppressErrorPath) { B.createUnreachable(loc); return destBB; } // We don't want to exit here with a dead cleanup on the stack, // so push the scope first. FullExpr scope(Cleanups, CleanupLocation::get(loc)); emitThrow(loc, emitManagedRValueWithCleanup(exn)); return destBB; }
/// Return true if this copy can be eliminated through Named Return Value /// Optimization (NRVO). /// /// Simple NRVO cases are handled naturally via backwardPropagateCopy. However, /// general NRVO is not handled via local propagation without global data /// flow. Nonetheless, NRVO is a simple pattern that can be detected using a /// different technique from propagation. /// /// Example: /// func nrvo<T : P>(z : Bool) -> T { /// var rvo : T /// if (z) { /// rvo = T(10) /// } /// else { /// rvo = T(1) /// } /// return rvo /// } /// /// Because of the control flow, backward propagation with a block will fail to /// find the initializer for the copy at "return rvo". Instead, we directly /// check for an NRVO pattern by observing a copy in a return block that is the /// only use of the copy's dest, which must be an @out arg. If there are no /// instructions between the copy and the return that may write to the copy's /// source, we simply replace the source's local stack address with the @out /// address. /// /// The following SIL pattern will be detected: /// /// sil @foo : $@convention(thin) <T> (@out T) -> () { /// bb0(%0 : $*T): /// %2 = alloc_stack $T /// ... // arbitrary control flow, but no other uses of %0 /// bbN: /// copy_addr [take] %2 to [initialization] %0 : $*T /// ... // no writes /// return static bool canNRVO(CopyAddrInst *CopyInst) { if (!isa<AllocStackInst>(CopyInst->getSrc())) return false; // The copy's dest must be an indirect SIL argument. Otherwise, it may not // dominate all uses of the source. Worse, it may be aliased. This // optimization will early-initialize the copy dest, so we can't allow aliases // to be accessed between the initialization and the return. auto OutArg = dyn_cast<SILArgument>(CopyInst->getDest()); if (!OutArg) return false; auto ArgConv = OutArg->getParameterInfo().getConvention(); if (ArgConv != ParameterConvention::Indirect_Out) return false; SILBasicBlock *BB = CopyInst->getParent(); if (!isa<ReturnInst>(BB->getTerminator())) return false; SILValue CopyDest = CopyInst->getDest(); if (!hasOneNonDebugUse(CopyDest)) return false; auto SI = CopyInst->getIterator(), SE = BB->end(); for (++SI; SI != SE; ++SI) { if (SI->mayWriteToMemory() && !isa<DeallocationInst>(SI)) return false; } return true; }
SILValue StackAllocationPromoter::getLiveOutValue(BlockSet &PhiBlocks, SILBasicBlock *StartBB) { LLVM_DEBUG(llvm::dbgs() << "*** Searching for a value definition.\n"); // Walk the Dom tree in search of a defining value: for (DomTreeNode *Node = DT->getNode(StartBB); Node; Node = Node->getIDom()) { SILBasicBlock *BB = Node->getBlock(); // If there is a store (that must come after the phi), use its value. BlockToInstMap::iterator it = LastStoreInBlock.find(BB); if (it != LastStoreInBlock.end()) if (auto *St = dyn_cast_or_null<StoreInst>(it->second)) { LLVM_DEBUG(llvm::dbgs() << "*** Found Store def " << *St->getSrc()); return St->getSrc(); } // If there is a Phi definition in this block: if (PhiBlocks.count(BB)) { // Return the dummy instruction that represents the new value that we will // add to the basic block. SILValue Phi = BB->getArgument(BB->getNumArguments() - 1); LLVM_DEBUG(llvm::dbgs() << "*** Found a dummy Phi def " << *Phi); return Phi; } // Move to the next dominating block. LLVM_DEBUG(llvm::dbgs() << "*** Walking up the iDOM.\n"); } LLVM_DEBUG(llvm::dbgs() << "*** Could not find a Def. Using Undef.\n"); return SILUndef::get(ASI->getElementType(), ASI->getModule()); }
/// Set up epilogue work for the thunk arguments based in the given argument. /// Default implementation simply passes it through. void FunctionSignatureTransform:: OwnedToGuaranteedAddArgumentRelease(ArgumentDescriptor &AD, SILBuilder &Builder, SILFunction *F) { // If we have any arguments that were consumed but are now guaranteed, // insert a release_value. if (!AD.OwnedToGuaranteed) { return; } SILInstruction *Call = findOnlyApply(F); if (isa<ApplyInst>(Call)) { Builder.setInsertionPoint(&*std::next(SILBasicBlock::iterator(Call))); Builder.createReleaseValue(RegularLocation(SourceLoc()), F->getArguments()[AD.Index], Builder.getDefaultAtomicity()); } else { SILBasicBlock *NormalBB = dyn_cast<TryApplyInst>(Call)->getNormalBB(); Builder.setInsertionPoint(&*NormalBB->begin()); Builder.createReleaseValue(RegularLocation(SourceLoc()), F->getArguments()[AD.Index], Builder.getDefaultAtomicity()); SILBasicBlock *ErrorBB = dyn_cast<TryApplyInst>(Call)->getErrorBB(); Builder.setInsertionPoint(&*ErrorBB->begin()); Builder.createReleaseValue(RegularLocation(SourceLoc()), F->getArguments()[AD.Index], Builder.getDefaultAtomicity()); } }
SILValue BBState::computeForwardingValues(RLEContext &Ctx, MemLocation &L, SILInstruction *InsertPt, bool UseForwardValOut) { SILBasicBlock *ParentBB = InsertPt->getParent(); bool IsTerminator = (InsertPt == ParentBB->getTerminator()); // We do not have a SILValue for the current MemLocation, try to construct // one. // // Collect the locations and their corresponding values into a map. // First, collect current available locations and their corresponding values // into a map. MemLocationValueMap Values; if (!Ctx.gatherValues(ParentBB, L, Values, UseForwardValOut)) return SILValue(); // If the InsertPt is the terminator instruction of the basic block, we // *refresh* it as terminator instruction could be deleted as a result // of adding new edge values to the terminator instruction. if (IsTerminator) InsertPt = ParentBB->getTerminator(); // Second, reduce the available values into a single SILValue we can use to // forward. SILValue TheForwardingValue; TheForwardingValue = MemLocation::reduceWithValues(L, &ParentBB->getModule(), Values, InsertPt); /// Return the forwarding value. return TheForwardingValue; }
void State::initializeAllConsumingUses( ArrayRef<BranchPropagatedUser> consumingUses, SmallVectorImpl<BrPropUserAndBlockPair> &predsToAddToWorklist) { for (BranchPropagatedUser user : consumingUses) { SILBasicBlock *userBlock = user.getParent(); // First initialize our state for the consuming user. // // If we find another consuming instruction associated with userBlock this // will emit a checker error. initializeConsumingUse(user, userBlock); // Then check if the given block has a use after free and emit an error if // we find one. checkForSameBlockUseAfterFree(user, userBlock); // If this user is in the same block as the value, do not visit // predecessors. We must be extra tolerant here since we allow for // unreachable code. if (userBlock == value->getParentBlock()) continue; // Then for each predecessor of this block... for (auto *pred : userBlock->getPredecessorBlocks()) { // If this block is not a block that we have already put on the list, add // it to the worklist. predsToAddToWorklist.push_back({user, pred}); } } }
void RLEContext::processBasicBlocksWithGenKillSet() { // Process each basic block with the gen and kill set. Every time the // ForwardSetOut of a basic block changes, the optimization is rerun on its // successors. llvm::SmallVector<SILBasicBlock *, 16> WorkList; llvm::DenseSet<SILBasicBlock *> HandledBBs; // Push into the worklist in post order so that we can pop from the back and // get reverse post order. for (SILBasicBlock *BB : PO->getPostOrder()) { WorkList.push_back(BB); HandledBBs.insert(BB); } while (!WorkList.empty()) { SILBasicBlock *BB = WorkList.pop_back_val(); HandledBBs.erase(BB); // Intersection. BlockState &Forwarder = getBlockState(BB); // Compute the ForwardSetIn at the beginning of the basic block. Forwarder.mergePredecessorAvailSet(*this); if (Forwarder.processBasicBlockWithGenKillSet()) { for (auto &X : BB->getSuccessors()) { // We do not push basic block into the worklist if its already // in the worklist. if (HandledBBs.find(X) != HandledBBs.end()) continue; WorkList.push_back(X); } } } }
/// Perform a foreign error check by testing whether the error was nil. static void emitErrorIsNonNilErrorCheck(SILGenFunction &gen, SILLocation loc, ManagedValue errorSlot, bool suppressErrorCheck) { // If we're suppressing the check, just don't check. if (suppressErrorCheck) return; SILValue optionalError = gen.B.emitLoadValueOperation( loc, errorSlot.forward(gen), LoadOwnershipQualifier::Take); ASTContext &ctx = gen.getASTContext(); // Switch on the optional error. SILBasicBlock *errorBB = gen.createBasicBlock(FunctionSection::Postmatter); errorBB->createArgument(optionalError->getType().unwrapAnyOptionalType()); SILBasicBlock *contBB = gen.createBasicBlock(); gen.B.createSwitchEnum(loc, optionalError, /*default*/ nullptr, { { ctx.getOptionalSomeDecl(), errorBB }, { ctx.getOptionalNoneDecl(), contBB } }); // Emit the error block. Pass in none for the errorSlot since we have passed // in the errorSlot as our BB argument so we can pass ownership correctly. In // emitForeignErrorBlock, we will create the appropriate cleanup for the // argument. gen.emitForeignErrorBlock(loc, errorBB, None); // Return the result. gen.B.emitBlock(contBB); return; }
SILValue SILArgument::getIncomingValue(unsigned BBIndex) { SILBasicBlock *Parent = getParent(); if (Parent->pred_empty()) return SILValue(); unsigned Index = getIndex(); // We could do an early check if the size of the pred list is <= BBIndex, but // that would involve walking the linked list anyways, so we just iterate once // over the loop. // We use this funky loop since predecessors are stored in a linked list but // we want array like semantics. unsigned BBCount = 0; for (SILBasicBlock *Pred : Parent->getPreds()) { // If BBCount is not BBIndex, continue. if (BBCount < BBIndex) { BBCount++; continue; } // This will return an empty SILValue if we found something we do not // understand. return getIncomingValueForPred(Parent, Pred, Index); } return SILValue(); }
// Given a block argument address base, check if it is actually a box projected // from a switch_enum. This is a valid pattern at any SIL stage resulting in a // block-type phi. In later SIL stages, the optimizer may form address-type // phis, causing this assert if called on those cases. static void checkSwitchEnumBlockArg(SILPhiArgument *arg) { assert(!arg->getType().isAddress()); SILBasicBlock *Pred = arg->getParent()->getSinglePredecessorBlock(); if (!Pred || !isa<SwitchEnumInst>(Pred->getTerminator())) { arg->dump(); llvm_unreachable("unexpected box source."); } }
/// \brief Splits a basic block into two at the specified instruction. /// /// Note that all the instructions BEFORE the specified iterator /// stay as part of the original basic block. The old basic block is left /// without a terminator. SILBasicBlock *SILBasicBlock::split(iterator I) { SILBasicBlock *New = new (Parent->getModule()) SILBasicBlock(Parent, this, /*after*/true); // Move all of the specified instructions from the original basic block into // the new basic block. New->InstList.splice(New->end(), InstList, I, end()); return New; }
void FunctionSignatureTransform::DeadArgumentTransformFunction() { SILBasicBlock *BB = &*F->begin(); for (const ArgumentDescriptor &AD : ArgumentDescList) { if (!AD.IsEntirelyDead) continue; eraseUsesOfValue(BB->getArgument(AD.Index)); } }
/// getOrEraseBlock - If there are branches to the specified JumpDest, /// return the block, otherwise return NULL. The JumpDest must be valid. static SILBasicBlock *getOrEraseBlock(SILGenFunction &SGF, JumpDest &dest) { SILBasicBlock *BB = dest.takeBlock(); if (BB->pred_empty()) { // If the block is unused, we don't need it; just delete it. SGF.eraseBasicBlock(BB); return nullptr; } return BB; }
/// Analyse one potential induction variable starting at Arg. InductionInfo *analyseIndVar(SILArgument *HeaderVal, BuiltinInst *Inc, IntegerLiteralInst *IncVal) { if (IncVal->getValue() != 1) return nullptr; // Find the start value. auto *PreheaderTerm = dyn_cast<BranchInst>(Preheader->getTerminator()); if (!PreheaderTerm) return nullptr; auto Start = PreheaderTerm->getArg(HeaderVal->getIndex()); // Find the exit condition. auto CondBr = dyn_cast<CondBranchInst>(ExitingBlk->getTerminator()); if (!CondBr) return nullptr; if (ExitBlk == CondBr->getFalseBB()) return nullptr; assert(ExitBlk == CondBr->getTrueBB() && "The loop's exiting blocks terminator must exit"); auto Cond = CondBr->getCondition(); SILValue End; // Look for a compare of induction variable + 1. // TODO: obviously we need to handle many more patterns. if (!match(Cond, m_ApplyInst(BuiltinValueKind::ICMP_EQ, m_TupleExtractInst(m_Specific(Inc), 0), m_SILValue(End))) && !match(Cond, m_ApplyInst(BuiltinValueKind::ICMP_EQ, m_SILValue(End), m_TupleExtractInst(m_Specific(Inc), 0)))) { DEBUG(llvm::dbgs() << " found no exit condition\n"); return nullptr; } // Make sure our end value is loop invariant. if (!dominates(DT, End, Preheader)) return nullptr; DEBUG(llvm::dbgs() << " found an induction variable (ICMP_EQ): " << *HeaderVal << " start: " << *Start << " end: " << *End); // Check whether the addition is overflow checked by a cond_fail or whether // code in the preheader's predecessor ensures that we won't overflow. bool IsRangeChecked = false; if (!isOverflowChecked(Inc)) { IsRangeChecked = isRangeChecked(Start, End, Preheader, DT); if (!IsRangeChecked) return nullptr; } return new (Allocator.Allocate()) InductionInfo( HeaderVal, Inc, Start, End, BuiltinValueKind::ICMP_EQ, IsRangeChecked); }
bool ARCRegionState::processBlockBottomUp( SILBasicBlock &BB, AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, bool FreezeOwnedArgEpilogueReleases, ConsumedArgToEpilogueReleaseMatcher &ConsumedArgToReleaseMap, BlotMapVector<SILInstruction *, BottomUpRefCountState> &IncToDecStateMap) { DEBUG(llvm::dbgs() << ">>>> Bottom Up!\n"); bool NestingDetected = false; BottomUpDataflowRCStateVisitor<ARCRegionState> DataflowVisitor( RCIA, *this, FreezeOwnedArgEpilogueReleases, ConsumedArgToReleaseMap, IncToDecStateMap); // For each non-terminator instruction I in BB visited in reverse... for (auto II = std::next(BB.rbegin()), IE = BB.rend(); II != IE;) { SILInstruction &I = *II; ++II; DEBUG(llvm::dbgs() << "VISITING:\n " << I); auto Result = DataflowVisitor.visit(&I); // If this instruction can have no further effects on another instructions, // continue. This happens for instance if we have cleared all of the state // we are tracking. if (Result.Kind == RCStateTransitionDataflowResultKind::NoEffects) continue; // Make sure that we propagate out whether or not nesting was detected. NestingDetected |= Result.NestingDetected; // This SILValue may be null if we were unable to find a specific RCIdentity // that the instruction "visits". SILValue Op = Result.RCIdentity; auto *InsertPt = &*std::next(SILBasicBlock::iterator(&I)); // For all other (reference counted value, ref count state) we are // tracking... for (auto &OtherState : getBottomupStates()) { // If the other state's value is blotted, skip it. if (!OtherState.hasValue()) continue; // If this is the state associated with the instruction that we are // currently visiting, bail. if (Op && OtherState->first == Op) continue; OtherState->second.updateForSameLoopInst(&I, InsertPt, AA); } } return NestingDetected; }
/// \brief Splits a basic block into two at the specified instruction. /// /// Note that all the instructions BEFORE the specified iterator /// stay as part of the original basic block. The old basic block is left /// without a terminator. SILBasicBlock *SILBasicBlock::splitBasicBlock(iterator I) { SILBasicBlock *New = new (Parent->getModule()) SILBasicBlock(Parent); SILFunction::iterator Where = std::next(SILFunction::iterator(this)); SILFunction::iterator First = SILFunction::iterator(New); if (Where != First) Parent->getBlocks().splice(Where, Parent->getBlocks(), First); // Move all of the specified instructions from the original basic block into // the new basic block. New->InstList.splice(New->end(), InstList, I, end()); return New; }
/// Optimize placement of initializer calls given a list of calls to the /// same initializer. All original initialization points must be dominated by /// the final initialization calls. /// /// The current heuristic hoists all initialization points within a function to /// a single dominating call in the outer loop preheader. void SILGlobalOpt::placeInitializers(SILFunction *InitF, ArrayRef<ApplyInst *> Calls) { LLVM_DEBUG(llvm::dbgs() << "GlobalOpt: calls to " << Demangle::demangleSymbolAsString(InitF->getName()) << " : " << Calls.size() << "\n"); // Map each initializer-containing function to its final initializer call. llvm::DenseMap<SILFunction *, ApplyInst *> ParentFuncs; for (auto *AI : Calls) { assert(AI->getNumArguments() == 0 && "ill-formed global init call"); assert(cast<FunctionRefInst>(AI->getCallee())->getReferencedFunction() == InitF && "wrong init call"); SILFunction *ParentF = AI->getFunction(); DominanceInfo *DT = DA->get(ParentF); ApplyInst *HoistAI = getHoistedApplyForInitializer(AI, DT, InitF, ParentF, ParentFuncs); // If we were unable to find anything, just go onto the next apply. if (!HoistAI) { continue; } // Otherwise, move this call to the outermost loop preheader. SILBasicBlock *BB = HoistAI->getParent(); typedef llvm::DomTreeNodeBase<SILBasicBlock> DomTreeNode; DomTreeNode *Node = DT->getNode(BB); while (Node) { SILBasicBlock *DomParentBB = Node->getBlock(); if (isAvailabilityCheck(DomParentBB)) { LLVM_DEBUG(llvm::dbgs() << " don't hoist above availability check " "at bb" << DomParentBB->getDebugID() << "\n"); break; } BB = DomParentBB; if (!isInLoop(BB)) break; Node = Node->getIDom(); } if (BB == HoistAI->getParent()) { // BB is either unreachable or not in a loop. LLVM_DEBUG(llvm::dbgs() << " skipping (not in a loop): " << *HoistAI << " in " << HoistAI->getFunction()->getName() << "\n"); continue; } LLVM_DEBUG(llvm::dbgs() << " hoisting: " << *HoistAI << " in " << HoistAI->getFunction()->getName() << "\n"); HoistAI->moveBefore(&*BB->begin()); placeFuncRef(HoistAI, DT); HasChanged = true; } }
static bool prepareExtraEpilog(SILGenFunction &SGF, JumpDest &dest, SILLocation &loc, SILValue *arg) { assert(!SGF.B.hasValidInsertionPoint()); // If we don't have a destination, we don't need to emit the epilog. if (!dest.isValid()) return false; // If the destination isn't used, we don't need to emit the epilog. SILBasicBlock *epilogBB = dest.getBlock(); auto pi = epilogBB->pred_begin(), pe = epilogBB->pred_end(); if (pi == pe) { dest = JumpDest::invalid(); SGF.eraseBasicBlock(epilogBB); return false; } assert(epilogBB->getNumArguments() <= 1); assert((epilogBB->getNumArguments() == 1) == (arg != nullptr)); if (arg) *arg = epilogBB->args_begin()[0]; bool reposition = true; // If the destination has a single branch predecessor, // consider emitting the epilog into it. SILBasicBlock *predBB = *pi; if (++pi == pe) { if (auto branch = dyn_cast<BranchInst>(predBB->getTerminator())) { assert(branch->getArgs().size() == epilogBB->getNumArguments()); // Save the location and operand information from the branch, // then destroy it. loc = branch->getLoc(); if (arg) *arg = branch->getArgs()[0]; predBB->erase(branch); // Erase the rethrow block. SGF.eraseBasicBlock(epilogBB); epilogBB = predBB; reposition = false; } } // Reposition the block to the end of the postmatter section // unless we're emitting into a single predecessor. if (reposition) { SGF.B.moveBlockTo(epilogBB, SGF.F.end()); } SGF.B.setInsertionPoint(epilogBB); return true; }
/// At least one value feeding the specified SILArgument is a Struct. Attempt to /// replace the Argument with a new Struct in the same block. /// /// When we handle more types of casts, this can become a template. /// /// ArgValues are the values feeding the specified Argument from each /// predecessor. They must be listed in order of Arg->getParent()->getPreds(). static StructInst * replaceBBArgWithStruct(SILPhiArgument *Arg, SmallVectorImpl<SILValue> &ArgValues) { SILBasicBlock *PhiBB = Arg->getParent(); auto *FirstSI = dyn_cast<StructInst>(ArgValues[0]); if (!FirstSI) return nullptr; // Collect the BBArg index of each struct oper. // e.g. // struct(A, B) // br (B, A) // : ArgIdxForOper => {1, 0} SmallVector<unsigned, 4> ArgIdxForOper; for (unsigned OperIdx : indices(FirstSI->getElements())) { bool FoundMatchingArgIdx = false; for (unsigned ArgIdx : indices(PhiBB->getArguments())) { SmallVectorImpl<SILValue>::const_iterator AVIter = ArgValues.begin(); bool TryNextArgIdx = false; for (SILBasicBlock *PredBB : PhiBB->getPredecessorBlocks()) { // All argument values must be StructInst. auto *PredSI = dyn_cast<StructInst>(*AVIter++); if (!PredSI) return nullptr; OperandValueArrayRef EdgeValues = getEdgeValuesForTerminator(PredBB->getTerminator(), PhiBB); if (EdgeValues[ArgIdx] != PredSI->getElements()[OperIdx]) { TryNextArgIdx = true; break; } } if (!TryNextArgIdx) { assert(AVIter == ArgValues.end() && "# ArgValues does not match # BB preds"); FoundMatchingArgIdx = true; ArgIdxForOper.push_back(ArgIdx); break; } } if (!FoundMatchingArgIdx) return nullptr; } SmallVector<SILValue, 4> StructArgs; for (auto ArgIdx : ArgIdxForOper) StructArgs.push_back(PhiBB->getArgument(ArgIdx)); SILBuilder Builder(PhiBB, PhiBB->begin()); return Builder.createStruct(cast<StructInst>(ArgValues[0])->getLoc(), Arg->getType(), StructArgs); }
/// \brief Check if the edge from the terminator is critical. bool swift::isCriticalEdge(TermInst *T, unsigned EdgeIdx) { assert(T->getSuccessors().size() > EdgeIdx && "Not enough successors"); auto SrcSuccs = T->getSuccessors(); if (SrcSuccs.size() <= 1) return false; SILBasicBlock *DestBB = SrcSuccs[EdgeIdx]; assert(!DestBB->pred_empty() && "There should be a predecessor"); if (DestBB->getSinglePredecessor()) return false; return true; }
static void setOutsideBlockUsesToUndef(SILInstruction *I) { if (I->use_empty()) return; SILBasicBlock *BB = I->getParent(); SILModule &Mod = BB->getModule(); // Replace all uses outside of I's basic block by undef. llvm::SmallVector<Operand *, 16> Uses(I->use_begin(), I->use_end()); for (auto *Use : Uses) if (auto *User = dyn_cast<SILInstruction>(Use->getUser())) if (User->getParent() != BB) Use->set(SILUndef::get(Use->get().getType(), Mod)); }
/// Check that the argument has the same incoming edge values as the value /// map. static bool isEquivalentPHI(SILPhiArgument *PHI, llvm::SmallDenseMap<SILBasicBlock *, SILValue, 8> &ValueMap) { SILBasicBlock *PhiBB = PHI->getParent(); size_t Idx = PHI->getIndex(); for (auto *PredBB : PhiBB->getPredecessorBlocks()) { auto DesiredVal = ValueMap[PredBB]; OperandValueArrayRef EdgeValues = getEdgeValuesForTerminator(PredBB->getTerminator(), PhiBB); if (EdgeValues[Idx] != DesiredVal) return false; } return true; }
/// Carry out the operations required for an indirect conditional cast /// using a scalar cast operation. void swift::emitIndirectConditionalCastWithScalar( SILBuilder &B, ModuleDecl *M, SILLocation loc, CastConsumptionKind consumption, SILValue src, CanType sourceType, SILValue dest, CanType targetType, SILBasicBlock *indirectSuccBB, SILBasicBlock *indirectFailBB, ProfileCounter TrueCount, ProfileCounter FalseCount) { assert(canUseScalarCheckedCastInstructions(B.getModule(), sourceType, targetType)); // We only need a different failure block if the cast consumption // requires us to destroy the source value. SILBasicBlock *scalarFailBB; if (!shouldDestroyOnFailure(consumption)) { scalarFailBB = indirectFailBB; } else { scalarFailBB = B.splitBlockForFallthrough(); } // We always need a different success block. SILBasicBlock *scalarSuccBB = B.splitBlockForFallthrough(); auto &srcTL = B.getModule().Types.getTypeLowering(src->getType()); // Always take; this works under an assumption that retaining the // result is equivalent to retaining the source. That means that // these casts would not be appropriate for bridging-like conversions. SILValue srcValue = srcTL.emitLoadOfCopy(B, loc, src, IsTake); SILType targetValueType = dest->getType().getObjectType(); B.createCheckedCastBranch(loc, /*exact*/ false, srcValue, targetValueType, scalarSuccBB, scalarFailBB, TrueCount, FalseCount); // Emit the success block. B.setInsertionPoint(scalarSuccBB); { auto &targetTL = B.getModule().Types.getTypeLowering(targetValueType); SILValue succValue = scalarSuccBB->createPHIArgument( targetValueType, ValueOwnershipKind::Owned); if (!shouldTakeOnSuccess(consumption)) targetTL.emitCopyValue(B, loc, succValue); targetTL.emitStoreOfCopy(B, loc, succValue, dest, IsInitialization); B.createBranch(loc, indirectSuccBB); } // Emit the failure block. if (shouldDestroyOnFailure(consumption)) { B.setInsertionPoint(scalarFailBB); srcTL.emitDestroyValue(B, loc, srcValue); B.createBranch(loc, indirectFailBB); } }
void StmtEmitter::visitWhileStmt(WhileStmt *S) { LexicalScope condBufferScope(SGF, S); // Create a new basic block and jump into it. JumpDest loopDest = createJumpDest(S->getBody()); SGF.B.emitBlock(loopDest.getBlock(), S); // Create a break target (at this level in the cleanup stack) in case it is // needed. JumpDest breakDest = createJumpDest(S->getBody()); // Set the destinations for any 'break' and 'continue' statements inside the // body. SGF.BreakContinueDestStack.push_back({S, breakDest, loopDest}); // Evaluate the condition, the body, and a branch back to LoopBB when the // condition is true. On failure, jump to BreakBB. { // Enter a scope for any bound pattern variables. Scope conditionScope(SGF.Cleanups, S); auto NumTrueTaken = SGF.loadProfilerCount(S->getBody()); auto NumFalseTaken = SGF.loadProfilerCount(S); SGF.emitStmtCondition(S->getCond(), breakDest, S, NumTrueTaken, NumFalseTaken); // In the success path, emit the body of the while. SGF.emitProfilerIncrement(S->getBody()); SGF.emitStmt(S->getBody()); // Finish the "true part" by cleaning up any temporaries and jumping to the // continuation block. if (SGF.B.hasValidInsertionPoint()) { RegularLocation L(S->getBody()); L.pointToEnd(); SGF.Cleanups.emitBranchAndCleanups(loopDest, L); } } SGF.BreakContinueDestStack.pop_back(); // Handle break block. If it was used, we link it up with the cleanup chain, // otherwise we just remove it. SILBasicBlock *breakBB = breakDest.getBlock(); if (breakBB->pred_empty()) { SGF.eraseBasicBlock(breakBB); } else { SGF.B.emitBlock(breakBB); } }
void ARCSequenceDataflowEvaluator::mergePredecessors( ARCBBStateInfoHandle &DataHandle) { bool HasAtLeastOnePred = false; llvm::SmallVector<SILBasicBlock *, 4> BBThatNeedInsertPts; SILBasicBlock *BB = DataHandle.getBB(); ARCBBState &BBState = DataHandle.getState(); // For each successor of BB... for (SILBasicBlock *PredBB : BB->getPreds()) { // Try to look up the data handle for it. If we don't have any such state, // then the predecessor must be unreachable from the entrance and thus is // uninteresting to us. auto PredDataHandle = getTopDownBBState(PredBB); if (!PredDataHandle) continue; DEBUG(llvm::dbgs() << " Merging Pred: " << PredDataHandle->getID() << "\n"); // If the predecessor is the head of a backedge in our traversal, clear any // state we are tracking now and clear the state of the basic block. There // is some sort of control flow here that we do not understand. if (PredDataHandle->isBackedge(BB)) { BBState.clear(); break; } ARCBBState &PredBBState = PredDataHandle->getState(); // If we found the state but the state is for a trap BB, skip it. Trap BBs // leak all reference counts and do not reference semantic objects // in any manner. // // TODO: I think this is a copy paste error, since we a trap BB should have // an unreachable at its end. See if this can be removed. if (PredBBState.isTrapBB()) continue; if (HasAtLeastOnePred) { BBState.mergePredTopDown(PredBBState); continue; } BBState.initPredTopDown(PredBBState); HasAtLeastOnePred = true; } }
/// \brief Populate the body of the cloned closure, modifying instructions as /// necessary to take into consideration the removed parameters. void PromotedParamCloner::populateCloned() { SILFunction *Cloned = getCloned(); SILModule &M = Cloned->getModule(); // Create arguments for the entry block SILBasicBlock *OrigEntryBB = &*Orig->begin(); SILBasicBlock *ClonedEntryBB = new (M) SILBasicBlock(Cloned); unsigned ArgNo = 0; auto I = OrigEntryBB->bbarg_begin(), E = OrigEntryBB->bbarg_end(); while (I != E) { if (std::count(PromotedParamIndices.begin(), PromotedParamIndices.end(), ArgNo)) { // Create a new argument with the promoted type. auto promotedTy = (*I)->getType().castTo<SILBoxType>() ->getBoxedAddressType(); auto promotedArg = new (M) SILArgument(ClonedEntryBB, promotedTy, (*I)->getDecl()); PromotedParameters.insert(*I); // Map any projections of the box to the promoted argument. for (auto use : (*I)->getUses()) { if (auto project = dyn_cast<ProjectBoxInst>(use->getUser())) { ValueMap.insert(std::make_pair(project, promotedArg)); } } } else { // Create a new argument which copies the original argument. SILValue MappedValue = new (M) SILArgument(ClonedEntryBB, (*I)->getType(), (*I)->getDecl()); ValueMap.insert(std::make_pair(*I, MappedValue)); } ++ArgNo; ++I; } getBuilder().setInsertionPoint(ClonedEntryBB); BBMap.insert(std::make_pair(OrigEntryBB, ClonedEntryBB)); // Recursively visit original BBs in depth-first preorder, starting with the // entry block, cloning all instructions other than terminators. visitSILBasicBlock(OrigEntryBB); // Now iterate over the BBs and fix up the terminators. for (auto BI = BBMap.begin(), BE = BBMap.end(); BI != BE; ++BI) { getBuilder().setInsertionPoint(BI->second); visit(BI->first->getTerminator()); } }
void FunctionSignatureTransform::ArgumentExplosionFinalizeOptimizedFunction() { SILBasicBlock *BB = &*NewF->begin(); SILBuilder Builder(BB->begin()); Builder.setCurrentDebugScope(BB->getParent()->getDebugScope()); unsigned TotalArgIndex = 0; for (ArgumentDescriptor &AD : ArgumentDescList) { // Simply continue if do not explode. if (!AD.Explode) { AIM[TotalArgIndex] = AD.Index; TotalArgIndex ++; continue; } // OK, we need to explode this argument. unsigned ArgOffset = ++TotalArgIndex; unsigned OldArgIndex = ArgOffset - 1; llvm::SmallVector<SILValue, 8> LeafValues; // We do this in the same order as leaf types since ProjTree expects that the // order of leaf values matches the order of leaf types. llvm::SmallVector<const ProjectionTreeNode*, 8> LeafNodes; AD.ProjTree.getLeafNodes(LeafNodes); for (auto *Node : LeafNodes) { auto OwnershipKind = *AD.getTransformedOwnershipKind(Node->getType()); LeafValues.push_back(BB->insertFunctionArgument( ArgOffset++, Node->getType(), OwnershipKind, BB->getArgument(OldArgIndex)->getDecl())); AIM[TotalArgIndex - 1] = AD.Index; TotalArgIndex ++; } // Then go through the projection tree constructing aggregates and replacing // uses. AD.ProjTree.replaceValueUsesWithLeafUses(Builder, BB->getParent()->getLocation(), LeafValues); // We ignored debugvalue uses when we constructed the new arguments, in order // to preserve as much information as possible, we construct a new value for // OrigArg from the leaf values and use that in place of the OrigArg. SILValue NewOrigArgValue = AD.ProjTree.computeExplodedArgumentValue(Builder, BB->getParent()->getLocation(), LeafValues); // Replace all uses of the original arg with the new value. SILArgument *OrigArg = BB->getArgument(OldArgIndex); OrigArg->replaceAllUsesWith(NewOrigArgValue); // Now erase the old argument since it does not have any uses. We also // decrement ArgOffset since we have one less argument now. BB->eraseArgument(OldArgIndex); TotalArgIndex --; } }