diff options
author | Mircea Trofin <mtrofin@google.com> | 2018-12-21 22:48:50 +0000 |
---|---|---|
committer | Mircea Trofin <mtrofin@google.com> | 2018-12-21 22:48:50 +0000 |
commit | b53eeb6f4c824fcdfcb93dd9325a603c005660a7 (patch) | |
tree | 584b0989c4d54efc27f9a41e0c3430741f39fd7d /llvm | |
parent | 8d20cfdfc6c26533a87c525cb6e8dbc50a65e036 (diff) | |
download | bcm5719-llvm-b53eeb6f4c824fcdfcb93dd9325a603c005660a7.tar.gz bcm5719-llvm-b53eeb6f4c824fcdfcb93dd9325a603c005660a7.zip |
[llvm] API for encoding/decoding DWARF discriminators.
Summary:
Added a pair of APIs for encoding/decoding the 3 components of a DWARF discriminator described in http://lists.llvm.org/pipermail/llvm-dev/2016-October/106532.html: the base discriminator, the duplication factor (useful in profile-guided optimization) and the copy index (used to identify copies of code in cases like loop unrolling)
The encoding packs 3 unsigned values in 32 bits. This CL addresses 2 issues:
- communicates overflow back to the user
- supports encoding all 3 components together. Current APIs assume a sequencing of events. For example, creating a new discriminator based on an existing one by changing the base discriminator was not supported.
Reviewers: davidxl, danielcdh, wmi, dblaikie
Reviewed By: dblaikie
Subscribers: zzheng, dmgreen, aprantl, JDevlieghere, llvm-commits
Differential Revision: https://reviews.llvm.org/D55681
llvm-svn: 349973
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/include/llvm/IR/DebugInfoMetadata.h | 94 | ||||
-rw-r--r-- | llvm/lib/IR/DebugInfoMetadata.cpp | 43 | ||||
-rw-r--r-- | llvm/lib/Target/X86/X86DiscriminateMemOps.cpp | 40 | ||||
-rw-r--r-- | llvm/lib/Transforms/Utils/AddDiscriminators.cpp | 29 | ||||
-rw-r--r-- | llvm/lib/Transforms/Utils/LoopUnroll.cpp | 11 | ||||
-rw-r--r-- | llvm/lib/Transforms/Utils/LoopUnrollAndJam.cpp | 11 | ||||
-rw-r--r-- | llvm/lib/Transforms/Vectorize/LoopVectorize.cpp | 11 | ||||
-rw-r--r-- | llvm/unittests/IR/MetadataTest.cpp | 101 |
8 files changed, 284 insertions, 56 deletions
diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index 0830b5ccbec..a461d1bd4fe 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -1430,6 +1430,9 @@ class DILocation : public MDNode { /// Reverse transformation as getPrefixEncodingFromUnsigned. static unsigned getUnsignedFromPrefixEncoding(unsigned U) { + if (U & 1) + return 0; + U >>= 1; return (U & 0x20) ? (((U >> 1) & 0xfe0) | (U & 0x1f)) : (U & 0x1f); } @@ -1448,6 +1451,14 @@ class DILocation : public MDNode { getRawInlinedAt(), isImplicitCode()); } + static unsigned encodeComponent(unsigned C) { + return (C == 0) ? 1U : (getPrefixEncodingFromUnsigned(C) << 1); + } + + static unsigned encodingBits(unsigned C) { + return (C == 0) ? 1 : (C > 0x1f ? 14 : 7); + } + public: // Disallow replacing operands. void replaceOperandWith(unsigned I, Metadata *New) = delete; @@ -1518,20 +1529,35 @@ public: /// order. If the lowest bit is 1, the current component is empty, and the /// next component will start in the next bit. Otherwise, the current /// component is non-empty, and its content starts in the next bit. The - /// length of each components is either 5 bit or 12 bit: if the 7th bit + /// value of each components is either 5 bit or 12 bit: if the 7th bit /// is 0, the bit 2~6 (5 bits) are used to represent the component; if the /// 7th bit is 1, the bit 2~6 (5 bits) and 8~14 (7 bits) are combined to - /// represent the component. + /// represent the component. Thus, the number of bits used for a component + /// is either 0 (if it and all the next components are empty); 1 - if it is + /// empty; 7 - if its value is up to and including 0x1f (lsb and msb are both + /// 0); or 14, if its value is up to and including 0x1ff. Note that the last + /// component is also capped at 0x1ff, even in the case when both first + /// components are 0, and we'd technically have 29 bits available. + /// + /// For precise control over the data being encoded in the discriminator, + /// use encodeDiscriminator/decodeDiscriminator. + /// + /// Use {get|set}BaseDiscriminator and cloneWithDuplicationFactor after reading + /// their documentation, as their behavior has side-effects. inline unsigned getDiscriminator() const; /// Returns a new DILocation with updated \p Discriminator. inline const DILocation *cloneWithDiscriminator(unsigned Discriminator) const; - /// Returns a new DILocation with updated base discriminator \p BD. - inline const DILocation *setBaseDiscriminator(unsigned BD) const; + /// Returns a new DILocation with updated base discriminator \p BD. Only the + /// base discriminator is set in the new DILocation, the other encoded values + /// are elided. + /// If the discriminator cannot be encoded, the function returns None. + inline Optional<const DILocation *> setBaseDiscriminator(unsigned BD) const; - /// Returns the duplication factor stored in the discriminator. + /// Returns the duplication factor stored in the discriminator, or 1 if no + /// duplication factor (or 0) is encoded. inline unsigned getDuplicationFactor() const; /// Returns the copy identifier stored in the discriminator. @@ -1540,9 +1566,11 @@ public: /// Returns the base discriminator stored in the discriminator. inline unsigned getBaseDiscriminator() const; - /// Returns a new DILocation with duplication factor \p DF encoded in the - /// discriminator. - inline const DILocation *cloneWithDuplicationFactor(unsigned DF) const; + /// Returns a new DILocation with duplication factor \p DF * current + /// duplication factor encoded in the discriminator. The current duplication + /// factor is as defined by getDuplicationFactor(). + /// Returns None if encoding failed. + inline Optional<const DILocation *> cloneWithDuplicationFactor(unsigned DF) const; /// When two instructions are combined into a single instruction we also /// need to combine the original locations into a single location. @@ -1563,19 +1591,31 @@ public: /// Returns the base discriminator for a given encoded discriminator \p D. static unsigned getBaseDiscriminatorFromDiscriminator(unsigned D) { - if ((D & 1) == 0) - return getUnsignedFromPrefixEncoding(D >> 1); - else - return 0; + return getUnsignedFromPrefixEncoding(D); } - /// Returns the duplication factor for a given encoded discriminator \p D. + /// Raw encoding of the discriminator. APIs such as setBaseDiscriminator or + /// cloneWithDuplicationFactor have certain side-effects. This API, in + /// conjunction with cloneWithDiscriminator, may be used to encode precisely + /// the values provided. \p BD: base discriminator \p DF: duplication factor + /// \p CI: copy index + /// The return is None if the values cannot be encoded in 32 bits - for + /// example, values for BD or DF larger than 12 bits. Otherwise, the return + /// is the encoded value. + static Optional<unsigned> encodeDiscriminator(unsigned BD, unsigned DF, unsigned CI); + + /// Raw decoder for values in an encoded discriminator D. + static void decodeDiscriminator(unsigned D, unsigned &BD, unsigned &DF, + unsigned &CI); + + /// Returns the duplication factor for a given encoded discriminator \p D, or + /// 1 if no value or 0 is encoded. static unsigned getDuplicationFactorFromDiscriminator(unsigned D) { D = getNextComponentInDiscriminator(D); - if (D == 0 || (D & 1)) + unsigned Ret = getUnsignedFromPrefixEncoding(D); + if (Ret == 0) return 1; - else - return getUnsignedFromPrefixEncoding(D >> 1); + return Ret; } /// Returns the copy identifier for a given encoded discriminator \p D. @@ -1999,28 +2039,24 @@ unsigned DILocation::getCopyIdentifier() const { return getCopyIdentifierFromDiscriminator(getDiscriminator()); } -const DILocation *DILocation::setBaseDiscriminator(unsigned D) const { +Optional<const DILocation *> DILocation::setBaseDiscriminator(unsigned D) const { if (D == 0) return this; - else - return cloneWithDiscriminator(getPrefixEncodingFromUnsigned(D) << 1); + if (D > 0xfff) + return None; + return cloneWithDiscriminator(encodeComponent(D)); } -const DILocation *DILocation::cloneWithDuplicationFactor(unsigned DF) const { +Optional<const DILocation *> DILocation::cloneWithDuplicationFactor(unsigned DF) const { DF *= getDuplicationFactor(); if (DF <= 1) return this; unsigned BD = getBaseDiscriminator(); - unsigned CI = getCopyIdentifier() << (DF > 0x1f ? 14 : 7); - unsigned D = CI | (getPrefixEncodingFromUnsigned(DF) << 1); - - if (BD == 0) - D = (D << 1) | 1; - else - D = (D << (BD > 0x1f ? 14 : 7)) | (getPrefixEncodingFromUnsigned(BD) << 1); - - return cloneWithDiscriminator(D); + unsigned CI = getCopyIdentifier(); + if (Optional<unsigned> D = encodeDiscriminator(BD, DF, CI)) + return cloneWithDiscriminator(*D); + return None; } class DINamespace : public DIScope { diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index 3b702ce4798..92f3f21f754 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -20,6 +20,8 @@ #include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" +#include <numeric> + using namespace llvm; DILocation::DILocation(LLVMContext &C, StorageType Storage, unsigned Line, @@ -113,6 +115,47 @@ const DILocation *DILocation::getMergedLocation(const DILocation *LocA, return DILocation::get(Result->getContext(), 0, 0, S, L); } +Optional<unsigned> DILocation::encodeDiscriminator(unsigned BD, unsigned DF, unsigned CI) { + SmallVector<unsigned, 3> Components = {BD, DF, CI}; + uint64_t RemainingWork = 0U; + // We use RemainingWork to figure out if we have no remaining components to + // encode. For example: if BD != 0 but DF == 0 && CI == 0, we don't need to + // encode anything for the latter 2. + // Since any of the input components is at most 32 bits, their sum will be + // less than 34 bits, and thus RemainingWork won't overflow. + RemainingWork = std::accumulate(Components.begin(), Components.end(), RemainingWork); + + int I = 0; + unsigned Ret = 0; + unsigned NextBitInsertionIndex = 0; + while (RemainingWork > 0) { + unsigned C = Components[I++]; + RemainingWork -= C; + unsigned EC = encodeComponent(C); + Ret |= (EC << NextBitInsertionIndex); + NextBitInsertionIndex += encodingBits(C); + } + + // Encoding may be unsuccessful because of overflow. We determine success by + // checking equivalence of components before & after encoding. Alternatively, + // we could determine Success during encoding, but the current alternative is + // simpler. + unsigned TBD, TDF, TCI = 0; + decodeDiscriminator(Ret, TBD, TDF, TCI); + if (TBD == BD && TDF == DF && TCI == CI) + return Ret; + return None; +} + +void DILocation::decodeDiscriminator(unsigned D, unsigned &BD, unsigned &DF, + unsigned &CI) { + BD = getUnsignedFromPrefixEncoding(D); + DF = getUnsignedFromPrefixEncoding(getNextComponentInDiscriminator(D)); + CI = getUnsignedFromPrefixEncoding( + getNextComponentInDiscriminator(getNextComponentInDiscriminator(D))); +} + + DINode::DIFlags DINode::getFlag(StringRef Flag) { return StringSwitch<DIFlags>(Flag) #define HANDLE_DI_FLAG(ID, NAME) .Case("DIFlag" #NAME, Flag##NAME) diff --git a/llvm/lib/Target/X86/X86DiscriminateMemOps.cpp b/llvm/lib/Target/X86/X86DiscriminateMemOps.cpp index 5653babedf8..fcb7402d786 100644 --- a/llvm/lib/Target/X86/X86DiscriminateMemOps.cpp +++ b/llvm/lib/Target/X86/X86DiscriminateMemOps.cpp @@ -21,6 +21,7 @@ #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/ProfileData/SampleProf.h" #include "llvm/ProfileData/SampleProfReader.h" +#include "llvm/Support/Debug.h" #include "llvm/Transforms/IPO/SampleProfile.h" using namespace llvm; @@ -107,27 +108,36 @@ bool X86DiscriminateMemOps::runOnMachineFunction(MachineFunction &MF) { if (!DI) { DI = ReferenceDI; } - DenseSet<unsigned> &Set = Seen[diToLocation(DI)]; + Location L = diToLocation(DI); + DenseSet<unsigned> &Set = Seen[L]; const std::pair<DenseSet<unsigned>::iterator, bool> TryInsert = Set.insert(DI->getBaseDiscriminator()); if (!TryInsert.second) { - DI = DI->setBaseDiscriminator(++MemOpDiscriminators[diToLocation(DI)]); - updateDebugInfo(&MI, DI); - Changed = true; - const std::pair<DenseSet<unsigned>::iterator, bool> MustInsert = - Set.insert(DI->getBaseDiscriminator()); - // FIXME (mtrofin): check if the to-be inserted base discriminator can - // be added. This requires a new API on DILocation. - // The assumption is that this scenario is infrequent/OK not to support. - // If evidence points otherwise, we can explore synthesize unique DIs by - // adding fake line numbers. - if (!MustInsert.second) { - LLVM_DEBUG(dbgs() - << "Unable to create a unique discriminator in " + unsigned BF, DF, CI = 0; + DILocation::decodeDiscriminator(DI->getDiscriminator(), BF, DF, CI); + Optional<unsigned> EncodedDiscriminator = DILocation::encodeDiscriminator( + MemOpDiscriminators[L] + 1, DF, CI); + + if (!EncodedDiscriminator) { + // FIXME(mtrofin): The assumption is that this scenario is infrequent/OK + // not to support. If evidence points otherwise, we can explore synthesizeing + // unique DIs by adding fake line numbers, or by constructing 64 bit + // discriminators. + LLVM_DEBUG(dbgs() << "Unable to create a unique discriminator " + "for instruction with memory operand in: " << DI->getFilename() << " Line: " << DI->getLine() << " Column: " << DI->getColumn() - << ". This is likely due to a large macro expansion.\n"); + << ". This is likely due to a large macro expansion. \n"); + continue; } + // Since we were able to encode, bump the MemOpDiscriminators. + ++MemOpDiscriminators[L]; + DI = DI->cloneWithDiscriminator(EncodedDiscriminator.getValue()); + updateDebugInfo(&MI, DI); + Changed = true; + std::pair<DenseSet<unsigned>::iterator, bool> MustInsert = + Set.insert(DI->getBaseDiscriminator()); + assert(MustInsert.second && "New discriminator shouldn't be present in set"); } // Bump the reference DI to avoid cramming discriminators on line 0. diff --git a/llvm/lib/Transforms/Utils/AddDiscriminators.cpp b/llvm/lib/Transforms/Utils/AddDiscriminators.cpp index e3ef4236222..1e0fd5588ca 100644 --- a/llvm/lib/Transforms/Utils/AddDiscriminators.cpp +++ b/llvm/lib/Transforms/Utils/AddDiscriminators.cpp @@ -209,10 +209,18 @@ static bool addDiscriminators(Function &F) { // Only the lowest 7 bits are used to represent a discriminator to fit // it in 1 byte ULEB128 representation. unsigned Discriminator = R.second ? ++LDM[L] : LDM[L]; - I.setDebugLoc(DIL->setBaseDiscriminator(Discriminator)); - LLVM_DEBUG(dbgs() << DIL->getFilename() << ":" << DIL->getLine() << ":" - << DIL->getColumn() << ":" << Discriminator << " " << I - << "\n"); + auto NewDIL = DIL->setBaseDiscriminator(Discriminator); + if (!NewDIL) { + LLVM_DEBUG(dbgs() << "Could not encode discriminator: " + << DIL->getFilename() << ":" << DIL->getLine() << ":" + << DIL->getColumn() << ":" << Discriminator << " " + << I << "\n"); + } else { + I.setDebugLoc(NewDIL.getValue()); + LLVM_DEBUG(dbgs() << DIL->getFilename() << ":" << DIL->getLine() << ":" + << DIL->getColumn() << ":" << Discriminator << " " << I + << "\n"); + } Changed = true; } } @@ -239,8 +247,17 @@ static bool addDiscriminators(Function &F) { std::make_pair(CurrentDIL->getFilename(), CurrentDIL->getLine()); if (!CallLocations.insert(L).second) { unsigned Discriminator = ++LDM[L]; - Current->setDebugLoc(CurrentDIL->setBaseDiscriminator(Discriminator)); - Changed = true; + auto NewDIL = CurrentDIL->setBaseDiscriminator(Discriminator); + if (!NewDIL) { + LLVM_DEBUG(dbgs() + << "Could not encode discriminator: " + << CurrentDIL->getFilename() << ":" + << CurrentDIL->getLine() << ":" << CurrentDIL->getColumn() + << ":" << Discriminator << " " << I << "\n"); + } else { + Current->setDebugLoc(NewDIL.getValue()); + Changed = true; + } } } } diff --git a/llvm/lib/Transforms/Utils/LoopUnroll.cpp b/llvm/lib/Transforms/Utils/LoopUnroll.cpp index 0ed4038cc3e..da7ed2bd165 100644 --- a/llvm/lib/Transforms/Utils/LoopUnroll.cpp +++ b/llvm/lib/Transforms/Utils/LoopUnroll.cpp @@ -598,8 +598,15 @@ LoopUnrollResult llvm::UnrollLoop( for (BasicBlock *BB : L->getBlocks()) for (Instruction &I : *BB) if (!isa<DbgInfoIntrinsic>(&I)) - if (const DILocation *DIL = I.getDebugLoc()) - I.setDebugLoc(DIL->cloneWithDuplicationFactor(Count)); + if (const DILocation *DIL = I.getDebugLoc()) { + auto NewDIL = DIL->cloneWithDuplicationFactor(Count); + if (NewDIL) + I.setDebugLoc(NewDIL.getValue()); + else + LLVM_DEBUG(dbgs() + << "Failed to create new discriminator: " + << DIL->getFilename() << " Line: " << DIL->getLine()); + } for (unsigned It = 1; It != Count; ++It) { std::vector<BasicBlock*> NewBlocks; diff --git a/llvm/lib/Transforms/Utils/LoopUnrollAndJam.cpp b/llvm/lib/Transforms/Utils/LoopUnrollAndJam.cpp index b5d80f669fb..e26762639c1 100644 --- a/llvm/lib/Transforms/Utils/LoopUnrollAndJam.cpp +++ b/llvm/lib/Transforms/Utils/LoopUnrollAndJam.cpp @@ -300,8 +300,15 @@ LoopUnrollResult llvm::UnrollAndJamLoop( for (BasicBlock *BB : L->getBlocks()) for (Instruction &I : *BB) if (!isa<DbgInfoIntrinsic>(&I)) - if (const DILocation *DIL = I.getDebugLoc()) - I.setDebugLoc(DIL->cloneWithDuplicationFactor(Count)); + if (const DILocation *DIL = I.getDebugLoc()) { + auto NewDIL = DIL->cloneWithDuplicationFactor(Count); + if (NewDIL) + I.setDebugLoc(NewDIL.getValue()); + else + LLVM_DEBUG(dbgs() + << "Failed to create new discriminator: " + << DIL->getFilename() << " Line: " << DIL->getLine()); + } // Copy all blocks for (unsigned It = 1; It != Count; ++It) { diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp index c74352cf703..c45dee590b8 100644 --- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -759,8 +759,15 @@ void InnerLoopVectorizer::setDebugLocFromInst(IRBuilder<> &B, const Value *Ptr) if (const Instruction *Inst = dyn_cast_or_null<Instruction>(Ptr)) { const DILocation *DIL = Inst->getDebugLoc(); if (DIL && Inst->getFunction()->isDebugInfoForProfiling() && - !isa<DbgInfoIntrinsic>(Inst)) - B.SetCurrentDebugLocation(DIL->cloneWithDuplicationFactor(UF * VF)); + !isa<DbgInfoIntrinsic>(Inst)) { + auto NewDIL = DIL->cloneWithDuplicationFactor(UF * VF); + if (NewDIL) + B.SetCurrentDebugLocation(NewDIL.getValue()); + else + LLVM_DEBUG(dbgs() + << "Failed to create new discriminator: " + << DIL->getFilename() << " Line: " << DIL->getLine()); + } else B.SetCurrentDebugLocation(DIL); } else diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp index 3f744cd5e6d..883a5823100 100644 --- a/llvm/unittests/IR/MetadataTest.cpp +++ b/llvm/unittests/IR/MetadataTest.cpp @@ -981,6 +981,107 @@ TEST_F(DILocationTest, cloneTemporary) { EXPECT_TRUE(L2->isTemporary()); } +TEST_F(DILocationTest, discriminatorEncoding) { + EXPECT_EQ(0U, DILocation::encodeDiscriminator(0, 0, 0).getValue()); + + // Encode base discriminator as a component: lsb is 0, then the value. + // The other components are all absent, so we leave all the other bits 0. + EXPECT_EQ(2U, DILocation::encodeDiscriminator(1, 0, 0).getValue()); + + // Base discriminator component is empty, so lsb is 1. Next component is not + // empty, so its lsb is 0, then its value (1). Next component is empty. + // So the bit pattern is 101. + EXPECT_EQ(5U, DILocation::encodeDiscriminator(0, 1, 0).getValue()); + + // First 2 components are empty, so the bit pattern is 11. Then the + // next component - ending up with 1011. + EXPECT_EQ(0xbU, DILocation::encodeDiscriminator(0, 0, 1).getValue()); + + // The bit pattern for the first 2 components is 11. The next bit is 0, + // because the last component is not empty. We have 29 bits usable for + // encoding, but we cap it at 12 bits uniformously for all components. We + // encode the last component over 14 bits. + EXPECT_EQ(0xfffbU, DILocation::encodeDiscriminator(0, 0, 0xfff).getValue()); + + EXPECT_EQ(0x102U, DILocation::encodeDiscriminator(1, 1, 0).getValue()); + + EXPECT_EQ(0x13eU, DILocation::encodeDiscriminator(0x1f, 1, 0).getValue()); + + EXPECT_EQ(0x87feU, DILocation::encodeDiscriminator(0x1ff, 1, 0).getValue()); + + EXPECT_EQ(0x1f3eU, DILocation::encodeDiscriminator(0x1f, 0x1f, 0).getValue()); + + EXPECT_EQ(0x3ff3eU, + DILocation::encodeDiscriminator(0x1f, 0x1ff, 0).getValue()); + + EXPECT_EQ(0x1ff87feU, + DILocation::encodeDiscriminator(0x1ff, 0x1ff, 0).getValue()); + + EXPECT_EQ(0xfff9f3eU, + DILocation::encodeDiscriminator(0x1f, 0x1f, 0xfff).getValue()); + + EXPECT_EQ(0xffc3ff3eU, + DILocation::encodeDiscriminator(0x1f, 0x1ff, 0x1ff).getValue()); + + EXPECT_EQ(0xffcf87feU, + DILocation::encodeDiscriminator(0x1ff, 0x1f, 0x1ff).getValue()); + + EXPECT_EQ(0xe1ff87feU, + DILocation::encodeDiscriminator(0x1ff, 0x1ff, 7).getValue()); +} + +TEST_F(DILocationTest, discriminatorEncodingNegativeTests) { + EXPECT_EQ(None, DILocation::encodeDiscriminator(0, 0, 0x1000)); + EXPECT_EQ(None, DILocation::encodeDiscriminator(0x1000, 0, 0)); + EXPECT_EQ(None, DILocation::encodeDiscriminator(0, 0x1000, 0)); + EXPECT_EQ(None, DILocation::encodeDiscriminator(0, 0, 0x1000)); + EXPECT_EQ(None, DILocation::encodeDiscriminator(0x1ff, 0x1ff, 8)); + EXPECT_EQ(None, + DILocation::encodeDiscriminator(std::numeric_limits<uint32_t>::max(), + std::numeric_limits<uint32_t>::max(), + 0)); +} + +TEST_F(DILocationTest, discriminatorSpecialCases) { + // We don't test getCopyIdentifier here because the only way + // to set it is by constructing an encoded discriminator using + // encodeDiscriminator, which is already tested. + auto L1 = DILocation::get(Context, 1, 2, getSubprogram()); + EXPECT_EQ(0U, L1->getBaseDiscriminator()); + EXPECT_EQ(1U, L1->getDuplicationFactor()); + + auto L2 = L1->setBaseDiscriminator(1).getValue(); + EXPECT_EQ(0U, L1->getBaseDiscriminator()); + EXPECT_EQ(1U, L1->getDuplicationFactor()); + + EXPECT_EQ(1U, L2->getBaseDiscriminator()); + EXPECT_EQ(1U, L2->getDuplicationFactor()); + + auto L3 = L2->cloneWithDuplicationFactor(2).getValue(); + EXPECT_EQ(1U, L3->getBaseDiscriminator()); + EXPECT_EQ(2U, L3->getDuplicationFactor()); + + auto L4 = L3->cloneWithDuplicationFactor(4).getValue(); + EXPECT_EQ(1U, L4->getBaseDiscriminator()); + EXPECT_EQ(8U, L4->getDuplicationFactor()); + + auto L5 = L4->setBaseDiscriminator(2).getValue(); + EXPECT_EQ(2U, L5->getBaseDiscriminator()); + EXPECT_EQ(1U, L5->getDuplicationFactor()); + + // Check extreme cases + auto L6 = L1->setBaseDiscriminator(0xfff).getValue(); + EXPECT_EQ(0xfffU, L6->getBaseDiscriminator()); + EXPECT_EQ( + 0xfffU, + L6->cloneWithDuplicationFactor(0xfff).getValue()->getDuplicationFactor()); + + // Check we return None for unencodable cases. + EXPECT_EQ(None, L4->setBaseDiscriminator(0x1000)); + EXPECT_EQ(None, L4->cloneWithDuplicationFactor(0x1000)); +} + + typedef MetadataTest GenericDINodeTest; TEST_F(GenericDINodeTest, get) { |