Serialize index to binary (#273)
This commit is contained in:
@@ -29,13 +29,15 @@ public:
|
||||
void handleDeclOccurrence(const clang::NamedDecl* decl,
|
||||
RelationKind kind,
|
||||
clang::SourceLocation location) {
|
||||
assert(decl && "Invalid decl");
|
||||
if(!decl || location.isInvalid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(kind.is_one_of(RelationKind::Declaration,
|
||||
RelationKind::Definition,
|
||||
RelationKind::Reference,
|
||||
RelationKind::WeakReference) &&
|
||||
"Invalid kind");
|
||||
assert(location.isValid() && "Invalid location");
|
||||
|
||||
/// Forwards to the derived class. Check whether the derived class has
|
||||
/// its own implementation to avoid infinite recursion.
|
||||
@@ -94,8 +96,9 @@ public:
|
||||
RelationKind kind,
|
||||
const clang::NamedDecl* target,
|
||||
clang::SourceRange range) {
|
||||
assert(decl && "Invalid decl");
|
||||
assert(target && "Invalid target");
|
||||
if(!decl || !target || range.isInvalid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if constexpr(!std::same_as<decltype(&SemanticVisitor::handleRelation),
|
||||
decltype(&Derived::handleRelation)>) {
|
||||
|
||||
@@ -147,6 +147,18 @@ public:
|
||||
llvm::ArrayRef<std::string> compile_commands_dirs,
|
||||
llvm::StringRef workspace) -> void;
|
||||
|
||||
auto commands_size() {
|
||||
return command_infos.size();
|
||||
}
|
||||
|
||||
auto begin() {
|
||||
return command_infos.begin();
|
||||
}
|
||||
|
||||
auto end() {
|
||||
return command_infos.end();
|
||||
}
|
||||
|
||||
private:
|
||||
/// If file not found in CDB file, try to guess commands or use the default case.
|
||||
auto guess_or_fallback(this Self& self, llvm::StringRef file) -> LookupInfo;
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <bitset>
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
|
||||
namespace clice::index {
|
||||
|
||||
struct Contextual {
|
||||
/// The actual element id,
|
||||
std::uint32_t element_id;
|
||||
|
||||
constexpr inline static std::uint32_t FLAG = (1ull << 31);
|
||||
|
||||
static Contextual from(bool is_dependent, std::uint32_t offset) {
|
||||
Contextual ctx;
|
||||
ctx.element_id = offset;
|
||||
if(!is_dependent) {
|
||||
ctx.element_id |= FLAG;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
bool is_dependent() {
|
||||
return (element_id & FLAG) == 0;
|
||||
}
|
||||
|
||||
std::uint32_t offset() {
|
||||
return element_id & ~FLAG;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace clice::index
|
||||
@@ -1,184 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "RawIndex.h"
|
||||
|
||||
namespace clice::index::memory {
|
||||
|
||||
/// HeaderIndex store extra information to merge raw index from different header contexts.
|
||||
class HeaderIndex : public RawIndex {
|
||||
public:
|
||||
std::uint32_t file_count() {
|
||||
return header_contexts.size();
|
||||
}
|
||||
|
||||
/// The count of active header contexts in this index.
|
||||
std::uint32_t header_context_count() {
|
||||
return max_hctx_id - erased_hctx_ids.size();
|
||||
}
|
||||
|
||||
/// The count of active canonical contexts in this index.
|
||||
std::uint32_t canonical_context_count() {
|
||||
return max_cctx_id - erased_cctx_ids.size();
|
||||
}
|
||||
|
||||
/// Whether this contexts has only one single context.
|
||||
bool is_single_header_context() {
|
||||
return max_hctx_id == 1 && erased_hctx_ids.empty();
|
||||
}
|
||||
|
||||
auto erased_flag() {
|
||||
Bitmap map;
|
||||
map.set();
|
||||
for(auto cctx_id: erased_cctx_ids) {
|
||||
map.reset(cctx_id);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/// Get a new header context id.
|
||||
std::uint32_t alloc_hctx_id();
|
||||
|
||||
/// Get a new canonical context id.
|
||||
std::uint32_t alloc_cctx_id();
|
||||
|
||||
std::uint32_t alloc_dependent_elem_id() {
|
||||
auto id = dependent_elem_states.size();
|
||||
dependent_elem_states.emplace_back(false);
|
||||
return id;
|
||||
}
|
||||
|
||||
std::uint32_t alloc_independent_elem_id() {
|
||||
auto id = independent_elem_states.size();
|
||||
independent_elem_states.emplace_back();
|
||||
return id;
|
||||
}
|
||||
|
||||
struct HeaderContext {
|
||||
/// The include location id of this header context.
|
||||
std::uint32_t include;
|
||||
|
||||
/// The header context id of this header context.
|
||||
std::uint32_t hctx_id;
|
||||
|
||||
/// The canonical context id of this header context.
|
||||
std::uint32_t cctx_id;
|
||||
};
|
||||
|
||||
void remove(this HeaderIndex& self, llvm::StringRef path);
|
||||
|
||||
HeaderContext add_context(llvm::StringRef path, std::uint32_t include) {
|
||||
assert(!merged && "");
|
||||
auto& context = header_contexts[path].emplace_back();
|
||||
context.include = include;
|
||||
context.cctx_id = alloc_cctx_id();
|
||||
context.hctx_id = alloc_hctx_id();
|
||||
return context;
|
||||
}
|
||||
|
||||
HeaderContext
|
||||
merge(this HeaderIndex& self, llvm::StringRef path, std::uint32_t include, RawIndex& raw);
|
||||
|
||||
public:
|
||||
bool merged = false;
|
||||
|
||||
/// The max header context id.
|
||||
std::uint32_t max_hctx_id = 0;
|
||||
|
||||
/// The max canonical context id.
|
||||
std::uint32_t max_cctx_id = 0;
|
||||
|
||||
/// The erased header context id. if a header context is erased,
|
||||
/// we add its id for later reusing.
|
||||
std::deque<std::uint32_t> erased_hctx_ids;
|
||||
|
||||
/// Same as above but for canonical context id.
|
||||
std::deque<std::uint32_t> erased_cctx_ids;
|
||||
|
||||
/// A map between source file path and its header contexts.
|
||||
llvm::StringMap<llvm::SmallVector<HeaderContext>> header_contexts;
|
||||
|
||||
/// A map between canonical context id and corresponding ref counts
|
||||
/// referenced by header contexts.
|
||||
llvm::SmallVector<std::uint32_t> cctx_hctx_refs;
|
||||
|
||||
/// A map between canonical context id and corresponding ref counts
|
||||
/// referenced by contextual elements.
|
||||
llvm::SmallVector<std::uint32_t> cctx_element_refs;
|
||||
|
||||
using Bitmap = std::bitset<64>; /// use llvm::BitVector?
|
||||
|
||||
/// A map between dependent element id and its state, for dependent element
|
||||
/// we use bitmap to store states. Each bit in bitmap represents whether
|
||||
/// this element occurs in corresponding canonical context id.
|
||||
llvm::SmallVector<Bitmap> dependent_elem_states;
|
||||
|
||||
/// A map between independent element id and its state, for independent element
|
||||
/// we directly store the header context ids that it occurs in.
|
||||
std::vector<llvm::DenseSet<std::uint32_t>> independent_elem_states;
|
||||
};
|
||||
|
||||
} // namespace clice::index::memory
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template <typename... Ts>
|
||||
unsigned dense_hash(const Ts&... ts) {
|
||||
return llvm::DenseMapInfo<std::tuple<Ts...>>::getHashValue(std::tuple{ts...});
|
||||
}
|
||||
|
||||
template <>
|
||||
struct DenseMapInfo<clice::LocalSourceRange> {
|
||||
using R = clice::LocalSourceRange;
|
||||
|
||||
inline static R getEmptyKey() {
|
||||
return R(0, -1);
|
||||
}
|
||||
|
||||
inline static R getTombstoneKey() {
|
||||
return R(-1, 0);
|
||||
}
|
||||
|
||||
static auto getHashValue(const R& r) {
|
||||
return dense_hash(r.begin, r.end);
|
||||
}
|
||||
|
||||
static bool isEqual(const R& lhs, const R& rhs) {
|
||||
return lhs == rhs;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DenseMapInfo<clice::index::memory::Relation> {
|
||||
using R = clice::index::memory::Relation;
|
||||
|
||||
inline static R getEmptyKey() {
|
||||
return R{
|
||||
.kind = clice::RelationKind(),
|
||||
.range = clice::LocalSourceRange(0, 0),
|
||||
.target_symbol = 0,
|
||||
};
|
||||
}
|
||||
|
||||
inline static R getTombstoneKey() {
|
||||
return R{
|
||||
.kind = clice::RelationKind(),
|
||||
.range = clice::LocalSourceRange(-1, -1),
|
||||
.target_symbol = 0,
|
||||
};
|
||||
}
|
||||
|
||||
/// Contextual doen't take part in hashing and equality.
|
||||
static auto getHashValue(const R& relation) {
|
||||
return dense_hash(relation.kind.value(),
|
||||
relation.range.begin,
|
||||
relation.range.end,
|
||||
relation.target_symbol);
|
||||
}
|
||||
|
||||
static bool isEqual(const R& lhs, const R& rhs) {
|
||||
return lhs.kind == rhs.kind && lhs.range == rhs.range &&
|
||||
lhs.target_symbol == rhs.target_symbol;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
@@ -42,11 +42,20 @@ struct IncludeGraph {
|
||||
return paths[path_ref];
|
||||
}
|
||||
|
||||
std::uint32_t getInclude(clang::FileID fid) const {
|
||||
std::uint32_t include_location_id(clang::FileID fid) const {
|
||||
auto it = file_table.find(fid);
|
||||
assert(it != file_table.end());
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::uint32_t path_id(clang::FileID fid) {
|
||||
auto include = include_location_id(fid);
|
||||
if(include != -1) {
|
||||
return locations[include].path;
|
||||
} else {
|
||||
return paths.size() - 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace clice::index
|
||||
|
||||
@@ -1,77 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "TUIndex.h"
|
||||
|
||||
#define ROARING_EXCEPTIONS 0
|
||||
#define ROARING_TERMINATE(message) std::abort()
|
||||
#include "roaring/roaring.hh"
|
||||
|
||||
#include "Support/Bitmap.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
|
||||
namespace clice::index {
|
||||
|
||||
/// struct CompilationContext {
|
||||
/// /// The target of this compilation.
|
||||
/// llvm::StringRef target;
|
||||
///
|
||||
/// /// The canonical compilation command.
|
||||
/// llvm::StringRef command;
|
||||
///
|
||||
/// /// A version field for verification.
|
||||
/// std::uint32_t version;
|
||||
/// };
|
||||
///
|
||||
/// struct HeaderContext : CompilationContext {
|
||||
/// /// The include location in the include graph.
|
||||
/// std::uint32_t include;
|
||||
///
|
||||
/// /// The path of the file includes this header.
|
||||
/// llvm::StringRef path;
|
||||
/// };
|
||||
|
||||
struct HeaderContexts {
|
||||
std::uint32_t version = 0;
|
||||
|
||||
using Context = std::pair<std::uint32_t, std::uint32_t>;
|
||||
|
||||
/// A array of include location and its context id.
|
||||
llvm::SmallVector<Context> includes;
|
||||
};
|
||||
|
||||
struct MergedIndex {
|
||||
/// For each merged index, we will give it a canonical id.
|
||||
/// The max canonical id.
|
||||
std::uint32_t max_canonical_id = 0;
|
||||
|
||||
/// We use the value of SHA256 to judge whether two indices are same.
|
||||
/// Index with same content will be given same canonical id.
|
||||
llvm::DenseMap<llvm::StringRef, std::uint32_t> canonical_cache;
|
||||
|
||||
/// The allocator for storing sha256 hash.
|
||||
llvm::BumpPtrAllocator allocator;
|
||||
|
||||
/// The reference count of each canonical id.
|
||||
std::vector<std::uint32_t> canonical_ref_counts;
|
||||
|
||||
/// The canonical id set of removed index.
|
||||
roaring::Roaring removed;
|
||||
|
||||
/// A map between source file path and its header contexts.
|
||||
llvm::StringMap<HeaderContexts> contexts;
|
||||
|
||||
/// All merged symbol occurrences.
|
||||
llvm::DenseMap<Occurrence, roaring::Roaring> occurrences;
|
||||
|
||||
/// All merged symbol relations.
|
||||
llvm::DenseMap<SymbolHash, llvm::DenseMap<Relation, roaring::Roaring>> relations;
|
||||
|
||||
void remove(llvm::StringRef path);
|
||||
|
||||
void merge(llvm::StringRef path, std::uint32_t include, FileIndex& index);
|
||||
};
|
||||
|
||||
} // namespace clice::index
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template <typename... Ts>
|
||||
@@ -136,3 +68,76 @@ struct DenseMapInfo<clice::index::Relation> {
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
namespace clice::index {
|
||||
|
||||
/// struct CompilationContext {
|
||||
/// /// The target of this compilation.
|
||||
/// llvm::StringRef target;
|
||||
///
|
||||
/// /// The canonical compilation command.
|
||||
/// llvm::StringRef command;
|
||||
///
|
||||
/// /// A version field for verification.
|
||||
/// std::uint32_t version;
|
||||
/// };
|
||||
///
|
||||
/// struct HeaderContext : CompilationContext {
|
||||
/// /// The include location in the include graph.
|
||||
/// std::uint32_t include;
|
||||
///
|
||||
/// /// The path of the file includes this header.
|
||||
/// llvm::StringRef path;
|
||||
/// };
|
||||
|
||||
struct HeaderContexts {
|
||||
std::uint32_t version = 0;
|
||||
|
||||
using Context = std::pair<std::uint32_t, std::uint32_t>;
|
||||
|
||||
/// A array of include location and its context id.
|
||||
llvm::SmallVector<Context> includes;
|
||||
|
||||
friend bool operator== (const HeaderContexts& lhs, const HeaderContexts& rhs) = default;
|
||||
};
|
||||
|
||||
struct MergedIndex {
|
||||
/// For each merged index, we will give it a canonical id.
|
||||
/// The max canonical id.
|
||||
std::uint32_t max_canonical_id = 0;
|
||||
|
||||
/// We use the value of SHA256 to judge whether two indices are same.
|
||||
/// Index with same content will be given same canonical id.
|
||||
llvm::StringMap<std::uint32_t> canonical_cache;
|
||||
|
||||
/// The reference count of each canonical id.
|
||||
std::vector<std::uint32_t> canonical_ref_counts;
|
||||
|
||||
/// The canonical id set of removed index.
|
||||
roaring::Roaring removed;
|
||||
|
||||
/// A map between source file path and its header contexts.
|
||||
llvm::StringMap<HeaderContexts> contexts;
|
||||
|
||||
/// All merged symbol occurrences.
|
||||
llvm::DenseMap<Occurrence, roaring::Roaring> occurrences;
|
||||
|
||||
/// All merged symbol relations.
|
||||
llvm::DenseMap<SymbolHash, llvm::DenseMap<Relation, roaring::Roaring>> relations;
|
||||
|
||||
void remove(llvm::StringRef path);
|
||||
|
||||
void merge(llvm::StringRef path, std::uint32_t include, FileIndex& index);
|
||||
|
||||
void serialize(this MergedIndex& self, llvm::raw_ostream& out);
|
||||
|
||||
friend bool operator== (const MergedIndex& lhs, const MergedIndex& rhs) = default;
|
||||
};
|
||||
|
||||
struct MergedIndexView {
|
||||
const void* data;
|
||||
|
||||
MergedIndex deserialize();
|
||||
};
|
||||
|
||||
} // namespace clice::index
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Contextual.h"
|
||||
#include "AST/SymbolID.h"
|
||||
#include "AST/SymbolKind.h"
|
||||
#include "AST/RelationKind.h"
|
||||
#include "AST/SourceCode.h"
|
||||
|
||||
namespace clice::index::memory {
|
||||
|
||||
using SymbolID = std::uint64_t;
|
||||
|
||||
struct Relation {
|
||||
/// The context of this relation.
|
||||
Contextual ctx;
|
||||
|
||||
/// The relation kind of this relation.
|
||||
RelationKind kind;
|
||||
|
||||
/// The range of this relation.
|
||||
LocalSourceRange range;
|
||||
|
||||
/// A field to store extra information depend on kind.
|
||||
union {
|
||||
SymbolID target_symbol;
|
||||
LocalSourceRange definition_range;
|
||||
};
|
||||
};
|
||||
|
||||
struct Symbol {
|
||||
/// The symbol id.
|
||||
SymbolID id;
|
||||
|
||||
/// The symbol kind.
|
||||
SymbolKind kind;
|
||||
|
||||
/// Whether this symbol is not visible to other tu.
|
||||
bool is_tu_local = false;
|
||||
|
||||
/// Whether this symbol is defined in function scope.
|
||||
bool is_function_local = false;
|
||||
|
||||
/// The symbol name.
|
||||
std::string name;
|
||||
|
||||
/// All relations of this symbol.
|
||||
llvm::DenseSet<Relation> relations;
|
||||
};
|
||||
|
||||
struct Occurrence {
|
||||
/// The context of this occurrence.
|
||||
Contextual ctx;
|
||||
|
||||
/// The target symbol of this occurrence.
|
||||
SymbolID target_symbol;
|
||||
};
|
||||
|
||||
/// The raw index directly generated by indexing the source file.
|
||||
struct RawIndex {
|
||||
public:
|
||||
Symbol& get_symbol(SymbolID ID) {
|
||||
/// If not found, create a new symbol and return it.
|
||||
auto [it, _] = symbols.try_emplace(ID, Symbol{.id = ID});
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void add_relation(Symbol& symbol, Relation relation, bool is_dependent = true) {
|
||||
relation.ctx = Contextual::from(is_dependent, 0);
|
||||
symbol.relations.insert(relation);
|
||||
}
|
||||
|
||||
void add_occurrence(LocalSourceRange range, SymbolID target_symbol, bool is_dependent = true) {
|
||||
occurrences[range].emplace_back(Contextual::from(is_dependent, 0), target_symbol);
|
||||
}
|
||||
|
||||
public:
|
||||
/// The path of source file.
|
||||
std::string path;
|
||||
|
||||
/// The content of source file.
|
||||
std::string content;
|
||||
|
||||
/// All symbols in this index.
|
||||
llvm::DenseMap<SymbolID, Symbol> symbols;
|
||||
|
||||
/// All occurrences in this index.
|
||||
llvm::DenseMap<LocalSourceRange, llvm::SmallVector<Occurrence, 1>> occurrences;
|
||||
};
|
||||
|
||||
} // namespace clice::index::memory
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
#include "IncludeGraph.h"
|
||||
#include "AST/SourceCode.h"
|
||||
#include "AST/SymbolKind.h"
|
||||
#include "AST/RelationKind.h"
|
||||
#include "Support/Bitmap.h"
|
||||
|
||||
namespace clice::index {
|
||||
|
||||
@@ -12,15 +14,19 @@ using SymbolHash = std::uint64_t;
|
||||
struct Relation {
|
||||
RelationKind kind;
|
||||
|
||||
char padding[4] = {0, 0, 0, 0};
|
||||
std::uint32_t padding = 0;
|
||||
|
||||
LocalSourceRange range;
|
||||
|
||||
union {
|
||||
LocalSourceRange definition_range;
|
||||
SymbolHash target_symbol;
|
||||
|
||||
SymbolHash target_symbol;
|
||||
};
|
||||
void set_definition_range(LocalSourceRange range) {
|
||||
target_symbol = std::bit_cast<SymbolHash>(range);
|
||||
}
|
||||
|
||||
auto definition_range() {
|
||||
return std::bit_cast<LocalSourceRange>(target_symbol);
|
||||
}
|
||||
};
|
||||
|
||||
struct Occurrence {
|
||||
@@ -40,7 +46,10 @@ struct FileIndex {
|
||||
struct Symbol {
|
||||
std::string name;
|
||||
|
||||
/// ...
|
||||
SymbolKind kind;
|
||||
|
||||
/// All files that referenced this symbol.
|
||||
Bitmap reference_files;
|
||||
};
|
||||
|
||||
struct TUIndex {
|
||||
|
||||
@@ -11,8 +11,8 @@ struct Occurrence {
|
||||
}
|
||||
|
||||
struct Relation {
|
||||
kind: int;
|
||||
padding: int;
|
||||
kind: uint;
|
||||
padding: uint;
|
||||
range: Range;
|
||||
target_symbol: ulong;
|
||||
}
|
||||
|
||||
11
include/Support/Bitmap.h
Normal file
11
include/Support/Bitmap.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#define ROARING_EXCEPTIONS 0
|
||||
#define ROARING_TERMINATE(message) std::abort()
|
||||
#include "roaring/roaring.hh"
|
||||
|
||||
namespace clice {
|
||||
|
||||
using Bitmap = roaring::Roaring;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user