/// Combine counts of regions which cover the same area. static ArrayRef<CountedRegion> combineRegions(MutableArrayRef<CountedRegion> Regions) { if (Regions.empty()) return Regions; auto Active = Regions.begin(); auto End = Regions.end(); for (auto I = Regions.begin() + 1; I != End; ++I) { if (Active->startLoc() != I->startLoc() || Active->endLoc() != I->endLoc()) { // Shift to the next region. ++Active; if (Active != I) *Active = *I; continue; } // Merge duplicate region. // If CodeRegions and ExpansionRegions cover the same area, it's probably // a macro which is fully expanded to another macro. In that case, we need // to accumulate counts only from CodeRegions, or else the area will be // counted twice. // On the other hand, a macro may have a nested macro in its body. If the // outer macro is used several times, the ExpansionRegion for the nested // macro will also be added several times. These ExpansionRegions cover // the same source locations and have to be combined to reach the correct // value for that area. // We add counts of the regions of the same kind as the active region // to handle the both situations. if (I->Kind == Active->Kind) Active->ExecutionCount += I->ExecutionCount; } return Regions.drop_back(std::distance(++Active, End)); }
/// Prepare an Initialization that will initialize the result of the /// current function. /// /// \param directResultsBuffer - will be filled with the direct /// components of the result /// \param cleanups - will be filled (after initialization completes) /// with all the active cleanups managing the result values static std::unique_ptr<Initialization> prepareIndirectResultInit(SILGenFunction &gen, CanType formalResultType, SmallVectorImpl<SILValue> &directResultsBuffer, SmallVectorImpl<CleanupHandle> &cleanups) { auto fnType = gen.F.getLoweredFunctionType(); // Make space in the direct-results array for all the entries we need. directResultsBuffer.append(fnType->getNumDirectResults(), SILValue()); ArrayRef<SILResultInfo> allResults = fnType->getAllResults(); MutableArrayRef<SILValue> directResults = directResultsBuffer; ArrayRef<SILArgument*> indirectResultAddrs = gen.F.getIndirectResults(); auto init = prepareIndirectResultInit(gen, formalResultType, allResults, directResults, indirectResultAddrs, cleanups); assert(allResults.empty()); assert(directResults.empty()); assert(indirectResultAddrs.empty()); return init; }
static void emitSubSwitch(IRGenFunction &IGF, MutableArrayRef<EnumPayload::LazyValue> values, APInt mask, MutableArrayRef<std::pair<APInt, llvm::BasicBlock *>> cases, SwitchDefaultDest dflt) { recur: assert(!values.empty() && "didn't exit out when exhausting all values?!"); assert(!cases.empty() && "switching with no cases?!"); auto &DL = IGF.IGM.DataLayout; auto &pv = values.front(); values = values.slice(1); auto payloadTy = getPayloadType(pv); unsigned size = DL.getTypeSizeInBits(payloadTy); // Grab a chunk of the mask. auto maskPiece = mask.zextOrTrunc(size); mask = mask.lshr(size); // If the piece is zero, this doesn't affect the switch. We can just move // forward and recur. if (maskPiece == 0) { for (auto &casePair : cases) casePair.first = casePair.first.lshr(size); goto recur; } // Force the value we will test. auto v = forcePayloadValue(pv); auto payloadIntTy = llvm::IntegerType::get(IGF.IGM.getLLVMContext(), size); // Need to coerce to integer for 'icmp eq' if it's not already an integer // or pointer. (Switching or masking will also require a cast to integer.) if (!isa<llvm::IntegerType>(v->getType()) && !isa<llvm::PointerType>(v->getType())) v = IGF.Builder.CreateBitOrPointerCast(v, payloadIntTy); // Apply the mask if it's interesting. if (!maskPiece.isAllOnesValue()) { v = IGF.Builder.CreateBitOrPointerCast(v, payloadIntTy); auto maskConstant = llvm::ConstantInt::get(payloadIntTy, maskPiece); v = IGF.Builder.CreateAnd(v, maskConstant); } // Gather the values we will switch over for this payload chunk. // FIXME: std::map is lame. Should hash APInts. std::map<APInt, SmallVector<std::pair<APInt, llvm::BasicBlock*>, 2>, ult> subCases; for (auto casePair : cases) { // Grab a chunk of the value. auto valuePiece = casePair.first.zextOrTrunc(size); // Index the case according to this chunk. subCases[valuePiece].push_back({std::move(casePair.first).lshr(size), casePair.second}); } bool needsAdditionalCases = !values.empty() && mask != 0; SmallVector<std::pair<llvm::BasicBlock *, decltype(cases)>, 2> recursiveCases; auto blockForCases = [&](MutableArrayRef<std::pair<APInt, llvm::BasicBlock*>> cases) -> llvm::BasicBlock * { // If we need to recur, emit a new block. if (needsAdditionalCases) { auto newBB = IGF.createBasicBlock(""); recursiveCases.push_back({newBB, cases}); return newBB; } // Otherwise, we can jump directly to the ultimate destination. assert(cases.size() == 1 && "more than one case for final destination?!"); return cases.front().second; }; // If there's only one case, do a cond_br. if (subCases.size() == 1) { auto &subCase = *subCases.begin(); llvm::BasicBlock *block = blockForCases(subCase.second); // If the default case is unreachable, we don't need to conditionally // branch. if (dflt.getInt()) { IGF.Builder.CreateBr(block); goto next; } auto &valuePiece = subCase.first; llvm::Value *valueConstant = llvm::ConstantInt::get(payloadIntTy, valuePiece); valueConstant = IGF.Builder.CreateBitOrPointerCast(valueConstant, v->getType()); auto cmp = IGF.Builder.CreateICmpEQ(v, valueConstant); IGF.Builder.CreateCondBr(cmp, block, dflt.getPointer()); goto next; } // Otherwise, do a switch. { v = IGF.Builder.CreateBitOrPointerCast(v, payloadIntTy); auto swi = IGF.Builder.CreateSwitch(v, dflt.getPointer(), subCases.size()); for (auto &subCase : subCases) { auto &valuePiece = subCase.first; auto valueConstant = llvm::ConstantInt::get(IGF.IGM.getLLVMContext(), valuePiece); swi->addCase(valueConstant, blockForCases(subCase.second)); } } next: // Emit the recursive cases. for (auto &recursive : recursiveCases) { IGF.Builder.emitBlock(recursive.first); emitSubSwitch(IGF, values, mask, recursive.second, dflt); } }
bool swift::omitNeedlessWords(StringRef &baseName, MutableArrayRef<StringRef> argNames, StringRef firstParamName, OmissionTypeName resultType, OmissionTypeName contextType, ArrayRef<OmissionTypeName> paramTypes, bool returnsSelf, bool isProperty, const InheritedNameSet *allPropertyNames, StringScratchSpace &scratch) { bool anyChanges = false; /// Local function that lowercases all of the base names and /// argument names before returning. auto lowercaseAcronymsForReturn = [&] { StringRef newBaseName = toLowercaseInitialisms(baseName, scratch); if (baseName.data() != newBaseName.data()) { baseName = newBaseName; anyChanges = true; } for (StringRef &argName : argNames) { StringRef newArgName = toLowercaseInitialisms(argName, scratch); if (argName.data() != newArgName.data()) { argName = newArgName; anyChanges = true; } } return anyChanges; }; // If the result type matches the context, remove the context type from the // prefix of the name. bool resultTypeMatchesContext = returnsSelf || (resultType == contextType); if (resultTypeMatchesContext) { StringRef newBaseName = omitNeedlessWordsFromPrefix(baseName, contextType, scratch); if (newBaseName != baseName) { baseName = newBaseName; anyChanges = true; } } // Strip the context type from the base name of a method. if (!isProperty) { StringRef newBaseName = ::omitNeedlessWords(baseName, contextType, NameRole::BaseNameSelf, allPropertyNames, scratch); if (newBaseName != baseName) { baseName = newBaseName; anyChanges = true; } } if (paramTypes.empty()) { if (resultTypeMatchesContext) { StringRef newBaseName = ::omitNeedlessWords( baseName, returnsSelf ? contextType : resultType, NameRole::Property, allPropertyNames, scratch); if (newBaseName != baseName) { baseName = newBaseName; anyChanges = true; } } return lowercaseAcronymsForReturn(); } // If needed, split the base name. if (!argNames.empty() && splitBaseName(baseName, argNames[0], paramTypes[0], firstParamName)) anyChanges = true; // Omit needless words based on parameter types. for (unsigned i = 0, n = argNames.size(); i != n; ++i) { // If there is no corresponding parameter, there is nothing to // omit. if (i >= paramTypes.size()) continue; // Omit needless words based on the type of the parameter. NameRole role = i > 0 ? NameRole::SubsequentParameter : argNames[0].empty() ? NameRole::BaseName : baseName == "init" ? NameRole::SubsequentParameter : NameRole::FirstParameter; // Omit needless words from the name. StringRef name = role == NameRole::BaseName ? baseName : argNames[i]; StringRef newName = ::omitNeedlessWords(name, paramTypes[i], role, role == NameRole::BaseName ? allPropertyNames : nullptr, scratch); if (name == newName) continue; // Record this change. anyChanges = true; if (role == NameRole::BaseName) { baseName = newName; } else { argNames[i] = newName; } } return lowercaseAcronymsForReturn(); }