Skip to content

Commit 169d62a

Browse files
committed
WIP: Add support for types to LLVM graphs.
Signed-off-by: format 2020.06.15 <github.com/ChrisCummins/format>
1 parent 14921b6 commit 169d62a

File tree

6 files changed

+151
-16
lines changed

6 files changed

+151
-16
lines changed

programl/graph/format/graphviz_converter.cc

+11-5
Original file line numberDiff line numberDiff line change
@@ -195,26 +195,29 @@ labm8::Status SerializeGraphVizToString(const ProgramGraph& graph,
195195

196196
// Set the node shape.
197197
switch (node.type()) {
198+
attributes["style"] = "filled";
198199
case Node::INSTRUCTION:
199200
attributes["shape"] = "box";
200-
attributes["style"] = "filled";
201201
attributes["fillcolor"] = "#3c78d8";
202202
attributes["fontcolor"] = "#ffffff";
203203
break;
204204
case Node::VARIABLE:
205205
attributes["shape"] = "ellipse";
206-
attributes["style"] = "filled";
207206
attributes["fillcolor"] = "#f4cccc";
208207
attributes["color"] = "#990000";
209208
attributes["fontcolor"] = "#990000";
210209
break;
211210
case Node::CONSTANT:
212-
attributes["shape"] = "diamond";
213-
attributes["style"] = "filled";
211+
attributes["shape"] = "octagon";
214212
attributes["fillcolor"] = "#e99c9c";
215213
attributes["color"] = "#990000";
216214
attributes["fontcolor"] = "#990000";
217215
break;
216+
case Node::TYPE:
217+
attributes["shape"] = "diamond";
218+
attributes["fillcolor"] = "#cccccc";
219+
attributes["color"] = "#cccccc";
220+
attributes["fontcolor"] = "#222222";
218221
}
219222
}
220223

@@ -240,8 +243,11 @@ labm8::Status SerializeGraphVizToString(const ProgramGraph& graph,
240243
break;
241244
case Edge::CALL:
242245
attributes["color"] = "#65ae4d";
243-
attributes["weight"] = "1";
246+
attributes["weight"] = "1"; // TODO: Consider 0
244247
break;
248+
case Edge::TYPE:
249+
attributes["color"] = "#aaaaaa";
250+
attributes["weight"] = "0";
245251
}
246252

247253
// Set the edge label.

programl/graph/program_graph_builder.cc

+26
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ Node* ProgramGraphBuilder::AddConstant(const string& text) {
6767
return AddNode(Node::CONSTANT, text);
6868
}
6969

70+
Node* ProgramGraphBuilder::AddType(const string& text) {
71+
return AddNode(Node::TYPE, text);
72+
}
73+
7074
labm8::StatusOr<Edge*> ProgramGraphBuilder::AddControlEdge(int32_t position,
7175
const Node* source,
7276
const Node* target) {
@@ -143,6 +147,28 @@ labm8::StatusOr<Edge*> ProgramGraphBuilder::AddCallEdge(const Node* source,
143147
return AddEdge(Edge::CALL, /*position=*/0, source, target);
144148
}
145149

150+
labm8::StatusOr<Edge*> ProgramGraphBuilder::AddTypeEdge(int32_t position,
151+
const Node* source,
152+
const Node* target) {
153+
DCHECK(source) << "nullptr argument";
154+
DCHECK(target) << "nullptr argument";
155+
DCHECK(source) << "nullptr argument";
156+
DCHECK(target) << "nullptr argument";
157+
158+
if (source->type() != Node::TYPE) {
159+
return Status(labm8::error::Code::INVALID_ARGUMENT,
160+
"Invalid source type ({}) for type edge. Expected type",
161+
Node::Type_Name(source->type()));
162+
}
163+
if (target->type() == Node::INSTRUCTION) {
164+
return Status(labm8::error::Code::INVALID_ARGUMENT,
165+
"Invalid destination type (instruction) for type edge. "
166+
"Expected {variable,constant,type}");
167+
}
168+
169+
return AddEdge(Edge::TYPE, position, source, target);
170+
}
171+
146172
labm8::StatusOr<ProgramGraph> ProgramGraphBuilder::Build() {
147173
// Check that all nodes except the root are connected. The root is allowed to
148174
// have no connections in the case where it is an empty graph.

programl/graph/program_graph_builder.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ class ProgramGraphBuilder {
6161

6262
Node* AddConstant(const string& text);
6363

64+
Node* AddType(const string& text);
65+
6466
// Edge factories.
6567
[[nodiscard]] labm8::StatusOr<Edge*> AddControlEdge(int32_t position,
6668
const Node* source,
@@ -70,7 +72,8 @@ class ProgramGraphBuilder {
7072
const Node* source,
7173
const Node* target);
7274

73-
[[nodiscard]] labm8::StatusOr<Edge*> AddCallEdge(const Node* source,
75+
[[nodiscard]] labm8::StatusOr<Edge*> AddCallEdge(int32_t position,
76+
const Node* source,
7477
const Node* target);
7578

7679
const Node* GetRootNode() const { return &graph_.node(0); }
@@ -110,7 +113,7 @@ class ProgramGraphBuilder {
110113
int32_t GetIndex(const Function* function);
111114
int32_t GetIndex(const Node* node);
112115

113-
// Maps which covert store the index of objects in repeated field lists.
116+
// Maps which store the index of objects in repeated field lists.
114117
absl::flat_hash_map<Module*, int32_t> moduleIndices_;
115118
absl::flat_hash_map<Function*, int32_t> functionIndices_;
116119
absl::flat_hash_map<Node*, int32_t> nodeIndices_;

programl/ir/llvm/internal/BUILD

+10
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ cc_library(
4848
],
4949
)
5050

51+
cc_test(
52+
name = "program_graph_builder_test",
53+
srcs = ["program_graph_builder_test.cc"],
54+
deps = [
55+
":program_graph_builder",
56+
"//programl/proto:program_graph_options_cc",
57+
"@llvm//10.0.0",
58+
],
59+
)
60+
5161
cc_library(
5262
name = "program_graph_builder_pass",
5363
srcs = ["program_graph_builder_pass.cc"],

programl/ir/llvm/internal/program_graph_builder.cc

+84-9
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "programl/graph/features.h"
3232
#include "programl/ir/llvm/internal/text_encoder.h"
3333
#include "programl/proto/program_graph.pb.h"
34+
#include "program_graph_builder.h"
3435

3536
using labm8::Status;
3637

@@ -39,6 +40,11 @@ namespace ir {
3940
namespace llvm {
4041
namespace internal {
4142

43+
template<typename T>
44+
void AddFullTextFeature(T* element, const std::string& fullText) {
45+
graph::AddScalarFeature(element, "full_text", fullText);
46+
}
47+
4248
labm8::StatusOr<BasicBlockEntryExit> ProgramGraphBuilder::VisitBasicBlock(
4349
const ::llvm::BasicBlock& block, const Function* functionMessage,
4450
InstructionMap* instructions, ArgumentConsumerMap* argumentConsumers,
@@ -194,7 +200,7 @@ labm8::StatusOr<FunctionEntryExits> ProgramGraphBuilder::VisitFunction(
194200

195201
if (function.isDeclaration()) {
196202
Node* node = AddInstruction("; undefined function", functionMessage);
197-
graph::AddScalarFeature(node, "full_text", "");
203+
AddFullTextFeature(node, "");
198204
functionEntryExits.first = node;
199205
functionEntryExits.second.push_back(node);
200206
return functionEntryExits;
@@ -325,7 +331,7 @@ Node* ProgramGraphBuilder::AddLlvmInstruction(
325331
const LlvmTextComponents text = textEncoder_.Encode(instruction);
326332
Node* node = AddInstruction(text.opcode_name, function);
327333
node->set_block(blockCount_);
328-
graph::AddScalarFeature(node, "full_text", text.text);
334+
AddFullTextFeature(node, text.text);
329335

330336
// Add profiling information features, if available.
331337
uint64_t profTotalWeight;
@@ -345,29 +351,88 @@ Node* ProgramGraphBuilder::AddLlvmInstruction(
345351
Node* ProgramGraphBuilder::AddLlvmVariable(const ::llvm::Instruction* operand,
346352
const programl::Function* function) {
347353
const LlvmTextComponents text = textEncoder_.Encode(operand);
348-
Node* node = AddVariable(text.lhs_type, function);
354+
Node* node = AddVariable("var", function);
349355
node->set_block(blockCount_);
350-
graph::AddScalarFeature(node, "full_text", text.lhs);
351-
356+
AddFullTextFeature(node, text.lhs);
352357
return node;
353358
}
354359

355360
Node* ProgramGraphBuilder::AddLlvmVariable(const ::llvm::Argument* argument,
356361
const programl::Function* function) {
357362
const LlvmTextComponents text = textEncoder_.Encode(argument);
358-
Node* node = AddVariable(text.lhs_type, function);
363+
Node* node = AddVariable("var", function);
359364
node->set_block(blockCount_);
360-
graph::AddScalarFeature(node, "full_text", text.lhs);
365+
AddFullTextFeature(node, text.lhs);
366+
367+
Node* type = GetOrCreateType(operand->getType());
368+
AddTypeEdge(/*position=*/0, type, node);
361369

362370
return node;
363371
}
364372

365373
Node* ProgramGraphBuilder::AddLlvmConstant(const ::llvm::Constant* constant) {
366374
const LlvmTextComponents text = textEncoder_.Encode(constant);
367-
Node* node = AddConstant(text.lhs_type);
375+
Node* node = AddConstant("const");
368376
node->set_block(blockCount_);
369-
graph::AddScalarFeature(node, "full_text", text.text);
377+
AddFullTextFeature(node, text.text);
370378

379+
Node* type = GetOrCreateType(operand->getType());
380+
AddTypeEdge(/*position=*/0, type, node);
381+
return node;
382+
}
383+
384+
Node* ProgramGraphBuilder::AddLlvmType(const ::llvm::Type* type) {
385+
const LlvmTextComponents text = textEncoder_.Encode(constant);
386+
Node* node = AddType(text.ls_type);
387+
AddFullTextFeature(node, text.lhs);
388+
return node;
389+
}
390+
391+
Node* ProgramGraphBuilder::AddLlvmType(const ::llvm::StructType* type) {
392+
Node* node = AddType("struct");
393+
AddFullTextFeature(node, type->hasName() ? type->getName() : "struct");
394+
395+
// Add types for the struct elements, and type edges.
396+
for (int i = 0; i < type->getNumElements(); ++i) {
397+
const auto& member = type->elements()[i];
398+
// Re-use the type if it already exists to prevent duplication of member types.
399+
auto memberNode = GetOrCreateType(member);
400+
AddTypeEdge(/*position=*/i, memberNode, node);
401+
}
402+
403+
return node;
404+
}
405+
406+
Node* ProgramGraphBuilder::AddLlvmType(const ::llvm::PointerType* type) {
407+
Node* node = AddType("*");
408+
AddFullTextFeature(node, textEncoder_.Encode(constant).lhs);
409+
// Re-use the type if it already exists to prevent duplication of element types.
410+
auto elementType = GetOrCreateType(type->getElementType());
411+
AddTypeEdge(/*position=*/0,, elementType, node);
412+
return node;
413+
}
414+
415+
Node* ProgramGraphBuilder::AddLlvmType(const ::llvm::FunctionType* type) {
416+
Node* node = AddType("fn");
417+
AddFullTextFeature(node, textEncoder_.Encode(constant).lhs);
418+
return node;
419+
}
420+
421+
Node* ProgramGraphBuilder::AddLlvmType(const ::llvm::ArrayType* type) {
422+
Node* node = AddType("[]");
423+
AddFullTextFeature(node, textEncoder_.Encode(constant).lhs);
424+
// Re-use the type if it already exists to prevent duplication of element types.
425+
auto elementType = GetOrCreateType(type->getElementType());
426+
AddTypeEdge(/*position=*/0, elementType, node);
427+
return node;
428+
}
429+
430+
Node* ProgramGraphBuilder::AddLlvmType(const ::llvm::VectorType* type) {
431+
Node* node = AddType("vector");
432+
AddFullTextFeature(node, textEncoder_.Encode(constant).lhs);
433+
// Re-use the type if it already exists to prevent duplication of element types.
434+
auto elementType = GetOrCreateType(type->getElementType());
435+
AddTypeEdge(/*position=*/0, elementType, node);
371436
return node;
372437
}
373438

@@ -465,6 +530,16 @@ void ProgramGraphBuilder::Clear() {
465530
programl::graph::ProgramGraphBuilder::Clear();
466531
}
467532

533+
Node* ProgramGraphBuilder::GetOrCreateType(const ::llvm::Type* type) {
534+
auto it = types_.find(type);
535+
if (it == types_.end()) {
536+
Node* node = AddLlvmType(type);
537+
types_[type] = node;
538+
return node;
539+
}
540+
return it->second;
541+
}
542+
468543
} // namespace internal
469544
} // namespace llvm
470545
} // namespace ir

programl/ir/llvm/internal/program_graph_builder.h

+15
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "labm8/cpp/string.h"
2727
#include "llvm/IR/BasicBlock.h"
2828
#include "llvm/IR/Constant.h"
29+
#include "llvm/IR/DerivedTypes.h"
2930
#include "llvm/IR/Function.h"
3031
#include "llvm/IR/Module.h"
3132
#include "programl/graph/program_graph_builder.h"
@@ -74,6 +75,10 @@ class ProgramGraphBuilder : public programl::graph::ProgramGraphBuilder {
7475

7576
void Clear();
7677

78+
// Return the node representing a type. If no node already exists for this type, a new node is
79+
// created and added to the graph.
80+
Node* GetOrCreateType(const ::llvm::Type* type);
81+
7782
protected:
7883
[[nodiscard]] labm8::StatusOr<FunctionEntryExits> VisitFunction(
7984
const ::llvm::Function& function, const Function* functionMessage);
@@ -93,6 +98,14 @@ class ProgramGraphBuilder : public programl::graph::ProgramGraphBuilder {
9398
Node* AddLlvmVariable(const ::llvm::Argument* argument,
9499
const Function* function);
95100
Node* AddLlvmConstant(const ::llvm::Constant* constant);
101+
Node* AddLlvmType(const ::llvm::Type* type);
102+
103+
Node* AddLlvmType(const ::llvm::StructType* type);
104+
Node* AddLlvmType(const ::llvm::PointerType* type);
105+
// TODO: Node* AddLlvmType(const ::llvm::IntegerType* type);
106+
Node* AddLlvmType(const ::llvm::FunctionType* type);
107+
Node* AddLlvmType(const ::llvm::ArrayType* type);
108+
Node* AddLlvmType(const ::llvm::VectorType* type);
96109

97110
private:
98111
const ProgramGraphOptions options_;
@@ -110,6 +123,8 @@ class ProgramGraphBuilder : public programl::graph::ProgramGraphBuilder {
110123
// visited.
111124
absl::flat_hash_map<const ::llvm::Constant*, std::vector<PositionalNode>>
112125
constants_;
126+
// A map from an LLVM type to the node message that represents it.
127+
absl::flat_hash_map<const ::llvm::Type*, Node*> types_;
113128
};
114129

115130
} // namespace internal

0 commit comments

Comments
 (0)