[InputGraph] Expand InputGraph nodes.

Flavors may like to expand InputGraph nodes, when a filenode after parsing
results in more elements. One such example is while parsing GNU linker scripts.
The linker scripts after parsing would result in a lot of filenodes and probably
controlnodes too.

Adds unittests to verify functionality.

llvm-svn: 195515
This commit is contained in:
Shankar Easwaran 2013-11-22 23:08:24 +00:00
parent c0845334da
commit 3ac09bcb8f
3 changed files with 240 additions and 0 deletions

View File

@ -67,6 +67,9 @@ public:
/// \brief Set Ordinals for all the InputElements that form the InputGraph
virtual bool assignOrdinals();
/// Normalize the InputGraph.
virtual void normalize();
/// Destructor
virtual ~InputGraph() {}
@ -131,6 +134,13 @@ public:
File // Represents a type associated with File Nodes
};
/// How does the inputGraph expand the InputElement
enum class ExpandType : uint8_t {
None, // Do nothing(Default)
ReplaceAndExpand, // Replace current node and expand
ExpandOnly // Expand the current node
};
/// \brief Initialize the Input Element, The ordinal value of an input Element
/// is initially set to -1, if the user wants to override its ordinal,
/// let the user do it
@ -175,6 +185,16 @@ public:
/// \brief Reset the next index
virtual void resetNextIndex() = 0;
/// Normalize functions
/// \brief How do we want to expand the current node ?
virtual ExpandType expandType() const { return ExpandType::None; }
/// \brief Get the elements that we want to expand with.
virtual range<InputGraph::InputElementIterT> expandElements() {
llvm_unreachable("no element to expand");
}
protected:
Kind _kind; // The type of the Element
int64_t _ordinal; // The ordinal value

View File

@ -86,6 +86,38 @@ error_code InputGraph::setNextElementIndex(uint32_t index) {
return error_code::success();
}
// Normalize the InputGraph.
void InputGraph::normalize() {
auto iterb = _inputArgs.begin();
auto itere = _inputArgs.end();
auto currentIter = _inputArgs.begin();
bool replaceCurrentNode = false;
bool expand = false;
std::vector<std::unique_ptr<InputElement> > _workInputArgs;
while (iterb != itere) {
replaceCurrentNode = false;
expand = false;
InputElement::ExpandType expandType = (*iterb)->expandType();
if (expandType == InputElement::ExpandType::ReplaceAndExpand) {
replaceCurrentNode = true;
expand = true;
} else if (expandType == InputElement::ExpandType::ExpandOnly) {
replaceCurrentNode = false;
expand = true;
}
currentIter = iterb++;
if (expand)
_workInputArgs.insert(
_workInputArgs.end(),
std::make_move_iterator((*currentIter)->expandElements().begin()),
std::make_move_iterator((*currentIter)->expandElements().end()));
if (!replaceCurrentNode)
_workInputArgs.push_back(std::move(*currentIter));
}
_inputArgs = std::move(_workInputArgs);
}
/// InputElement
/// \brief Initialize the Input Element, The ordinal value of an input Element

View File

@ -78,6 +78,44 @@ public:
}
};
class MyExpandFileNode : public FileNode {
public:
MyExpandFileNode(StringRef path, int64_t ordinal, ExpandType expandType)
: FileNode(path, ordinal), _expandType(expandType) {}
bool validate() { return true; }
bool dump(raw_ostream &) { return true; }
virtual error_code parse(const LinkingContext &, raw_ostream &) {
return error_code::success();
}
virtual ErrorOr<File &> getNextFile() {
if (_nextFileIndex == _files.size())
return make_error_code(InputGraphError::no_more_files);
return *_files[_nextFileIndex++];
}
/// \brief How do we want to expand the current node ?
virtual ExpandType expandType() const { return _expandType; }
/// \brief Get the elements that we want to expand with.
virtual range<InputGraph::InputElementIterT> expandElements() {
return make_range(_expandElements.begin(), _expandElements.end());
}
/// Process the input Elemenet
virtual bool addElement(std::unique_ptr<InputElement> element) {
_expandElements.push_back(std::move(element));
return true;
}
private:
InputGraph::InputElementVectorT _expandElements;
ExpandType _expandType;
};
class MyObjFile : public SimpleFile {
public:
MyObjFile(LinkingContext &context, StringRef path)
@ -362,4 +400,154 @@ TEST_F(InputGraphTest, AddNodeWithGroupIteration) {
EXPECT_NE(InputGraphError::no_more_files, error_code(objfile));
EXPECT_EQ("group_objfile2", (*objfile).path());
}
// Node expansion tests.
TEST_F(InputGraphTest, ExpandInputGraphNode) {
std::unique_ptr<MyFileNode> myfile(new MyFileNode("multi_files1", 0));
std::vector<std::unique_ptr<File> > objfiles;
std::unique_ptr<MyObjFile> obj1(new MyObjFile(_context, "objfile1"));
std::unique_ptr<MyObjFile> obj2(new MyObjFile(_context, "objfile2"));
objfiles.push_back(std::move(obj1));
objfiles.push_back(std::move(obj2));
myfile->addFiles(std::move(objfiles));
EXPECT_EQ(true, inputGraph().addInputElement(std::move(myfile)));
objfiles.clear();
std::unique_ptr<MyExpandFileNode> expandFile(new MyExpandFileNode(
"expand_node", 1, InputElement::ExpandType::ExpandOnly));
std::unique_ptr<MyFileNode> filenode1(new MyFileNode("expand_file1", 2));
std::unique_ptr<MyObjFile> obj3(new MyObjFile(_context, "objfile3"));
objfiles.push_back(std::move(obj3));
filenode1->addFiles(std::move(objfiles));
expandFile->addElement(std::move(filenode1));
objfiles.clear();
std::unique_ptr<MyFileNode> filenode2(new MyFileNode("expand_file2", 3));
std::unique_ptr<MyObjFile> obj4(new MyObjFile(_context, "objfile4"));
objfiles.push_back(std::move(obj4));
filenode2->addFiles(std::move(objfiles));
expandFile->addElement(std::move(filenode2));
objfiles.clear();
// Add expand file to InputGraph
EXPECT_EQ(true, inputGraph().addInputElement(std::move(expandFile)));
std::unique_ptr<MyFileNode> filenode3(new MyFileNode("obj_after_expand", 4));
std::unique_ptr<MyObjFile> obj5(new MyObjFile(_context, "objfile5"));
std::unique_ptr<MyObjFile> obj6(new MyObjFile(_context, "objfile6"));
objfiles.push_back(std::move(obj5));
objfiles.push_back(std::move(obj6));
filenode3->addFiles(std::move(objfiles));
// Add an extra obj after the expand node
EXPECT_EQ(true, inputGraph().addInputElement(std::move(filenode3)));
inputGraph().normalize();
ErrorOr<InputElement *> nextElement = inputGraph().getNextInputElement();
EXPECT_NE(InputGraphError::no_more_elements, error_code(nextElement));
EXPECT_EQ(InputElement::Kind::File, (*nextElement)->kind());
FileNode *fileNode = llvm::dyn_cast<FileNode>(*nextElement);
EXPECT_EQ("multi_files1", (*fileNode).getUserPath());
nextElement = inputGraph().getNextInputElement();
EXPECT_NE(InputGraphError::no_more_elements, error_code(nextElement));
EXPECT_EQ(InputElement::Kind::File, (*nextElement)->kind());
fileNode = llvm::dyn_cast<FileNode>(*nextElement);
EXPECT_EQ("expand_file1", (*fileNode).getUserPath());
nextElement = inputGraph().getNextInputElement();
EXPECT_NE(InputGraphError::no_more_elements, error_code(nextElement));
EXPECT_EQ(InputElement::Kind::File, (*nextElement)->kind());
fileNode = llvm::dyn_cast<FileNode>(*nextElement);
EXPECT_EQ("expand_file2", (*fileNode).getUserPath());
nextElement = inputGraph().getNextInputElement();
EXPECT_NE(InputGraphError::no_more_elements, error_code(nextElement));
EXPECT_EQ(InputElement::Kind::File, (*nextElement)->kind());
fileNode = llvm::dyn_cast<FileNode>(*nextElement);
EXPECT_EQ("expand_node", (*fileNode).getUserPath());
nextElement = inputGraph().getNextInputElement();
EXPECT_NE(InputGraphError::no_more_elements, error_code(nextElement));
EXPECT_EQ(InputElement::Kind::File, (*nextElement)->kind());
fileNode = llvm::dyn_cast<FileNode>(*nextElement);
EXPECT_EQ("obj_after_expand", (*fileNode).getUserPath());
nextElement = inputGraph().getNextInputElement();
EXPECT_EQ(InputGraphError::no_more_elements, error_code(nextElement));
}
// Node expansion tests.
TEST_F(InputGraphTest, ExpandAndReplaceInputGraphNode) {
std::unique_ptr<MyFileNode> myfile(new MyFileNode("multi_files1", 0));
std::vector<std::unique_ptr<File> > objfiles;
std::unique_ptr<MyObjFile> obj1(new MyObjFile(_context, "objfile1"));
std::unique_ptr<MyObjFile> obj2(new MyObjFile(_context, "objfile2"));
objfiles.push_back(std::move(obj1));
objfiles.push_back(std::move(obj2));
myfile->addFiles(std::move(objfiles));
EXPECT_EQ(true, inputGraph().addInputElement(std::move(myfile)));
objfiles.clear();
std::unique_ptr<MyExpandFileNode> expandFile(new MyExpandFileNode(
"expand_node", 1, InputElement::ExpandType::ReplaceAndExpand));
std::unique_ptr<MyFileNode> filenode1(new MyFileNode("expand_file1", 2));
std::unique_ptr<MyObjFile> obj3(new MyObjFile(_context, "objfile3"));
objfiles.push_back(std::move(obj3));
filenode1->addFiles(std::move(objfiles));
expandFile->addElement(std::move(filenode1));
objfiles.clear();
std::unique_ptr<MyFileNode> filenode2(new MyFileNode("expand_file2", 3));
std::unique_ptr<MyObjFile> obj4(new MyObjFile(_context, "objfile4"));
objfiles.push_back(std::move(obj4));
filenode2->addFiles(std::move(objfiles));
expandFile->addElement(std::move(filenode2));
objfiles.clear();
// Add expand file to InputGraph
EXPECT_EQ(true, inputGraph().addInputElement(std::move(expandFile)));
std::unique_ptr<MyFileNode> filenode3(new MyFileNode("obj_after_expand", 4));
std::unique_ptr<MyObjFile> obj5(new MyObjFile(_context, "objfile5"));
std::unique_ptr<MyObjFile> obj6(new MyObjFile(_context, "objfile6"));
objfiles.push_back(std::move(obj5));
objfiles.push_back(std::move(obj6));
filenode3->addFiles(std::move(objfiles));
// Add an extra obj after the expand node
EXPECT_EQ(true, inputGraph().addInputElement(std::move(filenode3)));
inputGraph().normalize();
ErrorOr<InputElement *> nextElement = inputGraph().getNextInputElement();
EXPECT_NE(InputGraphError::no_more_elements, error_code(nextElement));
EXPECT_EQ(InputElement::Kind::File, (*nextElement)->kind());
FileNode *fileNode = llvm::dyn_cast<FileNode>(*nextElement);
EXPECT_EQ("multi_files1", (*fileNode).getUserPath());
nextElement = inputGraph().getNextInputElement();
EXPECT_NE(InputGraphError::no_more_elements, error_code(nextElement));
EXPECT_EQ(InputElement::Kind::File, (*nextElement)->kind());
fileNode = llvm::dyn_cast<FileNode>(*nextElement);
EXPECT_EQ("expand_file1", (*fileNode).getUserPath());
nextElement = inputGraph().getNextInputElement();
EXPECT_NE(InputGraphError::no_more_elements, error_code(nextElement));
EXPECT_EQ(InputElement::Kind::File, (*nextElement)->kind());
fileNode = llvm::dyn_cast<FileNode>(*nextElement);
EXPECT_EQ("expand_file2", (*fileNode).getUserPath());
nextElement = inputGraph().getNextInputElement();
EXPECT_NE(InputGraphError::no_more_elements, error_code(nextElement));
EXPECT_EQ(InputElement::Kind::File, (*nextElement)->kind());
fileNode = llvm::dyn_cast<FileNode>(*nextElement);
EXPECT_EQ("obj_after_expand", (*fileNode).getUserPath());
nextElement = inputGraph().getNextInputElement();
EXPECT_EQ(InputGraphError::no_more_elements, error_code(nextElement));
}
}