diff options
| author | Peter Collingbourne <peter@pcc.me.uk> | 2017-02-15 21:56:51 +0000 | 
|---|---|---|
| committer | Peter Collingbourne <peter@pcc.me.uk> | 2017-02-15 21:56:51 +0000 | 
| commit | 50cbd7cc90323668c028919f7eb9c4ed7732d8a6 (patch) | |
| tree | 85e736b7d9c55a615cd948a4856b5d691f5e51f7 /llvm/lib/Transforms | |
| parent | 3bf713043aab3b5acd848c9dbc8c311002bde36d (diff) | |
| download | bcm5719-llvm-50cbd7cc90323668c028919f7eb9c4ed7732d8a6.tar.gz bcm5719-llvm-50cbd7cc90323668c028919f7eb9c4ed7732d8a6.zip | |
Re-apply r295110 and r295144 with a fix for the ASan issue.
llvm-svn: 295241
Diffstat (limited to 'llvm/lib/Transforms')
| -rw-r--r-- | llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp | 254 | 
1 files changed, 156 insertions, 98 deletions
| diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp index 73ea5c19267..54e6fbd22f2 100644 --- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -282,6 +282,48 @@ 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 || CS.arg_empty()) +    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; @@ -291,10 +333,11 @@ struct DevirtModule {    IntegerType *Int8Ty;    PointerType *Int8PtrTy;    IntegerType *Int32Ty; +  IntegerType *Int64Ty;    bool RemarksEnabled; -  MapVector<VTableSlot, std::vector<VirtualCallSite>> CallSlots; +  MapVector<VTableSlot, VTableSlotInfo> 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 @@ -311,6 +354,7 @@ 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(); @@ -326,19 +370,30 @@ 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, -                           MutableArrayRef<VirtualCallSite> CallSites); +                           VTableSlotInfo &SlotInfo); +    bool tryEvaluateFunctionsWithArgs(        MutableArrayRef<VirtualCallTarget> TargetsForSlot, -      ArrayRef<ConstantInt *> Args); -  bool tryUniformRetValOpt(IntegerType *RetType, -                           MutableArrayRef<VirtualCallTarget> TargetsForSlot, -                           MutableArrayRef<VirtualCallSite> CallSites); +      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);    bool tryUniqueRetValOpt(unsigned BitWidth,                            MutableArrayRef<VirtualCallTarget> TargetsForSlot, -                          MutableArrayRef<VirtualCallSite> CallSites); +                          CallSiteInfo &CSInfo); + +  void applyVirtualConstProp(CallSiteInfo &CSInfo, StringRef FnName, +                             Constant *Byte, Constant *Bit);    bool tryVirtualConstProp(MutableArrayRef<VirtualCallTarget> TargetsForSlot, -                           ArrayRef<VirtualCallSite> CallSites); +                           VTableSlotInfo &SlotInfo);    void rebuildGlobal(VTableBits &B); @@ -519,9 +574,27 @@ 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, -    MutableArrayRef<VirtualCallSite> CallSites) { +    VTableSlotInfo &SlotInfo) {    // See if the program contains a single implementation of this virtual    // function.    Function *TheFn = TargetsForSlot[0].Fn; @@ -529,39 +602,34 @@ 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; -  // 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; -  } +  applySingleImplDevirt(SlotInfo, TheFn);    return true;  }  bool DevirtModule::tryEvaluateFunctionsWithArgs(      MutableArrayRef<VirtualCallTarget> TargetsForSlot, -    ArrayRef<ConstantInt *> Args) { +    ArrayRef<uint64_t> 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))); -    EvalArgs.insert(EvalArgs.end(), Args.begin(), Args.end()); +    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])); +    } +      Constant *RetVal;      if (!Eval.EvaluateFunction(Target.Fn, RetVal, EvalArgs) ||          !isa<ConstantInt>(RetVal)) @@ -571,9 +639,16 @@ 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( -    IntegerType *RetType, MutableArrayRef<VirtualCallTarget> TargetsForSlot, -    MutableArrayRef<VirtualCallSite> CallSites) { +    MutableArrayRef<VirtualCallTarget> TargetsForSlot, CallSiteInfo &CSInfo) {    // Uniform return value optimization. If all functions return the same    // constant, replace all calls with that constant.    uint64_t TheRetVal = TargetsForSlot[0].RetVal; @@ -581,19 +656,28 @@ bool DevirtModule::tryUniformRetValOpt(      if (Target.RetVal != TheRetVal)        return false; -  auto TheRetValConst = ConstantInt::get(RetType, TheRetVal); -  for (auto Call : CallSites) -    Call.replaceAndErase("uniform-ret-val", TargetsForSlot[0].Fn->getName(), -                         RemarksEnabled, TheRetValConst); +  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); +    Cmp = B.CreateZExt(Cmp, Call.CS->getType()); +    Call.replaceAndErase("unique-ret-val", FnName, RemarksEnabled, Cmp); +  } +} +  bool DevirtModule::tryUniqueRetValOpt(      unsigned BitWidth, MutableArrayRef<VirtualCallTarget> TargetsForSlot, -    MutableArrayRef<VirtualCallSite> CallSites) { +    CallSiteInfo &CSInfo) {    // IsOne controls whether we look for a 0 or a 1.    auto tryUniqueRetValOptFor = [&](bool IsOne) {      const TypeMemberInfo *UniqueMember = nullptr; @@ -610,15 +694,15 @@ bool DevirtModule::tryUniqueRetValOpt(      assert(UniqueMember);      // Replace each call with the comparison. -    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); -    } +    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) @@ -636,9 +720,29 @@ 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, -    ArrayRef<VirtualCallSite> CallSites) { +    VTableSlotInfo &SlotInfo) {    // This only works if the function returns an integer.    auto RetType = dyn_cast<IntegerType>(TargetsForSlot[0].Fn->getReturnType());    if (!RetType) @@ -657,42 +761,11 @@ bool DevirtModule::tryVirtualConstProp(        return false;    } -  // 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) { +  for (auto &&CSByConstantArg : SlotInfo.ConstCSInfo) {      if (!tryEvaluateFunctionsWithArgs(TargetsForSlot, CSByConstantArg.first))        continue; -    if (tryUniformRetValOpt(RetType, TargetsForSlot, CSByConstantArg.second)) +    if (tryUniformRetValOpt(TargetsForSlot, CSByConstantArg.second))        continue;      if (tryUniqueRetValOpt(BitWidth, TargetsForSlot, CSByConstantArg.second)) @@ -736,25 +809,10 @@ bool DevirtModule::tryVirtualConstProp(          Target.WasDevirt = true;      // Rewrite each call to a load from OffsetByte/OffsetBit. -    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); -      } -    } +    Constant *ByteConst = ConstantInt::get(Int64Ty, OffsetByte); +    Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit); +    applyVirtualConstProp(CSByConstantArg.second, +                          TargetsForSlot[0].Fn->getName(), ByteConst, BitConst);    }    return true;  } @@ -842,8 +900,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}].push_back( -              {CI->getArgOperand(0), Call.CS, nullptr}); +          CallSlots[{TypeId, Call.Offset}].addCallSite(CI->getArgOperand(0), +                                                       Call.CS, nullptr);          }        }      } @@ -929,8 +987,8 @@ void DevirtModule::scanTypeCheckedLoadUsers(Function *TypeCheckedLoadFunc) {      if (HasNonCallUses)        ++NumUnsafeUses;      for (DevirtCallSite Call : DevirtCalls) { -      CallSlots[{TypeId, Call.Offset}].push_back( -          {Ptr, Call.CS, &NumUnsafeUses}); +      CallSlots[{TypeId, Call.Offset}].addCallSite(Ptr, Call.CS, +                                                   &NumUnsafeUses);      }      CI->eraseFromParent(); | 

