chigraph  master
Systems programming language written for beginners in LLVM
GraphStruct.cpp
Go to the documentation of this file.
1 
3 #include "chi/GraphStruct.hpp"
4 #include "chi/Context.hpp"
5 #include "chi/GraphModule.hpp"
6 #include "chi/LLVMVersion.hpp"
7 #include "chi/NodeInstance.hpp"
8 #include "chi/NodeType.hpp"
9 #include "chi/Support/Result.hpp"
10 
11 #include <llvm/IR/DIBuilder.h>
12 #include <llvm/IR/DebugInfo.h>
13 #include <llvm/IR/DerivedTypes.h>
14 
15 #if LLVM_VERSION_LESS_EQUAL(3, 6)
16 #include <llvm/IR/Module.h>
17 #endif
18 
19 namespace chi {
20 
21 GraphStruct::GraphStruct(GraphModule& mod, std::string name)
22  : mModule{&mod}, mContext{&mod.context()}, mName{std::move(name)} {}
23 
24 std::vector<NodeInstance*> GraphStruct::setName(std::string newName, bool updateReferences) {
25  assert(!newName.empty() && "Cannot pass an empty name to GraphStruct::setName");
26 
28 
29  auto oldName = name();
30  mName = std::move(newName);
31 
32  // find references to update
33  if (updateReferences) {
34  auto makeInstances =
35  context().findInstancesOfType(module().fullNamePath(), "_make_" + oldName);
36 
37  for (auto makeInst : makeInstances) {
38  std::unique_ptr<NodeType> type;
39  auto res = module().nodeTypeFromName("_make_" + name(), {}, &type);
40 
41  if (!res) { return {}; }
42 
43  makeInst->setType(std::move(type));
44  }
45 
46  auto breakInstances =
47  context().findInstancesOfType(module().fullNamePath(), "_break_" + oldName);
48 
49  for (auto breakInst : breakInstances) {
50  std::unique_ptr<NodeType> type;
51  auto res = module().nodeTypeFromName("_break_" + name(), {}, &type);
52 
53  if (!res) { return {}; }
54 
55  breakInst->setType(std::move(type));
56  }
57 
58  // append breakInstances to makeInstances so wer can return the updated nodes
59  makeInstances.reserve(breakInstances.size() + makeInstances.size());
60  std::copy(breakInstances.begin(), breakInstances.end(), std::back_inserter(makeInstances));
61 
62  return makeInstances;
63  }
64 
65  return {};
66 }
67 
68 void GraphStruct::addType(DataType ty, std::string name, size_t addBefore, bool updateReferences) {
69  assert(addBefore <= types().size() && ty.valid());
70 
71  // invalidate the cache
73 
74  mTypes.emplace_back(name, ty);
75 
76  // invalidate the current DataType
77  mDataType = {};
78 
79  if (updateReferences) { updateNodeReferences(); }
80 }
81 
82 void GraphStruct::modifyType(size_t id, DataType newTy, std::string newName,
83  bool updateReferences) {
84  assert(id < types().size() && newTy.valid() && !newName.empty());
85 
86  // invalidate the cache
88 
89  mTypes[id] = {std::move(newName), std::move(newTy)};
90 
91  // invalidate the current DataType
92  mDataType = {};
93 
94  if (updateReferences) { updateNodeReferences(); }
95 }
96 
97 void GraphStruct::removeType(size_t id, bool updateReferences) {
98  assert(id < types().size());
99 
100  // invalidate the cache
102 
103  mTypes.erase(mTypes.begin() + id);
104 
105  // invalidate the current DataType
106  mDataType = {};
107 
108  if (updateReferences) { updateNodeReferences(); }
109 }
110 
112  // if we have already calculated this, use that
113  if (mDataType.valid()) { return mDataType; }
114 
115  if (types().empty()) { return {}; }
116 
117  // create llvm::Type
118  std::vector<llvm::Type*> llTypes;
119  llTypes.reserve(types().size());
120 
121  std::vector<
122 #if LLVM_VERSION_LESS_EQUAL(3, 5)
123  llvm::Value*
124 #else
125  llvm::Metadata*
126 #endif
127  >
128  diTypes;
129  diTypes.reserve(types().size());
130 
131  size_t currentOffset = 0;
132 
133 #if LLVM_VERSION_LESS_EQUAL(3, 6)
134  // make a temp module so we can make a DIBuilder
135  auto tmpMod = std::make_unique<llvm::Module>("tmp", context().llvmContext());
136  auto diBuilder = std::make_unique<llvm::DIBuilder>(*tmpMod);
137 #endif
138 
139  for (const auto& type : types()) {
140  auto debugType = type.type.debugType();
141 
142  llTypes.push_back(type.type.llvmType());
143 
144  auto member =
145 #if LLVM_VERSION_LESS_EQUAL(3, 6)
146  diBuilder->createMemberType(llvm::DIDescriptor(), type.name, llvm::DIFile(), 0,
147  debugType->getSizeInBits(), 8, currentOffset, 0, *debugType)
148 #else
149  llvm::DIDerivedType::get(context().llvmContext(), llvm::dwarf::DW_TAG_member,
150 #if LLVM_VERSION_LESS_EQUAL(3, 8)
151  llvm::MDString::get(context().llvmContext(), type.name),
152 #else
153  type.name,
154 #endif
155  nullptr, 0, nullptr, debugType, debugType->getSizeInBits(), 8,
156  currentOffset,
157 #if LLVM_VERSION_AT_LEAST(5, 0)
158  llvm::None,
159 #endif
160  llvm::DINode::DIFlags{}, nullptr)
161 #endif
162  ;
163 
164  diTypes.push_back(member);
165 
166  currentOffset += debugType->getSizeInBits();
167  }
168  auto llType = llvm::StructType::create(llTypes, name());
169 
170  auto diStructType =
171 #if LLVM_VERSION_LESS_EQUAL(3, 6)
172  new llvm::DICompositeType(diBuilder->createStructType(
173  llvm::DIDescriptor(), name(), llvm::DIFile(), 0, currentOffset, 8, 0, llvm::DIType(),
174  diBuilder->getOrCreateArray(
175  diTypes))); // TODO (#77): yeah this is a memory leak. Fix it.
176 #else
177  llvm::DICompositeType::get(
178  context().llvmContext(), llvm::dwarf::DW_TAG_structure_type, name(), nullptr, 0,
179  nullptr, nullptr, currentOffset, 8, 0, llvm::DINode::DIFlags{},
180  llvm::MDTuple::get(context().llvmContext(), diTypes), 0, nullptr, {}, "")
181 #endif
182  ;
183 
184  mDataType = DataType(&module(), name(), llType, diStructType);
185 
186  return mDataType;
187 }
188 
189 void GraphStruct::updateNodeReferences() {
190  auto makeInstances = context().findInstancesOfType(module().fullNamePath(), "_make_" + name());
191 
192  for (auto inst : makeInstances) {
193  // make a make type
194  std::unique_ptr<NodeType> ty;
195  auto res = module().nodeTypeFromName("_make_" + name(), {}, &ty);
196  if (!res) { return; }
197 
198  inst->setType(std::move(ty));
199  }
200 
201  auto breakInstances =
202  context().findInstancesOfType(module().fullNamePath(), "_break_" + name());
203  for (auto inst : breakInstances) {
204  // make a break type
205  std::unique_ptr<NodeType> ty;
206  auto res = module().nodeTypeFromName("_break_" + name(), {}, &ty);
207  if (!res) { return; }
208 
209  inst->setType(std::move(ty));
210  }
211 }
212 
213 } // namespace chi
std::vector< NodeInstance * > setName(std::string newName, bool updateReferences=true)
Set the name of the struct, and optionally update all references in the context.
Definition: GraphStruct.cpp:24
const std::string & name() const
Get the name of the type.
Definition: GraphStruct.hpp:43
void modifyType(size_t id, DataType newTy, std::string newName, bool updateReferences=true)
Change the type and name of a type.
Definition: GraphStruct.cpp:82
Defines the Result class and related functions.
GraphModule & module() const
Get the module.
Definition: GraphStruct.hpp:30
std::vector< NodeInstance * > findInstancesOfType(const boost::filesystem::path &moduleName, boost::string_view typeName) const
Find all uses of a node type in all the loaded modules.
Definition: Context.cpp:444
GraphStruct(GraphModule &mod, std::string name)
GraphType constructor; don&#39;t use this use GraphModule::newStruct.
Definition: GraphStruct.cpp:21
Define GraphStruct.
Context & context() const
Get the context.
Definition: GraphStruct.hpp:26
DataType dataType()
Get the DataType of the struct.
Defines the NodeType class.
llvm::LLVMContext & llvmContext()
Get the LLVMContext
Definition: Context.hpp:173
void removeType(size_t id, bool updateReferences=true)
Remove a type from a struct.
Definition: GraphStruct.cpp:97
const std::vector< NamedDataType > & types() const
Get the types the struct contains.
Definition: GraphStruct.hpp:47
void updateLastEditTime(std::time_t newLastEditTime=std::time(nullptr))
Update the last edit time, signifying that it&#39;s been edited.
Definition: ChiModule.hpp:105
Result nodeTypeFromName(boost::string_view name, const nlohmann::json &jsonData, std::unique_ptr< NodeType > *toFill) override
Create a node type that is in the module from the name and json.
bool valid() const
Check if the DataType is valid (if it&#39;s actually bound to a type and module)
Definition: DataType.hpp:44
void addType(DataType ty, std::string name, size_t addBefore, bool updateReferences=true)
Add a new type to the struct.
Definition: GraphStruct.cpp:68
Module that holds graph functions.
Definition: GraphModule.hpp:16
Defines the GraphModule class.
The namespace where chigraph lives.
Defines the Context class and related functions.
A type of data Loose wrapper around llvm::Type*, except it knows which ChiModule it&#39;s in and it embed...
Definition: DataType.hpp:17
Defines the NodeInstance class and related functions.