diff options
author | shadchin <shadchin@yandex-team.ru> | 2022-02-10 16:44:39 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:39 +0300 |
commit | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (patch) | |
tree | 64175d5cadab313b3e7039ebaa06c5bc3295e274 /contrib/libs/llvm12/lib/Transforms/Instrumentation | |
parent | 2598ef1d0aee359b4b6d5fdd1758916d5907d04f (diff) | |
download | ydb-e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0.tar.gz |
Restoring authorship annotation for <shadchin@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/libs/llvm12/lib/Transforms/Instrumentation')
20 files changed, 2816 insertions, 2816 deletions
diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/contrib/libs/llvm12/lib/Transforms/Instrumentation/AddressSanitizer.cpp index bb82bf2337..f4e471706d 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -105,7 +105,7 @@ static const uint64_t kSystemZ_ShadowOffset64 = 1ULL << 52; static const uint64_t kMIPS32_ShadowOffset32 = 0x0aaa0000; static const uint64_t kMIPS64_ShadowOffset64 = 1ULL << 37; static const uint64_t kAArch64_ShadowOffset64 = 1ULL << 36; -static const uint64_t kRISCV64_ShadowOffset64 = 0x20000000; +static const uint64_t kRISCV64_ShadowOffset64 = 0x20000000; static const uint64_t kFreeBSD_ShadowOffset32 = 1ULL << 30; static const uint64_t kFreeBSD_ShadowOffset64 = 1ULL << 46; static const uint64_t kNetBSD_ShadowOffset32 = 1ULL << 30; @@ -130,48 +130,48 @@ static const size_t kMaxStackMallocSize = 1 << 16; // 64K static const uintptr_t kCurrentStackFrameMagic = 0x41B58AB3; static const uintptr_t kRetiredStackFrameMagic = 0x45E0360E; -const char kAsanModuleCtorName[] = "asan.module_ctor"; -const char kAsanModuleDtorName[] = "asan.module_dtor"; +const char kAsanModuleCtorName[] = "asan.module_ctor"; +const char kAsanModuleDtorName[] = "asan.module_dtor"; static const uint64_t kAsanCtorAndDtorPriority = 1; // On Emscripten, the system needs more than one priorities for constructors. static const uint64_t kAsanEmscriptenCtorAndDtorPriority = 50; -const char kAsanReportErrorTemplate[] = "__asan_report_"; -const char kAsanRegisterGlobalsName[] = "__asan_register_globals"; -const char kAsanUnregisterGlobalsName[] = "__asan_unregister_globals"; -const char kAsanRegisterImageGlobalsName[] = "__asan_register_image_globals"; -const char kAsanUnregisterImageGlobalsName[] = - "__asan_unregister_image_globals"; -const char kAsanRegisterElfGlobalsName[] = "__asan_register_elf_globals"; -const char kAsanUnregisterElfGlobalsName[] = "__asan_unregister_elf_globals"; -const char kAsanPoisonGlobalsName[] = "__asan_before_dynamic_init"; -const char kAsanUnpoisonGlobalsName[] = "__asan_after_dynamic_init"; -const char kAsanInitName[] = "__asan_init"; -const char kAsanVersionCheckNamePrefix[] = "__asan_version_mismatch_check_v"; -const char kAsanPtrCmp[] = "__sanitizer_ptr_cmp"; -const char kAsanPtrSub[] = "__sanitizer_ptr_sub"; -const char kAsanHandleNoReturnName[] = "__asan_handle_no_return"; +const char kAsanReportErrorTemplate[] = "__asan_report_"; +const char kAsanRegisterGlobalsName[] = "__asan_register_globals"; +const char kAsanUnregisterGlobalsName[] = "__asan_unregister_globals"; +const char kAsanRegisterImageGlobalsName[] = "__asan_register_image_globals"; +const char kAsanUnregisterImageGlobalsName[] = + "__asan_unregister_image_globals"; +const char kAsanRegisterElfGlobalsName[] = "__asan_register_elf_globals"; +const char kAsanUnregisterElfGlobalsName[] = "__asan_unregister_elf_globals"; +const char kAsanPoisonGlobalsName[] = "__asan_before_dynamic_init"; +const char kAsanUnpoisonGlobalsName[] = "__asan_after_dynamic_init"; +const char kAsanInitName[] = "__asan_init"; +const char kAsanVersionCheckNamePrefix[] = "__asan_version_mismatch_check_v"; +const char kAsanPtrCmp[] = "__sanitizer_ptr_cmp"; +const char kAsanPtrSub[] = "__sanitizer_ptr_sub"; +const char kAsanHandleNoReturnName[] = "__asan_handle_no_return"; static const int kMaxAsanStackMallocSizeClass = 10; -const char kAsanStackMallocNameTemplate[] = "__asan_stack_malloc_"; -const char kAsanStackFreeNameTemplate[] = "__asan_stack_free_"; -const char kAsanGenPrefix[] = "___asan_gen_"; -const char kODRGenPrefix[] = "__odr_asan_gen_"; -const char kSanCovGenPrefix[] = "__sancov_gen_"; -const char kAsanSetShadowPrefix[] = "__asan_set_shadow_"; -const char kAsanPoisonStackMemoryName[] = "__asan_poison_stack_memory"; -const char kAsanUnpoisonStackMemoryName[] = "__asan_unpoison_stack_memory"; +const char kAsanStackMallocNameTemplate[] = "__asan_stack_malloc_"; +const char kAsanStackFreeNameTemplate[] = "__asan_stack_free_"; +const char kAsanGenPrefix[] = "___asan_gen_"; +const char kODRGenPrefix[] = "__odr_asan_gen_"; +const char kSanCovGenPrefix[] = "__sancov_gen_"; +const char kAsanSetShadowPrefix[] = "__asan_set_shadow_"; +const char kAsanPoisonStackMemoryName[] = "__asan_poison_stack_memory"; +const char kAsanUnpoisonStackMemoryName[] = "__asan_unpoison_stack_memory"; // ASan version script has __asan_* wildcard. Triple underscore prevents a // linker (gold) warning about attempting to export a local symbol. -const char kAsanGlobalsRegisteredFlagName[] = "___asan_globals_registered"; +const char kAsanGlobalsRegisteredFlagName[] = "___asan_globals_registered"; -const char kAsanOptionDetectUseAfterReturn[] = +const char kAsanOptionDetectUseAfterReturn[] = "__asan_option_detect_stack_use_after_return"; -const char kAsanShadowMemoryDynamicAddress[] = +const char kAsanShadowMemoryDynamicAddress[] = "__asan_shadow_memory_dynamic_address"; -const char kAsanAllocaPoison[] = "__asan_alloca_poison"; -const char kAsanAllocasUnpoison[] = "__asan_allocas_unpoison"; +const char kAsanAllocaPoison[] = "__asan_alloca_poison"; +const char kAsanAllocasUnpoison[] = "__asan_allocas_unpoison"; // Accesses sizes are powers of two: 1, 2, 4, 8, 16. static const size_t kNumberOfAccessSizes = 5; @@ -427,7 +427,7 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize, bool IsKasan) { bool IsAndroid = TargetTriple.isAndroid(); bool IsIOS = TargetTriple.isiOS() || TargetTriple.isWatchOS(); - bool IsMacOS = TargetTriple.isMacOSX(); + bool IsMacOS = TargetTriple.isMacOSX(); bool IsFreeBSD = TargetTriple.isOSFreeBSD(); bool IsNetBSD = TargetTriple.isOSNetBSD(); bool IsPS4CPU = TargetTriple.isPS4CPU(); @@ -440,7 +440,7 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize, bool IsMIPS64 = TargetTriple.isMIPS64(); bool IsArmOrThumb = TargetTriple.isARM() || TargetTriple.isThumb(); bool IsAArch64 = TargetTriple.getArch() == Triple::aarch64; - bool IsRISCV64 = TargetTriple.getArch() == Triple::riscv64; + bool IsRISCV64 = TargetTriple.getArch() == Triple::riscv64; bool IsWindows = TargetTriple.isOSWindows(); bool IsFuchsia = TargetTriple.isOSFuchsia(); bool IsMyriad = TargetTriple.getVendor() == llvm::Triple::Myriad; @@ -505,12 +505,12 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize, Mapping.Offset = kMIPS64_ShadowOffset64; else if (IsIOS) Mapping.Offset = kDynamicShadowSentinel; - else if (IsMacOS && IsAArch64) - Mapping.Offset = kDynamicShadowSentinel; + else if (IsMacOS && IsAArch64) + Mapping.Offset = kDynamicShadowSentinel; else if (IsAArch64) Mapping.Offset = kAArch64_ShadowOffset64; - else if (IsRISCV64) - Mapping.Offset = kRISCV64_ShadowOffset64; + else if (IsRISCV64) + Mapping.Offset = kRISCV64_ShadowOffset64; else Mapping.Offset = kDefaultShadowOffset64; } @@ -529,7 +529,7 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize, // we could OR the constant in a single instruction, but it's more // efficient to load it once and use indexed addressing. Mapping.OrShadowOffset = !IsAArch64 && !IsPPC64 && !IsSystemZ && !IsPS4CPU && - !IsRISCV64 && + !IsRISCV64 && !(Mapping.Offset & (Mapping.Offset - 1)) && Mapping.Offset != kDynamicShadowSentinel; bool IsAndroidWithIfuncSupport = @@ -961,14 +961,14 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> { void createDynamicAllocasInitStorage(); // ----------------------- Visitors. - /// Collect all Ret instructions, or the musttail call instruction if it - /// precedes the return instruction. - void visitReturnInst(ReturnInst &RI) { - if (CallInst *CI = RI.getParent()->getTerminatingMustTailCall()) - RetVec.push_back(CI); - else - RetVec.push_back(&RI); - } + /// Collect all Ret instructions, or the musttail call instruction if it + /// precedes the return instruction. + void visitReturnInst(ReturnInst &RI) { + if (CallInst *CI = RI.getParent()->getTerminatingMustTailCall()) + RetVec.push_back(CI); + else + RetVec.push_back(&RI); + } /// Collect all Resume instructions. void visitResumeInst(ResumeInst &RI) { RetVec.push_back(&RI); } @@ -1002,10 +1002,10 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> { // Unpoison dynamic allocas redzones. void unpoisonDynamicAllocas() { - for (Instruction *Ret : RetVec) + for (Instruction *Ret : RetVec) unpoisonDynamicAllocasBeforeInst(Ret, DynamicAllocaLayout); - for (Instruction *StackRestoreInst : StackRestoreVec) + for (Instruction *StackRestoreInst : StackRestoreVec) unpoisonDynamicAllocasBeforeInst(StackRestoreInst, StackRestoreInst->getOperand(0)); } @@ -1064,9 +1064,9 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> { !ConstantInt::isValueValidForType(IntptrTy, SizeValue)) return; // Find alloca instruction that corresponds to llvm.lifetime argument. - // Currently we can only handle lifetime markers pointing to the - // beginning of the alloca. - AllocaInst *AI = findAllocaForValue(II.getArgOperand(1), true); + // Currently we can only handle lifetime markers pointing to the + // beginning of the alloca. + AllocaInst *AI = findAllocaForValue(II.getArgOperand(1), true); if (!AI) { HasUntracedLifetimeIntrinsic = true; return; @@ -1561,7 +1561,7 @@ void AddressSanitizer::instrumentMop(ObjectSizeOffsetVisitor &ObjSizeVis, if (ClOpt && ClOptGlobals) { // If initialization order checking is disabled, a simple access to a // dynamically initialized global is always valid. - GlobalVariable *G = dyn_cast<GlobalVariable>(getUnderlyingObject(Addr)); + GlobalVariable *G = dyn_cast<GlobalVariable>(getUnderlyingObject(Addr)); if (G && (!ClInitializers || GlobalIsLinkerInitialized(G)) && isSafeAccess(ObjSizeVis, Addr, O.TypeSize)) { NumOptimizedAccessesToGlobalVar++; @@ -1571,7 +1571,7 @@ void AddressSanitizer::instrumentMop(ObjectSizeOffsetVisitor &ObjSizeVis, if (ClOpt && ClOptStack) { // A direct inbounds access to a stack variable is always valid. - if (isa<AllocaInst>(getUnderlyingObject(Addr)) && + if (isa<AllocaInst>(getUnderlyingObject(Addr)) && isSafeAccess(ObjSizeVis, Addr, O.TypeSize)) { NumOptimizedAccessesToStackVar++; return; @@ -1873,14 +1873,14 @@ bool ModuleAddressSanitizer::shouldInstrumentGlobal(GlobalVariable *G) const { return false; } - // Do not instrument user-defined sections (with names resembling - // valid C identifiers) - if (TargetTriple.isOSBinFormatELF()) { - if (llvm::all_of(Section, - [](char c) { return llvm::isAlnum(c) || c == '_'; })) - return false; - } - + // Do not instrument user-defined sections (with names resembling + // valid C identifiers) + if (TargetTriple.isOSBinFormatELF()) { + if (llvm::all_of(Section, + [](char c) { return llvm::isAlnum(c) || c == '_'; })) + return false; + } + // On COFF, if the section name contains '$', it is highly likely that the // user is using section sorting to create an array of globals similar to // the way initialization callbacks are registered in .init_array and @@ -1965,10 +1965,10 @@ StringRef ModuleAddressSanitizer::getGlobalMetadataSection() const { case Triple::ELF: return "asan_globals"; case Triple::MachO: return "__DATA,__asan_globals,regular"; case Triple::Wasm: - case Triple::GOFF: + case Triple::GOFF: case Triple::XCOFF: report_fatal_error( - "ModuleAddressSanitizer not implemented for object file format"); + "ModuleAddressSanitizer not implemented for object file format"); case Triple::UnknownObjectFormat: break; } @@ -2119,8 +2119,8 @@ void ModuleAddressSanitizer::InstrumentGlobalsELF( // Update llvm.compiler.used, adding the new metadata globals. This is // needed so that during LTO these variables stay alive. - if (!MetadataGlobals.empty()) - appendToCompilerUsed(M, MetadataGlobals); + if (!MetadataGlobals.empty()) + appendToCompilerUsed(M, MetadataGlobals); // RegisteredFlag serves two purposes. First, we can pass it to dladdr() // to look up the loaded image that contains it. Second, we can store in it @@ -2133,15 +2133,15 @@ void ModuleAddressSanitizer::InstrumentGlobalsELF( ConstantInt::get(IntptrTy, 0), kAsanGlobalsRegisteredFlagName); RegisteredFlag->setVisibility(GlobalVariable::HiddenVisibility); - // Create start and stop symbols. - GlobalVariable *StartELFMetadata = new GlobalVariable( - M, IntptrTy, false, GlobalVariable::ExternalWeakLinkage, nullptr, - "__start_" + getGlobalMetadataSection()); - StartELFMetadata->setVisibility(GlobalVariable::HiddenVisibility); - GlobalVariable *StopELFMetadata = new GlobalVariable( - M, IntptrTy, false, GlobalVariable::ExternalWeakLinkage, nullptr, - "__stop_" + getGlobalMetadataSection()); - StopELFMetadata->setVisibility(GlobalVariable::HiddenVisibility); + // Create start and stop symbols. + GlobalVariable *StartELFMetadata = new GlobalVariable( + M, IntptrTy, false, GlobalVariable::ExternalWeakLinkage, nullptr, + "__start_" + getGlobalMetadataSection()); + StartELFMetadata->setVisibility(GlobalVariable::HiddenVisibility); + GlobalVariable *StopELFMetadata = new GlobalVariable( + M, IntptrTy, false, GlobalVariable::ExternalWeakLinkage, nullptr, + "__stop_" + getGlobalMetadataSection()); + StopELFMetadata->setVisibility(GlobalVariable::HiddenVisibility); // Create a call to register the globals with the runtime. IRB.CreateCall(AsanRegisterElfGlobals, @@ -2345,9 +2345,9 @@ bool ModuleAddressSanitizer::InstrumentGlobals(IRBuilder<> &IRB, Module &M, NewGlobal->setSection("__TEXT,__asan_cstring,regular"); } - // Transfer the debug info and type metadata. The payload starts at offset - // zero so we can copy the metadata over as is. - NewGlobal->copyMetadata(G, 0); + // Transfer the debug info and type metadata. The payload starts at offset + // zero so we can copy the metadata over as is. + NewGlobal->copyMetadata(G, 0); Value *Indices2[2]; Indices2[0] = IRB.getInt32(0); @@ -3105,8 +3105,8 @@ void FunctionStackPoisoner::processStaticAllocas() { int StackMallocIdx = -1; DebugLoc EntryDebugLocation; if (auto SP = F.getSubprogram()) - EntryDebugLocation = - DILocation::get(SP->getContext(), SP->getScopeLine(), 0, SP); + EntryDebugLocation = + DILocation::get(SP->getContext(), SP->getScopeLine(), 0, SP); Instruction *InsBefore = AllocaVec[0]; IRBuilder<> IRB(InsBefore); @@ -3314,7 +3314,7 @@ void FunctionStackPoisoner::processStaticAllocas() { SmallVector<uint8_t, 64> ShadowAfterReturn; // (Un)poison the stack before all ret instructions. - for (Instruction *Ret : RetVec) { + for (Instruction *Ret : RetVec) { IRBuilder<> IRBRet(Ret); // Mark the current frame as retired. IRBRet.CreateStore(ConstantInt::get(IntptrTy, kRetiredStackFrameMagic), diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/CFGMST.h b/contrib/libs/llvm12/lib/Transforms/Instrumentation/CFGMST.h index 77f525c020..6580b6d7d7 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/CFGMST.h +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/CFGMST.h @@ -103,7 +103,7 @@ public: const BasicBlock *Entry = &(F.getEntryBlock()); uint64_t EntryWeight = (BFI != nullptr ? BFI->getEntryFreq() : 2); // If we want to instrument the entry count, lower the weight to 0. - if (InstrumentFuncEntry) + if (InstrumentFuncEntry) EntryWeight = 0; Edge *EntryIncoming = nullptr, *EntryOutgoing = nullptr, *ExitOutgoing = nullptr, *ExitIncoming = nullptr; @@ -278,19 +278,19 @@ public: BranchProbabilityInfo *BPI; BlockFrequencyInfo *BFI; - // If function entry will be always instrumented. - bool InstrumentFuncEntry; - + // If function entry will be always instrumented. + bool InstrumentFuncEntry; + public: - CFGMST(Function &Func, bool InstrumentFuncEntry_, - BranchProbabilityInfo *BPI_ = nullptr, + CFGMST(Function &Func, bool InstrumentFuncEntry_, + BranchProbabilityInfo *BPI_ = nullptr, BlockFrequencyInfo *BFI_ = nullptr) - : F(Func), BPI(BPI_), BFI(BFI_), - InstrumentFuncEntry(InstrumentFuncEntry_) { + : F(Func), BPI(BPI_), BFI(BFI_), + InstrumentFuncEntry(InstrumentFuncEntry_) { buildEdges(); sortEdgesByWeight(); computeMinimumSpanningTree(); - if (AllEdges.size() > 1 && InstrumentFuncEntry) + if (AllEdges.size() > 1 && InstrumentFuncEntry) std::iter_swap(std::move(AllEdges.begin()), std::move(AllEdges.begin() + AllEdges.size() - 1)); } diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/CGProfile.cpp b/contrib/libs/llvm12/lib/Transforms/Instrumentation/CGProfile.cpp index 80ad16c631..9acd82c005 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/CGProfile.cpp +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/CGProfile.cpp @@ -53,8 +53,8 @@ static bool runCGProfilePass( InstrProfSymtab Symtab; auto UpdateCounts = [&](TargetTransformInfo &TTI, Function *F, Function *CalledF, uint64_t NewCount) { - if (!CalledF || !TTI.isLoweredToCall(CalledF) || - CalledF->hasDLLImportStorageClass()) + if (!CalledF || !TTI.isLoweredToCall(CalledF) || + CalledF->hasDLLImportStorageClass()) return; uint64_t &Count = Counts[std::make_pair(F, CalledF)]; Count = SaturatingAdd(Count, NewCount); diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/ControlHeightReduction.cpp b/contrib/libs/llvm12/lib/Transforms/Instrumentation/ControlHeightReduction.cpp index 13e82eee95..927c34180d 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/ControlHeightReduction.cpp +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/ControlHeightReduction.cpp @@ -260,9 +260,9 @@ class CHRScope { if (TailRegionSet.count(Parent)) return false; - assert(llvm::any_of( - RegInfos, - [&Parent](const RegInfo &RI) { return Parent == RI.R; }) && + assert(llvm::any_of( + RegInfos, + [&Parent](const RegInfo &RI) { return Parent == RI.R; }) && "Must be in head"); return true; }); @@ -731,7 +731,7 @@ static Instruction* getBranchInsertPoint(RegInfo &RI) { } } for (Instruction &I : *EntryBB) { - if (EntryBlockSelectSet.contains(&I)) { + if (EntryBlockSelectSet.contains(&I)) { assert(&I == HoistPoint && "HoistPoint must be the first one in Selects"); break; @@ -949,9 +949,9 @@ void CHR::checkScopeHoistable(CHRScope *Scope) { << "Dropped select due to unhoistable branch"; }); } - llvm::erase_if(Selects, [EntryBB](SelectInst *SI) { - return SI->getParent() == EntryBB; - }); + llvm::erase_if(Selects, [EntryBB](SelectInst *SI) { + return SI->getParent() == EntryBB; + }); Unhoistables.clear(); InsertPoint = Branch; } @@ -1247,7 +1247,7 @@ SmallVector<CHRScope *, 8> CHR::splitScope( SmallVector<CHRScope *, 8> SubSplits = splitScope( Sub, Split, &SplitConditionValues, SplitInsertPoint, Output, SplitUnhoistables); - llvm::append_range(NewSubs, SubSplits); + llvm::append_range(NewSubs, SubSplits); } Split->Subs = NewSubs; } @@ -1304,17 +1304,17 @@ void CHR::classifyBiasedScopes(CHRScope *Scope, CHRScope *OutermostScope) { for (RegInfo &RI : Scope->RegInfos) { if (RI.HasBranch) { Region *R = RI.R; - if (TrueBiasedRegionsGlobal.contains(R)) + if (TrueBiasedRegionsGlobal.contains(R)) OutermostScope->TrueBiasedRegions.insert(R); - else if (FalseBiasedRegionsGlobal.contains(R)) + else if (FalseBiasedRegionsGlobal.contains(R)) OutermostScope->FalseBiasedRegions.insert(R); else llvm_unreachable("Must be biased"); } for (SelectInst *SI : RI.Selects) { - if (TrueBiasedSelectsGlobal.contains(SI)) + if (TrueBiasedSelectsGlobal.contains(SI)) OutermostScope->TrueBiasedSelects.insert(SI); - else if (FalseBiasedSelectsGlobal.contains(SI)) + else if (FalseBiasedSelectsGlobal.contains(SI)) OutermostScope->FalseBiasedSelects.insert(SI); else llvm_unreachable("Must be biased"); @@ -1397,8 +1397,8 @@ void CHR::setCHRRegions(CHRScope *Scope, CHRScope *OutermostScope) { DenseSet<Instruction *> HoistStops; bool IsHoisted = false; if (RI.HasBranch) { - assert((OutermostScope->TrueBiasedRegions.contains(R) || - OutermostScope->FalseBiasedRegions.contains(R)) && + assert((OutermostScope->TrueBiasedRegions.contains(R) || + OutermostScope->FalseBiasedRegions.contains(R)) && "Must be truthy or falsy"); auto *BI = cast<BranchInst>(R->getEntry()->getTerminator()); // Note checkHoistValue fills in HoistStops. @@ -1410,8 +1410,8 @@ void CHR::setCHRRegions(CHRScope *Scope, CHRScope *OutermostScope) { IsHoisted = true; } for (SelectInst *SI : RI.Selects) { - assert((OutermostScope->TrueBiasedSelects.contains(SI) || - OutermostScope->FalseBiasedSelects.contains(SI)) && + assert((OutermostScope->TrueBiasedSelects.contains(SI) || + OutermostScope->FalseBiasedSelects.contains(SI)) && "Must be true or false biased"); // Note checkHoistValue fills in HoistStops. DenseMap<Instruction *, bool> Visited; @@ -1607,7 +1607,7 @@ static void insertTrivialPHIs(CHRScope *Scope, // Insert a trivial phi for I (phi [&I, P0], [&I, P1], ...) at // ExitBlock. Replace I with the new phi in UI unless UI is another // phi at ExitBlock. - PHINode *PN = PHINode::Create(I.getType(), pred_size(ExitBlock), "", + PHINode *PN = PHINode::Create(I.getType(), pred_size(ExitBlock), "", &ExitBlock->front()); for (BasicBlock *Pred : predecessors(ExitBlock)) { PN->addIncoming(&I, Pred); diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp b/contrib/libs/llvm12/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp index 6112174f3c..1b14b8d569 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp @@ -46,7 +46,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h" +#include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/DepthFirstIterator.h" @@ -79,7 +79,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Module.h" -#include "llvm/IR/PassManager.h" +#include "llvm/IR/PassManager.h" #include "llvm/IR/Type.h" #include "llvm/IR/User.h" #include "llvm/IR/Value.h" @@ -106,18 +106,18 @@ using namespace llvm; -// This must be consistent with ShadowWidthBits. -static const Align kShadowTLSAlignment = Align(2); - -// The size of TLS variables. These constants must be kept in sync with the ones -// in dfsan.cpp. -static const unsigned kArgTLSSize = 800; -static const unsigned kRetvalTLSSize = 800; - +// This must be consistent with ShadowWidthBits. +static const Align kShadowTLSAlignment = Align(2); + +// The size of TLS variables. These constants must be kept in sync with the ones +// in dfsan.cpp. +static const unsigned kArgTLSSize = 800; +static const unsigned kRetvalTLSSize = 800; + // External symbol to be used when generating the shadow address for // architectures with multiple VMAs. Instead of using a constant integer // the runtime will set the external mask based on the VMA range. -const char kDFSanExternShadowPtrMask[] = "__dfsan_shadow_ptr_mask"; +const char kDFSanExternShadowPtrMask[] = "__dfsan_shadow_ptr_mask"; // The -dfsan-preserve-alignment flag controls whether this pass assumes that // alignment requirements provided by the input IR are correct. For example, @@ -177,8 +177,8 @@ static cl::opt<bool> ClDebugNonzeroLabels( // // If this flag is set to true, the user must provide definitions for the // following callback functions: -// void __dfsan_load_callback(dfsan_label Label, void* addr); -// void __dfsan_store_callback(dfsan_label Label, void* addr); +// void __dfsan_load_callback(dfsan_label Label, void* addr); +// void __dfsan_store_callback(dfsan_label Label, void* addr); // void __dfsan_mem_transfer_callback(dfsan_label *Start, size_t Len); // void __dfsan_cmp_callback(dfsan_label CombinedLabel); static cl::opt<bool> ClEventCallbacks( @@ -186,21 +186,21 @@ static cl::opt<bool> ClEventCallbacks( cl::desc("Insert calls to __dfsan_*_callback functions on data events."), cl::Hidden, cl::init(false)); -// Use a distinct bit for each base label, enabling faster unions with less -// instrumentation. Limits the max number of base labels to 16. -static cl::opt<bool> ClFast16Labels( - "dfsan-fast-16-labels", - cl::desc("Use more efficient instrumentation, limiting the number of " - "labels to 16."), - cl::Hidden, cl::init(false)); - -// Controls whether the pass tracks the control flow of select instructions. -static cl::opt<bool> ClTrackSelectControlFlow( - "dfsan-track-select-control-flow", - cl::desc("Propagate labels from condition values of select instructions " - "to results."), - cl::Hidden, cl::init(true)); - +// Use a distinct bit for each base label, enabling faster unions with less +// instrumentation. Limits the max number of base labels to 16. +static cl::opt<bool> ClFast16Labels( + "dfsan-fast-16-labels", + cl::desc("Use more efficient instrumentation, limiting the number of " + "labels to 16."), + cl::Hidden, cl::init(false)); + +// Controls whether the pass tracks the control flow of select instructions. +static cl::opt<bool> ClTrackSelectControlFlow( + "dfsan-track-select-control-flow", + cl::desc("Propagate labels from condition values of select instructions " + "to results."), + cl::Hidden, cl::init(true)); + static StringRef GetGlobalTypeString(const GlobalValue &G) { // Types of GlobalVariables are always pointer types. Type *GType = G.getValueType(); @@ -317,7 +317,7 @@ AttributeList TransformFunctionAttributes( llvm::makeArrayRef(ArgumentAttributes)); } -class DataFlowSanitizer { +class DataFlowSanitizer { friend struct DFSanFunction; friend class DFSanVisitor; @@ -361,12 +361,12 @@ class DataFlowSanitizer { Module *Mod; LLVMContext *Ctx; - Type *Int8Ptr; - /// The shadow type for all primitive types and vector types. - IntegerType *PrimitiveShadowTy; - PointerType *PrimitiveShadowPtrTy; + Type *Int8Ptr; + /// The shadow type for all primitive types and vector types. + IntegerType *PrimitiveShadowTy; + PointerType *PrimitiveShadowPtrTy; IntegerType *IntptrTy; - ConstantInt *ZeroPrimitiveShadow; + ConstantInt *ZeroPrimitiveShadow; ConstantInt *ShadowPtrMask; ConstantInt *ShadowPtrMul; Constant *ArgTLS; @@ -378,13 +378,13 @@ class DataFlowSanitizer { FunctionType *DFSanSetLabelFnTy; FunctionType *DFSanNonzeroLabelFnTy; FunctionType *DFSanVarargWrapperFnTy; - FunctionType *DFSanCmpCallbackFnTy; - FunctionType *DFSanLoadStoreCallbackFnTy; + FunctionType *DFSanCmpCallbackFnTy; + FunctionType *DFSanLoadStoreCallbackFnTy; FunctionType *DFSanMemTransferCallbackFnTy; FunctionCallee DFSanUnionFn; FunctionCallee DFSanCheckedUnionFn; FunctionCallee DFSanUnionLoadFn; - FunctionCallee DFSanUnionLoadFast16LabelsFn; + FunctionCallee DFSanUnionLoadFast16LabelsFn; FunctionCallee DFSanUnimplementedFn; FunctionCallee DFSanSetLabelFn; FunctionCallee DFSanNonzeroLabelFn; @@ -415,43 +415,43 @@ class DataFlowSanitizer { void initializeCallbackFunctions(Module &M); void initializeRuntimeFunctions(Module &M); - bool init(Module &M); - - /// Returns whether the pass tracks labels for struct fields and array - /// indices. Support only fast16 mode in TLS ABI mode. - bool shouldTrackFieldsAndIndices(); - - /// Returns a zero constant with the shadow type of OrigTy. - /// - /// getZeroShadow({T1,T2,...}) = {getZeroShadow(T1),getZeroShadow(T2,...} - /// getZeroShadow([n x T]) = [n x getZeroShadow(T)] - /// getZeroShadow(other type) = i16(0) - /// - /// Note that a zero shadow is always i16(0) when shouldTrackFieldsAndIndices - /// returns false. - Constant *getZeroShadow(Type *OrigTy); - /// Returns a zero constant with the shadow type of V's type. - Constant *getZeroShadow(Value *V); - - /// Checks if V is a zero shadow. - bool isZeroShadow(Value *V); - - /// Returns the shadow type of OrigTy. - /// - /// getShadowTy({T1,T2,...}) = {getShadowTy(T1),getShadowTy(T2),...} - /// getShadowTy([n x T]) = [n x getShadowTy(T)] - /// getShadowTy(other type) = i16 - /// - /// Note that a shadow type is always i16 when shouldTrackFieldsAndIndices - /// returns false. - Type *getShadowTy(Type *OrigTy); - /// Returns the shadow type of of V's type. - Type *getShadowTy(Value *V); - + bool init(Module &M); + + /// Returns whether the pass tracks labels for struct fields and array + /// indices. Support only fast16 mode in TLS ABI mode. + bool shouldTrackFieldsAndIndices(); + + /// Returns a zero constant with the shadow type of OrigTy. + /// + /// getZeroShadow({T1,T2,...}) = {getZeroShadow(T1),getZeroShadow(T2,...} + /// getZeroShadow([n x T]) = [n x getZeroShadow(T)] + /// getZeroShadow(other type) = i16(0) + /// + /// Note that a zero shadow is always i16(0) when shouldTrackFieldsAndIndices + /// returns false. + Constant *getZeroShadow(Type *OrigTy); + /// Returns a zero constant with the shadow type of V's type. + Constant *getZeroShadow(Value *V); + + /// Checks if V is a zero shadow. + bool isZeroShadow(Value *V); + + /// Returns the shadow type of OrigTy. + /// + /// getShadowTy({T1,T2,...}) = {getShadowTy(T1),getShadowTy(T2),...} + /// getShadowTy([n x T]) = [n x getShadowTy(T)] + /// getShadowTy(other type) = i16 + /// + /// Note that a shadow type is always i16 when shouldTrackFieldsAndIndices + /// returns false. + Type *getShadowTy(Type *OrigTy); + /// Returns the shadow type of of V's type. + Type *getShadowTy(Value *V); + public: - DataFlowSanitizer(const std::vector<std::string> &ABIListFiles); + DataFlowSanitizer(const std::vector<std::string> &ABIListFiles); - bool runImpl(Module &M); + bool runImpl(Module &M); }; struct DFSanFunction { @@ -468,17 +468,17 @@ struct DFSanFunction { std::vector<Value *> NonZeroChecks; bool AvoidNewBlocks; - struct CachedShadow { - BasicBlock *Block; // The block where Shadow is defined. + struct CachedShadow { + BasicBlock *Block; // The block where Shadow is defined. Value *Shadow; }; - /// Maps a value to its latest shadow value in terms of domination tree. - DenseMap<std::pair<Value *, Value *>, CachedShadow> CachedShadows; - /// Maps a value to its latest collapsed shadow value it was converted to in - /// terms of domination tree. When ClDebugNonzeroLabels is on, this cache is - /// used at a post process where CFG blocks are split. So it does not cache - /// BasicBlock like CachedShadows, but uses domination between values. - DenseMap<Value *, Value *> CachedCollapsedShadows; + /// Maps a value to its latest shadow value in terms of domination tree. + DenseMap<std::pair<Value *, Value *>, CachedShadow> CachedShadows; + /// Maps a value to its latest collapsed shadow value it was converted to in + /// terms of domination tree. When ClDebugNonzeroLabels is on, this cache is + /// used at a post process where CFG blocks are split. So it does not cache + /// BasicBlock like CachedShadows, but uses domination between values. + DenseMap<Value *, Value *> CachedCollapsedShadows; DenseMap<Value *, std::set<Value *>> ShadowElements; DFSanFunction(DataFlowSanitizer &DFS, Function *F, bool IsNativeABI) @@ -489,56 +489,56 @@ struct DFSanFunction { AvoidNewBlocks = F->size() > 1000; } - /// Computes the shadow address for a given function argument. - /// - /// Shadow = ArgTLS+ArgOffset. - Value *getArgTLS(Type *T, unsigned ArgOffset, IRBuilder<> &IRB); - - /// Computes the shadow address for a retval. - Value *getRetvalTLS(Type *T, IRBuilder<> &IRB); - + /// Computes the shadow address for a given function argument. + /// + /// Shadow = ArgTLS+ArgOffset. + Value *getArgTLS(Type *T, unsigned ArgOffset, IRBuilder<> &IRB); + + /// Computes the shadow address for a retval. + Value *getRetvalTLS(Type *T, IRBuilder<> &IRB); + Value *getShadow(Value *V); void setShadow(Instruction *I, Value *Shadow); - /// Generates IR to compute the union of the two given shadows, inserting it - /// before Pos. The combined value is with primitive type. + /// Generates IR to compute the union of the two given shadows, inserting it + /// before Pos. The combined value is with primitive type. Value *combineShadows(Value *V1, Value *V2, Instruction *Pos); - /// Combines the shadow values of V1 and V2, then converts the combined value - /// with primitive type into a shadow value with the original type T. - Value *combineShadowsThenConvert(Type *T, Value *V1, Value *V2, - Instruction *Pos); + /// Combines the shadow values of V1 and V2, then converts the combined value + /// with primitive type into a shadow value with the original type T. + Value *combineShadowsThenConvert(Type *T, Value *V1, Value *V2, + Instruction *Pos); Value *combineOperandShadows(Instruction *Inst); Value *loadShadow(Value *ShadowAddr, uint64_t Size, uint64_t Align, Instruction *Pos); - void storePrimitiveShadow(Value *Addr, uint64_t Size, Align Alignment, - Value *PrimitiveShadow, Instruction *Pos); - /// Applies PrimitiveShadow to all primitive subtypes of T, returning - /// the expanded shadow value. - /// - /// EFP({T1,T2, ...}, PS) = {EFP(T1,PS),EFP(T2,PS),...} - /// EFP([n x T], PS) = [n x EFP(T,PS)] - /// EFP(other types, PS) = PS - Value *expandFromPrimitiveShadow(Type *T, Value *PrimitiveShadow, - Instruction *Pos); - /// Collapses Shadow into a single primitive shadow value, unioning all - /// primitive shadow values in the process. Returns the final primitive - /// shadow value. - /// - /// CTP({V1,V2, ...}) = UNION(CFP(V1,PS),CFP(V2,PS),...) - /// CTP([V1,V2,...]) = UNION(CFP(V1,PS),CFP(V2,PS),...) - /// CTP(other types, PS) = PS - Value *collapseToPrimitiveShadow(Value *Shadow, Instruction *Pos); - -private: - /// Collapses the shadow with aggregate type into a single primitive shadow - /// value. - template <class AggregateType> - Value *collapseAggregateShadow(AggregateType *AT, Value *Shadow, - IRBuilder<> &IRB); - - Value *collapseToPrimitiveShadow(Value *Shadow, IRBuilder<> &IRB); - - /// Returns the shadow value of an argument A. - Value *getShadowForTLSArgument(Argument *A); + void storePrimitiveShadow(Value *Addr, uint64_t Size, Align Alignment, + Value *PrimitiveShadow, Instruction *Pos); + /// Applies PrimitiveShadow to all primitive subtypes of T, returning + /// the expanded shadow value. + /// + /// EFP({T1,T2, ...}, PS) = {EFP(T1,PS),EFP(T2,PS),...} + /// EFP([n x T], PS) = [n x EFP(T,PS)] + /// EFP(other types, PS) = PS + Value *expandFromPrimitiveShadow(Type *T, Value *PrimitiveShadow, + Instruction *Pos); + /// Collapses Shadow into a single primitive shadow value, unioning all + /// primitive shadow values in the process. Returns the final primitive + /// shadow value. + /// + /// CTP({V1,V2, ...}) = UNION(CFP(V1,PS),CFP(V2,PS),...) + /// CTP([V1,V2,...]) = UNION(CFP(V1,PS),CFP(V2,PS),...) + /// CTP(other types, PS) = PS + Value *collapseToPrimitiveShadow(Value *Shadow, Instruction *Pos); + +private: + /// Collapses the shadow with aggregate type into a single primitive shadow + /// value. + template <class AggregateType> + Value *collapseAggregateShadow(AggregateType *AT, Value *Shadow, + IRBuilder<> &IRB); + + Value *collapseToPrimitiveShadow(Value *Shadow, IRBuilder<> &IRB); + + /// Returns the shadow value of an argument A. + Value *getShadowForTLSArgument(Argument *A); }; class DFSanVisitor : public InstVisitor<DFSanVisitor> { @@ -579,9 +579,9 @@ public: } // end anonymous namespace DataFlowSanitizer::DataFlowSanitizer( - const std::vector<std::string> &ABIListFiles) { + const std::vector<std::string> &ABIListFiles) { std::vector<std::string> AllABIListFiles(std::move(ABIListFiles)); - llvm::append_range(AllABIListFiles, ClABIListFiles); + llvm::append_range(AllABIListFiles, ClABIListFiles); // FIXME: should we propagate vfs::FileSystem to this constructor? ABIList.set( SpecialCaseList::createOrDie(AllABIListFiles, *vfs::getRealFileSystem())); @@ -589,12 +589,12 @@ DataFlowSanitizer::DataFlowSanitizer( FunctionType *DataFlowSanitizer::getArgsFunctionType(FunctionType *T) { SmallVector<Type *, 4> ArgTypes(T->param_begin(), T->param_end()); - ArgTypes.append(T->getNumParams(), PrimitiveShadowTy); + ArgTypes.append(T->getNumParams(), PrimitiveShadowTy); if (T->isVarArg()) - ArgTypes.push_back(PrimitiveShadowPtrTy); + ArgTypes.push_back(PrimitiveShadowPtrTy); Type *RetType = T->getReturnType(); if (!RetType->isVoidTy()) - RetType = StructType::get(RetType, PrimitiveShadowTy); + RetType = StructType::get(RetType, PrimitiveShadowTy); return FunctionType::get(RetType, ArgTypes, T->isVarArg()); } @@ -603,10 +603,10 @@ FunctionType *DataFlowSanitizer::getTrampolineFunctionType(FunctionType *T) { SmallVector<Type *, 4> ArgTypes; ArgTypes.push_back(T->getPointerTo()); ArgTypes.append(T->param_begin(), T->param_end()); - ArgTypes.append(T->getNumParams(), PrimitiveShadowTy); + ArgTypes.append(T->getNumParams(), PrimitiveShadowTy); Type *RetType = T->getReturnType(); if (!RetType->isVoidTy()) - ArgTypes.push_back(PrimitiveShadowPtrTy); + ArgTypes.push_back(PrimitiveShadowPtrTy); return FunctionType::get(T->getReturnType(), ArgTypes, false); } @@ -632,174 +632,174 @@ TransformedFunction DataFlowSanitizer::getCustomFunctionType(FunctionType *T) { } } for (unsigned i = 0, e = T->getNumParams(); i != e; ++i) - ArgTypes.push_back(PrimitiveShadowTy); + ArgTypes.push_back(PrimitiveShadowTy); if (T->isVarArg()) - ArgTypes.push_back(PrimitiveShadowPtrTy); + ArgTypes.push_back(PrimitiveShadowPtrTy); Type *RetType = T->getReturnType(); if (!RetType->isVoidTy()) - ArgTypes.push_back(PrimitiveShadowPtrTy); + ArgTypes.push_back(PrimitiveShadowPtrTy); return TransformedFunction( T, FunctionType::get(T->getReturnType(), ArgTypes, T->isVarArg()), ArgumentIndexMapping); } -bool DataFlowSanitizer::isZeroShadow(Value *V) { - if (!shouldTrackFieldsAndIndices()) - return ZeroPrimitiveShadow == V; - - Type *T = V->getType(); - if (!isa<ArrayType>(T) && !isa<StructType>(T)) { - if (const ConstantInt *CI = dyn_cast<ConstantInt>(V)) - return CI->isZero(); - return false; - } - - return isa<ConstantAggregateZero>(V); -} - -bool DataFlowSanitizer::shouldTrackFieldsAndIndices() { - return getInstrumentedABI() == DataFlowSanitizer::IA_TLS && ClFast16Labels; -} - -Constant *DataFlowSanitizer::getZeroShadow(Type *OrigTy) { - if (!shouldTrackFieldsAndIndices()) - return ZeroPrimitiveShadow; - - if (!isa<ArrayType>(OrigTy) && !isa<StructType>(OrigTy)) - return ZeroPrimitiveShadow; - Type *ShadowTy = getShadowTy(OrigTy); - return ConstantAggregateZero::get(ShadowTy); -} - -Constant *DataFlowSanitizer::getZeroShadow(Value *V) { - return getZeroShadow(V->getType()); -} - -static Value *expandFromPrimitiveShadowRecursive( - Value *Shadow, SmallVector<unsigned, 4> &Indices, Type *SubShadowTy, - Value *PrimitiveShadow, IRBuilder<> &IRB) { - if (!isa<ArrayType>(SubShadowTy) && !isa<StructType>(SubShadowTy)) - return IRB.CreateInsertValue(Shadow, PrimitiveShadow, Indices); - - if (ArrayType *AT = dyn_cast<ArrayType>(SubShadowTy)) { - for (unsigned Idx = 0; Idx < AT->getNumElements(); Idx++) { - Indices.push_back(Idx); - Shadow = expandFromPrimitiveShadowRecursive( - Shadow, Indices, AT->getElementType(), PrimitiveShadow, IRB); - Indices.pop_back(); - } - return Shadow; - } - - if (StructType *ST = dyn_cast<StructType>(SubShadowTy)) { - for (unsigned Idx = 0; Idx < ST->getNumElements(); Idx++) { - Indices.push_back(Idx); - Shadow = expandFromPrimitiveShadowRecursive( - Shadow, Indices, ST->getElementType(Idx), PrimitiveShadow, IRB); - Indices.pop_back(); - } - return Shadow; - } - llvm_unreachable("Unexpected shadow type"); -} - -Value *DFSanFunction::expandFromPrimitiveShadow(Type *T, Value *PrimitiveShadow, - Instruction *Pos) { - Type *ShadowTy = DFS.getShadowTy(T); - - if (!isa<ArrayType>(ShadowTy) && !isa<StructType>(ShadowTy)) - return PrimitiveShadow; - - if (DFS.isZeroShadow(PrimitiveShadow)) - return DFS.getZeroShadow(ShadowTy); - - IRBuilder<> IRB(Pos); - SmallVector<unsigned, 4> Indices; - Value *Shadow = UndefValue::get(ShadowTy); - Shadow = expandFromPrimitiveShadowRecursive(Shadow, Indices, ShadowTy, - PrimitiveShadow, IRB); - - // Caches the primitive shadow value that built the shadow value. - CachedCollapsedShadows[Shadow] = PrimitiveShadow; - return Shadow; -} - -template <class AggregateType> -Value *DFSanFunction::collapseAggregateShadow(AggregateType *AT, Value *Shadow, - IRBuilder<> &IRB) { - if (!AT->getNumElements()) - return DFS.ZeroPrimitiveShadow; - - Value *FirstItem = IRB.CreateExtractValue(Shadow, 0); - Value *Aggregator = collapseToPrimitiveShadow(FirstItem, IRB); - - for (unsigned Idx = 1; Idx < AT->getNumElements(); Idx++) { - Value *ShadowItem = IRB.CreateExtractValue(Shadow, Idx); - Value *ShadowInner = collapseToPrimitiveShadow(ShadowItem, IRB); - Aggregator = IRB.CreateOr(Aggregator, ShadowInner); - } - return Aggregator; -} - -Value *DFSanFunction::collapseToPrimitiveShadow(Value *Shadow, - IRBuilder<> &IRB) { - Type *ShadowTy = Shadow->getType(); - if (!isa<ArrayType>(ShadowTy) && !isa<StructType>(ShadowTy)) - return Shadow; - if (ArrayType *AT = dyn_cast<ArrayType>(ShadowTy)) - return collapseAggregateShadow<>(AT, Shadow, IRB); - if (StructType *ST = dyn_cast<StructType>(ShadowTy)) - return collapseAggregateShadow<>(ST, Shadow, IRB); - llvm_unreachable("Unexpected shadow type"); -} - -Value *DFSanFunction::collapseToPrimitiveShadow(Value *Shadow, - Instruction *Pos) { - Type *ShadowTy = Shadow->getType(); - if (!isa<ArrayType>(ShadowTy) && !isa<StructType>(ShadowTy)) - return Shadow; - - assert(DFS.shouldTrackFieldsAndIndices()); - - // Checks if the cached collapsed shadow value dominates Pos. - Value *&CS = CachedCollapsedShadows[Shadow]; - if (CS && DT.dominates(CS, Pos)) - return CS; - - IRBuilder<> IRB(Pos); - Value *PrimitiveShadow = collapseToPrimitiveShadow(Shadow, IRB); - // Caches the converted primitive shadow value. - CS = PrimitiveShadow; - return PrimitiveShadow; -} - -Type *DataFlowSanitizer::getShadowTy(Type *OrigTy) { - if (!shouldTrackFieldsAndIndices()) - return PrimitiveShadowTy; - - if (!OrigTy->isSized()) - return PrimitiveShadowTy; - if (isa<IntegerType>(OrigTy)) - return PrimitiveShadowTy; - if (isa<VectorType>(OrigTy)) - return PrimitiveShadowTy; - if (ArrayType *AT = dyn_cast<ArrayType>(OrigTy)) - return ArrayType::get(getShadowTy(AT->getElementType()), - AT->getNumElements()); - if (StructType *ST = dyn_cast<StructType>(OrigTy)) { - SmallVector<Type *, 4> Elements; - for (unsigned I = 0, N = ST->getNumElements(); I < N; ++I) - Elements.push_back(getShadowTy(ST->getElementType(I))); - return StructType::get(*Ctx, Elements); - } - return PrimitiveShadowTy; -} - -Type *DataFlowSanitizer::getShadowTy(Value *V) { - return getShadowTy(V->getType()); -} - -bool DataFlowSanitizer::init(Module &M) { +bool DataFlowSanitizer::isZeroShadow(Value *V) { + if (!shouldTrackFieldsAndIndices()) + return ZeroPrimitiveShadow == V; + + Type *T = V->getType(); + if (!isa<ArrayType>(T) && !isa<StructType>(T)) { + if (const ConstantInt *CI = dyn_cast<ConstantInt>(V)) + return CI->isZero(); + return false; + } + + return isa<ConstantAggregateZero>(V); +} + +bool DataFlowSanitizer::shouldTrackFieldsAndIndices() { + return getInstrumentedABI() == DataFlowSanitizer::IA_TLS && ClFast16Labels; +} + +Constant *DataFlowSanitizer::getZeroShadow(Type *OrigTy) { + if (!shouldTrackFieldsAndIndices()) + return ZeroPrimitiveShadow; + + if (!isa<ArrayType>(OrigTy) && !isa<StructType>(OrigTy)) + return ZeroPrimitiveShadow; + Type *ShadowTy = getShadowTy(OrigTy); + return ConstantAggregateZero::get(ShadowTy); +} + +Constant *DataFlowSanitizer::getZeroShadow(Value *V) { + return getZeroShadow(V->getType()); +} + +static Value *expandFromPrimitiveShadowRecursive( + Value *Shadow, SmallVector<unsigned, 4> &Indices, Type *SubShadowTy, + Value *PrimitiveShadow, IRBuilder<> &IRB) { + if (!isa<ArrayType>(SubShadowTy) && !isa<StructType>(SubShadowTy)) + return IRB.CreateInsertValue(Shadow, PrimitiveShadow, Indices); + + if (ArrayType *AT = dyn_cast<ArrayType>(SubShadowTy)) { + for (unsigned Idx = 0; Idx < AT->getNumElements(); Idx++) { + Indices.push_back(Idx); + Shadow = expandFromPrimitiveShadowRecursive( + Shadow, Indices, AT->getElementType(), PrimitiveShadow, IRB); + Indices.pop_back(); + } + return Shadow; + } + + if (StructType *ST = dyn_cast<StructType>(SubShadowTy)) { + for (unsigned Idx = 0; Idx < ST->getNumElements(); Idx++) { + Indices.push_back(Idx); + Shadow = expandFromPrimitiveShadowRecursive( + Shadow, Indices, ST->getElementType(Idx), PrimitiveShadow, IRB); + Indices.pop_back(); + } + return Shadow; + } + llvm_unreachable("Unexpected shadow type"); +} + +Value *DFSanFunction::expandFromPrimitiveShadow(Type *T, Value *PrimitiveShadow, + Instruction *Pos) { + Type *ShadowTy = DFS.getShadowTy(T); + + if (!isa<ArrayType>(ShadowTy) && !isa<StructType>(ShadowTy)) + return PrimitiveShadow; + + if (DFS.isZeroShadow(PrimitiveShadow)) + return DFS.getZeroShadow(ShadowTy); + + IRBuilder<> IRB(Pos); + SmallVector<unsigned, 4> Indices; + Value *Shadow = UndefValue::get(ShadowTy); + Shadow = expandFromPrimitiveShadowRecursive(Shadow, Indices, ShadowTy, + PrimitiveShadow, IRB); + + // Caches the primitive shadow value that built the shadow value. + CachedCollapsedShadows[Shadow] = PrimitiveShadow; + return Shadow; +} + +template <class AggregateType> +Value *DFSanFunction::collapseAggregateShadow(AggregateType *AT, Value *Shadow, + IRBuilder<> &IRB) { + if (!AT->getNumElements()) + return DFS.ZeroPrimitiveShadow; + + Value *FirstItem = IRB.CreateExtractValue(Shadow, 0); + Value *Aggregator = collapseToPrimitiveShadow(FirstItem, IRB); + + for (unsigned Idx = 1; Idx < AT->getNumElements(); Idx++) { + Value *ShadowItem = IRB.CreateExtractValue(Shadow, Idx); + Value *ShadowInner = collapseToPrimitiveShadow(ShadowItem, IRB); + Aggregator = IRB.CreateOr(Aggregator, ShadowInner); + } + return Aggregator; +} + +Value *DFSanFunction::collapseToPrimitiveShadow(Value *Shadow, + IRBuilder<> &IRB) { + Type *ShadowTy = Shadow->getType(); + if (!isa<ArrayType>(ShadowTy) && !isa<StructType>(ShadowTy)) + return Shadow; + if (ArrayType *AT = dyn_cast<ArrayType>(ShadowTy)) + return collapseAggregateShadow<>(AT, Shadow, IRB); + if (StructType *ST = dyn_cast<StructType>(ShadowTy)) + return collapseAggregateShadow<>(ST, Shadow, IRB); + llvm_unreachable("Unexpected shadow type"); +} + +Value *DFSanFunction::collapseToPrimitiveShadow(Value *Shadow, + Instruction *Pos) { + Type *ShadowTy = Shadow->getType(); + if (!isa<ArrayType>(ShadowTy) && !isa<StructType>(ShadowTy)) + return Shadow; + + assert(DFS.shouldTrackFieldsAndIndices()); + + // Checks if the cached collapsed shadow value dominates Pos. + Value *&CS = CachedCollapsedShadows[Shadow]; + if (CS && DT.dominates(CS, Pos)) + return CS; + + IRBuilder<> IRB(Pos); + Value *PrimitiveShadow = collapseToPrimitiveShadow(Shadow, IRB); + // Caches the converted primitive shadow value. + CS = PrimitiveShadow; + return PrimitiveShadow; +} + +Type *DataFlowSanitizer::getShadowTy(Type *OrigTy) { + if (!shouldTrackFieldsAndIndices()) + return PrimitiveShadowTy; + + if (!OrigTy->isSized()) + return PrimitiveShadowTy; + if (isa<IntegerType>(OrigTy)) + return PrimitiveShadowTy; + if (isa<VectorType>(OrigTy)) + return PrimitiveShadowTy; + if (ArrayType *AT = dyn_cast<ArrayType>(OrigTy)) + return ArrayType::get(getShadowTy(AT->getElementType()), + AT->getNumElements()); + if (StructType *ST = dyn_cast<StructType>(OrigTy)) { + SmallVector<Type *, 4> Elements; + for (unsigned I = 0, N = ST->getNumElements(); I < N; ++I) + Elements.push_back(getShadowTy(ST->getElementType(I))); + return StructType::get(*Ctx, Elements); + } + return PrimitiveShadowTy; +} + +Type *DataFlowSanitizer::getShadowTy(Value *V) { + return getShadowTy(V->getType()); +} + +bool DataFlowSanitizer::init(Module &M) { Triple TargetTriple(M.getTargetTriple()); bool IsX86_64 = TargetTriple.getArch() == Triple::x86_64; bool IsMIPS64 = TargetTriple.isMIPS64(); @@ -810,11 +810,11 @@ bool DataFlowSanitizer::init(Module &M) { Mod = &M; Ctx = &M.getContext(); - Int8Ptr = Type::getInt8PtrTy(*Ctx); - PrimitiveShadowTy = IntegerType::get(*Ctx, ShadowWidthBits); - PrimitiveShadowPtrTy = PointerType::getUnqual(PrimitiveShadowTy); + Int8Ptr = Type::getInt8PtrTy(*Ctx); + PrimitiveShadowTy = IntegerType::get(*Ctx, ShadowWidthBits); + PrimitiveShadowPtrTy = PointerType::getUnqual(PrimitiveShadowTy); IntptrTy = DL.getIntPtrType(*Ctx); - ZeroPrimitiveShadow = ConstantInt::getSigned(PrimitiveShadowTy, 0); + ZeroPrimitiveShadow = ConstantInt::getSigned(PrimitiveShadowTy, 0); ShadowPtrMul = ConstantInt::getSigned(IntptrTy, ShadowWidthBytes); if (IsX86_64) ShadowPtrMask = ConstantInt::getSigned(IntptrTy, ~0x700000000000LL); @@ -826,30 +826,30 @@ bool DataFlowSanitizer::init(Module &M) { else report_fatal_error("unsupported triple"); - Type *DFSanUnionArgs[2] = {PrimitiveShadowTy, PrimitiveShadowTy}; + Type *DFSanUnionArgs[2] = {PrimitiveShadowTy, PrimitiveShadowTy}; DFSanUnionFnTy = - FunctionType::get(PrimitiveShadowTy, DFSanUnionArgs, /*isVarArg=*/false); - Type *DFSanUnionLoadArgs[2] = {PrimitiveShadowPtrTy, IntptrTy}; - DFSanUnionLoadFnTy = FunctionType::get(PrimitiveShadowTy, DFSanUnionLoadArgs, - /*isVarArg=*/false); + FunctionType::get(PrimitiveShadowTy, DFSanUnionArgs, /*isVarArg=*/false); + Type *DFSanUnionLoadArgs[2] = {PrimitiveShadowPtrTy, IntptrTy}; + DFSanUnionLoadFnTy = FunctionType::get(PrimitiveShadowTy, DFSanUnionLoadArgs, + /*isVarArg=*/false); DFSanUnimplementedFnTy = FunctionType::get( Type::getVoidTy(*Ctx), Type::getInt8PtrTy(*Ctx), /*isVarArg=*/false); - Type *DFSanSetLabelArgs[3] = {PrimitiveShadowTy, Type::getInt8PtrTy(*Ctx), - IntptrTy}; + Type *DFSanSetLabelArgs[3] = {PrimitiveShadowTy, Type::getInt8PtrTy(*Ctx), + IntptrTy}; DFSanSetLabelFnTy = FunctionType::get(Type::getVoidTy(*Ctx), DFSanSetLabelArgs, /*isVarArg=*/false); - DFSanNonzeroLabelFnTy = - FunctionType::get(Type::getVoidTy(*Ctx), None, /*isVarArg=*/false); + DFSanNonzeroLabelFnTy = + FunctionType::get(Type::getVoidTy(*Ctx), None, /*isVarArg=*/false); DFSanVarargWrapperFnTy = FunctionType::get( Type::getVoidTy(*Ctx), Type::getInt8PtrTy(*Ctx), /*isVarArg=*/false); - DFSanCmpCallbackFnTy = - FunctionType::get(Type::getVoidTy(*Ctx), PrimitiveShadowTy, - /*isVarArg=*/false); - Type *DFSanLoadStoreCallbackArgs[2] = {PrimitiveShadowTy, Int8Ptr}; - DFSanLoadStoreCallbackFnTy = - FunctionType::get(Type::getVoidTy(*Ctx), DFSanLoadStoreCallbackArgs, - /*isVarArg=*/false); - Type *DFSanMemTransferCallbackArgs[2] = {PrimitiveShadowPtrTy, IntptrTy}; + DFSanCmpCallbackFnTy = + FunctionType::get(Type::getVoidTy(*Ctx), PrimitiveShadowTy, + /*isVarArg=*/false); + Type *DFSanLoadStoreCallbackArgs[2] = {PrimitiveShadowTy, Int8Ptr}; + DFSanLoadStoreCallbackFnTy = + FunctionType::get(Type::getVoidTy(*Ctx), DFSanLoadStoreCallbackArgs, + /*isVarArg=*/false); + Type *DFSanMemTransferCallbackArgs[2] = {PrimitiveShadowPtrTy, IntptrTy}; DFSanMemTransferCallbackFnTy = FunctionType::get(Type::getVoidTy(*Ctx), DFSanMemTransferCallbackArgs, /*isVarArg=*/false); @@ -954,21 +954,21 @@ Constant *DataFlowSanitizer::getOrBuildTrampolineFunction(FunctionType *FT, else RI = ReturnInst::Create(*Ctx, CI, BB); - // F is called by a wrapped custom function with primitive shadows. So - // its arguments and return value need conversion. + // F is called by a wrapped custom function with primitive shadows. So + // its arguments and return value need conversion. DFSanFunction DFSF(*this, F, /*IsNativeABI=*/true); Function::arg_iterator ValAI = F->arg_begin(), ShadowAI = AI; ++ValAI; - for (unsigned N = FT->getNumParams(); N != 0; ++ValAI, ++ShadowAI, --N) { - Value *Shadow = - DFSF.expandFromPrimitiveShadow(ValAI->getType(), &*ShadowAI, CI); - DFSF.ValShadowMap[&*ValAI] = Shadow; - } + for (unsigned N = FT->getNumParams(); N != 0; ++ValAI, ++ShadowAI, --N) { + Value *Shadow = + DFSF.expandFromPrimitiveShadow(ValAI->getType(), &*ShadowAI, CI); + DFSF.ValShadowMap[&*ValAI] = Shadow; + } DFSanVisitor(DFSF).visitCallInst(*CI); - if (!FT->getReturnType()->isVoidTy()) { - Value *PrimitiveShadow = DFSF.collapseToPrimitiveShadow( - DFSF.getShadow(RI->getReturnValue()), RI); - new StoreInst(PrimitiveShadow, &*std::prev(F->arg_end()), RI); - } + if (!FT->getReturnType()->isVoidTy()) { + Value *PrimitiveShadow = DFSF.collapseToPrimitiveShadow( + DFSF.getShadow(RI->getReturnValue()), RI); + new StoreInst(PrimitiveShadow, &*std::prev(F->arg_end()), RI); + } } return cast<Constant>(C.getCallee()); @@ -1013,17 +1013,17 @@ void DataFlowSanitizer::initializeRuntimeFunctions(Module &M) { DFSanUnionLoadFn = Mod->getOrInsertFunction("__dfsan_union_load", DFSanUnionLoadFnTy, AL); } - { - AttributeList AL; - AL = AL.addAttribute(M.getContext(), AttributeList::FunctionIndex, - Attribute::NoUnwind); - AL = AL.addAttribute(M.getContext(), AttributeList::FunctionIndex, - Attribute::ReadOnly); - AL = AL.addAttribute(M.getContext(), AttributeList::ReturnIndex, - Attribute::ZExt); - DFSanUnionLoadFast16LabelsFn = Mod->getOrInsertFunction( - "__dfsan_union_load_fast16labels", DFSanUnionLoadFnTy, AL); - } + { + AttributeList AL; + AL = AL.addAttribute(M.getContext(), AttributeList::FunctionIndex, + Attribute::NoUnwind); + AL = AL.addAttribute(M.getContext(), AttributeList::FunctionIndex, + Attribute::ReadOnly); + AL = AL.addAttribute(M.getContext(), AttributeList::ReturnIndex, + Attribute::ZExt); + DFSanUnionLoadFast16LabelsFn = Mod->getOrInsertFunction( + "__dfsan_union_load_fast16labels", DFSanUnionLoadFnTy, AL); + } DFSanUnimplementedFn = Mod->getOrInsertFunction("__dfsan_unimplemented", DFSanUnimplementedFnTy); { @@ -1041,18 +1041,18 @@ void DataFlowSanitizer::initializeRuntimeFunctions(Module &M) { // Initializes event callback functions and declare them in the module void DataFlowSanitizer::initializeCallbackFunctions(Module &M) { DFSanLoadCallbackFn = Mod->getOrInsertFunction("__dfsan_load_callback", - DFSanLoadStoreCallbackFnTy); - DFSanStoreCallbackFn = Mod->getOrInsertFunction("__dfsan_store_callback", - DFSanLoadStoreCallbackFnTy); + DFSanLoadStoreCallbackFnTy); + DFSanStoreCallbackFn = Mod->getOrInsertFunction("__dfsan_store_callback", + DFSanLoadStoreCallbackFnTy); DFSanMemTransferCallbackFn = Mod->getOrInsertFunction( "__dfsan_mem_transfer_callback", DFSanMemTransferCallbackFnTy); - DFSanCmpCallbackFn = - Mod->getOrInsertFunction("__dfsan_cmp_callback", DFSanCmpCallbackFnTy); + DFSanCmpCallbackFn = + Mod->getOrInsertFunction("__dfsan_cmp_callback", DFSanCmpCallbackFnTy); } -bool DataFlowSanitizer::runImpl(Module &M) { - init(M); - +bool DataFlowSanitizer::runImpl(Module &M) { + init(M); + if (ABIList.isIn(M, "skip")) return false; @@ -1061,18 +1061,18 @@ bool DataFlowSanitizer::runImpl(Module &M) { bool Changed = false; - Type *ArgTLSTy = ArrayType::get(Type::getInt64Ty(*Ctx), kArgTLSSize / 8); - ArgTLS = Mod->getOrInsertGlobal("__dfsan_arg_tls", ArgTLSTy); - if (GlobalVariable *G = dyn_cast<GlobalVariable>(ArgTLS)) { - Changed |= G->getThreadLocalMode() != GlobalVariable::InitialExecTLSModel; - G->setThreadLocalMode(GlobalVariable::InitialExecTLSModel); + Type *ArgTLSTy = ArrayType::get(Type::getInt64Ty(*Ctx), kArgTLSSize / 8); + ArgTLS = Mod->getOrInsertGlobal("__dfsan_arg_tls", ArgTLSTy); + if (GlobalVariable *G = dyn_cast<GlobalVariable>(ArgTLS)) { + Changed |= G->getThreadLocalMode() != GlobalVariable::InitialExecTLSModel; + G->setThreadLocalMode(GlobalVariable::InitialExecTLSModel); } - Type *RetvalTLSTy = - ArrayType::get(Type::getInt64Ty(*Ctx), kRetvalTLSSize / 8); - RetvalTLS = Mod->getOrInsertGlobal("__dfsan_retval_tls", RetvalTLSTy); - if (GlobalVariable *G = dyn_cast<GlobalVariable>(RetvalTLS)) { - Changed |= G->getThreadLocalMode() != GlobalVariable::InitialExecTLSModel; - G->setThreadLocalMode(GlobalVariable::InitialExecTLSModel); + Type *RetvalTLSTy = + ArrayType::get(Type::getInt64Ty(*Ctx), kRetvalTLSSize / 8); + RetvalTLS = Mod->getOrInsertGlobal("__dfsan_retval_tls", RetvalTLSTy); + if (GlobalVariable *G = dyn_cast<GlobalVariable>(RetvalTLS)) { + Changed |= G->getThreadLocalMode() != GlobalVariable::InitialExecTLSModel; + G->setThreadLocalMode(GlobalVariable::InitialExecTLSModel); } ExternalShadowMask = @@ -1088,7 +1088,7 @@ bool DataFlowSanitizer::runImpl(Module &M) { &i != DFSanUnionFn.getCallee()->stripPointerCasts() && &i != DFSanCheckedUnionFn.getCallee()->stripPointerCasts() && &i != DFSanUnionLoadFn.getCallee()->stripPointerCasts() && - &i != DFSanUnionLoadFast16LabelsFn.getCallee()->stripPointerCasts() && + &i != DFSanUnionLoadFast16LabelsFn.getCallee()->stripPointerCasts() && &i != DFSanUnimplementedFn.getCallee()->stripPointerCasts() && &i != DFSanSetLabelFn.getCallee()->stripPointerCasts() && &i != DFSanNonzeroLabelFn.getCallee()->stripPointerCasts() && @@ -1288,9 +1288,9 @@ bool DataFlowSanitizer::runImpl(Module &M) { while (isa<PHINode>(Pos) || isa<AllocaInst>(Pos)) Pos = Pos->getNextNode(); IRBuilder<> IRB(Pos); - Value *PrimitiveShadow = DFSF.collapseToPrimitiveShadow(V, Pos); - Value *Ne = - IRB.CreateICmpNE(PrimitiveShadow, DFSF.DFS.ZeroPrimitiveShadow); + Value *PrimitiveShadow = DFSF.collapseToPrimitiveShadow(V, Pos); + Value *Ne = + IRB.CreateICmpNE(PrimitiveShadow, DFSF.DFS.ZeroPrimitiveShadow); BranchInst *BI = cast<BranchInst>(SplitBlockAndInsertIfThen( Ne, Pos, /*Unreachable=*/false, ColdCallWeights)); IRBuilder<> ThenIRB(BI); @@ -1303,61 +1303,61 @@ bool DataFlowSanitizer::runImpl(Module &M) { M.global_size() != InitialGlobalSize || M.size() != InitialModuleSize; } -Value *DFSanFunction::getArgTLS(Type *T, unsigned ArgOffset, IRBuilder<> &IRB) { - Value *Base = IRB.CreatePointerCast(DFS.ArgTLS, DFS.IntptrTy); - if (ArgOffset) - Base = IRB.CreateAdd(Base, ConstantInt::get(DFS.IntptrTy, ArgOffset)); - return IRB.CreateIntToPtr(Base, PointerType::get(DFS.getShadowTy(T), 0), - "_dfsarg"); -} - -Value *DFSanFunction::getRetvalTLS(Type *T, IRBuilder<> &IRB) { - return IRB.CreatePointerCast( - DFS.RetvalTLS, PointerType::get(DFS.getShadowTy(T), 0), "_dfsret"); +Value *DFSanFunction::getArgTLS(Type *T, unsigned ArgOffset, IRBuilder<> &IRB) { + Value *Base = IRB.CreatePointerCast(DFS.ArgTLS, DFS.IntptrTy); + if (ArgOffset) + Base = IRB.CreateAdd(Base, ConstantInt::get(DFS.IntptrTy, ArgOffset)); + return IRB.CreateIntToPtr(Base, PointerType::get(DFS.getShadowTy(T), 0), + "_dfsarg"); } -Value *DFSanFunction::getShadowForTLSArgument(Argument *A) { - unsigned ArgOffset = 0; - const DataLayout &DL = F->getParent()->getDataLayout(); - for (auto &FArg : F->args()) { - if (!FArg.getType()->isSized()) { - if (A == &FArg) - break; - continue; - } - - unsigned Size = DL.getTypeAllocSize(DFS.getShadowTy(&FArg)); - if (A != &FArg) { - ArgOffset += alignTo(Size, kShadowTLSAlignment); - if (ArgOffset > kArgTLSSize) - break; // ArgTLS overflows, uses a zero shadow. - continue; - } - - if (ArgOffset + Size > kArgTLSSize) - break; // ArgTLS overflows, uses a zero shadow. - - Instruction *ArgTLSPos = &*F->getEntryBlock().begin(); - IRBuilder<> IRB(ArgTLSPos); - Value *ArgShadowPtr = getArgTLS(FArg.getType(), ArgOffset, IRB); - return IRB.CreateAlignedLoad(DFS.getShadowTy(&FArg), ArgShadowPtr, - kShadowTLSAlignment); - } - - return DFS.getZeroShadow(A); +Value *DFSanFunction::getRetvalTLS(Type *T, IRBuilder<> &IRB) { + return IRB.CreatePointerCast( + DFS.RetvalTLS, PointerType::get(DFS.getShadowTy(T), 0), "_dfsret"); +} + +Value *DFSanFunction::getShadowForTLSArgument(Argument *A) { + unsigned ArgOffset = 0; + const DataLayout &DL = F->getParent()->getDataLayout(); + for (auto &FArg : F->args()) { + if (!FArg.getType()->isSized()) { + if (A == &FArg) + break; + continue; + } + + unsigned Size = DL.getTypeAllocSize(DFS.getShadowTy(&FArg)); + if (A != &FArg) { + ArgOffset += alignTo(Size, kShadowTLSAlignment); + if (ArgOffset > kArgTLSSize) + break; // ArgTLS overflows, uses a zero shadow. + continue; + } + + if (ArgOffset + Size > kArgTLSSize) + break; // ArgTLS overflows, uses a zero shadow. + + Instruction *ArgTLSPos = &*F->getEntryBlock().begin(); + IRBuilder<> IRB(ArgTLSPos); + Value *ArgShadowPtr = getArgTLS(FArg.getType(), ArgOffset, IRB); + return IRB.CreateAlignedLoad(DFS.getShadowTy(&FArg), ArgShadowPtr, + kShadowTLSAlignment); + } + + return DFS.getZeroShadow(A); } Value *DFSanFunction::getShadow(Value *V) { if (!isa<Argument>(V) && !isa<Instruction>(V)) - return DFS.getZeroShadow(V); + return DFS.getZeroShadow(V); Value *&Shadow = ValShadowMap[V]; if (!Shadow) { if (Argument *A = dyn_cast<Argument>(V)) { if (IsNativeABI) - return DFS.getZeroShadow(V); + return DFS.getZeroShadow(V); switch (IA) { case DataFlowSanitizer::IA_TLS: { - Shadow = getShadowForTLSArgument(A); + Shadow = getShadowForTLSArgument(A); break; } case DataFlowSanitizer::IA_Args: { @@ -1366,13 +1366,13 @@ Value *DFSanFunction::getShadow(Value *V) { while (ArgIdx--) ++i; Shadow = &*i; - assert(Shadow->getType() == DFS.PrimitiveShadowTy); + assert(Shadow->getType() == DFS.PrimitiveShadowTy); break; } } NonZeroChecks.push_back(Shadow); } else { - Shadow = DFS.getZeroShadow(V); + Shadow = DFS.getZeroShadow(V); } } return Shadow; @@ -1380,8 +1380,8 @@ Value *DFSanFunction::getShadow(Value *V) { void DFSanFunction::setShadow(Instruction *I, Value *Shadow) { assert(!ValShadowMap.count(I)); - assert(DFS.shouldTrackFieldsAndIndices() || - Shadow->getType() == DFS.PrimitiveShadowTy); + assert(DFS.shouldTrackFieldsAndIndices() || + Shadow->getType() == DFS.PrimitiveShadowTy); ValShadowMap[I] = Shadow; } @@ -1398,60 +1398,60 @@ Value *DataFlowSanitizer::getShadowAddress(Value *Addr, Instruction *Pos) { IRB.CreateAnd(IRB.CreatePtrToInt(Addr, IntptrTy), IRB.CreatePtrToInt(ShadowPtrMaskValue, IntptrTy)), ShadowPtrMul), - PrimitiveShadowPtrTy); + PrimitiveShadowPtrTy); +} + +Value *DFSanFunction::combineShadowsThenConvert(Type *T, Value *V1, Value *V2, + Instruction *Pos) { + Value *PrimitiveValue = combineShadows(V1, V2, Pos); + return expandFromPrimitiveShadow(T, PrimitiveValue, Pos); } -Value *DFSanFunction::combineShadowsThenConvert(Type *T, Value *V1, Value *V2, - Instruction *Pos) { - Value *PrimitiveValue = combineShadows(V1, V2, Pos); - return expandFromPrimitiveShadow(T, PrimitiveValue, Pos); -} - // Generates IR to compute the union of the two given shadows, inserting it -// before Pos. The combined value is with primitive type. +// before Pos. The combined value is with primitive type. Value *DFSanFunction::combineShadows(Value *V1, Value *V2, Instruction *Pos) { - if (DFS.isZeroShadow(V1)) - return collapseToPrimitiveShadow(V2, Pos); - if (DFS.isZeroShadow(V2)) - return collapseToPrimitiveShadow(V1, Pos); + if (DFS.isZeroShadow(V1)) + return collapseToPrimitiveShadow(V2, Pos); + if (DFS.isZeroShadow(V2)) + return collapseToPrimitiveShadow(V1, Pos); if (V1 == V2) - return collapseToPrimitiveShadow(V1, Pos); + return collapseToPrimitiveShadow(V1, Pos); auto V1Elems = ShadowElements.find(V1); auto V2Elems = ShadowElements.find(V2); if (V1Elems != ShadowElements.end() && V2Elems != ShadowElements.end()) { if (std::includes(V1Elems->second.begin(), V1Elems->second.end(), V2Elems->second.begin(), V2Elems->second.end())) { - return collapseToPrimitiveShadow(V1, Pos); + return collapseToPrimitiveShadow(V1, Pos); } else if (std::includes(V2Elems->second.begin(), V2Elems->second.end(), V1Elems->second.begin(), V1Elems->second.end())) { - return collapseToPrimitiveShadow(V2, Pos); + return collapseToPrimitiveShadow(V2, Pos); } } else if (V1Elems != ShadowElements.end()) { if (V1Elems->second.count(V2)) - return collapseToPrimitiveShadow(V1, Pos); + return collapseToPrimitiveShadow(V1, Pos); } else if (V2Elems != ShadowElements.end()) { if (V2Elems->second.count(V1)) - return collapseToPrimitiveShadow(V2, Pos); + return collapseToPrimitiveShadow(V2, Pos); } auto Key = std::make_pair(V1, V2); if (V1 > V2) std::swap(Key.first, Key.second); - CachedShadow &CCS = CachedShadows[Key]; + CachedShadow &CCS = CachedShadows[Key]; if (CCS.Block && DT.dominates(CCS.Block, Pos->getParent())) return CCS.Shadow; - // Converts inputs shadows to shadows with primitive types. - Value *PV1 = collapseToPrimitiveShadow(V1, Pos); - Value *PV2 = collapseToPrimitiveShadow(V2, Pos); - + // Converts inputs shadows to shadows with primitive types. + Value *PV1 = collapseToPrimitiveShadow(V1, Pos); + Value *PV2 = collapseToPrimitiveShadow(V2, Pos); + IRBuilder<> IRB(Pos); - if (ClFast16Labels) { - CCS.Block = Pos->getParent(); - CCS.Shadow = IRB.CreateOr(PV1, PV2); - } else if (AvoidNewBlocks) { - CallInst *Call = IRB.CreateCall(DFS.DFSanCheckedUnionFn, {PV1, PV2}); + if (ClFast16Labels) { + CCS.Block = Pos->getParent(); + CCS.Shadow = IRB.CreateOr(PV1, PV2); + } else if (AvoidNewBlocks) { + CallInst *Call = IRB.CreateCall(DFS.DFSanCheckedUnionFn, {PV1, PV2}); Call->addAttribute(AttributeList::ReturnIndex, Attribute::ZExt); Call->addParamAttr(0, Attribute::ZExt); Call->addParamAttr(1, Attribute::ZExt); @@ -1460,20 +1460,20 @@ Value *DFSanFunction::combineShadows(Value *V1, Value *V2, Instruction *Pos) { CCS.Shadow = Call; } else { BasicBlock *Head = Pos->getParent(); - Value *Ne = IRB.CreateICmpNE(PV1, PV2); + Value *Ne = IRB.CreateICmpNE(PV1, PV2); BranchInst *BI = cast<BranchInst>(SplitBlockAndInsertIfThen( Ne, Pos, /*Unreachable=*/false, DFS.ColdCallWeights, &DT)); IRBuilder<> ThenIRB(BI); - CallInst *Call = ThenIRB.CreateCall(DFS.DFSanUnionFn, {PV1, PV2}); + CallInst *Call = ThenIRB.CreateCall(DFS.DFSanUnionFn, {PV1, PV2}); Call->addAttribute(AttributeList::ReturnIndex, Attribute::ZExt); Call->addParamAttr(0, Attribute::ZExt); Call->addParamAttr(1, Attribute::ZExt); BasicBlock *Tail = BI->getSuccessor(0); - PHINode *Phi = - PHINode::Create(DFS.PrimitiveShadowTy, 2, "", &Tail->front()); + PHINode *Phi = + PHINode::Create(DFS.PrimitiveShadowTy, 2, "", &Tail->front()); Phi->addIncoming(Call, Call->getParent()); - Phi->addIncoming(PV1, Head); + Phi->addIncoming(PV1, Head); CCS.Block = Tail; CCS.Shadow = Phi; @@ -1500,13 +1500,13 @@ Value *DFSanFunction::combineShadows(Value *V1, Value *V2, Instruction *Pos) { // the computed union Value. Value *DFSanFunction::combineOperandShadows(Instruction *Inst) { if (Inst->getNumOperands() == 0) - return DFS.getZeroShadow(Inst); + return DFS.getZeroShadow(Inst); Value *Shadow = getShadow(Inst->getOperand(0)); for (unsigned i = 1, n = Inst->getNumOperands(); i != n; ++i) { Shadow = combineShadows(Shadow, getShadow(Inst->getOperand(i)), Inst); } - return expandFromPrimitiveShadow(Inst->getType(), Shadow, Inst); + return expandFromPrimitiveShadow(Inst->getType(), Shadow, Inst); } Value *DFSanVisitor::visitOperandShadowInst(Instruction &I) { @@ -1516,21 +1516,21 @@ Value *DFSanVisitor::visitOperandShadowInst(Instruction &I) { } // Generates IR to load shadow corresponding to bytes [Addr, Addr+Size), where -// Addr has alignment Align, and take the union of each of those shadows. The -// returned shadow always has primitive type. +// Addr has alignment Align, and take the union of each of those shadows. The +// returned shadow always has primitive type. Value *DFSanFunction::loadShadow(Value *Addr, uint64_t Size, uint64_t Align, Instruction *Pos) { if (AllocaInst *AI = dyn_cast<AllocaInst>(Addr)) { const auto i = AllocaShadowMap.find(AI); if (i != AllocaShadowMap.end()) { IRBuilder<> IRB(Pos); - return IRB.CreateLoad(DFS.PrimitiveShadowTy, i->second); + return IRB.CreateLoad(DFS.PrimitiveShadowTy, i->second); } } const llvm::Align ShadowAlign(Align * DFS.ShadowWidthBytes); SmallVector<const Value *, 2> Objs; - getUnderlyingObjects(Addr, Objs); + getUnderlyingObjects(Addr, Objs); bool AllConstants = true; for (const Value *Obj : Objs) { if (isa<Function>(Obj) || isa<BlockAddress>(Obj)) @@ -1542,51 +1542,51 @@ Value *DFSanFunction::loadShadow(Value *Addr, uint64_t Size, uint64_t Align, break; } if (AllConstants) - return DFS.ZeroPrimitiveShadow; + return DFS.ZeroPrimitiveShadow; Value *ShadowAddr = DFS.getShadowAddress(Addr, Pos); switch (Size) { case 0: - return DFS.ZeroPrimitiveShadow; + return DFS.ZeroPrimitiveShadow; case 1: { - LoadInst *LI = new LoadInst(DFS.PrimitiveShadowTy, ShadowAddr, "", Pos); + LoadInst *LI = new LoadInst(DFS.PrimitiveShadowTy, ShadowAddr, "", Pos); LI->setAlignment(ShadowAlign); return LI; } case 2: { IRBuilder<> IRB(Pos); - Value *ShadowAddr1 = IRB.CreateGEP(DFS.PrimitiveShadowTy, ShadowAddr, + Value *ShadowAddr1 = IRB.CreateGEP(DFS.PrimitiveShadowTy, ShadowAddr, ConstantInt::get(DFS.IntptrTy, 1)); return combineShadows( - IRB.CreateAlignedLoad(DFS.PrimitiveShadowTy, ShadowAddr, ShadowAlign), - IRB.CreateAlignedLoad(DFS.PrimitiveShadowTy, ShadowAddr1, ShadowAlign), - Pos); - } - } - - if (ClFast16Labels && Size % (64 / DFS.ShadowWidthBits) == 0) { - // First OR all the WideShadows, then OR individual shadows within the - // combined WideShadow. This is fewer instructions than ORing shadows - // individually. - IRBuilder<> IRB(Pos); - Value *WideAddr = - IRB.CreateBitCast(ShadowAddr, Type::getInt64PtrTy(*DFS.Ctx)); - Value *CombinedWideShadow = - IRB.CreateAlignedLoad(IRB.getInt64Ty(), WideAddr, ShadowAlign); - for (uint64_t Ofs = 64 / DFS.ShadowWidthBits; Ofs != Size; - Ofs += 64 / DFS.ShadowWidthBits) { - WideAddr = IRB.CreateGEP(Type::getInt64Ty(*DFS.Ctx), WideAddr, - ConstantInt::get(DFS.IntptrTy, 1)); - Value *NextWideShadow = - IRB.CreateAlignedLoad(IRB.getInt64Ty(), WideAddr, ShadowAlign); - CombinedWideShadow = IRB.CreateOr(CombinedWideShadow, NextWideShadow); - } - for (unsigned Width = 32; Width >= DFS.ShadowWidthBits; Width >>= 1) { - Value *ShrShadow = IRB.CreateLShr(CombinedWideShadow, Width); - CombinedWideShadow = IRB.CreateOr(CombinedWideShadow, ShrShadow); - } - return IRB.CreateTrunc(CombinedWideShadow, DFS.PrimitiveShadowTy); - } + IRB.CreateAlignedLoad(DFS.PrimitiveShadowTy, ShadowAddr, ShadowAlign), + IRB.CreateAlignedLoad(DFS.PrimitiveShadowTy, ShadowAddr1, ShadowAlign), + Pos); + } + } + + if (ClFast16Labels && Size % (64 / DFS.ShadowWidthBits) == 0) { + // First OR all the WideShadows, then OR individual shadows within the + // combined WideShadow. This is fewer instructions than ORing shadows + // individually. + IRBuilder<> IRB(Pos); + Value *WideAddr = + IRB.CreateBitCast(ShadowAddr, Type::getInt64PtrTy(*DFS.Ctx)); + Value *CombinedWideShadow = + IRB.CreateAlignedLoad(IRB.getInt64Ty(), WideAddr, ShadowAlign); + for (uint64_t Ofs = 64 / DFS.ShadowWidthBits; Ofs != Size; + Ofs += 64 / DFS.ShadowWidthBits) { + WideAddr = IRB.CreateGEP(Type::getInt64Ty(*DFS.Ctx), WideAddr, + ConstantInt::get(DFS.IntptrTy, 1)); + Value *NextWideShadow = + IRB.CreateAlignedLoad(IRB.getInt64Ty(), WideAddr, ShadowAlign); + CombinedWideShadow = IRB.CreateOr(CombinedWideShadow, NextWideShadow); + } + for (unsigned Width = 32; Width >= DFS.ShadowWidthBits; Width >>= 1) { + Value *ShrShadow = IRB.CreateLShr(CombinedWideShadow, Width); + CombinedWideShadow = IRB.CreateOr(CombinedWideShadow, ShrShadow); + } + return IRB.CreateTrunc(CombinedWideShadow, DFS.PrimitiveShadowTy); + } if (!AvoidNewBlocks && Size % (64 / DFS.ShadowWidthBits) == 0) { // Fast path for the common case where each byte has identical shadow: load // shadow 64 bits at a time, fall out to a __dfsan_union_load call if any @@ -1605,7 +1605,7 @@ Value *DFSanFunction::loadShadow(Value *Addr, uint64_t Size, uint64_t Align, IRB.CreateBitCast(ShadowAddr, Type::getInt64PtrTy(*DFS.Ctx)); Value *WideShadow = IRB.CreateAlignedLoad(IRB.getInt64Ty(), WideAddr, ShadowAlign); - Value *TruncShadow = IRB.CreateTrunc(WideShadow, DFS.PrimitiveShadowTy); + Value *TruncShadow = IRB.CreateTrunc(WideShadow, DFS.PrimitiveShadowTy); Value *ShlShadow = IRB.CreateShl(WideShadow, DFS.ShadowWidthBits); Value *ShrShadow = IRB.CreateLShr(WideShadow, 64 - DFS.ShadowWidthBits); Value *RotShadow = IRB.CreateOr(ShlShadow, ShrShadow); @@ -1646,18 +1646,18 @@ Value *DFSanFunction::loadShadow(Value *Addr, uint64_t Size, uint64_t Align, LastBr->setSuccessor(0, Tail); FallbackIRB.CreateBr(Tail); - PHINode *Shadow = - PHINode::Create(DFS.PrimitiveShadowTy, 2, "", &Tail->front()); + PHINode *Shadow = + PHINode::Create(DFS.PrimitiveShadowTy, 2, "", &Tail->front()); Shadow->addIncoming(FallbackCall, FallbackBB); Shadow->addIncoming(TruncShadow, LastBr->getParent()); return Shadow; } IRBuilder<> IRB(Pos); - FunctionCallee &UnionLoadFn = - ClFast16Labels ? DFS.DFSanUnionLoadFast16LabelsFn : DFS.DFSanUnionLoadFn; + FunctionCallee &UnionLoadFn = + ClFast16Labels ? DFS.DFSanUnionLoadFast16LabelsFn : DFS.DFSanUnionLoadFn; CallInst *FallbackCall = IRB.CreateCall( - UnionLoadFn, {ShadowAddr, ConstantInt::get(DFS.IntptrTy, Size)}); + UnionLoadFn, {ShadowAddr, ConstantInt::get(DFS.IntptrTy, Size)}); FallbackCall->addAttribute(AttributeList::ReturnIndex, Attribute::ZExt); return FallbackCall; } @@ -1666,39 +1666,39 @@ void DFSanVisitor::visitLoadInst(LoadInst &LI) { auto &DL = LI.getModule()->getDataLayout(); uint64_t Size = DL.getTypeStoreSize(LI.getType()); if (Size == 0) { - DFSF.setShadow(&LI, DFSF.DFS.getZeroShadow(&LI)); + DFSF.setShadow(&LI, DFSF.DFS.getZeroShadow(&LI)); return; } Align Alignment = ClPreserveAlignment ? LI.getAlign() : Align(1); - Value *PrimitiveShadow = + Value *PrimitiveShadow = DFSF.loadShadow(LI.getPointerOperand(), Size, Alignment.value(), &LI); if (ClCombinePointerLabelsOnLoad) { Value *PtrShadow = DFSF.getShadow(LI.getPointerOperand()); - PrimitiveShadow = DFSF.combineShadows(PrimitiveShadow, PtrShadow, &LI); + PrimitiveShadow = DFSF.combineShadows(PrimitiveShadow, PtrShadow, &LI); } - if (!DFSF.DFS.isZeroShadow(PrimitiveShadow)) - DFSF.NonZeroChecks.push_back(PrimitiveShadow); + if (!DFSF.DFS.isZeroShadow(PrimitiveShadow)) + DFSF.NonZeroChecks.push_back(PrimitiveShadow); - Value *Shadow = - DFSF.expandFromPrimitiveShadow(LI.getType(), PrimitiveShadow, &LI); + Value *Shadow = + DFSF.expandFromPrimitiveShadow(LI.getType(), PrimitiveShadow, &LI); DFSF.setShadow(&LI, Shadow); if (ClEventCallbacks) { IRBuilder<> IRB(&LI); - Value *Addr8 = IRB.CreateBitCast(LI.getPointerOperand(), DFSF.DFS.Int8Ptr); - IRB.CreateCall(DFSF.DFS.DFSanLoadCallbackFn, {PrimitiveShadow, Addr8}); + Value *Addr8 = IRB.CreateBitCast(LI.getPointerOperand(), DFSF.DFS.Int8Ptr); + IRB.CreateCall(DFSF.DFS.DFSanLoadCallbackFn, {PrimitiveShadow, Addr8}); } } -void DFSanFunction::storePrimitiveShadow(Value *Addr, uint64_t Size, - Align Alignment, - Value *PrimitiveShadow, - Instruction *Pos) { +void DFSanFunction::storePrimitiveShadow(Value *Addr, uint64_t Size, + Align Alignment, + Value *PrimitiveShadow, + Instruction *Pos) { if (AllocaInst *AI = dyn_cast<AllocaInst>(Addr)) { const auto i = AllocaShadowMap.find(AI); if (i != AllocaShadowMap.end()) { IRBuilder<> IRB(Pos); - IRB.CreateStore(PrimitiveShadow, i->second); + IRB.CreateStore(PrimitiveShadow, i->second); return; } } @@ -1706,7 +1706,7 @@ void DFSanFunction::storePrimitiveShadow(Value *Addr, uint64_t Size, const Align ShadowAlign(Alignment.value() * DFS.ShadowWidthBytes); IRBuilder<> IRB(Pos); Value *ShadowAddr = DFS.getShadowAddress(Addr, Pos); - if (DFS.isZeroShadow(PrimitiveShadow)) { + if (DFS.isZeroShadow(PrimitiveShadow)) { IntegerType *ShadowTy = IntegerType::get(*DFS.Ctx, Size * DFS.ShadowWidthBits); Value *ExtZeroShadow = ConstantInt::get(ShadowTy, 0); @@ -1719,13 +1719,13 @@ void DFSanFunction::storePrimitiveShadow(Value *Addr, uint64_t Size, const unsigned ShadowVecSize = 128 / DFS.ShadowWidthBits; uint64_t Offset = 0; if (Size >= ShadowVecSize) { - auto *ShadowVecTy = - FixedVectorType::get(DFS.PrimitiveShadowTy, ShadowVecSize); + auto *ShadowVecTy = + FixedVectorType::get(DFS.PrimitiveShadowTy, ShadowVecSize); Value *ShadowVec = UndefValue::get(ShadowVecTy); for (unsigned i = 0; i != ShadowVecSize; ++i) { ShadowVec = IRB.CreateInsertElement( - ShadowVec, PrimitiveShadow, - ConstantInt::get(Type::getInt32Ty(*DFS.Ctx), i)); + ShadowVec, PrimitiveShadow, + ConstantInt::get(Type::getInt32Ty(*DFS.Ctx), i)); } Value *ShadowVecAddr = IRB.CreateBitCast(ShadowAddr, PointerType::getUnqual(ShadowVecTy)); @@ -1740,8 +1740,8 @@ void DFSanFunction::storePrimitiveShadow(Value *Addr, uint64_t Size, } while (Size > 0) { Value *CurShadowAddr = - IRB.CreateConstGEP1_32(DFS.PrimitiveShadowTy, ShadowAddr, Offset); - IRB.CreateAlignedStore(PrimitiveShadow, CurShadowAddr, ShadowAlign); + IRB.CreateConstGEP1_32(DFS.PrimitiveShadowTy, ShadowAddr, Offset); + IRB.CreateAlignedStore(PrimitiveShadow, CurShadowAddr, ShadowAlign); --Size; ++Offset; } @@ -1756,19 +1756,19 @@ void DFSanVisitor::visitStoreInst(StoreInst &SI) { const Align Alignment = ClPreserveAlignment ? SI.getAlign() : Align(1); Value* Shadow = DFSF.getShadow(SI.getValueOperand()); - Value *PrimitiveShadow; + Value *PrimitiveShadow; if (ClCombinePointerLabelsOnStore) { Value *PtrShadow = DFSF.getShadow(SI.getPointerOperand()); - PrimitiveShadow = DFSF.combineShadows(Shadow, PtrShadow, &SI); - } else { - PrimitiveShadow = DFSF.collapseToPrimitiveShadow(Shadow, &SI); + PrimitiveShadow = DFSF.combineShadows(Shadow, PtrShadow, &SI); + } else { + PrimitiveShadow = DFSF.collapseToPrimitiveShadow(Shadow, &SI); } - DFSF.storePrimitiveShadow(SI.getPointerOperand(), Size, Alignment, - PrimitiveShadow, &SI); + DFSF.storePrimitiveShadow(SI.getPointerOperand(), Size, Alignment, + PrimitiveShadow, &SI); if (ClEventCallbacks) { IRBuilder<> IRB(&SI); - Value *Addr8 = IRB.CreateBitCast(SI.getPointerOperand(), DFSF.DFS.Int8Ptr); - IRB.CreateCall(DFSF.DFS.DFSanStoreCallbackFn, {PrimitiveShadow, Addr8}); + Value *Addr8 = IRB.CreateBitCast(SI.getPointerOperand(), DFSF.DFS.Int8Ptr); + IRB.CreateCall(DFSF.DFS.DFSanStoreCallbackFn, {PrimitiveShadow, Addr8}); } } @@ -1807,29 +1807,29 @@ void DFSanVisitor::visitShuffleVectorInst(ShuffleVectorInst &I) { } void DFSanVisitor::visitExtractValueInst(ExtractValueInst &I) { - if (!DFSF.DFS.shouldTrackFieldsAndIndices()) { - visitOperandShadowInst(I); - return; - } - - IRBuilder<> IRB(&I); - Value *Agg = I.getAggregateOperand(); - Value *AggShadow = DFSF.getShadow(Agg); - Value *ResShadow = IRB.CreateExtractValue(AggShadow, I.getIndices()); - DFSF.setShadow(&I, ResShadow); + if (!DFSF.DFS.shouldTrackFieldsAndIndices()) { + visitOperandShadowInst(I); + return; + } + + IRBuilder<> IRB(&I); + Value *Agg = I.getAggregateOperand(); + Value *AggShadow = DFSF.getShadow(Agg); + Value *ResShadow = IRB.CreateExtractValue(AggShadow, I.getIndices()); + DFSF.setShadow(&I, ResShadow); } void DFSanVisitor::visitInsertValueInst(InsertValueInst &I) { - if (!DFSF.DFS.shouldTrackFieldsAndIndices()) { - visitOperandShadowInst(I); - return; - } - - IRBuilder<> IRB(&I); - Value *AggShadow = DFSF.getShadow(I.getAggregateOperand()); - Value *InsShadow = DFSF.getShadow(I.getInsertedValueOperand()); - Value *Res = IRB.CreateInsertValue(AggShadow, InsShadow, I.getIndices()); - DFSF.setShadow(&I, Res); + if (!DFSF.DFS.shouldTrackFieldsAndIndices()) { + visitOperandShadowInst(I); + return; + } + + IRBuilder<> IRB(&I); + Value *AggShadow = DFSF.getShadow(I.getAggregateOperand()); + Value *InsShadow = DFSF.getShadow(I.getInsertedValueOperand()); + Value *Res = IRB.CreateInsertValue(AggShadow, InsShadow, I.getIndices()); + DFSF.setShadow(&I, Res); } void DFSanVisitor::visitAllocaInst(AllocaInst &I) { @@ -1848,20 +1848,20 @@ void DFSanVisitor::visitAllocaInst(AllocaInst &I) { } if (AllLoadsStores) { IRBuilder<> IRB(&I); - DFSF.AllocaShadowMap[&I] = IRB.CreateAlloca(DFSF.DFS.PrimitiveShadowTy); + DFSF.AllocaShadowMap[&I] = IRB.CreateAlloca(DFSF.DFS.PrimitiveShadowTy); } - DFSF.setShadow(&I, DFSF.DFS.ZeroPrimitiveShadow); + DFSF.setShadow(&I, DFSF.DFS.ZeroPrimitiveShadow); } void DFSanVisitor::visitSelectInst(SelectInst &I) { Value *CondShadow = DFSF.getShadow(I.getCondition()); Value *TrueShadow = DFSF.getShadow(I.getTrueValue()); Value *FalseShadow = DFSF.getShadow(I.getFalseValue()); - Value *ShadowSel = nullptr; + Value *ShadowSel = nullptr; if (isa<VectorType>(I.getCondition()->getType())) { - ShadowSel = DFSF.combineShadowsThenConvert(I.getType(), TrueShadow, - FalseShadow, &I); + ShadowSel = DFSF.combineShadowsThenConvert(I.getType(), TrueShadow, + FalseShadow, &I); } else { if (TrueShadow == FalseShadow) { ShadowSel = TrueShadow; @@ -1870,10 +1870,10 @@ void DFSanVisitor::visitSelectInst(SelectInst &I) { SelectInst::Create(I.getCondition(), TrueShadow, FalseShadow, "", &I); } } - DFSF.setShadow(&I, ClTrackSelectControlFlow - ? DFSF.combineShadowsThenConvert( - I.getType(), CondShadow, ShadowSel, &I) - : ShadowSel); + DFSF.setShadow(&I, ClTrackSelectControlFlow + ? DFSF.combineShadowsThenConvert( + I.getType(), CondShadow, ShadowSel, &I) + : ShadowSel); } void DFSanVisitor::visitMemSetInst(MemSetInst &I) { @@ -1917,15 +1917,15 @@ void DFSanVisitor::visitReturnInst(ReturnInst &RI) { case DataFlowSanitizer::IA_TLS: { Value *S = DFSF.getShadow(RI.getReturnValue()); IRBuilder<> IRB(&RI); - Type *RT = DFSF.F->getFunctionType()->getReturnType(); - unsigned Size = - getDataLayout().getTypeAllocSize(DFSF.DFS.getShadowTy(RT)); - if (Size <= kRetvalTLSSize) { - // If the size overflows, stores nothing. At callsite, oversized return - // shadows are set to zero. - IRB.CreateAlignedStore(S, DFSF.getRetvalTLS(RT, IRB), - kShadowTLSAlignment); - } + Type *RT = DFSF.F->getFunctionType()->getReturnType(); + unsigned Size = + getDataLayout().getTypeAllocSize(DFSF.DFS.getShadowTy(RT)); + if (Size <= kRetvalTLSSize) { + // If the size overflows, stores nothing. At callsite, oversized return + // shadows are set to zero. + IRB.CreateAlignedStore(S, DFSF.getRetvalTLS(RT, IRB), + kShadowTLSAlignment); + } break; } case DataFlowSanitizer::IA_Args: { @@ -1965,11 +1965,11 @@ void DFSanVisitor::visitCallBase(CallBase &CB) { CB.setCalledFunction(F); IRB.CreateCall(DFSF.DFS.DFSanUnimplementedFn, IRB.CreateGlobalStringPtr(F->getName())); - DFSF.setShadow(&CB, DFSF.DFS.getZeroShadow(&CB)); + DFSF.setShadow(&CB, DFSF.DFS.getZeroShadow(&CB)); return; case DataFlowSanitizer::WK_Discard: CB.setCalledFunction(F); - DFSF.setShadow(&CB, DFSF.DFS.getZeroShadow(&CB)); + DFSF.setShadow(&CB, DFSF.DFS.getZeroShadow(&CB)); return; case DataFlowSanitizer::WK_Functional: CB.setCalledFunction(F); @@ -2021,11 +2021,11 @@ void DFSanVisitor::visitCallBase(CallBase &CB) { i = CB.arg_begin(); const unsigned ShadowArgStart = Args.size(); for (unsigned n = FT->getNumParams(); n != 0; ++i, --n) - Args.push_back( - DFSF.collapseToPrimitiveShadow(DFSF.getShadow(*i), &CB)); + Args.push_back( + DFSF.collapseToPrimitiveShadow(DFSF.getShadow(*i), &CB)); if (FT->isVarArg()) { - auto *LabelVATy = ArrayType::get(DFSF.DFS.PrimitiveShadowTy, + auto *LabelVATy = ArrayType::get(DFSF.DFS.PrimitiveShadowTy, CB.arg_size() - FT->getNumParams()); auto *LabelVAAlloca = new AllocaInst( LabelVATy, getDataLayout().getAllocaAddrSpace(), @@ -2033,9 +2033,9 @@ void DFSanVisitor::visitCallBase(CallBase &CB) { for (unsigned n = 0; i != CB.arg_end(); ++i, ++n) { auto LabelVAPtr = IRB.CreateStructGEP(LabelVATy, LabelVAAlloca, n); - IRB.CreateStore( - DFSF.collapseToPrimitiveShadow(DFSF.getShadow(*i), &CB), - LabelVAPtr); + IRB.CreateStore( + DFSF.collapseToPrimitiveShadow(DFSF.getShadow(*i), &CB), + LabelVAPtr); } Args.push_back(IRB.CreateStructGEP(LabelVATy, LabelVAAlloca, 0)); @@ -2044,9 +2044,9 @@ void DFSanVisitor::visitCallBase(CallBase &CB) { if (!FT->getReturnType()->isVoidTy()) { if (!DFSF.LabelReturnAlloca) { DFSF.LabelReturnAlloca = - new AllocaInst(DFSF.DFS.PrimitiveShadowTy, - getDataLayout().getAllocaAddrSpace(), - "labelreturn", &DFSF.F->getEntryBlock().front()); + new AllocaInst(DFSF.DFS.PrimitiveShadowTy, + getDataLayout().getAllocaAddrSpace(), + "labelreturn", &DFSF.F->getEntryBlock().front()); } Args.push_back(DFSF.LabelReturnAlloca); } @@ -2061,19 +2061,19 @@ void DFSanVisitor::visitCallBase(CallBase &CB) { // Update the parameter attributes of the custom call instruction to // zero extend the shadow parameters. This is required for targets - // which consider PrimitiveShadowTy an illegal type. + // which consider PrimitiveShadowTy an illegal type. for (unsigned n = 0; n < FT->getNumParams(); n++) { const unsigned ArgNo = ShadowArgStart + n; - if (CustomCI->getArgOperand(ArgNo)->getType() == - DFSF.DFS.PrimitiveShadowTy) + if (CustomCI->getArgOperand(ArgNo)->getType() == + DFSF.DFS.PrimitiveShadowTy) CustomCI->addParamAttr(ArgNo, Attribute::ZExt); } if (!FT->getReturnType()->isVoidTy()) { - LoadInst *LabelLoad = IRB.CreateLoad(DFSF.DFS.PrimitiveShadowTy, - DFSF.LabelReturnAlloca); - DFSF.setShadow(CustomCI, DFSF.expandFromPrimitiveShadow( - FT->getReturnType(), LabelLoad, &CB)); + LoadInst *LabelLoad = IRB.CreateLoad(DFSF.DFS.PrimitiveShadowTy, + DFSF.LabelReturnAlloca); + DFSF.setShadow(CustomCI, DFSF.expandFromPrimitiveShadow( + FT->getReturnType(), LabelLoad, &CB)); } CI->replaceAllUsesWith(CustomCI); @@ -2086,20 +2086,20 @@ void DFSanVisitor::visitCallBase(CallBase &CB) { FunctionType *FT = CB.getFunctionType(); if (DFSF.DFS.getInstrumentedABI() == DataFlowSanitizer::IA_TLS) { - unsigned ArgOffset = 0; - const DataLayout &DL = getDataLayout(); - for (unsigned I = 0, N = FT->getNumParams(); I != N; ++I) { - unsigned Size = - DL.getTypeAllocSize(DFSF.DFS.getShadowTy(FT->getParamType(I))); - // Stop storing if arguments' size overflows. Inside a function, arguments - // after overflow have zero shadow values. - if (ArgOffset + Size > kArgTLSSize) - break; - IRB.CreateAlignedStore( - DFSF.getShadow(CB.getArgOperand(I)), - DFSF.getArgTLS(FT->getParamType(I), ArgOffset, IRB), - kShadowTLSAlignment); - ArgOffset += alignTo(Size, kShadowTLSAlignment); + unsigned ArgOffset = 0; + const DataLayout &DL = getDataLayout(); + for (unsigned I = 0, N = FT->getNumParams(); I != N; ++I) { + unsigned Size = + DL.getTypeAllocSize(DFSF.DFS.getShadowTy(FT->getParamType(I))); + // Stop storing if arguments' size overflows. Inside a function, arguments + // after overflow have zero shadow values. + if (ArgOffset + Size > kArgTLSSize) + break; + IRB.CreateAlignedStore( + DFSF.getShadow(CB.getArgOperand(I)), + DFSF.getArgTLS(FT->getParamType(I), ArgOffset, IRB), + kShadowTLSAlignment); + ArgOffset += alignTo(Size, kShadowTLSAlignment); } } @@ -2120,19 +2120,19 @@ void DFSanVisitor::visitCallBase(CallBase &CB) { if (DFSF.DFS.getInstrumentedABI() == DataFlowSanitizer::IA_TLS) { IRBuilder<> NextIRB(Next); - const DataLayout &DL = getDataLayout(); - unsigned Size = DL.getTypeAllocSize(DFSF.DFS.getShadowTy(&CB)); - if (Size > kRetvalTLSSize) { - // Set overflowed return shadow to be zero. - DFSF.setShadow(&CB, DFSF.DFS.getZeroShadow(&CB)); - } else { - LoadInst *LI = NextIRB.CreateAlignedLoad( - DFSF.DFS.getShadowTy(&CB), DFSF.getRetvalTLS(CB.getType(), NextIRB), - kShadowTLSAlignment, "_dfsret"); - DFSF.SkipInsts.insert(LI); - DFSF.setShadow(&CB, LI); - DFSF.NonZeroChecks.push_back(LI); - } + const DataLayout &DL = getDataLayout(); + unsigned Size = DL.getTypeAllocSize(DFSF.DFS.getShadowTy(&CB)); + if (Size > kRetvalTLSSize) { + // Set overflowed return shadow to be zero. + DFSF.setShadow(&CB, DFSF.DFS.getZeroShadow(&CB)); + } else { + LoadInst *LI = NextIRB.CreateAlignedLoad( + DFSF.DFS.getShadowTy(&CB), DFSF.getRetvalTLS(CB.getType(), NextIRB), + kShadowTLSAlignment, "_dfsret"); + DFSF.SkipInsts.insert(LI); + DFSF.setShadow(&CB, LI); + DFSF.NonZeroChecks.push_back(LI); + } } } @@ -2154,8 +2154,8 @@ void DFSanVisitor::visitCallBase(CallBase &CB) { if (FT->isVarArg()) { unsigned VarArgSize = CB.arg_size() - FT->getNumParams(); - ArrayType *VarArgArrayTy = - ArrayType::get(DFSF.DFS.PrimitiveShadowTy, VarArgSize); + ArrayType *VarArgArrayTy = + ArrayType::get(DFSF.DFS.PrimitiveShadowTy, VarArgSize); AllocaInst *VarArgShadow = new AllocaInst(VarArgArrayTy, getDataLayout().getAllocaAddrSpace(), "", &DFSF.F->getEntryBlock().front()); @@ -2196,12 +2196,12 @@ void DFSanVisitor::visitCallBase(CallBase &CB) { } void DFSanVisitor::visitPHINode(PHINode &PN) { - Type *ShadowTy = DFSF.DFS.getShadowTy(&PN); + Type *ShadowTy = DFSF.DFS.getShadowTy(&PN); PHINode *ShadowPN = - PHINode::Create(ShadowTy, PN.getNumIncomingValues(), "", &PN); + PHINode::Create(ShadowTy, PN.getNumIncomingValues(), "", &PN); // Give the shadow phi node valid predecessors to fool SplitEdge into working. - Value *UndefShadow = UndefValue::get(ShadowTy); + Value *UndefShadow = UndefValue::get(ShadowTy); for (PHINode::block_iterator i = PN.block_begin(), e = PN.block_end(); i != e; ++i) { ShadowPN->addIncoming(UndefShadow, *i); @@ -2210,39 +2210,39 @@ void DFSanVisitor::visitPHINode(PHINode &PN) { DFSF.PHIFixups.push_back(std::make_pair(&PN, ShadowPN)); DFSF.setShadow(&PN, ShadowPN); } - -namespace { -class DataFlowSanitizerLegacyPass : public ModulePass { -private: - std::vector<std::string> ABIListFiles; - -public: - static char ID; - - DataFlowSanitizerLegacyPass( - const std::vector<std::string> &ABIListFiles = std::vector<std::string>()) - : ModulePass(ID), ABIListFiles(ABIListFiles) {} - - bool runOnModule(Module &M) override { - return DataFlowSanitizer(ABIListFiles).runImpl(M); - } -}; -} // namespace - -char DataFlowSanitizerLegacyPass::ID; - -INITIALIZE_PASS(DataFlowSanitizerLegacyPass, "dfsan", - "DataFlowSanitizer: dynamic data flow analysis.", false, false) - -ModulePass *llvm::createDataFlowSanitizerLegacyPassPass( - const std::vector<std::string> &ABIListFiles) { - return new DataFlowSanitizerLegacyPass(ABIListFiles); -} - -PreservedAnalyses DataFlowSanitizerPass::run(Module &M, - ModuleAnalysisManager &AM) { - if (DataFlowSanitizer(ABIListFiles).runImpl(M)) { - return PreservedAnalyses::none(); - } - return PreservedAnalyses::all(); -} + +namespace { +class DataFlowSanitizerLegacyPass : public ModulePass { +private: + std::vector<std::string> ABIListFiles; + +public: + static char ID; + + DataFlowSanitizerLegacyPass( + const std::vector<std::string> &ABIListFiles = std::vector<std::string>()) + : ModulePass(ID), ABIListFiles(ABIListFiles) {} + + bool runOnModule(Module &M) override { + return DataFlowSanitizer(ABIListFiles).runImpl(M); + } +}; +} // namespace + +char DataFlowSanitizerLegacyPass::ID; + +INITIALIZE_PASS(DataFlowSanitizerLegacyPass, "dfsan", + "DataFlowSanitizer: dynamic data flow analysis.", false, false) + +ModulePass *llvm::createDataFlowSanitizerLegacyPassPass( + const std::vector<std::string> &ABIListFiles) { + return new DataFlowSanitizerLegacyPass(ABIListFiles); +} + +PreservedAnalyses DataFlowSanitizerPass::run(Module &M, + ModuleAnalysisManager &AM) { + if (DataFlowSanitizer(ABIListFiles).runImpl(M)) { + return PreservedAnalyses::none(); + } + return PreservedAnalyses::all(); +} diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/contrib/libs/llvm12/lib/Transforms/Instrumentation/GCOVProfiling.cpp index 2d52317d0d..527644a69d 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/GCOVProfiling.cpp +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/GCOVProfiling.cpp @@ -13,17 +13,17 @@ // //===----------------------------------------------------------------------===// -#include "CFGMST.h" +#include "CFGMST.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Hashing.h" -#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Sequence.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" -#include "llvm/Analysis/BlockFrequencyInfo.h" -#include "llvm/Analysis/BranchProbabilityInfo.h" +#include "llvm/Analysis/BlockFrequencyInfo.h" +#include "llvm/Analysis/BranchProbabilityInfo.h" #include "llvm/Analysis/EHPersonalities.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/CFG.h" @@ -36,7 +36,7 @@ #include "llvm/IR/Module.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" -#include "llvm/Support/CRC.h" +#include "llvm/Support/CRC.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" @@ -57,8 +57,8 @@ namespace endian = llvm::support::endian; #define DEBUG_TYPE "insert-gcov-profiling" enum : uint32_t { - GCOV_ARC_ON_TREE = 1 << 0, - + GCOV_ARC_ON_TREE = 1 << 0, + GCOV_TAG_FUNCTION = 0x01000000, GCOV_TAG_BLOCKS = 0x01410000, GCOV_TAG_ARCS = 0x01430000, @@ -69,9 +69,9 @@ static cl::opt<std::string> DefaultGCOVVersion("default-gcov-version", cl::init("408*"), cl::Hidden, cl::ValueRequired); -static cl::opt<bool> AtomicCounter("gcov-atomic-counter", cl::Hidden, - cl::desc("Make counter updates atomic")); - +static cl::opt<bool> AtomicCounter("gcov-atomic-counter", cl::Hidden, + cl::desc("Make counter updates atomic")); + // Returns the number of words which will be used to represent this string. static unsigned wordsOfString(StringRef s) { // Length + NUL-terminated string + 0~3 padding NULs. @@ -83,7 +83,7 @@ GCOVOptions GCOVOptions::getDefault() { Options.EmitNotes = true; Options.EmitData = true; Options.NoRedZone = false; - Options.Atomic = AtomicCounter; + Options.Atomic = AtomicCounter; if (DefaultGCOVVersion.size() != 4) { llvm::report_fatal_error(std::string("Invalid -default-gcov-version: ") + @@ -101,8 +101,8 @@ public: GCOVProfiler() : GCOVProfiler(GCOVOptions::getDefault()) {} GCOVProfiler(const GCOVOptions &Opts) : Options(Opts) {} bool - runOnModule(Module &M, function_ref<BlockFrequencyInfo *(Function &F)> GetBFI, - function_ref<BranchProbabilityInfo *(Function &F)> GetBPI, + runOnModule(Module &M, function_ref<BlockFrequencyInfo *(Function &F)> GetBFI, + function_ref<BranchProbabilityInfo *(Function &F)> GetBPI, std::function<const TargetLibraryInfo &(Function &F)> GetTLI); void write(uint32_t i) { @@ -119,14 +119,14 @@ public: private: // Create the .gcno files for the Module based on DebugInfo. - bool - emitProfileNotes(NamedMDNode *CUNode, bool HasExecOrFork, - function_ref<BlockFrequencyInfo *(Function &F)> GetBFI, - function_ref<BranchProbabilityInfo *(Function &F)> GetBPI, - function_ref<const TargetLibraryInfo &(Function &F)> GetTLI); + bool + emitProfileNotes(NamedMDNode *CUNode, bool HasExecOrFork, + function_ref<BlockFrequencyInfo *(Function &F)> GetBFI, + function_ref<BranchProbabilityInfo *(Function &F)> GetBPI, + function_ref<const TargetLibraryInfo &(Function &F)> GetTLI); - void emitGlobalConstructor( - SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP); + void emitGlobalConstructor( + SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP); bool isFunctionInstrumented(const Function &F); std::vector<Regex> createRegexesFromString(StringRef RegexesStr); @@ -164,7 +164,7 @@ private: SmallVector<std::unique_ptr<GCOVFunction>, 16> Funcs; std::vector<Regex> FilterRe; std::vector<Regex> ExcludeRe; - DenseSet<const BasicBlock *> ExecBlocks; + DenseSet<const BasicBlock *> ExecBlocks; StringMap<bool> InstrumentedFiles; }; @@ -180,68 +180,68 @@ public: StringRef getPassName() const override { return "GCOV Profiler"; } bool runOnModule(Module &M) override { - auto GetBFI = [this](Function &F) { - return &this->getAnalysis<BlockFrequencyInfoWrapperPass>(F).getBFI(); - }; - auto GetBPI = [this](Function &F) { - return &this->getAnalysis<BranchProbabilityInfoWrapperPass>(F).getBPI(); - }; - auto GetTLI = [this](Function &F) -> const TargetLibraryInfo & { - return this->getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F); - }; - return Profiler.runOnModule(M, GetBFI, GetBPI, GetTLI); + auto GetBFI = [this](Function &F) { + return &this->getAnalysis<BlockFrequencyInfoWrapperPass>(F).getBFI(); + }; + auto GetBPI = [this](Function &F) { + return &this->getAnalysis<BranchProbabilityInfoWrapperPass>(F).getBPI(); + }; + auto GetTLI = [this](Function &F) -> const TargetLibraryInfo & { + return this->getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F); + }; + return Profiler.runOnModule(M, GetBFI, GetBPI, GetTLI); } void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.addRequired<BlockFrequencyInfoWrapperPass>(); + AU.addRequired<BlockFrequencyInfoWrapperPass>(); AU.addRequired<TargetLibraryInfoWrapperPass>(); } private: GCOVProfiler Profiler; }; - -struct BBInfo { - BBInfo *Group; - uint32_t Index; - uint32_t Rank = 0; - - BBInfo(unsigned Index) : Group(this), Index(Index) {} - const std::string infoString() const { - return (Twine("Index=") + Twine(Index)).str(); - } -}; - -struct Edge { - // This class implements the CFG edges. Note the CFG can be a multi-graph. - // So there might be multiple edges with same SrcBB and DestBB. - const BasicBlock *SrcBB; - const BasicBlock *DestBB; - uint64_t Weight; - BasicBlock *Place = nullptr; - uint32_t SrcNumber, DstNumber; - bool InMST = false; - bool Removed = false; - bool IsCritical = false; - - Edge(const BasicBlock *Src, const BasicBlock *Dest, uint64_t W = 1) - : SrcBB(Src), DestBB(Dest), Weight(W) {} - - // Return the information string of an edge. - const std::string infoString() const { - return (Twine(Removed ? "-" : " ") + (InMST ? " " : "*") + - (IsCritical ? "c" : " ") + " W=" + Twine(Weight)) - .str(); - } -}; + +struct BBInfo { + BBInfo *Group; + uint32_t Index; + uint32_t Rank = 0; + + BBInfo(unsigned Index) : Group(this), Index(Index) {} + const std::string infoString() const { + return (Twine("Index=") + Twine(Index)).str(); + } +}; + +struct Edge { + // This class implements the CFG edges. Note the CFG can be a multi-graph. + // So there might be multiple edges with same SrcBB and DestBB. + const BasicBlock *SrcBB; + const BasicBlock *DestBB; + uint64_t Weight; + BasicBlock *Place = nullptr; + uint32_t SrcNumber, DstNumber; + bool InMST = false; + bool Removed = false; + bool IsCritical = false; + + Edge(const BasicBlock *Src, const BasicBlock *Dest, uint64_t W = 1) + : SrcBB(Src), DestBB(Dest), Weight(W) {} + + // Return the information string of an edge. + const std::string infoString() const { + return (Twine(Removed ? "-" : " ") + (InMST ? " " : "*") + + (IsCritical ? "c" : " ") + " W=" + Twine(Weight)) + .str(); + } +}; } char GCOVProfilerLegacyPass::ID = 0; INITIALIZE_PASS_BEGIN( GCOVProfilerLegacyPass, "insert-gcov-profiling", "Insert instrumentation for GCOV profiling", false, false) -INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass) -INITIALIZE_PASS_DEPENDENCY(BranchProbabilityInfoWrapperPass) +INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass) +INITIALIZE_PASS_DEPENDENCY(BranchProbabilityInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) INITIALIZE_PASS_END( GCOVProfilerLegacyPass, "insert-gcov-profiling", @@ -326,8 +326,8 @@ namespace { return LinesByFile.try_emplace(Filename, P, Filename).first->second; } - void addEdge(GCOVBlock &Successor, uint32_t Flags) { - OutEdges.emplace_back(&Successor, Flags); + void addEdge(GCOVBlock &Successor, uint32_t Flags) { + OutEdges.emplace_back(&Successor, Flags); } void writeOut() { @@ -360,10 +360,10 @@ namespace { assert(OutEdges.empty()); } - uint32_t Number; - SmallVector<std::pair<GCOVBlock *, uint32_t>, 4> OutEdges; - - private: + uint32_t Number; + SmallVector<std::pair<GCOVBlock *, uint32_t>, 4> OutEdges; + + private: friend class GCOVFunction; GCOVBlock(GCOVProfiler *P, uint32_t Number) @@ -380,11 +380,11 @@ namespace { GCOVFunction(GCOVProfiler *P, Function *F, const DISubprogram *SP, unsigned EndLine, uint32_t Ident, int Version) : GCOVRecord(P), SP(SP), EndLine(EndLine), Ident(Ident), - Version(Version), EntryBlock(P, 0), ReturnBlock(P, 1) { + Version(Version), EntryBlock(P, 0), ReturnBlock(P, 1) { LLVM_DEBUG(dbgs() << "Function: " << getFunctionName(SP) << "\n"); bool ExitBlockBeforeBody = Version >= 48; - uint32_t i = ExitBlockBeforeBody ? 2 : 1; - for (BasicBlock &BB : *F) + uint32_t i = ExitBlockBeforeBody ? 2 : 1; + for (BasicBlock &BB : *F) Blocks.insert(std::make_pair(&BB, GCOVBlock(P, i++))); if (!ExitBlockBeforeBody) ReturnBlock.Number = i; @@ -396,11 +396,11 @@ namespace { FuncChecksum = hash_value(FunctionNameAndLine); } - GCOVBlock &getBlock(const BasicBlock *BB) { - return Blocks.find(const_cast<BasicBlock *>(BB))->second; + GCOVBlock &getBlock(const BasicBlock *BB) { + return Blocks.find(const_cast<BasicBlock *>(BB))->second; } - GCOVBlock &getEntryBlock() { return EntryBlock; } + GCOVBlock &getEntryBlock() { return EntryBlock; } GCOVBlock &getReturnBlock() { return ReturnBlock; } @@ -443,52 +443,52 @@ namespace { // Emit count of blocks. write(GCOV_TAG_BLOCKS); if (Version < 80) { - write(Blocks.size() + 2); - for (int i = Blocks.size() + 2; i; --i) + write(Blocks.size() + 2); + for (int i = Blocks.size() + 2; i; --i) write(0); } else { write(1); - write(Blocks.size() + 2); + write(Blocks.size() + 2); } LLVM_DEBUG(dbgs() << (Blocks.size() + 1) << " blocks\n"); // Emit edges between blocks. - const uint32_t Outgoing = EntryBlock.OutEdges.size(); - if (Outgoing) { - write(GCOV_TAG_ARCS); - write(Outgoing * 2 + 1); - write(EntryBlock.Number); - for (const auto &E : EntryBlock.OutEdges) { - write(E.first->Number); - write(E.second); - } - } - for (auto &It : Blocks) { - const GCOVBlock &Block = It.second; + const uint32_t Outgoing = EntryBlock.OutEdges.size(); + if (Outgoing) { + write(GCOV_TAG_ARCS); + write(Outgoing * 2 + 1); + write(EntryBlock.Number); + for (const auto &E : EntryBlock.OutEdges) { + write(E.first->Number); + write(E.second); + } + } + for (auto &It : Blocks) { + const GCOVBlock &Block = It.second; if (Block.OutEdges.empty()) continue; write(GCOV_TAG_ARCS); write(Block.OutEdges.size() * 2 + 1); write(Block.Number); - for (const auto &E : Block.OutEdges) { - write(E.first->Number); - write(E.second); + for (const auto &E : Block.OutEdges) { + write(E.first->Number); + write(E.second); } } // Emit lines for each block. - for (auto &It : Blocks) - It.second.writeOut(); + for (auto &It : Blocks) + It.second.writeOut(); } - public: + public: const DISubprogram *SP; unsigned EndLine; uint32_t Ident; uint32_t FuncChecksum; int Version; - MapVector<BasicBlock *, GCOVBlock> Blocks; - GCOVBlock EntryBlock; + MapVector<BasicBlock *, GCOVBlock> Blocks; + GCOVBlock EntryBlock; GCOVBlock ReturnBlock; }; } @@ -602,23 +602,23 @@ std::string GCOVProfiler::mangleName(const DICompileUnit *CU, } bool GCOVProfiler::runOnModule( - Module &M, function_ref<BlockFrequencyInfo *(Function &F)> GetBFI, - function_ref<BranchProbabilityInfo *(Function &F)> GetBPI, - std::function<const TargetLibraryInfo &(Function &F)> GetTLI) { + Module &M, function_ref<BlockFrequencyInfo *(Function &F)> GetBFI, + function_ref<BranchProbabilityInfo *(Function &F)> GetBPI, + std::function<const TargetLibraryInfo &(Function &F)> GetTLI) { this->M = &M; this->GetTLI = std::move(GetTLI); Ctx = &M.getContext(); - NamedMDNode *CUNode = M.getNamedMetadata("llvm.dbg.cu"); - if (!CUNode || (!Options.EmitNotes && !Options.EmitData)) - return false; + NamedMDNode *CUNode = M.getNamedMetadata("llvm.dbg.cu"); + if (!CUNode || (!Options.EmitNotes && !Options.EmitData)) + return false; + + bool HasExecOrFork = AddFlushBeforeForkAndExec(); - bool HasExecOrFork = AddFlushBeforeForkAndExec(); - FilterRe = createRegexesFromString(Options.Filter); ExcludeRe = createRegexesFromString(Options.Exclude); - emitProfileNotes(CUNode, HasExecOrFork, GetBFI, GetBPI, this->GetTLI); - return true; + emitProfileNotes(CUNode, HasExecOrFork, GetBFI, GetBPI, this->GetTLI); + return true; } PreservedAnalyses GCOVProfilerPass::run(Module &M, @@ -628,17 +628,17 @@ PreservedAnalyses GCOVProfilerPass::run(Module &M, FunctionAnalysisManager &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); - auto GetBFI = [&FAM](Function &F) { - return &FAM.getResult<BlockFrequencyAnalysis>(F); - }; - auto GetBPI = [&FAM](Function &F) { - return &FAM.getResult<BranchProbabilityAnalysis>(F); - }; - auto GetTLI = [&FAM](Function &F) -> const TargetLibraryInfo & { - return FAM.getResult<TargetLibraryAnalysis>(F); - }; - - if (!Profiler.runOnModule(M, GetBFI, GetBPI, GetTLI)) + auto GetBFI = [&FAM](Function &F) { + return &FAM.getResult<BlockFrequencyAnalysis>(F); + }; + auto GetBPI = [&FAM](Function &F) { + return &FAM.getResult<BranchProbabilityAnalysis>(F); + }; + auto GetTLI = [&FAM](Function &F) -> const TargetLibraryInfo & { + return FAM.getResult<TargetLibraryAnalysis>(F); + }; + + if (!Profiler.runOnModule(M, GetBFI, GetBPI, GetTLI)) return PreservedAnalyses::all(); return PreservedAnalyses::none(); @@ -744,7 +744,7 @@ bool GCOVProfiler::AddFlushBeforeForkAndExec() { // dumped FunctionCallee ResetF = M->getOrInsertFunction("llvm_reset_counters", FTy); Builder.CreateCall(ResetF)->setDebugLoc(Loc); - ExecBlocks.insert(Parent); + ExecBlocks.insert(Parent); Parent->splitBasicBlock(NextInst); Parent->back().setDebugLoc(Loc); } @@ -752,67 +752,67 @@ bool GCOVProfiler::AddFlushBeforeForkAndExec() { return !Forks.empty() || !Execs.empty(); } -static BasicBlock *getInstrBB(CFGMST<Edge, BBInfo> &MST, Edge &E, - const DenseSet<const BasicBlock *> &ExecBlocks) { - if (E.InMST || E.Removed) - return nullptr; - - BasicBlock *SrcBB = const_cast<BasicBlock *>(E.SrcBB); - BasicBlock *DestBB = const_cast<BasicBlock *>(E.DestBB); - // For a fake edge, instrument the real BB. - if (SrcBB == nullptr) - return DestBB; - if (DestBB == nullptr) - return SrcBB; - - auto CanInstrument = [](BasicBlock *BB) -> BasicBlock * { - // There are basic blocks (such as catchswitch) cannot be instrumented. - // If the returned first insertion point is the end of BB, skip this BB. - if (BB->getFirstInsertionPt() == BB->end()) - return nullptr; - return BB; - }; - - // Instrument the SrcBB if it has a single successor, - // otherwise, the DestBB if this is not a critical edge. - Instruction *TI = SrcBB->getTerminator(); - if (TI->getNumSuccessors() <= 1 && !ExecBlocks.count(SrcBB)) - return CanInstrument(SrcBB); - if (!E.IsCritical) - return CanInstrument(DestBB); - - // Some IndirectBr critical edges cannot be split by the previous - // SplitIndirectBrCriticalEdges call. Bail out. - const unsigned SuccNum = GetSuccessorNumber(SrcBB, DestBB); - BasicBlock *InstrBB = - isa<IndirectBrInst>(TI) ? nullptr : SplitCriticalEdge(TI, SuccNum); - if (!InstrBB) - return nullptr; - - MST.addEdge(SrcBB, InstrBB, 0); - MST.addEdge(InstrBB, DestBB, 0).InMST = true; - E.Removed = true; - - return CanInstrument(InstrBB); -} - -#ifndef NDEBUG -static void dumpEdges(CFGMST<Edge, BBInfo> &MST, GCOVFunction &GF) { - size_t ID = 0; - for (auto &E : make_pointee_range(MST.AllEdges)) { - GCOVBlock &Src = E.SrcBB ? GF.getBlock(E.SrcBB) : GF.getEntryBlock(); - GCOVBlock &Dst = E.DestBB ? GF.getBlock(E.DestBB) : GF.getReturnBlock(); - dbgs() << " Edge " << ID++ << ": " << Src.Number << "->" << Dst.Number - << E.infoString() << "\n"; - } -} -#endif - -bool GCOVProfiler::emitProfileNotes( - NamedMDNode *CUNode, bool HasExecOrFork, - function_ref<BlockFrequencyInfo *(Function &F)> GetBFI, - function_ref<BranchProbabilityInfo *(Function &F)> GetBPI, - function_ref<const TargetLibraryInfo &(Function &F)> GetTLI) { +static BasicBlock *getInstrBB(CFGMST<Edge, BBInfo> &MST, Edge &E, + const DenseSet<const BasicBlock *> &ExecBlocks) { + if (E.InMST || E.Removed) + return nullptr; + + BasicBlock *SrcBB = const_cast<BasicBlock *>(E.SrcBB); + BasicBlock *DestBB = const_cast<BasicBlock *>(E.DestBB); + // For a fake edge, instrument the real BB. + if (SrcBB == nullptr) + return DestBB; + if (DestBB == nullptr) + return SrcBB; + + auto CanInstrument = [](BasicBlock *BB) -> BasicBlock * { + // There are basic blocks (such as catchswitch) cannot be instrumented. + // If the returned first insertion point is the end of BB, skip this BB. + if (BB->getFirstInsertionPt() == BB->end()) + return nullptr; + return BB; + }; + + // Instrument the SrcBB if it has a single successor, + // otherwise, the DestBB if this is not a critical edge. + Instruction *TI = SrcBB->getTerminator(); + if (TI->getNumSuccessors() <= 1 && !ExecBlocks.count(SrcBB)) + return CanInstrument(SrcBB); + if (!E.IsCritical) + return CanInstrument(DestBB); + + // Some IndirectBr critical edges cannot be split by the previous + // SplitIndirectBrCriticalEdges call. Bail out. + const unsigned SuccNum = GetSuccessorNumber(SrcBB, DestBB); + BasicBlock *InstrBB = + isa<IndirectBrInst>(TI) ? nullptr : SplitCriticalEdge(TI, SuccNum); + if (!InstrBB) + return nullptr; + + MST.addEdge(SrcBB, InstrBB, 0); + MST.addEdge(InstrBB, DestBB, 0).InMST = true; + E.Removed = true; + + return CanInstrument(InstrBB); +} + +#ifndef NDEBUG +static void dumpEdges(CFGMST<Edge, BBInfo> &MST, GCOVFunction &GF) { + size_t ID = 0; + for (auto &E : make_pointee_range(MST.AllEdges)) { + GCOVBlock &Src = E.SrcBB ? GF.getBlock(E.SrcBB) : GF.getEntryBlock(); + GCOVBlock &Dst = E.DestBB ? GF.getBlock(E.DestBB) : GF.getReturnBlock(); + dbgs() << " Edge " << ID++ << ": " << Src.Number << "->" << Dst.Number + << E.infoString() << "\n"; + } +} +#endif + +bool GCOVProfiler::emitProfileNotes( + NamedMDNode *CUNode, bool HasExecOrFork, + function_ref<BlockFrequencyInfo *(Function &F)> GetBFI, + function_ref<BranchProbabilityInfo *(Function &F)> GetBPI, + function_ref<const TargetLibraryInfo &(Function &F)> GetTLI) { int Version; { uint8_t c3 = Options.Version[0]; @@ -822,20 +822,20 @@ bool GCOVProfiler::emitProfileNotes( : (c3 - '0') * 10 + c1 - '0'; } - bool EmitGCDA = Options.EmitData; - for (unsigned i = 0, e = CUNode->getNumOperands(); i != e; ++i) { + bool EmitGCDA = Options.EmitData; + for (unsigned i = 0, e = CUNode->getNumOperands(); i != e; ++i) { // Each compile unit gets its own .gcno file. This means that whether we run // this pass over the original .o's as they're produced, or run it after // LTO, we'll generate the same .gcno files. - auto *CU = cast<DICompileUnit>(CUNode->getOperand(i)); + auto *CU = cast<DICompileUnit>(CUNode->getOperand(i)); // Skip module skeleton (and module) CUs. if (CU->getDWOId()) continue; - std::vector<uint8_t> EdgeDestinations; - SmallVector<std::pair<GlobalVariable *, MDNode *>, 8> CountersBySP; + std::vector<uint8_t> EdgeDestinations; + SmallVector<std::pair<GlobalVariable *, MDNode *>, 8> CountersBySP; Endian = M->getDataLayout().isLittleEndian() ? support::endianness::little : support::endianness::big; @@ -849,82 +849,82 @@ bool GCOVProfiler::emitProfileNotes( // TODO: Functions using scope-based EH are currently not supported. if (isUsingScopeBasedEH(F)) continue; - // Add the function line number to the lines of the entry block - // to have a counter for the function definition. - uint32_t Line = SP->getLine(); - auto Filename = getFilename(SP); - - BranchProbabilityInfo *BPI = GetBPI(F); - BlockFrequencyInfo *BFI = GetBFI(F); - - // Split indirectbr critical edges here before computing the MST rather - // than later in getInstrBB() to avoid invalidating it. - SplitIndirectBrCriticalEdges(F, BPI, BFI); - - CFGMST<Edge, BBInfo> MST(F, /*InstrumentFuncEntry_=*/false, BPI, BFI); - - // getInstrBB can split basic blocks and push elements to AllEdges. - for (size_t I : llvm::seq<size_t>(0, MST.AllEdges.size())) { - auto &E = *MST.AllEdges[I]; - // For now, disable spanning tree optimization when fork or exec* is - // used. - if (HasExecOrFork) - E.InMST = false; - E.Place = getInstrBB(MST, E, ExecBlocks); - } - // Basic blocks in F are finalized at this point. + // Add the function line number to the lines of the entry block + // to have a counter for the function definition. + uint32_t Line = SP->getLine(); + auto Filename = getFilename(SP); + + BranchProbabilityInfo *BPI = GetBPI(F); + BlockFrequencyInfo *BFI = GetBFI(F); + + // Split indirectbr critical edges here before computing the MST rather + // than later in getInstrBB() to avoid invalidating it. + SplitIndirectBrCriticalEdges(F, BPI, BFI); + + CFGMST<Edge, BBInfo> MST(F, /*InstrumentFuncEntry_=*/false, BPI, BFI); + + // getInstrBB can split basic blocks and push elements to AllEdges. + for (size_t I : llvm::seq<size_t>(0, MST.AllEdges.size())) { + auto &E = *MST.AllEdges[I]; + // For now, disable spanning tree optimization when fork or exec* is + // used. + if (HasExecOrFork) + E.InMST = false; + E.Place = getInstrBB(MST, E, ExecBlocks); + } + // Basic blocks in F are finalized at this point. BasicBlock &EntryBlock = F.getEntryBlock(); Funcs.push_back(std::make_unique<GCOVFunction>(this, &F, SP, EndLine, FunctionIdent++, Version)); GCOVFunction &Func = *Funcs.back(); - // Some non-tree edges are IndirectBr which cannot be split. Ignore them - // as well. - llvm::erase_if(MST.AllEdges, [](std::unique_ptr<Edge> &E) { - return E->Removed || (!E->InMST && !E->Place); - }); - const size_t Measured = - std::stable_partition( - MST.AllEdges.begin(), MST.AllEdges.end(), - [](std::unique_ptr<Edge> &E) { return E->Place; }) - - MST.AllEdges.begin(); - for (size_t I : llvm::seq<size_t>(0, Measured)) { - Edge &E = *MST.AllEdges[I]; - GCOVBlock &Src = - E.SrcBB ? Func.getBlock(E.SrcBB) : Func.getEntryBlock(); - GCOVBlock &Dst = - E.DestBB ? Func.getBlock(E.DestBB) : Func.getReturnBlock(); - E.SrcNumber = Src.Number; - E.DstNumber = Dst.Number; - } - std::stable_sort( - MST.AllEdges.begin(), MST.AllEdges.begin() + Measured, - [](const std::unique_ptr<Edge> &L, const std::unique_ptr<Edge> &R) { - return L->SrcNumber != R->SrcNumber ? L->SrcNumber < R->SrcNumber - : L->DstNumber < R->DstNumber; - }); - - for (const Edge &E : make_pointee_range(MST.AllEdges)) { - GCOVBlock &Src = - E.SrcBB ? Func.getBlock(E.SrcBB) : Func.getEntryBlock(); - GCOVBlock &Dst = - E.DestBB ? Func.getBlock(E.DestBB) : Func.getReturnBlock(); - Src.addEdge(Dst, E.Place ? 0 : uint32_t(GCOV_ARC_ON_TREE)); - } - + // Some non-tree edges are IndirectBr which cannot be split. Ignore them + // as well. + llvm::erase_if(MST.AllEdges, [](std::unique_ptr<Edge> &E) { + return E->Removed || (!E->InMST && !E->Place); + }); + const size_t Measured = + std::stable_partition( + MST.AllEdges.begin(), MST.AllEdges.end(), + [](std::unique_ptr<Edge> &E) { return E->Place; }) - + MST.AllEdges.begin(); + for (size_t I : llvm::seq<size_t>(0, Measured)) { + Edge &E = *MST.AllEdges[I]; + GCOVBlock &Src = + E.SrcBB ? Func.getBlock(E.SrcBB) : Func.getEntryBlock(); + GCOVBlock &Dst = + E.DestBB ? Func.getBlock(E.DestBB) : Func.getReturnBlock(); + E.SrcNumber = Src.Number; + E.DstNumber = Dst.Number; + } + std::stable_sort( + MST.AllEdges.begin(), MST.AllEdges.begin() + Measured, + [](const std::unique_ptr<Edge> &L, const std::unique_ptr<Edge> &R) { + return L->SrcNumber != R->SrcNumber ? L->SrcNumber < R->SrcNumber + : L->DstNumber < R->DstNumber; + }); + + for (const Edge &E : make_pointee_range(MST.AllEdges)) { + GCOVBlock &Src = + E.SrcBB ? Func.getBlock(E.SrcBB) : Func.getEntryBlock(); + GCOVBlock &Dst = + E.DestBB ? Func.getBlock(E.DestBB) : Func.getReturnBlock(); + Src.addEdge(Dst, E.Place ? 0 : uint32_t(GCOV_ARC_ON_TREE)); + } + // Artificial functions such as global initializers if (!SP->isArtificial()) Func.getBlock(&EntryBlock).getFile(Filename).addLine(Line); - LLVM_DEBUG(dumpEdges(MST, Func)); - - for (auto &GB : Func.Blocks) { - const BasicBlock &BB = *GB.first; - auto &Block = GB.second; - for (auto Succ : Block.OutEdges) { - uint32_t Idx = Succ.first->Number; - do EdgeDestinations.push_back(Idx & 255); - while ((Idx >>= 8) > 0); + LLVM_DEBUG(dumpEdges(MST, Func)); + + for (auto &GB : Func.Blocks) { + const BasicBlock &BB = *GB.first; + auto &Block = GB.second; + for (auto Succ : Block.OutEdges) { + uint32_t Idx = Succ.first->Number; + do EdgeDestinations.push_back(Idx & 255); + while ((Idx >>= 8) > 0); } for (auto &I : BB) { @@ -950,110 +950,110 @@ bool GCOVProfiler::emitProfileNotes( } Line = 0; } - if (EmitGCDA) { - DISubprogram *SP = F.getSubprogram(); - ArrayType *CounterTy = ArrayType::get(Type::getInt64Ty(*Ctx), Measured); - GlobalVariable *Counters = new GlobalVariable( - *M, CounterTy, false, GlobalValue::InternalLinkage, - Constant::getNullValue(CounterTy), "__llvm_gcov_ctr"); - CountersBySP.emplace_back(Counters, SP); - - for (size_t I : llvm::seq<size_t>(0, Measured)) { - const Edge &E = *MST.AllEdges[I]; - IRBuilder<> Builder(E.Place, E.Place->getFirstInsertionPt()); - Value *V = Builder.CreateConstInBoundsGEP2_64( - Counters->getValueType(), Counters, 0, I); - if (Options.Atomic) { - Builder.CreateAtomicRMW(AtomicRMWInst::Add, V, Builder.getInt64(1), - AtomicOrdering::Monotonic); - } else { - Value *Count = - Builder.CreateLoad(Builder.getInt64Ty(), V, "gcov_ctr"); - Count = Builder.CreateAdd(Count, Builder.getInt64(1)); - Builder.CreateStore(Count, V); - } - } - } + if (EmitGCDA) { + DISubprogram *SP = F.getSubprogram(); + ArrayType *CounterTy = ArrayType::get(Type::getInt64Ty(*Ctx), Measured); + GlobalVariable *Counters = new GlobalVariable( + *M, CounterTy, false, GlobalValue::InternalLinkage, + Constant::getNullValue(CounterTy), "__llvm_gcov_ctr"); + CountersBySP.emplace_back(Counters, SP); + + for (size_t I : llvm::seq<size_t>(0, Measured)) { + const Edge &E = *MST.AllEdges[I]; + IRBuilder<> Builder(E.Place, E.Place->getFirstInsertionPt()); + Value *V = Builder.CreateConstInBoundsGEP2_64( + Counters->getValueType(), Counters, 0, I); + if (Options.Atomic) { + Builder.CreateAtomicRMW(AtomicRMWInst::Add, V, Builder.getInt64(1), + AtomicOrdering::Monotonic); + } else { + Value *Count = + Builder.CreateLoad(Builder.getInt64Ty(), V, "gcov_ctr"); + Count = Builder.CreateAdd(Count, Builder.getInt64(1)); + Builder.CreateStore(Count, V); + } + } + } } char Tmp[4]; - JamCRC JC; - JC.update(EdgeDestinations); - uint32_t Stamp = JC.getCRC(); + JamCRC JC; + JC.update(EdgeDestinations); + uint32_t Stamp = JC.getCRC(); FileChecksums.push_back(Stamp); - if (Options.EmitNotes) { - std::error_code EC; - raw_fd_ostream out(mangleName(CU, GCovFileType::GCNO), EC, - sys::fs::OF_None); - if (EC) { - Ctx->emitError( - Twine("failed to open coverage notes file for writing: ") + - EC.message()); + if (Options.EmitNotes) { + std::error_code EC; + raw_fd_ostream out(mangleName(CU, GCovFileType::GCNO), EC, + sys::fs::OF_None); + if (EC) { + Ctx->emitError( + Twine("failed to open coverage notes file for writing: ") + + EC.message()); continue; } - os = &out; - if (Endian == support::endianness::big) { - out.write("gcno", 4); - out.write(Options.Version, 4); - } else { - out.write("oncg", 4); - std::reverse_copy(Options.Version, Options.Version + 4, Tmp); - out.write(Tmp, 4); - } - write(Stamp); - if (Version >= 90) - writeString(""); // unuseful current_working_directory - if (Version >= 80) - write(0); // unuseful has_unexecuted_blocks - - for (auto &Func : Funcs) - Func->writeOut(Stamp); - - write(0); - write(0); - out.close(); - } - - if (EmitGCDA) { - emitGlobalConstructor(CountersBySP); - EmitGCDA = false; + os = &out; + if (Endian == support::endianness::big) { + out.write("gcno", 4); + out.write(Options.Version, 4); + } else { + out.write("oncg", 4); + std::reverse_copy(Options.Version, Options.Version + 4, Tmp); + out.write(Tmp, 4); + } + write(Stamp); + if (Version >= 90) + writeString(""); // unuseful current_working_directory + if (Version >= 80) + write(0); // unuseful has_unexecuted_blocks + + for (auto &Func : Funcs) + Func->writeOut(Stamp); + + write(0); + write(0); + out.close(); + } + + if (EmitGCDA) { + emitGlobalConstructor(CountersBySP); + EmitGCDA = false; } - } - return true; -} - -void GCOVProfiler::emitGlobalConstructor( - SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP) { - Function *WriteoutF = insertCounterWriteout(CountersBySP); - Function *ResetF = insertReset(CountersBySP); - - // Create a small bit of code that registers the "__llvm_gcov_writeout" to - // be executed at exit and the "__llvm_gcov_flush" function to be executed - // when "__gcov_flush" is called. - FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); - Function *F = Function::Create(FTy, GlobalValue::InternalLinkage, - "__llvm_gcov_init", M); - F->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); - F->setLinkage(GlobalValue::InternalLinkage); - F->addFnAttr(Attribute::NoInline); - if (Options.NoRedZone) - F->addFnAttr(Attribute::NoRedZone); - - BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", F); - IRBuilder<> Builder(BB); - - FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); - auto *PFTy = PointerType::get(FTy, 0); - FTy = FunctionType::get(Builder.getVoidTy(), {PFTy, PFTy}, false); - - // Initialize the environment and register the local writeout, flush and - // reset functions. - FunctionCallee GCOVInit = M->getOrInsertFunction("llvm_gcov_init", FTy); - Builder.CreateCall(GCOVInit, {WriteoutF, ResetF}); - Builder.CreateRetVoid(); - - appendToGlobalCtors(*M, F, 0); + } + return true; +} + +void GCOVProfiler::emitGlobalConstructor( + SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP) { + Function *WriteoutF = insertCounterWriteout(CountersBySP); + Function *ResetF = insertReset(CountersBySP); + + // Create a small bit of code that registers the "__llvm_gcov_writeout" to + // be executed at exit and the "__llvm_gcov_flush" function to be executed + // when "__gcov_flush" is called. + FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); + Function *F = Function::Create(FTy, GlobalValue::InternalLinkage, + "__llvm_gcov_init", M); + F->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); + F->setLinkage(GlobalValue::InternalLinkage); + F->addFnAttr(Attribute::NoInline); + if (Options.NoRedZone) + F->addFnAttr(Attribute::NoRedZone); + + BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", F); + IRBuilder<> Builder(BB); + + FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); + auto *PFTy = PointerType::get(FTy, 0); + FTy = FunctionType::get(Builder.getVoidTy(), {PFTy, PFTy}, false); + + // Initialize the environment and register the local writeout, flush and + // reset functions. + FunctionCallee GCOVInit = M->getOrInsertFunction("llvm_gcov_init", FTy); + Builder.CreateCall(GCOVInit, {WriteoutF, ResetF}); + Builder.CreateRetVoid(); + + appendToGlobalCtors(*M, F, 0); } FunctionCallee GCOVProfiler::getStartFileFunc(const TargetLibraryInfo *TLI) { @@ -1140,19 +1140,19 @@ Function *GCOVProfiler::insertCounterWriteout( // Collect the relevant data into a large constant data structure that we can // walk to write out everything. StructType *StartFileCallArgsTy = StructType::create( - {Builder.getInt8PtrTy(), Builder.getInt32Ty(), Builder.getInt32Ty()}, - "start_file_args_ty"); + {Builder.getInt8PtrTy(), Builder.getInt32Ty(), Builder.getInt32Ty()}, + "start_file_args_ty"); StructType *EmitFunctionCallArgsTy = StructType::create( - {Builder.getInt32Ty(), Builder.getInt32Ty(), Builder.getInt32Ty()}, - "emit_function_args_ty"); + {Builder.getInt32Ty(), Builder.getInt32Ty(), Builder.getInt32Ty()}, + "emit_function_args_ty"); StructType *EmitArcsCallArgsTy = StructType::create( - {Builder.getInt32Ty(), Builder.getInt64Ty()->getPointerTo()}, - "emit_arcs_args_ty"); + {Builder.getInt32Ty(), Builder.getInt64Ty()->getPointerTo()}, + "emit_arcs_args_ty"); StructType *FileInfoTy = StructType::create({StartFileCallArgsTy, Builder.getInt32Ty(), EmitFunctionCallArgsTy->getPointerTo(), - EmitArcsCallArgsTy->getPointerTo()}, - "file_info"); + EmitArcsCallArgsTy->getPointerTo()}, + "file_info"); Constant *Zero32 = Builder.getInt32(0); // Build an explicit array of two zeros for use in ConstantExpr GEP building. @@ -1262,46 +1262,46 @@ Function *GCOVProfiler::insertCounterWriteout( // The index into the files structure is our loop induction variable. Builder.SetInsertPoint(FileLoopHeader); - PHINode *IV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2, - "file_idx"); + PHINode *IV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2, + "file_idx"); IV->addIncoming(Builder.getInt32(0), BB); auto *FileInfoPtr = Builder.CreateInBoundsGEP( FileInfoArrayTy, FileInfoArrayGV, {Builder.getInt32(0), IV}); auto *StartFileCallArgsPtr = - Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 0, "start_file_args"); + Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 0, "start_file_args"); auto *StartFileCall = Builder.CreateCall( StartFile, {Builder.CreateLoad(StartFileCallArgsTy->getElementType(0), Builder.CreateStructGEP(StartFileCallArgsTy, - StartFileCallArgsPtr, 0), - "filename"), + StartFileCallArgsPtr, 0), + "filename"), Builder.CreateLoad(StartFileCallArgsTy->getElementType(1), Builder.CreateStructGEP(StartFileCallArgsTy, - StartFileCallArgsPtr, 1), - "version"), + StartFileCallArgsPtr, 1), + "version"), Builder.CreateLoad(StartFileCallArgsTy->getElementType(2), Builder.CreateStructGEP(StartFileCallArgsTy, - StartFileCallArgsPtr, 2), - "stamp")}); + StartFileCallArgsPtr, 2), + "stamp")}); if (auto AK = TLI->getExtAttrForI32Param(false)) StartFileCall->addParamAttr(2, AK); - auto *NumCounters = Builder.CreateLoad( - FileInfoTy->getElementType(1), - Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 1), "num_ctrs"); + auto *NumCounters = Builder.CreateLoad( + FileInfoTy->getElementType(1), + Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 1), "num_ctrs"); auto *EmitFunctionCallArgsArray = Builder.CreateLoad(FileInfoTy->getElementType(2), - Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 2), - "emit_function_args"); - auto *EmitArcsCallArgsArray = Builder.CreateLoad( - FileInfoTy->getElementType(3), - Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 3), "emit_arcs_args"); + Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 2), + "emit_function_args"); + auto *EmitArcsCallArgsArray = Builder.CreateLoad( + FileInfoTy->getElementType(3), + Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 3), "emit_arcs_args"); auto *EnterCounterLoopCond = Builder.CreateICmpSLT(Builder.getInt32(0), NumCounters); Builder.CreateCondBr(EnterCounterLoopCond, CounterLoopHeader, FileLoopLatch); Builder.SetInsertPoint(CounterLoopHeader); - auto *JV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2, - "ctr_idx"); + auto *JV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2, + "ctr_idx"); JV->addIncoming(Builder.getInt32(0), FileLoopHeader); auto *EmitFunctionCallArgsPtr = Builder.CreateInBoundsGEP( EmitFunctionCallArgsTy, EmitFunctionCallArgsArray, JV); @@ -1309,16 +1309,16 @@ Function *GCOVProfiler::insertCounterWriteout( EmitFunction, {Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(0), Builder.CreateStructGEP(EmitFunctionCallArgsTy, - EmitFunctionCallArgsPtr, 0), - "ident"), + EmitFunctionCallArgsPtr, 0), + "ident"), Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(1), Builder.CreateStructGEP(EmitFunctionCallArgsTy, - EmitFunctionCallArgsPtr, 1), - "func_checkssum"), + EmitFunctionCallArgsPtr, 1), + "func_checkssum"), Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(2), Builder.CreateStructGEP(EmitFunctionCallArgsTy, - EmitFunctionCallArgsPtr, 2), - "cfg_checksum")}); + EmitFunctionCallArgsPtr, 2), + "cfg_checksum")}); if (auto AK = TLI->getExtAttrForI32Param(false)) { EmitFunctionCall->addParamAttr(0, AK); EmitFunctionCall->addParamAttr(1, AK); @@ -1330,12 +1330,12 @@ Function *GCOVProfiler::insertCounterWriteout( EmitArcs, {Builder.CreateLoad( EmitArcsCallArgsTy->getElementType(0), - Builder.CreateStructGEP(EmitArcsCallArgsTy, EmitArcsCallArgsPtr, 0), - "num_counters"), - Builder.CreateLoad( - EmitArcsCallArgsTy->getElementType(1), - Builder.CreateStructGEP(EmitArcsCallArgsTy, EmitArcsCallArgsPtr, 1), - "counters")}); + Builder.CreateStructGEP(EmitArcsCallArgsTy, EmitArcsCallArgsPtr, 0), + "num_counters"), + Builder.CreateLoad( + EmitArcsCallArgsTy->getElementType(1), + Builder.CreateStructGEP(EmitArcsCallArgsTy, EmitArcsCallArgsPtr, 1), + "counters")}); if (auto AK = TLI->getExtAttrForI32Param(false)) EmitArcsCall->addParamAttr(0, AK); auto *NextJV = Builder.CreateAdd(JV, Builder.getInt32(1)); @@ -1346,7 +1346,7 @@ Function *GCOVProfiler::insertCounterWriteout( Builder.SetInsertPoint(FileLoopLatch); Builder.CreateCall(SummaryInfo, {}); Builder.CreateCall(EndFile, {}); - auto *NextIV = Builder.CreateAdd(IV, Builder.getInt32(1), "next_file_idx"); + auto *NextIV = Builder.CreateAdd(IV, Builder.getInt32(1), "next_file_idx"); auto *FileLoopCond = Builder.CreateICmpSLT(NextIV, Builder.getInt32(FileInfos.size())); Builder.CreateCondBr(FileLoopCond, FileLoopHeader, ExitBB); diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/contrib/libs/llvm12/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp index d668193c02..fedd9bfc97 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp @@ -55,12 +55,12 @@ using namespace llvm; #define DEBUG_TYPE "hwasan" -const char kHwasanModuleCtorName[] = "hwasan.module_ctor"; -const char kHwasanNoteName[] = "hwasan.note"; -const char kHwasanInitName[] = "__hwasan_init"; -const char kHwasanPersonalityThunkName[] = "__hwasan_personality_thunk"; +const char kHwasanModuleCtorName[] = "hwasan.module_ctor"; +const char kHwasanNoteName[] = "hwasan.note"; +const char kHwasanInitName[] = "__hwasan_init"; +const char kHwasanPersonalityThunkName[] = "__hwasan_personality_thunk"; -const char kHwasanShadowMemoryDynamicAddress[] = +const char kHwasanShadowMemoryDynamicAddress[] = "__hwasan_shadow_memory_dynamic_address"; // Accesses sizes are powers of two: 1, 2, 4, 8, 16. @@ -202,14 +202,14 @@ public: bool sanitizeFunction(Function &F); void initializeModule(); - void createHwasanCtorComdat(); + void createHwasanCtorComdat(); void initializeCallbacks(Module &M); - Value *getOpaqueNoopCast(IRBuilder<> &IRB, Value *Val); - + Value *getOpaqueNoopCast(IRBuilder<> &IRB, Value *Val); + Value *getDynamicShadowIfunc(IRBuilder<> &IRB); - Value *getShadowNonTls(IRBuilder<> &IRB); + Value *getShadowNonTls(IRBuilder<> &IRB); void untagPointerOperand(Instruction *I, Value *Addr); Value *memToShadow(Value *Shadow, IRBuilder<> &IRB); @@ -281,13 +281,13 @@ private: bool CompileKernel; bool Recover; - bool OutlinedChecks; + bool OutlinedChecks; bool UseShortGranules; bool InstrumentLandingPads; - bool HasMatchAllTag = false; - uint8_t MatchAllTag = 0; - + bool HasMatchAllTag = false; + uint8_t MatchAllTag = 0; + Function *HwasanCtorFunction; FunctionCallee HwasanMemoryAccessCallback[2][kNumberOfAccessSizes]; @@ -298,7 +298,7 @@ private: Constant *ShadowGlobal; - Value *ShadowBase = nullptr; + Value *ShadowBase = nullptr; Value *StackBaseTag = nullptr; GlobalValue *ThreadPtrGlobal = nullptr; }; @@ -370,106 +370,106 @@ PreservedAnalyses HWAddressSanitizerPass::run(Module &M, return PreservedAnalyses::all(); } -void HWAddressSanitizer::createHwasanCtorComdat() { - std::tie(HwasanCtorFunction, std::ignore) = - getOrCreateSanitizerCtorAndInitFunctions( - M, kHwasanModuleCtorName, kHwasanInitName, - /*InitArgTypes=*/{}, - /*InitArgs=*/{}, - // This callback is invoked when the functions are created the first - // time. Hook them into the global ctors list in that case: - [&](Function *Ctor, FunctionCallee) { - Comdat *CtorComdat = M.getOrInsertComdat(kHwasanModuleCtorName); - Ctor->setComdat(CtorComdat); - appendToGlobalCtors(M, Ctor, 0, Ctor); - }); - - // Create a note that contains pointers to the list of global - // descriptors. Adding a note to the output file will cause the linker to - // create a PT_NOTE program header pointing to the note that we can use to - // find the descriptor list starting from the program headers. A function - // provided by the runtime initializes the shadow memory for the globals by - // accessing the descriptor list via the note. The dynamic loader needs to - // call this function whenever a library is loaded. - // - // The reason why we use a note for this instead of a more conventional - // approach of having a global constructor pass a descriptor list pointer to - // the runtime is because of an order of initialization problem. With - // constructors we can encounter the following problematic scenario: - // - // 1) library A depends on library B and also interposes one of B's symbols - // 2) B's constructors are called before A's (as required for correctness) - // 3) during construction, B accesses one of its "own" globals (actually - // interposed by A) and triggers a HWASAN failure due to the initialization - // for A not having happened yet - // - // Even without interposition it is possible to run into similar situations in - // cases where two libraries mutually depend on each other. - // - // We only need one note per binary, so put everything for the note in a - // comdat. This needs to be a comdat with an .init_array section to prevent - // newer versions of lld from discarding the note. - // - // Create the note even if we aren't instrumenting globals. This ensures that - // binaries linked from object files with both instrumented and - // non-instrumented globals will end up with a note, even if a comdat from an - // object file with non-instrumented globals is selected. The note is harmless - // if the runtime doesn't support it, since it will just be ignored. - Comdat *NoteComdat = M.getOrInsertComdat(kHwasanModuleCtorName); - - Type *Int8Arr0Ty = ArrayType::get(Int8Ty, 0); - auto Start = - new GlobalVariable(M, Int8Arr0Ty, true, GlobalVariable::ExternalLinkage, - nullptr, "__start_hwasan_globals"); - Start->setVisibility(GlobalValue::HiddenVisibility); - Start->setDSOLocal(true); - auto Stop = - new GlobalVariable(M, Int8Arr0Ty, true, GlobalVariable::ExternalLinkage, - nullptr, "__stop_hwasan_globals"); - Stop->setVisibility(GlobalValue::HiddenVisibility); - Stop->setDSOLocal(true); - - // Null-terminated so actually 8 bytes, which are required in order to align - // the note properly. - auto *Name = ConstantDataArray::get(*C, "LLVM\0\0\0"); - - auto *NoteTy = StructType::get(Int32Ty, Int32Ty, Int32Ty, Name->getType(), - Int32Ty, Int32Ty); - auto *Note = - new GlobalVariable(M, NoteTy, /*isConstant=*/true, - GlobalValue::PrivateLinkage, nullptr, kHwasanNoteName); - Note->setSection(".note.hwasan.globals"); - Note->setComdat(NoteComdat); - Note->setAlignment(Align(4)); - Note->setDSOLocal(true); - - // The pointers in the note need to be relative so that the note ends up being - // placed in rodata, which is the standard location for notes. - auto CreateRelPtr = [&](Constant *Ptr) { - return ConstantExpr::getTrunc( - ConstantExpr::getSub(ConstantExpr::getPtrToInt(Ptr, Int64Ty), - ConstantExpr::getPtrToInt(Note, Int64Ty)), - Int32Ty); - }; - Note->setInitializer(ConstantStruct::getAnon( - {ConstantInt::get(Int32Ty, 8), // n_namesz - ConstantInt::get(Int32Ty, 8), // n_descsz - ConstantInt::get(Int32Ty, ELF::NT_LLVM_HWASAN_GLOBALS), // n_type - Name, CreateRelPtr(Start), CreateRelPtr(Stop)})); - appendToCompilerUsed(M, Note); - - // Create a zero-length global in hwasan_globals so that the linker will - // always create start and stop symbols. - auto Dummy = new GlobalVariable( - M, Int8Arr0Ty, /*isConstantGlobal*/ true, GlobalVariable::PrivateLinkage, - Constant::getNullValue(Int8Arr0Ty), "hwasan.dummy.global"); - Dummy->setSection("hwasan_globals"); - Dummy->setComdat(NoteComdat); - Dummy->setMetadata(LLVMContext::MD_associated, - MDNode::get(*C, ValueAsMetadata::get(Note))); - appendToCompilerUsed(M, Dummy); -} - +void HWAddressSanitizer::createHwasanCtorComdat() { + std::tie(HwasanCtorFunction, std::ignore) = + getOrCreateSanitizerCtorAndInitFunctions( + M, kHwasanModuleCtorName, kHwasanInitName, + /*InitArgTypes=*/{}, + /*InitArgs=*/{}, + // This callback is invoked when the functions are created the first + // time. Hook them into the global ctors list in that case: + [&](Function *Ctor, FunctionCallee) { + Comdat *CtorComdat = M.getOrInsertComdat(kHwasanModuleCtorName); + Ctor->setComdat(CtorComdat); + appendToGlobalCtors(M, Ctor, 0, Ctor); + }); + + // Create a note that contains pointers to the list of global + // descriptors. Adding a note to the output file will cause the linker to + // create a PT_NOTE program header pointing to the note that we can use to + // find the descriptor list starting from the program headers. A function + // provided by the runtime initializes the shadow memory for the globals by + // accessing the descriptor list via the note. The dynamic loader needs to + // call this function whenever a library is loaded. + // + // The reason why we use a note for this instead of a more conventional + // approach of having a global constructor pass a descriptor list pointer to + // the runtime is because of an order of initialization problem. With + // constructors we can encounter the following problematic scenario: + // + // 1) library A depends on library B and also interposes one of B's symbols + // 2) B's constructors are called before A's (as required for correctness) + // 3) during construction, B accesses one of its "own" globals (actually + // interposed by A) and triggers a HWASAN failure due to the initialization + // for A not having happened yet + // + // Even without interposition it is possible to run into similar situations in + // cases where two libraries mutually depend on each other. + // + // We only need one note per binary, so put everything for the note in a + // comdat. This needs to be a comdat with an .init_array section to prevent + // newer versions of lld from discarding the note. + // + // Create the note even if we aren't instrumenting globals. This ensures that + // binaries linked from object files with both instrumented and + // non-instrumented globals will end up with a note, even if a comdat from an + // object file with non-instrumented globals is selected. The note is harmless + // if the runtime doesn't support it, since it will just be ignored. + Comdat *NoteComdat = M.getOrInsertComdat(kHwasanModuleCtorName); + + Type *Int8Arr0Ty = ArrayType::get(Int8Ty, 0); + auto Start = + new GlobalVariable(M, Int8Arr0Ty, true, GlobalVariable::ExternalLinkage, + nullptr, "__start_hwasan_globals"); + Start->setVisibility(GlobalValue::HiddenVisibility); + Start->setDSOLocal(true); + auto Stop = + new GlobalVariable(M, Int8Arr0Ty, true, GlobalVariable::ExternalLinkage, + nullptr, "__stop_hwasan_globals"); + Stop->setVisibility(GlobalValue::HiddenVisibility); + Stop->setDSOLocal(true); + + // Null-terminated so actually 8 bytes, which are required in order to align + // the note properly. + auto *Name = ConstantDataArray::get(*C, "LLVM\0\0\0"); + + auto *NoteTy = StructType::get(Int32Ty, Int32Ty, Int32Ty, Name->getType(), + Int32Ty, Int32Ty); + auto *Note = + new GlobalVariable(M, NoteTy, /*isConstant=*/true, + GlobalValue::PrivateLinkage, nullptr, kHwasanNoteName); + Note->setSection(".note.hwasan.globals"); + Note->setComdat(NoteComdat); + Note->setAlignment(Align(4)); + Note->setDSOLocal(true); + + // The pointers in the note need to be relative so that the note ends up being + // placed in rodata, which is the standard location for notes. + auto CreateRelPtr = [&](Constant *Ptr) { + return ConstantExpr::getTrunc( + ConstantExpr::getSub(ConstantExpr::getPtrToInt(Ptr, Int64Ty), + ConstantExpr::getPtrToInt(Note, Int64Ty)), + Int32Ty); + }; + Note->setInitializer(ConstantStruct::getAnon( + {ConstantInt::get(Int32Ty, 8), // n_namesz + ConstantInt::get(Int32Ty, 8), // n_descsz + ConstantInt::get(Int32Ty, ELF::NT_LLVM_HWASAN_GLOBALS), // n_type + Name, CreateRelPtr(Start), CreateRelPtr(Stop)})); + appendToCompilerUsed(M, Note); + + // Create a zero-length global in hwasan_globals so that the linker will + // always create start and stop symbols. + auto Dummy = new GlobalVariable( + M, Int8Arr0Ty, /*isConstantGlobal*/ true, GlobalVariable::PrivateLinkage, + Constant::getNullValue(Int8Arr0Ty), "hwasan.dummy.global"); + Dummy->setSection("hwasan_globals"); + Dummy->setComdat(NoteComdat); + Dummy->setMetadata(LLVMContext::MD_associated, + MDNode::get(*C, ValueAsMetadata::get(Note))); + appendToCompilerUsed(M, Dummy); +} + /// Module-level initialization. /// /// inserts a call to __hwasan_init to the module's constructor list. @@ -498,27 +498,27 @@ void HWAddressSanitizer::initializeModule() { UseShortGranules = ClUseShortGranules.getNumOccurrences() ? ClUseShortGranules : NewRuntime; - OutlinedChecks = - TargetTriple.isAArch64() && TargetTriple.isOSBinFormatELF() && - (ClInlineAllChecks.getNumOccurrences() ? !ClInlineAllChecks : !Recover); - - if (ClMatchAllTag.getNumOccurrences()) { - if (ClMatchAllTag != -1) { - HasMatchAllTag = true; - MatchAllTag = ClMatchAllTag & 0xFF; - } - } else if (CompileKernel) { - HasMatchAllTag = true; - MatchAllTag = 0xFF; - } - + OutlinedChecks = + TargetTriple.isAArch64() && TargetTriple.isOSBinFormatELF() && + (ClInlineAllChecks.getNumOccurrences() ? !ClInlineAllChecks : !Recover); + + if (ClMatchAllTag.getNumOccurrences()) { + if (ClMatchAllTag != -1) { + HasMatchAllTag = true; + MatchAllTag = ClMatchAllTag & 0xFF; + } + } else if (CompileKernel) { + HasMatchAllTag = true; + MatchAllTag = 0xFF; + } + // If we don't have personality function support, fall back to landing pads. InstrumentLandingPads = ClInstrumentLandingPads.getNumOccurrences() ? ClInstrumentLandingPads : !NewRuntime; if (!CompileKernel) { - createHwasanCtorComdat(); + createHwasanCtorComdat(); bool InstrumentGlobals = ClGlobals.getNumOccurrences() ? ClGlobals : NewRuntime; if (InstrumentGlobals) @@ -589,27 +589,27 @@ void HWAddressSanitizer::initializeCallbacks(Module &M) { M.getOrInsertFunction("__hwasan_handle_vfork", IRB.getVoidTy(), IntptrTy); } -Value *HWAddressSanitizer::getOpaqueNoopCast(IRBuilder<> &IRB, Value *Val) { +Value *HWAddressSanitizer::getOpaqueNoopCast(IRBuilder<> &IRB, Value *Val) { // An empty inline asm with input reg == output reg. // An opaque no-op cast, basically. - // This prevents code bloat as a result of rematerializing trivial definitions - // such as constants or global addresses at every load and store. - InlineAsm *Asm = - InlineAsm::get(FunctionType::get(Int8PtrTy, {Val->getType()}, false), - StringRef(""), StringRef("=r,0"), - /*hasSideEffects=*/false); - return IRB.CreateCall(Asm, {Val}, ".hwasan.shadow"); + // This prevents code bloat as a result of rematerializing trivial definitions + // such as constants or global addresses at every load and store. + InlineAsm *Asm = + InlineAsm::get(FunctionType::get(Int8PtrTy, {Val->getType()}, false), + StringRef(""), StringRef("=r,0"), + /*hasSideEffects=*/false); + return IRB.CreateCall(Asm, {Val}, ".hwasan.shadow"); +} + +Value *HWAddressSanitizer::getDynamicShadowIfunc(IRBuilder<> &IRB) { + return getOpaqueNoopCast(IRB, ShadowGlobal); } -Value *HWAddressSanitizer::getDynamicShadowIfunc(IRBuilder<> &IRB) { - return getOpaqueNoopCast(IRB, ShadowGlobal); -} - -Value *HWAddressSanitizer::getShadowNonTls(IRBuilder<> &IRB) { +Value *HWAddressSanitizer::getShadowNonTls(IRBuilder<> &IRB) { if (Mapping.Offset != kDynamicShadowSentinel) - return getOpaqueNoopCast( - IRB, ConstantExpr::getIntToPtr( - ConstantInt::get(IntptrTy, Mapping.Offset), Int8PtrTy)); + return getOpaqueNoopCast( + IRB, ConstantExpr::getIntToPtr( + ConstantInt::get(IntptrTy, Mapping.Offset), Int8PtrTy)); if (Mapping.InGlobal) { return getDynamicShadowIfunc(IRB); @@ -645,7 +645,7 @@ void HWAddressSanitizer::getInterestingMemoryOperands( return; // Do not instrument the load fetching the dynamic shadow address. - if (ShadowBase == I) + if (ShadowBase == I) return; if (LoadInst *LI = dyn_cast<LoadInst>(I)) { @@ -715,29 +715,29 @@ Value *HWAddressSanitizer::memToShadow(Value *Mem, IRBuilder<> &IRB) { if (Mapping.Offset == 0) return IRB.CreateIntToPtr(Shadow, Int8PtrTy); // (Mem >> Scale) + Offset - return IRB.CreateGEP(Int8Ty, ShadowBase, Shadow); + return IRB.CreateGEP(Int8Ty, ShadowBase, Shadow); } void HWAddressSanitizer::instrumentMemAccessInline(Value *Ptr, bool IsWrite, unsigned AccessSizeIndex, Instruction *InsertBefore) { - const int64_t AccessInfo = - (CompileKernel << HWASanAccessInfo::CompileKernelShift) + - (HasMatchAllTag << HWASanAccessInfo::HasMatchAllShift) + - (MatchAllTag << HWASanAccessInfo::MatchAllShift) + - (Recover << HWASanAccessInfo::RecoverShift) + - (IsWrite << HWASanAccessInfo::IsWriteShift) + - (AccessSizeIndex << HWASanAccessInfo::AccessSizeShift); + const int64_t AccessInfo = + (CompileKernel << HWASanAccessInfo::CompileKernelShift) + + (HasMatchAllTag << HWASanAccessInfo::HasMatchAllShift) + + (MatchAllTag << HWASanAccessInfo::MatchAllShift) + + (Recover << HWASanAccessInfo::RecoverShift) + + (IsWrite << HWASanAccessInfo::IsWriteShift) + + (AccessSizeIndex << HWASanAccessInfo::AccessSizeShift); IRBuilder<> IRB(InsertBefore); - if (OutlinedChecks) { + if (OutlinedChecks) { Module *M = IRB.GetInsertBlock()->getParent()->getParent(); Ptr = IRB.CreateBitCast(Ptr, Int8PtrTy); IRB.CreateCall(Intrinsic::getDeclaration( M, UseShortGranules ? Intrinsic::hwasan_check_memaccess_shortgranules : Intrinsic::hwasan_check_memaccess), - {ShadowBase, Ptr, ConstantInt::get(Int32Ty, AccessInfo)}); + {ShadowBase, Ptr, ConstantInt::get(Int32Ty, AccessInfo)}); return; } @@ -749,9 +749,9 @@ void HWAddressSanitizer::instrumentMemAccessInline(Value *Ptr, bool IsWrite, Value *MemTag = IRB.CreateLoad(Int8Ty, Shadow); Value *TagMismatch = IRB.CreateICmpNE(PtrTag, MemTag); - if (HasMatchAllTag) { - Value *TagNotIgnored = IRB.CreateICmpNE( - PtrTag, ConstantInt::get(PtrTag->getType(), MatchAllTag)); + if (HasMatchAllTag) { + Value *TagNotIgnored = IRB.CreateICmpNE( + PtrTag, ConstantInt::get(PtrTag->getType(), MatchAllTag)); TagMismatch = IRB.CreateAnd(TagMismatch, TagNotIgnored); } @@ -773,8 +773,8 @@ void HWAddressSanitizer::instrumentMemAccessInline(Value *Ptr, bool IsWrite, Value *PtrLowBitsOOB = IRB.CreateICmpUGE(PtrLowBits, MemTag); SplitBlockAndInsertIfThen(PtrLowBitsOOB, CheckTerm, false, MDBuilder(*C).createBranchWeights(1, 100000), - (DomTreeUpdater *)nullptr, nullptr, - CheckFailTerm->getParent()); + (DomTreeUpdater *)nullptr, nullptr, + CheckFailTerm->getParent()); IRB.SetInsertPoint(CheckTerm); Value *InlineTagAddr = IRB.CreateOr(AddrLong, 15); @@ -783,8 +783,8 @@ void HWAddressSanitizer::instrumentMemAccessInline(Value *Ptr, bool IsWrite, Value *InlineTagMismatch = IRB.CreateICmpNE(PtrTag, InlineTag); SplitBlockAndInsertIfThen(InlineTagMismatch, CheckTerm, false, MDBuilder(*C).createBranchWeights(1, 100000), - (DomTreeUpdater *)nullptr, nullptr, - CheckFailTerm->getParent()); + (DomTreeUpdater *)nullptr, nullptr, + CheckFailTerm->getParent()); IRB.SetInsertPoint(CheckFailTerm); InlineAsm *Asm; @@ -793,9 +793,9 @@ void HWAddressSanitizer::instrumentMemAccessInline(Value *Ptr, bool IsWrite, // The signal handler will find the data address in rdi. Asm = InlineAsm::get( FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false), - "int3\nnopl " + - itostr(0x40 + (AccessInfo & HWASanAccessInfo::RuntimeMask)) + - "(%rax)", + "int3\nnopl " + + itostr(0x40 + (AccessInfo & HWASanAccessInfo::RuntimeMask)) + + "(%rax)", "{rdi}", /*hasSideEffects=*/true); break; @@ -804,8 +804,8 @@ void HWAddressSanitizer::instrumentMemAccessInline(Value *Ptr, bool IsWrite, // The signal handler will find the data address in x0. Asm = InlineAsm::get( FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false), - "brk #" + - itostr(0x900 + (AccessInfo & HWASanAccessInfo::RuntimeMask)), + "brk #" + + itostr(0x900 + (AccessInfo & HWASanAccessInfo::RuntimeMask)), "{x0}", /*hasSideEffects=*/true); break; @@ -1028,12 +1028,12 @@ Value *HWAddressSanitizer::getHwasanThreadSlotPtr(IRBuilder<> &IRB, Type *Ty) { void HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord) { if (!Mapping.InTls) { - ShadowBase = getShadowNonTls(IRB); + ShadowBase = getShadowNonTls(IRB); return; } if (!WithFrameRecord && TargetTriple.isAndroid()) { - ShadowBase = getDynamicShadowIfunc(IRB); + ShadowBase = getDynamicShadowIfunc(IRB); return; } @@ -1094,12 +1094,12 @@ void HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord) { // Get shadow base address by aligning RecordPtr up. // Note: this is not correct if the pointer is already aligned. // Runtime library will make sure this never happens. - ShadowBase = IRB.CreateAdd( + ShadowBase = IRB.CreateAdd( IRB.CreateOr( ThreadLongMaybeUntagged, ConstantInt::get(IntptrTy, (1ULL << kShadowBaseAlignment) - 1)), ConstantInt::get(IntptrTy, 1), "hwasan.shadow"); - ShadowBase = IRB.CreateIntToPtr(ShadowBase, Int8PtrTy); + ShadowBase = IRB.CreateIntToPtr(ShadowBase, Int8PtrTy); } Value *HWAddressSanitizer::readRegister(IRBuilder<> &IRB, StringRef Name) { @@ -1251,7 +1251,7 @@ bool HWAddressSanitizer::sanitizeFunction(Function &F) { IntrinToInstrument.empty()) return Changed; - assert(!ShadowBase); + assert(!ShadowBase); Instruction *InsertPt = &*F.getEntryBlock().begin(); IRBuilder<> EntryIRB(InsertPt); @@ -1331,7 +1331,7 @@ bool HWAddressSanitizer::sanitizeFunction(Function &F) { instrumentMemIntrinsic(cast<MemIntrinsic>(Inst)); } - ShadowBase = nullptr; + ShadowBase = nullptr; StackBaseTag = nullptr; return true; diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp b/contrib/libs/llvm12/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp index 068cf578dd..5b9557a9b3 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp @@ -263,15 +263,15 @@ ICallPromotionFunc::getPromotionCandidatesForCallSite( break; } - // Don't promote if the symbol is not defined in the module. This avoids - // creating a reference to a symbol that doesn't exist in the module - // This can happen when we compile with a sample profile collected from - // one binary but used for another, which may have profiled targets that - // aren't used in the new binary. We might have a declaration initially in - // the case where the symbol is globally dead in the binary and removed by - // ThinLTO. + // Don't promote if the symbol is not defined in the module. This avoids + // creating a reference to a symbol that doesn't exist in the module + // This can happen when we compile with a sample profile collected from + // one binary but used for another, which may have profiled targets that + // aren't used in the new binary. We might have a declaration initially in + // the case where the symbol is globally dead in the binary and removed by + // ThinLTO. Function *TargetFunction = Symtab->getFunction(Target); - if (TargetFunction == nullptr || TargetFunction->isDeclaration()) { + if (TargetFunction == nullptr || TargetFunction->isDeclaration()) { LLVM_DEBUG(dbgs() << " Not promote: Cannot find the target\n"); ORE.emit([&]() { return OptimizationRemarkMissed(DEBUG_TYPE, "UnableToFindTarget", &CB) diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/InstrProfiling.cpp b/contrib/libs/llvm12/lib/Transforms/Instrumentation/InstrProfiling.cpp index 83e048d010..9efc7d1ac5 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/InstrProfiling.cpp +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/InstrProfiling.cpp @@ -135,10 +135,10 @@ cl::opt<bool> IterativeCounterPromotion( cl::ZeroOrMore, "iterative-counter-promotion", cl::init(true), cl::desc("Allow counter promotion across the whole loop nest.")); -cl::opt<bool> SkipRetExitBlock( - cl::ZeroOrMore, "skip-ret-exit-block", cl::init(true), - cl::desc("Suppress counter promotion if exit blocks contain ret.")); - +cl::opt<bool> SkipRetExitBlock( + cl::ZeroOrMore, "skip-ret-exit-block", cl::init(true), + cl::desc("Suppress counter promotion if exit blocks contain ret.")); + class InstrProfilingLegacyPass : public ModulePass { InstrProfiling InstrProf; @@ -261,18 +261,18 @@ public: // Skip 'infinite' loops: if (ExitBlocks.size() == 0) return false; - - // Skip if any of the ExitBlocks contains a ret instruction. - // This is to prevent dumping of incomplete profile -- if the - // the loop is a long running loop and dump is called in the middle - // of the loop, the result profile is incomplete. - // FIXME: add other heuristics to detect long running loops. - if (SkipRetExitBlock) { - for (auto BB : ExitBlocks) - if (isa<ReturnInst>(BB->getTerminator())) - return false; - } - + + // Skip if any of the ExitBlocks contains a ret instruction. + // This is to prevent dumping of incomplete profile -- if the + // the loop is a long running loop and dump is called in the middle + // of the loop, the result profile is incomplete. + // FIXME: add other heuristics to detect long running loops. + if (SkipRetExitBlock) { + for (auto BB : ExitBlocks) + if (isa<ReturnInst>(BB->getTerminator())) + return false; + } + unsigned MaxProm = getMaxNumOfPromotionsInLoop(&L); if (MaxProm == 0) return false; @@ -396,15 +396,15 @@ private: BlockFrequencyInfo *BFI; }; -enum class ValueProfilingCallType { - // Individual values are tracked. Currently used for indiret call target - // profiling. - Default, - - // MemOp: the memop size value profiling. - MemOp -}; - +enum class ValueProfilingCallType { + // Individual values are tracked. Currently used for indiret call target + // profiling. + Default, + + // MemOp: the memop size value profiling. + MemOp +}; + } // end anonymous namespace PreservedAnalyses InstrProfiling::run(Module &M, ModuleAnalysisManager &AM) { @@ -587,9 +587,9 @@ bool InstrProfiling::run( return true; } -static FunctionCallee getOrInsertValueProfilingCall( - Module &M, const TargetLibraryInfo &TLI, - ValueProfilingCallType CallType = ValueProfilingCallType::Default) { +static FunctionCallee getOrInsertValueProfilingCall( + Module &M, const TargetLibraryInfo &TLI, + ValueProfilingCallType CallType = ValueProfilingCallType::Default) { LLVMContext &Ctx = M.getContext(); auto *ReturnTy = Type::getVoidTy(M.getContext()); @@ -597,19 +597,19 @@ static FunctionCallee getOrInsertValueProfilingCall( if (auto AK = TLI.getExtAttrForI32Param(false)) AL = AL.addParamAttribute(M.getContext(), 2, AK); - assert((CallType == ValueProfilingCallType::Default || - CallType == ValueProfilingCallType::MemOp) && - "Must be Default or MemOp"); - Type *ParamTypes[] = { + assert((CallType == ValueProfilingCallType::Default || + CallType == ValueProfilingCallType::MemOp) && + "Must be Default or MemOp"); + Type *ParamTypes[] = { #define VALUE_PROF_FUNC_PARAM(ParamType, ParamName, ParamLLVMType) ParamLLVMType #include "llvm/ProfileData/InstrProfData.inc" - }; - auto *ValueProfilingCallTy = - FunctionType::get(ReturnTy, makeArrayRef(ParamTypes), false); - StringRef FuncName = CallType == ValueProfilingCallType::Default - ? getInstrProfValueProfFuncName() - : getInstrProfValueProfMemOpFuncName(); - return M.getOrInsertFunction(FuncName, ValueProfilingCallTy, AL); + }; + auto *ValueProfilingCallTy = + FunctionType::get(ReturnTy, makeArrayRef(ParamTypes), false); + StringRef FuncName = CallType == ValueProfilingCallType::Default + ? getInstrProfValueProfFuncName() + : getInstrProfValueProfMemOpFuncName(); + return M.getOrInsertFunction(FuncName, ValueProfilingCallTy, AL); } void InstrProfiling::computeNumValueSiteCounts(InstrProfValueProfileInst *Ind) { @@ -638,8 +638,8 @@ void InstrProfiling::lowerValueProfileInst(InstrProfValueProfileInst *Ind) { Index += It->second.NumValueSites[Kind]; IRBuilder<> Builder(Ind); - bool IsMemOpSize = (Ind->getValueKind()->getZExtValue() == - llvm::InstrProfValueKind::IPVK_MemOPSize); + bool IsMemOpSize = (Ind->getValueKind()->getZExtValue() == + llvm::InstrProfValueKind::IPVK_MemOPSize); CallInst *Call = nullptr; auto *TLI = &GetTLI(*Ind->getFunction()); @@ -649,19 +649,19 @@ void InstrProfiling::lowerValueProfileInst(InstrProfValueProfileInst *Ind) { // WinEHPrepare pass. SmallVector<OperandBundleDef, 1> OpBundles; Ind->getOperandBundlesAsDefs(OpBundles); - if (!IsMemOpSize) { + if (!IsMemOpSize) { Value *Args[3] = {Ind->getTargetValue(), Builder.CreateBitCast(DataVar, Builder.getInt8PtrTy()), Builder.getInt32(Index)}; Call = Builder.CreateCall(getOrInsertValueProfilingCall(*M, *TLI), Args, OpBundles); } else { - Value *Args[3] = {Ind->getTargetValue(), - Builder.CreateBitCast(DataVar, Builder.getInt8PtrTy()), - Builder.getInt32(Index)}; - Call = Builder.CreateCall( - getOrInsertValueProfilingCall(*M, *TLI, ValueProfilingCallType::MemOp), - Args, OpBundles); + Value *Args[3] = {Ind->getTargetValue(), + Builder.CreateBitCast(DataVar, Builder.getInt8PtrTy()), + Builder.getInt32(Index)}; + Call = Builder.CreateCall( + getOrInsertValueProfilingCall(*M, *TLI, ValueProfilingCallType::MemOp), + Args, OpBundles); } if (auto AK = TLI->getExtAttrForI32Param(false)) Call->addParamAttr(2, AK); @@ -828,11 +828,11 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfIncrementInst *Inc) { Visibility = GlobalValue::HiddenVisibility; } } - std::string DataVarName = getVarName(Inc, getInstrProfDataVarPrefix()); + std::string DataVarName = getVarName(Inc, getInstrProfDataVarPrefix()); auto MaybeSetComdat = [=](GlobalVariable *GV) { if (NeedComdat) - GV->setComdat(M->getOrInsertComdat(TT.isOSBinFormatCOFF() ? GV->getName() - : DataVarName)); + GV->setComdat(M->getOrInsertComdat(TT.isOSBinFormatCOFF() ? GV->getName() + : DataVarName)); }; uint64_t NumCounters = Inc->getNumCounters()->getZExtValue(); @@ -897,9 +897,9 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfIncrementInst *Inc) { #define INSTR_PROF_DATA(Type, LLVMType, Name, Init) Init, #include "llvm/ProfileData/InstrProfData.inc" }; - auto *Data = - new GlobalVariable(*M, DataTy, false, Linkage, - ConstantStruct::get(DataTy, DataVals), DataVarName); + auto *Data = + new GlobalVariable(*M, DataTy, false, Linkage, + ConstantStruct::get(DataTy, DataVals), DataVarName); Data->setVisibility(Visibility); Data->setSection(getInstrProfSectionName(IPSK_data, TT.getObjectFormat())); Data->setAlignment(Align(INSTR_PROF_DATA_ALIGNMENT)); diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/Instrumentation.cpp b/contrib/libs/llvm12/lib/Transforms/Instrumentation/Instrumentation.cpp index ff4a00fcb7..cfdf3cad97 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/Instrumentation.cpp +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/Instrumentation.cpp @@ -105,8 +105,8 @@ Comdat *llvm::GetOrCreateFunctionComdat(Function &F, Triple &T, void llvm::initializeInstrumentation(PassRegistry &Registry) { initializeAddressSanitizerLegacyPassPass(Registry); initializeModuleAddressSanitizerLegacyPassPass(Registry); - initializeMemProfilerLegacyPassPass(Registry); - initializeModuleMemProfilerLegacyPassPass(Registry); + initializeMemProfilerLegacyPassPass(Registry); + initializeModuleMemProfilerLegacyPassPass(Registry); initializeBoundsCheckingLegacyPassPass(Registry); initializeControlHeightReductionLegacyPassPass(Registry); initializeGCOVProfilerLegacyPassPass(Registry); @@ -121,7 +121,7 @@ void llvm::initializeInstrumentation(PassRegistry &Registry) { initializeHWAddressSanitizerLegacyPassPass(Registry); initializeThreadSanitizerLegacyPassPass(Registry); initializeModuleSanitizerCoverageLegacyPassPass(Registry); - initializeDataFlowSanitizerLegacyPassPass(Registry); + initializeDataFlowSanitizerLegacyPassPass(Registry); } /// LLVMInitializeInstrumentation - C binding for diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/MemProfiler.cpp b/contrib/libs/llvm12/lib/Transforms/Instrumentation/MemProfiler.cpp index fa2edf52a2..0e6a404a9e 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/MemProfiler.cpp +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/MemProfiler.cpp @@ -1,638 +1,638 @@ -//===- MemProfiler.cpp - memory allocation and access profiler ------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is a part of MemProfiler. Memory accesses are instrumented -// to increment the access count held in a shadow memory location, or -// alternatively to call into the runtime. Memory intrinsic calls (memmove, -// memcpy, memset) are changed to call the memory profiling runtime version -// instead. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Transforms/Instrumentation/MemProfiler.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" -#include "llvm/IR/Constant.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/GlobalValue.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Type.h" -#include "llvm/IR/Value.h" -#include "llvm/InitializePasses.h" -#include "llvm/Pass.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Debug.h" -#include "llvm/Transforms/Instrumentation.h" -#include "llvm/Transforms/Utils/BasicBlockUtils.h" -#include "llvm/Transforms/Utils/ModuleUtils.h" - -using namespace llvm; - -#define DEBUG_TYPE "memprof" - -constexpr int LLVM_MEM_PROFILER_VERSION = 1; - -// Size of memory mapped to a single shadow location. -constexpr uint64_t DefaultShadowGranularity = 64; - -// Scale from granularity down to shadow size. -constexpr uint64_t DefaultShadowScale = 3; - -constexpr char MemProfModuleCtorName[] = "memprof.module_ctor"; -constexpr uint64_t MemProfCtorAndDtorPriority = 1; -// On Emscripten, the system needs more than one priorities for constructors. -constexpr uint64_t MemProfEmscriptenCtorAndDtorPriority = 50; -constexpr char MemProfInitName[] = "__memprof_init"; -constexpr char MemProfVersionCheckNamePrefix[] = - "__memprof_version_mismatch_check_v"; - -constexpr char MemProfShadowMemoryDynamicAddress[] = - "__memprof_shadow_memory_dynamic_address"; - -constexpr char MemProfFilenameVar[] = "__memprof_profile_filename"; - -// Command-line flags. - -static cl::opt<bool> ClInsertVersionCheck( - "memprof-guard-against-version-mismatch", - cl::desc("Guard against compiler/runtime version mismatch."), cl::Hidden, - cl::init(true)); - -// This flag may need to be replaced with -f[no-]memprof-reads. -static cl::opt<bool> ClInstrumentReads("memprof-instrument-reads", - cl::desc("instrument read instructions"), - cl::Hidden, cl::init(true)); - -static cl::opt<bool> - ClInstrumentWrites("memprof-instrument-writes", - cl::desc("instrument write instructions"), cl::Hidden, - cl::init(true)); - -static cl::opt<bool> ClInstrumentAtomics( - "memprof-instrument-atomics", - cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden, - cl::init(true)); - -static cl::opt<bool> ClUseCalls( - "memprof-use-callbacks", - cl::desc("Use callbacks instead of inline instrumentation sequences."), - cl::Hidden, cl::init(false)); - -static cl::opt<std::string> - ClMemoryAccessCallbackPrefix("memprof-memory-access-callback-prefix", - cl::desc("Prefix for memory access callbacks"), - cl::Hidden, cl::init("__memprof_")); - -// These flags allow to change the shadow mapping. -// The shadow mapping looks like -// Shadow = ((Mem & mask) >> scale) + offset - -static cl::opt<int> ClMappingScale("memprof-mapping-scale", - cl::desc("scale of memprof shadow mapping"), - cl::Hidden, cl::init(DefaultShadowScale)); - -static cl::opt<int> - ClMappingGranularity("memprof-mapping-granularity", - cl::desc("granularity of memprof shadow mapping"), - cl::Hidden, cl::init(DefaultShadowGranularity)); - -// Debug flags. - -static cl::opt<int> ClDebug("memprof-debug", cl::desc("debug"), cl::Hidden, - cl::init(0)); - -static cl::opt<std::string> ClDebugFunc("memprof-debug-func", cl::Hidden, - cl::desc("Debug func")); - -static cl::opt<int> ClDebugMin("memprof-debug-min", cl::desc("Debug min inst"), - cl::Hidden, cl::init(-1)); - -static cl::opt<int> ClDebugMax("memprof-debug-max", cl::desc("Debug max inst"), - cl::Hidden, cl::init(-1)); - -STATISTIC(NumInstrumentedReads, "Number of instrumented reads"); -STATISTIC(NumInstrumentedWrites, "Number of instrumented writes"); - -namespace { - -/// This struct defines the shadow mapping using the rule: -/// shadow = ((mem & mask) >> Scale) ADD DynamicShadowOffset. -struct ShadowMapping { - ShadowMapping() { - Scale = ClMappingScale; - Granularity = ClMappingGranularity; - Mask = ~(Granularity - 1); - } - - int Scale; - int Granularity; - uint64_t Mask; // Computed as ~(Granularity-1) -}; - -static uint64_t getCtorAndDtorPriority(Triple &TargetTriple) { - return TargetTriple.isOSEmscripten() ? MemProfEmscriptenCtorAndDtorPriority - : MemProfCtorAndDtorPriority; -} - -struct InterestingMemoryAccess { - Value *Addr = nullptr; - bool IsWrite; - unsigned Alignment; - uint64_t TypeSize; - Value *MaybeMask = nullptr; -}; - -/// Instrument the code in module to profile memory accesses. -class MemProfiler { -public: - MemProfiler(Module &M) { - C = &(M.getContext()); - LongSize = M.getDataLayout().getPointerSizeInBits(); - IntptrTy = Type::getIntNTy(*C, LongSize); - } - - /// If it is an interesting memory access, populate information - /// about the access and return a InterestingMemoryAccess struct. - /// Otherwise return None. - Optional<InterestingMemoryAccess> - isInterestingMemoryAccess(Instruction *I) const; - - void instrumentMop(Instruction *I, const DataLayout &DL, - InterestingMemoryAccess &Access); - void instrumentAddress(Instruction *OrigIns, Instruction *InsertBefore, - Value *Addr, uint32_t TypeSize, bool IsWrite); - void instrumentMaskedLoadOrStore(const DataLayout &DL, Value *Mask, - Instruction *I, Value *Addr, - unsigned Alignment, uint32_t TypeSize, - bool IsWrite); - void instrumentMemIntrinsic(MemIntrinsic *MI); - Value *memToShadow(Value *Shadow, IRBuilder<> &IRB); - bool instrumentFunction(Function &F); - bool maybeInsertMemProfInitAtFunctionEntry(Function &F); - bool insertDynamicShadowAtFunctionEntry(Function &F); - -private: - void initializeCallbacks(Module &M); - - LLVMContext *C; - int LongSize; - Type *IntptrTy; - ShadowMapping Mapping; - - // These arrays is indexed by AccessIsWrite - FunctionCallee MemProfMemoryAccessCallback[2]; - FunctionCallee MemProfMemoryAccessCallbackSized[2]; - - FunctionCallee MemProfMemmove, MemProfMemcpy, MemProfMemset; - Value *DynamicShadowOffset = nullptr; -}; - -class MemProfilerLegacyPass : public FunctionPass { -public: - static char ID; - - explicit MemProfilerLegacyPass() : FunctionPass(ID) { - initializeMemProfilerLegacyPassPass(*PassRegistry::getPassRegistry()); - } - - StringRef getPassName() const override { return "MemProfilerFunctionPass"; } - - bool runOnFunction(Function &F) override { - MemProfiler Profiler(*F.getParent()); - return Profiler.instrumentFunction(F); - } -}; - -class ModuleMemProfiler { -public: - ModuleMemProfiler(Module &M) { TargetTriple = Triple(M.getTargetTriple()); } - - bool instrumentModule(Module &); - -private: - Triple TargetTriple; - ShadowMapping Mapping; - Function *MemProfCtorFunction = nullptr; -}; - -class ModuleMemProfilerLegacyPass : public ModulePass { -public: - static char ID; - - explicit ModuleMemProfilerLegacyPass() : ModulePass(ID) { - initializeModuleMemProfilerLegacyPassPass(*PassRegistry::getPassRegistry()); - } - - StringRef getPassName() const override { return "ModuleMemProfiler"; } - - void getAnalysisUsage(AnalysisUsage &AU) const override {} - - bool runOnModule(Module &M) override { - ModuleMemProfiler MemProfiler(M); - return MemProfiler.instrumentModule(M); - } -}; - -} // end anonymous namespace - -MemProfilerPass::MemProfilerPass() {} - -PreservedAnalyses MemProfilerPass::run(Function &F, - AnalysisManager<Function> &AM) { - Module &M = *F.getParent(); - MemProfiler Profiler(M); - if (Profiler.instrumentFunction(F)) - return PreservedAnalyses::none(); - return PreservedAnalyses::all(); - - return PreservedAnalyses::all(); -} - -ModuleMemProfilerPass::ModuleMemProfilerPass() {} - -PreservedAnalyses ModuleMemProfilerPass::run(Module &M, - AnalysisManager<Module> &AM) { - ModuleMemProfiler Profiler(M); - if (Profiler.instrumentModule(M)) - return PreservedAnalyses::none(); - return PreservedAnalyses::all(); -} - -char MemProfilerLegacyPass::ID = 0; - -INITIALIZE_PASS_BEGIN(MemProfilerLegacyPass, "memprof", - "MemProfiler: profile memory allocations and accesses.", - false, false) -INITIALIZE_PASS_END(MemProfilerLegacyPass, "memprof", - "MemProfiler: profile memory allocations and accesses.", - false, false) - -FunctionPass *llvm::createMemProfilerFunctionPass() { - return new MemProfilerLegacyPass(); -} - -char ModuleMemProfilerLegacyPass::ID = 0; - -INITIALIZE_PASS(ModuleMemProfilerLegacyPass, "memprof-module", - "MemProfiler: profile memory allocations and accesses." - "ModulePass", - false, false) - -ModulePass *llvm::createModuleMemProfilerLegacyPassPass() { - return new ModuleMemProfilerLegacyPass(); -} - -Value *MemProfiler::memToShadow(Value *Shadow, IRBuilder<> &IRB) { - // (Shadow & mask) >> scale - Shadow = IRB.CreateAnd(Shadow, Mapping.Mask); - Shadow = IRB.CreateLShr(Shadow, Mapping.Scale); - // (Shadow >> scale) | offset - assert(DynamicShadowOffset); - return IRB.CreateAdd(Shadow, DynamicShadowOffset); -} - -// Instrument memset/memmove/memcpy -void MemProfiler::instrumentMemIntrinsic(MemIntrinsic *MI) { - IRBuilder<> IRB(MI); - if (isa<MemTransferInst>(MI)) { - IRB.CreateCall( - isa<MemMoveInst>(MI) ? MemProfMemmove : MemProfMemcpy, - {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()), - IRB.CreatePointerCast(MI->getOperand(1), IRB.getInt8PtrTy()), - IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)}); - } else if (isa<MemSetInst>(MI)) { - IRB.CreateCall( - MemProfMemset, - {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()), - IRB.CreateIntCast(MI->getOperand(1), IRB.getInt32Ty(), false), - IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)}); - } - MI->eraseFromParent(); -} - -Optional<InterestingMemoryAccess> -MemProfiler::isInterestingMemoryAccess(Instruction *I) const { - // Do not instrument the load fetching the dynamic shadow address. - if (DynamicShadowOffset == I) - return None; - - InterestingMemoryAccess Access; - - const DataLayout &DL = I->getModule()->getDataLayout(); - if (LoadInst *LI = dyn_cast<LoadInst>(I)) { - if (!ClInstrumentReads) - return None; - Access.IsWrite = false; - Access.TypeSize = DL.getTypeStoreSizeInBits(LI->getType()); - Access.Alignment = LI->getAlignment(); - Access.Addr = LI->getPointerOperand(); - } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) { - if (!ClInstrumentWrites) - return None; - Access.IsWrite = true; - Access.TypeSize = - DL.getTypeStoreSizeInBits(SI->getValueOperand()->getType()); - Access.Alignment = SI->getAlignment(); - Access.Addr = SI->getPointerOperand(); - } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) { - if (!ClInstrumentAtomics) - return None; - Access.IsWrite = true; - Access.TypeSize = - DL.getTypeStoreSizeInBits(RMW->getValOperand()->getType()); - Access.Alignment = 0; - Access.Addr = RMW->getPointerOperand(); - } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) { - if (!ClInstrumentAtomics) - return None; - Access.IsWrite = true; - Access.TypeSize = - DL.getTypeStoreSizeInBits(XCHG->getCompareOperand()->getType()); - Access.Alignment = 0; - Access.Addr = XCHG->getPointerOperand(); - } else if (auto *CI = dyn_cast<CallInst>(I)) { - auto *F = CI->getCalledFunction(); - if (F && (F->getIntrinsicID() == Intrinsic::masked_load || - F->getIntrinsicID() == Intrinsic::masked_store)) { - unsigned OpOffset = 0; - if (F->getIntrinsicID() == Intrinsic::masked_store) { - if (!ClInstrumentWrites) - return None; - // Masked store has an initial operand for the value. - OpOffset = 1; - Access.IsWrite = true; - } else { - if (!ClInstrumentReads) - return None; - Access.IsWrite = false; - } - - auto *BasePtr = CI->getOperand(0 + OpOffset); - auto *Ty = cast<PointerType>(BasePtr->getType())->getElementType(); - Access.TypeSize = DL.getTypeStoreSizeInBits(Ty); - if (auto *AlignmentConstant = - dyn_cast<ConstantInt>(CI->getOperand(1 + OpOffset))) - Access.Alignment = (unsigned)AlignmentConstant->getZExtValue(); - else - Access.Alignment = 1; // No alignment guarantees. We probably got Undef - Access.MaybeMask = CI->getOperand(2 + OpOffset); - Access.Addr = BasePtr; - } - } - - if (!Access.Addr) - return None; - - // Do not instrument acesses from different address spaces; we cannot deal - // with them. - Type *PtrTy = cast<PointerType>(Access.Addr->getType()->getScalarType()); - if (PtrTy->getPointerAddressSpace() != 0) - return None; - - // Ignore swifterror addresses. - // swifterror memory addresses are mem2reg promoted by instruction - // selection. As such they cannot have regular uses like an instrumentation - // function and it makes no sense to track them as memory. - if (Access.Addr->isSwiftError()) - return None; - - return Access; -} - -void MemProfiler::instrumentMaskedLoadOrStore(const DataLayout &DL, Value *Mask, - Instruction *I, Value *Addr, - unsigned Alignment, - uint32_t TypeSize, bool IsWrite) { - auto *VTy = cast<FixedVectorType>( - cast<PointerType>(Addr->getType())->getElementType()); - uint64_t ElemTypeSize = DL.getTypeStoreSizeInBits(VTy->getScalarType()); - unsigned Num = VTy->getNumElements(); - auto *Zero = ConstantInt::get(IntptrTy, 0); - for (unsigned Idx = 0; Idx < Num; ++Idx) { - Value *InstrumentedAddress = nullptr; - Instruction *InsertBefore = I; - if (auto *Vector = dyn_cast<ConstantVector>(Mask)) { - // dyn_cast as we might get UndefValue - if (auto *Masked = dyn_cast<ConstantInt>(Vector->getOperand(Idx))) { - if (Masked->isZero()) - // Mask is constant false, so no instrumentation needed. - continue; - // If we have a true or undef value, fall through to instrumentAddress. - // with InsertBefore == I - } - } else { - IRBuilder<> IRB(I); - Value *MaskElem = IRB.CreateExtractElement(Mask, Idx); - Instruction *ThenTerm = SplitBlockAndInsertIfThen(MaskElem, I, false); - InsertBefore = ThenTerm; - } - - IRBuilder<> IRB(InsertBefore); - InstrumentedAddress = - IRB.CreateGEP(VTy, Addr, {Zero, ConstantInt::get(IntptrTy, Idx)}); - instrumentAddress(I, InsertBefore, InstrumentedAddress, ElemTypeSize, - IsWrite); - } -} - -void MemProfiler::instrumentMop(Instruction *I, const DataLayout &DL, - InterestingMemoryAccess &Access) { - if (Access.IsWrite) - NumInstrumentedWrites++; - else - NumInstrumentedReads++; - - if (Access.MaybeMask) { - instrumentMaskedLoadOrStore(DL, Access.MaybeMask, I, Access.Addr, - Access.Alignment, Access.TypeSize, - Access.IsWrite); - } else { - // Since the access counts will be accumulated across the entire allocation, - // we only update the shadow access count for the first location and thus - // don't need to worry about alignment and type size. - instrumentAddress(I, I, Access.Addr, Access.TypeSize, Access.IsWrite); - } -} - -void MemProfiler::instrumentAddress(Instruction *OrigIns, - Instruction *InsertBefore, Value *Addr, - uint32_t TypeSize, bool IsWrite) { - IRBuilder<> IRB(InsertBefore); - Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy); - - if (ClUseCalls) { - IRB.CreateCall(MemProfMemoryAccessCallback[IsWrite], AddrLong); - return; - } - - // Create an inline sequence to compute shadow location, and increment the - // value by one. - Type *ShadowTy = Type::getInt64Ty(*C); - Type *ShadowPtrTy = PointerType::get(ShadowTy, 0); - Value *ShadowPtr = memToShadow(AddrLong, IRB); - Value *ShadowAddr = IRB.CreateIntToPtr(ShadowPtr, ShadowPtrTy); - Value *ShadowValue = IRB.CreateLoad(ShadowTy, ShadowAddr); - Value *Inc = ConstantInt::get(Type::getInt64Ty(*C), 1); - ShadowValue = IRB.CreateAdd(ShadowValue, Inc); - IRB.CreateStore(ShadowValue, ShadowAddr); -} - -// Create the variable for the profile file name. -void createProfileFileNameVar(Module &M) { - const MDString *MemProfFilename = - dyn_cast_or_null<MDString>(M.getModuleFlag("MemProfProfileFilename")); - if (!MemProfFilename) - return; - assert(!MemProfFilename->getString().empty() && - "Unexpected MemProfProfileFilename metadata with empty string"); - Constant *ProfileNameConst = ConstantDataArray::getString( - M.getContext(), MemProfFilename->getString(), true); - GlobalVariable *ProfileNameVar = new GlobalVariable( - M, ProfileNameConst->getType(), /*isConstant=*/true, - GlobalValue::WeakAnyLinkage, ProfileNameConst, MemProfFilenameVar); - Triple TT(M.getTargetTriple()); - if (TT.supportsCOMDAT()) { - ProfileNameVar->setLinkage(GlobalValue::ExternalLinkage); - ProfileNameVar->setComdat(M.getOrInsertComdat(MemProfFilenameVar)); - } -} - -bool ModuleMemProfiler::instrumentModule(Module &M) { - // Create a module constructor. - std::string MemProfVersion = std::to_string(LLVM_MEM_PROFILER_VERSION); - std::string VersionCheckName = - ClInsertVersionCheck ? (MemProfVersionCheckNamePrefix + MemProfVersion) - : ""; - std::tie(MemProfCtorFunction, std::ignore) = - createSanitizerCtorAndInitFunctions(M, MemProfModuleCtorName, - MemProfInitName, /*InitArgTypes=*/{}, - /*InitArgs=*/{}, VersionCheckName); - - const uint64_t Priority = getCtorAndDtorPriority(TargetTriple); - appendToGlobalCtors(M, MemProfCtorFunction, Priority); - - createProfileFileNameVar(M); - - return true; -} - -void MemProfiler::initializeCallbacks(Module &M) { - IRBuilder<> IRB(*C); - - for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) { - const std::string TypeStr = AccessIsWrite ? "store" : "load"; - - SmallVector<Type *, 3> Args2 = {IntptrTy, IntptrTy}; - SmallVector<Type *, 2> Args1{1, IntptrTy}; - MemProfMemoryAccessCallbackSized[AccessIsWrite] = - M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + TypeStr + "N", - FunctionType::get(IRB.getVoidTy(), Args2, false)); - - MemProfMemoryAccessCallback[AccessIsWrite] = - M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + TypeStr, - FunctionType::get(IRB.getVoidTy(), Args1, false)); - } - MemProfMemmove = M.getOrInsertFunction( - ClMemoryAccessCallbackPrefix + "memmove", IRB.getInt8PtrTy(), - IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy); - MemProfMemcpy = M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + "memcpy", - IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), - IRB.getInt8PtrTy(), IntptrTy); - MemProfMemset = M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + "memset", - IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), - IRB.getInt32Ty(), IntptrTy); -} - -bool MemProfiler::maybeInsertMemProfInitAtFunctionEntry(Function &F) { - // For each NSObject descendant having a +load method, this method is invoked - // by the ObjC runtime before any of the static constructors is called. - // Therefore we need to instrument such methods with a call to __memprof_init - // at the beginning in order to initialize our runtime before any access to - // the shadow memory. - // We cannot just ignore these methods, because they may call other - // instrumented functions. - if (F.getName().find(" load]") != std::string::npos) { - FunctionCallee MemProfInitFunction = - declareSanitizerInitFunction(*F.getParent(), MemProfInitName, {}); - IRBuilder<> IRB(&F.front(), F.front().begin()); - IRB.CreateCall(MemProfInitFunction, {}); - return true; - } - return false; -} - -bool MemProfiler::insertDynamicShadowAtFunctionEntry(Function &F) { - IRBuilder<> IRB(&F.front().front()); - Value *GlobalDynamicAddress = F.getParent()->getOrInsertGlobal( - MemProfShadowMemoryDynamicAddress, IntptrTy); - if (F.getParent()->getPICLevel() == PICLevel::NotPIC) - cast<GlobalVariable>(GlobalDynamicAddress)->setDSOLocal(true); - DynamicShadowOffset = IRB.CreateLoad(IntptrTy, GlobalDynamicAddress); - return true; -} - -bool MemProfiler::instrumentFunction(Function &F) { - if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) - return false; - if (ClDebugFunc == F.getName()) - return false; - if (F.getName().startswith("__memprof_")) - return false; - - bool FunctionModified = false; - - // If needed, insert __memprof_init. - // This function needs to be called even if the function body is not - // instrumented. - if (maybeInsertMemProfInitAtFunctionEntry(F)) - FunctionModified = true; - - LLVM_DEBUG(dbgs() << "MEMPROF instrumenting:\n" << F << "\n"); - - initializeCallbacks(*F.getParent()); - - FunctionModified |= insertDynamicShadowAtFunctionEntry(F); - - SmallVector<Instruction *, 16> ToInstrument; - - // Fill the set of memory operations to instrument. - for (auto &BB : F) { - for (auto &Inst : BB) { - if (isInterestingMemoryAccess(&Inst) || isa<MemIntrinsic>(Inst)) - ToInstrument.push_back(&Inst); - } - } - - int NumInstrumented = 0; - for (auto *Inst : ToInstrument) { - if (ClDebugMin < 0 || ClDebugMax < 0 || - (NumInstrumented >= ClDebugMin && NumInstrumented <= ClDebugMax)) { - Optional<InterestingMemoryAccess> Access = - isInterestingMemoryAccess(Inst); - if (Access) - instrumentMop(Inst, F.getParent()->getDataLayout(), *Access); - else - instrumentMemIntrinsic(cast<MemIntrinsic>(Inst)); - } - NumInstrumented++; - } - - if (NumInstrumented > 0) - FunctionModified = true; - - LLVM_DEBUG(dbgs() << "MEMPROF done instrumenting: " << FunctionModified << " " - << F << "\n"); - - return FunctionModified; -} +//===- MemProfiler.cpp - memory allocation and access profiler ------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of MemProfiler. Memory accesses are instrumented +// to increment the access count held in a shadow memory location, or +// alternatively to call into the runtime. Memory intrinsic calls (memmove, +// memcpy, memset) are changed to call the memory profiling runtime version +// instead. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Instrumentation/MemProfiler.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/IR/Constant.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Value.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Transforms/Instrumentation.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" + +using namespace llvm; + +#define DEBUG_TYPE "memprof" + +constexpr int LLVM_MEM_PROFILER_VERSION = 1; + +// Size of memory mapped to a single shadow location. +constexpr uint64_t DefaultShadowGranularity = 64; + +// Scale from granularity down to shadow size. +constexpr uint64_t DefaultShadowScale = 3; + +constexpr char MemProfModuleCtorName[] = "memprof.module_ctor"; +constexpr uint64_t MemProfCtorAndDtorPriority = 1; +// On Emscripten, the system needs more than one priorities for constructors. +constexpr uint64_t MemProfEmscriptenCtorAndDtorPriority = 50; +constexpr char MemProfInitName[] = "__memprof_init"; +constexpr char MemProfVersionCheckNamePrefix[] = + "__memprof_version_mismatch_check_v"; + +constexpr char MemProfShadowMemoryDynamicAddress[] = + "__memprof_shadow_memory_dynamic_address"; + +constexpr char MemProfFilenameVar[] = "__memprof_profile_filename"; + +// Command-line flags. + +static cl::opt<bool> ClInsertVersionCheck( + "memprof-guard-against-version-mismatch", + cl::desc("Guard against compiler/runtime version mismatch."), cl::Hidden, + cl::init(true)); + +// This flag may need to be replaced with -f[no-]memprof-reads. +static cl::opt<bool> ClInstrumentReads("memprof-instrument-reads", + cl::desc("instrument read instructions"), + cl::Hidden, cl::init(true)); + +static cl::opt<bool> + ClInstrumentWrites("memprof-instrument-writes", + cl::desc("instrument write instructions"), cl::Hidden, + cl::init(true)); + +static cl::opt<bool> ClInstrumentAtomics( + "memprof-instrument-atomics", + cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden, + cl::init(true)); + +static cl::opt<bool> ClUseCalls( + "memprof-use-callbacks", + cl::desc("Use callbacks instead of inline instrumentation sequences."), + cl::Hidden, cl::init(false)); + +static cl::opt<std::string> + ClMemoryAccessCallbackPrefix("memprof-memory-access-callback-prefix", + cl::desc("Prefix for memory access callbacks"), + cl::Hidden, cl::init("__memprof_")); + +// These flags allow to change the shadow mapping. +// The shadow mapping looks like +// Shadow = ((Mem & mask) >> scale) + offset + +static cl::opt<int> ClMappingScale("memprof-mapping-scale", + cl::desc("scale of memprof shadow mapping"), + cl::Hidden, cl::init(DefaultShadowScale)); + +static cl::opt<int> + ClMappingGranularity("memprof-mapping-granularity", + cl::desc("granularity of memprof shadow mapping"), + cl::Hidden, cl::init(DefaultShadowGranularity)); + +// Debug flags. + +static cl::opt<int> ClDebug("memprof-debug", cl::desc("debug"), cl::Hidden, + cl::init(0)); + +static cl::opt<std::string> ClDebugFunc("memprof-debug-func", cl::Hidden, + cl::desc("Debug func")); + +static cl::opt<int> ClDebugMin("memprof-debug-min", cl::desc("Debug min inst"), + cl::Hidden, cl::init(-1)); + +static cl::opt<int> ClDebugMax("memprof-debug-max", cl::desc("Debug max inst"), + cl::Hidden, cl::init(-1)); + +STATISTIC(NumInstrumentedReads, "Number of instrumented reads"); +STATISTIC(NumInstrumentedWrites, "Number of instrumented writes"); + +namespace { + +/// This struct defines the shadow mapping using the rule: +/// shadow = ((mem & mask) >> Scale) ADD DynamicShadowOffset. +struct ShadowMapping { + ShadowMapping() { + Scale = ClMappingScale; + Granularity = ClMappingGranularity; + Mask = ~(Granularity - 1); + } + + int Scale; + int Granularity; + uint64_t Mask; // Computed as ~(Granularity-1) +}; + +static uint64_t getCtorAndDtorPriority(Triple &TargetTriple) { + return TargetTriple.isOSEmscripten() ? MemProfEmscriptenCtorAndDtorPriority + : MemProfCtorAndDtorPriority; +} + +struct InterestingMemoryAccess { + Value *Addr = nullptr; + bool IsWrite; + unsigned Alignment; + uint64_t TypeSize; + Value *MaybeMask = nullptr; +}; + +/// Instrument the code in module to profile memory accesses. +class MemProfiler { +public: + MemProfiler(Module &M) { + C = &(M.getContext()); + LongSize = M.getDataLayout().getPointerSizeInBits(); + IntptrTy = Type::getIntNTy(*C, LongSize); + } + + /// If it is an interesting memory access, populate information + /// about the access and return a InterestingMemoryAccess struct. + /// Otherwise return None. + Optional<InterestingMemoryAccess> + isInterestingMemoryAccess(Instruction *I) const; + + void instrumentMop(Instruction *I, const DataLayout &DL, + InterestingMemoryAccess &Access); + void instrumentAddress(Instruction *OrigIns, Instruction *InsertBefore, + Value *Addr, uint32_t TypeSize, bool IsWrite); + void instrumentMaskedLoadOrStore(const DataLayout &DL, Value *Mask, + Instruction *I, Value *Addr, + unsigned Alignment, uint32_t TypeSize, + bool IsWrite); + void instrumentMemIntrinsic(MemIntrinsic *MI); + Value *memToShadow(Value *Shadow, IRBuilder<> &IRB); + bool instrumentFunction(Function &F); + bool maybeInsertMemProfInitAtFunctionEntry(Function &F); + bool insertDynamicShadowAtFunctionEntry(Function &F); + +private: + void initializeCallbacks(Module &M); + + LLVMContext *C; + int LongSize; + Type *IntptrTy; + ShadowMapping Mapping; + + // These arrays is indexed by AccessIsWrite + FunctionCallee MemProfMemoryAccessCallback[2]; + FunctionCallee MemProfMemoryAccessCallbackSized[2]; + + FunctionCallee MemProfMemmove, MemProfMemcpy, MemProfMemset; + Value *DynamicShadowOffset = nullptr; +}; + +class MemProfilerLegacyPass : public FunctionPass { +public: + static char ID; + + explicit MemProfilerLegacyPass() : FunctionPass(ID) { + initializeMemProfilerLegacyPassPass(*PassRegistry::getPassRegistry()); + } + + StringRef getPassName() const override { return "MemProfilerFunctionPass"; } + + bool runOnFunction(Function &F) override { + MemProfiler Profiler(*F.getParent()); + return Profiler.instrumentFunction(F); + } +}; + +class ModuleMemProfiler { +public: + ModuleMemProfiler(Module &M) { TargetTriple = Triple(M.getTargetTriple()); } + + bool instrumentModule(Module &); + +private: + Triple TargetTriple; + ShadowMapping Mapping; + Function *MemProfCtorFunction = nullptr; +}; + +class ModuleMemProfilerLegacyPass : public ModulePass { +public: + static char ID; + + explicit ModuleMemProfilerLegacyPass() : ModulePass(ID) { + initializeModuleMemProfilerLegacyPassPass(*PassRegistry::getPassRegistry()); + } + + StringRef getPassName() const override { return "ModuleMemProfiler"; } + + void getAnalysisUsage(AnalysisUsage &AU) const override {} + + bool runOnModule(Module &M) override { + ModuleMemProfiler MemProfiler(M); + return MemProfiler.instrumentModule(M); + } +}; + +} // end anonymous namespace + +MemProfilerPass::MemProfilerPass() {} + +PreservedAnalyses MemProfilerPass::run(Function &F, + AnalysisManager<Function> &AM) { + Module &M = *F.getParent(); + MemProfiler Profiler(M); + if (Profiler.instrumentFunction(F)) + return PreservedAnalyses::none(); + return PreservedAnalyses::all(); + + return PreservedAnalyses::all(); +} + +ModuleMemProfilerPass::ModuleMemProfilerPass() {} + +PreservedAnalyses ModuleMemProfilerPass::run(Module &M, + AnalysisManager<Module> &AM) { + ModuleMemProfiler Profiler(M); + if (Profiler.instrumentModule(M)) + return PreservedAnalyses::none(); + return PreservedAnalyses::all(); +} + +char MemProfilerLegacyPass::ID = 0; + +INITIALIZE_PASS_BEGIN(MemProfilerLegacyPass, "memprof", + "MemProfiler: profile memory allocations and accesses.", + false, false) +INITIALIZE_PASS_END(MemProfilerLegacyPass, "memprof", + "MemProfiler: profile memory allocations and accesses.", + false, false) + +FunctionPass *llvm::createMemProfilerFunctionPass() { + return new MemProfilerLegacyPass(); +} + +char ModuleMemProfilerLegacyPass::ID = 0; + +INITIALIZE_PASS(ModuleMemProfilerLegacyPass, "memprof-module", + "MemProfiler: profile memory allocations and accesses." + "ModulePass", + false, false) + +ModulePass *llvm::createModuleMemProfilerLegacyPassPass() { + return new ModuleMemProfilerLegacyPass(); +} + +Value *MemProfiler::memToShadow(Value *Shadow, IRBuilder<> &IRB) { + // (Shadow & mask) >> scale + Shadow = IRB.CreateAnd(Shadow, Mapping.Mask); + Shadow = IRB.CreateLShr(Shadow, Mapping.Scale); + // (Shadow >> scale) | offset + assert(DynamicShadowOffset); + return IRB.CreateAdd(Shadow, DynamicShadowOffset); +} + +// Instrument memset/memmove/memcpy +void MemProfiler::instrumentMemIntrinsic(MemIntrinsic *MI) { + IRBuilder<> IRB(MI); + if (isa<MemTransferInst>(MI)) { + IRB.CreateCall( + isa<MemMoveInst>(MI) ? MemProfMemmove : MemProfMemcpy, + {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()), + IRB.CreatePointerCast(MI->getOperand(1), IRB.getInt8PtrTy()), + IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)}); + } else if (isa<MemSetInst>(MI)) { + IRB.CreateCall( + MemProfMemset, + {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()), + IRB.CreateIntCast(MI->getOperand(1), IRB.getInt32Ty(), false), + IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)}); + } + MI->eraseFromParent(); +} + +Optional<InterestingMemoryAccess> +MemProfiler::isInterestingMemoryAccess(Instruction *I) const { + // Do not instrument the load fetching the dynamic shadow address. + if (DynamicShadowOffset == I) + return None; + + InterestingMemoryAccess Access; + + const DataLayout &DL = I->getModule()->getDataLayout(); + if (LoadInst *LI = dyn_cast<LoadInst>(I)) { + if (!ClInstrumentReads) + return None; + Access.IsWrite = false; + Access.TypeSize = DL.getTypeStoreSizeInBits(LI->getType()); + Access.Alignment = LI->getAlignment(); + Access.Addr = LI->getPointerOperand(); + } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) { + if (!ClInstrumentWrites) + return None; + Access.IsWrite = true; + Access.TypeSize = + DL.getTypeStoreSizeInBits(SI->getValueOperand()->getType()); + Access.Alignment = SI->getAlignment(); + Access.Addr = SI->getPointerOperand(); + } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) { + if (!ClInstrumentAtomics) + return None; + Access.IsWrite = true; + Access.TypeSize = + DL.getTypeStoreSizeInBits(RMW->getValOperand()->getType()); + Access.Alignment = 0; + Access.Addr = RMW->getPointerOperand(); + } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) { + if (!ClInstrumentAtomics) + return None; + Access.IsWrite = true; + Access.TypeSize = + DL.getTypeStoreSizeInBits(XCHG->getCompareOperand()->getType()); + Access.Alignment = 0; + Access.Addr = XCHG->getPointerOperand(); + } else if (auto *CI = dyn_cast<CallInst>(I)) { + auto *F = CI->getCalledFunction(); + if (F && (F->getIntrinsicID() == Intrinsic::masked_load || + F->getIntrinsicID() == Intrinsic::masked_store)) { + unsigned OpOffset = 0; + if (F->getIntrinsicID() == Intrinsic::masked_store) { + if (!ClInstrumentWrites) + return None; + // Masked store has an initial operand for the value. + OpOffset = 1; + Access.IsWrite = true; + } else { + if (!ClInstrumentReads) + return None; + Access.IsWrite = false; + } + + auto *BasePtr = CI->getOperand(0 + OpOffset); + auto *Ty = cast<PointerType>(BasePtr->getType())->getElementType(); + Access.TypeSize = DL.getTypeStoreSizeInBits(Ty); + if (auto *AlignmentConstant = + dyn_cast<ConstantInt>(CI->getOperand(1 + OpOffset))) + Access.Alignment = (unsigned)AlignmentConstant->getZExtValue(); + else + Access.Alignment = 1; // No alignment guarantees. We probably got Undef + Access.MaybeMask = CI->getOperand(2 + OpOffset); + Access.Addr = BasePtr; + } + } + + if (!Access.Addr) + return None; + + // Do not instrument acesses from different address spaces; we cannot deal + // with them. + Type *PtrTy = cast<PointerType>(Access.Addr->getType()->getScalarType()); + if (PtrTy->getPointerAddressSpace() != 0) + return None; + + // Ignore swifterror addresses. + // swifterror memory addresses are mem2reg promoted by instruction + // selection. As such they cannot have regular uses like an instrumentation + // function and it makes no sense to track them as memory. + if (Access.Addr->isSwiftError()) + return None; + + return Access; +} + +void MemProfiler::instrumentMaskedLoadOrStore(const DataLayout &DL, Value *Mask, + Instruction *I, Value *Addr, + unsigned Alignment, + uint32_t TypeSize, bool IsWrite) { + auto *VTy = cast<FixedVectorType>( + cast<PointerType>(Addr->getType())->getElementType()); + uint64_t ElemTypeSize = DL.getTypeStoreSizeInBits(VTy->getScalarType()); + unsigned Num = VTy->getNumElements(); + auto *Zero = ConstantInt::get(IntptrTy, 0); + for (unsigned Idx = 0; Idx < Num; ++Idx) { + Value *InstrumentedAddress = nullptr; + Instruction *InsertBefore = I; + if (auto *Vector = dyn_cast<ConstantVector>(Mask)) { + // dyn_cast as we might get UndefValue + if (auto *Masked = dyn_cast<ConstantInt>(Vector->getOperand(Idx))) { + if (Masked->isZero()) + // Mask is constant false, so no instrumentation needed. + continue; + // If we have a true or undef value, fall through to instrumentAddress. + // with InsertBefore == I + } + } else { + IRBuilder<> IRB(I); + Value *MaskElem = IRB.CreateExtractElement(Mask, Idx); + Instruction *ThenTerm = SplitBlockAndInsertIfThen(MaskElem, I, false); + InsertBefore = ThenTerm; + } + + IRBuilder<> IRB(InsertBefore); + InstrumentedAddress = + IRB.CreateGEP(VTy, Addr, {Zero, ConstantInt::get(IntptrTy, Idx)}); + instrumentAddress(I, InsertBefore, InstrumentedAddress, ElemTypeSize, + IsWrite); + } +} + +void MemProfiler::instrumentMop(Instruction *I, const DataLayout &DL, + InterestingMemoryAccess &Access) { + if (Access.IsWrite) + NumInstrumentedWrites++; + else + NumInstrumentedReads++; + + if (Access.MaybeMask) { + instrumentMaskedLoadOrStore(DL, Access.MaybeMask, I, Access.Addr, + Access.Alignment, Access.TypeSize, + Access.IsWrite); + } else { + // Since the access counts will be accumulated across the entire allocation, + // we only update the shadow access count for the first location and thus + // don't need to worry about alignment and type size. + instrumentAddress(I, I, Access.Addr, Access.TypeSize, Access.IsWrite); + } +} + +void MemProfiler::instrumentAddress(Instruction *OrigIns, + Instruction *InsertBefore, Value *Addr, + uint32_t TypeSize, bool IsWrite) { + IRBuilder<> IRB(InsertBefore); + Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy); + + if (ClUseCalls) { + IRB.CreateCall(MemProfMemoryAccessCallback[IsWrite], AddrLong); + return; + } + + // Create an inline sequence to compute shadow location, and increment the + // value by one. + Type *ShadowTy = Type::getInt64Ty(*C); + Type *ShadowPtrTy = PointerType::get(ShadowTy, 0); + Value *ShadowPtr = memToShadow(AddrLong, IRB); + Value *ShadowAddr = IRB.CreateIntToPtr(ShadowPtr, ShadowPtrTy); + Value *ShadowValue = IRB.CreateLoad(ShadowTy, ShadowAddr); + Value *Inc = ConstantInt::get(Type::getInt64Ty(*C), 1); + ShadowValue = IRB.CreateAdd(ShadowValue, Inc); + IRB.CreateStore(ShadowValue, ShadowAddr); +} + +// Create the variable for the profile file name. +void createProfileFileNameVar(Module &M) { + const MDString *MemProfFilename = + dyn_cast_or_null<MDString>(M.getModuleFlag("MemProfProfileFilename")); + if (!MemProfFilename) + return; + assert(!MemProfFilename->getString().empty() && + "Unexpected MemProfProfileFilename metadata with empty string"); + Constant *ProfileNameConst = ConstantDataArray::getString( + M.getContext(), MemProfFilename->getString(), true); + GlobalVariable *ProfileNameVar = new GlobalVariable( + M, ProfileNameConst->getType(), /*isConstant=*/true, + GlobalValue::WeakAnyLinkage, ProfileNameConst, MemProfFilenameVar); + Triple TT(M.getTargetTriple()); + if (TT.supportsCOMDAT()) { + ProfileNameVar->setLinkage(GlobalValue::ExternalLinkage); + ProfileNameVar->setComdat(M.getOrInsertComdat(MemProfFilenameVar)); + } +} + +bool ModuleMemProfiler::instrumentModule(Module &M) { + // Create a module constructor. + std::string MemProfVersion = std::to_string(LLVM_MEM_PROFILER_VERSION); + std::string VersionCheckName = + ClInsertVersionCheck ? (MemProfVersionCheckNamePrefix + MemProfVersion) + : ""; + std::tie(MemProfCtorFunction, std::ignore) = + createSanitizerCtorAndInitFunctions(M, MemProfModuleCtorName, + MemProfInitName, /*InitArgTypes=*/{}, + /*InitArgs=*/{}, VersionCheckName); + + const uint64_t Priority = getCtorAndDtorPriority(TargetTriple); + appendToGlobalCtors(M, MemProfCtorFunction, Priority); + + createProfileFileNameVar(M); + + return true; +} + +void MemProfiler::initializeCallbacks(Module &M) { + IRBuilder<> IRB(*C); + + for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) { + const std::string TypeStr = AccessIsWrite ? "store" : "load"; + + SmallVector<Type *, 3> Args2 = {IntptrTy, IntptrTy}; + SmallVector<Type *, 2> Args1{1, IntptrTy}; + MemProfMemoryAccessCallbackSized[AccessIsWrite] = + M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + TypeStr + "N", + FunctionType::get(IRB.getVoidTy(), Args2, false)); + + MemProfMemoryAccessCallback[AccessIsWrite] = + M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + TypeStr, + FunctionType::get(IRB.getVoidTy(), Args1, false)); + } + MemProfMemmove = M.getOrInsertFunction( + ClMemoryAccessCallbackPrefix + "memmove", IRB.getInt8PtrTy(), + IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy); + MemProfMemcpy = M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + "memcpy", + IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), + IRB.getInt8PtrTy(), IntptrTy); + MemProfMemset = M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + "memset", + IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), + IRB.getInt32Ty(), IntptrTy); +} + +bool MemProfiler::maybeInsertMemProfInitAtFunctionEntry(Function &F) { + // For each NSObject descendant having a +load method, this method is invoked + // by the ObjC runtime before any of the static constructors is called. + // Therefore we need to instrument such methods with a call to __memprof_init + // at the beginning in order to initialize our runtime before any access to + // the shadow memory. + // We cannot just ignore these methods, because they may call other + // instrumented functions. + if (F.getName().find(" load]") != std::string::npos) { + FunctionCallee MemProfInitFunction = + declareSanitizerInitFunction(*F.getParent(), MemProfInitName, {}); + IRBuilder<> IRB(&F.front(), F.front().begin()); + IRB.CreateCall(MemProfInitFunction, {}); + return true; + } + return false; +} + +bool MemProfiler::insertDynamicShadowAtFunctionEntry(Function &F) { + IRBuilder<> IRB(&F.front().front()); + Value *GlobalDynamicAddress = F.getParent()->getOrInsertGlobal( + MemProfShadowMemoryDynamicAddress, IntptrTy); + if (F.getParent()->getPICLevel() == PICLevel::NotPIC) + cast<GlobalVariable>(GlobalDynamicAddress)->setDSOLocal(true); + DynamicShadowOffset = IRB.CreateLoad(IntptrTy, GlobalDynamicAddress); + return true; +} + +bool MemProfiler::instrumentFunction(Function &F) { + if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) + return false; + if (ClDebugFunc == F.getName()) + return false; + if (F.getName().startswith("__memprof_")) + return false; + + bool FunctionModified = false; + + // If needed, insert __memprof_init. + // This function needs to be called even if the function body is not + // instrumented. + if (maybeInsertMemProfInitAtFunctionEntry(F)) + FunctionModified = true; + + LLVM_DEBUG(dbgs() << "MEMPROF instrumenting:\n" << F << "\n"); + + initializeCallbacks(*F.getParent()); + + FunctionModified |= insertDynamicShadowAtFunctionEntry(F); + + SmallVector<Instruction *, 16> ToInstrument; + + // Fill the set of memory operations to instrument. + for (auto &BB : F) { + for (auto &Inst : BB) { + if (isInterestingMemoryAccess(&Inst) || isa<MemIntrinsic>(Inst)) + ToInstrument.push_back(&Inst); + } + } + + int NumInstrumented = 0; + for (auto *Inst : ToInstrument) { + if (ClDebugMin < 0 || ClDebugMax < 0 || + (NumInstrumented >= ClDebugMin && NumInstrumented <= ClDebugMax)) { + Optional<InterestingMemoryAccess> Access = + isInterestingMemoryAccess(Inst); + if (Access) + instrumentMop(Inst, F.getParent()->getDataLayout(), *Access); + else + instrumentMemIntrinsic(cast<MemIntrinsic>(Inst)); + } + NumInstrumented++; + } + + if (NumInstrumented > 0) + FunctionModified = true; + + LLVM_DEBUG(dbgs() << "MEMPROF done instrumenting: " << FunctionModified << " " + << F << "\n"); + + return FunctionModified; +} diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/contrib/libs/llvm12/lib/Transforms/Instrumentation/MemorySanitizer.cpp index affc204924..7a6874584d 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/MemorySanitizer.cpp +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/MemorySanitizer.cpp @@ -153,7 +153,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Analysis/TargetLibraryInfo.h" -#include "llvm/Analysis/ValueTracking.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/BasicBlock.h" @@ -338,8 +338,8 @@ static cl::opt<uint64_t> ClOriginBase("msan-origin-base", cl::desc("Define custom MSan OriginBase"), cl::Hidden, cl::init(0)); -const char kMsanModuleCtorName[] = "msan.module_ctor"; -const char kMsanInitName[] = "__msan_init"; +const char kMsanModuleCtorName[] = "msan.module_ctor"; +const char kMsanInitName[] = "__msan_init"; namespace { @@ -573,9 +573,9 @@ private: /// uninitialized value and returns an updated origin id encoding this info. FunctionCallee MsanChainOriginFn; - /// Run-time helper that paints an origin over a region. - FunctionCallee MsanSetOriginFn; - + /// Run-time helper that paints an origin over a region. + FunctionCallee MsanSetOriginFn; + /// MSan runtime replacements for memmove, memcpy and memset. FunctionCallee MemmoveFn, MemcpyFn, MemsetFn; @@ -854,9 +854,9 @@ void MemorySanitizer::initializeCallbacks(Module &M) { // instrumentation. MsanChainOriginFn = M.getOrInsertFunction( "__msan_chain_origin", IRB.getInt32Ty(), IRB.getInt32Ty()); - MsanSetOriginFn = - M.getOrInsertFunction("__msan_set_origin", IRB.getVoidTy(), - IRB.getInt8PtrTy(), IntptrTy, IRB.getInt32Ty()); + MsanSetOriginFn = + M.getOrInsertFunction("__msan_set_origin", IRB.getVoidTy(), + IRB.getInt8PtrTy(), IntptrTy, IRB.getInt32Ty()); MemmoveFn = M.getOrInsertFunction( "__msan_memmove", IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy); @@ -1056,7 +1056,7 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { ValueMap<Value*, Value*> ShadowMap, OriginMap; std::unique_ptr<VarArgHelper> VAHelper; const TargetLibraryInfo *TLI; - Instruction *FnPrologueEnd; + Instruction *FnPrologueEnd; // The following flags disable parts of MSan instrumentation based on // exclusion list contents and command-line options. @@ -1088,31 +1088,31 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { PoisonStack = SanitizeFunction && ClPoisonStack; PoisonUndef = SanitizeFunction && ClPoisonUndef; - // In the presence of unreachable blocks, we may see Phi nodes with - // incoming nodes from such blocks. Since InstVisitor skips unreachable - // blocks, such nodes will not have any shadow value associated with them. - // It's easier to remove unreachable blocks than deal with missing shadow. - removeUnreachableBlocks(F); - + // In the presence of unreachable blocks, we may see Phi nodes with + // incoming nodes from such blocks. Since InstVisitor skips unreachable + // blocks, such nodes will not have any shadow value associated with them. + // It's easier to remove unreachable blocks than deal with missing shadow. + removeUnreachableBlocks(F); + MS.initializeCallbacks(*F.getParent()); - FnPrologueEnd = IRBuilder<>(F.getEntryBlock().getFirstNonPHI()) - .CreateIntrinsic(Intrinsic::donothing, {}, {}); - - if (MS.CompileKernel) { - IRBuilder<> IRB(FnPrologueEnd); - insertKmsanPrologue(IRB); - } - + FnPrologueEnd = IRBuilder<>(F.getEntryBlock().getFirstNonPHI()) + .CreateIntrinsic(Intrinsic::donothing, {}, {}); + + if (MS.CompileKernel) { + IRBuilder<> IRB(FnPrologueEnd); + insertKmsanPrologue(IRB); + } + LLVM_DEBUG(if (!InsertChecks) dbgs() << "MemorySanitizer is not inserting checks into '" << F.getName() << "'\n"); } - bool isInPrologue(Instruction &I) { - return I.getParent() == FnPrologueEnd->getParent() && - (&I == FnPrologueEnd || I.comesBefore(FnPrologueEnd)); - } - + bool isInPrologue(Instruction &I) { + return I.getParent() == FnPrologueEnd->getParent() && + (&I == FnPrologueEnd || I.comesBefore(FnPrologueEnd)); + } + Value *updateOrigin(Value *V, IRBuilder<> &IRB) { if (MS.TrackOrigins <= 1) return V; return IRB.CreateCall(MS.MsanChainOriginFn, V); @@ -1164,31 +1164,31 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { const DataLayout &DL = F.getParent()->getDataLayout(); const Align OriginAlignment = std::max(kMinOriginAlignment, Alignment); unsigned StoreSize = DL.getTypeStoreSize(Shadow->getType()); - Value *ConvertedShadow = convertShadowToScalar(Shadow, IRB); - if (auto *ConstantShadow = dyn_cast<Constant>(ConvertedShadow)) { - if (ClCheckConstantShadow && !ConstantShadow->isZeroValue()) - paintOrigin(IRB, updateOrigin(Origin, IRB), OriginPtr, StoreSize, + Value *ConvertedShadow = convertShadowToScalar(Shadow, IRB); + if (auto *ConstantShadow = dyn_cast<Constant>(ConvertedShadow)) { + if (ClCheckConstantShadow && !ConstantShadow->isZeroValue()) + paintOrigin(IRB, updateOrigin(Origin, IRB), OriginPtr, StoreSize, OriginAlignment); - return; + return; + } + + unsigned TypeSizeInBits = DL.getTypeSizeInBits(ConvertedShadow->getType()); + unsigned SizeIndex = TypeSizeToSizeIndex(TypeSizeInBits); + if (AsCall && SizeIndex < kNumberOfAccessSizes && !MS.CompileKernel) { + FunctionCallee Fn = MS.MaybeStoreOriginFn[SizeIndex]; + Value *ConvertedShadow2 = + IRB.CreateZExt(ConvertedShadow, IRB.getIntNTy(8 * (1 << SizeIndex))); + IRB.CreateCall(Fn, + {ConvertedShadow2, + IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()), Origin}); + } else { + Value *Cmp = convertToBool(ConvertedShadow, IRB, "_mscmp"); + Instruction *CheckTerm = SplitBlockAndInsertIfThen( + Cmp, &*IRB.GetInsertPoint(), false, MS.OriginStoreWeights); + IRBuilder<> IRBNew(CheckTerm); + paintOrigin(IRBNew, updateOrigin(Origin, IRBNew), OriginPtr, StoreSize, + OriginAlignment); } - - unsigned TypeSizeInBits = DL.getTypeSizeInBits(ConvertedShadow->getType()); - unsigned SizeIndex = TypeSizeToSizeIndex(TypeSizeInBits); - if (AsCall && SizeIndex < kNumberOfAccessSizes && !MS.CompileKernel) { - FunctionCallee Fn = MS.MaybeStoreOriginFn[SizeIndex]; - Value *ConvertedShadow2 = - IRB.CreateZExt(ConvertedShadow, IRB.getIntNTy(8 * (1 << SizeIndex))); - IRB.CreateCall(Fn, - {ConvertedShadow2, - IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()), Origin}); - } else { - Value *Cmp = convertToBool(ConvertedShadow, IRB, "_mscmp"); - Instruction *CheckTerm = SplitBlockAndInsertIfThen( - Cmp, &*IRB.GetInsertPoint(), false, MS.OriginStoreWeights); - IRBuilder<> IRBNew(CheckTerm); - paintOrigin(IRBNew, updateOrigin(Origin, IRBNew), OriginPtr, StoreSize, - OriginAlignment); - } } void materializeStores(bool InstrumentWithCalls) { @@ -1232,7 +1232,7 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { bool AsCall) { IRBuilder<> IRB(OrigIns); LLVM_DEBUG(dbgs() << " SHAD0 : " << *Shadow << "\n"); - Value *ConvertedShadow = convertShadowToScalar(Shadow, IRB); + Value *ConvertedShadow = convertShadowToScalar(Shadow, IRB); LLVM_DEBUG(dbgs() << " SHAD1 : " << *ConvertedShadow << "\n"); if (auto *ConstantShadow = dyn_cast<Constant>(ConvertedShadow)) { @@ -1254,7 +1254,7 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { ? Origin : (Value *)IRB.getInt32(0)}); } else { - Value *Cmp = convertToBool(ConvertedShadow, IRB, "_mscmp"); + Value *Cmp = convertToBool(ConvertedShadow, IRB, "_mscmp"); Instruction *CheckTerm = SplitBlockAndInsertIfThen( Cmp, OrigIns, /* Unreachable */ !MS.Recover, MS.ColdCallWeights); @@ -1275,8 +1275,8 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { LLVM_DEBUG(dbgs() << "DONE:\n" << F); } - // Returns the last instruction in the new prologue - void insertKmsanPrologue(IRBuilder<> &IRB) { + // Returns the last instruction in the new prologue + void insertKmsanPrologue(IRBuilder<> &IRB) { Value *ContextState = IRB.CreateCall(MS.MsanGetContextStateFn, {}); Constant *Zero = IRB.getInt32(0); MS.ParamTLS = IRB.CreateGEP(MS.MsanContextStateTy, ContextState, @@ -1302,7 +1302,7 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { // Iterate all BBs in depth-first order and create shadow instructions // for all instructions (where applicable). // For PHI nodes we create dummy shadow PHIs which will be finalized later. - for (BasicBlock *BB : depth_first(FnPrologueEnd->getParent())) + for (BasicBlock *BB : depth_first(FnPrologueEnd->getParent())) visit(*BB); // Finalize PHI nodes. @@ -1389,68 +1389,68 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { return ty; } - /// Extract combined shadow of struct elements as a bool - Value *collapseStructShadow(StructType *Struct, Value *Shadow, - IRBuilder<> &IRB) { - Value *FalseVal = IRB.getIntN(/* width */ 1, /* value */ 0); - Value *Aggregator = FalseVal; - - for (unsigned Idx = 0; Idx < Struct->getNumElements(); Idx++) { - // Combine by ORing together each element's bool shadow - Value *ShadowItem = IRB.CreateExtractValue(Shadow, Idx); - Value *ShadowInner = convertShadowToScalar(ShadowItem, IRB); - Value *ShadowBool = convertToBool(ShadowInner, IRB); - - if (Aggregator != FalseVal) - Aggregator = IRB.CreateOr(Aggregator, ShadowBool); - else - Aggregator = ShadowBool; - } - - return Aggregator; - } - - // Extract combined shadow of array elements - Value *collapseArrayShadow(ArrayType *Array, Value *Shadow, - IRBuilder<> &IRB) { - if (!Array->getNumElements()) - return IRB.getIntN(/* width */ 1, /* value */ 0); - - Value *FirstItem = IRB.CreateExtractValue(Shadow, 0); - Value *Aggregator = convertShadowToScalar(FirstItem, IRB); - - for (unsigned Idx = 1; Idx < Array->getNumElements(); Idx++) { - Value *ShadowItem = IRB.CreateExtractValue(Shadow, Idx); - Value *ShadowInner = convertShadowToScalar(ShadowItem, IRB); - Aggregator = IRB.CreateOr(Aggregator, ShadowInner); - } - return Aggregator; - } - - /// Convert a shadow value to it's flattened variant. The resulting - /// shadow may not necessarily have the same bit width as the input - /// value, but it will always be comparable to zero. - Value *convertShadowToScalar(Value *V, IRBuilder<> &IRB) { - if (StructType *Struct = dyn_cast<StructType>(V->getType())) - return collapseStructShadow(Struct, V, IRB); - if (ArrayType *Array = dyn_cast<ArrayType>(V->getType())) - return collapseArrayShadow(Array, V, IRB); + /// Extract combined shadow of struct elements as a bool + Value *collapseStructShadow(StructType *Struct, Value *Shadow, + IRBuilder<> &IRB) { + Value *FalseVal = IRB.getIntN(/* width */ 1, /* value */ 0); + Value *Aggregator = FalseVal; + + for (unsigned Idx = 0; Idx < Struct->getNumElements(); Idx++) { + // Combine by ORing together each element's bool shadow + Value *ShadowItem = IRB.CreateExtractValue(Shadow, Idx); + Value *ShadowInner = convertShadowToScalar(ShadowItem, IRB); + Value *ShadowBool = convertToBool(ShadowInner, IRB); + + if (Aggregator != FalseVal) + Aggregator = IRB.CreateOr(Aggregator, ShadowBool); + else + Aggregator = ShadowBool; + } + + return Aggregator; + } + + // Extract combined shadow of array elements + Value *collapseArrayShadow(ArrayType *Array, Value *Shadow, + IRBuilder<> &IRB) { + if (!Array->getNumElements()) + return IRB.getIntN(/* width */ 1, /* value */ 0); + + Value *FirstItem = IRB.CreateExtractValue(Shadow, 0); + Value *Aggregator = convertShadowToScalar(FirstItem, IRB); + + for (unsigned Idx = 1; Idx < Array->getNumElements(); Idx++) { + Value *ShadowItem = IRB.CreateExtractValue(Shadow, Idx); + Value *ShadowInner = convertShadowToScalar(ShadowItem, IRB); + Aggregator = IRB.CreateOr(Aggregator, ShadowInner); + } + return Aggregator; + } + + /// Convert a shadow value to it's flattened variant. The resulting + /// shadow may not necessarily have the same bit width as the input + /// value, but it will always be comparable to zero. + Value *convertShadowToScalar(Value *V, IRBuilder<> &IRB) { + if (StructType *Struct = dyn_cast<StructType>(V->getType())) + return collapseStructShadow(Struct, V, IRB); + if (ArrayType *Array = dyn_cast<ArrayType>(V->getType())) + return collapseArrayShadow(Array, V, IRB); Type *Ty = V->getType(); Type *NoVecTy = getShadowTyNoVec(Ty); if (Ty == NoVecTy) return V; return IRB.CreateBitCast(V, NoVecTy); } - // Convert a scalar value to an i1 by comparing with 0 - Value *convertToBool(Value *V, IRBuilder<> &IRB, const Twine &name = "") { - Type *VTy = V->getType(); - assert(VTy->isIntegerTy()); - if (VTy->getIntegerBitWidth() == 1) - // Just converting a bool to a bool, so do nothing. - return V; - return IRB.CreateICmpNE(V, ConstantInt::get(VTy, 0), name); - } - + // Convert a scalar value to an i1 by comparing with 0 + Value *convertToBool(Value *V, IRBuilder<> &IRB, const Twine &name = "") { + Type *VTy = V->getType(); + assert(VTy->isIntegerTy()); + if (VTy->getIntegerBitWidth() == 1) + // Just converting a bool to a bool, so do nothing. + return V; + return IRB.CreateICmpNE(V, ConstantInt::get(VTy, 0), name); + } + /// Compute the integer shadow offset that corresponds to a given /// application address. /// @@ -1669,7 +1669,7 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { if (*ShadowPtr) return *ShadowPtr; Function *F = A->getParent(); - IRBuilder<> EntryIRB(FnPrologueEnd); + IRBuilder<> EntryIRB(FnPrologueEnd); unsigned ArgOffset = 0; const DataLayout &DL = F->getParent()->getDataLayout(); for (auto &FArg : F->args()) { @@ -1737,8 +1737,8 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { } else { setOrigin(A, getCleanOrigin()); } - - break; + + break; } if (!FArgEagerCheck) @@ -1786,10 +1786,10 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { if (!InsertChecks) return; #ifndef NDEBUG Type *ShadowTy = Shadow->getType(); - assert((isa<IntegerType>(ShadowTy) || isa<VectorType>(ShadowTy) || - isa<StructType>(ShadowTy) || isa<ArrayType>(ShadowTy)) && - "Can only insert checks for integer, vector, and aggregate shadow " - "types"); + assert((isa<IntegerType>(ShadowTy) || isa<VectorType>(ShadowTy) || + isa<StructType>(ShadowTy) || isa<ArrayType>(ShadowTy)) && + "Can only insert checks for integer, vector, and aggregate shadow " + "types"); #endif InstrumentationList.push_back( ShadowOriginAndInsertPoint(Shadow, Origin, OrigIns)); @@ -1831,24 +1831,24 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { llvm_unreachable("Unknown ordering"); } - Value *makeAddReleaseOrderingTable(IRBuilder<> &IRB) { - constexpr int NumOrderings = (int)AtomicOrderingCABI::seq_cst + 1; - uint32_t OrderingTable[NumOrderings] = {}; - - OrderingTable[(int)AtomicOrderingCABI::relaxed] = - OrderingTable[(int)AtomicOrderingCABI::release] = - (int)AtomicOrderingCABI::release; - OrderingTable[(int)AtomicOrderingCABI::consume] = - OrderingTable[(int)AtomicOrderingCABI::acquire] = - OrderingTable[(int)AtomicOrderingCABI::acq_rel] = - (int)AtomicOrderingCABI::acq_rel; - OrderingTable[(int)AtomicOrderingCABI::seq_cst] = - (int)AtomicOrderingCABI::seq_cst; - - return ConstantDataVector::get(IRB.getContext(), - makeArrayRef(OrderingTable, NumOrderings)); - } - + Value *makeAddReleaseOrderingTable(IRBuilder<> &IRB) { + constexpr int NumOrderings = (int)AtomicOrderingCABI::seq_cst + 1; + uint32_t OrderingTable[NumOrderings] = {}; + + OrderingTable[(int)AtomicOrderingCABI::relaxed] = + OrderingTable[(int)AtomicOrderingCABI::release] = + (int)AtomicOrderingCABI::release; + OrderingTable[(int)AtomicOrderingCABI::consume] = + OrderingTable[(int)AtomicOrderingCABI::acquire] = + OrderingTable[(int)AtomicOrderingCABI::acq_rel] = + (int)AtomicOrderingCABI::acq_rel; + OrderingTable[(int)AtomicOrderingCABI::seq_cst] = + (int)AtomicOrderingCABI::seq_cst; + + return ConstantDataVector::get(IRB.getContext(), + makeArrayRef(OrderingTable, NumOrderings)); + } + AtomicOrdering addAcquireOrdering(AtomicOrdering a) { switch (a) { case AtomicOrdering::NotAtomic: @@ -1866,33 +1866,33 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { llvm_unreachable("Unknown ordering"); } - Value *makeAddAcquireOrderingTable(IRBuilder<> &IRB) { - constexpr int NumOrderings = (int)AtomicOrderingCABI::seq_cst + 1; - uint32_t OrderingTable[NumOrderings] = {}; - - OrderingTable[(int)AtomicOrderingCABI::relaxed] = - OrderingTable[(int)AtomicOrderingCABI::acquire] = - OrderingTable[(int)AtomicOrderingCABI::consume] = - (int)AtomicOrderingCABI::acquire; - OrderingTable[(int)AtomicOrderingCABI::release] = - OrderingTable[(int)AtomicOrderingCABI::acq_rel] = - (int)AtomicOrderingCABI::acq_rel; - OrderingTable[(int)AtomicOrderingCABI::seq_cst] = - (int)AtomicOrderingCABI::seq_cst; - - return ConstantDataVector::get(IRB.getContext(), - makeArrayRef(OrderingTable, NumOrderings)); - } - + Value *makeAddAcquireOrderingTable(IRBuilder<> &IRB) { + constexpr int NumOrderings = (int)AtomicOrderingCABI::seq_cst + 1; + uint32_t OrderingTable[NumOrderings] = {}; + + OrderingTable[(int)AtomicOrderingCABI::relaxed] = + OrderingTable[(int)AtomicOrderingCABI::acquire] = + OrderingTable[(int)AtomicOrderingCABI::consume] = + (int)AtomicOrderingCABI::acquire; + OrderingTable[(int)AtomicOrderingCABI::release] = + OrderingTable[(int)AtomicOrderingCABI::acq_rel] = + (int)AtomicOrderingCABI::acq_rel; + OrderingTable[(int)AtomicOrderingCABI::seq_cst] = + (int)AtomicOrderingCABI::seq_cst; + + return ConstantDataVector::get(IRB.getContext(), + makeArrayRef(OrderingTable, NumOrderings)); + } + // ------------------- Visitors. using InstVisitor<MemorySanitizerVisitor>::visit; void visit(Instruction &I) { - if (I.getMetadata("nosanitize")) - return; - // Don't want to visit if we're in the prologue - if (isInPrologue(I)) - return; - InstVisitor<MemorySanitizerVisitor>::visit(I); + if (I.getMetadata("nosanitize")) + return; + // Don't want to visit if we're in the prologue + if (isInPrologue(I)) + return; + InstVisitor<MemorySanitizerVisitor>::visit(I); } /// Instrument LoadInst @@ -2148,7 +2148,7 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { Constant *ConstOrigin = dyn_cast<Constant>(OpOrigin); // No point in adding something that might result in 0 origin value. if (!ConstOrigin || !ConstOrigin->isNullValue()) { - Value *FlatShadow = MSV->convertShadowToScalar(OpShadow, IRB); + Value *FlatShadow = MSV->convertShadowToScalar(OpShadow, IRB); Value *Cond = IRB.CreateICmpNE(FlatShadow, MSV->getCleanShadow(FlatShadow)); Origin = IRB.CreateSelect(Cond, OpOrigin, Origin); @@ -2703,7 +2703,7 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { void handleLifetimeStart(IntrinsicInst &I) { if (!PoisonStack) return; - AllocaInst *AI = llvm::findAllocaForValue(I.getArgOperand(1)); + AllocaInst *AI = llvm::findAllocaForValue(I.getArgOperand(1)); if (!AI) InstrumentLifetimeStart = false; LifetimeStartList.push_back(std::make_pair(&I, AI)); @@ -2734,16 +2734,16 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { // We copy the shadow of \p CopyOp[NumUsedElements:] to \p // Out[NumUsedElements:]. This means that intrinsics without \p CopyOp always // return a fully initialized value. - void handleVectorConvertIntrinsic(IntrinsicInst &I, int NumUsedElements, - bool HasRoundingMode = false) { + void handleVectorConvertIntrinsic(IntrinsicInst &I, int NumUsedElements, + bool HasRoundingMode = false) { IRBuilder<> IRB(&I); Value *CopyOp, *ConvertOp; - assert((!HasRoundingMode || - isa<ConstantInt>(I.getArgOperand(I.getNumArgOperands() - 1))) && - "Invalid rounding mode"); - - switch (I.getNumArgOperands() - HasRoundingMode) { + assert((!HasRoundingMode || + isa<ConstantInt>(I.getArgOperand(I.getNumArgOperands() - 1))) && + "Invalid rounding mode"); + + switch (I.getNumArgOperands() - HasRoundingMode) { case 2: CopyOp = I.getArgOperand(0); ConvertOp = I.getArgOperand(1); @@ -2999,7 +2999,7 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { setOrigin(&I, getOrigin(&I, 0)); } - // Instrument vector.reduce.or intrinsic. + // Instrument vector.reduce.or intrinsic. // Valid (non-poisoned) set bits in the operand pull low the // corresponding shadow bits. void handleVectorReduceOrIntrinsic(IntrinsicInst &I) { @@ -3017,7 +3017,7 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { setOrigin(&I, getOrigin(&I, 0)); } - // Instrument vector.reduce.and intrinsic. + // Instrument vector.reduce.and intrinsic. // Valid (non-poisoned) unset bits in the operand pull down the // corresponding shadow bits. void handleVectorReduceAndIntrinsic(IntrinsicInst &I) { @@ -3195,10 +3195,10 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { assert(isa<ConstantInt>(I.getArgOperand(2)) && "pclmul 3rd operand must be a constant"); unsigned Imm = cast<ConstantInt>(I.getArgOperand(2))->getZExtValue(); - Value *Shuf0 = IRB.CreateShuffleVector(getShadow(&I, 0), - getPclmulMask(Width, Imm & 0x01)); - Value *Shuf1 = IRB.CreateShuffleVector(getShadow(&I, 1), - getPclmulMask(Width, Imm & 0x10)); + Value *Shuf0 = IRB.CreateShuffleVector(getShadow(&I, 0), + getPclmulMask(Width, Imm & 0x01)); + Value *Shuf1 = IRB.CreateShuffleVector(getShadow(&I, 1), + getPclmulMask(Width, Imm & 0x10)); ShadowAndOriginCombiner SOC(this, IRB); SOC.Add(Shuf0, getOrigin(&I, 0)); SOC.Add(Shuf1, getOrigin(&I, 1)); @@ -3231,24 +3231,24 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { setOriginForNaryOp(I); } - // Instrument abs intrinsic. - // handleUnknownIntrinsic can't handle it because of the last - // is_int_min_poison argument which does not match the result type. - void handleAbsIntrinsic(IntrinsicInst &I) { - assert(I.getType()->isIntOrIntVectorTy()); - assert(I.getArgOperand(0)->getType() == I.getType()); - - // FIXME: Handle is_int_min_poison. - IRBuilder<> IRB(&I); - setShadow(&I, getShadow(&I, 0)); - setOrigin(&I, getOrigin(&I, 0)); - } - + // Instrument abs intrinsic. + // handleUnknownIntrinsic can't handle it because of the last + // is_int_min_poison argument which does not match the result type. + void handleAbsIntrinsic(IntrinsicInst &I) { + assert(I.getType()->isIntOrIntVectorTy()); + assert(I.getArgOperand(0)->getType() == I.getType()); + + // FIXME: Handle is_int_min_poison. + IRBuilder<> IRB(&I); + setShadow(&I, getShadow(&I, 0)); + setOrigin(&I, getOrigin(&I, 0)); + } + void visitIntrinsicInst(IntrinsicInst &I) { switch (I.getIntrinsicID()) { - case Intrinsic::abs: - handleAbsIntrinsic(I); - break; + case Intrinsic::abs: + handleAbsIntrinsic(I); + break; case Intrinsic::lifetime_start: handleLifetimeStart(I); break; @@ -3265,15 +3265,15 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { case Intrinsic::masked_load: handleMaskedLoad(I); break; - case Intrinsic::vector_reduce_and: + case Intrinsic::vector_reduce_and: handleVectorReduceAndIntrinsic(I); break; - case Intrinsic::vector_reduce_or: + case Intrinsic::vector_reduce_or: handleVectorReduceOrIntrinsic(I); break; - case Intrinsic::vector_reduce_add: - case Intrinsic::vector_reduce_xor: - case Intrinsic::vector_reduce_mul: + case Intrinsic::vector_reduce_add: + case Intrinsic::vector_reduce_xor: + case Intrinsic::vector_reduce_mul: handleVectorReduceIntrinsic(I); break; case Intrinsic::x86_sse_stmxcsr: @@ -3293,8 +3293,8 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { case Intrinsic::x86_avx512_cvtusi2ss: case Intrinsic::x86_avx512_cvtusi642sd: case Intrinsic::x86_avx512_cvtusi642ss: - handleVectorConvertIntrinsic(I, 1, true); - break; + handleVectorConvertIntrinsic(I, 1, true); + break; case Intrinsic::x86_sse2_cvtsd2si64: case Intrinsic::x86_sse2_cvtsd2si: case Intrinsic::x86_sse2_cvtsd2ss: @@ -3520,63 +3520,63 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { } } - void visitLibAtomicLoad(CallBase &CB) { - // Since we use getNextNode here, we can't have CB terminate the BB. - assert(isa<CallInst>(CB)); - - IRBuilder<> IRB(&CB); - Value *Size = CB.getArgOperand(0); - Value *SrcPtr = CB.getArgOperand(1); - Value *DstPtr = CB.getArgOperand(2); - Value *Ordering = CB.getArgOperand(3); - // Convert the call to have at least Acquire ordering to make sure - // the shadow operations aren't reordered before it. - Value *NewOrdering = - IRB.CreateExtractElement(makeAddAcquireOrderingTable(IRB), Ordering); - CB.setArgOperand(3, NewOrdering); - - IRBuilder<> NextIRB(CB.getNextNode()); - NextIRB.SetCurrentDebugLocation(CB.getDebugLoc()); - - Value *SrcShadowPtr, *SrcOriginPtr; - std::tie(SrcShadowPtr, SrcOriginPtr) = - getShadowOriginPtr(SrcPtr, NextIRB, NextIRB.getInt8Ty(), Align(1), - /*isStore*/ false); - Value *DstShadowPtr = - getShadowOriginPtr(DstPtr, NextIRB, NextIRB.getInt8Ty(), Align(1), - /*isStore*/ true) - .first; - - NextIRB.CreateMemCpy(DstShadowPtr, Align(1), SrcShadowPtr, Align(1), Size); - if (MS.TrackOrigins) { - Value *SrcOrigin = NextIRB.CreateAlignedLoad(MS.OriginTy, SrcOriginPtr, - kMinOriginAlignment); - Value *NewOrigin = updateOrigin(SrcOrigin, NextIRB); - NextIRB.CreateCall(MS.MsanSetOriginFn, {DstPtr, Size, NewOrigin}); - } - } - - void visitLibAtomicStore(CallBase &CB) { - IRBuilder<> IRB(&CB); - Value *Size = CB.getArgOperand(0); - Value *DstPtr = CB.getArgOperand(2); - Value *Ordering = CB.getArgOperand(3); - // Convert the call to have at least Release ordering to make sure - // the shadow operations aren't reordered after it. - Value *NewOrdering = - IRB.CreateExtractElement(makeAddReleaseOrderingTable(IRB), Ordering); - CB.setArgOperand(3, NewOrdering); - - Value *DstShadowPtr = - getShadowOriginPtr(DstPtr, IRB, IRB.getInt8Ty(), Align(1), - /*isStore*/ true) - .first; - - // Atomic store always paints clean shadow/origin. See file header. - IRB.CreateMemSet(DstShadowPtr, getCleanShadow(IRB.getInt8Ty()), Size, - Align(1)); - } - + void visitLibAtomicLoad(CallBase &CB) { + // Since we use getNextNode here, we can't have CB terminate the BB. + assert(isa<CallInst>(CB)); + + IRBuilder<> IRB(&CB); + Value *Size = CB.getArgOperand(0); + Value *SrcPtr = CB.getArgOperand(1); + Value *DstPtr = CB.getArgOperand(2); + Value *Ordering = CB.getArgOperand(3); + // Convert the call to have at least Acquire ordering to make sure + // the shadow operations aren't reordered before it. + Value *NewOrdering = + IRB.CreateExtractElement(makeAddAcquireOrderingTable(IRB), Ordering); + CB.setArgOperand(3, NewOrdering); + + IRBuilder<> NextIRB(CB.getNextNode()); + NextIRB.SetCurrentDebugLocation(CB.getDebugLoc()); + + Value *SrcShadowPtr, *SrcOriginPtr; + std::tie(SrcShadowPtr, SrcOriginPtr) = + getShadowOriginPtr(SrcPtr, NextIRB, NextIRB.getInt8Ty(), Align(1), + /*isStore*/ false); + Value *DstShadowPtr = + getShadowOriginPtr(DstPtr, NextIRB, NextIRB.getInt8Ty(), Align(1), + /*isStore*/ true) + .first; + + NextIRB.CreateMemCpy(DstShadowPtr, Align(1), SrcShadowPtr, Align(1), Size); + if (MS.TrackOrigins) { + Value *SrcOrigin = NextIRB.CreateAlignedLoad(MS.OriginTy, SrcOriginPtr, + kMinOriginAlignment); + Value *NewOrigin = updateOrigin(SrcOrigin, NextIRB); + NextIRB.CreateCall(MS.MsanSetOriginFn, {DstPtr, Size, NewOrigin}); + } + } + + void visitLibAtomicStore(CallBase &CB) { + IRBuilder<> IRB(&CB); + Value *Size = CB.getArgOperand(0); + Value *DstPtr = CB.getArgOperand(2); + Value *Ordering = CB.getArgOperand(3); + // Convert the call to have at least Release ordering to make sure + // the shadow operations aren't reordered after it. + Value *NewOrdering = + IRB.CreateExtractElement(makeAddReleaseOrderingTable(IRB), Ordering); + CB.setArgOperand(3, NewOrdering); + + Value *DstShadowPtr = + getShadowOriginPtr(DstPtr, IRB, IRB.getInt8Ty(), Align(1), + /*isStore*/ true) + .first; + + // Atomic store always paints clean shadow/origin. See file header. + IRB.CreateMemSet(DstShadowPtr, getCleanShadow(IRB.getInt8Ty()), Size, + Align(1)); + } + void visitCallBase(CallBase &CB) { assert(!CB.getMetadata("nosanitize")); if (CB.isInlineAsm()) { @@ -3590,28 +3590,28 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { visitInstruction(CB); return; } - LibFunc LF; - if (TLI->getLibFunc(CB, LF)) { - // libatomic.a functions need to have special handling because there isn't - // a good way to intercept them or compile the library with - // instrumentation. - switch (LF) { - case LibFunc_atomic_load: - if (!isa<CallInst>(CB)) { - llvm::errs() << "MSAN -- cannot instrument invoke of libatomic load." - "Ignoring!\n"; - break; - } - visitLibAtomicLoad(CB); - return; - case LibFunc_atomic_store: - visitLibAtomicStore(CB); - return; - default: - break; - } - } - + LibFunc LF; + if (TLI->getLibFunc(CB, LF)) { + // libatomic.a functions need to have special handling because there isn't + // a good way to intercept them or compile the library with + // instrumentation. + switch (LF) { + case LibFunc_atomic_load: + if (!isa<CallInst>(CB)) { + llvm::errs() << "MSAN -- cannot instrument invoke of libatomic load." + "Ignoring!\n"; + break; + } + visitLibAtomicLoad(CB); + return; + case LibFunc_atomic_store: + visitLibAtomicStore(CB); + return; + default: + break; + } + } + if (auto *Call = dyn_cast<CallInst>(&CB)) { assert(!isa<IntrinsicInst>(Call) && "intrinsics are handled elsewhere"); @@ -3619,14 +3619,14 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { // will become a non-readonly function after it is instrumented by us. To // prevent this code from being optimized out, mark that function // non-readonly in advance. - AttrBuilder B; - B.addAttribute(Attribute::ReadOnly) - .addAttribute(Attribute::ReadNone) - .addAttribute(Attribute::WriteOnly) - .addAttribute(Attribute::ArgMemOnly) - .addAttribute(Attribute::Speculatable); - - Call->removeAttributes(AttributeList::FunctionIndex, B); + AttrBuilder B; + B.addAttribute(Attribute::ReadOnly) + .addAttribute(Attribute::ReadNone) + .addAttribute(Attribute::WriteOnly) + .addAttribute(Attribute::ArgMemOnly) + .addAttribute(Attribute::Speculatable); + + Call->removeAttributes(AttributeList::FunctionIndex, B); if (Function *Func = Call->getCalledFunction()) { Func->removeAttributes(AttributeList::FunctionIndex, B); } @@ -3634,12 +3634,12 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { maybeMarkSanitizerLibraryCallNoBuiltin(Call, TLI); } IRBuilder<> IRB(&CB); - bool MayCheckCall = ClEagerChecks; - if (Function *Func = CB.getCalledFunction()) { - // __sanitizer_unaligned_{load,store} functions may be called by users - // and always expects shadows in the TLS. So don't check them. - MayCheckCall &= !Func->getName().startswith("__sanitizer_unaligned_"); - } + bool MayCheckCall = ClEagerChecks; + if (Function *Func = CB.getCalledFunction()) { + // __sanitizer_unaligned_{load,store} functions may be called by users + // and always expects shadows in the TLS. So don't check them. + MayCheckCall &= !Func->getName().startswith("__sanitizer_unaligned_"); + } unsigned ArgOffset = 0; LLVM_DEBUG(dbgs() << " CallSite: " << CB << "\n"); @@ -3665,7 +3665,7 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { bool ByVal = CB.paramHasAttr(i, Attribute::ByVal); bool NoUndef = CB.paramHasAttr(i, Attribute::NoUndef); - bool EagerCheck = MayCheckCall && !ByVal && NoUndef; + bool EagerCheck = MayCheckCall && !ByVal && NoUndef; if (EagerCheck) { insertShadowCheck(A, &CB); @@ -3705,7 +3705,7 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { (void)Store; assert(Size != 0 && Store != nullptr); LLVM_DEBUG(dbgs() << " Param:" << *Store << "\n"); - ArgOffset += alignTo(Size, kShadowTLSAlignment); + ArgOffset += alignTo(Size, kShadowTLSAlignment); } LLVM_DEBUG(dbgs() << " done with call args\n"); @@ -3721,7 +3721,7 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { if (isa<CallInst>(CB) && cast<CallInst>(CB).isMustTailCall()) return; - if (MayCheckCall && CB.hasRetAttr(Attribute::NoUndef)) { + if (MayCheckCall && CB.hasRetAttr(Attribute::NoUndef)) { setShadow(&CB, getCleanShadow(&CB)); setOrigin(&CB, getCleanOrigin()); return; @@ -4104,12 +4104,12 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { setOrigin(&I, getCleanOrigin()); } - void visitFreezeInst(FreezeInst &I) { - // Freeze always returns a fully defined value. - setShadow(&I, getCleanShadow(&I)); - setOrigin(&I, getCleanOrigin()); - } - + void visitFreezeInst(FreezeInst &I) { + // Freeze always returns a fully defined value. + setShadow(&I, getCleanShadow(&I)); + setOrigin(&I, getCleanOrigin()); + } + void visitInstruction(Instruction &I) { // Everything else: stop propagating and check for poisoned shadow. if (ClDumpStrictInstructions) @@ -4333,7 +4333,7 @@ struct VarArgAMD64Helper : public VarArgHelper { if (!VAStartInstrumentationList.empty()) { // If there is a va_start in this function, make a backup copy of // va_arg_tls somewhere in the function entry block. - IRBuilder<> IRB(MSV.FnPrologueEnd); + IRBuilder<> IRB(MSV.FnPrologueEnd); VAArgOverflowSize = IRB.CreateLoad(IRB.getInt64Ty(), MS.VAArgOverflowSizeTLS); Value *CopySize = @@ -4479,7 +4479,7 @@ struct VarArgMIPS64Helper : public VarArgHelper { void finalizeInstrumentation() override { assert(!VAArgSize && !VAArgTLSCopy && "finalizeInstrumentation called twice"); - IRBuilder<> IRB(MSV.FnPrologueEnd); + IRBuilder<> IRB(MSV.FnPrologueEnd); VAArgSize = IRB.CreateLoad(IRB.getInt64Ty(), MS.VAArgOverflowSizeTLS); Value *CopySize = IRB.CreateAdd(ConstantInt::get(MS.IntptrTy, 0), VAArgSize); @@ -4672,7 +4672,7 @@ struct VarArgAArch64Helper : public VarArgHelper { if (!VAStartInstrumentationList.empty()) { // If there is a va_start in this function, make a backup copy of // va_arg_tls somewhere in the function entry block. - IRBuilder<> IRB(MSV.FnPrologueEnd); + IRBuilder<> IRB(MSV.FnPrologueEnd); VAArgOverflowSize = IRB.CreateLoad(IRB.getInt64Ty(), MS.VAArgOverflowSizeTLS); Value *CopySize = @@ -4792,9 +4792,9 @@ struct VarArgPowerPC64Helper : public VarArgHelper { // For PowerPC, we need to deal with alignment of stack arguments - // they are mostly aligned to 8 bytes, but vectors and i128 arrays // are aligned to 16 bytes, byvals can be aligned to 8 or 16 bytes, - // For that reason, we compute current offset from stack pointer (which is - // always properly aligned), and offset for the first vararg, then subtract - // them. + // For that reason, we compute current offset from stack pointer (which is + // always properly aligned), and offset for the first vararg, then subtract + // them. unsigned VAArgBase; Triple TargetTriple(F.getParent()->getTargetTriple()); // Parameter save area starts at 48 bytes from frame pointer for ABIv1, @@ -4917,7 +4917,7 @@ struct VarArgPowerPC64Helper : public VarArgHelper { void finalizeInstrumentation() override { assert(!VAArgSize && !VAArgTLSCopy && "finalizeInstrumentation called twice"); - IRBuilder<> IRB(MSV.FnPrologueEnd); + IRBuilder<> IRB(MSV.FnPrologueEnd); VAArgSize = IRB.CreateLoad(IRB.getInt64Ty(), MS.VAArgOverflowSizeTLS); Value *CopySize = IRB.CreateAdd(ConstantInt::get(MS.IntptrTy, 0), VAArgSize); @@ -5236,7 +5236,7 @@ struct VarArgSystemZHelper : public VarArgHelper { if (!VAStartInstrumentationList.empty()) { // If there is a va_start in this function, make a backup copy of // va_arg_tls somewhere in the function entry block. - IRBuilder<> IRB(MSV.FnPrologueEnd); + IRBuilder<> IRB(MSV.FnPrologueEnd); VAArgOverflowSize = IRB.CreateLoad(IRB.getInt64Ty(), MS.VAArgOverflowSizeTLS); Value *CopySize = diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/PGOInstrumentation.cpp b/contrib/libs/llvm12/lib/Transforms/Instrumentation/PGOInstrumentation.cpp index 763fe7c656..be6c8c6310 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/PGOInstrumentation.cpp +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/PGOInstrumentation.cpp @@ -248,38 +248,38 @@ static cl::opt<bool> "optimization remarks: -{Rpass|" "pass-remarks}=pgo-instrumentation")); -static cl::opt<bool> PGOInstrumentEntry( - "pgo-instrument-entry", cl::init(false), cl::Hidden, - cl::desc("Force to instrument function entry basicblock.")); - -static cl::opt<bool> - PGOFixEntryCount("pgo-fix-entry-count", cl::init(true), cl::Hidden, - cl::desc("Fix function entry count in profile use.")); - -static cl::opt<bool> PGOVerifyHotBFI( - "pgo-verify-hot-bfi", cl::init(false), cl::Hidden, - cl::desc("Print out the non-match BFI count if a hot raw profile count " - "becomes non-hot, or a cold raw profile count becomes hot. " - "The print is enabled under -Rpass-analysis=pgo, or " - "internal option -pass-remakrs-analysis=pgo.")); - -static cl::opt<bool> PGOVerifyBFI( - "pgo-verify-bfi", cl::init(false), cl::Hidden, - cl::desc("Print out mismatched BFI counts after setting profile metadata " - "The print is enabled under -Rpass-analysis=pgo, or " - "internal option -pass-remakrs-analysis=pgo.")); - -static cl::opt<unsigned> PGOVerifyBFIRatio( - "pgo-verify-bfi-ratio", cl::init(5), cl::Hidden, - cl::desc("Set the threshold for pgo-verify-big -- only print out " - "mismatched BFI if the difference percentage is greater than " - "this value (in percentage).")); - -static cl::opt<unsigned> PGOVerifyBFICutoff( - "pgo-verify-bfi-cutoff", cl::init(1), cl::Hidden, - cl::desc("Set the threshold for pgo-verify-bfi -- skip the counts whose " - "profile count value is below.")); - +static cl::opt<bool> PGOInstrumentEntry( + "pgo-instrument-entry", cl::init(false), cl::Hidden, + cl::desc("Force to instrument function entry basicblock.")); + +static cl::opt<bool> + PGOFixEntryCount("pgo-fix-entry-count", cl::init(true), cl::Hidden, + cl::desc("Fix function entry count in profile use.")); + +static cl::opt<bool> PGOVerifyHotBFI( + "pgo-verify-hot-bfi", cl::init(false), cl::Hidden, + cl::desc("Print out the non-match BFI count if a hot raw profile count " + "becomes non-hot, or a cold raw profile count becomes hot. " + "The print is enabled under -Rpass-analysis=pgo, or " + "internal option -pass-remakrs-analysis=pgo.")); + +static cl::opt<bool> PGOVerifyBFI( + "pgo-verify-bfi", cl::init(false), cl::Hidden, + cl::desc("Print out mismatched BFI counts after setting profile metadata " + "The print is enabled under -Rpass-analysis=pgo, or " + "internal option -pass-remakrs-analysis=pgo.")); + +static cl::opt<unsigned> PGOVerifyBFIRatio( + "pgo-verify-bfi-ratio", cl::init(5), cl::Hidden, + cl::desc("Set the threshold for pgo-verify-big -- only print out " + "mismatched BFI if the difference percentage is greater than " + "this value (in percentage).")); + +static cl::opt<unsigned> PGOVerifyBFICutoff( + "pgo-verify-bfi-cutoff", cl::init(1), cl::Hidden, + cl::desc("Set the threshold for pgo-verify-bfi -- skip the counts whose " + "profile count value is below.")); + // Command line option to turn on CFG dot dump after profile annotation. // Defined in Analysis/BlockFrequencyInfo.cpp: -pgo-view-counts extern cl::opt<PGOViewCountsType> PGOViewCounts; @@ -288,10 +288,10 @@ extern cl::opt<PGOViewCountsType> PGOViewCounts; // Defined in Analysis/BlockFrequencyInfo.cpp: -view-bfi-func-name= extern cl::opt<std::string> ViewBlockFreqFuncName; -static cl::opt<bool> - PGOOldCFGHashing("pgo-instr-old-cfg-hashing", cl::init(false), cl::Hidden, - cl::desc("Use the old CFG function hashing")); - +static cl::opt<bool> + PGOOldCFGHashing("pgo-instr-old-cfg-hashing", cl::init(false), cl::Hidden, + cl::desc("Use the old CFG function hashing")); + // Return a string describing the branch condition that can be // used in static branch probability heuristics: static std::string getBranchCondString(Instruction *TI) { @@ -460,7 +460,7 @@ public: private: bool runOnModule(Module &M) override { createProfileFileNameVar(M, InstrProfileOutput); - createIRLevelProfileFlagVar(M, /* IsCS */ true, PGOInstrumentEntry); + createIRLevelProfileFlagVar(M, /* IsCS */ true, PGOInstrumentEntry); return false; } std::string InstrProfileOutput; @@ -607,11 +607,11 @@ public: Function &Func, TargetLibraryInfo &TLI, std::unordered_multimap<Comdat *, GlobalValue *> &ComdatMembers, bool CreateGlobalVar = false, BranchProbabilityInfo *BPI = nullptr, - BlockFrequencyInfo *BFI = nullptr, bool IsCS = false, - bool InstrumentFuncEntry = true) + BlockFrequencyInfo *BFI = nullptr, bool IsCS = false, + bool InstrumentFuncEntry = true) : F(Func), IsCS(IsCS), ComdatMembers(ComdatMembers), VPC(Func, TLI), - ValueSites(IPVK_Last + 1), SIVisitor(Func), - MST(F, InstrumentFuncEntry, BPI, BFI) { + ValueSites(IPVK_Last + 1), SIVisitor(Func), + MST(F, InstrumentFuncEntry, BPI, BFI) { // This should be done before CFG hash computation. SIVisitor.countSelects(Func); ValueSites[IPVK_MemOPSize] = VPC.get(IPVK_MemOPSize); @@ -648,8 +648,8 @@ public: } // end anonymous namespace // Compute Hash value for the CFG: the lower 32 bits are CRC32 of the index -// value of each BB in the CFG. The higher 32 bits are the CRC32 of the numbers -// of selects, indirect calls, mem ops and edges. +// value of each BB in the CFG. The higher 32 bits are the CRC32 of the numbers +// of selects, indirect calls, mem ops and edges. template <class Edge, class BBInfo> void FuncPGOInstrumentation<Edge, BBInfo>::computeCFGHash() { std::vector<uint8_t> Indexes; @@ -668,31 +668,31 @@ void FuncPGOInstrumentation<Edge, BBInfo>::computeCFGHash() { } JC.update(Indexes); - JamCRC JCH; - if (PGOOldCFGHashing) { - // Hash format for context sensitive profile. Reserve 4 bits for other - // information. - FunctionHash = (uint64_t)SIVisitor.getNumOfSelectInsts() << 56 | - (uint64_t)ValueSites[IPVK_IndirectCallTarget].size() << 48 | - //(uint64_t)ValueSites[IPVK_MemOPSize].size() << 40 | - (uint64_t)MST.AllEdges.size() << 32 | JC.getCRC(); - } else { - // The higher 32 bits. - auto updateJCH = [&JCH](uint64_t Num) { - uint8_t Data[8]; - support::endian::write64le(Data, Num); - JCH.update(Data); - }; - updateJCH((uint64_t)SIVisitor.getNumOfSelectInsts()); - updateJCH((uint64_t)ValueSites[IPVK_IndirectCallTarget].size()); - updateJCH((uint64_t)ValueSites[IPVK_MemOPSize].size()); - updateJCH((uint64_t)MST.AllEdges.size()); - - // Hash format for context sensitive profile. Reserve 4 bits for other - // information. - FunctionHash = (((uint64_t)JCH.getCRC()) << 28) + JC.getCRC(); - } - + JamCRC JCH; + if (PGOOldCFGHashing) { + // Hash format for context sensitive profile. Reserve 4 bits for other + // information. + FunctionHash = (uint64_t)SIVisitor.getNumOfSelectInsts() << 56 | + (uint64_t)ValueSites[IPVK_IndirectCallTarget].size() << 48 | + //(uint64_t)ValueSites[IPVK_MemOPSize].size() << 40 | + (uint64_t)MST.AllEdges.size() << 32 | JC.getCRC(); + } else { + // The higher 32 bits. + auto updateJCH = [&JCH](uint64_t Num) { + uint8_t Data[8]; + support::endian::write64le(Data, Num); + JCH.update(Data); + }; + updateJCH((uint64_t)SIVisitor.getNumOfSelectInsts()); + updateJCH((uint64_t)ValueSites[IPVK_IndirectCallTarget].size()); + updateJCH((uint64_t)ValueSites[IPVK_MemOPSize].size()); + updateJCH((uint64_t)MST.AllEdges.size()); + + // Hash format for context sensitive profile. Reserve 4 bits for other + // information. + FunctionHash = (((uint64_t)JCH.getCRC()) << 28) + JC.getCRC(); + } + // Reserve bit 60-63 for other information purpose. FunctionHash &= 0x0FFFFFFFFFFFFFFF; if (IsCS) @@ -701,12 +701,12 @@ void FuncPGOInstrumentation<Edge, BBInfo>::computeCFGHash() { << " CRC = " << JC.getCRC() << ", Selects = " << SIVisitor.getNumOfSelectInsts() << ", Edges = " << MST.AllEdges.size() << ", ICSites = " - << ValueSites[IPVK_IndirectCallTarget].size()); - if (!PGOOldCFGHashing) { - LLVM_DEBUG(dbgs() << ", Memops = " << ValueSites[IPVK_MemOPSize].size() - << ", High32 CRC = " << JCH.getCRC()); - } - LLVM_DEBUG(dbgs() << ", Hash = " << FunctionHash << "\n";); + << ValueSites[IPVK_IndirectCallTarget].size()); + if (!PGOOldCFGHashing) { + LLVM_DEBUG(dbgs() << ", Memops = " << ValueSites[IPVK_MemOPSize].size() + << ", High32 CRC = " << JCH.getCRC()); + } + LLVM_DEBUG(dbgs() << ", Hash = " << FunctionHash << "\n";); } // Check if we can safely rename this Comdat function. @@ -717,7 +717,7 @@ static bool canRenameComdat( return false; // FIXME: Current only handle those Comdat groups that only containing one - // function. + // function. // (1) For a Comdat group containing multiple functions, we need to have a // unique postfix based on the hashes for each function. There is a // non-trivial code refactoring to do this efficiently. @@ -725,7 +725,7 @@ static bool canRenameComdat( // group including global vars. Comdat *C = F.getComdat(); for (auto &&CM : make_range(ComdatMembers.equal_range(C))) { - assert(!isa<GlobalAlias>(CM.second)); + assert(!isa<GlobalAlias>(CM.second)); Function *FM = dyn_cast<Function>(CM.second); if (FM != &F) return false; @@ -766,7 +766,7 @@ void FuncPGOInstrumentation<Edge, BBInfo>::renameComdatFunction() { for (auto &&CM : make_range(ComdatMembers.equal_range(OrigComdat))) { // Must be a function. - cast<Function>(CM.second)->setComdat(NewComdat); + cast<Function>(CM.second)->setComdat(NewComdat); } } @@ -831,11 +831,11 @@ BasicBlock *FuncPGOInstrumentation<Edge, BBInfo>::getInstrBB(Edge *E) { if (!E->IsCritical) return canInstrument(DestBB); - // Some IndirectBr critical edges cannot be split by the previous - // SplitIndirectBrCriticalEdges call. Bail out. + // Some IndirectBr critical edges cannot be split by the previous + // SplitIndirectBrCriticalEdges call. Bail out. unsigned SuccNum = GetSuccessorNumber(SrcBB, DestBB); - BasicBlock *InstrBB = - isa<IndirectBrInst>(TI) ? nullptr : SplitCriticalEdge(TI, SuccNum); + BasicBlock *InstrBB = + isa<IndirectBrInst>(TI) ? nullptr : SplitCriticalEdge(TI, SuccNum); if (!InstrBB) { LLVM_DEBUG( dbgs() << "Fail to split critical edge: not instrument this edge.\n"); @@ -898,8 +898,8 @@ static void instrumentOneFunc( // later in getInstrBB() to avoid invalidating it. SplitIndirectBrCriticalEdges(F, BPI, BFI); - FuncPGOInstrumentation<PGOEdge, BBInfo> FuncInfo( - F, TLI, ComdatMembers, true, BPI, BFI, IsCS, PGOInstrumentEntry); + FuncPGOInstrumentation<PGOEdge, BBInfo> FuncInfo( + F, TLI, ComdatMembers, true, BPI, BFI, IsCS, PGOInstrumentEntry); std::vector<BasicBlock *> InstrumentBBs; FuncInfo.getInstrumentBBs(InstrumentBBs); unsigned NumCounters = @@ -1057,15 +1057,15 @@ public: PGOUseFunc(Function &Func, Module *Modu, TargetLibraryInfo &TLI, std::unordered_multimap<Comdat *, GlobalValue *> &ComdatMembers, BranchProbabilityInfo *BPI, BlockFrequencyInfo *BFIin, - ProfileSummaryInfo *PSI, bool IsCS, bool InstrumentFuncEntry) + ProfileSummaryInfo *PSI, bool IsCS, bool InstrumentFuncEntry) : F(Func), M(Modu), BFI(BFIin), PSI(PSI), - FuncInfo(Func, TLI, ComdatMembers, false, BPI, BFIin, IsCS, - InstrumentFuncEntry), + FuncInfo(Func, TLI, ComdatMembers, false, BPI, BFIin, IsCS, + InstrumentFuncEntry), FreqAttr(FFA_Normal), IsCS(IsCS) {} // Read counts for the instrumented BB from profile. - bool readCounters(IndexedInstrProfReader *PGOReader, bool &AllZeros, - bool &AllMinusOnes); + bool readCounters(IndexedInstrProfReader *PGOReader, bool &AllZeros, + bool &AllMinusOnes); // Populate the counts for all BBs. void populateCounters(); @@ -1176,18 +1176,18 @@ bool PGOUseFunc::setInstrumentedCounts( if (NumCounters != CountFromProfile.size()) { return false; } - auto *FuncEntry = &*F.begin(); - + auto *FuncEntry = &*F.begin(); + // Set the profile count to the Instrumented BBs. uint32_t I = 0; for (BasicBlock *InstrBB : InstrumentBBs) { uint64_t CountValue = CountFromProfile[I++]; UseBBInfo &Info = getBBInfo(InstrBB); - // If we reach here, we know that we have some nonzero count - // values in this function. The entry count should not be 0. - // Fix it if necessary. - if (InstrBB == FuncEntry && CountValue == 0) - CountValue = 1; + // If we reach here, we know that we have some nonzero count + // values in this function. The entry count should not be 0. + // Fix it if necessary. + if (InstrBB == FuncEntry && CountValue == 0) + CountValue = 1; Info.setBBInfoCount(CountValue); } ProfileCountSize = CountFromProfile.size(); @@ -1248,8 +1248,8 @@ void PGOUseFunc::setEdgeCount(DirectEdges &Edges, uint64_t Value) { // Read the profile from ProfileFileName and assign the value to the // instrumented BB and the edges. This function also updates ProgramMaxCount. // Return true if the profile are successfully read, and false on errors. -bool PGOUseFunc::readCounters(IndexedInstrProfReader *PGOReader, bool &AllZeros, - bool &AllMinusOnes) { +bool PGOUseFunc::readCounters(IndexedInstrProfReader *PGOReader, bool &AllZeros, + bool &AllMinusOnes) { auto &Ctx = M->getContext(); Expected<InstrProfRecord> Result = PGOReader->getInstrProfRecord(FuncInfo.FuncName, FuncInfo.FunctionHash); @@ -1292,13 +1292,13 @@ bool PGOUseFunc::readCounters(IndexedInstrProfReader *PGOReader, bool &AllZeros, IsCS ? NumOfCSPGOFunc++ : NumOfPGOFunc++; LLVM_DEBUG(dbgs() << CountFromProfile.size() << " counts\n"); - AllMinusOnes = (CountFromProfile.size() > 0); + AllMinusOnes = (CountFromProfile.size() > 0); uint64_t ValueSum = 0; for (unsigned I = 0, S = CountFromProfile.size(); I < S; I++) { LLVM_DEBUG(dbgs() << " " << I << ": " << CountFromProfile[I] << "\n"); ValueSum += CountFromProfile[I]; - if (CountFromProfile[I] != (uint64_t)-1) - AllMinusOnes = false; + if (CountFromProfile[I] != (uint64_t)-1) + AllMinusOnes = false; } AllZeros = (ValueSum == 0); @@ -1389,11 +1389,11 @@ void PGOUseFunc::populateCounters() { continue; FuncMaxCount = std::max(FuncMaxCount, BI->CountValue); } - - // Fix the obviously inconsistent entry count. - if (FuncMaxCount > 0 && FuncEntryCount == 0) - FuncEntryCount = 1; - F.setEntryCount(ProfileCount(FuncEntryCount, Function::PCT_Real)); + + // Fix the obviously inconsistent entry count. + if (FuncMaxCount > 0 && FuncEntryCount == 0) + FuncEntryCount = 1; + F.setEntryCount(ProfileCount(FuncEntryCount, Function::PCT_Real)); markFunctionAttributes(FuncEntryCount, FuncMaxCount); // Now annotate select instructions @@ -1584,15 +1584,15 @@ static bool InstrumentAllFunctions( // For the context-sensitve instrumentation, we should have a separated pass // (before LTO/ThinLTO linking) to create these variables. if (!IsCS) - createIRLevelProfileFlagVar(M, /* IsCS */ false, PGOInstrumentEntry); + createIRLevelProfileFlagVar(M, /* IsCS */ false, PGOInstrumentEntry); std::unordered_multimap<Comdat *, GlobalValue *> ComdatMembers; collectComdatMembers(M, ComdatMembers); for (auto &F : M) { if (F.isDeclaration()) continue; - if (F.hasFnAttribute(llvm::Attribute::NoProfile)) - continue; + if (F.hasFnAttribute(llvm::Attribute::NoProfile)) + continue; auto &TLI = LookupTLI(F); auto *BPI = LookupBPI(F); auto *BFI = LookupBFI(F); @@ -1604,7 +1604,7 @@ static bool InstrumentAllFunctions( PreservedAnalyses PGOInstrumentationGenCreateVar::run(Module &M, ModuleAnalysisManager &AM) { createProfileFileNameVar(M, CSInstrName); - createIRLevelProfileFlagVar(M, /* IsCS */ true, PGOInstrumentEntry); + createIRLevelProfileFlagVar(M, /* IsCS */ true, PGOInstrumentEntry); return PreservedAnalyses::all(); } @@ -1643,129 +1643,129 @@ PreservedAnalyses PGOInstrumentationGen::run(Module &M, return PreservedAnalyses::none(); } -// Using the ratio b/w sums of profile count values and BFI count values to -// adjust the func entry count. -static void fixFuncEntryCount(PGOUseFunc &Func, LoopInfo &LI, - BranchProbabilityInfo &NBPI) { - Function &F = Func.getFunc(); - BlockFrequencyInfo NBFI(F, NBPI, LI); -#ifndef NDEBUG - auto BFIEntryCount = F.getEntryCount(); - assert(BFIEntryCount.hasValue() && (BFIEntryCount.getCount() > 0) && - "Invalid BFI Entrycount"); -#endif - auto SumCount = APFloat::getZero(APFloat::IEEEdouble()); - auto SumBFICount = APFloat::getZero(APFloat::IEEEdouble()); - for (auto &BBI : F) { - uint64_t CountValue = 0; - uint64_t BFICountValue = 0; - if (!Func.findBBInfo(&BBI)) - continue; - auto BFICount = NBFI.getBlockProfileCount(&BBI); - CountValue = Func.getBBInfo(&BBI).CountValue; - BFICountValue = BFICount.getValue(); - SumCount.add(APFloat(CountValue * 1.0), APFloat::rmNearestTiesToEven); - SumBFICount.add(APFloat(BFICountValue * 1.0), APFloat::rmNearestTiesToEven); - } - if (SumCount.isZero()) - return; - - assert(SumBFICount.compare(APFloat(0.0)) == APFloat::cmpGreaterThan && - "Incorrect sum of BFI counts"); - if (SumBFICount.compare(SumCount) == APFloat::cmpEqual) - return; - double Scale = (SumCount / SumBFICount).convertToDouble(); - if (Scale < 1.001 && Scale > 0.999) - return; - - uint64_t FuncEntryCount = Func.getBBInfo(&*F.begin()).CountValue; - uint64_t NewEntryCount = 0.5 + FuncEntryCount * Scale; - if (NewEntryCount == 0) - NewEntryCount = 1; - if (NewEntryCount != FuncEntryCount) { - F.setEntryCount(ProfileCount(NewEntryCount, Function::PCT_Real)); - LLVM_DEBUG(dbgs() << "FixFuncEntryCount: in " << F.getName() - << ", entry_count " << FuncEntryCount << " --> " - << NewEntryCount << "\n"); - } -} - -// Compare the profile count values with BFI count values, and print out -// the non-matching ones. -static void verifyFuncBFI(PGOUseFunc &Func, LoopInfo &LI, - BranchProbabilityInfo &NBPI, - uint64_t HotCountThreshold, - uint64_t ColdCountThreshold) { - Function &F = Func.getFunc(); - BlockFrequencyInfo NBFI(F, NBPI, LI); - // bool PrintFunc = false; - bool HotBBOnly = PGOVerifyHotBFI; - std::string Msg; - OptimizationRemarkEmitter ORE(&F); - - unsigned BBNum = 0, BBMisMatchNum = 0, NonZeroBBNum = 0; - for (auto &BBI : F) { - uint64_t CountValue = 0; - uint64_t BFICountValue = 0; - - if (Func.getBBInfo(&BBI).CountValid) - CountValue = Func.getBBInfo(&BBI).CountValue; - - BBNum++; - if (CountValue) - NonZeroBBNum++; - auto BFICount = NBFI.getBlockProfileCount(&BBI); - if (BFICount) - BFICountValue = BFICount.getValue(); - - if (HotBBOnly) { - bool rawIsHot = CountValue >= HotCountThreshold; - bool BFIIsHot = BFICountValue >= HotCountThreshold; - bool rawIsCold = CountValue <= ColdCountThreshold; - bool ShowCount = false; - if (rawIsHot && !BFIIsHot) { - Msg = "raw-Hot to BFI-nonHot"; - ShowCount = true; - } else if (rawIsCold && BFIIsHot) { - Msg = "raw-Cold to BFI-Hot"; - ShowCount = true; - } - if (!ShowCount) - continue; - } else { - if ((CountValue < PGOVerifyBFICutoff) && - (BFICountValue < PGOVerifyBFICutoff)) - continue; - uint64_t Diff = (BFICountValue >= CountValue) - ? BFICountValue - CountValue - : CountValue - BFICountValue; - if (Diff < CountValue / 100 * PGOVerifyBFIRatio) - continue; - } - BBMisMatchNum++; - - ORE.emit([&]() { - OptimizationRemarkAnalysis Remark(DEBUG_TYPE, "bfi-verify", - F.getSubprogram(), &BBI); - Remark << "BB " << ore::NV("Block", BBI.getName()) - << " Count=" << ore::NV("Count", CountValue) - << " BFI_Count=" << ore::NV("Count", BFICountValue); - if (!Msg.empty()) - Remark << " (" << Msg << ")"; - return Remark; - }); - } - if (BBMisMatchNum) - ORE.emit([&]() { - return OptimizationRemarkAnalysis(DEBUG_TYPE, "bfi-verify", - F.getSubprogram(), &F.getEntryBlock()) - << "In Func " << ore::NV("Function", F.getName()) - << ": Num_of_BB=" << ore::NV("Count", BBNum) - << ", Num_of_non_zerovalue_BB=" << ore::NV("Count", NonZeroBBNum) - << ", Num_of_mis_matching_BB=" << ore::NV("Count", BBMisMatchNum); - }); -} - +// Using the ratio b/w sums of profile count values and BFI count values to +// adjust the func entry count. +static void fixFuncEntryCount(PGOUseFunc &Func, LoopInfo &LI, + BranchProbabilityInfo &NBPI) { + Function &F = Func.getFunc(); + BlockFrequencyInfo NBFI(F, NBPI, LI); +#ifndef NDEBUG + auto BFIEntryCount = F.getEntryCount(); + assert(BFIEntryCount.hasValue() && (BFIEntryCount.getCount() > 0) && + "Invalid BFI Entrycount"); +#endif + auto SumCount = APFloat::getZero(APFloat::IEEEdouble()); + auto SumBFICount = APFloat::getZero(APFloat::IEEEdouble()); + for (auto &BBI : F) { + uint64_t CountValue = 0; + uint64_t BFICountValue = 0; + if (!Func.findBBInfo(&BBI)) + continue; + auto BFICount = NBFI.getBlockProfileCount(&BBI); + CountValue = Func.getBBInfo(&BBI).CountValue; + BFICountValue = BFICount.getValue(); + SumCount.add(APFloat(CountValue * 1.0), APFloat::rmNearestTiesToEven); + SumBFICount.add(APFloat(BFICountValue * 1.0), APFloat::rmNearestTiesToEven); + } + if (SumCount.isZero()) + return; + + assert(SumBFICount.compare(APFloat(0.0)) == APFloat::cmpGreaterThan && + "Incorrect sum of BFI counts"); + if (SumBFICount.compare(SumCount) == APFloat::cmpEqual) + return; + double Scale = (SumCount / SumBFICount).convertToDouble(); + if (Scale < 1.001 && Scale > 0.999) + return; + + uint64_t FuncEntryCount = Func.getBBInfo(&*F.begin()).CountValue; + uint64_t NewEntryCount = 0.5 + FuncEntryCount * Scale; + if (NewEntryCount == 0) + NewEntryCount = 1; + if (NewEntryCount != FuncEntryCount) { + F.setEntryCount(ProfileCount(NewEntryCount, Function::PCT_Real)); + LLVM_DEBUG(dbgs() << "FixFuncEntryCount: in " << F.getName() + << ", entry_count " << FuncEntryCount << " --> " + << NewEntryCount << "\n"); + } +} + +// Compare the profile count values with BFI count values, and print out +// the non-matching ones. +static void verifyFuncBFI(PGOUseFunc &Func, LoopInfo &LI, + BranchProbabilityInfo &NBPI, + uint64_t HotCountThreshold, + uint64_t ColdCountThreshold) { + Function &F = Func.getFunc(); + BlockFrequencyInfo NBFI(F, NBPI, LI); + // bool PrintFunc = false; + bool HotBBOnly = PGOVerifyHotBFI; + std::string Msg; + OptimizationRemarkEmitter ORE(&F); + + unsigned BBNum = 0, BBMisMatchNum = 0, NonZeroBBNum = 0; + for (auto &BBI : F) { + uint64_t CountValue = 0; + uint64_t BFICountValue = 0; + + if (Func.getBBInfo(&BBI).CountValid) + CountValue = Func.getBBInfo(&BBI).CountValue; + + BBNum++; + if (CountValue) + NonZeroBBNum++; + auto BFICount = NBFI.getBlockProfileCount(&BBI); + if (BFICount) + BFICountValue = BFICount.getValue(); + + if (HotBBOnly) { + bool rawIsHot = CountValue >= HotCountThreshold; + bool BFIIsHot = BFICountValue >= HotCountThreshold; + bool rawIsCold = CountValue <= ColdCountThreshold; + bool ShowCount = false; + if (rawIsHot && !BFIIsHot) { + Msg = "raw-Hot to BFI-nonHot"; + ShowCount = true; + } else if (rawIsCold && BFIIsHot) { + Msg = "raw-Cold to BFI-Hot"; + ShowCount = true; + } + if (!ShowCount) + continue; + } else { + if ((CountValue < PGOVerifyBFICutoff) && + (BFICountValue < PGOVerifyBFICutoff)) + continue; + uint64_t Diff = (BFICountValue >= CountValue) + ? BFICountValue - CountValue + : CountValue - BFICountValue; + if (Diff < CountValue / 100 * PGOVerifyBFIRatio) + continue; + } + BBMisMatchNum++; + + ORE.emit([&]() { + OptimizationRemarkAnalysis Remark(DEBUG_TYPE, "bfi-verify", + F.getSubprogram(), &BBI); + Remark << "BB " << ore::NV("Block", BBI.getName()) + << " Count=" << ore::NV("Count", CountValue) + << " BFI_Count=" << ore::NV("Count", BFICountValue); + if (!Msg.empty()) + Remark << " (" << Msg << ")"; + return Remark; + }); + } + if (BBMisMatchNum) + ORE.emit([&]() { + return OptimizationRemarkAnalysis(DEBUG_TYPE, "bfi-verify", + F.getSubprogram(), &F.getEntryBlock()) + << "In Func " << ore::NV("Function", F.getName()) + << ": Num_of_BB=" << ore::NV("Count", BBNum) + << ", Num_of_non_zerovalue_BB=" << ore::NV("Count", NonZeroBBNum) + << ", Num_of_mis_matching_BB=" << ore::NV("Count", BBMisMatchNum); + }); +} + static bool annotateAllFunctions( Module &M, StringRef ProfileFileName, StringRef ProfileRemappingFileName, function_ref<TargetLibraryInfo &(Function &)> LookupTLI, @@ -1814,12 +1814,12 @@ static bool annotateAllFunctions( collectComdatMembers(M, ComdatMembers); std::vector<Function *> HotFunctions; std::vector<Function *> ColdFunctions; - - // If the profile marked as always instrument the entry BB, do the - // same. Note this can be overwritten by the internal option in CFGMST.h - bool InstrumentFuncEntry = PGOReader->instrEntryBBEnabled(); - if (PGOInstrumentEntry.getNumOccurrences() > 0) - InstrumentFuncEntry = PGOInstrumentEntry; + + // If the profile marked as always instrument the entry BB, do the + // same. Note this can be overwritten by the internal option in CFGMST.h + bool InstrumentFuncEntry = PGOReader->instrEntryBBEnabled(); + if (PGOInstrumentEntry.getNumOccurrences() > 0) + InstrumentFuncEntry = PGOInstrumentEntry; for (auto &F : M) { if (F.isDeclaration()) continue; @@ -1829,15 +1829,15 @@ static bool annotateAllFunctions( // Split indirectbr critical edges here before computing the MST rather than // later in getInstrBB() to avoid invalidating it. SplitIndirectBrCriticalEdges(F, BPI, BFI); - PGOUseFunc Func(F, &M, TLI, ComdatMembers, BPI, BFI, PSI, IsCS, - InstrumentFuncEntry); - // When AllMinusOnes is true, it means the profile for the function - // is unrepresentative and this function is actually hot. Set the - // entry count of the function to be multiple times of hot threshold - // and drop all its internal counters. - bool AllMinusOnes = false; + PGOUseFunc Func(F, &M, TLI, ComdatMembers, BPI, BFI, PSI, IsCS, + InstrumentFuncEntry); + // When AllMinusOnes is true, it means the profile for the function + // is unrepresentative and this function is actually hot. Set the + // entry count of the function to be multiple times of hot threshold + // and drop all its internal counters. + bool AllMinusOnes = false; bool AllZeros = false; - if (!Func.readCounters(PGOReader.get(), AllZeros, AllMinusOnes)) + if (!Func.readCounters(PGOReader.get(), AllZeros, AllMinusOnes)) continue; if (AllZeros) { F.setEntryCount(ProfileCount(0, Function::PCT_Real)); @@ -1845,15 +1845,15 @@ static bool annotateAllFunctions( ColdFunctions.push_back(&F); continue; } - const unsigned MultiplyFactor = 3; - if (AllMinusOnes) { - uint64_t HotThreshold = PSI->getHotCountThreshold(); - if (HotThreshold) - F.setEntryCount( - ProfileCount(HotThreshold * MultiplyFactor, Function::PCT_Real)); - HotFunctions.push_back(&F); - continue; - } + const unsigned MultiplyFactor = 3; + if (AllMinusOnes) { + uint64_t HotThreshold = PSI->getHotCountThreshold(); + if (HotThreshold) + F.setEntryCount( + ProfileCount(HotThreshold * MultiplyFactor, Function::PCT_Real)); + HotFunctions.push_back(&F); + continue; + } Func.populateCounters(); Func.setBranchWeights(); Func.annotateValueSites(); @@ -1891,23 +1891,23 @@ static bool annotateAllFunctions( Func.dumpInfo(); } } - - if (PGOVerifyBFI || PGOVerifyHotBFI || PGOFixEntryCount) { - LoopInfo LI{DominatorTree(F)}; - BranchProbabilityInfo NBPI(F, LI); - - // Fix func entry count. - if (PGOFixEntryCount) - fixFuncEntryCount(Func, LI, NBPI); - - // Verify BlockFrequency information. - uint64_t HotCountThreshold = 0, ColdCountThreshold = 0; - if (PGOVerifyHotBFI) { - HotCountThreshold = PSI->getOrCompHotCountThreshold(); - ColdCountThreshold = PSI->getOrCompColdCountThreshold(); - } - verifyFuncBFI(Func, LI, NBPI, HotCountThreshold, ColdCountThreshold); - } + + if (PGOVerifyBFI || PGOVerifyHotBFI || PGOFixEntryCount) { + LoopInfo LI{DominatorTree(F)}; + BranchProbabilityInfo NBPI(F, LI); + + // Fix func entry count. + if (PGOFixEntryCount) + fixFuncEntryCount(Func, LI, NBPI); + + // Verify BlockFrequency information. + uint64_t HotCountThreshold = 0, ColdCountThreshold = 0; + if (PGOVerifyHotBFI) { + HotCountThreshold = PSI->getOrCompHotCountThreshold(); + ColdCountThreshold = PSI->getOrCompColdCountThreshold(); + } + verifyFuncBFI(Func, LI, NBPI, HotCountThreshold, ColdCountThreshold); + } } // Set function hotness attribute from the profile. @@ -1920,17 +1920,17 @@ static bool annotateAllFunctions( << "\n"); } for (auto &F : ColdFunctions) { - // Only set when there is no Attribute::Hot set by the user. For Hot - // attribute, user's annotation has the precedence over the profile. - if (F->hasFnAttribute(Attribute::Hot)) { - auto &Ctx = M.getContext(); - std::string Msg = std::string("Function ") + F->getName().str() + - std::string(" is annotated as a hot function but" - " the profile is cold"); - Ctx.diagnose( - DiagnosticInfoPGOProfile(M.getName().data(), Msg, DS_Warning)); - continue; - } + // Only set when there is no Attribute::Hot set by the user. For Hot + // attribute, user's annotation has the precedence over the profile. + if (F->hasFnAttribute(Attribute::Hot)) { + auto &Ctx = M.getContext(); + std::string Msg = std::string("Function ") + F->getName().str() + + std::string(" is annotated as a hot function but" + " the profile is cold"); + Ctx.diagnose( + DiagnosticInfoPGOProfile(M.getName().data(), Msg, DS_Warning)); + continue; + } F->addFnAttr(Attribute::Cold); LLVM_DEBUG(dbgs() << "Set cold attribute to function: " << F->getName() << "\n"); diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp b/contrib/libs/llvm12/lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp index 3f5db5380e..55a93b6152 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp @@ -22,7 +22,7 @@ #include "llvm/Analysis/DomTreeUpdater.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" -#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Dominators.h" @@ -39,8 +39,8 @@ #include "llvm/Pass.h" #include "llvm/PassRegistry.h" #include "llvm/ProfileData/InstrProf.h" -#define INSTR_PROF_VALUE_PROF_MEMOP_API -#include "llvm/ProfileData/InstrProfData.inc" +#define INSTR_PROF_VALUE_PROF_MEMOP_API +#include "llvm/ProfileData/InstrProfData.inc" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -97,10 +97,10 @@ cl::opt<bool> cl::Hidden, cl::desc("Size-specialize memcmp and bcmp calls")); -static cl::opt<unsigned> - MemOpMaxOptSize("memop-value-prof-max-opt-size", cl::Hidden, cl::init(128), - cl::desc("Optimize the memop size <= this value")); - +static cl::opt<unsigned> + MemOpMaxOptSize("memop-value-prof-max-opt-size", cl::Hidden, cl::init(128), + cl::desc("Optimize the memop size <= this value")); + namespace { class PGOMemOPSizeOptLegacyPass : public FunctionPass { public: @@ -254,7 +254,7 @@ public: LibFunc Func; if (TLI.getLibFunc(CI, Func) && (Func == LibFunc_memcmp || Func == LibFunc_bcmp) && - !isa<ConstantInt>(CI.getArgOperand(2))) { + !isa<ConstantInt>(CI.getArgOperand(2))) { WorkList.push_back(MemOp(&CI)); } } @@ -346,7 +346,7 @@ bool MemOPSizeOpt::perform(MemOp MO) { if (MemOPScaleCount) C = getScaledCount(C, ActualCount, SavedTotalCount); - if (!InstrProfIsSingleValRange(V) || V > MemOpMaxOptSize) + if (!InstrProfIsSingleValRange(V) || V > MemOpMaxOptSize) continue; // ValueCounts are sorted on the count. Break at the first un-profitable diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/PoisonChecking.cpp b/contrib/libs/llvm12/lib/Transforms/Instrumentation/PoisonChecking.cpp index 1cd36629b5..fc52672618 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/PoisonChecking.cpp +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/PoisonChecking.cpp @@ -282,10 +282,10 @@ static bool rewrite(Function &F) { // Note: There are many more sources of documented UB, but this pass only // attempts to find UB triggered by propagation of poison. - SmallPtrSet<const Value *, 4> NonPoisonOps; - getGuaranteedNonPoisonOps(&I, NonPoisonOps); - for (const Value *Op : NonPoisonOps) - CreateAssertNot(B, getPoisonFor(ValToPoison, const_cast<Value *>(Op))); + SmallPtrSet<const Value *, 4> NonPoisonOps; + getGuaranteedNonPoisonOps(&I, NonPoisonOps); + for (const Value *Op : NonPoisonOps) + CreateAssertNot(B, getPoisonFor(ValToPoison, const_cast<Value *>(Op))); if (LocalCheck) if (auto *RI = dyn_cast<ReturnInst>(&I)) @@ -295,11 +295,11 @@ static bool rewrite(Function &F) { } SmallVector<Value*, 4> Checks; - if (propagatesPoison(cast<Operator>(&I))) + if (propagatesPoison(cast<Operator>(&I))) for (Value *V : I.operands()) Checks.push_back(getPoisonFor(ValToPoison, V)); - if (canCreatePoison(cast<Operator>(&I))) + if (canCreatePoison(cast<Operator>(&I))) generateCreationChecks(I, Checks); ValToPoison[&I] = buildOrChain(B, Checks); } diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/contrib/libs/llvm12/lib/Transforms/Instrumentation/SanitizerCoverage.cpp index b840aafde7..2d4b079394 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/SanitizerCoverage.cpp +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -45,39 +45,39 @@ using namespace llvm; #define DEBUG_TYPE "sancov" -const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir"; -const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc"; -const char SanCovTraceCmp1[] = "__sanitizer_cov_trace_cmp1"; -const char SanCovTraceCmp2[] = "__sanitizer_cov_trace_cmp2"; -const char SanCovTraceCmp4[] = "__sanitizer_cov_trace_cmp4"; -const char SanCovTraceCmp8[] = "__sanitizer_cov_trace_cmp8"; -const char SanCovTraceConstCmp1[] = "__sanitizer_cov_trace_const_cmp1"; -const char SanCovTraceConstCmp2[] = "__sanitizer_cov_trace_const_cmp2"; -const char SanCovTraceConstCmp4[] = "__sanitizer_cov_trace_const_cmp4"; -const char SanCovTraceConstCmp8[] = "__sanitizer_cov_trace_const_cmp8"; -const char SanCovTraceDiv4[] = "__sanitizer_cov_trace_div4"; -const char SanCovTraceDiv8[] = "__sanitizer_cov_trace_div8"; -const char SanCovTraceGep[] = "__sanitizer_cov_trace_gep"; -const char SanCovTraceSwitchName[] = "__sanitizer_cov_trace_switch"; -const char SanCovModuleCtorTracePcGuardName[] = +const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir"; +const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc"; +const char SanCovTraceCmp1[] = "__sanitizer_cov_trace_cmp1"; +const char SanCovTraceCmp2[] = "__sanitizer_cov_trace_cmp2"; +const char SanCovTraceCmp4[] = "__sanitizer_cov_trace_cmp4"; +const char SanCovTraceCmp8[] = "__sanitizer_cov_trace_cmp8"; +const char SanCovTraceConstCmp1[] = "__sanitizer_cov_trace_const_cmp1"; +const char SanCovTraceConstCmp2[] = "__sanitizer_cov_trace_const_cmp2"; +const char SanCovTraceConstCmp4[] = "__sanitizer_cov_trace_const_cmp4"; +const char SanCovTraceConstCmp8[] = "__sanitizer_cov_trace_const_cmp8"; +const char SanCovTraceDiv4[] = "__sanitizer_cov_trace_div4"; +const char SanCovTraceDiv8[] = "__sanitizer_cov_trace_div8"; +const char SanCovTraceGep[] = "__sanitizer_cov_trace_gep"; +const char SanCovTraceSwitchName[] = "__sanitizer_cov_trace_switch"; +const char SanCovModuleCtorTracePcGuardName[] = "sancov.module_ctor_trace_pc_guard"; -const char SanCovModuleCtor8bitCountersName[] = +const char SanCovModuleCtor8bitCountersName[] = "sancov.module_ctor_8bit_counters"; -const char SanCovModuleCtorBoolFlagName[] = "sancov.module_ctor_bool_flag"; +const char SanCovModuleCtorBoolFlagName[] = "sancov.module_ctor_bool_flag"; static const uint64_t SanCtorAndDtorPriority = 2; -const char SanCovTracePCGuardName[] = "__sanitizer_cov_trace_pc_guard"; -const char SanCovTracePCGuardInitName[] = "__sanitizer_cov_trace_pc_guard_init"; -const char SanCov8bitCountersInitName[] = "__sanitizer_cov_8bit_counters_init"; -const char SanCovBoolFlagInitName[] = "__sanitizer_cov_bool_flag_init"; -const char SanCovPCsInitName[] = "__sanitizer_cov_pcs_init"; +const char SanCovTracePCGuardName[] = "__sanitizer_cov_trace_pc_guard"; +const char SanCovTracePCGuardInitName[] = "__sanitizer_cov_trace_pc_guard_init"; +const char SanCov8bitCountersInitName[] = "__sanitizer_cov_8bit_counters_init"; +const char SanCovBoolFlagInitName[] = "__sanitizer_cov_bool_flag_init"; +const char SanCovPCsInitName[] = "__sanitizer_cov_pcs_init"; -const char SanCovGuardsSectionName[] = "sancov_guards"; -const char SanCovCountersSectionName[] = "sancov_cntrs"; -const char SanCovBoolFlagSectionName[] = "sancov_bools"; -const char SanCovPCsSectionName[] = "sancov_pcs"; +const char SanCovGuardsSectionName[] = "sancov_guards"; +const char SanCovCountersSectionName[] = "sancov_cntrs"; +const char SanCovBoolFlagSectionName[] = "sancov_bools"; +const char SanCovPCsSectionName[] = "sancov_pcs"; -const char SanCovLowestStackName[] = "__sancov_lowest_stack"; +const char SanCovLowestStackName[] = "__sancov_lowest_stack"; static cl::opt<int> ClCoverageLevel( "sanitizer-coverage-level", @@ -328,24 +328,24 @@ PreservedAnalyses ModuleSanitizerCoveragePass::run(Module &M, std::pair<Value *, Value *> ModuleSanitizerCoverage::CreateSecStartEnd(Module &M, const char *Section, Type *Ty) { - GlobalVariable *SecStart = new GlobalVariable( - M, Ty->getPointerElementType(), false, GlobalVariable::ExternalLinkage, - nullptr, getSectionStart(Section)); + GlobalVariable *SecStart = new GlobalVariable( + M, Ty->getPointerElementType(), false, GlobalVariable::ExternalLinkage, + nullptr, getSectionStart(Section)); SecStart->setVisibility(GlobalValue::HiddenVisibility); - GlobalVariable *SecEnd = new GlobalVariable( - M, Ty->getPointerElementType(), false, GlobalVariable::ExternalLinkage, - nullptr, getSectionEnd(Section)); + GlobalVariable *SecEnd = new GlobalVariable( + M, Ty->getPointerElementType(), false, GlobalVariable::ExternalLinkage, + nullptr, getSectionEnd(Section)); SecEnd->setVisibility(GlobalValue::HiddenVisibility); IRBuilder<> IRB(M.getContext()); if (!TargetTriple.isOSBinFormatCOFF()) - return std::make_pair(SecStart, SecEnd); + return std::make_pair(SecStart, SecEnd); // Account for the fact that on windows-msvc __start_* symbols actually // point to a uint64_t before the start of the array. auto SecStartI8Ptr = IRB.CreatePointerCast(SecStart, Int8PtrTy); auto GEP = IRB.CreateGEP(Int8Ty, SecStartI8Ptr, ConstantInt::get(IntptrTy, sizeof(uint64_t))); - return std::make_pair(IRB.CreatePointerCast(GEP, Ty), SecEnd); + return std::make_pair(IRB.CreatePointerCast(GEP, Ty), SecEnd); } Function *ModuleSanitizerCoverage::CreateInitCallsForSections( @@ -415,13 +415,13 @@ bool ModuleSanitizerCoverage::instrumentModule( SanCovTracePCIndir = M.getOrInsertFunction(SanCovTracePCIndirName, VoidTy, IntptrTy); - // Make sure smaller parameters are zero-extended to i64 if required by the - // target ABI. + // Make sure smaller parameters are zero-extended to i64 if required by the + // target ABI. AttributeList SanCovTraceCmpZeroExtAL; - SanCovTraceCmpZeroExtAL = - SanCovTraceCmpZeroExtAL.addParamAttribute(*C, 0, Attribute::ZExt); - SanCovTraceCmpZeroExtAL = - SanCovTraceCmpZeroExtAL.addParamAttribute(*C, 1, Attribute::ZExt); + SanCovTraceCmpZeroExtAL = + SanCovTraceCmpZeroExtAL.addParamAttribute(*C, 0, Attribute::ZExt); + SanCovTraceCmpZeroExtAL = + SanCovTraceCmpZeroExtAL.addParamAttribute(*C, 1, Attribute::ZExt); SanCovTraceCmpFunction[0] = M.getOrInsertFunction(SanCovTraceCmp1, SanCovTraceCmpZeroExtAL, VoidTy, @@ -446,7 +446,7 @@ bool ModuleSanitizerCoverage::instrumentModule( { AttributeList AL; - AL = AL.addParamAttribute(*C, 0, Attribute::ZExt); + AL = AL.addParamAttribute(*C, 0, Attribute::ZExt); SanCovTraceDivFunction[0] = M.getOrInsertFunction(SanCovTraceDiv4, AL, VoidTy, IRB.getInt32Ty()); } @@ -509,23 +509,23 @@ bool ModuleSanitizerCoverage::instrumentModule( // True if block has successors and it dominates all of them. static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) { - if (succ_empty(BB)) + if (succ_empty(BB)) return false; - return llvm::all_of(successors(BB), [&](const BasicBlock *SUCC) { - return DT->dominates(BB, SUCC); - }); + return llvm::all_of(successors(BB), [&](const BasicBlock *SUCC) { + return DT->dominates(BB, SUCC); + }); } // True if block has predecessors and it postdominates all of them. static bool isFullPostDominator(const BasicBlock *BB, const PostDominatorTree *PDT) { - if (pred_empty(BB)) + if (pred_empty(BB)) return false; - return llvm::all_of(predecessors(BB), [&](const BasicBlock *PRED) { - return PDT->dominates(BB, PRED); - }); + return llvm::all_of(predecessors(BB), [&](const BasicBlock *PRED) { + return PDT->dominates(BB, PRED); + }); } static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, @@ -795,7 +795,7 @@ void ModuleSanitizerCoverage::InjectTraceForSwitch( C = ConstantExpr::getCast(CastInst::ZExt, It.getCaseValue(), Int64Ty); Initializers.push_back(C); } - llvm::sort(drop_begin(Initializers, 2), + llvm::sort(drop_begin(Initializers, 2), [](const Constant *A, const Constant *B) { return cast<ConstantInt>(A)->getLimitedValue() < cast<ConstantInt>(B)->getLimitedValue(); @@ -883,7 +883,7 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, DebugLoc EntryLoc; if (IsEntryBB) { if (auto SP = F.getSubprogram()) - EntryLoc = DILocation::get(SP->getContext(), SP->getScopeLine(), 0, SP); + EntryLoc = DILocation::get(SP->getContext(), SP->getScopeLine(), 0, SP); // Keep static allocas and llvm.localescape calls in the entry block. Even // if we aren't splitting the block, it's nice for allocas to be before // calls. diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/ThreadSanitizer.cpp b/contrib/libs/llvm12/lib/Transforms/Instrumentation/ThreadSanitizer.cpp index 85d36a0d4f..783878cf1e 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/ThreadSanitizer.cpp +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/ThreadSanitizer.cpp @@ -19,8 +19,8 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/Optional.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" @@ -53,36 +53,36 @@ using namespace llvm; #define DEBUG_TYPE "tsan" -static cl::opt<bool> ClInstrumentMemoryAccesses( +static cl::opt<bool> ClInstrumentMemoryAccesses( "tsan-instrument-memory-accesses", cl::init(true), cl::desc("Instrument memory accesses"), cl::Hidden); -static cl::opt<bool> - ClInstrumentFuncEntryExit("tsan-instrument-func-entry-exit", cl::init(true), - cl::desc("Instrument function entry and exit"), - cl::Hidden); -static cl::opt<bool> ClHandleCxxExceptions( +static cl::opt<bool> + ClInstrumentFuncEntryExit("tsan-instrument-func-entry-exit", cl::init(true), + cl::desc("Instrument function entry and exit"), + cl::Hidden); +static cl::opt<bool> ClHandleCxxExceptions( "tsan-handle-cxx-exceptions", cl::init(true), cl::desc("Handle C++ exceptions (insert cleanup blocks for unwinding)"), cl::Hidden); -static cl::opt<bool> ClInstrumentAtomics("tsan-instrument-atomics", - cl::init(true), - cl::desc("Instrument atomics"), - cl::Hidden); -static cl::opt<bool> ClInstrumentMemIntrinsics( +static cl::opt<bool> ClInstrumentAtomics("tsan-instrument-atomics", + cl::init(true), + cl::desc("Instrument atomics"), + cl::Hidden); +static cl::opt<bool> ClInstrumentMemIntrinsics( "tsan-instrument-memintrinsics", cl::init(true), cl::desc("Instrument memintrinsics (memset/memcpy/memmove)"), cl::Hidden); -static cl::opt<bool> ClDistinguishVolatile( +static cl::opt<bool> ClDistinguishVolatile( "tsan-distinguish-volatile", cl::init(false), cl::desc("Emit special instrumentation for accesses to volatiles"), cl::Hidden); -static cl::opt<bool> ClInstrumentReadBeforeWrite( +static cl::opt<bool> ClInstrumentReadBeforeWrite( "tsan-instrument-read-before-write", cl::init(false), cl::desc("Do not eliminate read instrumentation for read-before-writes"), cl::Hidden); -static cl::opt<bool> ClCompoundReadBeforeWrite( - "tsan-compound-read-before-write", cl::init(false), - cl::desc("Emit special compound instrumentation for reads-before-writes"), - cl::Hidden); +static cl::opt<bool> ClCompoundReadBeforeWrite( + "tsan-compound-read-before-write", cl::init(false), + cl::desc("Emit special compound instrumentation for reads-before-writes"), + cl::Hidden); STATISTIC(NumInstrumentedReads, "Number of instrumented reads"); STATISTIC(NumInstrumentedWrites, "Number of instrumented writes"); @@ -96,8 +96,8 @@ STATISTIC(NumOmittedReadsFromConstantGlobals, STATISTIC(NumOmittedReadsFromVtable, "Number of vtable reads"); STATISTIC(NumOmittedNonCaptured, "Number of accesses ignored due to capturing"); -const char kTsanModuleCtorName[] = "tsan.module_ctor"; -const char kTsanInitName[] = "__tsan_init"; +const char kTsanModuleCtorName[] = "tsan.module_ctor"; +const char kTsanInitName[] = "__tsan_init"; namespace { @@ -108,37 +108,37 @@ namespace { /// ensures the __tsan_init function is in the list of global constructors for /// the module. struct ThreadSanitizer { - ThreadSanitizer() { - // Sanity check options and warn user. - if (ClInstrumentReadBeforeWrite && ClCompoundReadBeforeWrite) { - errs() - << "warning: Option -tsan-compound-read-before-write has no effect " - "when -tsan-instrument-read-before-write is set.\n"; - } - } - + ThreadSanitizer() { + // Sanity check options and warn user. + if (ClInstrumentReadBeforeWrite && ClCompoundReadBeforeWrite) { + errs() + << "warning: Option -tsan-compound-read-before-write has no effect " + "when -tsan-instrument-read-before-write is set.\n"; + } + } + bool sanitizeFunction(Function &F, const TargetLibraryInfo &TLI); private: - // Internal Instruction wrapper that contains more information about the - // Instruction from prior analysis. - struct InstructionInfo { - // Instrumentation emitted for this instruction is for a compounded set of - // read and write operations in the same basic block. - static constexpr unsigned kCompoundRW = (1U << 0); - - explicit InstructionInfo(Instruction *Inst) : Inst(Inst) {} - - Instruction *Inst; - unsigned Flags = 0; - }; - + // Internal Instruction wrapper that contains more information about the + // Instruction from prior analysis. + struct InstructionInfo { + // Instrumentation emitted for this instruction is for a compounded set of + // read and write operations in the same basic block. + static constexpr unsigned kCompoundRW = (1U << 0); + + explicit InstructionInfo(Instruction *Inst) : Inst(Inst) {} + + Instruction *Inst; + unsigned Flags = 0; + }; + void initialize(Module &M); - bool instrumentLoadOrStore(const InstructionInfo &II, const DataLayout &DL); + bool instrumentLoadOrStore(const InstructionInfo &II, const DataLayout &DL); bool instrumentAtomic(Instruction *I, const DataLayout &DL); bool instrumentMemIntrinsic(Instruction *I); void chooseInstructionsToInstrument(SmallVectorImpl<Instruction *> &Local, - SmallVectorImpl<InstructionInfo> &All, + SmallVectorImpl<InstructionInfo> &All, const DataLayout &DL); bool addrPointsToConstantData(Value *Addr); int getMemoryAccessFuncIndex(Value *Addr, const DataLayout &DL); @@ -159,8 +159,8 @@ private: FunctionCallee TsanVolatileWrite[kNumberOfAccessSizes]; FunctionCallee TsanUnalignedVolatileRead[kNumberOfAccessSizes]; FunctionCallee TsanUnalignedVolatileWrite[kNumberOfAccessSizes]; - FunctionCallee TsanCompoundRW[kNumberOfAccessSizes]; - FunctionCallee TsanUnalignedCompoundRW[kNumberOfAccessSizes]; + FunctionCallee TsanCompoundRW[kNumberOfAccessSizes]; + FunctionCallee TsanUnalignedCompoundRW[kNumberOfAccessSizes]; FunctionCallee TsanAtomicLoad[kNumberOfAccessSizes]; FunctionCallee TsanAtomicStore[kNumberOfAccessSizes]; FunctionCallee TsanAtomicRMW[AtomicRMWInst::LAST_BINOP + 1] @@ -299,15 +299,15 @@ void ThreadSanitizer::initialize(Module &M) { TsanUnalignedVolatileWrite[i] = M.getOrInsertFunction( UnalignedVolatileWriteName, Attr, IRB.getVoidTy(), IRB.getInt8PtrTy()); - SmallString<64> CompoundRWName("__tsan_read_write" + ByteSizeStr); - TsanCompoundRW[i] = M.getOrInsertFunction( - CompoundRWName, Attr, IRB.getVoidTy(), IRB.getInt8PtrTy()); - - SmallString<64> UnalignedCompoundRWName("__tsan_unaligned_read_write" + - ByteSizeStr); - TsanUnalignedCompoundRW[i] = M.getOrInsertFunction( - UnalignedCompoundRWName, Attr, IRB.getVoidTy(), IRB.getInt8PtrTy()); - + SmallString<64> CompoundRWName("__tsan_read_write" + ByteSizeStr); + TsanCompoundRW[i] = M.getOrInsertFunction( + CompoundRWName, Attr, IRB.getVoidTy(), IRB.getInt8PtrTy()); + + SmallString<64> UnalignedCompoundRWName("__tsan_unaligned_read_write" + + ByteSizeStr); + TsanUnalignedCompoundRW[i] = M.getOrInsertFunction( + UnalignedCompoundRWName, Attr, IRB.getVoidTy(), IRB.getInt8PtrTy()); + Type *Ty = Type::getIntNTy(M.getContext(), BitSize); Type *PtrTy = Ty->getPointerTo(); SmallString<32> AtomicLoadName("__tsan_atomic" + BitSizeStr + "_load"); @@ -442,43 +442,43 @@ bool ThreadSanitizer::addrPointsToConstantData(Value *Addr) { // 'Local' is a vector of insns within the same BB (no calls between). // 'All' is a vector of insns that will be instrumented. void ThreadSanitizer::chooseInstructionsToInstrument( - SmallVectorImpl<Instruction *> &Local, - SmallVectorImpl<InstructionInfo> &All, const DataLayout &DL) { - DenseMap<Value *, size_t> WriteTargets; // Map of addresses to index in All + SmallVectorImpl<Instruction *> &Local, + SmallVectorImpl<InstructionInfo> &All, const DataLayout &DL) { + DenseMap<Value *, size_t> WriteTargets; // Map of addresses to index in All // Iterate from the end. for (Instruction *I : reverse(Local)) { - const bool IsWrite = isa<StoreInst>(*I); - Value *Addr = IsWrite ? cast<StoreInst>(I)->getPointerOperand() - : cast<LoadInst>(I)->getPointerOperand(); - - if (!shouldInstrumentReadWriteFromAddress(I->getModule(), Addr)) - continue; - - if (!IsWrite) { - const auto WriteEntry = WriteTargets.find(Addr); - if (!ClInstrumentReadBeforeWrite && WriteEntry != WriteTargets.end()) { - auto &WI = All[WriteEntry->second]; - // If we distinguish volatile accesses and if either the read or write - // is volatile, do not omit any instrumentation. - const bool AnyVolatile = - ClDistinguishVolatile && (cast<LoadInst>(I)->isVolatile() || - cast<StoreInst>(WI.Inst)->isVolatile()); - if (!AnyVolatile) { - // We will write to this temp, so no reason to analyze the read. - // Mark the write instruction as compound. - WI.Flags |= InstructionInfo::kCompoundRW; - NumOmittedReadsBeforeWrite++; - continue; - } + const bool IsWrite = isa<StoreInst>(*I); + Value *Addr = IsWrite ? cast<StoreInst>(I)->getPointerOperand() + : cast<LoadInst>(I)->getPointerOperand(); + + if (!shouldInstrumentReadWriteFromAddress(I->getModule(), Addr)) + continue; + + if (!IsWrite) { + const auto WriteEntry = WriteTargets.find(Addr); + if (!ClInstrumentReadBeforeWrite && WriteEntry != WriteTargets.end()) { + auto &WI = All[WriteEntry->second]; + // If we distinguish volatile accesses and if either the read or write + // is volatile, do not omit any instrumentation. + const bool AnyVolatile = + ClDistinguishVolatile && (cast<LoadInst>(I)->isVolatile() || + cast<StoreInst>(WI.Inst)->isVolatile()); + if (!AnyVolatile) { + // We will write to this temp, so no reason to analyze the read. + // Mark the write instruction as compound. + WI.Flags |= InstructionInfo::kCompoundRW; + NumOmittedReadsBeforeWrite++; + continue; + } } - + if (addrPointsToConstantData(Addr)) { // Addr points to some constant data -- it can not race with any writes. continue; } } - - if (isa<AllocaInst>(getUnderlyingObject(Addr)) && + + if (isa<AllocaInst>(getUnderlyingObject(Addr)) && !PointerMayBeCaptured(Addr, true, true)) { // The variable is addressable but not captured, so it cannot be // referenced from a different thread and participate in a data race @@ -486,14 +486,14 @@ void ThreadSanitizer::chooseInstructionsToInstrument( NumOmittedNonCaptured++; continue; } - - // Instrument this instruction. - All.emplace_back(I); - if (IsWrite) { - // For read-before-write and compound instrumentation we only need one - // write target, and we can override any previous entry if it exists. - WriteTargets[Addr] = All.size() - 1; - } + + // Instrument this instruction. + All.emplace_back(I); + if (IsWrite) { + // For read-before-write and compound instrumentation we only need one + // write target, and we can override any previous entry if it exists. + WriteTargets[Addr] = All.size() - 1; + } } Local.clear(); } @@ -534,7 +534,7 @@ bool ThreadSanitizer::sanitizeFunction(Function &F, if (F.hasFnAttribute(Attribute::Naked)) return false; initialize(*F.getParent()); - SmallVector<InstructionInfo, 8> AllLoadsAndStores; + SmallVector<InstructionInfo, 8> AllLoadsAndStores; SmallVector<Instruction*, 8> LocalLoadsAndStores; SmallVector<Instruction*, 8> AtomicAccesses; SmallVector<Instruction*, 8> MemIntrinCalls; @@ -569,8 +569,8 @@ bool ThreadSanitizer::sanitizeFunction(Function &F, // Instrument memory accesses only if we want to report bugs in the function. if (ClInstrumentMemoryAccesses && SanitizeFunction) - for (const auto &II : AllLoadsAndStores) { - Res |= instrumentLoadOrStore(II, DL); + for (const auto &II : AllLoadsAndStores) { + Res |= instrumentLoadOrStore(II, DL); } // Instrument atomic memory accesses in any case (they can be used to @@ -608,12 +608,12 @@ bool ThreadSanitizer::sanitizeFunction(Function &F, return Res; } -bool ThreadSanitizer::instrumentLoadOrStore(const InstructionInfo &II, +bool ThreadSanitizer::instrumentLoadOrStore(const InstructionInfo &II, const DataLayout &DL) { - IRBuilder<> IRB(II.Inst); - const bool IsWrite = isa<StoreInst>(*II.Inst); - Value *Addr = IsWrite ? cast<StoreInst>(II.Inst)->getPointerOperand() - : cast<LoadInst>(II.Inst)->getPointerOperand(); + IRBuilder<> IRB(II.Inst); + const bool IsWrite = isa<StoreInst>(*II.Inst); + Value *Addr = IsWrite ? cast<StoreInst>(II.Inst)->getPointerOperand() + : cast<LoadInst>(II.Inst)->getPointerOperand(); // swifterror memory addresses are mem2reg promoted by instruction selection. // As such they cannot have regular uses like an instrumentation function and @@ -624,9 +624,9 @@ bool ThreadSanitizer::instrumentLoadOrStore(const InstructionInfo &II, int Idx = getMemoryAccessFuncIndex(Addr, DL); if (Idx < 0) return false; - if (IsWrite && isVtableAccess(II.Inst)) { - LLVM_DEBUG(dbgs() << " VPTR : " << *II.Inst << "\n"); - Value *StoredValue = cast<StoreInst>(II.Inst)->getValueOperand(); + if (IsWrite && isVtableAccess(II.Inst)) { + LLVM_DEBUG(dbgs() << " VPTR : " << *II.Inst << "\n"); + Value *StoredValue = cast<StoreInst>(II.Inst)->getValueOperand(); // StoredValue may be a vector type if we are storing several vptrs at once. // In this case, just take the first element of the vector since this is // enough to find vptr races. @@ -642,46 +642,46 @@ bool ThreadSanitizer::instrumentLoadOrStore(const InstructionInfo &II, NumInstrumentedVtableWrites++; return true; } - if (!IsWrite && isVtableAccess(II.Inst)) { + if (!IsWrite && isVtableAccess(II.Inst)) { IRB.CreateCall(TsanVptrLoad, IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy())); NumInstrumentedVtableReads++; return true; } - - const unsigned Alignment = IsWrite ? cast<StoreInst>(II.Inst)->getAlignment() - : cast<LoadInst>(II.Inst)->getAlignment(); - const bool IsCompoundRW = - ClCompoundReadBeforeWrite && (II.Flags & InstructionInfo::kCompoundRW); - const bool IsVolatile = ClDistinguishVolatile && - (IsWrite ? cast<StoreInst>(II.Inst)->isVolatile() - : cast<LoadInst>(II.Inst)->isVolatile()); - assert((!IsVolatile || !IsCompoundRW) && "Compound volatile invalid!"); - + + const unsigned Alignment = IsWrite ? cast<StoreInst>(II.Inst)->getAlignment() + : cast<LoadInst>(II.Inst)->getAlignment(); + const bool IsCompoundRW = + ClCompoundReadBeforeWrite && (II.Flags & InstructionInfo::kCompoundRW); + const bool IsVolatile = ClDistinguishVolatile && + (IsWrite ? cast<StoreInst>(II.Inst)->isVolatile() + : cast<LoadInst>(II.Inst)->isVolatile()); + assert((!IsVolatile || !IsCompoundRW) && "Compound volatile invalid!"); + Type *OrigTy = cast<PointerType>(Addr->getType())->getElementType(); const uint32_t TypeSize = DL.getTypeStoreSizeInBits(OrigTy); FunctionCallee OnAccessFunc = nullptr; if (Alignment == 0 || Alignment >= 8 || (Alignment % (TypeSize / 8)) == 0) { - if (IsCompoundRW) - OnAccessFunc = TsanCompoundRW[Idx]; - else if (IsVolatile) + if (IsCompoundRW) + OnAccessFunc = TsanCompoundRW[Idx]; + else if (IsVolatile) OnAccessFunc = IsWrite ? TsanVolatileWrite[Idx] : TsanVolatileRead[Idx]; else OnAccessFunc = IsWrite ? TsanWrite[Idx] : TsanRead[Idx]; } else { - if (IsCompoundRW) - OnAccessFunc = TsanUnalignedCompoundRW[Idx]; - else if (IsVolatile) + if (IsCompoundRW) + OnAccessFunc = TsanUnalignedCompoundRW[Idx]; + else if (IsVolatile) OnAccessFunc = IsWrite ? TsanUnalignedVolatileWrite[Idx] : TsanUnalignedVolatileRead[Idx]; else OnAccessFunc = IsWrite ? TsanUnalignedWrite[Idx] : TsanUnalignedRead[Idx]; } IRB.CreateCall(OnAccessFunc, IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy())); - if (IsCompoundRW || IsWrite) - NumInstrumentedWrites++; - if (IsCompoundRW || !IsWrite) - NumInstrumentedReads++; + if (IsCompoundRW || IsWrite) + NumInstrumentedWrites++; + if (IsCompoundRW || !IsWrite) + NumInstrumentedReads++; return true; } diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/ValueProfileCollector.cpp b/contrib/libs/llvm12/lib/Transforms/Instrumentation/ValueProfileCollector.cpp index e4c06b9466..fb6216bb21 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/ValueProfileCollector.cpp +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/ValueProfileCollector.cpp @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// #include "ValueProfilePlugins.inc" -#include "llvm/IR/Function.h" +#include "llvm/IR/Function.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/InitializePasses.h" diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/ValueProfileCollector.h b/contrib/libs/llvm12/lib/Transforms/Instrumentation/ValueProfileCollector.h index b3840d7a69..584a60ab45 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/ValueProfileCollector.h +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/ValueProfileCollector.h @@ -18,15 +18,15 @@ #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/ProfileData/InstrProf.h" -#include <memory> -#include <vector> +#include <memory> +#include <vector> namespace llvm { -class Function; -class Instruction; -class Value; - +class Function; +class Instruction; +class Value; + /// Utility analysis that determines what values are worth profiling. /// The actual logic is inside the ValueProfileCollectorImpl, whose job is to /// populate the Candidates vector. diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/ya.make b/contrib/libs/llvm12/lib/Transforms/Instrumentation/ya.make index 82f8c92dc5..39dab1eb7d 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/ya.make +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/ya.make @@ -15,14 +15,14 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) PEERDIR( - contrib/libs/llvm12 - contrib/libs/llvm12/include - contrib/libs/llvm12/lib/Analysis - contrib/libs/llvm12/lib/IR - contrib/libs/llvm12/lib/MC - contrib/libs/llvm12/lib/ProfileData - contrib/libs/llvm12/lib/Support - contrib/libs/llvm12/lib/Transforms/Utils + contrib/libs/llvm12 + contrib/libs/llvm12/include + contrib/libs/llvm12/lib/Analysis + contrib/libs/llvm12/lib/IR + contrib/libs/llvm12/lib/MC + contrib/libs/llvm12/lib/ProfileData + contrib/libs/llvm12/lib/Support + contrib/libs/llvm12/lib/Transforms/Utils ) ADDINCL( @@ -45,7 +45,7 @@ SRCS( InstrOrderFile.cpp InstrProfiling.cpp Instrumentation.cpp - MemProfiler.cpp + MemProfiler.cpp MemorySanitizer.cpp PGOInstrumentation.cpp PGOMemOPSizeOpt.cpp |