blob: 7ff3e36fea48de6d633ca95821f1b04a98596598 [file] [log] [blame] [edit]
//===- AbbrevTrieNode.cpp ------------------------------------------------===//
// Implements abbreviation lookup tries.
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/Bitcode/NaCl/AbbrevTrieNode.h"
#include "llvm/Bitcode/NaCl/NaClBitcodeValueDist.h"
using namespace llvm;
void AbbrevTrieNode::GetSuccessorLabels(SuccessorLabels &Labels) const {
for (SuccessorMap::const_iterator
IndexIter = Successors.begin(), IndexIterEnd = Successors.end();
IndexIter != IndexIterEnd; ++IndexIter) {
if (const SuccessorValueMap *ValueMap = IndexIter->second) {
for (SuccessorValueMap::const_iterator
ValueIter = ValueMap->begin(), ValueIterEnd = ValueMap->end();
ValueIter != ValueIterEnd; ++ValueIter) {
Labels.push_back(std::pair<size_t, uint64_t>(IndexIter->first,
ValueIter->first));
}
}
}
}
AbbrevTrieNode::~AbbrevTrieNode() {
for (SuccessorMap::const_iterator
Iter = Successors.begin(), IterEnd = Successors.end();
Iter != IterEnd; ++Iter) {
if (const SuccessorValueMap *ValueMap = Iter->second) {
for (SuccessorValueMap::const_iterator
Iter = ValueMap->begin(), IterEnd = ValueMap->end();
Iter != IterEnd; ++Iter) {
delete Iter->second;
}
delete ValueMap;
}
}
}
void AbbrevTrieNode::Print(raw_ostream &Stream,
const std::string &Indent,
bool LocalOnly) const {
std::string IndentPlus(Indent);
IndentPlus.append(" ");
std::string IndentPlusPlus(IndentPlus);
IndentPlusPlus.append(" ");
if (! Abbreviations.empty()) {
Stream << Indent << "Abbreviations:\n";
for (std::set<AbbrevIndexPair>::const_iterator
Iter = Abbreviations.begin(), IterEnd = Abbreviations.end();
Iter != IterEnd; ++Iter) {
Stream << IndentPlus;
Iter->second->Print(Stream, /* AddNewline= */ false);
Stream << " (abbrev #" << Iter->first << ")\n";
}
}
if (LocalOnly) return;
if (!Successors.empty()) {
Stream << Indent << "Successor Map:\n";
SuccessorLabels Labels;
GetSuccessorLabels(Labels);
for (SuccessorLabels::const_iterator
Iter = Labels.begin(), IterEnd = Labels.end();
Iter != IterEnd; ++Iter) {
size_t Index = Iter->first;
if (Index == 0) {
Stream << IndentPlus << "Record.Code = " << Iter->second << "\n";
} else {
Stream << IndentPlus << "Record.Values[" << (Index-1)
<< "] = " << Iter->second << "\n";
}
GetSuccessor(Iter->first, Iter->second)->Print(Stream, IndentPlusPlus);
}
}
}
AbbrevTrieNode *AbbrevTrieNode::
GetSuccessor(size_t Index, uint64_t Value) const {
SuccessorMap::const_iterator IndexPos = Successors.find(Index);
if (IndexPos != Successors.end()) {
if (SuccessorValueMap *ValueMap = IndexPos->second) {
SuccessorValueMap::iterator ValuePos = ValueMap->find(Value);
if (ValuePos != ValueMap->end())
return ValuePos->second;
}
}
return 0;
}
bool AbbrevTrieNode::Add(NaClBitCodeAbbrev *Abbrev,
size_t Index, size_t SkipIndex) {
if (Index >= Abbrev->getNumOperandInfos()) return false;
bool AddedNodes = false;
// Skip over matches that may match because they don't have constants
// in the index.
while (SkipIndex < Index) {
SuccessorMap::iterator Pos = Successors.find(SkipIndex);
if (Pos != Successors.end()) {
SuccessorValueMap *ValueMap = Pos->second;
for (SuccessorValueMap::const_iterator
Iter = ValueMap->begin(), IterEnd = ValueMap->end();
Iter != IterEnd; ++Iter) {
if (AbbrevTrieNode *Successor = Iter->second) {
if (Successor->Add(Abbrev, Index, SkipIndex+1))
AddedNodes = true;
}
}
}
++SkipIndex;
}
// Now update successors for next matching constant in abbreviation.
for (; Index < Abbrev->GetMinRecordSize(); ++Index) {
const NaClBitCodeAbbrevOp &Op = Abbrev->getOperandInfo(Index);
if (Op.isLiteral()) {
if (Index == SkipIndex) {
// No preceeding nodes to match, add here.
SuccessorValueMap *ValueMap = Successors[Index];
if (ValueMap == 0) {
ValueMap = new SuccessorValueMap();
Successors[Index] = ValueMap;
}
AbbrevTrieNode *Successor = (*ValueMap)[Op.getValue()];
if (Successor == 0) {
Successor = new AbbrevTrieNode();
AddedNodes = true;
(*ValueMap)[Op.getValue()] = Successor;
}
if (Successor->Add(Abbrev, Index+1, Index+1))
AddedNodes = true;
} else {
// Need to match all possible prefixes before inserting constant.
if (Add(Abbrev, Index, SkipIndex))
AddedNodes = true;
}
return AddedNodes;
}
}
return AddedNodes;
}
void AbbrevTrieNode::Insert(AbbrevIndexPair &AbbrevPair) {
NaClBitCodeAbbrev *Abbrev = AbbrevPair.second;
for (std::map<size_t, SuccessorValueMap*>::iterator
Iter = Successors.begin(), IterEnd = Successors.end();
Iter != IterEnd; ++Iter) {
if (SuccessorValueMap *ValueMap = Iter->second) {
if (Iter->first < Abbrev->GetMinRecordSize()) {
const NaClBitCodeAbbrevOp &Op =
Abbrev->getOperandInfo(Iter->first);
if (Op.isLiteral()) {
uint64_t Value = Op.getValue();
SuccessorValueMap::iterator Pos = ValueMap->find(Value);
if (Pos != ValueMap->end()) {
if (AbbrevTrieNode *Next = Pos->second) {
// Found constant that will be followed, update subgraph
// and quit.
Next->Insert(AbbrevPair);
return;
}
}
} else {
// Not literal, so it may (or may not) be followed, depending
// on the value in the record that will be matched against. So
// add to subgraph, and here if no succeeding matching literal
// constants.
for (SuccessorValueMap::iterator
Iter = ValueMap->begin(), IterEnd = ValueMap->end();
Iter != IterEnd; ++Iter) {
if (AbbrevTrieNode *Next = Iter->second)
Next->Insert(AbbrevPair);
}
}
} else if (!Abbrev->IsFixedSize()) {
// May match array element. So add to subgraph as well as here.
for (SuccessorValueMap::iterator
Iter = ValueMap->begin(), IterEnd = ValueMap->end();
Iter != IterEnd; ++Iter) {
if (AbbrevTrieNode *Next = Iter->second)
Next->Insert(AbbrevPair);
}
}
}
}
// If reached, no guarantees that any edge was followed, so add
// to matches of this node.
Abbreviations.insert(AbbrevPair);
}
const AbbrevTrieNode *AbbrevTrieNode::
MatchRecord(const NaClBitcodeRecordData &Record) const {
for (std::map<size_t, SuccessorValueMap*>::const_iterator
Iter = Successors.begin(), IterEnd = Successors.end();
Iter != IterEnd; ++Iter) {
if (SuccessorValueMap *ValueMap = Iter->second) {
if (Iter->first <= Record.Values.size()) {
uint64_t Value;
if (Iter->first == 0)
Value = Record.Code;
else
Value = Record.Values[Iter->first-1];
SuccessorValueMap::iterator Pos = ValueMap->find(Value);
if (Pos != ValueMap->end()) {
if (AbbrevTrieNode *Next = Pos->second) {
return Next->MatchRecord(Record);
}
}
} else {
// Map index too big, quit.
break;
}
}
}
// If reached, no refinement found, use this node.
return this;
}
static void ComputeAbbrevRange(NaClBitCodeAbbrev *Abbrev,
size_t &MinIndex, size_t &MaxIndex) {
// Find the range of record lengths for which the abbreviation may
// apply. Note: To keep a limit on the number of copies, collapse all
// records with length > NaClValueIndexCutoff into the same bucket.
MinIndex = Abbrev->GetMinRecordSize();
if (MinIndex > NaClValueIndexCutoff) {
MinIndex = NaClValueIndexCutoff + 1;
}
MaxIndex = MinIndex;
if (!Abbrev->IsFixedSize()) {
MaxIndex = NaClValueIndexCutoff + 1;
}
}
// Once all nodes have been added (via calls to AddAbbrevToLookupMap),
// this function adds the given abbreviation pair to all possible
// matchxes in the lookup map.
static void AddAbbrevPairToLookupMap(AbbrevLookupSizeMap &LookupMap,
AbbrevIndexPair &AbbrevPair) {
size_t MinIndex, MaxIndex;
ComputeAbbrevRange(AbbrevPair.second, MinIndex, MaxIndex);
for (size_t Index = MinIndex; Index <= MaxIndex; ++Index) {
AbbrevTrieNode *Node = LookupMap[Index];
assert(Node);
Node->Insert(AbbrevPair);
}
}
// Adds the given abbreviation to the corresponding lookup map, constructing
// the map of usable lookup tries.
static bool AddAbbrevToLookupMap(AbbrevLookupSizeMap &LookupMap,
NaClBitCodeAbbrev *Abbrev) {
bool Added = false;
size_t MinIndex, MaxIndex;
ComputeAbbrevRange(Abbrev, MinIndex, MaxIndex);
for (size_t Index = MinIndex; Index <= MaxIndex; ++Index) {
AbbrevTrieNode *Node = LookupMap[Index];
if (Node == 0) {
Node = new AbbrevTrieNode();
LookupMap[Index] = Node;
Added = true;
}
if (Node->Add(Abbrev)) Added = true;
}
return Added;
}
void llvm::NaClBuildAbbrevLookupMap(
AbbrevLookupSizeMap &LookupMap,
const SmallVectorImpl<NaClBitCodeAbbrev*> &Abbrevs,
size_t InitialIndex) {
// First build nodes of trie.
bool FixpointFound = false;
while (!FixpointFound) {
FixpointFound = true;
for (size_t i = InitialIndex; i < Abbrevs.size(); ++i) {
if (AddAbbrevToLookupMap(LookupMap, Abbrevs[i]))
FixpointFound = false;
}
}
// Now populate with abbreviations that apply.
for (size_t i = InitialIndex; i < Abbrevs.size(); ++i) {
AbbrevIndexPair Pair(i, Abbrevs[i]);
AddAbbrevPairToLookupMap(LookupMap, Pair);
}
}