Revert "[Support][JSON] Use std::unordered_map for object storage" (#193549)
Reverts llvm/llvm-project#171230 to look at failures.
This commit is contained in:
@@ -155,7 +155,7 @@ static void insertComment(Object &Description, json::Value &Comment,
|
||||
Description[Key] = std::move(CommentsArray);
|
||||
Description["Has" + Key.str()] = true;
|
||||
} else {
|
||||
DescriptionIt->second.getAsArray()->push_back(Comment);
|
||||
DescriptionIt->getSecond().getAsArray()->push_back(Comment);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/Version.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
@@ -25,7 +25,7 @@ std::optional<VersionTuple> DarwinSDKInfo::RelatedTargetVersionMapping::map(
|
||||
return MaximumValue;
|
||||
auto KV = Mapping.find(Key.normalize());
|
||||
if (KV != Mapping.end())
|
||||
return KV->second;
|
||||
return KV->getSecond();
|
||||
// If no exact entry found, try just the major key version. Only do so when
|
||||
// a minor version number is present, to avoid recursing indefinitely into
|
||||
// the major-only check.
|
||||
@@ -43,10 +43,10 @@ DarwinSDKInfo::RelatedTargetVersionMapping::parseJSON(
|
||||
VersionTuple MinValue = Min;
|
||||
llvm::DenseMap<VersionTuple, VersionTuple> Mapping;
|
||||
for (const auto &KV : Obj) {
|
||||
if (auto Val = KV.second.getAsString()) {
|
||||
if (auto Val = KV.getSecond().getAsString()) {
|
||||
llvm::VersionTuple KeyVersion;
|
||||
llvm::VersionTuple ValueVersion;
|
||||
if (KeyVersion.tryParse(KV.first) || ValueVersion.tryParse(*Val))
|
||||
if (KeyVersion.tryParse(KV.getFirst()) || ValueVersion.tryParse(*Val))
|
||||
return std::nullopt;
|
||||
Mapping[KeyVersion.normalize()] = ValueVersion;
|
||||
if (KeyVersion < Min)
|
||||
@@ -119,7 +119,7 @@ static DarwinSDKInfo::PlatformInfoStorageType parsePlatformInfos(
|
||||
|
||||
for (auto SupportedTargetPair : *SupportedTargets) {
|
||||
llvm::json::Object *SupportedTarget =
|
||||
SupportedTargetPair.second.getAsObject();
|
||||
SupportedTargetPair.getSecond().getAsObject();
|
||||
auto Vendor = SupportedTarget->getString("LLVMTargetTripleVendor");
|
||||
auto OS = SupportedTarget->getString("LLVMTargetTripleSys");
|
||||
if (!Vendor || !OS)
|
||||
@@ -136,7 +136,7 @@ static DarwinSDKInfo::PlatformInfoStorageType parsePlatformInfos(
|
||||
|
||||
// The key is either the Xcode platform, or a variant. The platform must be
|
||||
// the first entry in the returned PlatformInfoStorageType.
|
||||
StringRef PlatformOrVariant = SupportedTargetPair.first;
|
||||
StringRef PlatformOrVariant = SupportedTargetPair.getFirst();
|
||||
|
||||
StringRef EffectivePlatformPrefix;
|
||||
// Ignore iosmac value if it exists.
|
||||
@@ -202,12 +202,12 @@ DarwinSDKInfo::parseDarwinSDKSettingsJSON(std::string FilePath,
|
||||
// FIXME: Generalize this out beyond iOS-deriving targets.
|
||||
// Look for ios_<targetos> version mapping for targets that derive from ios.
|
||||
for (const auto &KV : *VM) {
|
||||
auto Pair = StringRef(KV.first).split("_");
|
||||
auto Pair = StringRef(KV.getFirst()).split("_");
|
||||
if (Pair.first.compare_insensitive("ios") == 0) {
|
||||
llvm::Triple TT(llvm::Twine("--") + Pair.second.lower());
|
||||
if (TT.getOS() != llvm::Triple::UnknownOS) {
|
||||
auto Mapping = RelatedTargetVersionMapping::parseJSON(
|
||||
*KV.second.getAsObject(), *MaximumDeploymentVersion);
|
||||
*KV.getSecond().getAsObject(), *MaximumDeploymentVersion);
|
||||
if (Mapping)
|
||||
VersionMappings[OSEnvPair(llvm::Triple::IOS,
|
||||
llvm::Triple::UnknownEnvironment,
|
||||
|
||||
@@ -84,8 +84,8 @@ getArgListFromJSON(const StringRef Input, llvm::opt::OptTable *Table,
|
||||
return llvm::opt::InputArgList();
|
||||
|
||||
for (const auto &KV : *Root) {
|
||||
const Array *ArgList = KV.second.getAsArray();
|
||||
std::string Label = "-X" + KV.first.str();
|
||||
const Array *ArgList = KV.getSecond().getAsArray();
|
||||
std::string Label = "-X" + KV.getFirst().str();
|
||||
if (!ArgList)
|
||||
return make_error<TextAPIError>(TextAPIErrorCode::InvalidInputFormat);
|
||||
for (auto Arg : *ArgList) {
|
||||
|
||||
@@ -83,7 +83,7 @@ TEST_F(SarifDocumentWriterTest, canCreateEmptyDocument) {
|
||||
const llvm::json::Object &EmptyDoc = Writer.createDocument();
|
||||
std::vector<StringRef> Keys(EmptyDoc.size());
|
||||
std::transform(EmptyDoc.begin(), EmptyDoc.end(), Keys.begin(),
|
||||
[](auto Item) { return Item.first; });
|
||||
[](auto Item) { return Item.getFirst(); });
|
||||
|
||||
// THEN:
|
||||
ASSERT_THAT(Keys, testing::UnorderedElementsAre("$schema", "version"));
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
#include "lldb/Target/DynamicLoader.h"
|
||||
#include "lldb/lldb-forward.h"
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
class DynamicLoaderWindowsDYLD : public DynamicLoader {
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#define liblldb_IntelPTPerThreadTraceCollection_H_
|
||||
|
||||
#include "IntelPTSingleBufferTrace.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include <optional>
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
@@ -15,7 +15,6 @@ add_benchmark(MustacheBench Mustache.cpp PARTIAL_SOURCES_INTENDED)
|
||||
add_benchmark(SpecialCaseListBM SpecialCaseListBM.cpp PARTIAL_SOURCES_INTENDED)
|
||||
add_benchmark(DWARFVerifierBM DWARFVerifierBM.cpp PARTIAL_SOURCES_INTENDED)
|
||||
add_benchmark(PointerUnionBM PointerUnionBM.cpp PARTIAL_SOURCES_INTENDED)
|
||||
add_benchmark(JSONParserBM JSONParserBM.cpp PARTIAL_SOURCES_INTENDED)
|
||||
|
||||
add_benchmark(RuntimeLibcallsBench RuntimeLibcalls.cpp PARTIAL_SOURCES_INTENDED)
|
||||
|
||||
|
||||
@@ -1,299 +0,0 @@
|
||||
//===- JSONParserBM.cpp - JSON parser benchmarks --------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// \file
|
||||
// Benchmarks for LLVM's JSON parser.
|
||||
// Runs parsing, tree iteration, and object key lookup with generated inputs.
|
||||
// Measures time performance and memory consumption.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/JSON.h"
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <random>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Memory tracking via global operator new
|
||||
//
|
||||
// These are global overrides so the benchmark might be over-counting memory
|
||||
// allocations and usage. The data is still useful for comparisons with this
|
||||
// benchmark itself.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static std::atomic_size_t TotalAllocatedBytes{0};
|
||||
static std::atomic_size_t NumAllocs{0};
|
||||
static bool TrackMemory = false;
|
||||
|
||||
// Single-object new/delete.
|
||||
void *operator new(std::size_t Size) {
|
||||
if (TrackMemory) {
|
||||
TotalAllocatedBytes += Size;
|
||||
++NumAllocs;
|
||||
}
|
||||
return std::malloc(Size);
|
||||
}
|
||||
|
||||
void *operator new(std::size_t Size, std::align_val_t) {
|
||||
if (TrackMemory) {
|
||||
TotalAllocatedBytes += Size;
|
||||
++NumAllocs;
|
||||
}
|
||||
return std::malloc(Size);
|
||||
}
|
||||
|
||||
void *operator new(std::size_t Size, const std::nothrow_t &) noexcept {
|
||||
if (TrackMemory) {
|
||||
TotalAllocatedBytes += Size;
|
||||
++NumAllocs;
|
||||
}
|
||||
return std::malloc(Size);
|
||||
}
|
||||
|
||||
void *operator new(std::size_t Size, std::align_val_t,
|
||||
const std::nothrow_t &) noexcept {
|
||||
if (TrackMemory) {
|
||||
TotalAllocatedBytes += Size;
|
||||
++NumAllocs;
|
||||
}
|
||||
return std::malloc(Size);
|
||||
}
|
||||
|
||||
void operator delete(void *Ptr) noexcept { std::free(Ptr); }
|
||||
void operator delete(void *Ptr, std::align_val_t) noexcept { std::free(Ptr); }
|
||||
void operator delete(void *Ptr, std::size_t) noexcept { std::free(Ptr); }
|
||||
void operator delete(void *Ptr, std::size_t, std::align_val_t) noexcept {
|
||||
std::free(Ptr);
|
||||
}
|
||||
|
||||
// Array new/delete.
|
||||
void *operator new[](std::size_t Size) {
|
||||
if (TrackMemory) {
|
||||
TotalAllocatedBytes += Size;
|
||||
++NumAllocs;
|
||||
}
|
||||
return std::malloc(Size);
|
||||
}
|
||||
|
||||
void *operator new[](std::size_t Size, std::align_val_t) {
|
||||
if (TrackMemory) {
|
||||
TotalAllocatedBytes += Size;
|
||||
++NumAllocs;
|
||||
}
|
||||
return std::malloc(Size);
|
||||
}
|
||||
|
||||
void *operator new[](std::size_t Size, const std::nothrow_t &) noexcept {
|
||||
if (TrackMemory) {
|
||||
TotalAllocatedBytes += Size;
|
||||
++NumAllocs;
|
||||
}
|
||||
return std::malloc(Size);
|
||||
}
|
||||
|
||||
void *operator new[](std::size_t Size, std::align_val_t,
|
||||
const std::nothrow_t &) noexcept {
|
||||
if (TrackMemory) {
|
||||
TotalAllocatedBytes += Size;
|
||||
++NumAllocs;
|
||||
}
|
||||
return std::malloc(Size);
|
||||
}
|
||||
|
||||
void operator delete[](void *Ptr) noexcept { std::free(Ptr); }
|
||||
void operator delete[](void *Ptr, std::align_val_t) noexcept { std::free(Ptr); }
|
||||
void operator delete[](void *Ptr, std::size_t) noexcept { std::free(Ptr); }
|
||||
void operator delete[](void *Ptr, std::size_t, std::align_val_t) noexcept {
|
||||
std::free(Ptr);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Test data generation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Generate a JSON string with \p N entries in an array. Each entry is a nested
|
||||
/// structure with objects and arrays to exercise parsing, iteration, and lookup
|
||||
/// at multiple depths.
|
||||
///
|
||||
/// Structure:
|
||||
/// {"items": [
|
||||
/// {
|
||||
/// "name": "item_I",
|
||||
/// "value": I,
|
||||
/// "tags": [
|
||||
/// {"label": "tag_0", "priority": 0},
|
||||
/// ...
|
||||
/// ],
|
||||
/// "details": {
|
||||
/// "description": "description text for item I",
|
||||
/// "active": true/false,
|
||||
/// "nested": { "x": I, "y": I*100 }
|
||||
/// }
|
||||
/// },
|
||||
/// ...
|
||||
/// ]}
|
||||
static std::string generateJSON(int N) {
|
||||
std::string S;
|
||||
raw_string_ostream OS(S);
|
||||
OS << "{\"items\": [\n";
|
||||
for (int I = 0; I < N; ++I) {
|
||||
if (I > 0)
|
||||
OS << ",\n";
|
||||
OS << " {\n"
|
||||
<< " \"name\": \"item_" << I << "\",\n"
|
||||
<< " \"value\": " << I << ",\n"
|
||||
<< " \"tags\": [\n"
|
||||
<< " {\"label\": \"tag_0\", \"priority\": 0},\n"
|
||||
<< " {\"label\": \"tag_1\", \"priority\": 1},\n"
|
||||
<< " {\"label\": \"tag_2\", \"priority\": 2}\n"
|
||||
<< " ],\n"
|
||||
<< " \"details\": {\n"
|
||||
<< " \"description\": \"description text for item " << I << "\",\n"
|
||||
<< " \"active\": " << (I % 2 == 0 ? "true" : "false") << ",\n"
|
||||
<< " \"nested\": {\"x\": " << I << ", \"y\": " << I * 100 << "}\n"
|
||||
<< " }\n"
|
||||
<< " }";
|
||||
}
|
||||
OS << "\n]}";
|
||||
return S;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Tree traversal helpers
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Walk the JSON value tree, visiting every node. Returns the number of
|
||||
/// nodes visited.
|
||||
static size_t walkTree(const json::Value &V) {
|
||||
size_t Count = 1;
|
||||
if (const auto *Obj = V.getAsObject()) {
|
||||
for (const auto &KV : *Obj)
|
||||
Count += walkTree(KV.second);
|
||||
} else if (const auto *Arr = V.getAsArray()) {
|
||||
for (const auto &Elem : *Arr)
|
||||
Count += walkTree(Elem);
|
||||
}
|
||||
return Count;
|
||||
}
|
||||
|
||||
/// An Object paired with its own keys, for lookup benchmarks.
|
||||
struct ObjectWithKeys {
|
||||
const json::Object *Obj;
|
||||
SmallVector<std::string> Keys;
|
||||
};
|
||||
|
||||
/// Collect every Object in the tree together with its own keys.
|
||||
static void collectObjectsWithKeys(const json::Value &V,
|
||||
SmallVectorImpl<ObjectWithKeys> &Result) {
|
||||
if (const auto *Obj = V.getAsObject()) {
|
||||
ObjectWithKeys Entry;
|
||||
Entry.Obj = Obj;
|
||||
for (const auto &KV : *Obj) {
|
||||
Entry.Keys.push_back(std::string(StringRef(KV.first)));
|
||||
collectObjectsWithKeys(KV.second, Result);
|
||||
}
|
||||
Result.push_back(std::move(Entry));
|
||||
} else if (const auto *Arr = V.getAsArray()) {
|
||||
for (const auto &Elem : *Arr)
|
||||
collectObjectsWithKeys(Elem, Result);
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Benchmarks
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Benchmark json::parse(). Reports parse throughput and memory allocated.
|
||||
static void BM_JSONParse(benchmark::State &State) {
|
||||
std::string JSON = generateJSON(State.range(0));
|
||||
|
||||
// Measure memory for a single parse before the timed loop.
|
||||
TotalAllocatedBytes = 0;
|
||||
NumAllocs = 0;
|
||||
TrackMemory = true;
|
||||
{
|
||||
auto V = json::parse(JSON);
|
||||
benchmark::DoNotOptimize(V);
|
||||
}
|
||||
TrackMemory = false;
|
||||
|
||||
State.counters["AllocBytes"] = TotalAllocatedBytes.load();
|
||||
State.counters["Allocs"] = NumAllocs.load();
|
||||
|
||||
for (auto _ : State) {
|
||||
auto V = json::parse(JSON);
|
||||
benchmark::DoNotOptimize(V);
|
||||
}
|
||||
State.counters["ParseByteRate"] = benchmark::Counter(
|
||||
State.iterations() * JSON.size(), benchmark::Counter::kIsRate,
|
||||
benchmark::Counter::kIs1024);
|
||||
}
|
||||
BENCHMARK(BM_JSONParse)->Arg(10)->Arg(1000)->Arg(100000);
|
||||
|
||||
/// Benchmark recursive tree iteration over a parsed JSON value.
|
||||
static void BM_JSONIterate(benchmark::State &State) {
|
||||
std::string JSON = generateJSON(State.range(0));
|
||||
json::Value Root = cantFail(json::parse(JSON));
|
||||
size_t NodeCount = 0;
|
||||
for (auto _ : State) {
|
||||
NodeCount = walkTree(Root);
|
||||
benchmark::DoNotOptimize(NodeCount);
|
||||
}
|
||||
State.SetItemsProcessed(State.iterations() * NodeCount);
|
||||
}
|
||||
BENCHMARK(BM_JSONIterate)->Arg(10)->Arg(1000)->Arg(100000);
|
||||
|
||||
/// Benchmark Object::get() with each object's own keys in insertion order.
|
||||
static void BM_JSONLookupSequential(benchmark::State &State) {
|
||||
std::string JSON = generateJSON(State.range(0));
|
||||
json::Value Root = cantFail(json::parse(JSON));
|
||||
SmallVector<ObjectWithKeys> ObjKeys;
|
||||
collectObjectsWithKeys(Root, ObjKeys);
|
||||
|
||||
size_t TotalLookups = 0;
|
||||
for (const auto &OK : ObjKeys)
|
||||
TotalLookups += OK.Keys.size();
|
||||
|
||||
for (auto _ : State) {
|
||||
for (const auto &OK : ObjKeys)
|
||||
for (const auto &K : OK.Keys)
|
||||
benchmark::DoNotOptimize(OK.Obj->get(K));
|
||||
}
|
||||
State.SetItemsProcessed(State.iterations() * TotalLookups);
|
||||
}
|
||||
BENCHMARK(BM_JSONLookupSequential)->Arg(10)->Arg(1000)->Arg(100000);
|
||||
|
||||
/// Benchmark Object::get() with each object's own keys in random order.
|
||||
static void BM_JSONLookupRandom(benchmark::State &State) {
|
||||
std::string JSON = generateJSON(State.range(0));
|
||||
json::Value Root = cantFail(json::parse(JSON));
|
||||
SmallVector<ObjectWithKeys> ObjKeys;
|
||||
collectObjectsWithKeys(Root, ObjKeys);
|
||||
|
||||
std::mt19937 RNG(42);
|
||||
size_t TotalLookups = 0;
|
||||
for (auto &OK : ObjKeys) {
|
||||
TotalLookups += OK.Keys.size();
|
||||
std::shuffle(OK.Keys.begin(), OK.Keys.end(), RNG);
|
||||
}
|
||||
|
||||
for (auto _ : State) {
|
||||
for (const auto &OK : ObjKeys)
|
||||
for (const auto &K : OK.Keys)
|
||||
benchmark::DoNotOptimize(OK.Obj->get(K));
|
||||
}
|
||||
State.SetItemsProcessed(State.iterations() * TotalLookups);
|
||||
}
|
||||
BENCHMARK(BM_JSONLookupRandom)->Arg(10)->Arg(1000)->Arg(100000);
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
@@ -46,17 +46,16 @@
|
||||
#ifndef LLVM_SUPPORT_JSON_H
|
||||
#define LLVM_SUPPORT_JSON_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/STLFunctionalExtras.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/AlignOf.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace llvm {
|
||||
namespace json {
|
||||
@@ -95,14 +94,9 @@ class Value;
|
||||
template <typename T> Value toJSON(const std::optional<T> &Opt);
|
||||
|
||||
/// An Object is a JSON object, which maps strings to heterogenous JSON values.
|
||||
/// ObjectKey is a maybe-owned string.
|
||||
/// It simulates DenseMap<ObjectKey, Value>. ObjectKey is a maybe-owned string.
|
||||
class Object {
|
||||
struct ObjectKeyHash {
|
||||
template <typename T> size_t operator()(const T &Key) const {
|
||||
return hash_value(Key);
|
||||
}
|
||||
};
|
||||
using Storage = std::unordered_map<ObjectKey, Value, ObjectKeyHash>;
|
||||
using Storage = DenseMap<ObjectKey, Value, llvm::DenseMapInfo<StringRef>>;
|
||||
Storage M;
|
||||
|
||||
public:
|
||||
@@ -139,11 +133,8 @@ public:
|
||||
bool erase(StringRef K);
|
||||
void erase(iterator I) { M.erase(I); }
|
||||
|
||||
// TODO: Implement heterogeneous lookup using StringRef directly. We need to
|
||||
// make ObjectKey transparent with transparent hash and key equality check.
|
||||
// This is supported for unordered containers in C++20.
|
||||
iterator find(const ObjectKey &K) { return M.find(K); }
|
||||
const_iterator find(const ObjectKey &K) const { return M.find(K); }
|
||||
iterator find(StringRef K) { return M.find_as(K); }
|
||||
const_iterator find(StringRef K) const { return M.find_as(K); }
|
||||
// operator[] acts as if Value was default-constructible as null.
|
||||
LLVM_ABI Value &operator[](const ObjectKey &K);
|
||||
LLVM_ABI Value &operator[](ObjectKey &&K);
|
||||
@@ -655,7 +646,7 @@ inline Object::Object(std::initializer_list<KV> Properties) {
|
||||
for (const auto &P : Properties) {
|
||||
auto R = try_emplace(P.K, nullptr);
|
||||
if (R.second)
|
||||
R.first->second.moveFrom(std::move(P.V));
|
||||
R.first->getSecond().moveFrom(std::move(P.V));
|
||||
}
|
||||
}
|
||||
inline std::pair<Object::iterator, bool> Object::insert(KV E) {
|
||||
|
||||
@@ -22,10 +22,10 @@ namespace llvm {
|
||||
namespace json {
|
||||
|
||||
Value &Object::operator[](const ObjectKey &K) {
|
||||
return try_emplace(K, nullptr).first->second;
|
||||
return try_emplace(K, nullptr).first->getSecond();
|
||||
}
|
||||
Value &Object::operator[](ObjectKey &&K) {
|
||||
return try_emplace(std::move(K), nullptr).first->second;
|
||||
return try_emplace(std::move(K), nullptr).first->getSecond();
|
||||
}
|
||||
Value *Object::get(StringRef K) {
|
||||
auto I = find(K);
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
|
||||
#include "Views/InstructionView.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/MC/MCInstPrinter.h"
|
||||
|
||||
Reference in New Issue
Block a user