Index: llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp =================================================================== --- llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -297,6 +297,7 @@ IntegerType *Int8Ty; PointerType *Int8PtrTy; IntegerType *Int32Ty; + IntegerType *Int64Ty; bool RemarksEnabled; @@ -316,6 +317,7 @@ : M(M), Int8Ty(Type::getInt8Ty(M.getContext())), Int8PtrTy(Type::getInt8PtrTy(M.getContext())), Int32Ty(Type::getInt32Ty(M.getContext())), + Int64Ty(Type::getInt64Ty(M.getContext())), RemarksEnabled(areRemarksEnabled()) {} bool areRemarksEnabled(); @@ -331,16 +333,28 @@ tryFindVirtualCallTargets(std::vector &TargetsForSlot, const std::set &TypeMemberInfos, uint64_t ByteOffset); + + void applySingleImplDevirt(VTableSlotInfo &SlotInfo, Constant *TheFn); bool trySingleImplDevirt(MutableArrayRef TargetsForSlot, VTableSlotInfo &SlotInfo); + bool tryEvaluateFunctionsWithArgs( MutableArrayRef TargetsForSlot, ArrayRef Args); + + void applyUniformRetValOpt(CallSiteInfo &CSInfo, StringRef FnName, + uint64_t TheRetVal); bool tryUniformRetValOpt(MutableArrayRef TargetsForSlot, CallSiteInfo &CSInfo); + + void applyUniqueRetValOpt(CallSiteInfo &CSInfo, StringRef FnName, bool IsOne, + Constant *UniqueMemberAddr); bool tryUniqueRetValOpt(unsigned BitWidth, MutableArrayRef TargetsForSlot, CallSiteInfo &CSInfo); + + void applyVirtualConstProp(CallSiteInfo &CSInfo, StringRef FnName, + Constant *Byte, Constant *Bit); bool tryVirtualConstProp(MutableArrayRef TargetsForSlot, VTableSlotInfo &SlotInfo); @@ -475,19 +489,8 @@ return !TargetsForSlot.empty(); } -bool DevirtModule::trySingleImplDevirt( - MutableArrayRef TargetsForSlot, - VTableSlotInfo &SlotInfo) { - // See if the program contains a single implementation of this virtual - // function. - Function *TheFn = TargetsForSlot[0].Fn; - for (auto &&Target : TargetsForSlot) - if (TheFn != Target.Fn) - return false; - - if (RemarksEnabled) - TargetsForSlot[0].WasDevirt = true; - // If so, update each call site to call that implementation directly. +void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo, + Constant *TheFn) { auto Apply = [&](CallSiteInfo &CSInfo) { for (auto &&VCallSite : CSInfo.CallSites) { if (RemarksEnabled) @@ -502,6 +505,22 @@ Apply(SlotInfo.CSInfo); for (auto &P : SlotInfo.ConstCSInfo) Apply(P.second); +} + +bool DevirtModule::trySingleImplDevirt( + MutableArrayRef TargetsForSlot, + VTableSlotInfo &SlotInfo) { + // See if the program contains a single implementation of this virtual + // function. + Function *TheFn = TargetsForSlot[0].Fn; + for (auto &&Target : TargetsForSlot) + 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); return true; } @@ -535,6 +554,14 @@ 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(Call.CS.getType()), TheRetVal)); +} + bool DevirtModule::tryUniformRetValOpt( MutableArrayRef TargetsForSlot, CallSiteInfo &CSInfo) { // Uniform return value optimization. If all functions return the same @@ -544,16 +571,24 @@ if (Target.RetVal != TheRetVal) return false; - for (auto Call : CSInfo.CallSites) - Call.replaceAndErase("uniform-ret-val", TargetsForSlot[0].Fn->getName(), - RemarksEnabled, - ConstantInt::get(Call.CS->getType(), TheRetVal)); + applyUniformRetValOpt(CSInfo, TargetsForSlot[0].Fn->getName(), TheRetVal); 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); + Call.replaceAndErase("unique-ret-val", FnName, RemarksEnabled, Cmp); + } +} + bool DevirtModule::tryUniqueRetValOpt( unsigned BitWidth, MutableArrayRef TargetsForSlot, CallSiteInfo &CSInfo) { @@ -573,16 +608,15 @@ assert(UniqueMember); // Replace each call with the comparison. - for (auto &&Call : CSInfo.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); - Cmp = B.CreateZExt(Cmp, Call.CS->getType()); - Call.replaceAndErase("unique-ret-val", TargetsForSlot[0].Fn->getName(), - RemarksEnabled, Cmp); - } + 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); + // Update devirtualization statistics for targets. if (RemarksEnabled) for (auto &&Target : TargetsForSlot) @@ -600,6 +634,26 @@ return false; } +void DevirtModule::applyVirtualConstProp(CallSiteInfo &CSInfo, StringRef FnName, + Constant *Byte, Constant *Bit) { + for (auto Call : CSInfo.CallSites) { + auto *RetType = cast(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 TargetsForSlot, VTableSlotInfo &SlotInfo) { @@ -669,28 +723,10 @@ Target.WasDevirt = true; // Rewrite each call to a load from OffsetByte/OffsetBit. - for (auto Call : CSByConstantArg.second.CallSites) { - auto *CSRetType = cast(Call.CS.getType()); - IRBuilder<> B(Call.CS.getInstruction()); - Value *Addr = B.CreateConstGEP1_64(Call.VTable, OffsetByte); - if (CSRetType->getBitWidth() == 1) { - Value *Bits = B.CreateLoad(Addr); - Value *Bit = ConstantInt::get(Int8Ty, 1ULL << OffsetBit); - Value *BitsAndBit = B.CreateAnd(Bits, Bit); - Value *IsBitSet = - B.CreateICmpNE(BitsAndBit, ConstantInt::get(Int8Ty, 0)); - IsBitSet = B.CreateZExt(IsBitSet, Call.CS->getType()); - Call.replaceAndErase("virtual-const-prop-1-bit", - TargetsForSlot[0].Fn->getName(), - RemarksEnabled, IsBitSet); - } else { - Value *ValAddr = B.CreateBitCast(Addr, CSRetType->getPointerTo()); - Value *Val = B.CreateLoad(CSRetType, ValAddr); - Call.replaceAndErase("virtual-const-prop", - TargetsForSlot[0].Fn->getName(), - RemarksEnabled, Val); - } - } + Constant *ByteConst = ConstantInt::get(Int64Ty, OffsetByte); + Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit); + applyVirtualConstProp(CSByConstantArg.second, + TargetsForSlot[0].Fn->getName(), ByteConst, BitConst); } return true; }