1 using System;
2 using System.Collections;
3 using System.IO;
4 using CodeFormatter = System.Text.CodeFormatter;
5
6 namespace cmsx.intermediate
7 {
8 public const int printMachineCodeStage = 9999;
9
10 public class CompileUnit
11 {
12 public nothrow CompileUnit(Context& context_) : context(context_)
13 {
14 }
15 public nothrow void SetFileName(const string& fileName_)
16 {
17 fileName = fileName_;
18 }
19 public void AddInfo(const string& id_, MDStructRef* mdRef_)
20 {
21 id = id_;
22 mdRef = mdRef_;
23 }
24 public Function* AddFunction(int lineNumber, Type* type, const string& name, bool once, MDStructRef* md)
25 {
26 if (type is FunctionType*)
27 {
28 Function* function = new Function(context, cast<FunctionType*>(type), name, once, md);
29 functions.Add(UniquePtr<Function>(function));
30 return function;
31 }
32 else
33 {
34 throw Exception("function type expected (" + fileName + ":" + ToString(lineNumber) + ")");
35 }
36 }
37 public void MapInstructions()
38 {
39 for (const UniquePtr<Function>& function : functions)
40 {
41 function->MapInstructions();
42 }
43 }
44 public void CombineBasicBlocks()
45 {
46 for (const UniquePtr<Function>& function : functions)
47 {
48 function->CombineBasicBlocks();
49 }
50 }
51 public void Validate()
52 {
53 for (const UniquePtr<Function>& function : functions)
54 {
55 try
56 {
57 function->Validate();
58 }
59 catch (const Exception& ex)
60 {
61 throw Exception("validation of function " + function->name + " in file '" + fileName + "' failed: " + ex.Message());
62 }
63 }
64 }
65 public void Print(int stage)
66 {
67 string filePath;
68 if (stage == printMachineCodeStage)
69 {
70 filePath = Path.ChangeExtension(fileName, ".is");
71 }
72 else
73 {
74 filePath = Path.ChangeExtension(fileName, ".i" + ToString(stage));
75 }
76 StreamWriter writer = File.CreateText(filePath);
77 CodeFormatter formatter(writer);
78 formatter.SetIndentSize(5);
79 context.PrintTypes(formatter);
80 if (!globalVariables.IsEmpty())
81 {
82 formatter.WriteLine();
83 formatter.WriteLine("data");
84 formatter.WriteLine("{");
85 formatter.IncIndent();
86 for (UniquePtr<GlobalVariable>& globalVariable : globalVariables)
87 {
88 globalVariable->Print(formatter);
89 formatter.WriteLine();
90 }
91 formatter.DecIndent();
92 formatter.WriteLine("}");
93 }
94 formatter.WriteLine();
95 bool first = true;
96 for (const UniquePtr<Function>& function : functions)
97 {
98 if (first)
99 {
100 first = false;
101 }
102 else
103 {
104 formatter.WriteLine();
105 }
106 function->Print(formatter, stage);
107 }
108 if (Flags.Get(Flag.verbose))
109 {
110 Console.Out() << "==> " << filePath << endl();
111 }
112 }
113 public nothrow void ComputeLivenessAndNextUse()
114 {
115 for (const UniquePtr<Function>& function : functions)
116 {
117 function->ComputeLivenessAndNextUse();
118 }
119 }
120 public GlobalVariable* GetGlobalVariableNothrow(const string& globalVariableName) const
121 {
122 HashMap<string, GlobalVariable*>.ConstIterator it = globalVariableMap.CFind(globalVariableName);
123 if (it != globalVariableMap.CEnd())
124 {
125 return it->second;
126 }
127 else
128 {
129 return null;
130 }
131 }
132 public GlobalVariable* GetGlobalVariable(const string& globalVariableName) const
133 {
134 GlobalVariable* globalVar = GetGlobalVariableNothrow(globalVariableName);
135 if (globalVar != null)
136 {
137 return globalVar;
138 }
139 else
140 {
141 throw Exception("global variable '" + globalVariableName + "' not found");
142 }
143 }
144 public void AddGlobalVariable(Type* type, const string& name, ConstantValue* initializer, int line, bool once)
145 {
146 Location* dataLocation = dataLocations.GetDataLocation(context.GetSymbolOperand(name));
147 GlobalVariable* globalVariable = new GlobalVariable(type, name, initializer, line, dataLocation, once);
148 globalVariables.Add(UniquePtr<GlobalVariable>(globalVariable));
149 globalVariableMap[name] = globalVariable;
150 }
151 public void ValidateGlobalVariables()
152 {
153 for (const UniquePtr<GlobalVariable>& globalVariable : globalVariables)
154 {
155 globalVariable->Validate();
156 }
157 }
158 public void GenerateCode(MachineCode& machineCode)
159 {
160 StreamWriter* writer = &Console.Out();
161 UniquePtr<StreamWriter> debugWriter;
162 if (Flags.Get(Flag.debug))
163 {
164 string filePath = Path.ChangeExtension(fileName, ".id");
165 debugWriter.Reset(new StreamWriter(File.CreateText(filePath)));
166 writer = debugWriter.Get();
167 }
168 CodeFormatter formatter(*writer);
169 for (const UniquePtr<GlobalVariable>& globalVariable : globalVariables)
170 {
171 globalVariable->GenerateDeclaration(machineCode);
172 }
173 for (const UniquePtr<Function>& function : functions)
174 {
175 function->GenerateDeclaration(machineCode);
176 }
177 if (!globalVariables.IsEmpty())
178 {
179 machineCode.GetInstruction(separatorInstructionOpCode, null);
180 machineCode.GetInstruction(cmsx.assembly.DATA, null);
181 machineCode.GetInstruction(separatorInstructionOpCode, null);
182 for (const UniquePtr<GlobalVariable>& globalVariable : globalVariables)
183 {
184 globalVariable->GenerateDefinition(machineCode, context);
185 }
186 machineCode.GetInstruction(separatorInstructionOpCode, null);
187 machineCode.GetInstruction(cmsx.assembly.CODE, null);
188 }
189 List<Function*> debugInfoFuncs;
190 for (const UniquePtr<Function>& function : functions)
191 {
192 machineCode.GetInstruction(separatorInstructionOpCode, null);
193 function->GenerateCode(machineCode, formatter);
194 if (function->md != null)
195 {
196 debugInfoFuncs.Add(function.Get());
197 }
198 }
199 machineCode.GetInstruction(separatorInstructionOpCode, null);
200 machineCode.GetInstruction(cmsx.assembly.DEBUG, null);
201 machineCode.GetInstruction(separatorInstructionOpCode, null);
202 MDStruct* compileUnitStruct = metadata.GetMDStruct(mdRef->id);
203 MDItem* sourceFileNameItem = compileUnitStruct->GetItem("sourceFileName");
204 HashMap<string, int> sourceFileNameMap;
205 string sourceFileName;
206 if (sourceFileNameItem is MDString*)
207 {
208 sourceFileName = cast<MDString*>(sourceFileNameItem)->value;
209 sourceFileNameMap[sourceFileName] = mdRef->id;
210 }
211 else
212 {
213 throw Exception("metadata string expected");
214 }
215 for (Function* debugInfoFunc : debugInfoFuncs)
216 {
217 MDStructRef* md = debugInfoFunc->md;
218 MDStruct* mdStruct = metadata.GetMDStruct(md->id);
219 MDItem* sourceFileItem = mdStruct->GetItem("sourceFile");
220 if (sourceFileItem is MDStructRef*)
221 {
222 MDStructRef* mdRef = cast<MDStructRef*>(sourceFileItem);
223 MDStruct* sourceFileStruct = metadata.GetMDStruct(mdRef->id);
224 MDItem* sourceFileNameItem = sourceFileStruct->GetItem("sourceFileName");
225 if (sourceFileNameItem is MDString*)
226 {
227 sourceFileName = cast<MDString*>(sourceFileNameItem)->value;
228 sourceFileNameMap[sourceFileName] = mdRef->id;
229 }
230 else
231 {
232 throw Exception("metadata string expected");
233 }
234 }
235 else
236 {
237 throw Exception("metadata ref expected");
238 }
239 }
240 for (const Pair<string, int>& sourceFile : sourceFileNameMap)
241 {
242 const string& sourceFileName = sourceFile.first;
243 int sourceFileNameId = sourceFile.second;
244 MachineInstruction* bspecInst = machineCode.GetInstruction(cmsx.assembly.BSPEC, null);
245 MachineInstruction* octaInst = machineCode.GetInstruction(cmsx.assembly.OCTA, null);
246 octaInst->AddOperand(context.GetLiteralOperand(cmsx.assembly.FILEINFO));
247 octaInst->AddOperand(context.GetStringOperand(sourceFileName));
248 octaInst->AddOperand(context.GetLiteralOperand(cast<ulong>(sourceFileNameId)));
249 MachineInstruction* especInst = machineCode.GetInstruction(cmsx.assembly.ESPEC, null);
250 }
251 if (!debugInfoFuncs.IsEmpty())
252 {
253 for (Function* debugInfoFunc : debugInfoFuncs)
254 {
255 MDStructRef* md = debugInfoFunc->md;
256 MDStruct* mdStruct = metadata.GetMDStruct(md->id);
257 MDItem* fullNameItem = mdStruct->GetItem("fullName");
258 string functionFullName;
259 if (fullNameItem is MDString*)
260 {
261 functionFullName = cast<MDString*>(fullNameItem)->value;
262 }
263 else
264 {
265 throw Exception("metadata string expected");
266 }
267 MDItem* sourceFileItem = mdStruct->GetItem("sourceFile");
268 int sourceFileNameId = 0;
269 if (sourceFileItem is MDStructRef*)
270 {
271 sourceFileNameId = cast<MDStructRef*>(sourceFileItem)->id;
272 }
273 else
274 {
275 throw Exception("metadata ref expected");
276 }
277 MachineInstruction* bspecInst = machineCode.GetInstruction(cmsx.assembly.BSPEC, null);
278 MachineInstruction* octaInst = machineCode.GetInstruction(cmsx.assembly.OCTA, null);
279 octaInst->AddOperand(context.GetLiteralOperand(cmsx.assembly.FUNCINFO));
280 octaInst->AddOperand(context.GetSymbolOperand(debugInfoFunc->name));
281 octaInst->AddOperand(context.GetStringOperand(functionFullName));
282 octaInst->AddOperand(context.GetLiteralOperand(cast<ulong>(sourceFileNameId)));
283 octaInst->AddOperand(context.GetLiteralOperand(debugInfoFunc->frameSize));
284 MachineInstruction* especInst = machineCode.GetInstruction(cmsx.assembly.ESPEC, null);
285 }
286 }
287 }
288 public Context& context;
289 public string fileName;
290 public Metadata metadata;
291 private List<UniquePtr<GlobalVariable>> globalVariables;
292 private HashMap<string, GlobalVariable*> globalVariableMap;
293 private List<UniquePtr<Function>> functions;
294 private DataLocations dataLocations;
295 private string id;
296 private MDStructRef* mdRef;
297 }
298 }