// a function which searches for the key in the map passed in. Returns 0 if unsuccessful or the instruction number on success int findKey(llvm::DenseMap<llvm::Instruction*, int>& map, llvm::Instruction* key){ llvm::DenseMap<llvm::Instruction*, int>::iterator iter = map.find(key); if(iter == map.end()) return 0; else return iter->second; }
ICInfo* getICInfo(void* rtn_addr) { // TODO: load this from the CF instead of tracking it separately auto&& it = ics_by_return_addr.find(rtn_addr); if (it == ics_by_return_addr.end()) return NULL; return it->second; }
static llvm::MDNode *myGetType(const Type *type) { typedef llvm::DenseMap<const Type*, llvm::MDNode *>::const_iterator TypeNodeIter; TypeNodeIter i = myTypeDescriptors.find(type); if(i != myTypeDescriptors.end()) return i->second; return NULL; }
static void updateSSAForUseOfInst(SILSSAUpdater &Updater, SmallVectorImpl<SILArgument*> &InsertedPHIs, const llvm::DenseMap<ValueBase *, SILValue> &ValueMap, SILBasicBlock *Header, SILBasicBlock *EntryCheckBlock, ValueBase *Inst) { if (Inst->use_empty()) return; // Find the mapped instruction. assert(ValueMap.count(Inst) && "Expected to find value in map!"); SILValue MappedValue = ValueMap.find(Inst)->second; assert(MappedValue); // For each use of a specific result value of the instruction. if (Inst->hasValue()) { SILValue Res(Inst); assert(Res->getType() == MappedValue->getType() && "The types must match"); InsertedPHIs.clear(); Updater.Initialize(Res->getType()); Updater.AddAvailableValue(Header, Res); Updater.AddAvailableValue(EntryCheckBlock, MappedValue); // Because of the way that phi nodes are represented we have to collect all // uses before we update SSA. Modifying one phi node can invalidate another // unrelated phi nodes operands through the common branch instruction (that // has to be modified). This would invalidate a plain ValueUseIterator. // Instead we collect uses wrapping uses in branches specially so that we // can reconstruct the use even after the branch has been modified. SmallVector<UseWrapper, 8> StoredUses; for (auto *U : Res->getUses()) StoredUses.push_back(UseWrapper(U)); for (auto U : StoredUses) { Operand *Use = U; SILInstruction *User = Use->getUser(); assert(User && "Missing user"); // Ignore uses in the same basic block. if (User->getParent() == Header) continue; assert(User->getParent() != EntryCheckBlock && "The entry check block should dominate the header"); Updater.RewriteUse(*Use); } // Canonicalize inserted phis to avoid extra BB Args. for (SILArgument *Arg : InsertedPHIs) { if (SILInstruction *Inst = replaceBBArgWithCast(Arg)) { Arg->replaceAllUsesWith(Inst); // DCE+SimplifyCFG runs as a post-pass cleanup. // DCE replaces dead arg values with undef. // SimplifyCFG deletes the dead BB arg. } } } }
// Return a range of scopes for the given closure. The elements of the // returned range have type `SILFunction *` and are non-null. Return an empty // range for a SILFunction that is not a closure or is a dead closure. ScopeRange getClosureScopes(SILFunction *ClosureF) { IndexRange indexRange(nullptr, nullptr); auto closureScopesPos = closureToScopesMap.find(ClosureF); if (closureScopesPos != closureToScopesMap.end()) { auto &indexedScopes = closureScopesPos->second; indexRange = IndexRange(indexedScopes.begin(), indexedScopes.end()); } return makeOptionalTransformRange(indexRange, IndexLookupFunc(indexedScopes)); }
int lookupScopeIndex(SILFunction *scopeFunc) { auto indexPos = scopeToIndexMap.find(scopeFunc); if (indexPos != scopeToIndexMap.end()) return indexPos->second; int scopeIdx = indexedScopes.size(); scopeToIndexMap[scopeFunc] = scopeIdx; indexedScopes.push_back(scopeFunc); return scopeIdx; }
void erase(SILFunction *F) { // If this function is a mapped closure scope, remove it, leaving a nullptr // sentinel. auto indexPos = scopeToIndexMap.find(F); if (indexPos != scopeToIndexMap.end()) { indexedScopes[indexPos->second] = nullptr; scopeToIndexMap.erase(F); } // If this function is a closure, remove it. closureToScopesMap.erase(F); }
static void mapOperands(SILInstruction *I, const llvm::DenseMap<ValueBase *, SILValue> &ValueMap) { for (auto &Opd : I->getAllOperands()) { SILValue OrigVal = Opd.get(); ValueBase *OrigDef = OrigVal; auto Found = ValueMap.find(OrigDef); if (Found != ValueMap.end()) { SILValue MappedVal = Found->second; Opd.set(MappedVal); } } }
void addDecl(llvm::DenseMap<K, FoundDecl> &Map, K Key, FoundDecl FD) { // Add the declaration if we haven't found an equivalent yet, otherwise // replace the equivalent if the found decl has a higher access level. auto existingDecl = Map.find(Key); if ((existingDecl == Map.end()) || (Map[Key].first->getFormalAccess() < FD.first->getFormalAccess())) { if (existingDecl != Map.end()) declsToReport.erase({existingDecl->getSecond().first}); Map[Key] = FD; declsToReport.insert(FD); } }
void VisitCallExpr(CallExpr* CE) { Visit(CE->getCallee()); FunctionDecl* FDecl = CE->getDirectCallee(); if (FDecl && isDeclCandidate(FDecl)) { decl_map_t::const_iterator it = m_NonNullArgIndexs.find(FDecl); const std::bitset<32>& ArgIndexs = it->second; Sema::ContextRAII pushedDC(m_Sema, FDecl); for (int index = 0; index < 32; ++index) { if (ArgIndexs.test(index)) { // Get the argument with the nonnull attribute. Expr* Arg = CE->getArg(index); CE->setArg(index, SynthesizeCheck(Arg)); } } } }
/// Insert a block into the worklist and set its stack depth. void insert(SILBasicBlock *BB, int StackDepth) { auto Iter = Block2StackDepth.find(BB); if (Iter != Block2StackDepth.end()) { // We already handled the block. assert(StackDepth >= 0); if (Iter->second < 0) { // Update the stack depth if we didn't set it yet for the block. Iter->second = StackDepth; } else { assert(Iter->second == StackDepth && "inconsistent stack depth at a CFG merge point"); } } else { Block2StackDepth[BB] = StackDepth; ToHandle.push_back(BB); } }
static void mapOperands(SILInstruction *I, const llvm::DenseMap<ValueBase *, SILValue> &ValueMap) { for (auto &Opd : I->getAllOperands()) { SILValue OrigVal = Opd.get(); ValueBase *OrigDef = OrigVal.getDef(); auto Found = ValueMap.find(OrigDef); if (Found != ValueMap.end()) { SILValue MappedVal = Found->second; unsigned ResultIdx = OrigVal.getResultNumber(); // All mapped instructions have their result number set to zero. Except // for arguments that we followed along one edge to their incoming value // on that edge. if (isa<SILArgument>(OrigDef)) ResultIdx = MappedVal.getResultNumber(); Opd.set(SILValue(MappedVal.getDef(), ResultIdx)); } } }
bool VisitCallExpr(CallExpr* CE) { VisitStmt(CE->getCallee()); FunctionDecl* FDecl = CE->getDirectCallee(); if (FDecl && isDeclCandidate(FDecl)) { decl_map_t::const_iterator it = m_NonNullArgIndexs.find(FDecl); const std::bitset<32>& ArgIndexs = it->second; Sema::ContextRAII pushedDC(m_Sema, FDecl); for (int index = 0; index < 32; ++index) { if (ArgIndexs.test(index)) { // Get the argument with the nonnull attribute. Expr* Arg = CE->getArg(index); if (Arg->getType().getTypePtr()->isPointerType() && !llvm::isa<clang::CXXThisExpr>(Arg)) CE->setArg(index, SynthesizeCheck(Arg)); } } } return true; }
ModuleDecl *loadModule(SourceLoc importLoc, ArrayRef<std::pair<Identifier, SourceLoc>> path) { // FIXME: Implement submodule support! Identifier name = path[0].first; auto it = ModuleWrappers.find(name); if (it != ModuleWrappers.end()) return it->second->getParentModule(); auto *decl = ModuleDecl::create(name, SwiftContext); // Silence error messages about testably importing a Clang module. decl->setTestingEnabled(); decl->setHasResolvedImports(); auto wrapperUnit = new (SwiftContext) DWARFModuleUnit(*decl); ModuleWrappers.insert({name, wrapperUnit}); decl->addFile(*wrapperUnit); // Force load adapter modules for all imported modules. decl->forAllVisibleModules({}, [](ModuleDecl::ImportedModule import) {}); return decl; }
int getStackDepth(SILBasicBlock *BB) { assert(Block2StackDepth.find(BB) != Block2StackDepth.end()); int Depth = Block2StackDepth.lookup(BB); assert(Depth >= 0 && "EndBlock not reachable from StartBlock"); return Depth; }
SolutionCompareResult ConstraintSystem::compareSolutions( ConstraintSystem &cs, ArrayRef<Solution> solutions, const SolutionDiff &diff, unsigned idx1, unsigned idx2, llvm::DenseMap<Expr *, unsigned> &weights) { if (cs.TC.getLangOpts().DebugConstraintSolver) { auto &log = cs.getASTContext().TypeCheckerDebug->getStream(); log.indent(cs.solverState->depth * 2) << "comparing solutions " << idx1 << " and " << idx2 <<"\n"; } // Whether the solutions are identical. bool identical = true; // Compare the fixed scores by themselves. if (solutions[idx1].getFixedScore() != solutions[idx2].getFixedScore()) { return solutions[idx1].getFixedScore() < solutions[idx2].getFixedScore() ? SolutionCompareResult::Better : SolutionCompareResult::Worse; } // Compute relative score. unsigned score1 = 0; unsigned score2 = 0; auto foundRefinement1 = false; auto foundRefinement2 = false; bool isStdlibOptionalMPlusOperator1 = false; bool isStdlibOptionalMPlusOperator2 = false; auto getWeight = [&](ConstraintLocator *locator) -> unsigned { if (auto *anchor = locator->getAnchor()) { auto weight = weights.find(anchor); if (weight != weights.end()) return weight->getSecond() + 1; } return 1; }; // Compare overload sets. for (auto &overload : diff.overloads) { unsigned weight = getWeight(overload.locator); auto choice1 = overload.choices[idx1]; auto choice2 = overload.choices[idx2]; // If the systems made the same choice, there's nothing interesting here. if (sameOverloadChoice(choice1, choice2)) continue; auto decl1 = choice1.getDecl(); auto dc1 = decl1->getDeclContext(); auto decl2 = choice2.getDecl(); auto dc2 = decl2->getDeclContext(); // The two systems are not identical. If the decls in question are distinct // protocol members, let the checks below determine if the two choices are // 'identical' or not. This allows us to structurally unify disparate // protocol members during overload resolution. // FIXME: Along with the FIXME below, this is a hack to work around // problems with restating requirements in protocols. identical = false; bool decl1InSubprotocol = false; bool decl2InSubprotocol = false; if (dc1->getContextKind() == DeclContextKind::GenericTypeDecl && dc1->getContextKind() == dc2->getContextKind()) { auto pd1 = dyn_cast<ProtocolDecl>(dc1); auto pd2 = dyn_cast<ProtocolDecl>(dc2); // FIXME: This hack tells us to prefer members of subprotocols over // those of the protocols they inherit, if all else fails. // If we were properly handling overrides of protocol members when // requirements get restated, it would not be necessary. if (pd1 && pd2 && pd1 != pd2) { identical = true; decl1InSubprotocol = pd1->inheritsFrom(pd2); decl2InSubprotocol = pd2->inheritsFrom(pd1); } } // If the kinds of overload choice don't match... if (choice1.getKind() != choice2.getKind()) { identical = false; // A declaration found directly beats any declaration found via dynamic // lookup, bridging, or optional unwrapping. if ((choice1.getKind() == OverloadChoiceKind::Decl) && (choice2.getKind() == OverloadChoiceKind::DeclViaDynamic || choice2.getKind() == OverloadChoiceKind::DeclViaBridge || choice2.getKind() == OverloadChoiceKind::DeclViaUnwrappedOptional)) { score1 += weight; continue; } if ((choice1.getKind() == OverloadChoiceKind::DeclViaDynamic || choice1.getKind() == OverloadChoiceKind::DeclViaBridge || choice1.getKind() == OverloadChoiceKind::DeclViaUnwrappedOptional) && choice2.getKind() == OverloadChoiceKind::Decl) { score2 += weight; continue; } continue; } // The kinds of overload choice match, but the contents don't. auto &tc = cs.getTypeChecker(); switch (choice1.getKind()) { case OverloadChoiceKind::TupleIndex: continue; case OverloadChoiceKind::BaseType: case OverloadChoiceKind::KeyPathApplication: llvm_unreachable("Never considered different"); case OverloadChoiceKind::DeclViaDynamic: case OverloadChoiceKind::Decl: case OverloadChoiceKind::DeclViaBridge: case OverloadChoiceKind::DeclViaUnwrappedOptional: case OverloadChoiceKind::DynamicMemberLookup: break; } // Determine whether one declaration is more specialized than the other. bool firstAsSpecializedAs = false; bool secondAsSpecializedAs = false; if (isDeclAsSpecializedAs(tc, cs.DC, decl1, decl2)) { score1 += weight; firstAsSpecializedAs = true; } if (isDeclAsSpecializedAs(tc, cs.DC, decl2, decl1)) { score2 += weight; secondAsSpecializedAs = true; } // If each is as specialized as the other, and both are constructors, // check the constructor kind. if (firstAsSpecializedAs && secondAsSpecializedAs) { if (auto ctor1 = dyn_cast<ConstructorDecl>(decl1)) { if (auto ctor2 = dyn_cast<ConstructorDecl>(decl2)) { if (ctor1->getInitKind() != ctor2->getInitKind()) { if (ctor1->getInitKind() < ctor2->getInitKind()) score1 += weight; else score2 += weight; } else if (ctor1->getInitKind() == CtorInitializerKind::Convenience) { // If both are convenience initializers, and the instance type of // one is a subtype of the other's, favor the subtype constructor. auto resType1 = ctor1->mapTypeIntoContext( ctor1->getResultInterfaceType()); auto resType2 = ctor2->mapTypeIntoContext( ctor2->getResultInterfaceType()); if (!resType1->isEqual(resType2)) { if (tc.isSubtypeOf(resType1, resType2, cs.DC)) { score1 += weight; } else if (tc.isSubtypeOf(resType2, resType1, cs.DC)) { score2 += weight; } } } } } } // If both declarations come from Clang, and one is a type and the other // is a function, prefer the function. if (decl1->hasClangNode() && decl2->hasClangNode() && ((isa<TypeDecl>(decl1) && isa<AbstractFunctionDecl>(decl2)) || (isa<AbstractFunctionDecl>(decl1) && isa<TypeDecl>(decl2)))) { if (isa<TypeDecl>(decl1)) score2 += weight; else score1 += weight; } // A class member is always better than a curried instance member. // If the members agree on instance-ness, a property is better than a // method (because a method is usually immediately invoked). if (!decl1->isInstanceMember() && decl2->isInstanceMember()) score1 += weight; else if (!decl2->isInstanceMember() && decl1->isInstanceMember()) score2 += weight; else if (isa<VarDecl>(decl1) && isa<FuncDecl>(decl2)) score1 += weight; else if (isa<VarDecl>(decl2) && isa<FuncDecl>(decl1)) score2 += weight; // If both are class properties with the same name, prefer // the one attached to the subclass because it could only be // found if requested directly. if (!decl1->isInstanceMember() && !decl2->isInstanceMember()) { if (isa<VarDecl>(decl1) && isa<VarDecl>(decl2)) { auto *nominal1 = dc1->getAsNominalTypeOrNominalTypeExtensionContext(); auto *nominal2 = dc2->getAsNominalTypeOrNominalTypeExtensionContext(); if (nominal1 && nominal2 && nominal1 != nominal2) { auto base1 = nominal1->getDeclaredType(); auto base2 = nominal2->getDeclaredType(); if (isNominallySuperclassOf(base1, base2)) score2 += weight; if (isNominallySuperclassOf(base2, base1)) score1 += weight; } } } // If we haven't found a refinement, record whether one overload is in // any way more constrained than another. We'll only utilize this // information in the case of a potential ambiguity. if (!(foundRefinement1 && foundRefinement2)) { if (isDeclMoreConstrainedThan(decl1, decl2)) { foundRefinement1 = true; } if (isDeclMoreConstrainedThan(decl2, decl1)) { foundRefinement2 = true; } } // FIXME: The rest of the hack for restating requirements. if (!(foundRefinement1 && foundRefinement2)) { if (identical && decl1InSubprotocol != decl2InSubprotocol) { foundRefinement1 = decl1InSubprotocol; foundRefinement2 = decl2InSubprotocol; } } // FIXME: Lousy hack for ?? to prefer the catamorphism (flattening) // over the mplus (non-flattening) overload if all else is equal. if (decl1->getBaseName() == "??") { assert(decl2->getBaseName() == "??"); auto check = [](const ValueDecl *VD) -> bool { if (!VD->getModuleContext()->isStdlibModule()) return false; auto fnTy = VD->getInterfaceType()->castTo<AnyFunctionType>(); if (!fnTy->getResult()->getOptionalObjectType()) return false; // Check that the standard library hasn't added another overload of // the ?? operator. auto params = fnTy->getParams(); assert(params.size() == 2); auto param1 = params[0].getType(); auto param2 = params[1].getType()->castTo<AnyFunctionType>(); assert(param1->getOptionalObjectType()); assert(param2->isAutoClosure()); assert(param2->getResult()->getOptionalObjectType()); (void) param1; (void) param2; return true; }; isStdlibOptionalMPlusOperator1 = check(decl1); isStdlibOptionalMPlusOperator2 = check(decl2); } } // Compare the type variable bindings. auto &tc = cs.getTypeChecker(); for (auto &binding : diff.typeBindings) { // If the type variable isn't one for which we should be looking at the // bindings, don't. if (!binding.typeVar->getImpl().prefersSubtypeBinding()) continue; auto type1 = binding.bindings[idx1]; auto type2 = binding.bindings[idx2]; // If the types are equivalent, there's nothing more to do. if (type1->isEqual(type2)) continue; // If either of the types still contains type variables, we can't // compare them. // FIXME: This is really unfortunate. More type variable sharing // (when it's sane) would help us do much better here. if (type1->hasTypeVariable() || type2->hasTypeVariable()) { identical = false; continue; } // If one type is a subtype of the other, but not vice-versa, // we prefer the system with the more-constrained type. // FIXME: Collapse this check into the second check. auto type1Better = tc.isSubtypeOf(type1, type2, cs.DC); auto type2Better = tc.isSubtypeOf(type2, type1, cs.DC); if (type1Better || type2Better) { if (type1Better) ++score1; if (type2Better) ++score2; // Prefer the unlabeled form of a type. auto unlabeled1 = type1->getUnlabeledType(cs.getASTContext()); auto unlabeled2 = type2->getUnlabeledType(cs.getASTContext()); if (unlabeled1->isEqual(unlabeled2)) { if (type1->isEqual(unlabeled1)) { ++score1; continue; } if (type2->isEqual(unlabeled2)) { ++score2; continue; } } identical = false; continue; } // The systems are not considered equivalent. identical = false; // If one type is convertible to of the other, but not vice-versa. type1Better = tc.isConvertibleTo(type1, type2, cs.DC); type2Better = tc.isConvertibleTo(type2, type1, cs.DC); if (type1Better || type2Better) { if (type1Better) ++score1; if (type2Better) ++score2; continue; } // A concrete type is better than an archetype. // FIXME: Total hack. if (type1->is<ArchetypeType>() != type2->is<ArchetypeType>()) { if (type1->is<ArchetypeType>()) ++score2; else ++score1; continue; } // FIXME: // This terrible hack is in place to support equality comparisons of non- // equatable option types to 'nil'. Until we have a way to constrain a type // variable on "!Equatable", if all other aspects of the overload choices // are equal, favor the overload that does not require an implicit literal // argument conversion to 'nil'. // Post-1.0, we'll need to remove this hack in favor of richer constraint // declarations. if (!(score1 || score2)) { if (auto nominalType2 = type2->getNominalOrBoundGenericNominal()) { if ((nominalType2->getName() == cs.TC.Context.Id_OptionalNilComparisonType)) { ++score2; } } if (auto nominalType1 = type1->getNominalOrBoundGenericNominal()) { if ((nominalType1->getName() == cs.TC.Context.Id_OptionalNilComparisonType)) { ++score1; } } } } // All other things considered equal, if any overload choice is more // more constrained than the other, increment the score. if (score1 == score2) { if (foundRefinement1) { ++score1; } if (foundRefinement2) { ++score2; } } // FIXME: All other things being equal, prefer the catamorphism (flattening) // overload of ?? over the mplus (non-flattening) overload. if (score1 == score2) { // This is correct: we want to /disprefer/ the mplus. score2 += isStdlibOptionalMPlusOperator1; score1 += isStdlibOptionalMPlusOperator2; } // FIXME: There are type variables and overloads not common to both solutions // that haven't been considered. They make the systems different, but don't // affect ranking. We need to handle this. // If the scores are different, we have a winner. if (score1 != score2) { return score1 > score2? SolutionCompareResult::Better : SolutionCompareResult::Worse; } // Neither system wins; report whether they were identical or not. return identical? SolutionCompareResult::Identical : SolutionCompareResult::Incomparable; }