diff options
author | Daniel Jasper <djasper@google.com> | 2017-02-15 09:56:08 +0000 |
---|---|---|
committer | Daniel Jasper <djasper@google.com> | 2017-02-15 09:56:08 +0000 |
commit | eef9b03395ccd2908718585e2b6d17c392e6ccd5 (patch) | |
tree | de51a34bdb908a86d1b4dc8af7ef67a93da72739 /llvm/lib | |
parent | 2c29b4036049d51699e519d38263a648bf254476 (diff) | |
download | bcm5719-llvm-eef9b03395ccd2908718585e2b6d17c392e6ccd5.tar.gz bcm5719-llvm-eef9b03395ccd2908718585e2b6d17c392e6ccd5.zip |
Revert r295110 and r295144.
This fails under ASAN:
http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-bootstrap/builds/798/steps/check-llvm%20asan/logs/stdio
llvm-svn: 295162
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp | 254 |
1 files changed, 98 insertions, 156 deletions
diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp index 7555baae599..73ea5c19267 100644 --- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -282,48 +282,6 @@ struct VirtualCallSite { } }; -// Call site information collected for a specific VTableSlot and possibly a list -// of constant integer arguments. The grouping by arguments is handled by the -// VTableSlotInfo class. -struct CallSiteInfo { - std::vector<VirtualCallSite> CallSites; -}; - -// Call site information collected for a specific VTableSlot. -struct VTableSlotInfo { - // The set of call sites which do not have all constant integer arguments - // (excluding "this"). - CallSiteInfo CSInfo; - - // The set of call sites with all constant integer arguments (excluding - // "this"), grouped by argument list. - std::map<std::vector<uint64_t>, CallSiteInfo> ConstCSInfo; - - void addCallSite(Value *VTable, CallSite CS, unsigned *NumUnsafeUses); - -private: - CallSiteInfo &findCallSiteInfo(CallSite CS); -}; - -CallSiteInfo &VTableSlotInfo::findCallSiteInfo(CallSite CS) { - std::vector<uint64_t> Args; - auto *CI = dyn_cast<IntegerType>(CS.getType()); - if (!CI || CI->getBitWidth() > 64) - return CSInfo; - for (auto &&Arg : make_range(CS.arg_begin() + 1, CS.arg_end())) { - auto *CI = dyn_cast<ConstantInt>(Arg); - if (!CI || CI->getBitWidth() > 64) - return CSInfo; - Args.push_back(CI->getZExtValue()); - } - return ConstCSInfo[Args]; -} - -void VTableSlotInfo::addCallSite(Value *VTable, CallSite CS, - unsigned *NumUnsafeUses) { - findCallSiteInfo(CS).CallSites.push_back({VTable, CS, NumUnsafeUses}); -} - struct DevirtModule { Module &M; @@ -333,11 +291,10 @@ struct DevirtModule { IntegerType *Int8Ty; PointerType *Int8PtrTy; IntegerType *Int32Ty; - IntegerType *Int64Ty; bool RemarksEnabled; - MapVector<VTableSlot, VTableSlotInfo> CallSlots; + MapVector<VTableSlot, std::vector<VirtualCallSite>> CallSlots; // This map keeps track of the number of "unsafe" uses of a loaded function // pointer. The key is the associated llvm.type.test intrinsic call generated @@ -354,7 +311,6 @@ struct DevirtModule { Int8Ty(Type::getInt8Ty(M.getContext())), Int8PtrTy(Type::getInt8PtrTy(M.getContext())), Int32Ty(Type::getInt32Ty(M.getContext())), - Int64Ty(Type::getInt64Ty(M.getContext())), RemarksEnabled(areRemarksEnabled()) {} bool areRemarksEnabled(); @@ -370,30 +326,19 @@ struct DevirtModule { tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot, const std::set<TypeMemberInfo> &TypeMemberInfos, uint64_t ByteOffset); - - void applySingleImplDevirt(VTableSlotInfo &SlotInfo, Constant *TheFn); bool trySingleImplDevirt(MutableArrayRef<VirtualCallTarget> TargetsForSlot, - VTableSlotInfo &SlotInfo); - + MutableArrayRef<VirtualCallSite> CallSites); bool tryEvaluateFunctionsWithArgs( MutableArrayRef<VirtualCallTarget> TargetsForSlot, - ArrayRef<uint64_t> Args); - - void applyUniformRetValOpt(CallSiteInfo &CSInfo, StringRef FnName, - uint64_t TheRetVal); - bool tryUniformRetValOpt(MutableArrayRef<VirtualCallTarget> TargetsForSlot, - CallSiteInfo &CSInfo); - - void applyUniqueRetValOpt(CallSiteInfo &CSInfo, StringRef FnName, bool IsOne, - Constant *UniqueMemberAddr); + ArrayRef<ConstantInt *> Args); + bool tryUniformRetValOpt(IntegerType *RetType, + MutableArrayRef<VirtualCallTarget> TargetsForSlot, + MutableArrayRef<VirtualCallSite> CallSites); bool tryUniqueRetValOpt(unsigned BitWidth, MutableArrayRef<VirtualCallTarget> TargetsForSlot, - CallSiteInfo &CSInfo); - - void applyVirtualConstProp(CallSiteInfo &CSInfo, StringRef FnName, - Constant *Byte, Constant *Bit); + MutableArrayRef<VirtualCallSite> CallSites); bool tryVirtualConstProp(MutableArrayRef<VirtualCallTarget> TargetsForSlot, - VTableSlotInfo &SlotInfo); + ArrayRef<VirtualCallSite> CallSites); void rebuildGlobal(VTableBits &B); @@ -574,27 +519,9 @@ bool DevirtModule::tryFindVirtualCallTargets( return !TargetsForSlot.empty(); } -void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo, - Constant *TheFn) { - auto Apply = [&](CallSiteInfo &CSInfo) { - for (auto &&VCallSite : CSInfo.CallSites) { - if (RemarksEnabled) - VCallSite.emitRemark("single-impl", TheFn->getName()); - VCallSite.CS.setCalledFunction(ConstantExpr::getBitCast( - TheFn, VCallSite.CS.getCalledValue()->getType())); - // This use is no longer unsafe. - if (VCallSite.NumUnsafeUses) - --*VCallSite.NumUnsafeUses; - } - }; - Apply(SlotInfo.CSInfo); - for (auto &P : SlotInfo.ConstCSInfo) - Apply(P.second); -} - bool DevirtModule::trySingleImplDevirt( MutableArrayRef<VirtualCallTarget> TargetsForSlot, - VTableSlotInfo &SlotInfo) { + MutableArrayRef<VirtualCallSite> CallSites) { // See if the program contains a single implementation of this virtual // function. Function *TheFn = TargetsForSlot[0].Fn; @@ -602,34 +529,39 @@ bool DevirtModule::trySingleImplDevirt( if (TheFn != Target.Fn) return false; - // If so, update each call site to call that implementation directly. if (RemarksEnabled) TargetsForSlot[0].WasDevirt = true; - applySingleImplDevirt(SlotInfo, TheFn); + // If so, update each call site to call that implementation directly. + for (auto &&VCallSite : CallSites) { + if (RemarksEnabled) + VCallSite.emitRemark("single-impl", TheFn->getName()); + VCallSite.CS.setCalledFunction(ConstantExpr::getBitCast( + TheFn, VCallSite.CS.getCalledValue()->getType())); + // This use is no longer unsafe. + if (VCallSite.NumUnsafeUses) + --*VCallSite.NumUnsafeUses; + } return true; } bool DevirtModule::tryEvaluateFunctionsWithArgs( MutableArrayRef<VirtualCallTarget> TargetsForSlot, - ArrayRef<uint64_t> Args) { + ArrayRef<ConstantInt *> Args) { // Evaluate each function and store the result in each target's RetVal // field. for (VirtualCallTarget &Target : TargetsForSlot) { if (Target.Fn->arg_size() != Args.size() + 1) return false; + for (unsigned I = 0; I != Args.size(); ++I) + if (Target.Fn->getFunctionType()->getParamType(I + 1) != + Args[I]->getType()) + return false; Evaluator Eval(M.getDataLayout(), nullptr); SmallVector<Constant *, 2> EvalArgs; EvalArgs.push_back( Constant::getNullValue(Target.Fn->getFunctionType()->getParamType(0))); - for (unsigned I = 0; I != Args.size(); ++I) { - auto *ArgTy = dyn_cast<IntegerType>( - Target.Fn->getFunctionType()->getParamType(I + 1)); - if (!ArgTy) - return false; - EvalArgs.push_back(ConstantInt::get(ArgTy, Args[I])); - } - + EvalArgs.insert(EvalArgs.end(), Args.begin(), Args.end()); Constant *RetVal; if (!Eval.EvaluateFunction(Target.Fn, RetVal, EvalArgs) || !isa<ConstantInt>(RetVal)) @@ -639,16 +571,9 @@ bool DevirtModule::tryEvaluateFunctionsWithArgs( return true; } -void DevirtModule::applyUniformRetValOpt(CallSiteInfo &CSInfo, StringRef FnName, - uint64_t TheRetVal) { - for (auto Call : CSInfo.CallSites) - Call.replaceAndErase( - "uniform-ret-val", FnName, RemarksEnabled, - ConstantInt::get(cast<IntegerType>(Call.CS.getType()), TheRetVal)); -} - bool DevirtModule::tryUniformRetValOpt( - MutableArrayRef<VirtualCallTarget> TargetsForSlot, CallSiteInfo &CSInfo) { + IntegerType *RetType, MutableArrayRef<VirtualCallTarget> TargetsForSlot, + MutableArrayRef<VirtualCallSite> CallSites) { // Uniform return value optimization. If all functions return the same // constant, replace all calls with that constant. uint64_t TheRetVal = TargetsForSlot[0].RetVal; @@ -656,28 +581,19 @@ bool DevirtModule::tryUniformRetValOpt( if (Target.RetVal != TheRetVal) return false; - applyUniformRetValOpt(CSInfo, TargetsForSlot[0].Fn->getName(), TheRetVal); + auto TheRetValConst = ConstantInt::get(RetType, TheRetVal); + for (auto Call : CallSites) + Call.replaceAndErase("uniform-ret-val", TargetsForSlot[0].Fn->getName(), + RemarksEnabled, TheRetValConst); if (RemarksEnabled) for (auto &&Target : TargetsForSlot) Target.WasDevirt = true; return true; } -void DevirtModule::applyUniqueRetValOpt(CallSiteInfo &CSInfo, StringRef FnName, - bool IsOne, - Constant *UniqueMemberAddr) { - for (auto &&Call : CSInfo.CallSites) { - IRBuilder<> B(Call.CS.getInstruction()); - Value *Cmp = B.CreateICmp(IsOne ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE, - Call.VTable, UniqueMemberAddr); - Cmp = B.CreateZExt(Cmp, Call.CS->getType()); - Call.replaceAndErase("unique-ret-val", FnName, RemarksEnabled, Cmp); - } -} - bool DevirtModule::tryUniqueRetValOpt( unsigned BitWidth, MutableArrayRef<VirtualCallTarget> TargetsForSlot, - CallSiteInfo &CSInfo) { + MutableArrayRef<VirtualCallSite> CallSites) { // IsOne controls whether we look for a 0 or a 1. auto tryUniqueRetValOptFor = [&](bool IsOne) { const TypeMemberInfo *UniqueMember = nullptr; @@ -694,15 +610,15 @@ bool DevirtModule::tryUniqueRetValOpt( assert(UniqueMember); // Replace each call with the comparison. - Constant *UniqueMemberAddr = - ConstantExpr::getBitCast(UniqueMember->Bits->GV, Int8PtrTy); - UniqueMemberAddr = ConstantExpr::getGetElementPtr( - Int8Ty, UniqueMemberAddr, - ConstantInt::get(Int64Ty, UniqueMember->Offset)); - - applyUniqueRetValOpt(CSInfo, TargetsForSlot[0].Fn->getName(), IsOne, - UniqueMemberAddr); - + for (auto &&Call : CallSites) { + IRBuilder<> B(Call.CS.getInstruction()); + Value *OneAddr = B.CreateBitCast(UniqueMember->Bits->GV, Int8PtrTy); + OneAddr = B.CreateConstGEP1_64(OneAddr, UniqueMember->Offset); + Value *Cmp = B.CreateICmp(IsOne ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE, + Call.VTable, OneAddr); + Call.replaceAndErase("unique-ret-val", TargetsForSlot[0].Fn->getName(), + RemarksEnabled, Cmp); + } // Update devirtualization statistics for targets. if (RemarksEnabled) for (auto &&Target : TargetsForSlot) @@ -720,29 +636,9 @@ bool DevirtModule::tryUniqueRetValOpt( return false; } -void DevirtModule::applyVirtualConstProp(CallSiteInfo &CSInfo, StringRef FnName, - Constant *Byte, Constant *Bit) { - for (auto Call : CSInfo.CallSites) { - auto *RetType = cast<IntegerType>(Call.CS.getType()); - IRBuilder<> B(Call.CS.getInstruction()); - Value *Addr = B.CreateGEP(Int8Ty, Call.VTable, Byte); - if (RetType->getBitWidth() == 1) { - Value *Bits = B.CreateLoad(Addr); - Value *BitsAndBit = B.CreateAnd(Bits, Bit); - auto IsBitSet = B.CreateICmpNE(BitsAndBit, ConstantInt::get(Int8Ty, 0)); - Call.replaceAndErase("virtual-const-prop-1-bit", FnName, RemarksEnabled, - IsBitSet); - } else { - Value *ValAddr = B.CreateBitCast(Addr, RetType->getPointerTo()); - Value *Val = B.CreateLoad(RetType, ValAddr); - Call.replaceAndErase("virtual-const-prop", FnName, RemarksEnabled, Val); - } - } -} - bool DevirtModule::tryVirtualConstProp( MutableArrayRef<VirtualCallTarget> TargetsForSlot, - VTableSlotInfo &SlotInfo) { + ArrayRef<VirtualCallSite> CallSites) { // This only works if the function returns an integer. auto RetType = dyn_cast<IntegerType>(TargetsForSlot[0].Fn->getReturnType()); if (!RetType) @@ -761,11 +657,42 @@ bool DevirtModule::tryVirtualConstProp( return false; } - for (auto &&CSByConstantArg : SlotInfo.ConstCSInfo) { + // Group call sites by the list of constant arguments they pass. + // The comparator ensures deterministic ordering. + struct ByAPIntValue { + bool operator()(const std::vector<ConstantInt *> &A, + const std::vector<ConstantInt *> &B) const { + return std::lexicographical_compare( + A.begin(), A.end(), B.begin(), B.end(), + [](ConstantInt *AI, ConstantInt *BI) { + return AI->getValue().ult(BI->getValue()); + }); + } + }; + std::map<std::vector<ConstantInt *>, std::vector<VirtualCallSite>, + ByAPIntValue> + VCallSitesByConstantArg; + for (auto &&VCallSite : CallSites) { + std::vector<ConstantInt *> Args; + if (VCallSite.CS.getType() != RetType) + continue; + for (auto &&Arg : + make_range(VCallSite.CS.arg_begin() + 1, VCallSite.CS.arg_end())) { + if (!isa<ConstantInt>(Arg)) + break; + Args.push_back(cast<ConstantInt>(&Arg)); + } + if (Args.size() + 1 != VCallSite.CS.arg_size()) + continue; + + VCallSitesByConstantArg[Args].push_back(VCallSite); + } + + for (auto &&CSByConstantArg : VCallSitesByConstantArg) { if (!tryEvaluateFunctionsWithArgs(TargetsForSlot, CSByConstantArg.first)) continue; - if (tryUniformRetValOpt(TargetsForSlot, CSByConstantArg.second)) + if (tryUniformRetValOpt(RetType, TargetsForSlot, CSByConstantArg.second)) continue; if (tryUniqueRetValOpt(BitWidth, TargetsForSlot, CSByConstantArg.second)) @@ -809,10 +736,25 @@ bool DevirtModule::tryVirtualConstProp( Target.WasDevirt = true; // Rewrite each call to a load from OffsetByte/OffsetBit. - Constant *ByteConst = ConstantInt::get(Int64Ty, OffsetByte); - Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit); - applyVirtualConstProp(CSByConstantArg.second, - TargetsForSlot[0].Fn->getName(), ByteConst, BitConst); + for (auto Call : CSByConstantArg.second) { + IRBuilder<> B(Call.CS.getInstruction()); + Value *Addr = B.CreateConstGEP1_64(Call.VTable, OffsetByte); + if (BitWidth == 1) { + Value *Bits = B.CreateLoad(Addr); + Value *Bit = ConstantInt::get(Int8Ty, 1ULL << OffsetBit); + Value *BitsAndBit = B.CreateAnd(Bits, Bit); + auto IsBitSet = B.CreateICmpNE(BitsAndBit, ConstantInt::get(Int8Ty, 0)); + Call.replaceAndErase("virtual-const-prop-1-bit", + TargetsForSlot[0].Fn->getName(), + RemarksEnabled, IsBitSet); + } else { + Value *ValAddr = B.CreateBitCast(Addr, RetType->getPointerTo()); + Value *Val = B.CreateLoad(RetType, ValAddr); + Call.replaceAndErase("virtual-const-prop", + TargetsForSlot[0].Fn->getName(), + RemarksEnabled, Val); + } + } } return true; } @@ -900,8 +842,8 @@ void DevirtModule::scanTypeTestUsers(Function *TypeTestFunc, Value *Ptr = CI->getArgOperand(0)->stripPointerCasts(); if (SeenPtrs.insert(Ptr).second) { for (DevirtCallSite Call : DevirtCalls) { - CallSlots[{TypeId, Call.Offset}].addCallSite(CI->getArgOperand(0), - Call.CS, nullptr); + CallSlots[{TypeId, Call.Offset}].push_back( + {CI->getArgOperand(0), Call.CS, nullptr}); } } } @@ -987,8 +929,8 @@ void DevirtModule::scanTypeCheckedLoadUsers(Function *TypeCheckedLoadFunc) { if (HasNonCallUses) ++NumUnsafeUses; for (DevirtCallSite Call : DevirtCalls) { - CallSlots[{TypeId, Call.Offset}].addCallSite(Ptr, Call.CS, - &NumUnsafeUses); + CallSlots[{TypeId, Call.Offset}].push_back( + {Ptr, Call.CS, &NumUnsafeUses}); } CI->eraseFromParent(); |