bool DevirtModule::run() { Function *TypeTestFunc = M.getFunction(Intrinsic::getName(Intrinsic::type_test)); Function *TypeCheckedLoadFunc = M.getFunction(Intrinsic::getName(Intrinsic::type_checked_load)); Function *AssumeFunc = M.getFunction(Intrinsic::getName(Intrinsic::assume)); if ((!TypeTestFunc || TypeTestFunc->use_empty() || !AssumeFunc || AssumeFunc->use_empty()) && (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->use_empty())) return false; if (TypeTestFunc && AssumeFunc) scanTypeTestUsers(TypeTestFunc, AssumeFunc); if (TypeCheckedLoadFunc) scanTypeCheckedLoadUsers(TypeCheckedLoadFunc); // Rebuild type metadata into a map for easy lookup. std::vector<VTableBits> Bits; DenseMap<Metadata *, std::set<TypeMemberInfo>> TypeIdMap; buildTypeIdentifierMap(Bits, TypeIdMap); if (TypeIdMap.empty()) return true; // For each (type, offset) pair: bool DidVirtualConstProp = false; std::map<std::string, Function*> DevirtTargets; for (auto &S : CallSlots) { // Search each of the members of the type identifier for the virtual // function implementation at offset S.first.ByteOffset, and add to // TargetsForSlot. std::vector<VirtualCallTarget> TargetsForSlot; if (!tryFindVirtualCallTargets(TargetsForSlot, TypeIdMap[S.first.TypeID], S.first.ByteOffset)) continue; if (!trySingleImplDevirt(TargetsForSlot, S.second) && tryVirtualConstProp(TargetsForSlot, S.second)) DidVirtualConstProp = true; // Collect functions devirtualized at least for one call site for stats. if (RemarksEnabled) for (const auto &T : TargetsForSlot) if (T.WasDevirt) DevirtTargets[T.Fn->getName()] = T.Fn; } if (RemarksEnabled) { // Generate remarks for each devirtualized function. for (const auto &DT : DevirtTargets) { Function *F = DT.second; DISubprogram *SP = F->getSubprogram(); DebugLoc DL = SP ? DebugLoc::get(SP->getScopeLine(), 0, SP) : DebugLoc(); emitOptimizationRemark(F->getContext(), DEBUG_TYPE, *F, DL, Twine("devirtualized ") + F->getName()); } } // If we were able to eliminate all unsafe uses for a type checked load, // eliminate the type test by replacing it with true. if (TypeCheckedLoadFunc) { auto True = ConstantInt::getTrue(M.getContext()); for (auto &&U : NumUnsafeUsesForTypeTest) { if (U.second == 0) { U.first->replaceAllUsesWith(True); U.first->eraseFromParent(); } } } // Rebuild each global we touched as part of virtual constant propagation to // include the before and after bytes. if (DidVirtualConstProp) for (VTableBits &B : Bits) rebuildGlobal(B); return true; }