1e98a4c5aSCarlos Alberto Enciso //===-- LVCompare.cpp -----------------------------------------------------===// 2e98a4c5aSCarlos Alberto Enciso // 3e98a4c5aSCarlos Alberto Enciso // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e98a4c5aSCarlos Alberto Enciso // See https://llvm.org/LICENSE.txt for license information. 5e98a4c5aSCarlos Alberto Enciso // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e98a4c5aSCarlos Alberto Enciso // 7e98a4c5aSCarlos Alberto Enciso //===----------------------------------------------------------------------===// 8e98a4c5aSCarlos Alberto Enciso // 9e98a4c5aSCarlos Alberto Enciso // This implements the LVCompare class. 10e98a4c5aSCarlos Alberto Enciso // 11e98a4c5aSCarlos Alberto Enciso //===----------------------------------------------------------------------===// 12e98a4c5aSCarlos Alberto Enciso 13e98a4c5aSCarlos Alberto Enciso #include "llvm/DebugInfo/LogicalView/Core/LVCompare.h" 14e98a4c5aSCarlos Alberto Enciso #include "llvm/DebugInfo/LogicalView/Core/LVOptions.h" 15e98a4c5aSCarlos Alberto Enciso #include "llvm/DebugInfo/LogicalView/Core/LVReader.h" 16e98a4c5aSCarlos Alberto Enciso #include <tuple> 17e98a4c5aSCarlos Alberto Enciso 18e98a4c5aSCarlos Alberto Enciso using namespace llvm; 19e98a4c5aSCarlos Alberto Enciso using namespace llvm::logicalview; 20e98a4c5aSCarlos Alberto Enciso 21e98a4c5aSCarlos Alberto Enciso #define DEBUG_TYPE "Compare" 22e98a4c5aSCarlos Alberto Enciso 23e98a4c5aSCarlos Alberto Enciso namespace { 24e98a4c5aSCarlos Alberto Enciso 25e98a4c5aSCarlos Alberto Enciso enum class LVCompareItem { Scope, Symbol, Type, Line, Total }; 26e98a4c5aSCarlos Alberto Enciso enum class LVCompareIndex { Header, Expected, Missing, Added }; 27e98a4c5aSCarlos Alberto Enciso using LVCompareEntry = std::tuple<const char *, unsigned, unsigned, unsigned>; 28e98a4c5aSCarlos Alberto Enciso using LVCompareInfo = std::map<LVCompareItem, LVCompareEntry>; 29e98a4c5aSCarlos Alberto Enciso LVCompareInfo Results = { 30e98a4c5aSCarlos Alberto Enciso {LVCompareItem::Line, LVCompareEntry("Lines", 0, 0, 0)}, 31e98a4c5aSCarlos Alberto Enciso {LVCompareItem::Scope, LVCompareEntry("Scopes", 0, 0, 0)}, 32e98a4c5aSCarlos Alberto Enciso {LVCompareItem::Symbol, LVCompareEntry("Symbols", 0, 0, 0)}, 33e98a4c5aSCarlos Alberto Enciso {LVCompareItem::Type, LVCompareEntry("Types", 0, 0, 0)}, 34e98a4c5aSCarlos Alberto Enciso {LVCompareItem::Total, LVCompareEntry("Total", 0, 0, 0)}}; 35e98a4c5aSCarlos Alberto Enciso static LVCompareInfo::iterator IterTotal = Results.end(); 36e98a4c5aSCarlos Alberto Enciso 37e98a4c5aSCarlos Alberto Enciso constexpr unsigned getHeader() { 38e98a4c5aSCarlos Alberto Enciso return static_cast<unsigned>(LVCompareIndex::Header); 39e98a4c5aSCarlos Alberto Enciso } 40e98a4c5aSCarlos Alberto Enciso constexpr unsigned getExpected() { 41e98a4c5aSCarlos Alberto Enciso return static_cast<unsigned>(LVCompareIndex::Expected); 42e98a4c5aSCarlos Alberto Enciso } 43e98a4c5aSCarlos Alberto Enciso constexpr unsigned getMissing() { 44e98a4c5aSCarlos Alberto Enciso return static_cast<unsigned>(LVCompareIndex::Missing); 45e98a4c5aSCarlos Alberto Enciso } 46e98a4c5aSCarlos Alberto Enciso constexpr unsigned getAdded() { 47e98a4c5aSCarlos Alberto Enciso return static_cast<unsigned>(LVCompareIndex::Added); 48e98a4c5aSCarlos Alberto Enciso } 49e98a4c5aSCarlos Alberto Enciso 50e98a4c5aSCarlos Alberto Enciso LVCompare *CurrentComparator = nullptr; 51e98a4c5aSCarlos Alberto Enciso 52e98a4c5aSCarlos Alberto Enciso void zeroResults() { 53e98a4c5aSCarlos Alberto Enciso // In case the same reader instance is used. 54e98a4c5aSCarlos Alberto Enciso for (LVCompareInfo::reference Entry : Results) { 55e98a4c5aSCarlos Alberto Enciso std::get<getExpected()>(Entry.second) = 0; 56e98a4c5aSCarlos Alberto Enciso std::get<getMissing()>(Entry.second) = 0; 57e98a4c5aSCarlos Alberto Enciso std::get<getAdded()>(Entry.second) = 0; 58e98a4c5aSCarlos Alberto Enciso } 59e98a4c5aSCarlos Alberto Enciso IterTotal = Results.find(LVCompareItem::Total); 60e98a4c5aSCarlos Alberto Enciso assert(IterTotal != Results.end()); 61e98a4c5aSCarlos Alberto Enciso } 62e98a4c5aSCarlos Alberto Enciso 63e98a4c5aSCarlos Alberto Enciso LVCompareInfo::iterator getResultsEntry(LVElement *Element) { 64e98a4c5aSCarlos Alberto Enciso LVCompareItem Kind; 65e98a4c5aSCarlos Alberto Enciso if (Element->getIsLine()) 66e98a4c5aSCarlos Alberto Enciso Kind = LVCompareItem::Line; 67e98a4c5aSCarlos Alberto Enciso else if (Element->getIsScope()) 68e98a4c5aSCarlos Alberto Enciso Kind = LVCompareItem::Scope; 69e98a4c5aSCarlos Alberto Enciso else if (Element->getIsSymbol()) 70e98a4c5aSCarlos Alberto Enciso Kind = LVCompareItem::Symbol; 71e98a4c5aSCarlos Alberto Enciso else 72e98a4c5aSCarlos Alberto Enciso Kind = LVCompareItem::Type; 73e98a4c5aSCarlos Alberto Enciso 74e98a4c5aSCarlos Alberto Enciso // Used to update the expected, missing or added entry for the given kind. 75e98a4c5aSCarlos Alberto Enciso LVCompareInfo::iterator Iter = Results.find(Kind); 76e98a4c5aSCarlos Alberto Enciso assert(Iter != Results.end()); 77e98a4c5aSCarlos Alberto Enciso return Iter; 78e98a4c5aSCarlos Alberto Enciso } 79e98a4c5aSCarlos Alberto Enciso 80e98a4c5aSCarlos Alberto Enciso void updateExpected(LVElement *Element) { 81e98a4c5aSCarlos Alberto Enciso LVCompareInfo::iterator Iter = getResultsEntry(Element); 82e98a4c5aSCarlos Alberto Enciso // Update total for expected. 83e98a4c5aSCarlos Alberto Enciso ++std::get<getExpected()>(IterTotal->second); 84e98a4c5aSCarlos Alberto Enciso // Update total for specific element kind. 85e98a4c5aSCarlos Alberto Enciso ++std::get<getExpected()>(Iter->second); 86e98a4c5aSCarlos Alberto Enciso } 87e98a4c5aSCarlos Alberto Enciso 88e98a4c5aSCarlos Alberto Enciso void updateMissingOrAdded(LVElement *Element, LVComparePass Pass) { 89e98a4c5aSCarlos Alberto Enciso LVCompareInfo::iterator Iter = getResultsEntry(Element); 90e98a4c5aSCarlos Alberto Enciso if (Pass == LVComparePass::Missing) { 91e98a4c5aSCarlos Alberto Enciso ++std::get<getMissing()>(IterTotal->second); 92e98a4c5aSCarlos Alberto Enciso ++std::get<getMissing()>(Iter->second); 93e98a4c5aSCarlos Alberto Enciso } else { 94e98a4c5aSCarlos Alberto Enciso ++std::get<getAdded()>(IterTotal->second); 95e98a4c5aSCarlos Alberto Enciso ++std::get<getAdded()>(Iter->second); 96e98a4c5aSCarlos Alberto Enciso } 97e98a4c5aSCarlos Alberto Enciso } 98e98a4c5aSCarlos Alberto Enciso 99e98a4c5aSCarlos Alberto Enciso } // namespace 100e98a4c5aSCarlos Alberto Enciso 101e98a4c5aSCarlos Alberto Enciso LVCompare &LVCompare::getInstance() { 102e98a4c5aSCarlos Alberto Enciso static LVCompare DefaultComparator(outs()); 103e98a4c5aSCarlos Alberto Enciso return CurrentComparator ? *CurrentComparator : DefaultComparator; 104e98a4c5aSCarlos Alberto Enciso } 105e98a4c5aSCarlos Alberto Enciso 106e98a4c5aSCarlos Alberto Enciso void LVCompare::setInstance(LVCompare *Comparator) { 107e98a4c5aSCarlos Alberto Enciso CurrentComparator = Comparator; 108e98a4c5aSCarlos Alberto Enciso } 109e98a4c5aSCarlos Alberto Enciso 110e98a4c5aSCarlos Alberto Enciso LVCompare::LVCompare(raw_ostream &OS) : OS(OS) { 111e98a4c5aSCarlos Alberto Enciso PrintLines = options().getPrintLines(); 112e98a4c5aSCarlos Alberto Enciso PrintSymbols = options().getPrintSymbols(); 113e98a4c5aSCarlos Alberto Enciso PrintTypes = options().getPrintTypes(); 114e98a4c5aSCarlos Alberto Enciso PrintScopes = 115e98a4c5aSCarlos Alberto Enciso options().getPrintScopes() || PrintLines || PrintSymbols || PrintTypes; 116e98a4c5aSCarlos Alberto Enciso } 117e98a4c5aSCarlos Alberto Enciso 118e98a4c5aSCarlos Alberto Enciso Error LVCompare::execute(LVReader *ReferenceReader, LVReader *TargetReader) { 119e98a4c5aSCarlos Alberto Enciso setInstance(this); 120e98a4c5aSCarlos Alberto Enciso // In the case of added elements, the 'Reference' reader will be modified; 121e98a4c5aSCarlos Alberto Enciso // those elements will be added to it. Update the current reader instance. 122e98a4c5aSCarlos Alberto Enciso LVReader::setInstance(ReferenceReader); 123e98a4c5aSCarlos Alberto Enciso 124e98a4c5aSCarlos Alberto Enciso auto PrintHeader = [this](LVScopeRoot *LHS, LVScopeRoot *RHS) { 125e98a4c5aSCarlos Alberto Enciso LLVM_DEBUG({ 126e98a4c5aSCarlos Alberto Enciso dbgs() << "[Reference] " << LHS->getName() << "\n" 127e98a4c5aSCarlos Alberto Enciso << "[Target] " << RHS->getName() << "\n"; 128e98a4c5aSCarlos Alberto Enciso }); 129e98a4c5aSCarlos Alberto Enciso OS << "\nReference: " << formattedName(LHS->getName()) << "\n" 130e98a4c5aSCarlos Alberto Enciso << "Target: " << formattedName(RHS->getName()) << "\n"; 131e98a4c5aSCarlos Alberto Enciso }; 132e98a4c5aSCarlos Alberto Enciso 133e98a4c5aSCarlos Alberto Enciso // We traverse the given scopes tree ('Reference' and 'Target') twice. 134e98a4c5aSCarlos Alberto Enciso // The first time we look for missing items from the 'Reference' and the 135e98a4c5aSCarlos Alberto Enciso // second time we look for items added to the 'Target'. 136e98a4c5aSCarlos Alberto Enciso // The comparison test includes the name, lexical level, type, source 137e98a4c5aSCarlos Alberto Enciso // location, etc. 138e98a4c5aSCarlos Alberto Enciso LVScopeRoot *ReferenceRoot = ReferenceReader->getScopesRoot(); 139e98a4c5aSCarlos Alberto Enciso LVScopeRoot *TargetRoot = TargetReader->getScopesRoot(); 140e98a4c5aSCarlos Alberto Enciso ReferenceRoot->setIsInCompare(); 141e98a4c5aSCarlos Alberto Enciso TargetRoot->setIsInCompare(); 142e98a4c5aSCarlos Alberto Enciso 143e98a4c5aSCarlos Alberto Enciso // Reset possible previous results. 144e98a4c5aSCarlos Alberto Enciso zeroResults(); 145e98a4c5aSCarlos Alberto Enciso 146e98a4c5aSCarlos Alberto Enciso if (options().getCompareContext()) { 147e98a4c5aSCarlos Alberto Enciso // Perform a logical view comparison as a whole unit. We start at the 148e98a4c5aSCarlos Alberto Enciso // root reference; at each scope an equal test is applied to its children. 149e98a4c5aSCarlos Alberto Enciso // If a difference is found, the current path is marked as missing. 150e98a4c5aSCarlos Alberto Enciso auto CompareViews = [this](LVScopeRoot *LHS, LVScopeRoot *RHS) -> Error { 151e98a4c5aSCarlos Alberto Enciso LHS->markMissingParents(RHS, /*TraverseChildren=*/true); 152e98a4c5aSCarlos Alberto Enciso if (LHS->getIsMissingLink() && options().getReportAnyView()) { 153e98a4c5aSCarlos Alberto Enciso // As we are printing a missing tree, enable formatting. 154e98a4c5aSCarlos Alberto Enciso options().setPrintFormatting(); 155e98a4c5aSCarlos Alberto Enciso OS << "\nMissing Tree:\n"; 156e98a4c5aSCarlos Alberto Enciso if (Error Err = LHS->doPrint(/*Split=*/false, /*Match=*/false, 157e98a4c5aSCarlos Alberto Enciso /*Print=*/true, OS)) 158e98a4c5aSCarlos Alberto Enciso return Err; 159e98a4c5aSCarlos Alberto Enciso options().resetPrintFormatting(); 160e98a4c5aSCarlos Alberto Enciso } 161e98a4c5aSCarlos Alberto Enciso 162e98a4c5aSCarlos Alberto Enciso return Error::success(); 163e98a4c5aSCarlos Alberto Enciso }; 164e98a4c5aSCarlos Alberto Enciso 165e98a4c5aSCarlos Alberto Enciso // If the user has requested printing details for the comparison, we 166e98a4c5aSCarlos Alberto Enciso // disable the indentation and the added/missing tags ('+'/'-'), as the 167e98a4c5aSCarlos Alberto Enciso // details are just a list of elements. 168e98a4c5aSCarlos Alberto Enciso options().resetPrintFormatting(); 169e98a4c5aSCarlos Alberto Enciso 170e98a4c5aSCarlos Alberto Enciso PrintHeader(ReferenceRoot, TargetRoot); 171e98a4c5aSCarlos Alberto Enciso Reader = ReferenceReader; 172e98a4c5aSCarlos Alberto Enciso if (Error Err = CompareViews(ReferenceRoot, TargetRoot)) 173e98a4c5aSCarlos Alberto Enciso return Err; 174e98a4c5aSCarlos Alberto Enciso FirstMissing = true; 175e98a4c5aSCarlos Alberto Enciso ReferenceRoot->report(LVComparePass::Missing); 176e98a4c5aSCarlos Alberto Enciso 177e98a4c5aSCarlos Alberto Enciso PrintHeader(TargetRoot, ReferenceRoot); 178e98a4c5aSCarlos Alberto Enciso Reader = TargetReader; 179e98a4c5aSCarlos Alberto Enciso if (Error Err = CompareViews(TargetRoot, ReferenceRoot)) 180e98a4c5aSCarlos Alberto Enciso return Err; 181e98a4c5aSCarlos Alberto Enciso FirstMissing = true; 182e98a4c5aSCarlos Alberto Enciso TargetRoot->report(LVComparePass::Added); 183e98a4c5aSCarlos Alberto Enciso 184e98a4c5aSCarlos Alberto Enciso options().setPrintFormatting(); 185e98a4c5aSCarlos Alberto Enciso 186e98a4c5aSCarlos Alberto Enciso // Display a summary with the elements missing and/or added. 187e98a4c5aSCarlos Alberto Enciso printSummary(); 188e98a4c5aSCarlos Alberto Enciso } else { 189e98a4c5aSCarlos Alberto Enciso // Perform logical elements comparison. An equal test is apply to each 190e98a4c5aSCarlos Alberto Enciso // element. If a difference is found, the reference element is marked as 191e98a4c5aSCarlos Alberto Enciso // 'missing'. 192e98a4c5aSCarlos Alberto Enciso // The final comparison result will show the 'Reference' scopes tree, 193e98a4c5aSCarlos Alberto Enciso // having both missing and added elements. 194e98a4c5aSCarlos Alberto Enciso using LVScopeLink = std::map<LVScope *, LVScope *>; 195e98a4c5aSCarlos Alberto Enciso LVScopeLink ScopeLinks; 196e98a4c5aSCarlos Alberto Enciso auto CompareReaders = [&](LVReader *LHS, LVReader *RHS, LVElements &Set, 197e98a4c5aSCarlos Alberto Enciso LVComparePass Pass) -> Error { 198e98a4c5aSCarlos Alberto Enciso auto FindMatch = [&](auto &References, auto &Targets, 199e98a4c5aSCarlos Alberto Enciso const char *Category) -> Error { 200e98a4c5aSCarlos Alberto Enciso LVElements Elements; 201e98a4c5aSCarlos Alberto Enciso for (LVElement *Reference : References) { 202e98a4c5aSCarlos Alberto Enciso // Report elements that can be printed; ignore logical elements that 203e98a4c5aSCarlos Alberto Enciso // have qualifiers. 204e98a4c5aSCarlos Alberto Enciso if (Reference->getIncludeInPrint()) { 205e98a4c5aSCarlos Alberto Enciso if (Pass == LVComparePass::Missing) 206e98a4c5aSCarlos Alberto Enciso updateExpected(Reference); 207e98a4c5aSCarlos Alberto Enciso Reference->setIsInCompare(); 208e98a4c5aSCarlos Alberto Enciso LVElement *CurrentTarget = nullptr; 2096e18003aSKazu Hirata if (llvm::any_of(Targets, [&](auto Target) -> bool { 210e98a4c5aSCarlos Alberto Enciso CurrentTarget = Target; 211e98a4c5aSCarlos Alberto Enciso return Reference->equals(Target); 212e98a4c5aSCarlos Alberto Enciso })) { 213e98a4c5aSCarlos Alberto Enciso if (Pass == LVComparePass::Missing && Reference->getIsScope()) { 214e98a4c5aSCarlos Alberto Enciso // If the elements being compared are scopes and are a match, 215e98a4c5aSCarlos Alberto Enciso // they are recorded, to be used when creating the augmented 216e98a4c5aSCarlos Alberto Enciso // tree, as insertion points for the "added" items. 217e98a4c5aSCarlos Alberto Enciso ScopeLinks.emplace(static_cast<LVScope *>(CurrentTarget), 218e98a4c5aSCarlos Alberto Enciso static_cast<LVScope *>(Reference)); 219e98a4c5aSCarlos Alberto Enciso } 220e98a4c5aSCarlos Alberto Enciso } else { 221e98a4c5aSCarlos Alberto Enciso // Element is missing or added. 222e98a4c5aSCarlos Alberto Enciso Pass == LVComparePass::Missing ? Reference->setIsMissing() 223e98a4c5aSCarlos Alberto Enciso : Reference->setIsAdded(); 224e98a4c5aSCarlos Alberto Enciso Elements.push_back(Reference); 225e98a4c5aSCarlos Alberto Enciso updateMissingOrAdded(Reference, Pass); 226e98a4c5aSCarlos Alberto Enciso // Record missing/added element. 227e98a4c5aSCarlos Alberto Enciso addPassEntry(Reader, Reference, Pass); 228e98a4c5aSCarlos Alberto Enciso } 229e98a4c5aSCarlos Alberto Enciso } 230e98a4c5aSCarlos Alberto Enciso } 231e98a4c5aSCarlos Alberto Enciso if (Pass == LVComparePass::Added) 232e98a4c5aSCarlos Alberto Enciso // Record all the current missing elements for this category. 233e98a4c5aSCarlos Alberto Enciso Set.insert(Set.end(), Elements.begin(), Elements.end()); 234e98a4c5aSCarlos Alberto Enciso if (options().getReportList()) { 235e98a4c5aSCarlos Alberto Enciso if (Elements.size()) { 236e98a4c5aSCarlos Alberto Enciso OS << "\n(" << Elements.size() << ") " 237e98a4c5aSCarlos Alberto Enciso << (Pass == LVComparePass::Missing ? "Missing" : "Added") << " " 238e98a4c5aSCarlos Alberto Enciso << Category << ":\n"; 239e98a4c5aSCarlos Alberto Enciso for (const LVElement *Element : Elements) { 240e98a4c5aSCarlos Alberto Enciso if (Error Err = Element->doPrint(/*Split=*/false, /*Match=*/false, 241e98a4c5aSCarlos Alberto Enciso /*Print=*/true, OS)) 242e98a4c5aSCarlos Alberto Enciso return Err; 243e98a4c5aSCarlos Alberto Enciso } 244e98a4c5aSCarlos Alberto Enciso } 245e98a4c5aSCarlos Alberto Enciso } 246e98a4c5aSCarlos Alberto Enciso 247e98a4c5aSCarlos Alberto Enciso return Error::success(); 248e98a4c5aSCarlos Alberto Enciso }; 249e98a4c5aSCarlos Alberto Enciso 250e98a4c5aSCarlos Alberto Enciso // First compare the scopes, so they will be inserted at the front of 251e98a4c5aSCarlos Alberto Enciso // the missing elements list. When they are moved, their children are 252e98a4c5aSCarlos Alberto Enciso // moved as well and no additional work is required. 253e98a4c5aSCarlos Alberto Enciso if (options().getCompareScopes()) 254e98a4c5aSCarlos Alberto Enciso if (Error Err = FindMatch(LHS->getScopes(), RHS->getScopes(), "Scopes")) 255e98a4c5aSCarlos Alberto Enciso return Err; 256e98a4c5aSCarlos Alberto Enciso if (options().getCompareSymbols()) 257e98a4c5aSCarlos Alberto Enciso if (Error Err = 258e98a4c5aSCarlos Alberto Enciso FindMatch(LHS->getSymbols(), RHS->getSymbols(), "Symbols")) 259e98a4c5aSCarlos Alberto Enciso return Err; 260e98a4c5aSCarlos Alberto Enciso if (options().getCompareTypes()) 261e98a4c5aSCarlos Alberto Enciso if (Error Err = FindMatch(LHS->getTypes(), RHS->getTypes(), "Types")) 262e98a4c5aSCarlos Alberto Enciso return Err; 263e98a4c5aSCarlos Alberto Enciso if (options().getCompareLines()) 264e98a4c5aSCarlos Alberto Enciso if (Error Err = FindMatch(LHS->getLines(), RHS->getLines(), "Lines")) 265e98a4c5aSCarlos Alberto Enciso return Err; 266e98a4c5aSCarlos Alberto Enciso 267e98a4c5aSCarlos Alberto Enciso return Error::success(); 268e98a4c5aSCarlos Alberto Enciso }; 269e98a4c5aSCarlos Alberto Enciso 270e98a4c5aSCarlos Alberto Enciso // If the user has requested printing details for the comparison, we 271e98a4c5aSCarlos Alberto Enciso // disable the indentation and the added/missing tags ('+'/'-'), as the 272e98a4c5aSCarlos Alberto Enciso // details are just a list of elements. 273e98a4c5aSCarlos Alberto Enciso options().resetPrintFormatting(); 274e98a4c5aSCarlos Alberto Enciso 275e98a4c5aSCarlos Alberto Enciso PrintHeader(ReferenceRoot, TargetRoot); 276e98a4c5aSCarlos Alberto Enciso // Include the root in the expected count. 277e98a4c5aSCarlos Alberto Enciso updateExpected(ReferenceRoot); 278e98a4c5aSCarlos Alberto Enciso 279e98a4c5aSCarlos Alberto Enciso LVElements ElementsToAdd; 280e98a4c5aSCarlos Alberto Enciso Reader = ReferenceReader; 281e98a4c5aSCarlos Alberto Enciso if (Error Err = CompareReaders(ReferenceReader, TargetReader, ElementsToAdd, 282e98a4c5aSCarlos Alberto Enciso LVComparePass::Missing)) 283e98a4c5aSCarlos Alberto Enciso return Err; 284e98a4c5aSCarlos Alberto Enciso Reader = TargetReader; 285e98a4c5aSCarlos Alberto Enciso if (Error Err = CompareReaders(TargetReader, ReferenceReader, ElementsToAdd, 286e98a4c5aSCarlos Alberto Enciso LVComparePass::Added)) 287e98a4c5aSCarlos Alberto Enciso return Err; 288e98a4c5aSCarlos Alberto Enciso 289e98a4c5aSCarlos Alberto Enciso LLVM_DEBUG({ 290e98a4c5aSCarlos Alberto Enciso dbgs() << "\nReference/Target Scope links:\n"; 291e98a4c5aSCarlos Alberto Enciso for (LVScopeLink::const_reference Entry : ScopeLinks) 292e98a4c5aSCarlos Alberto Enciso dbgs() << "Source: " << hexSquareString(Entry.first->getOffset()) << " " 293e98a4c5aSCarlos Alberto Enciso << "Destination: " << hexSquareString(Entry.second->getOffset()) 294e98a4c5aSCarlos Alberto Enciso << "\n"; 295e98a4c5aSCarlos Alberto Enciso dbgs() << "\n"; 296e98a4c5aSCarlos Alberto Enciso }); 297e98a4c5aSCarlos Alberto Enciso 298e98a4c5aSCarlos Alberto Enciso // Add the 'missing' elements from the 'Target' into the 'Reference'. 299e98a4c5aSCarlos Alberto Enciso // First insert the missing scopes, as they include any missing children. 300e98a4c5aSCarlos Alberto Enciso LVScope *Parent = nullptr; 301e98a4c5aSCarlos Alberto Enciso for (LVElement *Element : ElementsToAdd) { 302e98a4c5aSCarlos Alberto Enciso LLVM_DEBUG({ 303e98a4c5aSCarlos Alberto Enciso dbgs() << "Element to Insert: " << hexSquareString(Element->getOffset()) 304e98a4c5aSCarlos Alberto Enciso << ", Parent: " 305e98a4c5aSCarlos Alberto Enciso << hexSquareString(Element->getParentScope()->getOffset()) 306e98a4c5aSCarlos Alberto Enciso << "\n"; 307e98a4c5aSCarlos Alberto Enciso }); 308e98a4c5aSCarlos Alberto Enciso // Skip already inserted elements. They were inserted, if their parents 309e98a4c5aSCarlos Alberto Enciso // were missing. When inserting them, all the children are moved. 310e98a4c5aSCarlos Alberto Enciso if (Element->getHasMoved()) 311e98a4c5aSCarlos Alberto Enciso continue; 312e98a4c5aSCarlos Alberto Enciso 313e98a4c5aSCarlos Alberto Enciso // We need to find an insertion point in the reference scopes tree. 314e98a4c5aSCarlos Alberto Enciso Parent = Element->getParentScope(); 315*f01d45cfSKazu Hirata auto It = ScopeLinks.find(Parent); 316*f01d45cfSKazu Hirata if (It != ScopeLinks.end()) { 317*f01d45cfSKazu Hirata LVScope *InsertionPoint = It->second; 318e98a4c5aSCarlos Alberto Enciso LLVM_DEBUG({ 319e98a4c5aSCarlos Alberto Enciso dbgs() << "Inserted at: " 320e98a4c5aSCarlos Alberto Enciso << hexSquareString(InsertionPoint->getOffset()) << "\n"; 321e98a4c5aSCarlos Alberto Enciso }); 322e98a4c5aSCarlos Alberto Enciso if (Parent->removeElement(Element)) { 323e98a4c5aSCarlos Alberto Enciso // Be sure we have a current compile unit. 324e98a4c5aSCarlos Alberto Enciso getReader().setCompileUnit(InsertionPoint->getCompileUnitParent()); 325e98a4c5aSCarlos Alberto Enciso InsertionPoint->addElement(Element); 326e98a4c5aSCarlos Alberto Enciso Element->updateLevel(InsertionPoint, /*Moved=*/true); 327e98a4c5aSCarlos Alberto Enciso } 328e98a4c5aSCarlos Alberto Enciso } 329e98a4c5aSCarlos Alberto Enciso } 330e98a4c5aSCarlos Alberto Enciso 331e98a4c5aSCarlos Alberto Enciso options().setPrintFormatting(); 332e98a4c5aSCarlos Alberto Enciso 333e98a4c5aSCarlos Alberto Enciso // Display the augmented reference scopes tree. 334e98a4c5aSCarlos Alberto Enciso if (options().getReportAnyView()) 335e98a4c5aSCarlos Alberto Enciso if (Error Err = ReferenceReader->doPrint()) 336e98a4c5aSCarlos Alberto Enciso return Err; 337e98a4c5aSCarlos Alberto Enciso 338e98a4c5aSCarlos Alberto Enciso LLVM_DEBUG({ 339e98a4c5aSCarlos Alberto Enciso dbgs() << "\nModified Reference Reader"; 340e98a4c5aSCarlos Alberto Enciso if (Error Err = ReferenceReader->doPrint()) 341e98a4c5aSCarlos Alberto Enciso return Err; 342e98a4c5aSCarlos Alberto Enciso dbgs() << "\nModified Target Reader"; 343e98a4c5aSCarlos Alberto Enciso if (Error Err = TargetReader->doPrint()) 344e98a4c5aSCarlos Alberto Enciso return Err; 345e98a4c5aSCarlos Alberto Enciso }); 346e98a4c5aSCarlos Alberto Enciso 347e98a4c5aSCarlos Alberto Enciso // Display a summary with the elements missing and/or added. 348e98a4c5aSCarlos Alberto Enciso printSummary(); 349e98a4c5aSCarlos Alberto Enciso } 350e98a4c5aSCarlos Alberto Enciso 351e98a4c5aSCarlos Alberto Enciso return Error::success(); 352e98a4c5aSCarlos Alberto Enciso } 353e98a4c5aSCarlos Alberto Enciso 354e98a4c5aSCarlos Alberto Enciso void LVCompare::printCurrentStack() { 355e98a4c5aSCarlos Alberto Enciso for (const LVScope *Scope : ScopeStack) { 356e98a4c5aSCarlos Alberto Enciso Scope->printAttributes(OS); 357e98a4c5aSCarlos Alberto Enciso OS << Scope->lineNumberAsString(/*ShowZero=*/true) << " " << Scope->kind() 358e98a4c5aSCarlos Alberto Enciso << " " << formattedName(Scope->getName()) << "\n"; 359e98a4c5aSCarlos Alberto Enciso } 360e98a4c5aSCarlos Alberto Enciso } 361e98a4c5aSCarlos Alberto Enciso 362e98a4c5aSCarlos Alberto Enciso void LVCompare::printItem(LVElement *Element, LVComparePass Pass) { 363e98a4c5aSCarlos Alberto Enciso // Record expected, missing, added. 364e98a4c5aSCarlos Alberto Enciso updateExpected(Element); 365e98a4c5aSCarlos Alberto Enciso updateMissingOrAdded(Element, Pass); 366e98a4c5aSCarlos Alberto Enciso 367e98a4c5aSCarlos Alberto Enciso // Record missing/added element. 368e98a4c5aSCarlos Alberto Enciso if (Element->getIsMissing()) 369e98a4c5aSCarlos Alberto Enciso addPassEntry(Reader, Element, Pass); 370e98a4c5aSCarlos Alberto Enciso 371e98a4c5aSCarlos Alberto Enciso if ((!PrintLines && Element->getIsLine()) || 372e98a4c5aSCarlos Alberto Enciso (!PrintScopes && Element->getIsScope()) || 373e98a4c5aSCarlos Alberto Enciso (!PrintSymbols && Element->getIsSymbol()) || 374e98a4c5aSCarlos Alberto Enciso (!PrintTypes && Element->getIsType())) 375e98a4c5aSCarlos Alberto Enciso return; 376e98a4c5aSCarlos Alberto Enciso 377e98a4c5aSCarlos Alberto Enciso if (Element->getIsMissing()) { 378e98a4c5aSCarlos Alberto Enciso if (FirstMissing) { 379e98a4c5aSCarlos Alberto Enciso OS << "\n"; 380e98a4c5aSCarlos Alberto Enciso FirstMissing = false; 381e98a4c5aSCarlos Alberto Enciso } 382e98a4c5aSCarlos Alberto Enciso 383e98a4c5aSCarlos Alberto Enciso StringRef Kind = Element->kind(); 384e98a4c5aSCarlos Alberto Enciso StringRef Name = 385e98a4c5aSCarlos Alberto Enciso Element->getIsLine() ? Element->getPathname() : Element->getName(); 386e98a4c5aSCarlos Alberto Enciso StringRef Status = (Pass == LVComparePass::Missing) ? "Missing" : "Added"; 387e98a4c5aSCarlos Alberto Enciso OS << Status << " " << Kind << " '" << Name << "'"; 388e98a4c5aSCarlos Alberto Enciso if (Element->getLineNumber() > 0) 389e98a4c5aSCarlos Alberto Enciso OS << " at line " << Element->getLineNumber(); 390e98a4c5aSCarlos Alberto Enciso OS << "\n"; 391e98a4c5aSCarlos Alberto Enciso 392e98a4c5aSCarlos Alberto Enciso if (options().getReportList()) { 393e98a4c5aSCarlos Alberto Enciso printCurrentStack(); 394e98a4c5aSCarlos Alberto Enciso Element->printAttributes(OS); 395e98a4c5aSCarlos Alberto Enciso OS << Element->lineNumberAsString(/*ShowZero=*/true) << " " << Kind << " " 396e98a4c5aSCarlos Alberto Enciso << Name << "\n"; 397e98a4c5aSCarlos Alberto Enciso } 398e98a4c5aSCarlos Alberto Enciso } 399e98a4c5aSCarlos Alberto Enciso } 400e98a4c5aSCarlos Alberto Enciso 401e98a4c5aSCarlos Alberto Enciso void LVCompare::printSummary() const { 402e98a4c5aSCarlos Alberto Enciso if (!options().getPrintSummary()) 403e98a4c5aSCarlos Alberto Enciso return; 404e98a4c5aSCarlos Alberto Enciso std::string Separator = std::string(40, '-'); 405e98a4c5aSCarlos Alberto Enciso auto PrintSeparator = [&]() { OS << Separator << "\n"; }; 406e98a4c5aSCarlos Alberto Enciso auto PrintHeadingRow = [&](const char *T, const char *U, const char *V, 407e98a4c5aSCarlos Alberto Enciso const char *W) { 408e98a4c5aSCarlos Alberto Enciso OS << format("%-9s%9s %9s %9s\n", T, U, V, W); 409e98a4c5aSCarlos Alberto Enciso }; 410e98a4c5aSCarlos Alberto Enciso auto PrintDataRow = [&](const char *T, unsigned U, unsigned V, unsigned W) { 411e98a4c5aSCarlos Alberto Enciso OS << format("%-9s%9d %9d %9d\n", T, U, V, W); 412e98a4c5aSCarlos Alberto Enciso }; 413e98a4c5aSCarlos Alberto Enciso 414e98a4c5aSCarlos Alberto Enciso OS << "\n"; 415e98a4c5aSCarlos Alberto Enciso PrintSeparator(); 416e98a4c5aSCarlos Alberto Enciso PrintHeadingRow("Element", "Expected", "Missing", "Added"); 417e98a4c5aSCarlos Alberto Enciso PrintSeparator(); 418e98a4c5aSCarlos Alberto Enciso for (LVCompareInfo::reference Entry : Results) { 419e98a4c5aSCarlos Alberto Enciso if (Entry.first == LVCompareItem::Total) 420e98a4c5aSCarlos Alberto Enciso PrintSeparator(); 421e98a4c5aSCarlos Alberto Enciso PrintDataRow(std::get<getHeader()>(Entry.second), 422e98a4c5aSCarlos Alberto Enciso std::get<getExpected()>(Entry.second), 423e98a4c5aSCarlos Alberto Enciso std::get<getMissing()>(Entry.second), 424e98a4c5aSCarlos Alberto Enciso std::get<getAdded()>(Entry.second)); 425e98a4c5aSCarlos Alberto Enciso } 426e98a4c5aSCarlos Alberto Enciso } 427e98a4c5aSCarlos Alberto Enciso 428e98a4c5aSCarlos Alberto Enciso void LVCompare::print(raw_ostream &OS) const { OS << "LVCompare\n"; } 429