1
2
3
4
5
6 #include <cmajor/cmsxi/Data.hpp>
7 #include <cmajor/cmsxi/Context.hpp>
8 #include <unordered_map>
9 #include <set>
10
11 namespace cmsxi {
12
13 GlobalVariable::GlobalVariable(Type* type_, const std::string& name_) : type(type_), name(name_), initializer(nullptr), linkOnce(false)
14 {
15 }
16
17 std::string GlobalVariable::Name(Context& context)
18 {
19 return name;
20 }
21
22 Type* GlobalVariable::GetType(Context& context)
23 {
24 return context.GetPtrType(type);
25 }
26
27 void GlobalVariable::Write(Context& context, CodeFormatter& formatter)
28 {
29 formatter.Write(type->Name());
30 if (linkOnce)
31 {
32 formatter.Write(" once");
33 }
34 formatter.Write(" ");
35 formatter.Write(name);
36 if (initializer)
37 {
38 formatter.Write(" = ");
39 if (initializer->IsAggregateValue() || initializer->IsStringValue())
40 {
41 formatter.Write(initializer->Name(context));
42 }
43 else
44 {
45 formatter.Write(initializer->GetType(context)->Name());
46 formatter.Write(" ");
47 formatter.Write(initializer->Name(context));
48 }
49 }
50 else
51 {
52 formatter.Write(";");
53 }
54 }
55
56 DataRepository::DataRepository() : globalVariableDefinitions(), globalVariableMap(), nextStringId(0)
57 {
58 }
59
60 GlobalVariable* DataRepository::GetOrInsertGlobal(const std::string& name, Type* type)
61 {
62 auto it = globalVariableMap.find(name);
63 if (it != globalVariableMap.cend())
64 {
65 return it->second;
66 }
67 GlobalVariable* globalVariable = new GlobalVariable(type, name);
68 globalVariableDefinitions.push_back(std::unique_ptr<GlobalVariable>(globalVariable));
69 globalVariableMap[name] = globalVariable;
70 return globalVariable;
71 }
72
73 GlobalVariable* DataRepository::CreateGlobalStringPtr(Context& context, const std::string& stringValue)
74 {
75 GlobalVariable* globalVariable = new GlobalVariable(context.GetByteType(), "string" + std::to_string(nextStringId++) + "_" + compileUnitId);
76 globalVariable->SetInitializer(context.GetStringValue(globalVariable->GetType(context), stringValue));
77 globalVariableDefinitions.push_back(std::unique_ptr<GlobalVariable>(globalVariable));
78 return globalVariable;
79 }
80
81 void Visit(std::std::vector<GlobalVariable*>&order, GlobalVariable*variable, std::std::unordered_set<GlobalVariable*>&visited, std::std::unordered_set<GlobalVariable*>&tempVisit,
82 const std::std::unordered_map<GlobalVariable*, std::std::set<GlobalVariable*>>&dependencies, Context&context)
83 {
84 if (tempVisit.find(variable) == tempVisit.end())
85 {
86 if (visited.find(variable) == visited.end())
87 {
88 tempVisit.insert(variable);
89 auto i = dependencies.find(variable);
90 if (i != dependencies.end())
91 {
92 const std::std::set<GlobalVariable*>&dependsOn=i->second;
93 for (GlobalVariable* var : dependsOn)
94 {
95 Visit(order, var, visited, tempVisit, dependencies, context);
96 }
97 tempVisit.erase(variable);
98 visited.insert(variable);
99 order.push_back(variable);
100 }
101 else
102 {
103 tempVisit.erase(variable);
104 visited.insert(variable);
105 order.push_back(variable);
106 }
107 }
108 }
109 else
110 {
111 throw std::runtime_error("circular type dependency '" + variable->Name(context) + "' detected");
112 }
113 }
114
115 std::std::vector<GlobalVariable*>CreateDataOrder(conststd::std::vector<std::std::unique_ptr<GlobalVariable>>&globalVariables, Context&context)
116 {
117 std::unordered_map<std::string, GlobalVariable*> nameMap;
118 std::unordered_map<GlobalVariable*, std::std::set<GlobalVariable*>>dependencies;
119 for (const std::std::unique_ptr<GlobalVariable>&globalVariable : globalVariables)
120 {
121 nameMap[globalVariable->Name(context)] = globalVariable.get();
122 }
123 for (const std::std::unique_ptr<GlobalVariable>&globalVariable : globalVariables)
124 {
125 ConstantValue* initializer = globalVariable->Initializer();
126 if (initializer)
127 {
128 initializer->AddDependencies(globalVariable.get(), nameMap, dependencies, context);
129 }
130 }
131 std::vector<GlobalVariable*> order;
132 std::unordered_set<GlobalVariable*> visited;
133 std::unordered_set<GlobalVariable*> tempVisit;
134 for (const std::std::unique_ptr<GlobalVariable>&globalVariable : globalVariables)
135 {
136 if (visited.find(globalVariable.get()) == visited.end())
137 {
138 Visit(order, globalVariable.get(), visited, tempVisit, dependencies, context);
139 }
140 }
141 return order;
142 }
143
144 void DataRepository::Write(Context& context, CodeFormatter& formatter)
145 {
146 if (globalVariableDefinitions.empty()) return;
147 formatter.WriteLine("data");
148 formatter.WriteLine("{");
149 formatter.IncIndent();
150 std::vector<GlobalVariable*> dataOrder = CreateDataOrder(globalVariableDefinitions, context);
151 for (const auto& globalVariable : dataOrder)
152 {
153 globalVariable->Write(context, formatter);
154 formatter.WriteLine();
155 }
156 formatter.DecIndent();
157 formatter.WriteLine("}");
158 formatter.WriteLine();
159 }
160
161 void DataRepository::SetCompileUnitId(const std::string& compileUnitId_)
162 {
163 compileUnitId = compileUnitId_;
164 }
165
166 }
167