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 lineNumberType* typeconst string& namebool onceMDStructRef* md)
 25         {
 26             if (type is FunctionType*)
 27             {
 28                 Function* function = new Function(contextcast<FunctionType*>(type)nameoncemd);
 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(formatterstage);
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<stringGlobalVariable*>.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* typeconst string& nameConstantValue* initializerint linebool once)
145         {
146             Location* dataLocation = dataLocations.GetDataLocation(context.GetSymbolOperand(name));
147             GlobalVariable* globalVariable = new GlobalVariable(typenameinitializerlinedataLocationonce);
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(separatorInstructionOpCodenull);
180                 machineCode.GetInstruction(cmsx.assembly.DATAnull);
181                 machineCode.GetInstruction(separatorInstructionOpCodenull);
182                 for (const UniquePtr<GlobalVariable>& globalVariable : globalVariables)
183                 {
184                     globalVariable->GenerateDefinition(machineCodecontext);
185                 }
186                 machineCode.GetInstruction(separatorInstructionOpCodenull);
187                 machineCode.GetInstruction(cmsx.assembly.CODEnull);
188             }
189             List<Function*> debugInfoFuncs;
190             for (const UniquePtr<Function>& function : functions)
191             {
192                 machineCode.GetInstruction(separatorInstructionOpCodenull);
193                 function->GenerateCode(machineCodeformatter);
194                 if (function->md != null)
195                 {
196                     debugInfoFuncs.Add(function.Get());
197                 }
198             }
199             machineCode.GetInstruction(separatorInstructionOpCodenull);
200             machineCode.GetInstruction(cmsx.assembly.DEBUGnull);
201             machineCode.GetInstruction(separatorInstructionOpCodenull);
202             MDStruct* compileUnitStruct = metadata.GetMDStruct(mdRef->id);
203             MDItem* sourceFileNameItem = compileUnitStruct->GetItem("sourceFileName");
204             HashMap<stringint> 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<stringint>& sourceFile : sourceFileNameMap)
241             {
242                 const string& sourceFileName = sourceFile.first;
243                 int sourceFileNameId = sourceFile.second;
244                 MachineInstruction* bspecInst = machineCode.GetInstruction(cmsx.assembly.BSPECnull);
245                 MachineInstruction* octaInst = machineCode.GetInstruction(cmsx.assembly.OCTAnull);
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.ESPECnull);
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.BSPECnull);
278                     MachineInstruction* octaInst = machineCode.GetInstruction(cmsx.assembly.OCTAnull);
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.ESPECnull);
285                 }
286             }
287         }
288         public Context& context;
289         public string fileName;
290         public Metadata metadata;
291         private List<UniquePtr<GlobalVariable>> globalVariables;
292         private HashMap<stringGlobalVariable*> globalVariableMap;
293         private List<UniquePtr<Function>> functions;
294         private DataLocations dataLocations;
295         private string id;
296         private MDStructRef* mdRef;
297     }
298 }