| //===-- LVSupport.h ---------------------------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines support functions. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSUPPORT_H |
| #define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSUPPORT_H |
| |
| #include "llvm/ADT/SmallBitVector.h" |
| #include "llvm/ADT/SmallString.h" |
| #include "llvm/ADT/Twine.h" |
| #include "llvm/DebugInfo/LogicalView/Core/LVStringPool.h" |
| #include "llvm/Support/Debug.h" |
| #include "llvm/Support/Format.h" |
| #include "llvm/Support/Path.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <cctype> |
| #include <map> |
| #include <sstream> |
| |
| namespace llvm { |
| namespace logicalview { |
| |
| // Returns the unique string pool instance. |
| LVStringPool &getStringPool(); |
| |
| template <typename T> |
| using TypeIsValid = std::bool_constant<std::is_pointer<T>::value>; |
| |
| // Utility class to help memory management and perform an automatic cleaning. |
| template <typename T, unsigned N = 8> |
| class LVAutoSmallVector : public SmallVector<T, N> { |
| static_assert(TypeIsValid<T>::value, "T must be a pointer type"); |
| |
| public: |
| using iterator = typename SmallVector<T, N>::iterator; |
| LVAutoSmallVector() : SmallVector<T, N>::SmallVector() {} |
| |
| ~LVAutoSmallVector() { |
| // Destroy the constructed elements in the vector. |
| for (auto *Item : *this) |
| delete Item; |
| } |
| }; |
| |
| // Used to record specific characteristics about the objects. |
| template <typename T> class LVProperties { |
| SmallBitVector Bits = SmallBitVector(static_cast<unsigned>(T::LastEntry) + 1); |
| |
| public: |
| LVProperties() = default; |
| |
| void set(T Idx) { Bits[static_cast<unsigned>(Idx)] = 1; } |
| void reset(T Idx) { Bits[static_cast<unsigned>(Idx)] = 0; } |
| bool get(T Idx) const { return Bits[static_cast<unsigned>(Idx)]; } |
| }; |
| |
| // Generate get, set and reset 'bool' functions for LVProperties instances. |
| // FAMILY: instance name. |
| // ENUM: enumeration instance. |
| // FIELD: enumerator instance. |
| // F1, F2, F3: optional 'set' functions to be called. |
| #define BOOL_BIT(FAMILY, ENUM, FIELD) \ |
| bool get##FIELD() const { return FAMILY.get(ENUM::FIELD); } \ |
| void set##FIELD() { FAMILY.set(ENUM::FIELD); } \ |
| void reset##FIELD() { FAMILY.reset(ENUM::FIELD); } |
| |
| #define BOOL_BIT_1(FAMILY, ENUM, FIELD, F1) \ |
| bool get##FIELD() const { return FAMILY.get(ENUM::FIELD); } \ |
| void set##FIELD() { \ |
| FAMILY.set(ENUM::FIELD); \ |
| set##F1(); \ |
| } \ |
| void reset##FIELD() { FAMILY.reset(ENUM::FIELD); } |
| |
| #define BOOL_BIT_2(FAMILY, ENUM, FIELD, F1, F2) \ |
| bool get##FIELD() const { return FAMILY.get(ENUM::FIELD); } \ |
| void set##FIELD() { \ |
| FAMILY.set(ENUM::FIELD); \ |
| set##F1(); \ |
| set##F2(); \ |
| } \ |
| void reset##FIELD() { FAMILY.reset(ENUM::FIELD); } |
| |
| #define BOOL_BIT_3(FAMILY, ENUM, FIELD, F1, F2, F3) \ |
| bool get##FIELD() const { return FAMILY.get(ENUM::FIELD); } \ |
| void set##FIELD() { \ |
| FAMILY.set(ENUM::FIELD); \ |
| set##F1(); \ |
| set##F2(); \ |
| set##F3(); \ |
| } \ |
| void reset##FIELD() { FAMILY.reset(ENUM::FIELD); } |
| |
| // Generate get, set and reset functions for 'properties'. |
| #define PROPERTY(ENUM, FIELD) BOOL_BIT(Properties, ENUM, FIELD) |
| #define PROPERTY_1(ENUM, FIELD, F1) BOOL_BIT_1(Properties, ENUM, FIELD, F1) |
| #define PROPERTY_2(ENUM, FIELD, F1, F2) \ |
| BOOL_BIT_2(Properties, ENUM, FIELD, F1, F2) |
| #define PROPERTY_3(ENUM, FIELD, F1, F2, F3) \ |
| BOOL_BIT_3(Properties, ENUM, FIELD, F1, F2, F3) |
| |
| // Generate get, set and reset functions for 'kinds'. |
| #define KIND(ENUM, FIELD) BOOL_BIT(Kinds, ENUM, FIELD) |
| #define KIND_1(ENUM, FIELD, F1) BOOL_BIT_1(Kinds, ENUM, FIELD, F1) |
| #define KIND_2(ENUM, FIELD, F1, F2) BOOL_BIT_2(Kinds, ENUM, FIELD, F1, F2) |
| #define KIND_3(ENUM, FIELD, F1, F2, F3) \ |
| BOOL_BIT_3(Kinds, ENUM, FIELD, F1, F2, F3) |
| |
| const int HEX_WIDTH = 12; |
| inline FormattedNumber hexValue(uint64_t N, unsigned Width = HEX_WIDTH, |
| bool Upper = false) { |
| return format_hex(N, Width, Upper); |
| } |
| |
| // Output the hexadecimal representation of 'Value' using '[0x%08x]' format. |
| inline std::string hexString(uint64_t Value, size_t Width = HEX_WIDTH) { |
| std::string String; |
| raw_string_ostream Stream(String); |
| Stream << hexValue(Value, Width, false); |
| return Stream.str(); |
| } |
| |
| // Get a hexadecimal string representation for the given value. |
| inline std::string hexSquareString(uint64_t Value) { |
| return (Twine("[") + Twine(hexString(Value)) + Twine("]")).str(); |
| } |
| |
| // Return a string with the First and Others separated by spaces. |
| template <typename... Args> |
| std::string formatAttributes(const StringRef First, Args... Others) { |
| const auto List = {First, Others...}; |
| std::stringstream Stream; |
| size_t Size = 0; |
| for (const StringRef &Item : List) { |
| Stream << (Size ? " " : "") << Item.str(); |
| Size = Item.size(); |
| } |
| Stream << (Size ? " " : ""); |
| return Stream.str(); |
| } |
| |
| // Add an item to a map with second being a list. |
| template <typename MapType, typename ListType, typename KeyType, |
| typename ValueType> |
| void addItem(MapType *Map, KeyType Key, ValueType Value) { |
| ListType *List = nullptr; |
| typename MapType::const_iterator Iter = Map->find(Key); |
| if (Iter != Map->end()) |
| List = Iter->second; |
| else { |
| List = new ListType(); |
| Map->emplace(Key, List); |
| } |
| List->push_back(Value); |
| } |
| |
| // Delete the map contained list. |
| template <typename MapType> void deleteList(MapType &Map) { |
| for (typename MapType::const_reference Entry : Map) |
| delete Entry.second; |
| } |
| |
| // Double map data structure. |
| template <typename FirstKeyType, typename SecondKeyType, typename ValueType> |
| class LVDoubleMap { |
| static_assert(std::is_pointer<ValueType>::value, |
| "ValueType must be a pointer."); |
| using LVSecondMapType = std::map<SecondKeyType, ValueType>; |
| using LVFirstMapType = std::map<FirstKeyType, LVSecondMapType *>; |
| using LVAuxMapType = std::map<SecondKeyType, FirstKeyType>; |
| using LVValueTypes = std::vector<ValueType>; |
| LVFirstMapType FirstMap; |
| LVAuxMapType AuxMap; |
| |
| public: |
| LVDoubleMap() = default; |
| ~LVDoubleMap() { |
| for (auto &Entry : FirstMap) |
| delete Entry.second; |
| } |
| |
| void add(FirstKeyType FirstKey, SecondKeyType SecondKey, ValueType Value) { |
| LVSecondMapType *SecondMap = nullptr; |
| typename LVFirstMapType::iterator FirstIter = FirstMap.find(FirstKey); |
| if (FirstIter == FirstMap.end()) { |
| SecondMap = new LVSecondMapType(); |
| FirstMap.emplace(FirstKey, SecondMap); |
| } else { |
| SecondMap = FirstIter->second; |
| } |
| |
| assert(SecondMap && "SecondMap is null."); |
| if (SecondMap && SecondMap->find(SecondKey) == SecondMap->end()) |
| SecondMap->emplace(SecondKey, Value); |
| |
| typename LVAuxMapType::iterator AuxIter = AuxMap.find(SecondKey); |
| if (AuxIter == AuxMap.end()) { |
| AuxMap.emplace(SecondKey, FirstKey); |
| } |
| } |
| |
| LVSecondMapType *findMap(FirstKeyType FirstKey) const { |
| typename LVFirstMapType::const_iterator FirstIter = FirstMap.find(FirstKey); |
| if (FirstIter == FirstMap.end()) |
| return nullptr; |
| |
| LVSecondMapType *SecondMap = FirstIter->second; |
| return SecondMap; |
| } |
| |
| ValueType find(FirstKeyType FirstKey, SecondKeyType SecondKey) const { |
| LVSecondMapType *SecondMap = findMap(FirstKey); |
| if (!SecondMap) |
| return nullptr; |
| |
| typename LVSecondMapType::const_iterator SecondIter = |
| SecondMap->find(SecondKey); |
| return (SecondIter != SecondMap->end()) ? SecondIter->second : nullptr; |
| } |
| |
| ValueType find(SecondKeyType SecondKey) const { |
| typename LVAuxMapType::const_iterator AuxIter = AuxMap.find(SecondKey); |
| if (AuxIter == AuxMap.end()) |
| return nullptr; |
| return find(AuxIter->second, SecondKey); |
| } |
| |
| // Return a vector with all the 'ValueType' values. |
| LVValueTypes find() const { |
| LVValueTypes Values; |
| if (FirstMap.empty()) |
| return Values; |
| for (typename LVFirstMapType::const_reference FirstEntry : FirstMap) { |
| LVSecondMapType *SecondMap = FirstEntry.second; |
| for (typename LVSecondMapType::const_reference SecondEntry : *SecondMap) |
| Values.push_back(SecondEntry.second); |
| } |
| return Values; |
| } |
| }; |
| |
| // Unified and flattened pathnames. |
| std::string transformPath(StringRef Path); |
| std::string flattenedFilePath(StringRef Path); |
| |
| inline std::string formattedKind(StringRef Kind) { |
| return (Twine("{") + Twine(Kind) + Twine("}")).str(); |
| } |
| |
| inline std::string formattedName(StringRef Name) { |
| return (Twine("'") + Twine(Name) + Twine("'")).str(); |
| } |
| |
| inline std::string formattedNames(StringRef Name1, StringRef Name2) { |
| return (Twine("'") + Twine(Name1) + Twine(Name2) + Twine("'")).str(); |
| } |
| |
| // These are the values assigned to the debug location record IDs. |
| // See DebugInfo/CodeView/CodeViewSymbols.def. |
| // S_DEFRANGE 0x113f |
| // S_DEFRANGE_SUBFIELD 0x1140 |
| // S_DEFRANGE_REGISTER 0x1141 |
| // S_DEFRANGE_FRAMEPOINTER_REL 0x1142 |
| // S_DEFRANGE_SUBFIELD_REGISTER 0x1143 |
| // S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE 0x1144 |
| // S_DEFRANGE_REGISTER_REL 0x1145 |
| // When recording CodeView debug location, the above values are truncated |
| // to a uint8_t value in order to fit the 'OpCode' used for the logical |
| // debug location operations. |
| // Return the original CodeView enum value. |
| inline uint16_t getCodeViewOperationCode(uint8_t Code) { return 0x1100 | Code; } |
| |
| } // end namespace logicalview |
| } // end namespace llvm |
| |
| #endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSUPPORT_H |