summaryrefslogtreecommitdiff
path: root/lib/IR
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-12-18 20:10:56 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-12-18 20:10:56 +0000
commit044eb2f6afba375a914ac9d8024f8f5142bb912e (patch)
tree1475247dc9f9fe5be155ebd4c9069c75aadf8c20 /lib/IR
parenteb70dddbd77e120e5d490bd8fbe7ff3f8fa81c6b (diff)
Notes
Diffstat (limited to 'lib/IR')
-rw-r--r--lib/IR/AsmWriter.cpp43
-rw-r--r--lib/IR/Attributes.cpp16
-rw-r--r--lib/IR/AutoUpgrade.cpp253
-rw-r--r--lib/IR/BasicBlock.cpp13
-rw-r--r--lib/IR/CMakeLists.txt2
-rw-r--r--lib/IR/ConstantFold.cpp119
-rw-r--r--lib/IR/ConstantRange.cpp136
-rw-r--r--lib/IR/Constants.cpp1
-rw-r--r--lib/IR/Core.cpp18
-rw-r--r--lib/IR/DIBuilder.cpp137
-rw-r--r--lib/IR/DataLayout.cpp2
-rw-r--r--lib/IR/DebugInfo.cpp93
-rw-r--r--lib/IR/DebugInfoMetadata.cpp113
-rw-r--r--lib/IR/DebugLoc.cpp1
-rw-r--r--lib/IR/DiagnosticHandler.cpp91
-rw-r--r--lib/IR/DiagnosticInfo.cpp240
-rw-r--r--lib/IR/Dominators.cpp29
-rw-r--r--lib/IR/Function.cpp16
-rw-r--r--lib/IR/GCOV.cpp821
-rw-r--r--lib/IR/Globals.cpp1
-rw-r--r--lib/IR/IRBuilder.cpp15
-rw-r--r--lib/IR/IRPrintingPasses.cpp12
-rw-r--r--lib/IR/InlineAsm.cpp2
-rw-r--r--lib/IR/Instruction.cpp37
-rw-r--r--lib/IR/Instructions.cpp29
-rw-r--r--lib/IR/IntrinsicInst.cpp20
-rw-r--r--lib/IR/LLVMContext.cpp54
-rw-r--r--lib/IR/LLVMContextImpl.cpp3
-rw-r--r--lib/IR/LLVMContextImpl.h3
-rw-r--r--lib/IR/LegacyPassManager.cpp28
-rw-r--r--lib/IR/MDBuilder.cpp56
-rw-r--r--lib/IR/Metadata.cpp1
-rw-r--r--lib/IR/OptBisect.cpp19
-rw-r--r--lib/IR/Pass.cpp67
-rw-r--r--lib/IR/PassRegistry.cpp8
-rw-r--r--lib/IR/SafepointIRVerifier.cpp502
-rw-r--r--lib/IR/User.cpp1
-rw-r--r--lib/IR/Value.cpp51
-rw-r--r--lib/IR/ValueSymbolTable.cpp15
-rw-r--r--lib/IR/ValueTypes.cpp3
-rw-r--r--lib/IR/Verifier.cpp306
41 files changed, 1825 insertions, 1552 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);
+
+ 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 *PrevIdx = NewIdxs[i-1] ? NewIdxs[i-1] :
- cast<Constant>(Idxs[i - 1]);
- Constant *Div = ConstantExpr::getSDiv(CI, 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)
+ ConstantRange Result(BitWidth);
+
+ switch (BinOp) {
+ default:
// 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);
+ 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 (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)));
+ 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);
-
- 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);
-
- // 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::transferBlock(const BasicBlock *BB, BasicBlockState &BBS,
+ bool ContributionChanged) {
+ const AvailableValueSet &AvailableIn = BBS.AvailableIn;
+ AvailableValueSet &AvailableOut = BBS.AvailableOut;
- bool Cleared = false;
- TransferInstruction(I, Cleared, AvailableSet);
- (void)Cleared;
+ 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);
+ }
+
+ DEBUG(dbgs() << "Transfered block " << BB->getName() << " from ";
+ PrintValueSet(dbgs(), AvailableIn.begin(), AvailableIn.end());
+ dbgs() << " to ";
+ PrintValueSet(dbgs(), AvailableOut.begin(), AvailableOut.end());
+ dbgs() << "\n";);
+}
+
+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);
+
+ // 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();
}