diff options
Diffstat (limited to 'lib/Transforms/IPO/WholeProgramDevirt.cpp')
| -rw-r--r-- | lib/Transforms/IPO/WholeProgramDevirt.cpp | 202 | 
1 files changed, 154 insertions, 48 deletions
diff --git a/lib/Transforms/IPO/WholeProgramDevirt.cpp b/lib/Transforms/IPO/WholeProgramDevirt.cpp index 00769cd63229..ec56f0cde25d 100644 --- a/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ b/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -51,14 +51,13 @@  #include "llvm/ADT/iterator_range.h"  #include "llvm/Analysis/AliasAnalysis.h"  #include "llvm/Analysis/BasicAliasAnalysis.h" +#include "llvm/Analysis/OptimizationRemarkEmitter.h"  #include "llvm/Analysis/TypeMetadataUtils.h"  #include "llvm/IR/CallSite.h"  #include "llvm/IR/Constants.h"  #include "llvm/IR/DataLayout.h" -#include "llvm/IR/DebugInfoMetadata.h"  #include "llvm/IR/DebugLoc.h"  #include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/DiagnosticInfo.h"  #include "llvm/IR/Function.h"  #include "llvm/IR/GlobalAlias.h"  #include "llvm/IR/GlobalVariable.h" @@ -275,18 +274,39 @@ struct VirtualCallSite {    // of that field for details.    unsigned *NumUnsafeUses; -  void emitRemark(const Twine &OptName, const Twine &TargetName) { +  void +  emitRemark(const StringRef OptName, const StringRef TargetName, +             function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter) {      Function *F = CS.getCaller(); -    emitOptimizationRemark( -        F->getContext(), DEBUG_TYPE, *F, -        CS.getInstruction()->getDebugLoc(), -        OptName + ": devirtualized a call to " + TargetName); +    DebugLoc DLoc = CS->getDebugLoc(); +    BasicBlock *Block = CS.getParent(); + +    // In the new pass manager, we can request the optimization +    // remark emitter pass on a per-function-basis, which the +    // OREGetter will do for us. +    // In the old pass manager, this is harder, so we just build +    // a optimization remark emitter on the fly, when we need it. +    std::unique_ptr<OptimizationRemarkEmitter> OwnedORE; +    OptimizationRemarkEmitter *ORE; +    if (OREGetter) +      ORE = &OREGetter(F); +    else { +      OwnedORE = make_unique<OptimizationRemarkEmitter>(F); +      ORE = OwnedORE.get(); +    } + +    using namespace ore; +    ORE->emit(OptimizationRemark(DEBUG_TYPE, OptName, DLoc, Block) +              << NV("Optimization", OptName) << ": devirtualized a call to " +              << NV("FunctionName", TargetName));    } -  void replaceAndErase(const Twine &OptName, const Twine &TargetName, -                       bool RemarksEnabled, Value *New) { +  void replaceAndErase( +      const StringRef OptName, const StringRef TargetName, bool RemarksEnabled, +      function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter, +      Value *New) {      if (RemarksEnabled) -      emitRemark(OptName, TargetName); +      emitRemark(OptName, TargetName, OREGetter);      CS->replaceAllUsesWith(New);      if (auto II = dyn_cast<InvokeInst>(CS.getInstruction())) {        BranchInst::Create(II->getNormalDest(), CS.getInstruction()); @@ -383,6 +403,7 @@ struct DevirtModule {    IntegerType *IntPtrTy;    bool RemarksEnabled; +  function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter;    MapVector<VTableSlot, VTableSlotInfo> CallSlots; @@ -397,6 +418,7 @@ struct DevirtModule {    std::map<CallInst *, unsigned> NumUnsafeUsesForTypeTest;    DevirtModule(Module &M, function_ref<AAResults &(Function &)> AARGetter, +               function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter,                 ModuleSummaryIndex *ExportSummary,                 const ModuleSummaryIndex *ImportSummary)        : M(M), AARGetter(AARGetter), ExportSummary(ExportSummary), @@ -405,7 +427,7 @@ struct DevirtModule {          Int32Ty(Type::getInt32Ty(M.getContext())),          Int64Ty(Type::getInt64Ty(M.getContext())),          IntPtrTy(M.getDataLayout().getIntPtrType(M.getContext(), 0)), -        RemarksEnabled(areRemarksEnabled()) { +        RemarksEnabled(areRemarksEnabled()), OREGetter(OREGetter) {      assert(!(ExportSummary && ImportSummary));    } @@ -444,16 +466,23 @@ struct DevirtModule {    std::string getGlobalName(VTableSlot Slot, ArrayRef<uint64_t> Args,                              StringRef Name); +  bool shouldExportConstantsAsAbsoluteSymbols(); +    // This function is called during the export phase to create a symbol    // definition containing information about the given vtable slot and list of    // arguments.    void exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,                      Constant *C); +  void exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name, +                      uint32_t Const, uint32_t &Storage);    // This function is called during the import phase to create a reference to    // the symbol definition created during the export phase.    Constant *importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args, -                         StringRef Name, unsigned AbsWidth = 0); +                         StringRef Name); +  Constant *importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args, +                           StringRef Name, IntegerType *IntTy, +                           uint32_t Storage);    void applyUniqueRetValOpt(CallSiteInfo &CSInfo, StringRef FnName, bool IsOne,                              Constant *UniqueMemberAddr); @@ -482,8 +511,9 @@ struct DevirtModule {    // Lower the module using the action and summary passed as command line    // arguments. For testing purposes only. -  static bool runForTesting(Module &M, -                            function_ref<AAResults &(Function &)> AARGetter); +  static bool runForTesting( +      Module &M, function_ref<AAResults &(Function &)> AARGetter, +      function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter);  };  struct WholeProgramDevirt : public ModulePass { @@ -508,9 +538,14 @@ struct WholeProgramDevirt : public ModulePass {    bool runOnModule(Module &M) override {      if (skipModule(M))        return false; + +    auto OREGetter = function_ref<OptimizationRemarkEmitter &(Function *)>(); +      if (UseCommandLine) -      return DevirtModule::runForTesting(M, LegacyAARGetter(*this)); -    return DevirtModule(M, LegacyAARGetter(*this), ExportSummary, ImportSummary) +      return DevirtModule::runForTesting(M, LegacyAARGetter(*this), OREGetter); + +    return DevirtModule(M, LegacyAARGetter(*this), OREGetter, ExportSummary, +                        ImportSummary)          .run();    } @@ -542,13 +577,17 @@ PreservedAnalyses WholeProgramDevirtPass::run(Module &M,    auto AARGetter = [&](Function &F) -> AAResults & {      return FAM.getResult<AAManager>(F);    }; -  if (!DevirtModule(M, AARGetter, nullptr, nullptr).run()) +  auto OREGetter = [&](Function *F) -> OptimizationRemarkEmitter & { +    return FAM.getResult<OptimizationRemarkEmitterAnalysis>(*F); +  }; +  if (!DevirtModule(M, AARGetter, OREGetter, nullptr, nullptr).run())      return PreservedAnalyses::all();    return PreservedAnalyses::none();  }  bool DevirtModule::runForTesting( -    Module &M, function_ref<AAResults &(Function &)> AARGetter) { +    Module &M, function_ref<AAResults &(Function &)> AARGetter, +    function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter) {    ModuleSummaryIndex Summary;    // Handle the command-line summary arguments. This code is for testing @@ -566,7 +605,7 @@ bool DevirtModule::runForTesting(    bool Changed =        DevirtModule( -          M, AARGetter, +          M, AARGetter, OREGetter,            ClSummaryAction == PassSummaryAction::Export ? &Summary : nullptr,            ClSummaryAction == PassSummaryAction::Import ? &Summary : nullptr)            .run(); @@ -684,7 +723,7 @@ void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,    auto Apply = [&](CallSiteInfo &CSInfo) {      for (auto &&VCallSite : CSInfo.CallSites) {        if (RemarksEnabled) -        VCallSite.emitRemark("single-impl", TheFn->getName()); +        VCallSite.emitRemark("single-impl", TheFn->getName(), OREGetter);        VCallSite.CS.setCalledFunction(ConstantExpr::getBitCast(            TheFn, VCallSite.CS.getCalledValue()->getType()));        // This use is no longer unsafe. @@ -724,9 +763,24 @@ bool DevirtModule::trySingleImplDevirt(    // to make it visible to thin LTO objects. We can only get here during the    // ThinLTO export phase.    if (TheFn->hasLocalLinkage()) { +    std::string NewName = (TheFn->getName() + "$merged").str(); + +    // Since we are renaming the function, any comdats with the same name must +    // also be renamed. This is required when targeting COFF, as the comdat name +    // must match one of the names of the symbols in the comdat. +    if (Comdat *C = TheFn->getComdat()) { +      if (C->getName() == TheFn->getName()) { +        Comdat *NewC = M.getOrInsertComdat(NewName); +        NewC->setSelectionKind(C->getSelectionKind()); +        for (GlobalObject &GO : M.global_objects()) +          if (GO.getComdat() == C) +            GO.setComdat(NewC); +      } +    } +      TheFn->setLinkage(GlobalValue::ExternalLinkage);      TheFn->setVisibility(GlobalValue::HiddenVisibility); -    TheFn->setName(TheFn->getName() + "$merged"); +    TheFn->setName(NewName);    }    Res->TheKind = WholeProgramDevirtResolution::SingleImpl; @@ -769,7 +823,7 @@ void DevirtModule::applyUniformRetValOpt(CallSiteInfo &CSInfo, StringRef FnName,                                           uint64_t TheRetVal) {    for (auto Call : CSInfo.CallSites)      Call.replaceAndErase( -        "uniform-ret-val", FnName, RemarksEnabled, +        "uniform-ret-val", FnName, RemarksEnabled, OREGetter,          ConstantInt::get(cast<IntegerType>(Call.CS.getType()), TheRetVal));    CSInfo.markDevirt();  } @@ -808,6 +862,12 @@ std::string DevirtModule::getGlobalName(VTableSlot Slot,    return OS.str();  } +bool DevirtModule::shouldExportConstantsAsAbsoluteSymbols() { +  Triple T(M.getTargetTriple()); +  return (T.getArch() == Triple::x86 || T.getArch() == Triple::x86_64) && +         T.getObjectFormat() == Triple::ELF; +} +  void DevirtModule::exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,                                  StringRef Name, Constant *C) {    GlobalAlias *GA = GlobalAlias::create(Int8Ty, 0, GlobalValue::ExternalLinkage, @@ -815,27 +875,55 @@ void DevirtModule::exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,    GA->setVisibility(GlobalValue::HiddenVisibility);  } +void DevirtModule::exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args, +                                  StringRef Name, uint32_t Const, +                                  uint32_t &Storage) { +  if (shouldExportConstantsAsAbsoluteSymbols()) { +    exportGlobal( +        Slot, Args, Name, +        ConstantExpr::getIntToPtr(ConstantInt::get(Int32Ty, Const), Int8PtrTy)); +    return; +  } + +  Storage = Const; +} +  Constant *DevirtModule::importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args, -                                     StringRef Name, unsigned AbsWidth) { +                                     StringRef Name) {    Constant *C = M.getOrInsertGlobal(getGlobalName(Slot, Args, Name), Int8Ty);    auto *GV = dyn_cast<GlobalVariable>(C); +  if (GV) +    GV->setVisibility(GlobalValue::HiddenVisibility); +  return C; +} + +Constant *DevirtModule::importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args, +                                       StringRef Name, IntegerType *IntTy, +                                       uint32_t Storage) { +  if (!shouldExportConstantsAsAbsoluteSymbols()) +    return ConstantInt::get(IntTy, Storage); + +  Constant *C = importGlobal(Slot, Args, Name); +  auto *GV = cast<GlobalVariable>(C->stripPointerCasts()); +  C = ConstantExpr::getPtrToInt(C, IntTy); +    // We only need to set metadata if the global is newly created, in which    // case it would not have hidden visibility. -  if (!GV || GV->getVisibility() == GlobalValue::HiddenVisibility) +  if (GV->getMetadata(LLVMContext::MD_absolute_symbol))      return C; -  GV->setVisibility(GlobalValue::HiddenVisibility);    auto SetAbsRange = [&](uint64_t Min, uint64_t Max) {      auto *MinC = ConstantAsMetadata::get(ConstantInt::get(IntPtrTy, Min));      auto *MaxC = ConstantAsMetadata::get(ConstantInt::get(IntPtrTy, Max));      GV->setMetadata(LLVMContext::MD_absolute_symbol,                      MDNode::get(M.getContext(), {MinC, MaxC}));    }; +  unsigned AbsWidth = IntTy->getBitWidth();    if (AbsWidth == IntPtrTy->getBitWidth())      SetAbsRange(~0ull, ~0ull); // Full set. -  else if (AbsWidth) +  else      SetAbsRange(0, 1ull << AbsWidth); -  return GV; +  return C;  }  void DevirtModule::applyUniqueRetValOpt(CallSiteInfo &CSInfo, StringRef FnName, @@ -843,10 +931,12 @@ void DevirtModule::applyUniqueRetValOpt(CallSiteInfo &CSInfo, StringRef FnName,                                          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); +    Value *Cmp = +        B.CreateICmp(IsOne ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE, +                     B.CreateBitCast(Call.VTable, Int8PtrTy), UniqueMemberAddr);      Cmp = B.CreateZExt(Cmp, Call.CS->getType()); -    Call.replaceAndErase("unique-ret-val", FnName, RemarksEnabled, Cmp); +    Call.replaceAndErase("unique-ret-val", FnName, RemarksEnabled, OREGetter, +                         Cmp);    }    CSInfo.markDevirt();  } @@ -909,17 +999,19 @@ void DevirtModule::applyVirtualConstProp(CallSiteInfo &CSInfo, StringRef FnName,    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); +    Value *Addr = +        B.CreateGEP(Int8Ty, B.CreateBitCast(Call.VTable, Int8PtrTy), 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); +                           OREGetter, IsBitSet);      } else {        Value *ValAddr = B.CreateBitCast(Addr, RetType->getPointerTo());        Value *Val = B.CreateLoad(RetType, ValAddr); -      Call.replaceAndErase("virtual-const-prop", FnName, RemarksEnabled, Val); +      Call.replaceAndErase("virtual-const-prop", FnName, RemarksEnabled, +                           OREGetter, Val);      }    }    CSInfo.markDevirt(); @@ -1007,18 +1099,18 @@ bool DevirtModule::tryVirtualConstProp(        for (auto &&Target : TargetsForSlot)          Target.WasDevirt = true; -    Constant *ByteConst = ConstantInt::get(Int32Ty, OffsetByte); -    Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit);      if (CSByConstantArg.second.isExported()) {        ResByArg->TheKind = WholeProgramDevirtResolution::ByArg::VirtualConstProp; -      exportGlobal(Slot, CSByConstantArg.first, "byte", -                   ConstantExpr::getIntToPtr(ByteConst, Int8PtrTy)); -      exportGlobal(Slot, CSByConstantArg.first, "bit", -                   ConstantExpr::getIntToPtr(BitConst, Int8PtrTy)); +      exportConstant(Slot, CSByConstantArg.first, "byte", OffsetByte, +                     ResByArg->Byte); +      exportConstant(Slot, CSByConstantArg.first, "bit", 1ULL << OffsetBit, +                     ResByArg->Bit);      }      // Rewrite each call to a load from OffsetByte/OffsetBit. +    Constant *ByteConst = ConstantInt::get(Int32Ty, OffsetByte); +    Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit);      applyVirtualConstProp(CSByConstantArg.second,                            TargetsForSlot[0].Fn->getName(), ByteConst, BitConst);    } @@ -1112,8 +1204,7 @@ 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}].addCallSite(Ptr, Call.CS, nullptr);          }        }      } @@ -1250,10 +1341,10 @@ void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) {        break;      }      case WholeProgramDevirtResolution::ByArg::VirtualConstProp: { -      Constant *Byte = importGlobal(Slot, CSByConstantArg.first, "byte", 32); -      Byte = ConstantExpr::getPtrToInt(Byte, Int32Ty); -      Constant *Bit = importGlobal(Slot, CSByConstantArg.first, "bit", 8); -      Bit = ConstantExpr::getPtrToInt(Bit, Int8Ty); +      Constant *Byte = importConstant(Slot, CSByConstantArg.first, "byte", +                                      Int32Ty, ResByArg.Byte); +      Constant *Bit = importConstant(Slot, CSByConstantArg.first, "bit", Int8Ty, +                                     ResByArg.Bit);        applyVirtualConstProp(CSByConstantArg.second, "", Byte, Bit);      }      default: @@ -1406,9 +1497,24 @@ bool DevirtModule::run() {      // Generate remarks for each devirtualized function.      for (const auto &DT : DevirtTargets) {        Function *F = DT.second; -      DISubprogram *SP = F->getSubprogram(); -      emitOptimizationRemark(F->getContext(), DEBUG_TYPE, *F, SP, -                             Twine("devirtualized ") + F->getName()); + +      // In the new pass manager, we can request the optimization +      // remark emitter pass on a per-function-basis, which the +      // OREGetter will do for us. +      // In the old pass manager, this is harder, so we just build +      // a optimization remark emitter on the fly, when we need it. +      std::unique_ptr<OptimizationRemarkEmitter> OwnedORE; +      OptimizationRemarkEmitter *ORE; +      if (OREGetter) +        ORE = &OREGetter(F); +      else { +        OwnedORE = make_unique<OptimizationRemarkEmitter>(F); +        ORE = OwnedORE.get(); +      } + +      using namespace ore; +      ORE->emit(OptimizationRemark(DEBUG_TYPE, "Devirtualized", F) +                << "devirtualized " << NV("FunctionName", F->getName()));      }    }  | 
