diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:10:56 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:10:56 +0000 |
| commit | 044eb2f6afba375a914ac9d8024f8f5142bb912e (patch) | |
| tree | 1475247dc9f9fe5be155ebd4c9069c75aadf8c20 /lib/IR | |
| parent | eb70dddbd77e120e5d490bd8fbe7ff3f8fa81c6b (diff) | |
Notes
Diffstat (limited to 'lib/IR')
41 files changed, 1822 insertions, 1549 deletions
diff --git a/lib/IR/AsmWriter.cpp b/lib/IR/AsmWriter.cpp index 170bc544d53f..0fafe82404e4 100644 --- a/lib/IR/AsmWriter.cpp +++ b/lib/IR/AsmWriter.cpp @@ -373,7 +373,9 @@ static void PrintCallingConv(unsigned cc, raw_ostream &Out) { case CallingConv::HHVM: Out << "hhvmcc"; break; case CallingConv::HHVM_C: Out << "hhvm_ccc"; break; case CallingConv::AMDGPU_VS: Out << "amdgpu_vs"; break; + case CallingConv::AMDGPU_LS: Out << "amdgpu_ls"; break; case CallingConv::AMDGPU_HS: Out << "amdgpu_hs"; break; + case CallingConv::AMDGPU_ES: Out << "amdgpu_es"; break; case CallingConv::AMDGPU_GS: Out << "amdgpu_gs"; break; case CallingConv::AMDGPU_PS: Out << "amdgpu_ps"; break; case CallingConv::AMDGPU_CS: Out << "amdgpu_cs"; break; @@ -1046,6 +1048,10 @@ void SlotTracker::CreateFunctionSlot(const Value *V) { void SlotTracker::CreateMetadataSlot(const MDNode *N) { assert(N && "Can't insert a null Value into SlotTracker!"); + // Don't make slots for DIExpressions. We just print them inline everywhere. + if (isa<DIExpression>(N)) + return; + unsigned DestSlot = mdnNext; if (!mdnMap.insert(std::make_pair(N, DestSlot)).second) return; @@ -1102,10 +1108,12 @@ static void writeAtomicRMWOperation(raw_ostream &Out, static void WriteOptimizationInfo(raw_ostream &Out, const User *U) { if (const FPMathOperator *FPO = dyn_cast<const FPMathOperator>(U)) { - // Unsafe algebra implies all the others, no need to write them all out - if (FPO->hasUnsafeAlgebra()) + // 'Fast' is an abbreviation for all fast-math-flags. + if (FPO->isFast()) Out << " fast"; else { + if (FPO->hasAllowReassoc()) + Out << " reassoc"; if (FPO->hasNoNaNs()) Out << " nnan"; if (FPO->hasNoInfs()) @@ -1116,6 +1124,8 @@ static void WriteOptimizationInfo(raw_ostream &Out, const User *U) { Out << " arcp"; if (FPO->hasAllowContract()) Out << " contract"; + if (FPO->hasApproxFunc()) + Out << " afn"; } } @@ -1738,6 +1748,7 @@ static void writeDICompileUnit(raw_ostream &Out, const DICompileUnit *N, Printer.printBool("splitDebugInlining", N->getSplitDebugInlining(), true); Printer.printBool("debugInfoForProfiling", N->getDebugInfoForProfiling(), false); + Printer.printBool("gnuPubnames", N->getGnuPubnames(), false); Out << ")"; } @@ -2073,6 +2084,13 @@ static void WriteAsOperandInternal(raw_ostream &Out, const Metadata *MD, TypePrinting *TypePrinter, SlotTracker *Machine, const Module *Context, bool FromValue) { + // Write DIExpressions inline when used as a value. Improves readability of + // debug info intrinsics. + if (const DIExpression *Expr = dyn_cast<DIExpression>(MD)) { + writeDIExpression(Out, Expr, TypePrinter, Machine, Context); + return; + } + if (const MDNode *N = dyn_cast<MDNode>(MD)) { std::unique_ptr<SlotTracker> MachineStorage; if (!Machine) { @@ -2424,7 +2442,16 @@ void AssemblyWriter::printNamedMDNode(const NamedMDNode *NMD) { for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { if (i) Out << ", "; - int Slot = Machine.getMetadataSlot(NMD->getOperand(i)); + + // Write DIExpressions inline. + // FIXME: Ban DIExpressions in NamedMDNodes, they will serve no purpose. + MDNode *Op = NMD->getOperand(i); + if (auto *Expr = dyn_cast<DIExpression>(Op)) { + writeDIExpression(Out, Expr, nullptr, nullptr, nullptr); + continue; + } + + int Slot = Machine.getMetadataSlot(Op); if (Slot == -1) Out << "<badref>"; else @@ -2470,6 +2497,11 @@ static void PrintVisibility(GlobalValue::VisibilityTypes Vis, } } +static void PrintDSOLocation(bool IsDSOLocal, formatted_raw_ostream &Out){ + if (IsDSOLocal) + Out << "dso_local "; +} + static void PrintDLLStorageClass(GlobalValue::DLLStorageClassTypes SCT, formatted_raw_ostream &Out) { switch (SCT) { @@ -2540,6 +2572,7 @@ void AssemblyWriter::printGlobal(const GlobalVariable *GV) { Out << "external "; Out << getLinkagePrintName(GV->getLinkage()); + PrintDSOLocation(GV->isDSOLocal(), Out); PrintVisibility(GV->getVisibility(), Out); PrintDLLStorageClass(GV->getDLLStorageClass(), Out); PrintThreadLocalModel(GV->getThreadLocalMode(), Out); @@ -2586,6 +2619,7 @@ void AssemblyWriter::printIndirectSymbol(const GlobalIndirectSymbol *GIS) { Out << " = "; Out << getLinkagePrintName(GIS->getLinkage()); + PrintDSOLocation(GIS->isDSOLocal(), Out); PrintVisibility(GIS->getVisibility(), Out); PrintDLLStorageClass(GIS->getDLLStorageClass(), Out); PrintThreadLocalModel(GIS->getThreadLocalMode(), Out); @@ -2697,6 +2731,7 @@ void AssemblyWriter::printFunction(const Function *F) { Out << "define "; Out << getLinkagePrintName(F->getLinkage()); + PrintDSOLocation(F->isDSOLocal(), Out); PrintVisibility(F->getVisibility(), Out); PrintDLLStorageClass(F->getDLLStorageClass(), Out); @@ -3572,7 +3607,7 @@ static void printMetadataImpl(raw_ostream &ROS, const Metadata &MD, /* FromValue */ true); auto *N = dyn_cast<MDNode>(&MD); - if (OnlyAsOperand || !N) + if (OnlyAsOperand || !N || isa<DIExpression>(MD)) return; OS << " = "; diff --git a/lib/IR/Attributes.cpp b/lib/IR/Attributes.cpp index 8f2e641d64b9..1b19a0474727 100644 --- a/lib/IR/Attributes.cpp +++ b/lib/IR/Attributes.cpp @@ -245,6 +245,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const { if (hasAttribute(Attribute::SanitizeAddress)) return "sanitize_address"; + if (hasAttribute(Attribute::SanitizeHWAddress)) + return "sanitize_hwaddress"; if (hasAttribute(Attribute::AlwaysInline)) return "alwaysinline"; if (hasAttribute(Attribute::ArgMemOnly)) @@ -327,6 +329,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const { return "sspstrong"; if (hasAttribute(Attribute::SafeStack)) return "safestack"; + if (hasAttribute(Attribute::StrictFP)) + return "strictfp"; if (hasAttribute(Attribute::StructRet)) return "sret"; if (hasAttribute(Attribute::SanitizeThread)) @@ -788,14 +792,12 @@ std::string AttributeSetNode::getAsString(bool InAttrGrp) const { // AttributeListImpl Definition //===----------------------------------------------------------------------===// -/// Map from AttributeList index to the internal array index. Adding one works: -/// FunctionIndex: ~0U -> 0 -/// ReturnIndex: 0 -> 1 -/// FirstArgIndex: 1.. -> 2.. +/// Map from AttributeList index to the internal array index. Adding one happens +/// to work, but it relies on unsigned integer wrapping. MSVC warns about +/// unsigned wrapping in constexpr functions, so write out the conditional. LLVM +/// folds it to add anyway. static constexpr unsigned attrIdxToArrayIdx(unsigned Index) { - // MSVC warns about '~0U + 1' wrapping around when this is called on - // FunctionIndex, so cast to int first. - return static_cast<int>(Index) + 1; + return Index == AttributeList::FunctionIndex ? 0 : Index + 1; } AttributeListImpl::AttributeListImpl(LLVMContext &C, diff --git a/lib/IR/AutoUpgrade.cpp b/lib/IR/AutoUpgrade.cpp index 80640def955e..c258d1a4e3ad 100644 --- a/lib/IR/AutoUpgrade.cpp +++ b/lib/IR/AutoUpgrade.cpp @@ -15,8 +15,6 @@ #include "llvm/IR/AutoUpgrade.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/IR/CFG.h" -#include "llvm/IR/CallSite.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/DebugInfo.h" @@ -24,9 +22,9 @@ #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instruction.h" -#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Regex.h" #include <cstring> @@ -72,12 +70,24 @@ static bool ShouldUpgradeX86Intrinsic(Function *F, StringRef Name) { // like to use this information to remove upgrade code for some older // intrinsics. It is currently undecided how we will determine that future // point. - if (Name.startswith("sse2.pcmpeq.") || // Added in 3.1 + if (Name=="ssse3.pabs.b.128" || // Added in 6.0 + Name=="ssse3.pabs.w.128" || // Added in 6.0 + Name=="ssse3.pabs.d.128" || // Added in 6.0 + Name.startswith("avx512.mask.shuf.i") || // Added in 6.0 + Name.startswith("avx512.mask.shuf.f") || // Added in 6.0 + Name.startswith("avx512.kunpck") || //added in 6.0 + Name.startswith("avx2.pabs.") || // Added in 6.0 + Name.startswith("avx512.mask.pabs.") || // Added in 6.0 + Name.startswith("avx512.broadcastm") || // Added in 6.0 + Name.startswith("avx512.mask.pbroadcast") || // Added in 6.0 + Name.startswith("sse2.pcmpeq.") || // Added in 3.1 Name.startswith("sse2.pcmpgt.") || // Added in 3.1 Name.startswith("avx2.pcmpeq.") || // Added in 3.1 Name.startswith("avx2.pcmpgt.") || // Added in 3.1 Name.startswith("avx512.mask.pcmpeq.") || // Added in 3.9 Name.startswith("avx512.mask.pcmpgt.") || // Added in 3.9 + Name.startswith("avx.vperm2f128.") || // Added in 6.0 + Name == "avx2.vperm2i128" || // Added in 6.0 Name == "sse.add.ss" || // Added in 4.0 Name == "sse2.add.sd" || // Added in 4.0 Name == "sse.sub.ss" || // Added in 4.0 @@ -239,12 +249,19 @@ static bool ShouldUpgradeX86Intrinsic(Function *F, StringRef Name) { Name.startswith("avx2.pblendd.") || // Added in 3.7 Name.startswith("avx.vbroadcastf128") || // Added in 4.0 Name == "avx2.vbroadcasti128" || // Added in 3.7 + Name.startswith("avx512.mask.broadcastf") || // Added in 6.0 + Name.startswith("avx512.mask.broadcasti") || // Added in 6.0 Name == "xop.vpcmov" || // Added in 3.8 Name == "xop.vpcmov.256" || // Added in 5.0 Name.startswith("avx512.mask.move.s") || // Added in 4.0 Name.startswith("avx512.cvtmask2") || // Added in 5.0 (Name.startswith("xop.vpcom") && // Added in 3.2 - F->arg_size() == 2)) + F->arg_size() == 2) || + Name.startswith("avx512.ptestm") || //Added in 6.0 + Name.startswith("avx512.ptestnm") || //Added in 6.0 + Name.startswith("sse2.pavg") || // Added in 6.0 + Name.startswith("avx2.pavg") || // Added in 6.0 + Name.startswith("avx512.mask.pavg")) // Added in 6.0 return true; return false; @@ -420,6 +437,14 @@ static bool UpgradeIntrinsicFunction1(Function *F, Function *&NewFn) { } break; } + case 'd': { + if (Name == "dbg.value" && F->arg_size() == 4) { + rename(F); + NewFn = Intrinsic::getDeclaration(F->getParent(), Intrinsic::dbg_value); + return true; + } + break; + } case 'i': case 'l': { bool IsLifetimeStart = Name.startswith("lifetime.start"); @@ -774,6 +799,20 @@ static Value *UpgradeMaskedLoad(IRBuilder<> &Builder, return Builder.CreateMaskedLoad(Ptr, Align, Mask, Passthru); } +static Value *upgradeAbs(IRBuilder<> &Builder, CallInst &CI) { + Value *Op0 = CI.getArgOperand(0); + llvm::Type *Ty = Op0->getType(); + Value *Zero = llvm::Constant::getNullValue(Ty); + Value *Cmp = Builder.CreateICmp(ICmpInst::ICMP_SGT, Op0, Zero); + Value *Neg = Builder.CreateNeg(Op0); + Value *Res = Builder.CreateSelect(Cmp, Op0, Neg); + + if (CI.getNumArgOperands() == 3) + Res = EmitX86Select(Builder,CI.getArgOperand(2), Res, CI.getArgOperand(1)); + + return Res; +} + static Value *upgradeIntMinMax(IRBuilder<> &Builder, CallInst &CI, ICmpInst::Predicate Pred) { Value *Op0 = CI.getArgOperand(0); @@ -787,6 +826,26 @@ static Value *upgradeIntMinMax(IRBuilder<> &Builder, CallInst &CI, return Res; } +// Applying mask on vector of i1's and make sure result is at least 8 bits wide. +static Value *ApplyX86MaskOn1BitsVec(IRBuilder<> &Builder,Value *Vec, Value *Mask, + unsigned NumElts) { + const auto *C = dyn_cast<Constant>(Mask); + if (!C || !C->isAllOnesValue()) + Vec = Builder.CreateAnd(Vec, getX86MaskVec(Builder, Mask, NumElts)); + + if (NumElts < 8) { + uint32_t Indices[8]; + for (unsigned i = 0; i != NumElts; ++i) + Indices[i] = i; + for (unsigned i = NumElts; i != 8; ++i) + Indices[i] = NumElts + i % NumElts; + Vec = Builder.CreateShuffleVector(Vec, + Constant::getNullValue(Vec->getType()), + Indices); + } + return Builder.CreateBitCast(Vec, Builder.getIntNTy(std::max(NumElts, 8U))); +} + static Value *upgradeMaskedCompare(IRBuilder<> &Builder, CallInst &CI, unsigned CC, bool Signed) { Value *Op0 = CI.getArgOperand(0); @@ -812,22 +871,8 @@ static Value *upgradeMaskedCompare(IRBuilder<> &Builder, CallInst &CI, } Value *Mask = CI.getArgOperand(CI.getNumArgOperands() - 1); - const auto *C = dyn_cast<Constant>(Mask); - if (!C || !C->isAllOnesValue()) - Cmp = Builder.CreateAnd(Cmp, getX86MaskVec(Builder, Mask, NumElts)); - if (NumElts < 8) { - uint32_t Indices[8]; - for (unsigned i = 0; i != NumElts; ++i) - Indices[i] = i; - for (unsigned i = NumElts; i != 8; ++i) - Indices[i] = NumElts + i % NumElts; - Cmp = Builder.CreateShuffleVector(Cmp, - Constant::getNullValue(Cmp->getType()), - Indices); - } - return Builder.CreateBitCast(Cmp, IntegerType::get(CI.getContext(), - std::max(NumElts, 8U))); + return ApplyX86MaskOn1BitsVec(Builder, Cmp, Mask, NumElts); } // Replace a masked intrinsic with an older unmasked intrinsic. @@ -991,6 +1036,39 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Rep = Builder.CreateICmp(CmpEq ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_SGT, CI->getArgOperand(0), CI->getArgOperand(1)); Rep = Builder.CreateSExt(Rep, CI->getType(), ""); + } else if (IsX86 && (Name.startswith("avx512.broadcastm"))) { + Type *ExtTy = Type::getInt32Ty(C); + if (CI->getOperand(0)->getType()->isIntegerTy(8)) + ExtTy = Type::getInt64Ty(C); + unsigned NumElts = CI->getType()->getPrimitiveSizeInBits() / + ExtTy->getPrimitiveSizeInBits(); + Rep = Builder.CreateZExt(CI->getArgOperand(0), ExtTy); + Rep = Builder.CreateVectorSplat(NumElts, Rep); + } else if (IsX86 && (Name.startswith("avx512.ptestm") || + Name.startswith("avx512.ptestnm"))) { + Value *Op0 = CI->getArgOperand(0); + Value *Op1 = CI->getArgOperand(1); + Value *Mask = CI->getArgOperand(2); + Rep = Builder.CreateAnd(Op0, Op1); + llvm::Type *Ty = Op0->getType(); + Value *Zero = llvm::Constant::getNullValue(Ty); + ICmpInst::Predicate Pred = + Name.startswith("avx512.ptestm") ? ICmpInst::ICMP_NE : ICmpInst::ICMP_EQ; + Rep = Builder.CreateICmp(Pred, Rep, Zero); + unsigned NumElts = Op0->getType()->getVectorNumElements(); + Rep = ApplyX86MaskOn1BitsVec(Builder, Rep, Mask, NumElts); + } else if (IsX86 && (Name.startswith("avx512.mask.pbroadcast"))){ + unsigned NumElts = + CI->getArgOperand(1)->getType()->getVectorNumElements(); + Rep = Builder.CreateVectorSplat(NumElts, CI->getArgOperand(0)); + Rep = EmitX86Select(Builder, CI->getArgOperand(2), Rep, + CI->getArgOperand(1)); + } else if (IsX86 && (Name.startswith("avx512.kunpck"))) { + uint64_t Shift = CI->getType()->getScalarSizeInBits() / 2; + uint64_t And = (1ULL << Shift) - 1; + Value* LowBits = Builder.CreateAnd(CI->getArgOperand(0), And); + Value* HighBits = Builder.CreateShl(CI->getArgOperand(1), Shift); + Rep = Builder.CreateOr(LowBits, HighBits); } else if (IsX86 && (Name == "sse.add.ss" || Name == "sse2.add.sd")) { Type *I32Ty = Type::getInt32Ty(C); Value *Elt0 = Builder.CreateExtractElement(CI->getArgOperand(0), @@ -1037,6 +1115,12 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { } else if (IsX86 && Name.startswith("avx512.mask.ucmp")) { unsigned Imm = cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue(); Rep = upgradeMaskedCompare(Builder, *CI, Imm, false); + } else if(IsX86 && (Name == "ssse3.pabs.b.128" || + Name == "ssse3.pabs.w.128" || + Name == "ssse3.pabs.d.128" || + Name.startswith("avx2.pabs") || + Name.startswith("avx512.mask.pabs"))) { + Rep = upgradeAbs(Builder, *CI); } else if (IsX86 && (Name == "sse41.pmaxsb" || Name == "sse2.pmaxs.w" || Name == "sse41.pmaxsd" || @@ -1213,6 +1297,43 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { else Rep = Builder.CreateShuffleVector(Load, UndefValue::get(Load->getType()), { 0, 1, 2, 3, 0, 1, 2, 3 }); + } else if (IsX86 && (Name.startswith("avx512.mask.shuf.i") || + Name.startswith("avx512.mask.shuf.f"))) { + unsigned Imm = cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue(); + Type *VT = CI->getType(); + unsigned NumLanes = VT->getPrimitiveSizeInBits() / 128; + unsigned NumElementsInLane = 128 / VT->getScalarSizeInBits(); + unsigned ControlBitsMask = NumLanes - 1; + unsigned NumControlBits = NumLanes / 2; + SmallVector<uint32_t, 8> ShuffleMask(0); + + for (unsigned l = 0; l != NumLanes; ++l) { + unsigned LaneMask = (Imm >> (l * NumControlBits)) & ControlBitsMask; + // We actually need the other source. + if (l >= NumLanes / 2) + LaneMask += NumLanes; + for (unsigned i = 0; i != NumElementsInLane; ++i) + ShuffleMask.push_back(LaneMask * NumElementsInLane + i); + } + Rep = Builder.CreateShuffleVector(CI->getArgOperand(0), + CI->getArgOperand(1), ShuffleMask); + Rep = EmitX86Select(Builder, CI->getArgOperand(4), Rep, + CI->getArgOperand(3)); + }else if (IsX86 && (Name.startswith("avx512.mask.broadcastf") || + Name.startswith("avx512.mask.broadcasti"))) { + unsigned NumSrcElts = + CI->getArgOperand(0)->getType()->getVectorNumElements(); + unsigned NumDstElts = CI->getType()->getVectorNumElements(); + + SmallVector<uint32_t, 8> ShuffleMask(NumDstElts); + for (unsigned i = 0; i != NumDstElts; ++i) + ShuffleMask[i] = i % NumSrcElts; + + Rep = Builder.CreateShuffleVector(CI->getArgOperand(0), + CI->getArgOperand(0), + ShuffleMask); + Rep = EmitX86Select(Builder, CI->getArgOperand(2), Rep, + CI->getArgOperand(1)); } else if (IsX86 && (Name.startswith("avx2.pbroadcast") || Name.startswith("avx2.vbroadcast") || Name.startswith("avx512.pbroadcast") || @@ -1367,6 +1488,42 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { if (CI->getNumArgOperands() == 4) Rep = EmitX86Select(Builder, CI->getArgOperand(3), Rep, CI->getArgOperand(2)); + } else if (IsX86 && (Name.startswith("avx.vperm2f128.") || + Name == "avx2.vperm2i128")) { + // The immediate permute control byte looks like this: + // [1:0] - select 128 bits from sources for low half of destination + // [2] - ignore + // [3] - zero low half of destination + // [5:4] - select 128 bits from sources for high half of destination + // [6] - ignore + // [7] - zero high half of destination + + uint8_t Imm = cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue(); + + unsigned NumElts = CI->getType()->getVectorNumElements(); + unsigned HalfSize = NumElts / 2; + SmallVector<uint32_t, 8> ShuffleMask(NumElts); + + // Determine which operand(s) are actually in use for this instruction. + Value *V0 = (Imm & 0x02) ? CI->getArgOperand(1) : CI->getArgOperand(0); + Value *V1 = (Imm & 0x20) ? CI->getArgOperand(1) : CI->getArgOperand(0); + + // If needed, replace operands based on zero mask. + V0 = (Imm & 0x08) ? ConstantAggregateZero::get(CI->getType()) : V0; + V1 = (Imm & 0x80) ? ConstantAggregateZero::get(CI->getType()) : V1; + + // Permute low half of result. + unsigned StartIndex = (Imm & 0x01) ? HalfSize : 0; + for (unsigned i = 0; i < HalfSize; ++i) + ShuffleMask[i] = StartIndex + i; + + // Permute high half of result. + StartIndex = (Imm & 0x10) ? HalfSize : 0; + for (unsigned i = 0; i < HalfSize; ++i) + ShuffleMask[i + HalfSize] = NumElts + StartIndex + i; + + Rep = Builder.CreateShuffleVector(V0, V1, ShuffleMask); + } else if (IsX86 && (Name.startswith("avx.vpermil.") || Name == "sse2.pshuf.d" || Name.startswith("avx512.mask.vpermil.p") || @@ -1941,6 +2098,25 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { LoadInst *LI = Builder.CreateAlignedLoad(BC, VTy->getBitWidth() / 8); LI->setMetadata(M->getMDKindID("nontemporal"), Node); Rep = LI; + } else if (IsX86 && + (Name.startswith("sse2.pavg") || Name.startswith("avx2.pavg") || + Name.startswith("avx512.mask.pavg"))) { + // llvm.x86.sse2.pavg.b/w, llvm.x86.avx2.pavg.b/w, + // llvm.x86.avx512.mask.pavg.b/w + Value *A = CI->getArgOperand(0); + Value *B = CI->getArgOperand(1); + VectorType *ZextType = VectorType::getExtendedElementVectorType( + cast<VectorType>(A->getType())); + Value *ExtendedA = Builder.CreateZExt(A, ZextType); + Value *ExtendedB = Builder.CreateZExt(B, ZextType); + Value *Sum = Builder.CreateAdd(ExtendedA, ExtendedB); + Value *AddOne = Builder.CreateAdd(Sum, ConstantInt::get(ZextType, 1)); + Value *ShiftR = Builder.CreateLShr(AddOne, ConstantInt::get(ZextType, 1)); + Rep = Builder.CreateTrunc(ShiftR, A->getType()); + if (CI->getNumArgOperands() > 2) { + Rep = EmitX86Select(Builder, CI->getArgOperand(3), Rep, + CI->getArgOperand(2)); + } } else if (IsNVVM && (Name == "abs.i" || Name == "abs.ll")) { Value *Arg = CI->getArgOperand(0); Value *Neg = Builder.CreateNeg(Arg, "neg"); @@ -2055,6 +2231,20 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { NewCall = Builder.CreateCall(NewFn, {CI->getArgOperand(0)}); break; + case Intrinsic::dbg_value: + // Upgrade from the old version that had an extra offset argument. + assert(CI->getNumArgOperands() == 4); + // Drop nonzero offsets instead of attempting to upgrade them. + if (auto *Offset = dyn_cast_or_null<Constant>(CI->getArgOperand(1))) + if (Offset->isZeroValue()) { + NewCall = Builder.CreateCall( + NewFn, + {CI->getArgOperand(0), CI->getArgOperand(2), CI->getArgOperand(3)}); + break; + } + CI->eraseFromParent(); + return; + case Intrinsic::x86_xop_vfrcz_ss: case Intrinsic::x86_xop_vfrcz_sd: NewCall = Builder.CreateCall(NewFn, {CI->getArgOperand(1)}); @@ -2227,15 +2417,26 @@ Value *llvm::UpgradeBitCastExpr(unsigned Opc, Constant *C, Type *DestTy) { /// info. Return true if module is modified. bool llvm::UpgradeDebugInfo(Module &M) { unsigned Version = getDebugMetadataVersionFromModule(M); - if (Version == DEBUG_METADATA_VERSION) - return false; - - bool RetCode = StripDebugInfo(M); - if (RetCode) { + if (Version == DEBUG_METADATA_VERSION) { + bool BrokenDebugInfo = false; + if (verifyModule(M, &llvm::errs(), &BrokenDebugInfo)) + report_fatal_error("Broken module found, compilation aborted!"); + if (!BrokenDebugInfo) + // Everything is ok. + return false; + else { + // Diagnose malformed debug info. + DiagnosticInfoIgnoringInvalidDebugMetadata Diag(M); + M.getContext().diagnose(Diag); + } + } + bool Modified = StripDebugInfo(M); + if (Modified && Version != DEBUG_METADATA_VERSION) { + // Diagnose a version mismatch. DiagnosticInfoDebugMetadataVersion DiagVersion(M, Version); M.getContext().diagnose(DiagVersion); } - return RetCode; + return Modified; } bool llvm::UpgradeModuleFlags(Module &M) { diff --git a/lib/IR/BasicBlock.cpp b/lib/IR/BasicBlock.cpp index 2b780adf6c69..22513924a96d 100644 --- a/lib/IR/BasicBlock.cpp +++ b/lib/IR/BasicBlock.cpp @@ -447,3 +447,16 @@ bool BasicBlock::isLandingPad() const { const LandingPadInst *BasicBlock::getLandingPadInst() const { return dyn_cast<LandingPadInst>(getFirstNonPHI()); } + +Optional<uint64_t> BasicBlock::getIrrLoopHeaderWeight() const { + const TerminatorInst *TI = getTerminator(); + if (MDNode *MDIrrLoopHeader = + TI->getMetadata(LLVMContext::MD_irr_loop)) { + MDString *MDName = cast<MDString>(MDIrrLoopHeader->getOperand(0)); + if (MDName->getString().equals("loop_header_weight")) { + auto *CI = mdconst::extract<ConstantInt>(MDIrrLoopHeader->getOperand(1)); + return Optional<uint64_t>(CI->getValue().getZExtValue()); + } + } + return Optional<uint64_t>(); +} diff --git a/lib/IR/CMakeLists.txt b/lib/IR/CMakeLists.txt index 1cc229d68bfc..17822bbbb5cb 100644 --- a/lib/IR/CMakeLists.txt +++ b/lib/IR/CMakeLists.txt @@ -17,11 +17,11 @@ add_llvm_library(LLVMCore DebugInfo.cpp DebugInfoMetadata.cpp DebugLoc.cpp + DiagnosticHandler.cpp DiagnosticInfo.cpp DiagnosticPrinter.cpp Dominators.cpp Function.cpp - GCOV.cpp GVMaterializer.cpp Globals.cpp IRBuilder.cpp diff --git a/lib/IR/ConstantFold.cpp b/lib/IR/ConstantFold.cpp index 996331e68e83..90b10309b58b 100644 --- a/lib/IR/ConstantFold.cpp +++ b/lib/IR/ConstantFold.cpp @@ -629,6 +629,15 @@ Constant *llvm::ConstantFoldCastInstruction(unsigned opc, Constant *V, if (ConstantExpr *CE = dyn_cast<ConstantExpr>(V)) if (CE->getOpcode() == Instruction::GetElementPtr && CE->getOperand(0)->isNullValue()) { + // FIXME: Looks like getFoldedSizeOf(), getFoldedOffsetOf() and + // getFoldedAlignOf() don't handle the case when DestTy is a vector of + // pointers yet. We end up in asserts in CastInst::getCastOpcode (see + // test/Analysis/ConstantFolding/cast-vector.ll). I've only seen this + // happen in one "real" C-code test case, so it does not seem to be an + // important optimization to handle vectors here. For now, simply bail + // out. + if (DestTy->isVectorTy()) + return nullptr; GEPOperator *GEPO = cast<GEPOperator>(CE); Type *Ty = GEPO->getSourceElementType(); if (CE->getNumOperands() == 2) { @@ -2062,9 +2071,20 @@ Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C, Type *Ty = GetElementPtrInst::getIndexedType(PointeeTy, Idxs); assert(Ty && "Invalid indices for GEP!"); + Type *OrigGEPTy = PointerType::get(Ty, PtrTy->getAddressSpace()); Type *GEPTy = PointerType::get(Ty, PtrTy->getAddressSpace()); if (VectorType *VT = dyn_cast<VectorType>(C->getType())) - GEPTy = VectorType::get(GEPTy, VT->getNumElements()); + GEPTy = VectorType::get(OrigGEPTy, VT->getNumElements()); + + // The GEP returns a vector of pointers when one of more of + // its arguments is a vector. + for (unsigned i = 0, e = Idxs.size(); i != e; ++i) { + if (auto *VT = dyn_cast<VectorType>(Idxs[i]->getType())) { + GEPTy = VectorType::get(OrigGEPTy, VT->getNumElements()); + break; + } + } + return Constant::getNullValue(GEPTy); } } @@ -2190,17 +2210,17 @@ Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C, SmallVector<Constant *, 8> NewIdxs; Type *Ty = PointeeTy; Type *Prev = C->getType(); - bool Unknown = !isa<ConstantInt>(Idxs[0]); + bool Unknown = + !isa<ConstantInt>(Idxs[0]) && !isa<ConstantDataVector>(Idxs[0]); for (unsigned i = 1, e = Idxs.size(); i != e; Prev = Ty, Ty = cast<CompositeType>(Ty)->getTypeAtIndex(Idxs[i]), ++i) { - auto *CI = dyn_cast<ConstantInt>(Idxs[i]); - if (!CI) { + if (!isa<ConstantInt>(Idxs[i]) && !isa<ConstantDataVector>(Idxs[i])) { // We don't know if it's in range or not. Unknown = true; continue; } - if (!isa<ConstantInt>(Idxs[i - 1])) - // FIXME: add the support of cosntant vector index. + if (!isa<ConstantInt>(Idxs[i - 1]) && !isa<ConstantDataVector>(Idxs[i - 1])) + // Skip if the type of the previous index is not supported. continue; if (InRangeIndex && i == *InRangeIndex + 1) { // If an index is marked inrange, we cannot apply this canonicalization to @@ -2218,46 +2238,91 @@ Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C, Unknown = true; continue; } - if (isIndexInRangeOfArrayType(STy->getNumElements(), CI)) - // It's in range, skip to the next index. - continue; + if (ConstantInt *CI = dyn_cast<ConstantInt>(Idxs[i])) { + if (isIndexInRangeOfArrayType(STy->getNumElements(), CI)) + // It's in range, skip to the next index. + continue; + if (CI->getSExtValue() < 0) { + // It's out of range and negative, don't try to factor it. + Unknown = true; + continue; + } + } else { + auto *CV = cast<ConstantDataVector>(Idxs[i]); + bool InRange = true; + for (unsigned I = 0, E = CV->getNumElements(); I != E; ++I) { + auto *CI = cast<ConstantInt>(CV->getElementAsConstant(I)); + InRange &= isIndexInRangeOfArrayType(STy->getNumElements(), CI); + if (CI->getSExtValue() < 0) { + Unknown = true; + break; + } + } + if (InRange || Unknown) + // It's in range, skip to the next index. + // It's out of range and negative, don't try to factor it. + continue; + } if (isa<StructType>(Prev)) { // It's out of range, but the prior dimension is a struct // so we can't do anything about it. Unknown = true; continue; } - if (CI->getSExtValue() < 0) { - // It's out of range and negative, don't try to factor it. - Unknown = true; - continue; - } // It's out of range, but we can factor it into the prior // dimension. NewIdxs.resize(Idxs.size()); // Determine the number of elements in our sequential type. uint64_t NumElements = STy->getArrayNumElements(); - ConstantInt *Factor = ConstantInt::get(CI->getType(), NumElements); - NewIdxs[i] = ConstantExpr::getSRem(CI, Factor); + // Expand the current index or the previous index to a vector from a scalar + // if necessary. + Constant *CurrIdx = cast<Constant>(Idxs[i]); + auto *PrevIdx = + NewIdxs[i - 1] ? NewIdxs[i - 1] : cast<Constant>(Idxs[i - 1]); + bool IsCurrIdxVector = CurrIdx->getType()->isVectorTy(); + bool IsPrevIdxVector = PrevIdx->getType()->isVectorTy(); + bool UseVector = IsCurrIdxVector || IsPrevIdxVector; + + if (!IsCurrIdxVector && IsPrevIdxVector) + CurrIdx = ConstantDataVector::getSplat( + PrevIdx->getType()->getVectorNumElements(), CurrIdx); - Constant *PrevIdx = NewIdxs[i-1] ? NewIdxs[i-1] : - cast<Constant>(Idxs[i - 1]); - Constant *Div = ConstantExpr::getSDiv(CI, Factor); + if (!IsPrevIdxVector && IsCurrIdxVector) + PrevIdx = ConstantDataVector::getSplat( + CurrIdx->getType()->getVectorNumElements(), PrevIdx); + + Constant *Factor = + ConstantInt::get(CurrIdx->getType()->getScalarType(), NumElements); + if (UseVector) + Factor = ConstantDataVector::getSplat( + IsPrevIdxVector ? PrevIdx->getType()->getVectorNumElements() + : CurrIdx->getType()->getVectorNumElements(), + Factor); + + NewIdxs[i] = ConstantExpr::getSRem(CurrIdx, Factor); + + Constant *Div = ConstantExpr::getSDiv(CurrIdx, Factor); unsigned CommonExtendedWidth = - std::max(PrevIdx->getType()->getIntegerBitWidth(), - Div->getType()->getIntegerBitWidth()); + std::max(PrevIdx->getType()->getScalarSizeInBits(), + Div->getType()->getScalarSizeInBits()); CommonExtendedWidth = std::max(CommonExtendedWidth, 64U); // Before adding, extend both operands to i64 to avoid // overflow trouble. - if (!PrevIdx->getType()->isIntegerTy(CommonExtendedWidth)) - PrevIdx = ConstantExpr::getSExt( - PrevIdx, Type::getIntNTy(Div->getContext(), CommonExtendedWidth)); - if (!Div->getType()->isIntegerTy(CommonExtendedWidth)) - Div = ConstantExpr::getSExt( - Div, Type::getIntNTy(Div->getContext(), CommonExtendedWidth)); + Type *ExtendedTy = Type::getIntNTy(Div->getContext(), CommonExtendedWidth); + if (UseVector) + ExtendedTy = VectorType::get( + ExtendedTy, IsPrevIdxVector + ? PrevIdx->getType()->getVectorNumElements() + : CurrIdx->getType()->getVectorNumElements()); + + if (!PrevIdx->getType()->isIntOrIntVectorTy(CommonExtendedWidth)) + PrevIdx = ConstantExpr::getSExt(PrevIdx, ExtendedTy); + + if (!Div->getType()->isIntOrIntVectorTy(CommonExtendedWidth)) + Div = ConstantExpr::getSExt(Div, ExtendedTy); NewIdxs[i - 1] = ConstantExpr::getAdd(PrevIdx, Div); } diff --git a/lib/IR/ConstantRange.cpp b/lib/IR/ConstantRange.cpp index 4bd17257016d..48d16f334ba3 100644 --- a/lib/IR/ConstantRange.cpp +++ b/lib/IR/ConstantRange.cpp @@ -199,39 +199,63 @@ ConstantRange::makeGuaranteedNoWrapRegion(Instruction::BinaryOps BinOp, "NoWrapKind invalid!"); unsigned BitWidth = Other.getBitWidth(); - if (BinOp != Instruction::Add) - // Conservative answer: empty set - return ConstantRange(BitWidth, false); - - if (auto *C = Other.getSingleElement()) - if (C->isNullValue()) - // Full set: nothing signed / unsigned wraps when added to 0. - return ConstantRange(BitWidth); - ConstantRange Result(BitWidth); - if (NoWrapKind & OBO::NoUnsignedWrap) - Result = - SubsetIntersect(Result, ConstantRange(APInt::getNullValue(BitWidth), - -Other.getUnsignedMax())); - - if (NoWrapKind & OBO::NoSignedWrap) { - const APInt &SignedMin = Other.getSignedMin(); - const APInt &SignedMax = Other.getSignedMax(); + switch (BinOp) { + default: + // Conservative answer: empty set + return ConstantRange(BitWidth, false); - if (SignedMax.isStrictlyPositive()) - Result = SubsetIntersect( - Result, - ConstantRange(APInt::getSignedMinValue(BitWidth), - APInt::getSignedMinValue(BitWidth) - SignedMax)); + case Instruction::Add: + if (auto *C = Other.getSingleElement()) + if (C->isNullValue()) + // Full set: nothing signed / unsigned wraps when added to 0. + return ConstantRange(BitWidth); + if (NoWrapKind & OBO::NoUnsignedWrap) + Result = + SubsetIntersect(Result, ConstantRange(APInt::getNullValue(BitWidth), + -Other.getUnsignedMax())); + if (NoWrapKind & OBO::NoSignedWrap) { + const APInt &SignedMin = Other.getSignedMin(); + const APInt &SignedMax = Other.getSignedMax(); + if (SignedMax.isStrictlyPositive()) + Result = SubsetIntersect( + Result, + ConstantRange(APInt::getSignedMinValue(BitWidth), + APInt::getSignedMinValue(BitWidth) - SignedMax)); + if (SignedMin.isNegative()) + Result = SubsetIntersect( + Result, + ConstantRange(APInt::getSignedMinValue(BitWidth) - SignedMin, + APInt::getSignedMinValue(BitWidth))); + } + return Result; - if (SignedMin.isNegative()) - Result = SubsetIntersect( - Result, ConstantRange(APInt::getSignedMinValue(BitWidth) - SignedMin, - APInt::getSignedMinValue(BitWidth))); + case Instruction::Sub: + if (auto *C = Other.getSingleElement()) + if (C->isNullValue()) + // Full set: nothing signed / unsigned wraps when subtracting 0. + return ConstantRange(BitWidth); + if (NoWrapKind & OBO::NoUnsignedWrap) + Result = + SubsetIntersect(Result, ConstantRange(Other.getUnsignedMax(), + APInt::getMinValue(BitWidth))); + if (NoWrapKind & OBO::NoSignedWrap) { + const APInt &SignedMin = Other.getSignedMin(); + const APInt &SignedMax = Other.getSignedMax(); + if (SignedMax.isStrictlyPositive()) + Result = SubsetIntersect( + Result, + ConstantRange(APInt::getSignedMinValue(BitWidth) + SignedMax, + APInt::getSignedMinValue(BitWidth))); + if (SignedMin.isNegative()) + Result = SubsetIntersect( + Result, + ConstantRange(APInt::getSignedMinValue(BitWidth), + APInt::getSignedMinValue(BitWidth) + SignedMin)); + } + return Result; } - - return Result; } bool ConstantRange::isFullSet() const { @@ -656,6 +680,8 @@ ConstantRange ConstantRange::binaryOp(Instruction::BinaryOps BinOp, return shl(Other); case Instruction::LShr: return lshr(Other); + case Instruction::AShr: + return ashr(Other); case Instruction::And: return binaryAnd(Other); case Instruction::Or: @@ -922,6 +948,60 @@ ConstantRange::lshr(const ConstantRange &Other) const { return ConstantRange(std::move(min), std::move(max)); } +ConstantRange +ConstantRange::ashr(const ConstantRange &Other) const { + if (isEmptySet() || Other.isEmptySet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/false); + + // May straddle zero, so handle both positive and negative cases. + // 'PosMax' is the upper bound of the result of the ashr + // operation, when Upper of the LHS of ashr is a non-negative. + // number. Since ashr of a non-negative number will result in a + // smaller number, the Upper value of LHS is shifted right with + // the minimum value of 'Other' instead of the maximum value. + APInt PosMax = getSignedMax().ashr(Other.getUnsignedMin()) + 1; + + // 'PosMin' is the lower bound of the result of the ashr + // operation, when Lower of the LHS is a non-negative number. + // Since ashr of a non-negative number will result in a smaller + // number, the Lower value of LHS is shifted right with the + // maximum value of 'Other'. + APInt PosMin = getSignedMin().ashr(Other.getUnsignedMax()); + + // 'NegMax' is the upper bound of the result of the ashr + // operation, when Upper of the LHS of ashr is a negative number. + // Since 'ashr' of a negative number will result in a bigger + // number, the Upper value of LHS is shifted right with the + // maximum value of 'Other'. + APInt NegMax = getSignedMax().ashr(Other.getUnsignedMax()) + 1; + + // 'NegMin' is the lower bound of the result of the ashr + // operation, when Lower of the LHS of ashr is a negative number. + // Since 'ashr' of a negative number will result in a bigger + // number, the Lower value of LHS is shifted right with the + // minimum value of 'Other'. + APInt NegMin = getSignedMin().ashr(Other.getUnsignedMin()); + + APInt max, min; + if (getSignedMin().isNonNegative()) { + // Upper and Lower of LHS are non-negative. + min = PosMin; + max = PosMax; + } else if (getSignedMax().isNegative()) { + // Upper and Lower of LHS are negative. + min = NegMin; + max = NegMax; + } else { + // Upper is non-negative and Lower is negative. + min = NegMin; + max = PosMax; + } + if (min == max) + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + + return ConstantRange(std::move(min), std::move(max)); +} + ConstantRange ConstantRange::inverse() const { if (isFullSet()) return ConstantRange(getBitWidth(), /*isFullSet=*/false); diff --git a/lib/IR/Constants.cpp b/lib/IR/Constants.cpp index f56fe7089807..dccba779deb3 100644 --- a/lib/IR/Constants.cpp +++ b/lib/IR/Constants.cpp @@ -16,7 +16,6 @@ #include "LLVMContextImpl.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/GetElementPtrTypeIterator.h" diff --git a/lib/IR/Core.cpp b/lib/IR/Core.cpp index aba770457e2f..d3c33edec186 100644 --- a/lib/IR/Core.cpp +++ b/lib/IR/Core.cpp @@ -85,15 +85,15 @@ LLVMContextRef LLVMGetGlobalContext() { return wrap(&*GlobalContext); } void LLVMContextSetDiagnosticHandler(LLVMContextRef C, LLVMDiagnosticHandler Handler, void *DiagnosticContext) { - unwrap(C)->setDiagnosticHandler( - LLVM_EXTENSION reinterpret_cast<LLVMContext::DiagnosticHandlerTy>( + unwrap(C)->setDiagnosticHandlerCallBack( + LLVM_EXTENSION reinterpret_cast<DiagnosticHandler::DiagnosticHandlerTy>( Handler), DiagnosticContext); } LLVMDiagnosticHandler LLVMContextGetDiagnosticHandler(LLVMContextRef C) { return LLVM_EXTENSION reinterpret_cast<LLVMDiagnosticHandler>( - unwrap(C)->getDiagnosticHandler()); + unwrap(C)->getDiagnosticHandlerCallBack()); } void *LLVMContextGetDiagnosticContext(LLVMContextRef C) { @@ -276,7 +276,8 @@ LLVMBool LLVMPrintModuleToFile(LLVMModuleRef M, const char *Filename, dest.close(); if (dest.has_error()) { - *ErrorMessage = strdup("Error printing to file"); + std::string E = "Error printing to file: " + dest.error().message(); + *ErrorMessage = strdup(E.c_str()); return true; } @@ -451,9 +452,6 @@ LLVMTypeRef LLVMPPCFP128TypeInContext(LLVMContextRef C) { LLVMTypeRef LLVMX86MMXTypeInContext(LLVMContextRef C) { return (LLVMTypeRef) Type::getX86_MMXTy(*unwrap(C)); } -LLVMTypeRef LLVMTokenTypeInContext(LLVMContextRef C) { - return (LLVMTypeRef) Type::getTokenTy(*unwrap(C)); -} LLVMTypeRef LLVMHalfType(void) { return LLVMHalfTypeInContext(LLVMGetGlobalContext()); @@ -619,6 +617,12 @@ LLVMTypeRef LLVMVoidTypeInContext(LLVMContextRef C) { LLVMTypeRef LLVMLabelTypeInContext(LLVMContextRef C) { return wrap(Type::getLabelTy(*unwrap(C))); } +LLVMTypeRef LLVMTokenTypeInContext(LLVMContextRef C) { + return wrap(Type::getTokenTy(*unwrap(C))); +} +LLVMTypeRef LLVMMetadataTypeInContext(LLVMContextRef C) { + return wrap(Type::getMetadataTy(*unwrap(C))); +} LLVMTypeRef LLVMVoidType(void) { return LLVMVoidTypeInContext(LLVMGetGlobalContext()); diff --git a/lib/IR/DIBuilder.cpp b/lib/IR/DIBuilder.cpp index bce28ba3b950..a00c595d01c5 100644 --- a/lib/IR/DIBuilder.cpp +++ b/lib/IR/DIBuilder.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/DIBuilder.h" +#include "llvm/IR/IRBuilder.h" #include "LLVMContextImpl.h" #include "llvm/ADT/STLExtras.h" #include "llvm/BinaryFormat/Dwarf.h" @@ -24,6 +25,11 @@ using namespace llvm; using namespace llvm::dwarf; +cl::opt<bool> + UseDbgAddr("use-dbg-addr", + llvm::cl::desc("Use llvm.dbg.addr for all local variables"), + cl::init(false), cl::Hidden); + DIBuilder::DIBuilder(Module &m, bool AllowUnresolvedNodes) : M(m), VMContext(M.getContext()), CUNode(nullptr), DeclareFn(nullptr), ValueFn(nullptr), @@ -127,7 +133,7 @@ DICompileUnit *DIBuilder::createCompileUnit( unsigned Lang, DIFile *File, StringRef Producer, bool isOptimized, StringRef Flags, unsigned RunTimeVer, StringRef SplitName, DICompileUnit::DebugEmissionKind Kind, uint64_t DWOId, - bool SplitDebugInlining, bool DebugInfoForProfiling) { + bool SplitDebugInlining, bool DebugInfoForProfiling, bool GnuPubnames) { assert(((Lang <= dwarf::DW_LANG_Fortran08 && Lang >= dwarf::DW_LANG_C89) || (Lang <= dwarf::DW_LANG_hi_user && Lang >= dwarf::DW_LANG_lo_user)) && @@ -137,7 +143,7 @@ DICompileUnit *DIBuilder::createCompileUnit( CUNode = DICompileUnit::getDistinct( VMContext, Lang, File, Producer, isOptimized, Flags, RunTimeVer, SplitName, Kind, nullptr, nullptr, nullptr, nullptr, nullptr, DWOId, - SplitDebugInlining, DebugInfoForProfiling); + SplitDebugInlining, DebugInfoForProfiling, GnuPubnames); // Create a named metadata so that it is easier to find cu in a module. NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.cu"); @@ -595,6 +601,8 @@ DIGlobalVariableExpression *DIBuilder::createGlobalVariableExpression( VMContext, cast_or_null<DIScope>(Context), Name, LinkageName, F, LineNumber, Ty, isLocalToUnit, true, cast_or_null<DIDerivedType>(Decl), AlignInBits); + if (!Expr) + Expr = createExpression(); auto *N = DIGlobalVariableExpression::get(VMContext, GV, Expr); AllGVs.push_back(N); return N; @@ -668,12 +676,6 @@ DIExpression *DIBuilder::createExpression(ArrayRef<int64_t> Signed) { return createExpression(Addr); } -DIExpression *DIBuilder::createFragmentExpression(unsigned OffsetInBytes, - unsigned SizeInBytes) { - uint64_t Addr[] = {dwarf::DW_OP_LLVM_fragment, OffsetInBytes, SizeInBytes}; - return DIExpression::get(VMContext, Addr); -} - template <class... Ts> static DISubprogram *getSubprogram(bool IsDistinct, Ts &&... Args) { if (IsDistinct) @@ -770,87 +772,88 @@ DILexicalBlock *DIBuilder::createLexicalBlock(DIScope *Scope, DIFile *File, File, Line, Col); } -static Value *getDbgIntrinsicValueImpl(LLVMContext &VMContext, Value *V) { - assert(V && "no value passed to dbg intrinsic"); - return MetadataAsValue::get(VMContext, ValueAsMetadata::get(V)); -} - -static Instruction *withDebugLoc(Instruction *I, const DILocation *DL) { - I->setDebugLoc(const_cast<DILocation *>(DL)); - return I; -} - Instruction *DIBuilder::insertDeclare(Value *Storage, DILocalVariable *VarInfo, DIExpression *Expr, const DILocation *DL, Instruction *InsertBefore) { - assert(VarInfo && "empty or invalid DILocalVariable* passed to dbg.declare"); - assert(DL && "Expected debug loc"); - assert(DL->getScope()->getSubprogram() == - VarInfo->getScope()->getSubprogram() && - "Expected matching subprograms"); - if (!DeclareFn) - DeclareFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_declare); - - trackIfUnresolved(VarInfo); - trackIfUnresolved(Expr); - Value *Args[] = {getDbgIntrinsicValueImpl(VMContext, Storage), - MetadataAsValue::get(VMContext, VarInfo), - MetadataAsValue::get(VMContext, Expr)}; - return withDebugLoc(CallInst::Create(DeclareFn, Args, "", InsertBefore), DL); + return insertDeclare(Storage, VarInfo, Expr, DL, InsertBefore->getParent(), + InsertBefore); } Instruction *DIBuilder::insertDeclare(Value *Storage, DILocalVariable *VarInfo, DIExpression *Expr, const DILocation *DL, BasicBlock *InsertAtEnd) { - assert(VarInfo && "empty or invalid DILocalVariable* passed to dbg.declare"); - assert(DL && "Expected debug loc"); - assert(DL->getScope()->getSubprogram() == - VarInfo->getScope()->getSubprogram() && - "Expected matching subprograms"); - if (!DeclareFn) - DeclareFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_declare); - - trackIfUnresolved(VarInfo); - trackIfUnresolved(Expr); - Value *Args[] = {getDbgIntrinsicValueImpl(VMContext, Storage), - MetadataAsValue::get(VMContext, VarInfo), - MetadataAsValue::get(VMContext, Expr)}; - - // If this block already has a terminator then insert this intrinsic - // before the terminator. - if (TerminatorInst *T = InsertAtEnd->getTerminator()) - return withDebugLoc(CallInst::Create(DeclareFn, Args, "", T), DL); - return withDebugLoc(CallInst::Create(DeclareFn, Args, "", InsertAtEnd), DL); + // If this block already has a terminator then insert this intrinsic before + // the terminator. Otherwise, put it at the end of the block. + Instruction *InsertBefore = InsertAtEnd->getTerminator(); + return insertDeclare(Storage, VarInfo, Expr, DL, InsertAtEnd, InsertBefore); } -Instruction *DIBuilder::insertDbgValueIntrinsic(Value *V, uint64_t Offset, +Instruction *DIBuilder::insertDbgValueIntrinsic(Value *V, DILocalVariable *VarInfo, DIExpression *Expr, const DILocation *DL, Instruction *InsertBefore) { - assert(V && "no value passed to dbg.value"); - assert(VarInfo && "empty or invalid DILocalVariable* passed to dbg.value"); + return insertDbgValueIntrinsic( + V, VarInfo, Expr, DL, InsertBefore ? InsertBefore->getParent() : nullptr, + InsertBefore); +} + +Instruction *DIBuilder::insertDbgValueIntrinsic(Value *V, + DILocalVariable *VarInfo, + DIExpression *Expr, + const DILocation *DL, + BasicBlock *InsertAtEnd) { + return insertDbgValueIntrinsic(V, VarInfo, Expr, DL, InsertAtEnd, nullptr); +} + +/// Return an IRBuilder for inserting dbg.declare and dbg.value intrinsics. This +/// abstracts over the various ways to specify an insert position. +static IRBuilder<> getIRBForDbgInsertion(const DILocation *DL, + BasicBlock *InsertBB, + Instruction *InsertBefore) { + IRBuilder<> B(DL->getContext()); + if (InsertBefore) + B.SetInsertPoint(InsertBefore); + else if (InsertBB) + B.SetInsertPoint(InsertBB); + B.SetCurrentDebugLocation(DL); + return B; +} + +static Value *getDbgIntrinsicValueImpl(LLVMContext &VMContext, Value *V) { + assert(V && "no value passed to dbg intrinsic"); + return MetadataAsValue::get(VMContext, ValueAsMetadata::get(V)); +} + +static Function *getDeclareIntrin(Module &M) { + return Intrinsic::getDeclaration(&M, UseDbgAddr ? Intrinsic::dbg_addr + : Intrinsic::dbg_declare); +} + +Instruction *DIBuilder::insertDeclare(Value *Storage, DILocalVariable *VarInfo, + DIExpression *Expr, const DILocation *DL, + BasicBlock *InsertBB, Instruction *InsertBefore) { + assert(VarInfo && "empty or invalid DILocalVariable* passed to dbg.declare"); assert(DL && "Expected debug loc"); assert(DL->getScope()->getSubprogram() == VarInfo->getScope()->getSubprogram() && "Expected matching subprograms"); - if (!ValueFn) - ValueFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_value); + if (!DeclareFn) + DeclareFn = getDeclareIntrin(M); trackIfUnresolved(VarInfo); trackIfUnresolved(Expr); - Value *Args[] = {getDbgIntrinsicValueImpl(VMContext, V), - ConstantInt::get(Type::getInt64Ty(VMContext), Offset), + Value *Args[] = {getDbgIntrinsicValueImpl(VMContext, Storage), MetadataAsValue::get(VMContext, VarInfo), MetadataAsValue::get(VMContext, Expr)}; - return withDebugLoc(CallInst::Create(ValueFn, Args, "", InsertBefore), DL); + + IRBuilder<> B = getIRBForDbgInsertion(DL, InsertBB, InsertBefore); + return B.CreateCall(DeclareFn, Args); } -Instruction *DIBuilder::insertDbgValueIntrinsic(Value *V, uint64_t Offset, - DILocalVariable *VarInfo, - DIExpression *Expr, - const DILocation *DL, - BasicBlock *InsertAtEnd) { +Instruction *DIBuilder::insertDbgValueIntrinsic( + Value *V, DILocalVariable *VarInfo, DIExpression *Expr, + const DILocation *DL, BasicBlock *InsertBB, Instruction *InsertBefore) { assert(V && "no value passed to dbg.value"); assert(VarInfo && "empty or invalid DILocalVariable* passed to dbg.value"); assert(DL && "Expected debug loc"); @@ -863,15 +866,15 @@ Instruction *DIBuilder::insertDbgValueIntrinsic(Value *V, uint64_t Offset, trackIfUnresolved(VarInfo); trackIfUnresolved(Expr); Value *Args[] = {getDbgIntrinsicValueImpl(VMContext, V), - ConstantInt::get(Type::getInt64Ty(VMContext), Offset), MetadataAsValue::get(VMContext, VarInfo), MetadataAsValue::get(VMContext, Expr)}; - return withDebugLoc(CallInst::Create(ValueFn, Args, "", InsertAtEnd), DL); + IRBuilder<> B = getIRBForDbgInsertion(DL, InsertBB, InsertBefore); + return B.CreateCall(ValueFn, Args); } void DIBuilder::replaceVTableHolder(DICompositeType *&T, - DICompositeType *VTableHolder) { + DIType *VTableHolder) { { TypedTrackingMDRef<DICompositeType> N(T); N->replaceVTableHolder(VTableHolder); diff --git a/lib/IR/DataLayout.cpp b/lib/IR/DataLayout.cpp index 5de281a95237..f4dddeb30d0b 100644 --- a/lib/IR/DataLayout.cpp +++ b/lib/IR/DataLayout.cpp @@ -572,6 +572,8 @@ const StructLayout *DataLayout::getStructLayout(StructType *Ty) const { int NumElts = Ty->getNumElements(); StructLayout *L = (StructLayout *)malloc(sizeof(StructLayout)+(NumElts-1) * sizeof(uint64_t)); + if (L == nullptr) + report_bad_alloc_error("Allocation of StructLayout elements failed."); // Set SL before calling StructLayout's ctor. The ctor could cause other // entries to be added to TheMap, invalidating our reference. diff --git a/lib/IR/DebugInfo.cpp b/lib/IR/DebugInfo.cpp index 56cec57a4d07..7fff7526b926 100644 --- a/lib/IR/DebugInfo.cpp +++ b/lib/IR/DebugInfo.cpp @@ -12,10 +12,11 @@ // //===----------------------------------------------------------------------===// -#include "llvm/IR/DebugInfo.h" +#include "llvm-c/DebugInfo.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/None.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -23,6 +24,8 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/DIBuilder.h" #include "llvm/IR/Function.h" #include "llvm/IR/GVMaterializer.h" #include "llvm/IR/Instruction.h" @@ -290,7 +293,7 @@ static MDNode *stripDebugLocFromLoopID(MDNode *N) { bool llvm::stripDebugInfo(Function &F) { bool Changed = false; - if (F.getSubprogram()) { + if (F.getMetadata(LLVMContext::MD_dbg)) { Changed = true; F.setSubprogram(nullptr); } @@ -311,6 +314,9 @@ bool llvm::stripDebugInfo(Function &F) { } auto *TermInst = BB.getTerminator(); + if (!TermInst) + // This is invalid IR, but we may not have run the verifier yet + continue; if (auto *LoopID = TermInst->getMetadata(LLVMContext::MD_loop)) { auto *NewLoopID = LoopIDsMap.lookup(LoopID); if (!NewLoopID) @@ -470,7 +476,7 @@ private: CU->getSplitDebugFilename(), DICompileUnit::LineTablesOnly, EnumTypes, RetainedTypes, GlobalVariables, ImportedEntities, CU->getMacros(), CU->getDWOId(), CU->getSplitDebugInlining(), - CU->getDebugInfoForProfiling()); + CU->getDebugInfoForProfiling(), CU->getGnuPubnames()); } DILocation *getReplacementMDLocation(DILocation *MLD) { @@ -666,3 +672,84 @@ unsigned llvm::getDebugMetadataVersionFromModule(const Module &M) { return Val->getZExtValue(); return 0; } + +void Instruction::applyMergedLocation(const DILocation *LocA, + const DILocation *LocB) { + setDebugLoc(DILocation::getMergedLocation(LocA, LocB, this)); +} + +//===----------------------------------------------------------------------===// +// LLVM C API implementations. +//===----------------------------------------------------------------------===// + +static unsigned map_from_llvmDWARFsourcelanguage(LLVMDWARFSourceLanguage lang) { + switch (lang) { +#define HANDLE_DW_LANG(ID, NAME, VERSION, VENDOR) \ +case LLVMDWARFSourceLanguage##NAME: return ID; +#include "llvm/BinaryFormat/Dwarf.def" +#undef HANDLE_DW_LANG + } + llvm_unreachable("Unhandled Tag"); +} + +unsigned LLVMDebugMetadataVersion() { + return DEBUG_METADATA_VERSION; +} + +LLVMDIBuilderRef LLVMCreateDIBuilderDisallowUnresolved(LLVMModuleRef M) { + return wrap(new DIBuilder(*unwrap(M), false)); +} + +LLVMDIBuilderRef LLVMCreateDIBuilder(LLVMModuleRef M) { + return wrap(new DIBuilder(*unwrap(M))); +} + +unsigned LLVMGetModuleDebugMetadataVersion(LLVMModuleRef M) { + return getDebugMetadataVersionFromModule(*unwrap(M)); +} + +LLVMBool LLVMStripModuleDebugInfo(LLVMModuleRef M) { + return StripDebugInfo(*unwrap(M)); +} + +void LLVMDisposeDIBuilder(LLVMDIBuilderRef Builder) { + delete unwrap(Builder); +} + +void LLVMDIBuilderFinalize(LLVMDIBuilderRef Builder) { + unwrap(Builder)->finalize(); +} + +LLVMMetadataRef LLVMDIBuilderCreateCompileUnit( + LLVMDIBuilderRef Builder, LLVMDWARFSourceLanguage Lang, + LLVMMetadataRef FileRef, const char *Producer, size_t ProducerLen, + LLVMBool isOptimized, const char *Flags, size_t FlagsLen, + unsigned RuntimeVer, const char *SplitName, size_t SplitNameLen, + LLVMDWARFEmissionKind Kind, unsigned DWOId, LLVMBool SplitDebugInlining, + LLVMBool DebugInfoForProfiling) { + auto File = unwrap<DIFile>(FileRef); + + return wrap(unwrap(Builder)->createCompileUnit( + map_from_llvmDWARFsourcelanguage(Lang), File, + StringRef(Producer, ProducerLen), isOptimized, + StringRef(Flags, FlagsLen), RuntimeVer, + StringRef(SplitName, SplitNameLen), + static_cast<DICompileUnit::DebugEmissionKind>(Kind), DWOId, + SplitDebugInlining, DebugInfoForProfiling)); +} + +LLVMMetadataRef +LLVMDIBuilderCreateFile(LLVMDIBuilderRef Builder, const char *Filename, + size_t FilenameLen, const char *Directory, + size_t DirectoryLen) { + return wrap(unwrap(Builder)->createFile(StringRef(Filename, FilenameLen), + StringRef(Directory, DirectoryLen))); +} + +LLVMMetadataRef +LLVMDIBuilderCreateDebugLocation(LLVMContextRef Ctx, unsigned Line, + unsigned Column, LLVMMetadataRef Scope, + LLVMMetadataRef InlinedAt) { + return wrap(DILocation::get(*unwrap(Ctx), Line, Column, unwrap(Scope), + unwrap(InlinedAt))); +} diff --git a/lib/IR/DebugInfoMetadata.cpp b/lib/IR/DebugInfoMetadata.cpp index c14940bad45d..75ddd47b2591 100644 --- a/lib/IR/DebugInfoMetadata.cpp +++ b/lib/IR/DebugInfoMetadata.cpp @@ -14,9 +14,11 @@ #include "llvm/IR/DebugInfoMetadata.h" #include "LLVMContextImpl.h" #include "MetadataImpl.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" using namespace llvm; @@ -66,6 +68,31 @@ DILocation *DILocation::getImpl(LLVMContext &Context, unsigned Line, Storage, Context.pImpl->DILocations); } +const DILocation * +DILocation::getMergedLocation(const DILocation *LocA, const DILocation *LocB, + const Instruction *ForInst) { + if (!LocA || !LocB) + return nullptr; + + if (LocA == LocB || !LocA->canDiscriminate(*LocB)) + return LocA; + + if (!dyn_cast_or_null<CallInst>(ForInst)) + return nullptr; + + SmallPtrSet<DILocation *, 5> InlinedLocationsA; + for (DILocation *L = LocA->getInlinedAt(); L; L = L->getInlinedAt()) + InlinedLocationsA.insert(L); + const DILocation *Result = LocB; + for (DILocation *L = LocB->getInlinedAt(); L; L = L->getInlinedAt()) { + Result = L; + if (InlinedLocationsA.count(L)) + break; + } + return DILocation::get(Result->getContext(), 0, 0, Result->getScope(), + Result->getInlinedAt()); +} + DINode::DIFlags DINode::getFlag(StringRef Flag) { return StringSwitch<DIFlags>(Flag) #define HANDLE_DI_FLAG(ID, NAME) .Case("DIFlag" #NAME, Flag##NAME) @@ -354,6 +381,8 @@ DISubroutineType *DISubroutineType::getImpl(LLVMContext &Context, DIFlags Flags, DEFINE_GETIMPL_STORE(DISubroutineType, (Flags, CC), Ops); } +// FIXME: Implement this string-enum correspondence with a .def file and macros, +// so that the association is explicit rather than implied. static const char *ChecksumKindName[DIFile::CSK_Last + 1] = { "CSK_None", "CSK_MD5", @@ -391,7 +420,7 @@ DICompileUnit *DICompileUnit::getImpl( unsigned EmissionKind, Metadata *EnumTypes, Metadata *RetainedTypes, Metadata *GlobalVariables, Metadata *ImportedEntities, Metadata *Macros, uint64_t DWOId, bool SplitDebugInlining, bool DebugInfoForProfiling, - StorageType Storage, bool ShouldCreate) { + bool GnuPubnames, StorageType Storage, bool ShouldCreate) { assert(Storage != Uniqued && "Cannot unique DICompileUnit"); assert(isCanonical(Producer) && "Expected canonical MDString"); assert(isCanonical(Flags) && "Expected canonical MDString"); @@ -401,11 +430,10 @@ DICompileUnit *DICompileUnit::getImpl( File, Producer, Flags, SplitDebugFilename, EnumTypes, RetainedTypes, GlobalVariables, ImportedEntities, Macros}; - return storeImpl(new (array_lengthof(Ops)) - DICompileUnit(Context, Storage, SourceLanguage, - IsOptimized, RuntimeVersion, EmissionKind, - DWOId, SplitDebugInlining, - DebugInfoForProfiling, Ops), + return storeImpl(new (array_lengthof(Ops)) DICompileUnit( + Context, Storage, SourceLanguage, IsOptimized, + RuntimeVersion, EmissionKind, DWOId, SplitDebugInlining, + DebugInfoForProfiling, GnuPubnames, Ops), Storage); } @@ -586,6 +614,29 @@ DILocalVariable *DILocalVariable::getImpl(LLVMContext &Context, Metadata *Scope, DEFINE_GETIMPL_STORE(DILocalVariable, (Line, Arg, Flags, AlignInBits), Ops); } +Optional<uint64_t> DIVariable::getSizeInBits() const { + // This is used by the Verifier so be mindful of broken types. + const Metadata *RawType = getRawType(); + while (RawType) { + // Try to get the size directly. + if (auto *T = dyn_cast<DIType>(RawType)) + if (uint64_t Size = T->getSizeInBits()) + return Size; + + if (auto *DT = dyn_cast<DIDerivedType>(RawType)) { + // Look at the base type. + RawType = DT->getRawBaseType(); + continue; + } + + // Missing type or size. + break; + } + + // Fail gracefully. + return None; +} + DIExpression *DIExpression::getImpl(LLVMContext &Context, ArrayRef<uint64_t> Elements, StorageType Storage, bool ShouldCreate) { @@ -643,6 +694,7 @@ bool DIExpression::isValid() const { case dwarf::DW_OP_plus_uconst: case dwarf::DW_OP_plus: case dwarf::DW_OP_minus: + case dwarf::DW_OP_mul: case dwarf::DW_OP_deref: case dwarf::DW_OP_xderef: break; @@ -698,12 +750,17 @@ bool DIExpression::extractIfOffset(int64_t &Offset) const { return false; } -DIExpression *DIExpression::prepend(const DIExpression *Expr, bool Deref, - int64_t Offset, bool StackValue) { +DIExpression *DIExpression::prepend(const DIExpression *Expr, bool DerefBefore, + int64_t Offset, bool DerefAfter, + bool StackValue) { SmallVector<uint64_t, 8> Ops; + if (DerefBefore) + Ops.push_back(dwarf::DW_OP_deref); + appendOffset(Ops, Offset); - if (Deref) + if (DerefAfter) Ops.push_back(dwarf::DW_OP_deref); + if (Expr) for (auto Op : Expr->expr_ops()) { // A DW_OP_stack_value comes at the end, but before a DW_OP_LLVM_fragment. @@ -724,6 +781,44 @@ DIExpression *DIExpression::prepend(const DIExpression *Expr, bool Deref, return DIExpression::get(Expr->getContext(), Ops); } +Optional<DIExpression *> DIExpression::createFragmentExpression( + const DIExpression *Expr, unsigned OffsetInBits, unsigned SizeInBits) { + SmallVector<uint64_t, 8> Ops; + // Copy over the expression, but leave off any trailing DW_OP_LLVM_fragment. + if (Expr) { + for (auto Op : Expr->expr_ops()) { + switch (Op.getOp()) { + default: break; + case dwarf::DW_OP_plus: + case dwarf::DW_OP_minus: + // We can't safely split arithmetic into multiple fragments because we + // can't express carry-over between fragments. + // + // FIXME: We *could* preserve the lowest fragment of a constant offset + // operation if the offset fits into SizeInBits. + return None; + case dwarf::DW_OP_LLVM_fragment: { + // Make the new offset point into the existing fragment. + uint64_t FragmentOffsetInBits = Op.getArg(0); + // Op.getArg(0) is FragmentOffsetInBits. + // Op.getArg(1) is FragmentSizeInBits. + assert((OffsetInBits + SizeInBits <= Op.getArg(0) + Op.getArg(1)) && + "new fragment outside of original fragment"); + OffsetInBits += FragmentOffsetInBits; + continue; + } + } + Ops.push_back(Op.getOp()); + for (unsigned I = 0; I < Op.getNumArgs(); ++I) + Ops.push_back(Op.getArg(I)); + } + } + Ops.push_back(dwarf::DW_OP_LLVM_fragment); + Ops.push_back(OffsetInBits); + Ops.push_back(SizeInBits); + return DIExpression::get(Expr->getContext(), Ops); +} + bool DIExpression::isConstant() const { // Recognize DW_OP_constu C DW_OP_stack_value (DW_OP_LLVM_fragment Len Ofs)?. if (getNumElements() != 3 && getNumElements() != 6) diff --git a/lib/IR/DebugLoc.cpp b/lib/IR/DebugLoc.cpp index 6297395b4c00..0a494119c3fe 100644 --- a/lib/IR/DebugLoc.cpp +++ b/lib/IR/DebugLoc.cpp @@ -10,7 +10,6 @@ #include "llvm/IR/DebugLoc.h" #include "LLVMContextImpl.h" #include "llvm/IR/DebugInfo.h" -#include "llvm/IR/IntrinsicInst.h" using namespace llvm; //===----------------------------------------------------------------------===// diff --git a/lib/IR/DiagnosticHandler.cpp b/lib/IR/DiagnosticHandler.cpp new file mode 100644 index 000000000000..fb1ac438ffbe --- /dev/null +++ b/lib/IR/DiagnosticHandler.cpp @@ -0,0 +1,91 @@ +//===- DiagnosticHandler.h - DiagnosticHandler class for LLVM -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// +#include "llvm/IR/DiagnosticHandler.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Regex.h" + +using namespace llvm; + +namespace { + +/// \brief Regular expression corresponding to the value given in one of the +/// -pass-remarks* command line flags. Passes whose name matches this regexp +/// will emit a diagnostic when calling the associated diagnostic function +/// (emitOptimizationRemark, emitOptimizationRemarkMissed or +/// emitOptimizationRemarkAnalysis). +struct PassRemarksOpt { + std::shared_ptr<Regex> Pattern; + + void operator=(const std::string &Val) { + // Create a regexp object to match pass names for emitOptimizationRemark. + if (!Val.empty()) { + Pattern = std::make_shared<Regex>(Val); + std::string RegexError; + if (!Pattern->isValid(RegexError)) + report_fatal_error("Invalid regular expression '" + Val + + "' in -pass-remarks: " + RegexError, + false); + } + } +}; + +static PassRemarksOpt PassRemarksPassedOptLoc; +static PassRemarksOpt PassRemarksMissedOptLoc; +static PassRemarksOpt PassRemarksAnalysisOptLoc; + +// -pass-remarks +// Command line flag to enable emitOptimizationRemark() +static cl::opt<PassRemarksOpt, true, cl::parser<std::string>> PassRemarks( + "pass-remarks", cl::value_desc("pattern"), + cl::desc("Enable optimization remarks from passes whose name match " + "the given regular expression"), + cl::Hidden, cl::location(PassRemarksPassedOptLoc), cl::ValueRequired, + cl::ZeroOrMore); + +// -pass-remarks-missed +// Command line flag to enable emitOptimizationRemarkMissed() +static cl::opt<PassRemarksOpt, true, cl::parser<std::string>> PassRemarksMissed( + "pass-remarks-missed", cl::value_desc("pattern"), + cl::desc("Enable missed optimization remarks from passes whose name match " + "the given regular expression"), + cl::Hidden, cl::location(PassRemarksMissedOptLoc), cl::ValueRequired, + cl::ZeroOrMore); + +// -pass-remarks-analysis +// Command line flag to enable emitOptimizationRemarkAnalysis() +static cl::opt<PassRemarksOpt, true, cl::parser<std::string>> + PassRemarksAnalysis( + "pass-remarks-analysis", cl::value_desc("pattern"), + cl::desc( + "Enable optimization analysis remarks from passes whose name match " + "the given regular expression"), + cl::Hidden, cl::location(PassRemarksAnalysisOptLoc), cl::ValueRequired, + cl::ZeroOrMore); +} + +bool DiagnosticHandler::isAnalysisRemarkEnabled(StringRef PassName) const { + return (PassRemarksAnalysisOptLoc.Pattern && + PassRemarksAnalysisOptLoc.Pattern->match(PassName)); +} +bool DiagnosticHandler::isMissedOptRemarkEnabled(StringRef PassName) const { + return (PassRemarksMissedOptLoc.Pattern && + PassRemarksMissedOptLoc.Pattern->match(PassName)); +} +bool DiagnosticHandler::isPassedOptRemarkEnabled(StringRef PassName) const { + return (PassRemarksPassedOptLoc.Pattern && + PassRemarksPassedOptLoc.Pattern->match(PassName)); +} + +bool DiagnosticHandler::isAnyRemarkEnabled() const { + return (PassRemarksPassedOptLoc.Pattern || PassRemarksMissedOptLoc.Pattern || + PassRemarksAnalysisOptLoc.Pattern); +} diff --git a/lib/IR/DiagnosticInfo.cpp b/lib/IR/DiagnosticInfo.cpp index 5129d6b9b008..946df1a836ce 100644 --- a/lib/IR/DiagnosticInfo.cpp +++ b/lib/IR/DiagnosticInfo.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/DiagnosticInfo.h" +#include "LLVMContextImpl.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/ADT/iterator_range.h" @@ -41,64 +42,6 @@ using namespace llvm; -namespace { - -/// \brief Regular expression corresponding to the value given in one of the -/// -pass-remarks* command line flags. Passes whose name matches this regexp -/// will emit a diagnostic when calling the associated diagnostic function -/// (emitOptimizationRemark, emitOptimizationRemarkMissed or -/// emitOptimizationRemarkAnalysis). -struct PassRemarksOpt { - std::shared_ptr<Regex> Pattern; - - void operator=(const std::string &Val) { - // Create a regexp object to match pass names for emitOptimizationRemark. - if (!Val.empty()) { - Pattern = std::make_shared<Regex>(Val); - std::string RegexError; - if (!Pattern->isValid(RegexError)) - report_fatal_error("Invalid regular expression '" + Val + - "' in -pass-remarks: " + RegexError, - false); - } - } -}; - -} // end anonymous namespace - -static PassRemarksOpt PassRemarksOptLoc; -static PassRemarksOpt PassRemarksMissedOptLoc; -static PassRemarksOpt PassRemarksAnalysisOptLoc; - -// -pass-remarks -// Command line flag to enable emitOptimizationRemark() -static cl::opt<PassRemarksOpt, true, cl::parser<std::string>> -PassRemarks("pass-remarks", cl::value_desc("pattern"), - cl::desc("Enable optimization remarks from passes whose name match " - "the given regular expression"), - cl::Hidden, cl::location(PassRemarksOptLoc), cl::ValueRequired, - cl::ZeroOrMore); - -// -pass-remarks-missed -// Command line flag to enable emitOptimizationRemarkMissed() -static cl::opt<PassRemarksOpt, true, cl::parser<std::string>> PassRemarksMissed( - "pass-remarks-missed", cl::value_desc("pattern"), - cl::desc("Enable missed optimization remarks from passes whose name match " - "the given regular expression"), - cl::Hidden, cl::location(PassRemarksMissedOptLoc), cl::ValueRequired, - cl::ZeroOrMore); - -// -pass-remarks-analysis -// Command line flag to enable emitOptimizationRemarkAnalysis() -static cl::opt<PassRemarksOpt, true, cl::parser<std::string>> -PassRemarksAnalysis( - "pass-remarks-analysis", cl::value_desc("pattern"), - cl::desc( - "Enable optimization analysis remarks from passes whose name match " - "the given regular expression"), - cl::Hidden, cl::location(PassRemarksAnalysisOptLoc), cl::ValueRequired, - cl::ZeroOrMore); - int llvm::getNextAvailablePluginDiagnosticKind() { static std::atomic<int> PluginKindID(DK_FirstPluginKind); return ++PluginKindID; @@ -218,12 +161,39 @@ DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, const Type *T) OS << *T; } +DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, StringRef S) + : Key(Key), Val(S.str()) {} + DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, int N) : Key(Key), Val(itostr(N)) {} +DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, long N) + : Key(Key), Val(itostr(N)) {} + +DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, long long N) + : Key(Key), Val(itostr(N)) {} + DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, unsigned N) : Key(Key), Val(utostr(N)) {} +DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, + unsigned long N) + : Key(Key), Val(utostr(N)) {} + +DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, + unsigned long long N) + : Key(Key), Val(utostr(N)) {} + +DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, DebugLoc Loc) + : Key(Key), Loc(Loc) { + if (Loc) { + Val = (Loc->getFilename() + ":" + Twine(Loc.getLine()) + ":" + + Twine(Loc.getCol())).str(); + } else { + Val = "<UNKNOWN LOCATION>"; + } +} + void DiagnosticInfoOptimizationBase::print(DiagnosticPrinter &DP) const { DP << getLocationStr() << ": " << getMsg(); if (Hotness) @@ -259,9 +229,10 @@ OptimizationRemark::OptimizationRemark(const char *PassName, RemarkName, *Func, Func->getSubprogram(), &getFirstFunctionBlock(Func)) {} -bool OptimizationRemark::isEnabled(StringRef PassName) { - return PassRemarksOptLoc.Pattern && - PassRemarksOptLoc.Pattern->match(PassName); +bool OptimizationRemark::isEnabled() const { + const Function &Fn = getFunction(); + LLVMContext &Ctx = Fn.getContext(); + return Ctx.getDiagHandlerPtr()->isPassedOptRemarkEnabled(getPassName()); } OptimizationRemarkMissed::OptimizationRemarkMissed( @@ -279,9 +250,10 @@ OptimizationRemarkMissed::OptimizationRemarkMissed(const char *PassName, *Inst->getParent()->getParent(), Inst->getDebugLoc(), Inst->getParent()) {} -bool OptimizationRemarkMissed::isEnabled(StringRef PassName) { - return PassRemarksMissedOptLoc.Pattern && - PassRemarksMissedOptLoc.Pattern->match(PassName); +bool OptimizationRemarkMissed::isEnabled() const { + const Function &Fn = getFunction(); + LLVMContext &Ctx = Fn.getContext(); + return Ctx.getDiagHandlerPtr()->isMissedOptRemarkEnabled(getPassName()); } OptimizationRemarkAnalysis::OptimizationRemarkAnalysis( @@ -306,51 +278,17 @@ OptimizationRemarkAnalysis::OptimizationRemarkAnalysis( *cast<BasicBlock>(CodeRegion)->getParent(), Loc, CodeRegion) {} -bool OptimizationRemarkAnalysis::isEnabled(StringRef PassName) { - return PassRemarksAnalysisOptLoc.Pattern && - PassRemarksAnalysisOptLoc.Pattern->match(PassName); +bool OptimizationRemarkAnalysis::isEnabled() const { + const Function &Fn = getFunction(); + LLVMContext &Ctx = Fn.getContext(); + return Ctx.getDiagHandlerPtr()->isAnalysisRemarkEnabled(getPassName()) || + shouldAlwaysPrint(); } void DiagnosticInfoMIRParser::print(DiagnosticPrinter &DP) const { DP << Diagnostic; } -void llvm::emitOptimizationRemark(LLVMContext &Ctx, const char *PassName, - const Function &Fn, - const DiagnosticLocation &Loc, - const Twine &Msg) { - Ctx.diagnose(OptimizationRemark(PassName, Fn, Loc, Msg)); -} - -void llvm::emitOptimizationRemarkMissed(LLVMContext &Ctx, const char *PassName, - const Function &Fn, - const DiagnosticLocation &Loc, - const Twine &Msg) { - Ctx.diagnose(OptimizationRemarkMissed(PassName, Fn, Loc, Msg)); -} - -void llvm::emitOptimizationRemarkAnalysis(LLVMContext &Ctx, - const char *PassName, - const Function &Fn, - const DiagnosticLocation &Loc, - const Twine &Msg) { - Ctx.diagnose(OptimizationRemarkAnalysis(PassName, Fn, Loc, Msg)); -} - -void llvm::emitOptimizationRemarkAnalysisFPCommute( - LLVMContext &Ctx, const char *PassName, const Function &Fn, - const DiagnosticLocation &Loc, const Twine &Msg) { - Ctx.diagnose(OptimizationRemarkAnalysisFPCommute(PassName, Fn, Loc, Msg)); -} - -void llvm::emitOptimizationRemarkAnalysisAliasing(LLVMContext &Ctx, - const char *PassName, - const Function &Fn, - const DiagnosticLocation &Loc, - const Twine &Msg) { - Ctx.diagnose(OptimizationRemarkAnalysisAliasing(PassName, Fn, Loc, Msg)); -} - DiagnosticInfoOptimizationFailure::DiagnosticInfoOptimizationFailure( const char *PassName, StringRef RemarkName, const DiagnosticLocation &Loc, const Value *CodeRegion) @@ -377,28 +315,20 @@ void DiagnosticInfoISelFallback::print(DiagnosticPrinter &DP) const { DP << "Instruction selection used fallback path for " << getFunction(); } -DiagnosticInfoOptimizationBase &DiagnosticInfoOptimizationBase:: -operator<<(StringRef S) { +void DiagnosticInfoOptimizationBase::insert(StringRef S) { Args.emplace_back(S); - return *this; } -DiagnosticInfoOptimizationBase &DiagnosticInfoOptimizationBase:: -operator<<(Argument A) { +void DiagnosticInfoOptimizationBase::insert(Argument A) { Args.push_back(std::move(A)); - return *this; } -DiagnosticInfoOptimizationBase &DiagnosticInfoOptimizationBase:: -operator<<(setIsVerbose V) { +void DiagnosticInfoOptimizationBase::insert(setIsVerbose V) { IsVerbose = true; - return *this; } -DiagnosticInfoOptimizationBase &DiagnosticInfoOptimizationBase:: -operator<<(setExtraArgs EA) { +void DiagnosticInfoOptimizationBase::insert(setExtraArgs EA) { FirstExtraArgIndex = Args.size(); - return *this; } std::string DiagnosticInfoOptimizationBase::getMsg() const { @@ -411,3 +341,83 @@ std::string DiagnosticInfoOptimizationBase::getMsg() const { OS << Arg.Val; return OS.str(); } + +namespace llvm { +namespace yaml { + +void MappingTraits<DiagnosticInfoOptimizationBase *>::mapping( + IO &io, DiagnosticInfoOptimizationBase *&OptDiag) { + assert(io.outputting() && "input not yet implemented"); + + if (io.mapTag("!Passed", + (OptDiag->getKind() == DK_OptimizationRemark || + OptDiag->getKind() == DK_MachineOptimizationRemark))) + ; + else if (io.mapTag( + "!Missed", + (OptDiag->getKind() == DK_OptimizationRemarkMissed || + OptDiag->getKind() == DK_MachineOptimizationRemarkMissed))) + ; + else if (io.mapTag( + "!Analysis", + (OptDiag->getKind() == DK_OptimizationRemarkAnalysis || + OptDiag->getKind() == DK_MachineOptimizationRemarkAnalysis))) + ; + else if (io.mapTag("!AnalysisFPCommute", + OptDiag->getKind() == + DK_OptimizationRemarkAnalysisFPCommute)) + ; + else if (io.mapTag("!AnalysisAliasing", + OptDiag->getKind() == + DK_OptimizationRemarkAnalysisAliasing)) + ; + else if (io.mapTag("!Failure", OptDiag->getKind() == DK_OptimizationFailure)) + ; + else + llvm_unreachable("Unknown remark type"); + + // These are read-only for now. + DiagnosticLocation DL = OptDiag->getLocation(); + StringRef FN = + GlobalValue::dropLLVMManglingEscape(OptDiag->getFunction().getName()); + + StringRef PassName(OptDiag->PassName); + io.mapRequired("Pass", PassName); + io.mapRequired("Name", OptDiag->RemarkName); + if (!io.outputting() || DL.isValid()) + io.mapOptional("DebugLoc", DL); + io.mapRequired("Function", FN); + io.mapOptional("Hotness", OptDiag->Hotness); + io.mapOptional("Args", OptDiag->Args); +} + +template <> struct MappingTraits<DiagnosticLocation> { + static void mapping(IO &io, DiagnosticLocation &DL) { + assert(io.outputting() && "input not yet implemented"); + + StringRef File = DL.getFilename(); + unsigned Line = DL.getLine(); + unsigned Col = DL.getColumn(); + + io.mapRequired("File", File); + io.mapRequired("Line", Line); + io.mapRequired("Column", Col); + } + + static const bool flow = true; +}; + +// Implement this as a mapping for now to get proper quotation for the value. +template <> struct MappingTraits<DiagnosticInfoOptimizationBase::Argument> { + static void mapping(IO &io, DiagnosticInfoOptimizationBase::Argument &A) { + assert(io.outputting() && "input not yet implemented"); + io.mapRequired(A.Key.data(), A.Val); + if (A.Loc.isValid()) + io.mapOptional("DebugLoc", A.Loc); + } +}; + +} // end namespace yaml +} // end namespace llvm + +LLVM_YAML_IS_SEQUENCE_VECTOR(DiagnosticInfoOptimizationBase::Argument) diff --git a/lib/IR/Dominators.cpp b/lib/IR/Dominators.cpp index 4d7e3040ecd7..ad448a3f240c 100644 --- a/lib/IR/Dominators.cpp +++ b/lib/IR/Dominators.cpp @@ -33,9 +33,9 @@ bool llvm::VerifyDomInfo = true; #else bool llvm::VerifyDomInfo = false; #endif -static cl::opt<bool,true> -VerifyDomInfoX("verify-dom-info", cl::location(VerifyDomInfo), - cl::desc("Verify dominator info (time consuming)")); +static cl::opt<bool, true> + VerifyDomInfoX("verify-dom-info", cl::location(VerifyDomInfo), cl::Hidden, + cl::desc("Verify dominator info (time consuming)")); bool BasicBlockEdge::isSingleEdge() const { const TerminatorInst *TI = Start->getTerminator(); @@ -64,12 +64,12 @@ template class llvm::DomTreeNodeBase<BasicBlock>; template class llvm::DominatorTreeBase<BasicBlock, false>; // DomTreeBase template class llvm::DominatorTreeBase<BasicBlock, true>; // PostDomTreeBase -template void -llvm::DomTreeBuilder::Calculate<DomTreeBuilder::BBDomTree, Function>( - DomTreeBuilder::BBDomTree &DT, Function &F); -template void -llvm::DomTreeBuilder::Calculate<DomTreeBuilder::BBPostDomTree, Function>( - DomTreeBuilder::BBPostDomTree &DT, Function &F); +template struct llvm::DomTreeBuilder::Update<BasicBlock *>; + +template void llvm::DomTreeBuilder::Calculate<DomTreeBuilder::BBDomTree>( + DomTreeBuilder::BBDomTree &DT); +template void llvm::DomTreeBuilder::Calculate<DomTreeBuilder::BBPostDomTree>( + DomTreeBuilder::BBPostDomTree &DT); template void llvm::DomTreeBuilder::InsertEdge<DomTreeBuilder::BBDomTree>( DomTreeBuilder::BBDomTree &DT, BasicBlock *From, BasicBlock *To); @@ -81,6 +81,11 @@ template void llvm::DomTreeBuilder::DeleteEdge<DomTreeBuilder::BBDomTree>( template void llvm::DomTreeBuilder::DeleteEdge<DomTreeBuilder::BBPostDomTree>( DomTreeBuilder::BBPostDomTree &DT, BasicBlock *From, BasicBlock *To); +template void llvm::DomTreeBuilder::ApplyUpdates<DomTreeBuilder::BBDomTree>( + DomTreeBuilder::BBDomTree &DT, DomTreeBuilder::BBUpdates); +template void llvm::DomTreeBuilder::ApplyUpdates<DomTreeBuilder::BBPostDomTree>( + DomTreeBuilder::BBPostDomTree &DT, DomTreeBuilder::BBUpdates); + template bool llvm::DomTreeBuilder::Verify<DomTreeBuilder::BBDomTree>( const DomTreeBuilder::BBDomTree &DT); template bool llvm::DomTreeBuilder::Verify<DomTreeBuilder::BBPostDomTree>( @@ -310,10 +315,14 @@ void DominatorTree::verifyDomTree() const { DominatorTree OtherDT; OtherDT.recalculate(F); if (compare(OtherDT)) { - errs() << "DominatorTree is not up to date!\nComputed:\n"; + errs() << "DominatorTree for function " << F.getName() + << " is not up to date!\nComputed:\n"; print(errs()); errs() << "\nActual:\n"; OtherDT.print(errs()); + errs() << "\nCFG:\n"; + F.print(errs()); + errs().flush(); abort(); } } diff --git a/lib/IR/Function.cpp b/lib/IR/Function.cpp index 85a019856c01..1fff912ecf2f 100644 --- a/lib/IR/Function.cpp +++ b/lib/IR/Function.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/Function.h" -#include "LLVMContextImpl.h" #include "SymbolTableListTraitsImpl.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseSet.h" @@ -649,7 +648,10 @@ enum IIT_Info { IIT_VEC_OF_ANYPTRS_TO_ELT = 34, IIT_I128 = 35, IIT_V512 = 36, - IIT_V1024 = 37 + IIT_V1024 = 37, + IIT_STRUCT6 = 38, + IIT_STRUCT7 = 39, + IIT_STRUCT8 = 40 }; static void DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos, @@ -798,6 +800,9 @@ static void DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos, case IIT_EMPTYSTRUCT: OutputTable.push_back(IITDescriptor::get(IITDescriptor::Struct, 0)); return; + case IIT_STRUCT8: ++StructElts; LLVM_FALLTHROUGH; + case IIT_STRUCT7: ++StructElts; LLVM_FALLTHROUGH; + case IIT_STRUCT6: ++StructElts; LLVM_FALLTHROUGH; case IIT_STRUCT5: ++StructElts; LLVM_FALLTHROUGH; case IIT_STRUCT4: ++StructElts; LLVM_FALLTHROUGH; case IIT_STRUCT3: ++StructElts; LLVM_FALLTHROUGH; @@ -874,11 +879,10 @@ static Type *DecodeFixedType(ArrayRef<Intrinsic::IITDescriptor> &Infos, return PointerType::get(DecodeFixedType(Infos, Tys, Context), D.Pointer_AddressSpace); case IITDescriptor::Struct: { - Type *Elts[5]; - assert(D.Struct_NumElements <= 5 && "Can't handle this yet"); + SmallVector<Type *, 8> Elts; for (unsigned i = 0, e = D.Struct_NumElements; i != e; ++i) - Elts[i] = DecodeFixedType(Infos, Tys, Context); - return StructType::get(Context, makeArrayRef(Elts,D.Struct_NumElements)); + Elts.push_back(DecodeFixedType(Infos, Tys, Context)); + return StructType::get(Context, Elts); } case IITDescriptor::Argument: return Tys[D.getArgumentNumber()]; diff --git a/lib/IR/GCOV.cpp b/lib/IR/GCOV.cpp deleted file mode 100644 index d4b455228225..000000000000 --- a/lib/IR/GCOV.cpp +++ /dev/null @@ -1,821 +0,0 @@ -//===- GCOV.cpp - LLVM coverage tool --------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// GCOV implements the interface to read and write coverage files that use -// 'gcov' format. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Support/GCOV.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" -#include <algorithm> -#include <system_error> - -using namespace llvm; - -//===----------------------------------------------------------------------===// -// GCOVFile implementation. - -/// readGCNO - Read GCNO buffer. -bool GCOVFile::readGCNO(GCOVBuffer &Buffer) { - if (!Buffer.readGCNOFormat()) - return false; - if (!Buffer.readGCOVVersion(Version)) - return false; - - if (!Buffer.readInt(Checksum)) - return false; - while (true) { - if (!Buffer.readFunctionTag()) - break; - auto GFun = make_unique<GCOVFunction>(*this); - if (!GFun->readGCNO(Buffer, Version)) - return false; - Functions.push_back(std::move(GFun)); - } - - GCNOInitialized = true; - return true; -} - -/// readGCDA - Read GCDA buffer. It is required that readGCDA() can only be -/// called after readGCNO(). -bool GCOVFile::readGCDA(GCOVBuffer &Buffer) { - assert(GCNOInitialized && "readGCDA() can only be called after readGCNO()"); - if (!Buffer.readGCDAFormat()) - return false; - GCOV::GCOVVersion GCDAVersion; - if (!Buffer.readGCOVVersion(GCDAVersion)) - return false; - if (Version != GCDAVersion) { - errs() << "GCOV versions do not match.\n"; - return false; - } - - uint32_t GCDAChecksum; - if (!Buffer.readInt(GCDAChecksum)) - return false; - if (Checksum != GCDAChecksum) { - errs() << "File checksums do not match: " << Checksum - << " != " << GCDAChecksum << ".\n"; - return false; - } - for (size_t i = 0, e = Functions.size(); i < e; ++i) { - if (!Buffer.readFunctionTag()) { - errs() << "Unexpected number of functions.\n"; - return false; - } - if (!Functions[i]->readGCDA(Buffer, Version)) - return false; - } - if (Buffer.readObjectTag()) { - uint32_t Length; - uint32_t Dummy; - if (!Buffer.readInt(Length)) - return false; - if (!Buffer.readInt(Dummy)) - return false; // checksum - if (!Buffer.readInt(Dummy)) - return false; // num - if (!Buffer.readInt(RunCount)) - return false; - Buffer.advanceCursor(Length - 3); - } - while (Buffer.readProgramTag()) { - uint32_t Length; - if (!Buffer.readInt(Length)) - return false; - Buffer.advanceCursor(Length); - ++ProgramCount; - } - - return true; -} - -void GCOVFile::print(raw_ostream &OS) const { - for (const auto &FPtr : Functions) - FPtr->print(OS); -} - -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -/// dump - Dump GCOVFile content to dbgs() for debugging purposes. -LLVM_DUMP_METHOD void GCOVFile::dump() const { - print(dbgs()); -} -#endif - -/// collectLineCounts - Collect line counts. This must be used after -/// reading .gcno and .gcda files. -void GCOVFile::collectLineCounts(FileInfo &FI) { - for (const auto &FPtr : Functions) - FPtr->collectLineCounts(FI); - FI.setRunCount(RunCount); - FI.setProgramCount(ProgramCount); -} - -//===----------------------------------------------------------------------===// -// GCOVFunction implementation. - -/// readGCNO - Read a function from the GCNO buffer. Return false if an error -/// occurs. -bool GCOVFunction::readGCNO(GCOVBuffer &Buff, GCOV::GCOVVersion Version) { - uint32_t Dummy; - if (!Buff.readInt(Dummy)) - return false; // Function header length - if (!Buff.readInt(Ident)) - return false; - if (!Buff.readInt(Checksum)) - return false; - if (Version != GCOV::V402) { - uint32_t CfgChecksum; - if (!Buff.readInt(CfgChecksum)) - return false; - if (Parent.getChecksum() != CfgChecksum) { - errs() << "File checksums do not match: " << Parent.getChecksum() - << " != " << CfgChecksum << " in (" << Name << ").\n"; - return false; - } - } - if (!Buff.readString(Name)) - return false; - if (!Buff.readString(Filename)) - return false; - if (!Buff.readInt(LineNumber)) - return false; - - // read blocks. - if (!Buff.readBlockTag()) { - errs() << "Block tag not found.\n"; - return false; - } - uint32_t BlockCount; - if (!Buff.readInt(BlockCount)) - return false; - for (uint32_t i = 0, e = BlockCount; i != e; ++i) { - if (!Buff.readInt(Dummy)) - return false; // Block flags; - Blocks.push_back(make_unique<GCOVBlock>(*this, i)); - } - - // read edges. - while (Buff.readEdgeTag()) { - uint32_t EdgeCount; - if (!Buff.readInt(EdgeCount)) - return false; - EdgeCount = (EdgeCount - 1) / 2; - uint32_t BlockNo; - if (!Buff.readInt(BlockNo)) - return false; - if (BlockNo >= BlockCount) { - errs() << "Unexpected block number: " << BlockNo << " (in " << Name - << ").\n"; - return false; - } - for (uint32_t i = 0, e = EdgeCount; i != e; ++i) { - uint32_t Dst; - if (!Buff.readInt(Dst)) - return false; - Edges.push_back(make_unique<GCOVEdge>(*Blocks[BlockNo], *Blocks[Dst])); - GCOVEdge *Edge = Edges.back().get(); - Blocks[BlockNo]->addDstEdge(Edge); - Blocks[Dst]->addSrcEdge(Edge); - if (!Buff.readInt(Dummy)) - return false; // Edge flag - } - } - - // read line table. - while (Buff.readLineTag()) { - uint32_t LineTableLength; - // Read the length of this line table. - if (!Buff.readInt(LineTableLength)) - return false; - uint32_t EndPos = Buff.getCursor() + LineTableLength * 4; - uint32_t BlockNo; - // Read the block number this table is associated with. - if (!Buff.readInt(BlockNo)) - return false; - if (BlockNo >= BlockCount) { - errs() << "Unexpected block number: " << BlockNo << " (in " << Name - << ").\n"; - return false; - } - GCOVBlock &Block = *Blocks[BlockNo]; - // Read the word that pads the beginning of the line table. This may be a - // flag of some sort, but seems to always be zero. - if (!Buff.readInt(Dummy)) - return false; - - // Line information starts here and continues up until the last word. - if (Buff.getCursor() != (EndPos - sizeof(uint32_t))) { - StringRef F; - // Read the source file name. - if (!Buff.readString(F)) - return false; - if (Filename != F) { - errs() << "Multiple sources for a single basic block: " << Filename - << " != " << F << " (in " << Name << ").\n"; - return false; - } - // Read lines up to, but not including, the null terminator. - while (Buff.getCursor() < (EndPos - 2 * sizeof(uint32_t))) { - uint32_t Line; - if (!Buff.readInt(Line)) - return false; - // Line 0 means this instruction was injected by the compiler. Skip it. - if (!Line) - continue; - Block.addLine(Line); - } - // Read the null terminator. - if (!Buff.readInt(Dummy)) - return false; - } - // The last word is either a flag or padding, it isn't clear which. Skip - // over it. - if (!Buff.readInt(Dummy)) - return false; - } - return true; -} - -/// readGCDA - Read a function from the GCDA buffer. Return false if an error -/// occurs. -bool GCOVFunction::readGCDA(GCOVBuffer &Buff, GCOV::GCOVVersion Version) { - uint32_t HeaderLength; - if (!Buff.readInt(HeaderLength)) - return false; // Function header length - - uint64_t EndPos = Buff.getCursor() + HeaderLength * sizeof(uint32_t); - - uint32_t GCDAIdent; - if (!Buff.readInt(GCDAIdent)) - return false; - if (Ident != GCDAIdent) { - errs() << "Function identifiers do not match: " << Ident - << " != " << GCDAIdent << " (in " << Name << ").\n"; - return false; - } - - uint32_t GCDAChecksum; - if (!Buff.readInt(GCDAChecksum)) - return false; - if (Checksum != GCDAChecksum) { - errs() << "Function checksums do not match: " << Checksum - << " != " << GCDAChecksum << " (in " << Name << ").\n"; - return false; - } - - uint32_t CfgChecksum; - if (Version != GCOV::V402) { - if (!Buff.readInt(CfgChecksum)) - return false; - if (Parent.getChecksum() != CfgChecksum) { - errs() << "File checksums do not match: " << Parent.getChecksum() - << " != " << CfgChecksum << " (in " << Name << ").\n"; - return false; - } - } - - if (Buff.getCursor() < EndPos) { - StringRef GCDAName; - if (!Buff.readString(GCDAName)) - return false; - if (Name != GCDAName) { - errs() << "Function names do not match: " << Name << " != " << GCDAName - << ".\n"; - return false; - } - } - - if (!Buff.readArcTag()) { - errs() << "Arc tag not found (in " << Name << ").\n"; - return false; - } - - uint32_t Count; - if (!Buff.readInt(Count)) - return false; - Count /= 2; - - // This for loop adds the counts for each block. A second nested loop is - // required to combine the edge counts that are contained in the GCDA file. - for (uint32_t BlockNo = 0; Count > 0; ++BlockNo) { - // The last block is always reserved for exit block - if (BlockNo >= Blocks.size()) { - errs() << "Unexpected number of edges (in " << Name << ").\n"; - return false; - } - if (BlockNo == Blocks.size() - 1) - errs() << "(" << Name << ") has arcs from exit block.\n"; - GCOVBlock &Block = *Blocks[BlockNo]; - for (size_t EdgeNo = 0, End = Block.getNumDstEdges(); EdgeNo < End; - ++EdgeNo) { - if (Count == 0) { - errs() << "Unexpected number of edges (in " << Name << ").\n"; - return false; - } - uint64_t ArcCount; - if (!Buff.readInt64(ArcCount)) - return false; - Block.addCount(EdgeNo, ArcCount); - --Count; - } - Block.sortDstEdges(); - } - return true; -} - -/// getEntryCount - Get the number of times the function was called by -/// retrieving the entry block's count. -uint64_t GCOVFunction::getEntryCount() const { - return Blocks.front()->getCount(); -} - -/// getExitCount - Get the number of times the function returned by retrieving -/// the exit block's count. -uint64_t GCOVFunction::getExitCount() const { - return Blocks.back()->getCount(); -} - -void GCOVFunction::print(raw_ostream &OS) const { - OS << "===== " << Name << " (" << Ident << ") @ " << Filename << ":" - << LineNumber << "\n"; - for (const auto &Block : Blocks) - Block->print(OS); -} - -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -/// dump - Dump GCOVFunction content to dbgs() for debugging purposes. -LLVM_DUMP_METHOD void GCOVFunction::dump() const { - print(dbgs()); -} -#endif - -/// collectLineCounts - Collect line counts. This must be used after -/// reading .gcno and .gcda files. -void GCOVFunction::collectLineCounts(FileInfo &FI) { - // If the line number is zero, this is a function that doesn't actually appear - // in the source file, so there isn't anything we can do with it. - if (LineNumber == 0) - return; - - for (const auto &Block : Blocks) - Block->collectLineCounts(FI); - FI.addFunctionLine(Filename, LineNumber, this); -} - -//===----------------------------------------------------------------------===// -// GCOVBlock implementation. - -/// ~GCOVBlock - Delete GCOVBlock and its content. -GCOVBlock::~GCOVBlock() { - SrcEdges.clear(); - DstEdges.clear(); - Lines.clear(); -} - -/// addCount - Add to block counter while storing the edge count. If the -/// destination has no outgoing edges, also update that block's count too. -void GCOVBlock::addCount(size_t DstEdgeNo, uint64_t N) { - assert(DstEdgeNo < DstEdges.size()); // up to caller to ensure EdgeNo is valid - DstEdges[DstEdgeNo]->Count = N; - Counter += N; - if (!DstEdges[DstEdgeNo]->Dst.getNumDstEdges()) - DstEdges[DstEdgeNo]->Dst.Counter += N; -} - -/// sortDstEdges - Sort destination edges by block number, nop if already -/// sorted. This is required for printing branch info in the correct order. -void GCOVBlock::sortDstEdges() { - if (!DstEdgesAreSorted) { - SortDstEdgesFunctor SortEdges; - std::stable_sort(DstEdges.begin(), DstEdges.end(), SortEdges); - } -} - -/// collectLineCounts - Collect line counts. This must be used after -/// reading .gcno and .gcda files. -void GCOVBlock::collectLineCounts(FileInfo &FI) { - for (uint32_t N : Lines) - FI.addBlockLine(Parent.getFilename(), N, this); -} - -void GCOVBlock::print(raw_ostream &OS) const { - OS << "Block : " << Number << " Counter : " << Counter << "\n"; - if (!SrcEdges.empty()) { - OS << "\tSource Edges : "; - for (const GCOVEdge *Edge : SrcEdges) - OS << Edge->Src.Number << " (" << Edge->Count << "), "; - OS << "\n"; - } - if (!DstEdges.empty()) { - OS << "\tDestination Edges : "; - for (const GCOVEdge *Edge : DstEdges) - OS << Edge->Dst.Number << " (" << Edge->Count << "), "; - OS << "\n"; - } - if (!Lines.empty()) { - OS << "\tLines : "; - for (uint32_t N : Lines) - OS << (N) << ","; - OS << "\n"; - } -} - -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -/// dump - Dump GCOVBlock content to dbgs() for debugging purposes. -LLVM_DUMP_METHOD void GCOVBlock::dump() const { - print(dbgs()); -} -#endif - -//===----------------------------------------------------------------------===// -// FileInfo implementation. - -// Safe integer division, returns 0 if numerator is 0. -static uint32_t safeDiv(uint64_t Numerator, uint64_t Divisor) { - if (!Numerator) - return 0; - return Numerator / Divisor; -} - -// This custom division function mimics gcov's branch ouputs: -// - Round to closest whole number -// - Only output 0% or 100% if it's exactly that value -static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor) { - if (!Numerator) - return 0; - if (Numerator == Divisor) - return 100; - - uint8_t Res = (Numerator * 100 + Divisor / 2) / Divisor; - if (Res == 0) - return 1; - if (Res == 100) - return 99; - return Res; -} - -namespace { -struct formatBranchInfo { - formatBranchInfo(const GCOV::Options &Options, uint64_t Count, uint64_t Total) - : Options(Options), Count(Count), Total(Total) {} - - void print(raw_ostream &OS) const { - if (!Total) - OS << "never executed"; - else if (Options.BranchCount) - OS << "taken " << Count; - else - OS << "taken " << branchDiv(Count, Total) << "%"; - } - - const GCOV::Options &Options; - uint64_t Count; - uint64_t Total; -}; - -static raw_ostream &operator<<(raw_ostream &OS, const formatBranchInfo &FBI) { - FBI.print(OS); - return OS; -} - -class LineConsumer { - std::unique_ptr<MemoryBuffer> Buffer; - StringRef Remaining; - -public: - LineConsumer(StringRef Filename) { - ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = - MemoryBuffer::getFileOrSTDIN(Filename); - if (std::error_code EC = BufferOrErr.getError()) { - errs() << Filename << ": " << EC.message() << "\n"; - Remaining = ""; - } else { - Buffer = std::move(BufferOrErr.get()); - Remaining = Buffer->getBuffer(); - } - } - bool empty() { return Remaining.empty(); } - void printNext(raw_ostream &OS, uint32_t LineNum) { - StringRef Line; - if (empty()) - Line = "/*EOF*/"; - else - std::tie(Line, Remaining) = Remaining.split("\n"); - OS << format("%5u:", LineNum) << Line << "\n"; - } -}; -} // end anonymous namespace - -/// Convert a path to a gcov filename. If PreservePaths is true, this -/// translates "/" to "#", ".." to "^", and drops ".", to match gcov. -static std::string mangleCoveragePath(StringRef Filename, bool PreservePaths) { - if (!PreservePaths) - return sys::path::filename(Filename).str(); - - // This behaviour is defined by gcov in terms of text replacements, so it's - // not likely to do anything useful on filesystems with different textual - // conventions. - llvm::SmallString<256> Result(""); - StringRef::iterator I, S, E; - for (I = S = Filename.begin(), E = Filename.end(); I != E; ++I) { - if (*I != '/') - continue; - - if (I - S == 1 && *S == '.') { - // ".", the current directory, is skipped. - } else if (I - S == 2 && *S == '.' && *(S + 1) == '.') { - // "..", the parent directory, is replaced with "^". - Result.append("^#"); - } else { - if (S < I) - // Leave other components intact, - Result.append(S, I); - // And separate with "#". - Result.push_back('#'); - } - S = I + 1; - } - - if (S < I) - Result.append(S, I); - return Result.str(); -} - -std::string FileInfo::getCoveragePath(StringRef Filename, - StringRef MainFilename) { - if (Options.NoOutput) - // This is probably a bug in gcov, but when -n is specified, paths aren't - // mangled at all, and the -l and -p options are ignored. Here, we do the - // same. - return Filename; - - std::string CoveragePath; - if (Options.LongFileNames && !Filename.equals(MainFilename)) - CoveragePath = - mangleCoveragePath(MainFilename, Options.PreservePaths) + "##"; - CoveragePath += mangleCoveragePath(Filename, Options.PreservePaths) + ".gcov"; - return CoveragePath; -} - -std::unique_ptr<raw_ostream> -FileInfo::openCoveragePath(StringRef CoveragePath) { - if (Options.NoOutput) - return llvm::make_unique<raw_null_ostream>(); - - std::error_code EC; - auto OS = llvm::make_unique<raw_fd_ostream>(CoveragePath, EC, - sys::fs::F_Text); - if (EC) { - errs() << EC.message() << "\n"; - return llvm::make_unique<raw_null_ostream>(); - } - return std::move(OS); -} - -/// print - Print source files with collected line count information. -void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename, - StringRef GCNOFile, StringRef GCDAFile) { - SmallVector<StringRef, 4> Filenames; - for (const auto &LI : LineInfo) - Filenames.push_back(LI.first()); - std::sort(Filenames.begin(), Filenames.end()); - - for (StringRef Filename : Filenames) { - auto AllLines = LineConsumer(Filename); - - std::string CoveragePath = getCoveragePath(Filename, MainFilename); - std::unique_ptr<raw_ostream> CovStream = openCoveragePath(CoveragePath); - raw_ostream &CovOS = *CovStream; - - CovOS << " -: 0:Source:" << Filename << "\n"; - CovOS << " -: 0:Graph:" << GCNOFile << "\n"; - CovOS << " -: 0:Data:" << GCDAFile << "\n"; - CovOS << " -: 0:Runs:" << RunCount << "\n"; - CovOS << " -: 0:Programs:" << ProgramCount << "\n"; - - const LineData &Line = LineInfo[Filename]; - GCOVCoverage FileCoverage(Filename); - for (uint32_t LineIndex = 0; LineIndex < Line.LastLine || !AllLines.empty(); - ++LineIndex) { - if (Options.BranchInfo) { - FunctionLines::const_iterator FuncsIt = Line.Functions.find(LineIndex); - if (FuncsIt != Line.Functions.end()) - printFunctionSummary(CovOS, FuncsIt->second); - } - - BlockLines::const_iterator BlocksIt = Line.Blocks.find(LineIndex); - if (BlocksIt == Line.Blocks.end()) { - // No basic blocks are on this line. Not an executable line of code. - CovOS << " -:"; - AllLines.printNext(CovOS, LineIndex + 1); - } else { - const BlockVector &Blocks = BlocksIt->second; - - // Add up the block counts to form line counts. - DenseMap<const GCOVFunction *, bool> LineExecs; - uint64_t LineCount = 0; - for (const GCOVBlock *Block : Blocks) { - if (Options.AllBlocks) { - // Only take the highest block count for that line. - uint64_t BlockCount = Block->getCount(); - LineCount = LineCount > BlockCount ? LineCount : BlockCount; - } else { - // Sum up all of the block counts. - LineCount += Block->getCount(); - } - - if (Options.FuncCoverage) { - // This is a slightly convoluted way to most accurately gather line - // statistics for functions. Basically what is happening is that we - // don't want to count a single line with multiple blocks more than - // once. However, we also don't simply want to give the total line - // count to every function that starts on the line. Thus, what is - // happening here are two things: - // 1) Ensure that the number of logical lines is only incremented - // once per function. - // 2) If there are multiple blocks on the same line, ensure that the - // number of lines executed is incremented as long as at least - // one of the blocks are executed. - const GCOVFunction *Function = &Block->getParent(); - if (FuncCoverages.find(Function) == FuncCoverages.end()) { - std::pair<const GCOVFunction *, GCOVCoverage> KeyValue( - Function, GCOVCoverage(Function->getName())); - FuncCoverages.insert(KeyValue); - } - GCOVCoverage &FuncCoverage = FuncCoverages.find(Function)->second; - - if (LineExecs.find(Function) == LineExecs.end()) { - if (Block->getCount()) { - ++FuncCoverage.LinesExec; - LineExecs[Function] = true; - } else { - LineExecs[Function] = false; - } - ++FuncCoverage.LogicalLines; - } else if (!LineExecs[Function] && Block->getCount()) { - ++FuncCoverage.LinesExec; - LineExecs[Function] = true; - } - } - } - - if (LineCount == 0) - CovOS << " #####:"; - else { - CovOS << format("%9" PRIu64 ":", LineCount); - ++FileCoverage.LinesExec; - } - ++FileCoverage.LogicalLines; - - AllLines.printNext(CovOS, LineIndex + 1); - - uint32_t BlockNo = 0; - uint32_t EdgeNo = 0; - for (const GCOVBlock *Block : Blocks) { - // Only print block and branch information at the end of the block. - if (Block->getLastLine() != LineIndex + 1) - continue; - if (Options.AllBlocks) - printBlockInfo(CovOS, *Block, LineIndex, BlockNo); - if (Options.BranchInfo) { - size_t NumEdges = Block->getNumDstEdges(); - if (NumEdges > 1) - printBranchInfo(CovOS, *Block, FileCoverage, EdgeNo); - else if (Options.UncondBranch && NumEdges == 1) - printUncondBranchInfo(CovOS, EdgeNo, - (*Block->dst_begin())->Count); - } - } - } - } - FileCoverages.push_back(std::make_pair(CoveragePath, FileCoverage)); - } - - // FIXME: There is no way to detect calls given current instrumentation. - if (Options.FuncCoverage) - printFuncCoverage(InfoOS); - printFileCoverage(InfoOS); -} - -/// printFunctionSummary - Print function and block summary. -void FileInfo::printFunctionSummary(raw_ostream &OS, - const FunctionVector &Funcs) const { - for (const GCOVFunction *Func : Funcs) { - uint64_t EntryCount = Func->getEntryCount(); - uint32_t BlocksExec = 0; - for (const GCOVBlock &Block : Func->blocks()) - if (Block.getNumDstEdges() && Block.getCount()) - ++BlocksExec; - - OS << "function " << Func->getName() << " called " << EntryCount - << " returned " << safeDiv(Func->getExitCount() * 100, EntryCount) - << "% blocks executed " - << safeDiv(BlocksExec * 100, Func->getNumBlocks() - 1) << "%\n"; - } -} - -/// printBlockInfo - Output counts for each block. -void FileInfo::printBlockInfo(raw_ostream &OS, const GCOVBlock &Block, - uint32_t LineIndex, uint32_t &BlockNo) const { - if (Block.getCount() == 0) - OS << " $$$$$:"; - else - OS << format("%9" PRIu64 ":", Block.getCount()); - OS << format("%5u-block %2u\n", LineIndex + 1, BlockNo++); -} - -/// printBranchInfo - Print conditional branch probabilities. -void FileInfo::printBranchInfo(raw_ostream &OS, const GCOVBlock &Block, - GCOVCoverage &Coverage, uint32_t &EdgeNo) { - SmallVector<uint64_t, 16> BranchCounts; - uint64_t TotalCounts = 0; - for (const GCOVEdge *Edge : Block.dsts()) { - BranchCounts.push_back(Edge->Count); - TotalCounts += Edge->Count; - if (Block.getCount()) - ++Coverage.BranchesExec; - if (Edge->Count) - ++Coverage.BranchesTaken; - ++Coverage.Branches; - - if (Options.FuncCoverage) { - const GCOVFunction *Function = &Block.getParent(); - GCOVCoverage &FuncCoverage = FuncCoverages.find(Function)->second; - if (Block.getCount()) - ++FuncCoverage.BranchesExec; - if (Edge->Count) - ++FuncCoverage.BranchesTaken; - ++FuncCoverage.Branches; - } - } - - for (uint64_t N : BranchCounts) - OS << format("branch %2u ", EdgeNo++) - << formatBranchInfo(Options, N, TotalCounts) << "\n"; -} - -/// printUncondBranchInfo - Print unconditional branch probabilities. -void FileInfo::printUncondBranchInfo(raw_ostream &OS, uint32_t &EdgeNo, - uint64_t Count) const { - OS << format("unconditional %2u ", EdgeNo++) - << formatBranchInfo(Options, Count, Count) << "\n"; -} - -// printCoverage - Print generic coverage info used by both printFuncCoverage -// and printFileCoverage. -void FileInfo::printCoverage(raw_ostream &OS, - const GCOVCoverage &Coverage) const { - OS << format("Lines executed:%.2f%% of %u\n", - double(Coverage.LinesExec) * 100 / Coverage.LogicalLines, - Coverage.LogicalLines); - if (Options.BranchInfo) { - if (Coverage.Branches) { - OS << format("Branches executed:%.2f%% of %u\n", - double(Coverage.BranchesExec) * 100 / Coverage.Branches, - Coverage.Branches); - OS << format("Taken at least once:%.2f%% of %u\n", - double(Coverage.BranchesTaken) * 100 / Coverage.Branches, - Coverage.Branches); - } else { - OS << "No branches\n"; - } - OS << "No calls\n"; // to be consistent with gcov - } -} - -// printFuncCoverage - Print per-function coverage info. -void FileInfo::printFuncCoverage(raw_ostream &OS) const { - for (const auto &FC : FuncCoverages) { - const GCOVCoverage &Coverage = FC.second; - OS << "Function '" << Coverage.Name << "'\n"; - printCoverage(OS, Coverage); - OS << "\n"; - } -} - -// printFileCoverage - Print per-file coverage info. -void FileInfo::printFileCoverage(raw_ostream &OS) const { - for (const auto &FC : FileCoverages) { - const std::string &Filename = FC.first; - const GCOVCoverage &Coverage = FC.second; - OS << "File '" << Coverage.Name << "'\n"; - printCoverage(OS, Coverage); - if (!Options.NoOutput) - OS << Coverage.Name << ":creating '" << Filename << "'\n"; - OS << "\n"; - } -} diff --git a/lib/IR/Globals.cpp b/lib/IR/Globals.cpp index afd4a36270a8..da1b6c5e0c91 100644 --- a/lib/IR/Globals.cpp +++ b/lib/IR/Globals.cpp @@ -67,6 +67,7 @@ void GlobalValue::copyAttributesFrom(const GlobalValue *Src) { setVisibility(Src->getVisibility()); setUnnamedAddr(Src->getUnnamedAddr()); setDLLStorageClass(Src->getDLLStorageClass()); + setDSOLocal(Src->isDSOLocal()); } void GlobalValue::removeFromParent() { diff --git a/lib/IR/IRBuilder.cpp b/lib/IR/IRBuilder.cpp index b7fa07c6ffac..027c0255bcec 100644 --- a/lib/IR/IRBuilder.cpp +++ b/lib/IR/IRBuilder.cpp @@ -135,8 +135,13 @@ CreateMemCpy(Value *Dst, Value *Src, Value *Size, unsigned Align, } CallInst *IRBuilderBase::CreateElementUnorderedAtomicMemCpy( - Value *Dst, Value *Src, Value *Size, uint32_t ElementSize, MDNode *TBAATag, - MDNode *TBAAStructTag, MDNode *ScopeTag, MDNode *NoAliasTag) { + Value *Dst, unsigned DstAlign, Value *Src, unsigned SrcAlign, Value *Size, + uint32_t ElementSize, MDNode *TBAATag, MDNode *TBAAStructTag, + MDNode *ScopeTag, MDNode *NoAliasTag) { + assert(DstAlign >= ElementSize && + "Pointer alignment must be at least element size"); + assert(SrcAlign >= ElementSize && + "Pointer alignment must be at least element size"); Dst = getCastedInt8PtrValue(Dst); Src = getCastedInt8PtrValue(Src); @@ -148,6 +153,10 @@ CallInst *IRBuilderBase::CreateElementUnorderedAtomicMemCpy( CallInst *CI = createCallHelper(TheFn, Ops, this); + // Set the alignment of the pointer args. + CI->addParamAttr(0, Attribute::getWithAlignment(CI->getContext(), DstAlign)); + CI->addParamAttr(1, Attribute::getWithAlignment(CI->getContext(), SrcAlign)); + // Set the TBAA info if present. if (TBAATag) CI->setMetadata(LLVMContext::MD_tbaa, TBAATag); @@ -356,6 +365,7 @@ CallInst *IRBuilderBase::CreateMaskedLoad(Value *Ptr, unsigned Align, PointerType *PtrTy = cast<PointerType>(Ptr->getType()); Type *DataTy = PtrTy->getElementType(); assert(DataTy->isVectorTy() && "Ptr should point to a vector"); + assert(Mask && "Mask should not be all-ones (null)"); if (!PassThru) PassThru = UndefValue::get(DataTy); Type *OverloadedTypes[] = { DataTy, PtrTy }; @@ -375,6 +385,7 @@ CallInst *IRBuilderBase::CreateMaskedStore(Value *Val, Value *Ptr, PointerType *PtrTy = cast<PointerType>(Ptr->getType()); Type *DataTy = PtrTy->getElementType(); assert(DataTy->isVectorTy() && "Ptr should point to a vector"); + assert(Mask && "Mask should not be all-ones (null)"); Type *OverloadedTypes[] = { DataTy, PtrTy }; Value *Ops[] = { Val, Ptr, getInt32(Align), Mask }; return CreateMaskedIntrinsic(Intrinsic::masked_store, Ops, OverloadedTypes); diff --git a/lib/IR/IRPrintingPasses.cpp b/lib/IR/IRPrintingPasses.cpp index 955fdc749b2b..3b32814bed5c 100644 --- a/lib/IR/IRPrintingPasses.cpp +++ b/lib/IR/IRPrintingPasses.cpp @@ -44,8 +44,12 @@ PrintFunctionPass::PrintFunctionPass(raw_ostream &OS, const std::string &Banner) PreservedAnalyses PrintFunctionPass::run(Function &F, FunctionAnalysisManager &) { - if (isFunctionInPrintList(F.getName())) - OS << Banner << static_cast<Value &>(F); + if (isFunctionInPrintList(F.getName())) { + if (forcePrintModuleIR()) + OS << Banner << " (function: " << F.getName() << ")\n" << *F.getParent(); + else + OS << Banner << static_cast<Value &>(F); + } return PreservedAnalyses::all(); } @@ -71,7 +75,7 @@ public: AU.setPreservesAll(); } - StringRef getPassName() const override { return "Print Module IR"; }
+ StringRef getPassName() const override { return "Print Module IR"; } }; class PrintFunctionPassWrapper : public FunctionPass { @@ -94,7 +98,7 @@ public: AU.setPreservesAll(); } - StringRef getPassName() const override { return "Print Function IR"; }
+ StringRef getPassName() const override { return "Print Function IR"; } }; class PrintBasicBlockPass : public BasicBlockPass { diff --git a/lib/IR/InlineAsm.cpp b/lib/IR/InlineAsm.cpp index ad22efdf0eff..8667d7aab583 100644 --- a/lib/IR/InlineAsm.cpp +++ b/lib/IR/InlineAsm.cpp @@ -163,6 +163,7 @@ bool InlineAsm::ConstraintInfo::Parse(StringRef Str, return true; // Note that operand #n has a matching input. scInfo.MatchingInput = ConstraintsSoFar.size(); + assert(scInfo.MatchingInput >= 0); } else { if (ConstraintsSoFar[N].hasMatchingInput() && (size_t)ConstraintsSoFar[N].MatchingInput != @@ -170,6 +171,7 @@ bool InlineAsm::ConstraintInfo::Parse(StringRef Str, return true; // Note that operand #n has a matching input. ConstraintsSoFar[N].MatchingInput = ConstraintsSoFar.size(); + assert(ConstraintsSoFar[N].MatchingInput >= 0); } } else if (*I == '|') { multipleAlternativeIndex++; diff --git a/lib/IR/Instruction.cpp b/lib/IR/Instruction.cpp index 365cb019aec4..5f2a6146ad81 100644 --- a/lib/IR/Instruction.cpp +++ b/lib/IR/Instruction.cpp @@ -13,11 +13,9 @@ #include "llvm/IR/Instruction.h" #include "llvm/ADT/DenseSet.h" -#include "llvm/IR/CallSite.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/MDBuilder.h" -#include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" #include "llvm/IR/Type.h" using namespace llvm; @@ -89,6 +87,10 @@ void Instruction::moveBefore(Instruction *MovePos) { moveBefore(*MovePos->getParent(), MovePos->getIterator()); } +void Instruction::moveAfter(Instruction *MovePos) { + moveBefore(*MovePos->getParent(), ++MovePos->getIterator()); +} + void Instruction::moveBefore(BasicBlock &BB, SymbolTableList<Instruction>::iterator I) { assert(I == BB.end() || I->getParent() == &BB); @@ -142,9 +144,14 @@ bool Instruction::isExact() const { return cast<PossiblyExactOperator>(this)->isExact(); } -void Instruction::setHasUnsafeAlgebra(bool B) { +void Instruction::setFast(bool B) { assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op"); - cast<FPMathOperator>(this)->setHasUnsafeAlgebra(B); + cast<FPMathOperator>(this)->setFast(B); +} + +void Instruction::setHasAllowReassoc(bool B) { + assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op"); + cast<FPMathOperator>(this)->setHasAllowReassoc(B); } void Instruction::setHasNoNaNs(bool B) { @@ -167,6 +174,11 @@ void Instruction::setHasAllowReciprocal(bool B) { cast<FPMathOperator>(this)->setHasAllowReciprocal(B); } +void Instruction::setHasApproxFunc(bool B) { + assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op"); + cast<FPMathOperator>(this)->setHasApproxFunc(B); +} + void Instruction::setFastMathFlags(FastMathFlags FMF) { assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op"); cast<FPMathOperator>(this)->setFastMathFlags(FMF); @@ -177,9 +189,14 @@ void Instruction::copyFastMathFlags(FastMathFlags FMF) { cast<FPMathOperator>(this)->copyFastMathFlags(FMF); } -bool Instruction::hasUnsafeAlgebra() const { +bool Instruction::isFast() const { + assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op"); + return cast<FPMathOperator>(this)->isFast(); +} + +bool Instruction::hasAllowReassoc() const { assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op"); - return cast<FPMathOperator>(this)->hasUnsafeAlgebra(); + return cast<FPMathOperator>(this)->hasAllowReassoc(); } bool Instruction::hasNoNaNs() const { @@ -207,6 +224,11 @@ bool Instruction::hasAllowContract() const { return cast<FPMathOperator>(this)->hasAllowContract(); } +bool Instruction::hasApproxFunc() const { + assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op"); + return cast<FPMathOperator>(this)->hasApproxFunc(); +} + FastMathFlags Instruction::getFastMathFlags() const { assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op"); return cast<FPMathOperator>(this)->getFastMathFlags(); @@ -575,7 +597,7 @@ bool Instruction::isAssociative() const { switch (Opcode) { case FMul: case FAdd: - return cast<FPMathOperator>(this)->hasUnsafeAlgebra(); + return cast<FPMathOperator>(this)->isFast(); default: return false; } @@ -621,7 +643,6 @@ void Instruction::copyMetadata(const Instruction &SrcInst, } if (WL.empty() || WLS.count(LLVMContext::MD_dbg)) setDebugLoc(SrcInst.getDebugLoc()); - return; } Instruction *Instruction::clone() const { diff --git a/lib/IR/Instructions.cpp b/lib/IR/Instructions.cpp index 2c49564e328b..490fcbce7439 100644 --- a/lib/IR/Instructions.cpp +++ b/lib/IR/Instructions.cpp @@ -2299,7 +2299,7 @@ bool CastInst::isLosslessCast() const { bool CastInst::isNoopCast(Instruction::CastOps Opcode, Type *SrcTy, Type *DestTy, - Type *IntPtrTy) { + const DataLayout &DL) { switch (Opcode) { default: llvm_unreachable("Invalid CastOp"); case Instruction::Trunc: @@ -2317,30 +2317,16 @@ bool CastInst::isNoopCast(Instruction::CastOps Opcode, case Instruction::BitCast: return true; // BitCast never modifies bits. case Instruction::PtrToInt: - return IntPtrTy->getScalarSizeInBits() == + return DL.getIntPtrType(SrcTy)->getScalarSizeInBits() == DestTy->getScalarSizeInBits(); case Instruction::IntToPtr: - return IntPtrTy->getScalarSizeInBits() == + return DL.getIntPtrType(DestTy)->getScalarSizeInBits() == SrcTy->getScalarSizeInBits(); } } -/// @brief Determine if a cast is a no-op. -bool CastInst::isNoopCast(Type *IntPtrTy) const { - return isNoopCast(getOpcode(), getOperand(0)->getType(), getType(), IntPtrTy); -} - bool CastInst::isNoopCast(const DataLayout &DL) const { - Type *PtrOpTy = nullptr; - if (getOpcode() == Instruction::PtrToInt) - PtrOpTy = getOperand(0)->getType(); - else if (getOpcode() == Instruction::IntToPtr) - PtrOpTy = getType(); - - Type *IntPtrTy = - PtrOpTy ? DL.getIntPtrType(PtrOpTy) : DL.getIntPtrType(getContext(), 0); - - return isNoopCast(getOpcode(), getOperand(0)->getType(), getType(), IntPtrTy); + return isNoopCast(getOpcode(), getOperand(0)->getType(), getType(), DL); } /// This function determines if a pair of casts can be eliminated and what @@ -2891,12 +2877,15 @@ bool CastInst::isBitCastable(Type *SrcTy, Type *DestTy) { bool CastInst::isBitOrNoopPointerCastable(Type *SrcTy, Type *DestTy, const DataLayout &DL) { + // ptrtoint and inttoptr are not allowed on non-integral pointers if (auto *PtrTy = dyn_cast<PointerType>(SrcTy)) if (auto *IntTy = dyn_cast<IntegerType>(DestTy)) - return IntTy->getBitWidth() == DL.getPointerTypeSizeInBits(PtrTy); + return (IntTy->getBitWidth() == DL.getPointerTypeSizeInBits(PtrTy) && + !DL.isNonIntegralPointerType(PtrTy)); if (auto *PtrTy = dyn_cast<PointerType>(DestTy)) if (auto *IntTy = dyn_cast<IntegerType>(SrcTy)) - return IntTy->getBitWidth() == DL.getPointerTypeSizeInBits(PtrTy); + return (IntTy->getBitWidth() == DL.getPointerTypeSizeInBits(PtrTy) && + !DL.isNonIntegralPointerType(PtrTy)); return isBitCastable(SrcTy, DestTy); } diff --git a/lib/IR/IntrinsicInst.cpp b/lib/IR/IntrinsicInst.cpp index 8b12c55937f5..67bd5b69bb0f 100644 --- a/lib/IR/IntrinsicInst.cpp +++ b/lib/IR/IntrinsicInst.cpp @@ -14,10 +14,10 @@ // are all subclasses of the CallInst class. Note that none of these classes // has state or virtual methods, which is an important part of this gross/neat // hack working. -// +// // In some cases, arguments to intrinsics need to be generic and are defined as // type pointer to empty struct { }*. To access the real item of interest the -// cast instruction needs to be stripped away. +// cast instruction needs to be stripped away. // //===----------------------------------------------------------------------===// @@ -98,7 +98,7 @@ Value *InstrProfIncrementInst::getStep() const { ConstrainedFPIntrinsic::RoundingMode ConstrainedFPIntrinsic::getRoundingMode() const { unsigned NumOperands = getNumArgOperands(); - Metadata *MD = + Metadata *MD = dyn_cast<MetadataAsValue>(getArgOperand(NumOperands - 2))->getMetadata(); if (!MD || !isa<MDString>(MD)) return rmInvalid; @@ -118,7 +118,7 @@ ConstrainedFPIntrinsic::getRoundingMode() const { ConstrainedFPIntrinsic::ExceptionBehavior ConstrainedFPIntrinsic::getExceptionBehavior() const { unsigned NumOperands = getNumArgOperands(); - Metadata *MD = + Metadata *MD = dyn_cast<MetadataAsValue>(getArgOperand(NumOperands - 1))->getMetadata(); if (!MD || !isa<MDString>(MD)) return ebInvalid; @@ -132,7 +132,7 @@ ConstrainedFPIntrinsic::getExceptionBehavior() const { bool ConstrainedFPIntrinsic::isUnaryOp() const { switch (getIntrinsicID()) { - default: + default: return false; case Intrinsic::experimental_constrained_sqrt: case Intrinsic::experimental_constrained_sin: @@ -147,3 +147,13 @@ bool ConstrainedFPIntrinsic::isUnaryOp() const { return true; } } + +bool ConstrainedFPIntrinsic::isTernaryOp() const { + switch (getIntrinsicID()) { + default: + return false; + case Intrinsic::experimental_constrained_fma: + return true; + } +} + diff --git a/lib/IR/LLVMContext.cpp b/lib/IR/LLVMContext.cpp index c58459d6d5f5..c8b7c10a9a41 100644 --- a/lib/IR/LLVMContext.cpp +++ b/lib/IR/LLVMContext.cpp @@ -59,6 +59,8 @@ LLVMContext::LLVMContext() : pImpl(new LLVMContextImpl(*this)) { {MD_section_prefix, "section_prefix"}, {MD_absolute_symbol, "absolute_symbol"}, {MD_associated, "associated"}, + {MD_callees, "callees"}, + {MD_irr_loop, "irr_loop"}, }; for (auto &MDKind : MDKinds) { @@ -129,11 +131,17 @@ void *LLVMContext::getInlineAsmDiagnosticContext() const { return pImpl->InlineAsmDiagContext; } -void LLVMContext::setDiagnosticHandler(DiagnosticHandlerTy DiagnosticHandler, - void *DiagnosticContext, - bool RespectFilters) { - pImpl->DiagnosticHandler = DiagnosticHandler; - pImpl->DiagnosticContext = DiagnosticContext; +void LLVMContext::setDiagnosticHandlerCallBack( + DiagnosticHandler::DiagnosticHandlerTy DiagnosticHandler, + void *DiagnosticContext, bool RespectFilters) { + pImpl->DiagHandler->DiagHandlerCallback = DiagnosticHandler; + pImpl->DiagHandler->DiagnosticContext = DiagnosticContext; + pImpl->RespectDiagnosticFilters = RespectFilters; +} + +void LLVMContext::setDiagnosticHandler(std::unique_ptr<DiagnosticHandler> &&DH, + bool RespectFilters) { + pImpl->DiagHandler = std::move(DH); pImpl->RespectDiagnosticFilters = RespectFilters; } @@ -159,12 +167,13 @@ void LLVMContext::setDiagnosticsOutputFile(std::unique_ptr<yaml::Output> F) { pImpl->DiagnosticsOutputFile = std::move(F); } -LLVMContext::DiagnosticHandlerTy LLVMContext::getDiagnosticHandler() const { - return pImpl->DiagnosticHandler; +DiagnosticHandler::DiagnosticHandlerTy +LLVMContext::getDiagnosticHandlerCallBack() const { + return pImpl->DiagHandler->DiagHandlerCallback; } void *LLVMContext::getDiagnosticContext() const { - return pImpl->DiagnosticContext; + return pImpl->DiagHandler->DiagnosticContext; } void LLVMContext::setYieldCallback(YieldCallbackTy Callback, void *OpaqueHandle) @@ -192,8 +201,12 @@ static bool isDiagnosticEnabled(const DiagnosticInfo &DI) { // pattern, passed via one of the -pass-remarks* flags, matches the name of // the pass that is emitting the diagnostic. If there is no match, ignore the // diagnostic and return. + // + // Also noisy remarks are only enabled if we have hotness information to sort + // them. if (auto *Remark = dyn_cast<DiagnosticInfoOptimizationBase>(&DI)) - return Remark->isEnabled(); + return Remark->isEnabled() && + (!Remark->isVerbose() || Remark->getHotness()); return true; } @@ -214,12 +227,19 @@ LLVMContext::getDiagnosticMessagePrefix(DiagnosticSeverity Severity) { } void LLVMContext::diagnose(const DiagnosticInfo &DI) { + if (auto *OptDiagBase = dyn_cast<DiagnosticInfoOptimizationBase>(&DI)) { + yaml::Output *Out = getDiagnosticsOutputFile(); + if (Out) { + // For remarks the << operator takes a reference to a pointer. + auto *P = const_cast<DiagnosticInfoOptimizationBase *>(OptDiagBase); + *Out << P; + } + } // If there is a report handler, use it. - if (pImpl->DiagnosticHandler) { - if (!pImpl->RespectDiagnosticFilters || isDiagnosticEnabled(DI)) - pImpl->DiagnosticHandler(DI, pImpl->DiagnosticContext); + if (pImpl->DiagHandler && + (!pImpl->RespectDiagnosticFilters || isDiagnosticEnabled(DI)) && + pImpl->DiagHandler->handleDiagnostics(DI)) return; - } if (!isDiagnosticEnabled(DI)) return; @@ -315,3 +335,11 @@ void LLVMContext::setDiscardValueNames(bool Discard) { OptBisect &LLVMContext::getOptBisect() { return pImpl->getOptBisect(); } + +const DiagnosticHandler *LLVMContext::getDiagHandlerPtr() const { + return pImpl->DiagHandler.get(); +} + +std::unique_ptr<DiagnosticHandler> LLVMContext::getDiagnosticHandler() { + return std::move(pImpl->DiagHandler); +} diff --git a/lib/IR/LLVMContextImpl.cpp b/lib/IR/LLVMContextImpl.cpp index 57dd08b36fe7..4b44a6b69cad 100644 --- a/lib/IR/LLVMContextImpl.cpp +++ b/lib/IR/LLVMContextImpl.cpp @@ -22,7 +22,8 @@ using namespace llvm; LLVMContextImpl::LLVMContextImpl(LLVMContext &C) - : VoidTy(C, Type::VoidTyID), + : DiagHandler(llvm::make_unique<DiagnosticHandler>()), + VoidTy(C, Type::VoidTyID), LabelTy(C, Type::LabelTyID), HalfTy(C, Type::HalfTyID), FloatTy(C, Type::FloatTyID), diff --git a/lib/IR/LLVMContextImpl.h b/lib/IR/LLVMContextImpl.h index bea2c7ae8ff2..f41acfa8ea9c 100644 --- a/lib/IR/LLVMContextImpl.h +++ b/lib/IR/LLVMContextImpl.h @@ -1168,8 +1168,7 @@ public: LLVMContext::InlineAsmDiagHandlerTy InlineAsmDiagHandler = nullptr; void *InlineAsmDiagContext = nullptr; - LLVMContext::DiagnosticHandlerTy DiagnosticHandler = nullptr; - void *DiagnosticContext = nullptr; + std::unique_ptr<DiagnosticHandler> DiagHandler; bool RespectDiagnosticFilters = false; bool DiagnosticsHotnessRequested = false; uint64_t DiagnosticsHotnessThreshold = 0; diff --git a/lib/IR/LegacyPassManager.cpp b/lib/IR/LegacyPassManager.cpp index 995e1e570340..8bd9ed6ef0fa 100644 --- a/lib/IR/LegacyPassManager.cpp +++ b/lib/IR/LegacyPassManager.cpp @@ -75,21 +75,25 @@ PrintAfter("print-after", llvm::cl::desc("Print IR after specified passes"), cl::Hidden); +static cl::opt<bool> PrintBeforeAll("print-before-all", + llvm::cl::desc("Print IR before each pass"), + cl::init(false), cl::Hidden); +static cl::opt<bool> PrintAfterAll("print-after-all", + llvm::cl::desc("Print IR after each pass"), + cl::init(false), cl::Hidden); + static cl::opt<bool> -PrintBeforeAll("print-before-all", - llvm::cl::desc("Print IR before each pass"), - cl::init(false)); -static cl::opt<bool> -PrintAfterAll("print-after-all", - llvm::cl::desc("Print IR after each pass"), - cl::init(false)); + PrintModuleScope("print-module-scope", + cl::desc("When printing IR for print-[before|after]{-all} " + "always print a module IR"), + cl::init(false)); static cl::list<std::string> PrintFuncsList("filter-print-funcs", cl::value_desc("function names"), cl::desc("Only print IR for functions whose name " "match this for all print-[before|after][-all] " "options"), - cl::CommaSeparated); + cl::CommaSeparated, cl::Hidden); /// This is a helper to determine whether to print IR before or /// after a pass. @@ -117,6 +121,8 @@ static bool ShouldPrintAfterPass(const PassInfo *PI) { return PrintAfterAll || ShouldPrintBeforeOrAfterPass(PI, PrintAfter); } +bool llvm::forcePrintModuleIR() { return PrintModuleScope; } + bool llvm::isFunctionInPrintList(StringRef FunctionName) { static std::unordered_set<std::string> PrintFuncNames(PrintFuncsList.begin(), PrintFuncsList.end()); @@ -1729,9 +1735,9 @@ bool PassManager::run(Module &M) { // TimingInfo implementation bool llvm::TimePassesIsEnabled = false; -static cl::opt<bool,true> -EnableTiming("time-passes", cl::location(TimePassesIsEnabled), - cl::desc("Time each pass, printing elapsed time for each on exit")); +static cl::opt<bool, true> EnableTiming( + "time-passes", cl::location(TimePassesIsEnabled), cl::Hidden, + cl::desc("Time each pass, printing elapsed time for each on exit")); // createTheTimeInfo - This method either initializes the TheTimeInfo pointer to // a non-null value (if the -time-passes option is enabled) or it leaves it diff --git a/lib/IR/MDBuilder.cpp b/lib/IR/MDBuilder.cpp index b9c4f482adf5..6d77a8f2d601 100644 --- a/lib/IR/MDBuilder.cpp +++ b/lib/IR/MDBuilder.cpp @@ -14,6 +14,7 @@ #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" #include "llvm/IR/Metadata.h" using namespace llvm; @@ -62,9 +63,14 @@ MDNode *MDBuilder::createFunctionEntryCount( SmallVector<Metadata *, 8> Ops; Ops.push_back(createString("function_entry_count")); Ops.push_back(createConstant(ConstantInt::get(Int64Ty, Count))); - if (Imports) - for (auto ID : *Imports) + if (Imports) { + SmallVector<GlobalValue::GUID, 2> OrderID(Imports->begin(), Imports->end()); + std::stable_sort(OrderID.begin(), OrderID.end(), + [] (GlobalValue::GUID A, GlobalValue::GUID B) { + return A < B;}); + for (auto ID : OrderID) Ops.push_back(createConstant(ConstantInt::get(Int64Ty, ID))); + } return MDNode::get(Context, Ops); } @@ -90,6 +96,13 @@ MDNode *MDBuilder::createRange(Constant *Lo, Constant *Hi) { return MDNode::get(Context, {createConstant(Lo), createConstant(Hi)}); } +MDNode *MDBuilder::createCallees(ArrayRef<Function *> Callees) { + SmallVector<Metadata *, 4> Ops; + for (Function *F : Callees) + Ops.push_back(createConstant(F)); + return MDNode::get(Context, Ops); +} + MDNode *MDBuilder::createAnonymousAARoot(StringRef Name, MDNode *Extra) { // To ensure uniqueness the root node is self-referential. auto Dummy = MDNode::getTemporary(Context, None); @@ -144,7 +157,7 @@ MDNode *MDBuilder::createTBAAStructNode(ArrayRef<TBAAStructField> Fields) { for (unsigned i = 0, e = Fields.size(); i != e; ++i) { Vals[i * 3 + 0] = createConstant(ConstantInt::get(Int64, Fields[i].Offset)); Vals[i * 3 + 1] = createConstant(ConstantInt::get(Int64, Fields[i].Size)); - Vals[i * 3 + 2] = Fields[i].TBAA; + Vals[i * 3 + 2] = Fields[i].Type; } return MDNode::get(Context, Vals); } @@ -184,3 +197,40 @@ MDNode *MDBuilder::createTBAAStructTagNode(MDNode *BaseType, MDNode *AccessType, } return MDNode::get(Context, {BaseType, AccessType, createConstant(Off)}); } + +MDNode *MDBuilder::createTBAATypeNode(MDNode *Parent, uint64_t Size, + Metadata *Id, + ArrayRef<TBAAStructField> Fields) { + SmallVector<Metadata *, 4> Ops(3 + Fields.size() * 3); + Type *Int64 = Type::getInt64Ty(Context); + Ops[0] = Parent; + Ops[1] = createConstant(ConstantInt::get(Int64, Size)); + Ops[2] = Id; + for (unsigned I = 0, E = Fields.size(); I != E; ++I) { + Ops[I * 3 + 3] = Fields[I].Type; + Ops[I * 3 + 4] = createConstant(ConstantInt::get(Int64, Fields[I].Offset)); + Ops[I * 3 + 5] = createConstant(ConstantInt::get(Int64, Fields[I].Size)); + } + return MDNode::get(Context, Ops); +} + +MDNode *MDBuilder::createTBAAAccessTag(MDNode *BaseType, MDNode *AccessType, + uint64_t Offset, uint64_t Size, + bool IsImmutable) { + IntegerType *Int64 = Type::getInt64Ty(Context); + auto *OffsetNode = createConstant(ConstantInt::get(Int64, Offset)); + auto *SizeNode = createConstant(ConstantInt::get(Int64, Size)); + if (IsImmutable) { + auto *ImmutabilityFlagNode = createConstant(ConstantInt::get(Int64, 1)); + return MDNode::get(Context, {BaseType, AccessType, OffsetNode, SizeNode, + ImmutabilityFlagNode}); + } + return MDNode::get(Context, {BaseType, AccessType, OffsetNode, SizeNode}); +} + +MDNode *MDBuilder::createIrrLoopHeaderWeight(uint64_t Weight) { + SmallVector<Metadata *, 2> Vals(2); + Vals[0] = createString("loop_header_weight"); + Vals[1] = createConstant(ConstantInt::get(Type::getInt64Ty(Context), Weight)); + return MDNode::get(Context, Vals); +} diff --git a/lib/IR/Metadata.cpp b/lib/IR/Metadata.cpp index ac02ff76c843..a148ab65fc83 100644 --- a/lib/IR/Metadata.cpp +++ b/lib/IR/Metadata.cpp @@ -1431,7 +1431,6 @@ void GlobalObject::setMetadata(StringRef Kind, MDNode *N) { MDNode *GlobalObject::getMetadata(unsigned KindID) const { SmallVector<MDNode *, 1> MDs; getMetadata(KindID, MDs); - assert(MDs.size() <= 1 && "Expected at most one metadata attachment"); if (MDs.empty()) return nullptr; return MDs[0]; diff --git a/lib/IR/OptBisect.cpp b/lib/IR/OptBisect.cpp index f1c70058fac2..dc7dcd2e4a97 100644 --- a/lib/IR/OptBisect.cpp +++ b/lib/IR/OptBisect.cpp @@ -1,4 +1,4 @@ -//===------- llvm/IR/OptBisect/Bisect.cpp - LLVM Bisect support --------===// +//===- llvm/IR/OptBisect/Bisect.cpp - LLVM Bisect support -----------------===// // // The LLVM Compiler Infrastructure // @@ -6,31 +6,38 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// This file implements support for a bisecting optimizations based on a /// command line option. -/// +// //===----------------------------------------------------------------------===// #include "llvm/IR/OptBisect.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/CallGraphSCCPass.h" -#include "llvm/Analysis/LazyCallGraph.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/RegionInfo.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" #include "llvm/IR/Module.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <limits> +#include <string> using namespace llvm; static cl::opt<int> OptBisectLimit("opt-bisect-limit", cl::Hidden, - cl::init(INT_MAX), cl::Optional, + cl::init(std::numeric_limits<int>::max()), + cl::Optional, cl::desc("Maximum optimization to perform")); OptBisect::OptBisect() { - BisectEnabled = OptBisectLimit != INT_MAX; + BisectEnabled = OptBisectLimit != std::numeric_limits<int>::max(); } static void printPassMessage(const StringRef &Name, int PassNum, diff --git a/lib/IR/Pass.cpp b/lib/IR/Pass.cpp index f1b5f2f108dc..5e0b59476c4b 100644 --- a/lib/IR/Pass.cpp +++ b/lib/IR/Pass.cpp @@ -14,14 +14,22 @@ //===----------------------------------------------------------------------===// #include "llvm/Pass.h" +#include "llvm/IR/Attributes.h" +#include "llvm/IR/BasicBlock.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRPrintingPasses.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/LegacyPassNameParser.h" #include "llvm/IR/Module.h" #include "llvm/IR/OptBisect.h" +#include "llvm/PassInfo.h" #include "llvm/PassRegistry.h" +#include "llvm/PassSupport.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +#include <cassert> + using namespace llvm; #define DEBUG_TYPE "ir" @@ -36,11 +44,11 @@ Pass::~Pass() { } // Force out-of-line virtual method. -ModulePass::~ModulePass() { } +ModulePass::~ModulePass() = default; -Pass *ModulePass::createPrinterPass(raw_ostream &O, +Pass *ModulePass::createPrinterPass(raw_ostream &OS, const std::string &Banner) const { - return createPrintModulePass(O, Banner); + return createPrintModulePass(OS, Banner); } PassManagerType ModulePass::getPotentialPassManagerType() const { @@ -63,7 +71,6 @@ void Pass::dumpPassStructure(unsigned Offset) { /// getPassName - Return a nice clean name for a pass. This usually /// implemented in terms of the name that is registered by one of the /// Registration templates, but can be overloaded directly. -/// StringRef Pass::getPassName() const { AnalysisID AID = getPassID(); const PassInfo *PI = PassRegistry::getPassRegistry()->getPassInfo(AID); @@ -113,9 +120,8 @@ void Pass::setResolver(AnalysisResolver *AR) { // print - Print out the internal state of the pass. This is called by Analyze // to print out the contents of an analysis. Otherwise it is not necessary to // implement this method. -// -void Pass::print(raw_ostream &O,const Module*) const { - O << "Pass::print not implemented for pass: '" << getPassName() << "'!\n"; +void Pass::print(raw_ostream &OS, const Module *) const { + OS << "Pass::print not implemented for pass: '" << getPassName() << "'!\n"; } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) @@ -129,7 +135,7 @@ LLVM_DUMP_METHOD void Pass::dump() const { // ImmutablePass Implementation // // Force out-of-line virtual method. -ImmutablePass::~ImmutablePass() { } +ImmutablePass::~ImmutablePass() = default; void ImmutablePass::initializePass() { // By default, don't do anything. @@ -139,9 +145,9 @@ void ImmutablePass::initializePass() { // FunctionPass Implementation // -Pass *FunctionPass::createPrinterPass(raw_ostream &O, +Pass *FunctionPass::createPrinterPass(raw_ostream &OS, const std::string &Banner) const { - return createPrintFunctionPass(O, Banner); + return createPrintFunctionPass(OS, Banner); } PassManagerType FunctionPass::getPotentialPassManagerType() const { @@ -164,9 +170,9 @@ bool FunctionPass::skipFunction(const Function &F) const { // BasicBlockPass Implementation // -Pass *BasicBlockPass::createPrinterPass(raw_ostream &O, +Pass *BasicBlockPass::createPrinterPass(raw_ostream &OS, const std::string &Banner) const { - return createPrintBasicBlockPass(O, Banner); + return createPrintBasicBlockPass(OS, Banner); } bool BasicBlockPass::doInitialization(Function &) { @@ -219,7 +225,7 @@ Pass *Pass::createPass(AnalysisID ID) { //===----------------------------------------------------------------------===// // RegisterAGBase implementation -// + RegisterAGBase::RegisterAGBase(StringRef Name, const void *InterfaceID, const void *PassID, bool isDefault) : PassInfo(Name, InterfaceID) { @@ -233,7 +239,6 @@ RegisterAGBase::RegisterAGBase(StringRef Name, const void *InterfaceID, // enumeratePasses - Iterate over the registered passes, calling the // passEnumerate callback on each PassInfo object. -// void PassRegistrationListener::enumeratePasses() { PassRegistry::getPassRegistry()->enumerateWith(this); } @@ -243,28 +248,31 @@ PassNameParser::PassNameParser(cl::Option &O) PassRegistry::getPassRegistry()->addRegistrationListener(this); } -PassNameParser::~PassNameParser() { - // This only gets called during static destruction, in which case the - // PassRegistry will have already been destroyed by llvm_shutdown(). So - // attempting to remove the registration listener is an error. -} +// This only gets called during static destruction, in which case the +// PassRegistry will have already been destroyed by llvm_shutdown(). So +// attempting to remove the registration listener is an error. +PassNameParser::~PassNameParser() = default; //===----------------------------------------------------------------------===// // AnalysisUsage Class Implementation // namespace { - struct GetCFGOnlyPasses : public PassRegistrationListener { - typedef AnalysisUsage::VectorType VectorType; - VectorType &CFGOnlyList; - GetCFGOnlyPasses(VectorType &L) : CFGOnlyList(L) {} - void passEnumerate(const PassInfo *P) override { - if (P->isCFGOnlyPass()) - CFGOnlyList.push_back(P->getTypeInfo()); - } - }; -} +struct GetCFGOnlyPasses : public PassRegistrationListener { + using VectorType = AnalysisUsage::VectorType; + + VectorType &CFGOnlyList; + + GetCFGOnlyPasses(VectorType &L) : CFGOnlyList(L) {} + + void passEnumerate(const PassInfo *P) override { + if (P->isCFGOnlyPass()) + CFGOnlyList.push_back(P->getTypeInfo()); + } +}; + +} // end anonymous namespace // setPreservesCFG - This function should be called to by the pass, iff they do // not: @@ -274,7 +282,6 @@ namespace { // // This function annotates the AnalysisUsage info object to say that analyses // that only depend on the CFG are preserved by this pass. -// void AnalysisUsage::setPreservesCFG() { // Since this transformation doesn't modify the CFG, it preserves all analyses // that only depend on the CFG (like dominators, loop info, etc...) diff --git a/lib/IR/PassRegistry.cpp b/lib/IR/PassRegistry.cpp index c0f6f07169ff..b0f1a9928725 100644 --- a/lib/IR/PassRegistry.cpp +++ b/lib/IR/PassRegistry.cpp @@ -14,8 +14,12 @@ #include "llvm/PassRegistry.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/PassInfo.h" #include "llvm/PassSupport.h" #include "llvm/Support/ManagedStatic.h" +#include <cassert> +#include <memory> +#include <utility> using namespace llvm; @@ -33,7 +37,7 @@ PassRegistry *PassRegistry::getPassRegistry() { // Accessors // -PassRegistry::~PassRegistry() {} +PassRegistry::~PassRegistry() = default; const PassInfo *PassRegistry::getPassInfo(const void *TI) const { sys::SmartScopedReader<true> Guard(Lock); @@ -120,6 +124,6 @@ void PassRegistry::addRegistrationListener(PassRegistrationListener *L) { void PassRegistry::removeRegistrationListener(PassRegistrationListener *L) { sys::SmartScopedWriter<true> Guard(Lock); - auto I = find(Listeners, L); + auto I = llvm::find(Listeners, L); Listeners.erase(I); } diff --git a/lib/IR/SafepointIRVerifier.cpp b/lib/IR/SafepointIRVerifier.cpp index 8b328c221da3..68e0ce39a54e 100644 --- a/lib/IR/SafepointIRVerifier.cpp +++ b/lib/IR/SafepointIRVerifier.cpp @@ -32,6 +32,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/SetOperations.h" #include "llvm/ADT/SetVector.h" #include "llvm/IR/BasicBlock.h" @@ -60,6 +61,7 @@ static cl::opt<bool> PrintOnly("safepoint-ir-verifier-print-only", static void Verify(const Function &F, const DominatorTree &DT); +namespace { struct SafepointIRVerifier : public FunctionPass { static char ID; // Pass identification, replacement for typeid DominatorTree DT; @@ -79,6 +81,7 @@ struct SafepointIRVerifier : public FunctionPass { StringRef getPassName() const override { return "safepoint verifier"; } }; +} // namespace void llvm::verifySafepointIR(Function &F) { SafepointIRVerifier pass; @@ -134,92 +137,25 @@ static void PrintValueSet(raw_ostream &OS, IteratorTy Begin, IteratorTy End) { /// correctly relocated value at that point, and is a subset of the set of /// definitions dominating that point. +using AvailableValueSet = DenseSet<const Value *>; + /// State we compute and track per basic block. struct BasicBlockState { // Set of values available coming in, before the phi nodes - DenseSet<const Value *> AvailableIn; + AvailableValueSet AvailableIn; // Set of values available going out - DenseSet<const Value *> AvailableOut; + AvailableValueSet AvailableOut; // AvailableOut minus AvailableIn. // All elements are Instructions - DenseSet<const Value *> Contribution; + AvailableValueSet Contribution; // True if this block contains a safepoint and thus AvailableIn does not // contribute to AvailableOut. bool Cleared = false; }; - -/// Gather all the definitions dominating the start of BB into Result. This is -/// simply the Defs introduced by every dominating basic block and the function -/// arguments. -static void GatherDominatingDefs(const BasicBlock *BB, - DenseSet<const Value *> &Result, - const DominatorTree &DT, - DenseMap<const BasicBlock *, BasicBlockState *> &BlockMap) { - DomTreeNode *DTN = DT[const_cast<BasicBlock *>(BB)]; - - while (DTN->getIDom()) { - DTN = DTN->getIDom(); - const auto &Defs = BlockMap[DTN->getBlock()]->Contribution; - Result.insert(Defs.begin(), Defs.end()); - // If this block is 'Cleared', then nothing LiveIn to this block can be - // available after this block completes. Note: This turns out to be - // really important for reducing memory consuption of the initial available - // sets and thus peak memory usage by this verifier. - if (BlockMap[DTN->getBlock()]->Cleared) - return; - } - - for (const Argument &A : BB->getParent()->args()) - if (containsGCPtrType(A.getType())) - Result.insert(&A); -} - -/// Model the effect of an instruction on the set of available values. -static void TransferInstruction(const Instruction &I, bool &Cleared, - DenseSet<const Value *> &Available) { - if (isStatepoint(I)) { - Cleared = true; - Available.clear(); - } else if (containsGCPtrType(I.getType())) - Available.insert(&I); -} - -/// Compute the AvailableOut set for BB, based on the -/// BasicBlockState BBS, which is the BasicBlockState for BB. FirstPass is set -/// when the verifier runs for the first time computing the AvailableOut set -/// for BB. -static void TransferBlock(const BasicBlock *BB, - BasicBlockState &BBS, bool FirstPass) { - - const DenseSet<const Value *> &AvailableIn = BBS.AvailableIn; - DenseSet<const Value *> &AvailableOut = BBS.AvailableOut; - - if (BBS.Cleared) { - // AvailableOut does not change no matter how the input changes, just - // leave it be. We need to force this calculation the first time so that - // we have a AvailableOut at all. - if (FirstPass) { - AvailableOut = BBS.Contribution; - } - } else { - // Otherwise, we need to reduce the AvailableOut set by things which are no - // longer in our AvailableIn - DenseSet<const Value *> Temp = BBS.Contribution; - set_union(Temp, AvailableIn); - AvailableOut = std::move(Temp); - } - - DEBUG(dbgs() << "Transfered block " << BB->getName() << " from "; - PrintValueSet(dbgs(), AvailableIn.begin(), AvailableIn.end()); - dbgs() << " to "; - PrintValueSet(dbgs(), AvailableOut.begin(), AvailableOut.end()); - dbgs() << "\n";); -} - /// A given derived pointer can have multiple base pointers through phi/selects. /// This type indicates when the base pointer is exclusively constant /// (ExclusivelySomeConstant), and if that constant is proven to be exclusively @@ -291,32 +227,164 @@ static enum BaseType getBaseType(const Value *Val) { : BaseType::ExclusivelySomeConstant; } -static void Verify(const Function &F, const DominatorTree &DT) { +static bool isNotExclusivelyConstantDerived(const Value *V) { + return getBaseType(V) == BaseType::NonConstant; +} + +namespace { +class InstructionVerifier; + +/// Builds BasicBlockState for each BB of the function. +/// It can traverse function for verification and provides all required +/// information. +class GCPtrTracker { + const Function &F; SpecificBumpPtrAllocator<BasicBlockState> BSAllocator; DenseMap<const BasicBlock *, BasicBlockState *> BlockMap; - - DEBUG(dbgs() << "Verifying gc pointers in function: " << F.getName() << "\n"); - if (PrintOnly) - dbgs() << "Verifying gc pointers in function: " << F.getName() << "\n"; + // This set contains defs of unrelocated pointers that are proved to be legal + // and don't need verification. + DenseSet<const Instruction *> ValidUnrelocatedDefs; + +public: + GCPtrTracker(const Function &F, const DominatorTree &DT); + + BasicBlockState *getBasicBlockState(const BasicBlock *BB); + const BasicBlockState *getBasicBlockState(const BasicBlock *BB) const; + + /// Traverse each BB of the function and call + /// InstructionVerifier::verifyInstruction for each possibly invalid + /// instruction. + /// It destructively modifies GCPtrTracker so it's passed via rvalue reference + /// in order to prohibit further usages of GCPtrTracker as it'll be in + /// inconsistent state. + static void verifyFunction(GCPtrTracker &&Tracker, + InstructionVerifier &Verifier); + +private: + /// Returns true if the instruction may be safely skipped during verification. + bool instructionMayBeSkipped(const Instruction *I) const; + + /// Iterates over all BBs from BlockMap and recalculates AvailableIn/Out for + /// each of them until it converges. + void recalculateBBsStates(); + + /// Remove from Contribution all defs that legally produce unrelocated + /// pointers and saves them to ValidUnrelocatedDefs. + /// Though Contribution should belong to BBS it is passed separately with + /// different const-modifier in order to emphasize (and guarantee) that only + /// Contribution will be changed. + /// Returns true if Contribution was changed otherwise false. + bool removeValidUnrelocatedDefs(const BasicBlock *BB, + const BasicBlockState *BBS, + AvailableValueSet &Contribution); + + /// Gather all the definitions dominating the start of BB into Result. This is + /// simply the defs introduced by every dominating basic block and the + /// function arguments. + void gatherDominatingDefs(const BasicBlock *BB, AvailableValueSet &Result, + const DominatorTree &DT); + /// Compute the AvailableOut set for BB, based on the BasicBlockState BBS, + /// which is the BasicBlockState for BB. + /// ContributionChanged is set when the verifier runs for the first time + /// (in this case Contribution was changed from 'empty' to its initial state) + /// or when Contribution of this BB was changed since last computation. + static void transferBlock(const BasicBlock *BB, BasicBlockState &BBS, + bool ContributionChanged); + /// Model the effect of an instruction on the set of available values. + static void transferInstruction(const Instruction &I, bool &Cleared, + AvailableValueSet &Available); +}; + +/// It is a visitor for GCPtrTracker::verifyFunction. It decides if the +/// instruction (which uses heap reference) is legal or not, given our safepoint +/// semantics. +class InstructionVerifier { + bool AnyInvalidUses = false; + +public: + void verifyInstruction(const GCPtrTracker *Tracker, const Instruction &I, + const AvailableValueSet &AvailableSet); + + bool hasAnyInvalidUses() const { return AnyInvalidUses; } + +private: + void reportInvalidUse(const Value &V, const Instruction &I); +}; +} // end anonymous namespace + +GCPtrTracker::GCPtrTracker(const Function &F, const DominatorTree &DT) : F(F) { + // First, calculate Contribution of each BB. for (const BasicBlock &BB : F) { - BasicBlockState *BBS = new(BSAllocator.Allocate()) BasicBlockState; + BasicBlockState *BBS = new (BSAllocator.Allocate()) BasicBlockState; for (const auto &I : BB) - TransferInstruction(I, BBS->Cleared, BBS->Contribution); + transferInstruction(I, BBS->Cleared, BBS->Contribution); BlockMap[&BB] = BBS; } + // Initialize AvailableIn/Out sets of each BB using only information about + // dominating BBs. for (auto &BBI : BlockMap) { - GatherDominatingDefs(BBI.first, BBI.second->AvailableIn, DT, BlockMap); - TransferBlock(BBI.first, *BBI.second, true); + gatherDominatingDefs(BBI.first, BBI.second->AvailableIn, DT); + transferBlock(BBI.first, *BBI.second, true); } + // Simulate the flow of defs through the CFG and recalculate AvailableIn/Out + // sets of each BB until it converges. If any def is proved to be an + // unrelocated pointer, it will be removed from all BBSs. + recalculateBBsStates(); +} + +BasicBlockState *GCPtrTracker::getBasicBlockState(const BasicBlock *BB) { + auto it = BlockMap.find(BB); + assert(it != BlockMap.end() && + "No such BB in BlockMap! Probably BB from another function"); + return it->second; +} + +const BasicBlockState *GCPtrTracker::getBasicBlockState( + const BasicBlock *BB) const { + return const_cast<GCPtrTracker *>(this)->getBasicBlockState(BB); +} + +bool GCPtrTracker::instructionMayBeSkipped(const Instruction *I) const { + return ValidUnrelocatedDefs.count(I); +} + +void GCPtrTracker::verifyFunction(GCPtrTracker &&Tracker, + InstructionVerifier &Verifier) { + // We need RPO here to a) report always the first error b) report errors in + // same order from run to run. + ReversePostOrderTraversal<const Function *> RPOT(&Tracker.F); + for (const BasicBlock *BB : RPOT) { + BasicBlockState *BBS = Tracker.getBasicBlockState(BB); + // We destructively modify AvailableIn as we traverse the block instruction + // by instruction. + AvailableValueSet &AvailableSet = BBS->AvailableIn; + for (const Instruction &I : *BB) { + if (Tracker.instructionMayBeSkipped(&I)) + continue; // This instruction shouldn't be added to AvailableSet. + + Verifier.verifyInstruction(&Tracker, I, AvailableSet); + + // Model the effect of current instruction on AvailableSet to keep the set + // relevant at each point of BB. + bool Cleared = false; + transferInstruction(I, Cleared, AvailableSet); + (void)Cleared; + } + } +} + +void GCPtrTracker::recalculateBBsStates() { SetVector<const BasicBlock *> Worklist; + // TODO: This order is suboptimal, it's better to replace it with priority + // queue where priority is RPO number of BB. for (auto &BBI : BlockMap) Worklist.insert(BBI.first); - // This loop iterates the AvailableIn and AvailableOut sets to a fixed point. + // This loop iterates the AvailableIn/Out sets until it converges. // The AvailableIn and AvailableOut sets decrease as we iterate. while (!Worklist.empty()) { const BasicBlock *BB = Worklist.pop_back_val(); @@ -326,111 +394,205 @@ static void Verify(const Function &F, const DominatorTree &DT) { for (const BasicBlock *PBB : predecessors(BB)) set_intersect(BBS->AvailableIn, BlockMap[PBB]->AvailableOut); - if (OldInCount == BBS->AvailableIn.size()) - continue; + assert(OldInCount >= BBS->AvailableIn.size() && "invariant!"); - assert(OldInCount > BBS->AvailableIn.size() && "invariant!"); + bool InputsChanged = OldInCount != BBS->AvailableIn.size(); + bool ContributionChanged = + removeValidUnrelocatedDefs(BB, BBS, BBS->Contribution); + if (!InputsChanged && !ContributionChanged) + continue; size_t OldOutCount = BBS->AvailableOut.size(); - TransferBlock(BB, *BBS, false); + transferBlock(BB, *BBS, ContributionChanged); if (OldOutCount != BBS->AvailableOut.size()) { assert(OldOutCount > BBS->AvailableOut.size() && "invariant!"); Worklist.insert(succ_begin(BB), succ_end(BB)); } } +} - // We now have all the information we need to decide if the use of a heap - // reference is legal or not, given our safepoint semantics. +bool GCPtrTracker::removeValidUnrelocatedDefs(const BasicBlock *BB, + const BasicBlockState *BBS, + AvailableValueSet &Contribution) { + assert(&BBS->Contribution == &Contribution && + "Passed Contribution should be from the passed BasicBlockState!"); + AvailableValueSet AvailableSet = BBS->AvailableIn; + bool ContributionChanged = false; + for (const Instruction &I : *BB) { + bool ProducesUnrelocatedPointer = false; + if ((isa<GetElementPtrInst>(I) || isa<BitCastInst>(I)) && + containsGCPtrType(I.getType())) { + // GEP/bitcast of unrelocated pointer is legal by itself but this + // def shouldn't appear in any AvailableSet. + for (const Value *V : I.operands()) + if (containsGCPtrType(V->getType()) && + isNotExclusivelyConstantDerived(V) && !AvailableSet.count(V)) { + ProducesUnrelocatedPointer = true; + break; + } + } + if (!ProducesUnrelocatedPointer) { + bool Cleared = false; + transferInstruction(I, Cleared, AvailableSet); + (void)Cleared; + } else { + // Remove def of unrelocated pointer from Contribution of this BB + // and trigger update of all its successors. + Contribution.erase(&I); + ValidUnrelocatedDefs.insert(&I); + DEBUG(dbgs() << "Removing " << I << " from Contribution of " + << BB->getName() << "\n"); + ContributionChanged = true; + } + } + return ContributionChanged; +} - bool AnyInvalidUses = false; +void GCPtrTracker::gatherDominatingDefs(const BasicBlock *BB, + AvailableValueSet &Result, + const DominatorTree &DT) { + DomTreeNode *DTN = DT[const_cast<BasicBlock *>(BB)]; - auto ReportInvalidUse = [&AnyInvalidUses](const Value &V, - const Instruction &I) { - errs() << "Illegal use of unrelocated value found!\n"; - errs() << "Def: " << V << "\n"; - errs() << "Use: " << I << "\n"; - if (!PrintOnly) - abort(); - AnyInvalidUses = true; - }; + while (DTN->getIDom()) { + DTN = DTN->getIDom(); + const auto &Defs = BlockMap[DTN->getBlock()]->Contribution; + Result.insert(Defs.begin(), Defs.end()); + // If this block is 'Cleared', then nothing LiveIn to this block can be + // available after this block completes. Note: This turns out to be + // really important for reducing memory consuption of the initial available + // sets and thus peak memory usage by this verifier. + if (BlockMap[DTN->getBlock()]->Cleared) + return; + } - auto isNotExclusivelyConstantDerived = [](const Value *V) { - return getBaseType(V) == BaseType::NonConstant; - }; + for (const Argument &A : BB->getParent()->args()) + if (containsGCPtrType(A.getType())) + Result.insert(&A); +} - for (const BasicBlock &BB : F) { - // We destructively modify AvailableIn as we traverse the block instruction - // by instruction. - DenseSet<const Value *> &AvailableSet = BlockMap[&BB]->AvailableIn; - for (const Instruction &I : BB) { - if (const PHINode *PN = dyn_cast<PHINode>(&I)) { - if (containsGCPtrType(PN->getType())) - for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { - const BasicBlock *InBB = PN->getIncomingBlock(i); - const Value *InValue = PN->getIncomingValue(i); +void GCPtrTracker::transferBlock(const BasicBlock *BB, BasicBlockState &BBS, + bool ContributionChanged) { + const AvailableValueSet &AvailableIn = BBS.AvailableIn; + AvailableValueSet &AvailableOut = BBS.AvailableOut; + + if (BBS.Cleared) { + // AvailableOut will change only when Contribution changed. + if (ContributionChanged) + AvailableOut = BBS.Contribution; + } else { + // Otherwise, we need to reduce the AvailableOut set by things which are no + // longer in our AvailableIn + AvailableValueSet Temp = BBS.Contribution; + set_union(Temp, AvailableIn); + AvailableOut = std::move(Temp); + } - if (isNotExclusivelyConstantDerived(InValue) && - !BlockMap[InBB]->AvailableOut.count(InValue)) - ReportInvalidUse(*InValue, *PN); - } - } else if (isa<CmpInst>(I) && - containsGCPtrType(I.getOperand(0)->getType())) { - Value *LHS = I.getOperand(0), *RHS = I.getOperand(1); - enum BaseType baseTyLHS = getBaseType(LHS), - baseTyRHS = getBaseType(RHS); + DEBUG(dbgs() << "Transfered block " << BB->getName() << " from "; + PrintValueSet(dbgs(), AvailableIn.begin(), AvailableIn.end()); + dbgs() << " to "; + PrintValueSet(dbgs(), AvailableOut.begin(), AvailableOut.end()); + dbgs() << "\n";); +} - // Returns true if LHS and RHS are unrelocated pointers and they are - // valid unrelocated uses. - auto hasValidUnrelocatedUse = [&AvailableSet, baseTyLHS, baseTyRHS, &LHS, &RHS] () { - // A cmp instruction has valid unrelocated pointer operands only if - // both operands are unrelocated pointers. - // In the comparison between two pointers, if one is an unrelocated - // use, the other *should be* an unrelocated use, for this - // instruction to contain valid unrelocated uses. This unrelocated - // use can be a null constant as well, or another unrelocated - // pointer. - if (AvailableSet.count(LHS) || AvailableSet.count(RHS)) - return false; - // Constant pointers (that are not exclusively null) may have - // meaning in different VMs, so we cannot reorder the compare - // against constant pointers before the safepoint. In other words, - // comparison of an unrelocated use against a non-null constant - // maybe invalid. - if ((baseTyLHS == BaseType::ExclusivelySomeConstant && - baseTyRHS == BaseType::NonConstant) || - (baseTyLHS == BaseType::NonConstant && - baseTyRHS == BaseType::ExclusivelySomeConstant)) - return false; - // All other cases are valid cases enumerated below: - // 1. Comparison between an exlusively derived null pointer and a - // constant base pointer. - // 2. Comparison between an exlusively derived null pointer and a - // non-constant unrelocated base pointer. - // 3. Comparison between 2 unrelocated pointers. - return true; - }; - if (!hasValidUnrelocatedUse()) { - // Print out all non-constant derived pointers that are unrelocated - // uses, which are invalid. - if (baseTyLHS == BaseType::NonConstant && !AvailableSet.count(LHS)) - ReportInvalidUse(*LHS, I); - if (baseTyRHS == BaseType::NonConstant && !AvailableSet.count(RHS)) - ReportInvalidUse(*RHS, I); - } - } else { - for (const Value *V : I.operands()) - if (containsGCPtrType(V->getType()) && - isNotExclusivelyConstantDerived(V) && !AvailableSet.count(V)) - ReportInvalidUse(*V, I); +void GCPtrTracker::transferInstruction(const Instruction &I, bool &Cleared, + AvailableValueSet &Available) { + if (isStatepoint(I)) { + Cleared = true; + Available.clear(); + } else if (containsGCPtrType(I.getType())) + Available.insert(&I); +} + +void InstructionVerifier::verifyInstruction( + const GCPtrTracker *Tracker, const Instruction &I, + const AvailableValueSet &AvailableSet) { + if (const PHINode *PN = dyn_cast<PHINode>(&I)) { + if (containsGCPtrType(PN->getType())) + for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { + const BasicBlock *InBB = PN->getIncomingBlock(i); + const Value *InValue = PN->getIncomingValue(i); + + if (isNotExclusivelyConstantDerived(InValue) && + !Tracker->getBasicBlockState(InBB)->AvailableOut.count(InValue)) + reportInvalidUse(*InValue, *PN); } + } else if (isa<CmpInst>(I) && + containsGCPtrType(I.getOperand(0)->getType())) { + Value *LHS = I.getOperand(0), *RHS = I.getOperand(1); + enum BaseType baseTyLHS = getBaseType(LHS), + baseTyRHS = getBaseType(RHS); - bool Cleared = false; - TransferInstruction(I, Cleared, AvailableSet); - (void)Cleared; + // Returns true if LHS and RHS are unrelocated pointers and they are + // valid unrelocated uses. + auto hasValidUnrelocatedUse = [&AvailableSet, baseTyLHS, baseTyRHS, &LHS, + &RHS] () { + // A cmp instruction has valid unrelocated pointer operands only if + // both operands are unrelocated pointers. + // In the comparison between two pointers, if one is an unrelocated + // use, the other *should be* an unrelocated use, for this + // instruction to contain valid unrelocated uses. This unrelocated + // use can be a null constant as well, or another unrelocated + // pointer. + if (AvailableSet.count(LHS) || AvailableSet.count(RHS)) + return false; + // Constant pointers (that are not exclusively null) may have + // meaning in different VMs, so we cannot reorder the compare + // against constant pointers before the safepoint. In other words, + // comparison of an unrelocated use against a non-null constant + // maybe invalid. + if ((baseTyLHS == BaseType::ExclusivelySomeConstant && + baseTyRHS == BaseType::NonConstant) || + (baseTyLHS == BaseType::NonConstant && + baseTyRHS == BaseType::ExclusivelySomeConstant)) + return false; + // All other cases are valid cases enumerated below: + // 1. Comparison between an exlusively derived null pointer and a + // constant base pointer. + // 2. Comparison between an exlusively derived null pointer and a + // non-constant unrelocated base pointer. + // 3. Comparison between 2 unrelocated pointers. + return true; + }; + if (!hasValidUnrelocatedUse()) { + // Print out all non-constant derived pointers that are unrelocated + // uses, which are invalid. + if (baseTyLHS == BaseType::NonConstant && !AvailableSet.count(LHS)) + reportInvalidUse(*LHS, I); + if (baseTyRHS == BaseType::NonConstant && !AvailableSet.count(RHS)) + reportInvalidUse(*RHS, I); } + } else { + for (const Value *V : I.operands()) + if (containsGCPtrType(V->getType()) && + isNotExclusivelyConstantDerived(V) && !AvailableSet.count(V)) + reportInvalidUse(*V, I); } +} + +void InstructionVerifier::reportInvalidUse(const Value &V, + const Instruction &I) { + errs() << "Illegal use of unrelocated value found!\n"; + errs() << "Def: " << V << "\n"; + errs() << "Use: " << I << "\n"; + if (!PrintOnly) + abort(); + AnyInvalidUses = true; +} + +static void Verify(const Function &F, const DominatorTree &DT) { + DEBUG(dbgs() << "Verifying gc pointers in function: " << F.getName() << "\n"); + if (PrintOnly) + dbgs() << "Verifying gc pointers in function: " << F.getName() << "\n"; + + GCPtrTracker Tracker(F, DT); + + // We now have all the information we need to decide if the use of a heap + // reference is legal or not, given our safepoint semantics. + + InstructionVerifier Verifier; + GCPtrTracker::verifyFunction(std::move(Tracker), Verifier); - if (PrintOnly && !AnyInvalidUses) { + if (PrintOnly && !Verifier.hasAnyInvalidUses()) { dbgs() << "No illegal uses found by SafepointIRVerifier in: " << F.getName() << "\n"; } diff --git a/lib/IR/User.cpp b/lib/IR/User.cpp index d46039107f33..041593f20b57 100644 --- a/lib/IR/User.cpp +++ b/lib/IR/User.cpp @@ -10,7 +10,6 @@ #include "llvm/IR/User.h" #include "llvm/IR/Constant.h" #include "llvm/IR/GlobalValue.h" -#include "llvm/IR/Operator.h" namespace llvm { class BasicBlock; diff --git a/lib/IR/Value.cpp b/lib/IR/Value.cpp index 51a7d424c1f3..eae697b2e4b9 100644 --- a/lib/IR/Value.cpp +++ b/lib/IR/Value.cpp @@ -15,6 +15,7 @@ #include "LLVMContextImpl.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SetVector.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" @@ -50,6 +51,7 @@ Value::Value(Type *ty, unsigned scid) : VTy(checkType(ty)), UseList(nullptr), SubclassID(scid), HasValueHandle(0), SubclassOptionalData(0), SubclassData(0), NumUserOperands(0), IsUsedByMD(false), HasName(false) { + static_assert(ConstantFirstVal == 0, "!(SubclassID < ConstantFirstVal)"); // FIXME: Why isn't this in the subclass gunk?? // Note, we cannot call isa<CallInst> before the CallInst has been // constructed. @@ -57,7 +59,7 @@ Value::Value(Type *ty, unsigned scid) assert((VTy->isFirstClassType() || VTy->isVoidTy() || VTy->isStructTy()) && "invalid CallInst type!"); else if (SubclassID != BasicBlockVal && - (SubclassID < ConstantFirstVal || SubclassID > ConstantLastVal)) + (/*SubclassID < ConstantFirstVal ||*/ SubclassID > ConstantLastVal)) assert((VTy->isFirstClassType() || VTy->isVoidTy()) && "Cannot create non-first-class values except for constants!"); static_assert(sizeof(Value) == 2 * sizeof(void *) + 2 * sizeof(unsigned), @@ -407,7 +409,7 @@ void Value::doRAUW(Value *New, bool NoMetadata) { if (!NoMetadata && isUsedByMetadata()) ValueAsMetadata::handleRAUW(this, New); - while (!use_empty()) { + while (!materialized_use_empty()) { Use &U = *UseList; // Must handle Constants specially, we cannot call replaceUsesOfWith on a // constant because they are uniqued. @@ -454,6 +456,35 @@ void Value::replaceUsesOutsideBlock(Value *New, BasicBlock *BB) { } } +void Value::replaceUsesExceptBlockAddr(Value *New) { + SmallSetVector<Constant *, 4> Constants; + use_iterator UI = use_begin(), E = use_end(); + for (; UI != E;) { + Use &U = *UI; + ++UI; + + if (isa<BlockAddress>(U.getUser())) + continue; + + // Must handle Constants specially, we cannot call replaceUsesOfWith on a + // constant because they are uniqued. + if (auto *C = dyn_cast<Constant>(U.getUser())) { + if (!isa<GlobalValue>(C)) { + // Save unique users to avoid processing operand replacement + // more than once. + Constants.insert(C); + continue; + } + } + + U.set(New); + } + + // Process operand replacement of saved constants. + for (auto *C : Constants) + C->handleOperandChange(this, New); +} + namespace { // Various metrics for how much to strip off of pointers. enum PointerStripKind { @@ -588,17 +619,17 @@ const Value *Value::stripInBoundsOffsets() const { return stripPointerCastsAndOffsets<PSK_InBounds>(this); } -unsigned Value::getPointerDereferenceableBytes(const DataLayout &DL, +uint64_t Value::getPointerDereferenceableBytes(const DataLayout &DL, bool &CanBeNull) const { assert(getType()->isPointerTy() && "must be pointer"); - unsigned DerefBytes = 0; + uint64_t DerefBytes = 0; CanBeNull = false; if (const Argument *A = dyn_cast<Argument>(this)) { DerefBytes = A->getDereferenceableBytes(); - if (DerefBytes == 0 && A->hasByValAttr() && A->getType()->isSized()) { - DerefBytes = DL.getTypeStoreSize(A->getType()); - CanBeNull = false; + if (DerefBytes == 0 && A->hasByValAttr()) { + Type *PT = cast<PointerType>(A->getType())->getElementType(); + DerefBytes = DL.getTypeStoreSize(PT); } if (DerefBytes == 0) { DerefBytes = A->getDereferenceableOrNullBytes(); @@ -624,8 +655,10 @@ unsigned Value::getPointerDereferenceableBytes(const DataLayout &DL, CanBeNull = true; } } else if (auto *AI = dyn_cast<AllocaInst>(this)) { - if (AI->getAllocatedType()->isSized()) { - DerefBytes = DL.getTypeStoreSize(AI->getAllocatedType()); + const ConstantInt *ArraySize = dyn_cast<ConstantInt>(AI->getArraySize()); + if (ArraySize && AI->getAllocatedType()->isSized()) { + DerefBytes = DL.getTypeStoreSize(AI->getAllocatedType()) * + ArraySize->getZExtValue(); CanBeNull = false; } } else if (auto *GV = dyn_cast<GlobalVariable>(this)) { diff --git a/lib/IR/ValueSymbolTable.cpp b/lib/IR/ValueSymbolTable.cpp index ccdabe0817b4..0da1990c3a3f 100644 --- a/lib/IR/ValueSymbolTable.cpp +++ b/lib/IR/ValueSymbolTable.cpp @@ -13,7 +13,9 @@ #include "llvm/IR/ValueSymbolTable.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Triple.h" #include "llvm/IR/GlobalValue.h" +#include "llvm/IR/Module.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" #include "llvm/Support/Casting.h" @@ -45,8 +47,17 @@ ValueName *ValueSymbolTable::makeUniqueName(Value *V, // Trim any suffix off and append the next number. UniqueName.resize(BaseSize); raw_svector_ostream S(UniqueName); - if (isa<GlobalValue>(V)) - S << "."; + if (auto *GV = dyn_cast<GlobalValue>(V)) { + // A dot is appended to mark it as clone during ABI demangling so that + // for example "_Z1fv" and "_Z1fv.1" both demangle to "f()", the second + // one being a clone. + // On NVPTX we cannot use a dot because PTX only allows [A-Za-z0-9_$] for + // identifiers. This breaks ABI demangling but at least ptxas accepts and + // compiles the program. + const Module *M = GV->getParent(); + if (!(M && Triple(M->getTargetTriple()).isNVPTX())) + S << "."; + } S << ++LastUnique; // Try insert the vmap entry with this suffix. diff --git a/lib/IR/ValueTypes.cpp b/lib/IR/ValueTypes.cpp index cf6ee063c2d5..22f9fe7a66d7 100644 --- a/lib/IR/ValueTypes.cpp +++ b/lib/IR/ValueTypes.cpp @@ -14,7 +14,6 @@ #include "llvm/CodeGen/ValueTypes.h" #include "llvm/ADT/StringExtras.h" #include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/LLVMContext.h" #include "llvm/IR/Type.h" #include "llvm/Support/ErrorHandling.h" using namespace llvm; @@ -149,6 +148,7 @@ std::string EVT::getEVTString() const { case MVT::v16i1: return "v16i1"; case MVT::v32i1: return "v32i1"; case MVT::v64i1: return "v64i1"; + case MVT::v128i1: return "v128i1"; case MVT::v512i1: return "v512i1"; case MVT::v1024i1: return "v1024i1"; case MVT::v1i8: return "v1i8"; @@ -228,6 +228,7 @@ Type *EVT::getTypeForEVT(LLVMContext &Context) const { case MVT::v16i1: return VectorType::get(Type::getInt1Ty(Context), 16); case MVT::v32i1: return VectorType::get(Type::getInt1Ty(Context), 32); case MVT::v64i1: return VectorType::get(Type::getInt1Ty(Context), 64); + case MVT::v128i1: return VectorType::get(Type::getInt1Ty(Context), 128); case MVT::v512i1: return VectorType::get(Type::getInt1Ty(Context), 512); case MVT::v1024i1: return VectorType::get(Type::getInt1Ty(Context), 1024); case MVT::v1i8: return VectorType::get(Type::getInt8Ty(Context), 1); diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index 454a56a76923..534104686d81 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -75,7 +75,6 @@ #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalAlias.h" @@ -115,8 +114,6 @@ using namespace llvm; -static cl::opt<bool> VerifyDebugInfo("verify-debug-info", cl::init(true)); - namespace llvm { struct VerifierSupport { @@ -468,8 +465,7 @@ private: void visitUserOp2(Instruction &I) { visitUserOp1(I); } void visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS); void visitConstrainedFPIntrinsic(ConstrainedFPIntrinsic &FPI); - template <class DbgIntrinsicTy> - void visitDbgIntrinsic(StringRef Kind, DbgIntrinsicTy &DII); + void visitDbgIntrinsic(StringRef Kind, DbgInfoIntrinsic &DII); void visitAtomicCmpXchgInst(AtomicCmpXchgInst &CXI); void visitAtomicRMWInst(AtomicRMWInst &RMWI); void visitFenceInst(FenceInst &FI); @@ -507,6 +503,10 @@ private: void verifySiblingFuncletUnwinds(); void verifyFragmentExpression(const DbgInfoIntrinsic &I); + template <typename ValueOrMetadata> + void verifyFragmentExpression(const DIVariable &V, + DIExpression::FragmentInfo Fragment, + ValueOrMetadata *Desc); void verifyFnArgs(const DbgInfoIntrinsic &I); /// Module-level debug info verification... @@ -565,6 +565,10 @@ void Verifier::visitGlobalValue(const GlobalValue &GV) { if (GV.isDeclarationForLinker()) Assert(!GV.hasComdat(), "Declaration may not be in a Comdat!", &GV); + if (GV.hasDLLImportStorageClass()) + Assert(!GV.isDSOLocal(), + "GlobalValue with DLLImport Storage is dso_local!", &GV); + forEachUser(&GV, GlobalValueVisited, [&](const Value *V) -> bool { if (const Instruction *I = dyn_cast<Instruction>(V)) { if (!I->getParent() || !I->getParent()->getParent()) @@ -839,6 +843,8 @@ void Verifier::visitDILocation(const DILocation &N) { "location requires a valid scope", &N, N.getRawScope()); if (auto *IA = N.getRawInlinedAt()) AssertDI(isa<DILocation>(IA), "inlined-at should be a location", &N, IA); + if (auto *SP = dyn_cast<DISubprogram>(N.getRawScope())) + AssertDI(SP->isDefinition(), "scope points into the type hierarchy", &N); } void Verifier::visitGenericDINode(const GenericDINode &N) { @@ -1067,6 +1073,8 @@ void Verifier::visitDILexicalBlockBase(const DILexicalBlockBase &N) { AssertDI(N.getTag() == dwarf::DW_TAG_lexical_block, "invalid tag", &N); AssertDI(N.getRawScope() && isa<DILocalScope>(N.getRawScope()), "invalid local scope", &N, N.getRawScope()); + if (auto *SP = dyn_cast<DISubprogram>(N.getRawScope())) + AssertDI(SP->isDefinition(), "scope points into the type hierarchy", &N); } void Verifier::visitDILexicalBlock(const DILexicalBlock &N) { @@ -1139,7 +1147,6 @@ void Verifier::visitDITemplateValueParameter( void Verifier::visitDIVariable(const DIVariable &N) { if (auto *S = N.getRawScope()) AssertDI(isa<DIScope>(S), "invalid scope", &N, S); - AssertDI(isType(N.getRawType()), "invalid type ref", &N, N.getRawType()); if (auto *F = N.getRawFile()) AssertDI(isa<DIFile>(F), "invalid file", &N, F); } @@ -1150,6 +1157,8 @@ void Verifier::visitDIGlobalVariable(const DIGlobalVariable &N) { AssertDI(N.getTag() == dwarf::DW_TAG_variable, "invalid tag", &N); AssertDI(!N.getName().empty(), "missing global variable name", &N); + AssertDI(isType(N.getRawType()), "invalid type ref", &N, N.getRawType()); + AssertDI(N.getType(), "missing global variable type", &N); if (auto *Member = N.getRawStaticDataMemberDeclaration()) { AssertDI(isa<DIDerivedType>(Member), "invalid static data member declaration", &N, Member); @@ -1160,6 +1169,7 @@ void Verifier::visitDILocalVariable(const DILocalVariable &N) { // Checks common to all variables. visitDIVariable(N); + AssertDI(isType(N.getRawType()), "invalid type ref", &N, N.getRawType()); AssertDI(N.getTag() == dwarf::DW_TAG_variable, "invalid tag", &N); AssertDI(N.getRawScope() && isa<DILocalScope>(N.getRawScope()), "local variable requires a valid scope", &N, N.getRawScope()); @@ -1174,8 +1184,11 @@ void Verifier::visitDIGlobalVariableExpression( AssertDI(GVE.getVariable(), "missing variable"); if (auto *Var = GVE.getVariable()) visitDIGlobalVariable(*Var); - if (auto *Expr = GVE.getExpression()) + if (auto *Expr = GVE.getExpression()) { visitDIExpression(*Expr); + if (auto Fragment = Expr->getFragmentInfo()) + verifyFragmentExpression(*GVE.getVariable(), *Fragment, &GVE); + } } void Verifier::visitDIObjCProperty(const DIObjCProperty &N) { @@ -1361,6 +1374,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) { case Attribute::NonLazyBind: case Attribute::ReturnsTwice: case Attribute::SanitizeAddress: + case Attribute::SanitizeHWAddress: case Attribute::SanitizeThread: case Attribute::SanitizeMemory: case Attribute::MinSize: @@ -1377,6 +1391,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) { case Attribute::InaccessibleMemOrArgMemOnly: case Attribute::AllocSize: case Attribute::Speculatable: + case Attribute::StrictFP: return true; default: break; @@ -3001,7 +3016,11 @@ void Verifier::visitGetElementPtrInst(GetElementPtrInst &GEP) { Assert(isa<PointerType>(TargetTy), "GEP base pointer is not a vector or a vector of pointers", &GEP); Assert(GEP.getSourceElementType()->isSized(), "GEP into unsized type!", &GEP); + SmallVector<Value*, 16> Idxs(GEP.idx_begin(), GEP.idx_end()); + Assert(all_of( + Idxs, [](Value* V) { return V->getType()->isIntOrIntVectorTy(); }), + "GEP indexes must be integers", &GEP); Type *ElTy = GetElementPtrInst::getIndexedType(GEP.getSourceElementType(), Idxs); Assert(ElTy, "Invalid indices for GEP pointer type!", &GEP); @@ -3969,6 +3988,7 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) { case Intrinsic::experimental_constrained_fmul: case Intrinsic::experimental_constrained_fdiv: case Intrinsic::experimental_constrained_frem: + case Intrinsic::experimental_constrained_fma: case Intrinsic::experimental_constrained_sqrt: case Intrinsic::experimental_constrained_pow: case Intrinsic::experimental_constrained_powi: @@ -3987,10 +4007,13 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) { case Intrinsic::dbg_declare: // llvm.dbg.declare Assert(isa<MetadataAsValue>(CS.getArgOperand(0)), "invalid llvm.dbg.declare intrinsic call 1", CS); - visitDbgIntrinsic("declare", cast<DbgDeclareInst>(*CS.getInstruction())); + visitDbgIntrinsic("declare", cast<DbgInfoIntrinsic>(*CS.getInstruction())); + break; + case Intrinsic::dbg_addr: // llvm.dbg.addr + visitDbgIntrinsic("addr", cast<DbgInfoIntrinsic>(*CS.getInstruction())); break; case Intrinsic::dbg_value: // llvm.dbg.value - visitDbgIntrinsic("value", cast<DbgValueInst>(*CS.getInstruction())); + visitDbgIntrinsic("value", cast<DbgInfoIntrinsic>(*CS.getInstruction())); break; case Intrinsic::memcpy: case Intrinsic::memmove: @@ -4008,9 +4031,7 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) { break; } case Intrinsic::memcpy_element_unordered_atomic: { - const ElementUnorderedAtomicMemCpyInst *MI = - cast<ElementUnorderedAtomicMemCpyInst>(CS.getInstruction()); - ; + const AtomicMemCpyInst *MI = cast<AtomicMemCpyInst>(CS.getInstruction()); ConstantInt *ElementSizeCI = dyn_cast<ConstantInt>(MI->getRawElementSizeInBytes()); @@ -4045,7 +4066,7 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) { break; } case Intrinsic::memmove_element_unordered_atomic: { - auto *MI = cast<ElementUnorderedAtomicMemMoveInst>(CS.getInstruction()); + auto *MI = cast<AtomicMemMoveInst>(CS.getInstruction()); ConstantInt *ElementSizeCI = dyn_cast<ConstantInt>(MI->getRawElementSizeInBytes()); @@ -4080,7 +4101,7 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) { break; } case Intrinsic::memset_element_unordered_atomic: { - auto *MI = cast<ElementUnorderedAtomicMemSetInst>(CS.getInstruction()); + auto *MI = cast<AtomicMemSetInst>(CS.getInstruction()); ConstantInt *ElementSizeCI = dyn_cast<ConstantInt>(MI->getRawElementSizeInBytes()); @@ -4429,8 +4450,9 @@ static DISubprogram *getSubprogram(Metadata *LocalScope) { void Verifier::visitConstrainedFPIntrinsic(ConstrainedFPIntrinsic &FPI) { unsigned NumOperands = FPI.getNumArgOperands(); - Assert(((NumOperands == 3 && FPI.isUnaryOp()) || (NumOperands == 4)), - "invalid arguments for constrained FP intrinsic", &FPI); + Assert(((NumOperands == 5 && FPI.isTernaryOp()) || + (NumOperands == 3 && FPI.isUnaryOp()) || (NumOperands == 4)), + "invalid arguments for constrained FP intrinsic", &FPI); Assert(isa<MetadataAsValue>(FPI.getArgOperand(NumOperands-1)), "invalid exception behavior argument", &FPI); Assert(isa<MetadataAsValue>(FPI.getArgOperand(NumOperands-2)), @@ -4441,8 +4463,7 @@ void Verifier::visitConstrainedFPIntrinsic(ConstrainedFPIntrinsic &FPI) { "invalid exception behavior argument", &FPI); } -template <class DbgIntrinsicTy> -void Verifier::visitDbgIntrinsic(StringRef Kind, DbgIntrinsicTy &DII) { +void Verifier::visitDbgIntrinsic(StringRef Kind, DbgInfoIntrinsic &DII) { auto *MD = cast<MetadataAsValue>(DII.getArgOperand(0))->getMetadata(); AssertDI(isa<ValueAsMetadata>(MD) || (isa<MDNode>(MD) && !cast<MDNode>(MD)->getNumOperands()), @@ -4481,46 +4502,15 @@ void Verifier::visitDbgIntrinsic(StringRef Kind, DbgIntrinsicTy &DII) { verifyFnArgs(DII); } -static uint64_t getVariableSize(const DILocalVariable &V) { - // Be careful of broken types (checked elsewhere). - const Metadata *RawType = V.getRawType(); - while (RawType) { - // Try to get the size directly. - if (auto *T = dyn_cast<DIType>(RawType)) - if (uint64_t Size = T->getSizeInBits()) - return Size; - - if (auto *DT = dyn_cast<DIDerivedType>(RawType)) { - // Look at the base type. - RawType = DT->getRawBaseType(); - continue; - } - - // Missing type or size. - break; - } - - // Fail gracefully. - return 0; -} - void Verifier::verifyFragmentExpression(const DbgInfoIntrinsic &I) { - DILocalVariable *V; - DIExpression *E; - if (auto *DVI = dyn_cast<DbgValueInst>(&I)) { - V = dyn_cast_or_null<DILocalVariable>(DVI->getRawVariable()); - E = dyn_cast_or_null<DIExpression>(DVI->getRawExpression()); - } else { - auto *DDI = cast<DbgDeclareInst>(&I); - V = dyn_cast_or_null<DILocalVariable>(DDI->getRawVariable()); - E = dyn_cast_or_null<DIExpression>(DDI->getRawExpression()); - } + DILocalVariable *V = dyn_cast_or_null<DILocalVariable>(I.getRawVariable()); + DIExpression *E = dyn_cast_or_null<DIExpression>(I.getRawExpression()); // We don't know whether this intrinsic verified correctly. if (!V || !E || !E->isValid()) return; - // Nothing to do if this isn't a bit piece expression. + // Nothing to do if this isn't a DW_OP_LLVM_fragment expression. auto Fragment = E->getFragmentInfo(); if (!Fragment) return; @@ -4534,17 +4524,24 @@ void Verifier::verifyFragmentExpression(const DbgInfoIntrinsic &I) { if (V->isArtificial()) return; + verifyFragmentExpression(*V, *Fragment, &I); +} + +template <typename ValueOrMetadata> +void Verifier::verifyFragmentExpression(const DIVariable &V, + DIExpression::FragmentInfo Fragment, + ValueOrMetadata *Desc) { // If there's no size, the type is broken, but that should be checked // elsewhere. - uint64_t VarSize = getVariableSize(*V); + auto VarSize = V.getSizeInBits(); if (!VarSize) return; - unsigned FragSize = Fragment->SizeInBits; - unsigned FragOffset = Fragment->OffsetInBits; - AssertDI(FragSize + FragOffset <= VarSize, - "fragment is larger than or outside of variable", &I, V, E); - AssertDI(FragSize != VarSize, "fragment covers entire variable", &I, V, E); + unsigned FragSize = Fragment.SizeInBits; + unsigned FragOffset = Fragment.OffsetInBits; + AssertDI(FragSize + FragOffset <= *VarSize, + "fragment is larger than or outside of variable", Desc, &V); + AssertDI(FragSize != *VarSize, "fragment covers entire variable", Desc, &V); } void Verifier::verifyFnArgs(const DbgInfoIntrinsic &I) { @@ -4554,18 +4551,11 @@ void Verifier::verifyFnArgs(const DbgInfoIntrinsic &I) { if (!HasDebugInfo) return; - DILocalVariable *Var; - if (auto *DV = dyn_cast<DbgValueInst>(&I)) { - // For performance reasons only check non-inlined ones. - if (DV->getDebugLoc()->getInlinedAt()) - return; - Var = DV->getVariable(); - } else { - auto *DD = cast<DbgDeclareInst>(&I); - if (DD->getDebugLoc()->getInlinedAt()) - return; - Var = DD->getVariable(); - } + // For performance reasons only check non-inlined ones. + if (I.getDebugLoc()->getInlinedAt()) + return; + + DILocalVariable *Var = I.getVariable(); AssertDI(Var, "dbg intrinsic without variable"); unsigned ArgNo = Var->getArg(); @@ -4584,6 +4574,11 @@ void Verifier::verifyFnArgs(const DbgInfoIntrinsic &I) { } void Verifier::verifyCompileUnits() { + // When more than one Module is imported into the same context, such as during + // an LTO build before linking the modules, ODR type uniquing may cause types + // to point to a different CU. This check does not make sense in this case. + if (M.getContext().isODRUniquingDebugTypes()) + return; auto *CUs = M.getNamedMetadata("llvm.dbg.cu"); SmallPtrSet<const Metadata *, 2> Listed; if (CUs) @@ -4675,19 +4670,8 @@ struct VerifierLegacyPass : public FunctionPass { HasErrors |= !V->verify(F); HasErrors |= !V->verify(); - if (FatalErrors) { - if (HasErrors) - report_fatal_error("Broken module found, compilation aborted!"); - assert(!V->hasBrokenDebugInfo() && "Module contains invalid debug info"); - } - - // Strip broken debug info. - if (V->hasBrokenDebugInfo()) { - DiagnosticInfoIgnoringInvalidDebugMetadata DiagInvalid(M); - M.getContext().diagnose(DiagInvalid); - if (!StripDebugInfo(M)) - report_fatal_error("Failed to strip malformed debug info"); - } + if (FatalErrors && (HasErrors || V->hasBrokenDebugInfo())) + report_fatal_error("Broken module found, compilation aborted!"); return false; } @@ -4716,7 +4700,8 @@ template <typename... Tys> void TBAAVerifier::CheckFailed(Tys &&... Args) { /// TBAA scheme. This means \p BaseNode is either a scalar node, or a /// struct-type node describing an aggregate data structure (like a struct). TBAAVerifier::TBAABaseNodeSummary -TBAAVerifier::verifyTBAABaseNode(Instruction &I, const MDNode *BaseNode) { +TBAAVerifier::verifyTBAABaseNode(Instruction &I, const MDNode *BaseNode, + bool IsNewFormat) { if (BaseNode->getNumOperands() < 2) { CheckFailed("Base nodes must have at least two operands", &I, BaseNode); return {true, ~0u}; @@ -4726,7 +4711,7 @@ TBAAVerifier::verifyTBAABaseNode(Instruction &I, const MDNode *BaseNode) { if (Itr != TBAABaseNodes.end()) return Itr->second; - auto Result = verifyTBAABaseNodeImpl(I, BaseNode); + auto Result = verifyTBAABaseNodeImpl(I, BaseNode, IsNewFormat); auto InsertResult = TBAABaseNodes.insert({BaseNode, Result}); (void)InsertResult; assert(InsertResult.second && "We just checked!"); @@ -4734,7 +4719,8 @@ TBAAVerifier::verifyTBAABaseNode(Instruction &I, const MDNode *BaseNode) { } TBAAVerifier::TBAABaseNodeSummary -TBAAVerifier::verifyTBAABaseNodeImpl(Instruction &I, const MDNode *BaseNode) { +TBAAVerifier::verifyTBAABaseNodeImpl(Instruction &I, const MDNode *BaseNode, + bool IsNewFormat) { const TBAAVerifier::TBAABaseNodeSummary InvalidNode = {true, ~0u}; if (BaseNode->getNumOperands() == 2) { @@ -4744,13 +4730,32 @@ TBAAVerifier::verifyTBAABaseNodeImpl(Instruction &I, const MDNode *BaseNode) { : InvalidNode; } - if (BaseNode->getNumOperands() % 2 != 1) { - CheckFailed("Struct tag nodes must have an odd number of operands!", - BaseNode); - return InvalidNode; + if (IsNewFormat) { + if (BaseNode->getNumOperands() % 3 != 0) { + CheckFailed("Access tag nodes must have the number of operands that is a " + "multiple of 3!", BaseNode); + return InvalidNode; + } + } else { + if (BaseNode->getNumOperands() % 2 != 1) { + CheckFailed("Struct tag nodes must have an odd number of operands!", + BaseNode); + return InvalidNode; + } } - if (!isa<MDString>(BaseNode->getOperand(0))) { + // Check the type size field. + if (IsNewFormat) { + auto *TypeSizeNode = mdconst::dyn_extract_or_null<ConstantInt>( + BaseNode->getOperand(1)); + if (!TypeSizeNode) { + CheckFailed("Type size nodes must be constants!", &I, BaseNode); + return InvalidNode; + } + } + + // Check the type name field. In the new format it can be anything. + if (!IsNewFormat && !isa<MDString>(BaseNode->getOperand(0))) { CheckFailed("Struct tag nodes have a string as their first operand", BaseNode); return InvalidNode; @@ -4763,7 +4768,10 @@ TBAAVerifier::verifyTBAABaseNodeImpl(Instruction &I, const MDNode *BaseNode) { // We've already checked that BaseNode is not a degenerate root node with one // operand in \c verifyTBAABaseNode, so this loop should run at least once. - for (unsigned Idx = 1; Idx < BaseNode->getNumOperands(); Idx += 2) { + unsigned FirstFieldOpNo = IsNewFormat ? 3 : 1; + unsigned NumOpsPerField = IsNewFormat ? 3 : 2; + for (unsigned Idx = FirstFieldOpNo; Idx < BaseNode->getNumOperands(); + Idx += NumOpsPerField) { const MDOperand &FieldTy = BaseNode->getOperand(Idx); const MDOperand &FieldOffset = BaseNode->getOperand(Idx + 1); if (!isa<MDNode>(FieldTy)) { @@ -4805,6 +4813,16 @@ TBAAVerifier::verifyTBAABaseNodeImpl(Instruction &I, const MDNode *BaseNode) { } PrevOffset = OffsetEntryCI->getValue(); + + if (IsNewFormat) { + auto *MemberSizeNode = mdconst::dyn_extract_or_null<ConstantInt>( + BaseNode->getOperand(Idx + 2)); + if (!MemberSizeNode) { + CheckFailed("Member size entries must be constants!", &I, BaseNode); + Failed = true; + continue; + } + } } return Failed ? InvalidNode @@ -4854,7 +4872,8 @@ bool TBAAVerifier::isValidScalarTBAANode(const MDNode *MD) { /// We assume we've okayed \p BaseNode via \c verifyTBAABaseNode. MDNode *TBAAVerifier::getFieldNodeFromTBAABaseNode(Instruction &I, const MDNode *BaseNode, - APInt &Offset) { + APInt &Offset, + bool IsNewFormat) { assert(BaseNode->getNumOperands() >= 2 && "Invalid base node!"); // Scalar nodes have only one possible "field" -- their parent in the access @@ -4863,35 +4882,52 @@ MDNode *TBAAVerifier::getFieldNodeFromTBAABaseNode(Instruction &I, if (BaseNode->getNumOperands() == 2) return cast<MDNode>(BaseNode->getOperand(1)); - for (unsigned Idx = 1; Idx < BaseNode->getNumOperands(); Idx += 2) { + unsigned FirstFieldOpNo = IsNewFormat ? 3 : 1; + unsigned NumOpsPerField = IsNewFormat ? 3 : 2; + for (unsigned Idx = FirstFieldOpNo; Idx < BaseNode->getNumOperands(); + Idx += NumOpsPerField) { auto *OffsetEntryCI = mdconst::extract<ConstantInt>(BaseNode->getOperand(Idx + 1)); if (OffsetEntryCI->getValue().ugt(Offset)) { - if (Idx == 1) { + if (Idx == FirstFieldOpNo) { CheckFailed("Could not find TBAA parent in struct type node", &I, BaseNode, &Offset); return nullptr; } + unsigned PrevIdx = Idx - NumOpsPerField; auto *PrevOffsetEntryCI = - mdconst::extract<ConstantInt>(BaseNode->getOperand(Idx - 1)); + mdconst::extract<ConstantInt>(BaseNode->getOperand(PrevIdx + 1)); Offset -= PrevOffsetEntryCI->getValue(); - return cast<MDNode>(BaseNode->getOperand(Idx - 2)); + return cast<MDNode>(BaseNode->getOperand(PrevIdx)); } } + unsigned LastIdx = BaseNode->getNumOperands() - NumOpsPerField; auto *LastOffsetEntryCI = mdconst::extract<ConstantInt>( - BaseNode->getOperand(BaseNode->getNumOperands() - 1)); - + BaseNode->getOperand(LastIdx + 1)); Offset -= LastOffsetEntryCI->getValue(); - return cast<MDNode>(BaseNode->getOperand(BaseNode->getNumOperands() - 2)); + return cast<MDNode>(BaseNode->getOperand(LastIdx)); +} + +static bool isNewFormatTBAATypeNode(llvm::MDNode *Type) { + if (!Type || Type->getNumOperands() < 3) + return false; + + // In the new format type nodes shall have a reference to the parent type as + // its first operand. + MDNode *Parent = dyn_cast_or_null<MDNode>(Type->getOperand(0)); + if (!Parent) + return false; + + return true; } bool TBAAVerifier::visitTBAAMetadata(Instruction &I, const MDNode *MD) { AssertTBAA(isa<LoadInst>(I) || isa<StoreInst>(I) || isa<CallInst>(I) || isa<VAArgInst>(I) || isa<AtomicRMWInst>(I) || isa<AtomicCmpXchgInst>(I), - "TBAA is only for loads, stores and calls!", &I); + "This instruction shall not have a TBAA access tag!", &I); bool IsStructPathTBAA = isa<MDNode>(MD->getOperand(0)) && MD->getNumOperands() >= 3; @@ -4900,18 +4936,34 @@ bool TBAAVerifier::visitTBAAMetadata(Instruction &I, const MDNode *MD) { IsStructPathTBAA, "Old-style TBAA is no longer allowed, use struct-path TBAA instead", &I); - AssertTBAA(MD->getNumOperands() < 5, - "Struct tag metadata must have either 3 or 4 operands", &I, MD); - MDNode *BaseNode = dyn_cast_or_null<MDNode>(MD->getOperand(0)); MDNode *AccessType = dyn_cast_or_null<MDNode>(MD->getOperand(1)); - if (MD->getNumOperands() == 4) { - auto *IsImmutableCI = - mdconst::dyn_extract_or_null<ConstantInt>(MD->getOperand(3)); + bool IsNewFormat = isNewFormatTBAATypeNode(AccessType); + + if (IsNewFormat) { + AssertTBAA(MD->getNumOperands() == 4 || MD->getNumOperands() == 5, + "Access tag metadata must have either 4 or 5 operands", &I, MD); + } else { + AssertTBAA(MD->getNumOperands() < 5, + "Struct tag metadata must have either 3 or 4 operands", &I, MD); + } + + // Check the access size field. + if (IsNewFormat) { + auto *AccessSizeNode = mdconst::dyn_extract_or_null<ConstantInt>( + MD->getOperand(3)); + AssertTBAA(AccessSizeNode, "Access size field must be a constant", &I, MD); + } + + // Check the immutability flag. + unsigned ImmutabilityFlagOpNo = IsNewFormat ? 4 : 3; + if (MD->getNumOperands() == ImmutabilityFlagOpNo + 1) { + auto *IsImmutableCI = mdconst::dyn_extract_or_null<ConstantInt>( + MD->getOperand(ImmutabilityFlagOpNo)); AssertTBAA(IsImmutableCI, - "Immutability tag on struct tag metadata must be a constant", &I, - MD); + "Immutability tag on struct tag metadata must be a constant", + &I, MD); AssertTBAA( IsImmutableCI->isZero() || IsImmutableCI->isOne(), "Immutability part of the struct tag metadata must be either 0 or 1", @@ -4919,13 +4971,15 @@ bool TBAAVerifier::visitTBAAMetadata(Instruction &I, const MDNode *MD) { } AssertTBAA(BaseNode && AccessType, - "Malformed struct tag metadata: base and access-type " + "Malformed struct tag metadata: base and access-type " "should be non-null and point to Metadata nodes", &I, MD, BaseNode, AccessType); - AssertTBAA(isValidScalarTBAANode(AccessType), - "Access type node must be a valid scalar type", &I, MD, - AccessType); + if (!IsNewFormat) { + AssertTBAA(isValidScalarTBAANode(AccessType), + "Access type node must be a valid scalar type", &I, MD, + AccessType); + } auto *OffsetCI = mdconst::dyn_extract_or_null<ConstantInt>(MD->getOperand(2)); AssertTBAA(OffsetCI, "Offset must be constant integer", &I, MD); @@ -4936,7 +4990,8 @@ bool TBAAVerifier::visitTBAAMetadata(Instruction &I, const MDNode *MD) { SmallPtrSet<MDNode *, 4> StructPath; for (/* empty */; BaseNode && !IsRootTBAANode(BaseNode); - BaseNode = getFieldNodeFromTBAABaseNode(I, BaseNode, Offset)) { + BaseNode = getFieldNodeFromTBAABaseNode(I, BaseNode, Offset, + IsNewFormat)) { if (!StructPath.insert(BaseNode).second) { CheckFailed("Cycle detected in struct path", &I, MD); return false; @@ -4944,7 +4999,8 @@ bool TBAAVerifier::visitTBAAMetadata(Instruction &I, const MDNode *MD) { bool Invalid; unsigned BaseNodeBitWidth; - std::tie(Invalid, BaseNodeBitWidth) = verifyTBAABaseNode(I, BaseNode); + std::tie(Invalid, BaseNodeBitWidth) = verifyTBAABaseNode(I, BaseNode, + IsNewFormat); // If the base node is invalid in itself, then we've already printed all the // errors we wanted to print. @@ -4958,9 +5014,13 @@ bool TBAAVerifier::visitTBAAMetadata(Instruction &I, const MDNode *MD) { &I, MD, &Offset); AssertTBAA(BaseNodeBitWidth == Offset.getBitWidth() || - (BaseNodeBitWidth == 0 && Offset == 0), + (BaseNodeBitWidth == 0 && Offset == 0) || + (IsNewFormat && BaseNodeBitWidth == ~0u), "Access bit-width not the same as description bit-width", &I, MD, BaseNodeBitWidth, Offset.getBitWidth()); + + if (IsNewFormat && SeenAccessTypeInPath) + break; } AssertTBAA(SeenAccessTypeInPath, "Did not see access type in access path!", @@ -4990,19 +5050,9 @@ VerifierAnalysis::Result VerifierAnalysis::run(Function &F, PreservedAnalyses VerifierPass::run(Module &M, ModuleAnalysisManager &AM) { auto Res = AM.getResult<VerifierAnalysis>(M); - if (FatalErrors) { - if (Res.IRBroken) - report_fatal_error("Broken module found, compilation aborted!"); - assert(!Res.DebugInfoBroken && "Module contains invalid debug info"); - } + if (FatalErrors && (Res.IRBroken || Res.DebugInfoBroken)) + report_fatal_error("Broken module found, compilation aborted!"); - // Strip broken debug info. - if (Res.DebugInfoBroken) { - DiagnosticInfoIgnoringInvalidDebugMetadata DiagInvalid(M); - M.getContext().diagnose(DiagInvalid); - if (!StripDebugInfo(M)) - report_fatal_error("Failed to strip malformed debug info"); - } return PreservedAnalyses::all(); } |
