1 using System;
  2 using System.Collections;
  3 using CodeFormatter = System.Text.CodeFormatter;
  4 
  5 namespace cmsx.intermediate
  6 {
  7     public const uint prologId = cast<uint>(-1);
  8     public const uint epilogId = cast<uint>(-2);
  9 
 10     public class Function
 11     {
 12         public nothrow Function(Context& context_FunctionType* type_const string& name_bool once_MDStructRef* md_) : 
 13             context(context_)type(type_)name(name_)addressDescriptors()frameLocations(context.regs)nextValueNumber(0)nextInstructionIndex(0)nextArgIndex(0)frameSizeOperand(null)
 14             prolog(*thisprologId)epilog(*thisepilogId)once(once_)md(md_)frameSize(0u)
 15         {
 16         }
 17         public BasicBlock* AddBasicBlock(uint id)
 18         {
 19             BasicBlock* bb = new BasicBlock(*thisid);
 20             basicBlocks.Add(UniquePtr<BasicBlock>(bb));
 21             return bb;
 22         }
 23         public Value* MakeIdValue(int lineNumberuint idType* type)
 24         {
 25             HashMap<uintIdValue*>.ConstIterator it = idValueMap.CFind(id);
 26             if (it != idValueMap.CEnd())
 27             {
 28                 IdValue* idValue = it->second;
 29                 if (idValue->type != type)
 30                 {
 31                     throw Exception("type " + type->Name() + " conflicts type " + idValue->type->Name() + " in earlier definition at line " + ToString(idValue->line) + 
 32                         " (" + context.compileUnit.fileName + ":" + ToString(lineNumber) + ")");
 33                 }
 34                 return idValue;
 35             }
 36             else
 37             {
 38                 IdValue* idValue = new IdValue(id);
 39                 idValue->type = type;
 40                 idValue->line = lineNumber;
 41                 values.Add(UniquePtr<Value>(idValue));
 42                 idValueMap[id] = idValue;
 43                 return idValue;
 44             }
 45         }
 46         public void MapInstructions()
 47         {
 48             uint nextIdNumber = 0u;
 49             for (const UniquePtr<BasicBlock>& bb : basicBlocks)
 50             {
 51                 bb->MapInstructions(nextIdNumber);
 52             }
 53         }
 54         public void MapInstruction(uint idInstruction* instruction)
 55         {
 56             HashMap<uintInstruction*>.ConstIterator it = instructionMap.CFind(id);
 57             if (it == instructionMap.CEnd())
 58             {
 59                 instructionMap[id] = instruction;
 60             }
 61             else
 62             {
 63                 throw Exception("instruction '" + instruction->OperationName() + "' id " + ToString(id) + " at line '" + ToString(instruction->line) + "' already mapped at line " + ToString(it->second->line));
 64             }
 65         }
 66         public void Validate()
 67         {
 68             for (const UniquePtr<BasicBlock>& bb : basicBlocks)
 69             {
 70                 bb->Validate();
 71             }
 72         }
 73         public Value* ResolveOperand(int lineValue* operand)
 74         {
 75             if (operand != null)
 76             {
 77                 IdValue* idValue = operand as IdValue*;
 78                 if (idValue != null)
 79                 {
 80                     uint id = idValue->id;
 81                     HashMap<uintInstruction*>.ConstIterator it = instructionMap.CFind(id);
 82                     if (it != instructionMap.CEnd())
 83                     {
 84                         Instruction* instruction = it->second;
 85                         if (idValue->type != instruction->type)
 86                         {
 87                             throw Exception("error : type conflict for operand '" + operand->Name() + "' at line " + ToString(operand->line) + " with " + instruction->OperationName() + 
 88                                 " instruction at line " + ToString(instruction->line));
 89                         }
 90                         return instruction;
 91                     }
 92                     else
 93                     {
 94                         throw Exception("error : id of operand '" + operand->Name() + "' at line " + ToString(operand->line) + "' is not found from instruction map");
 95                     }
 96                 }
 97                 else
 98                 {
 99                     return operand;
100                 }
101             }
102             else
103             {
104                 throw Exception("internal error : operand is null at line " + ToString(line));
105             }
106         }
107         public BasicBlock* GetBasicBlock(uint target)
108         {
109             if (target < basicBlocks.Count())
110             {
111                 return basicBlocks[target].Get();
112             }
113             else
114             {
115                 return null;
116             }
117         }
118         public void Print(CodeFormatter& formatterint stage)
119         {
120             nextInstructionIndex = 0;
121             nextValueNumber = 0;
122             string onceStr;
123             if (once)
124             {
125                 onceStr = " once";
126             }
127             formatter.WriteLine("function " + type->Name() + onceStr + " @" + name);
128             formatter.WriteLine("{");
129             formatter.IncIndent();
130             bool first = true;
131             for (const UniquePtr<BasicBlock>& basicBlock : basicBlocks)
132             {
133                 if (first)
134                 {
135                     first = false;
136                 }
137                 else
138                 {
139                     formatter.WriteLine();
140                 }
141                 basicBlock->Print(formatterstage);
142             }
143             formatter.DecIndent();
144             formatter.WriteLine("}");
145         }
146         public inline nothrow int GetNextInstructionIndex()
147         {
148             return nextInstructionIndex++;
149         }
150         public inline nothrow int GetNextValueNumber()
151         {
152             return nextValueNumber++;
153         }
154         public inline nothrow int GetNextArgIndex()
155         {
156             return nextArgIndex++;
157         }
158         public inline nothrow void ResetNextArgIndex()
159         {
160              nextArgIndex = 0;
161         }
162         public nothrow void ComputeLivenessAndNextUse()
163         {
164             for (const UniquePtr<BasicBlock>& bb : basicBlocks)
165             {
166                 bb->ComputeLivenessAndNextUse();
167             }
168         }
169         public void GenerateDeclaration(MachineCode& machineCode)
170         {
171             if (once )
172             {
173                 MachineInstruction* linkOnceInst = machineCode.GetInstruction(cmsx.assembly.LINKONCEnull);
174                 linkOnceInst->AddOperand(machineCode.context.GetSymbolOperand(name));
175             }
176             else
177             {
178                 MachineInstruction* externInst = machineCode.GetInstruction(cmsx.assembly.EXTERNnull);
179                 externInst->AddOperand(machineCode.context.GetSymbolOperand(name));
180             }
181         }
182         public void GenerateCode(MachineCode& machineCodeCodeFormatter& formatter)
183         {
184             try
185             {
186                 machineCode.currentLineNumber = 0u;
187                 nextInstructionIndex = 0;
188                 nextValueNumber = 0;
189                 if (!basicBlocks.IsEmpty())
190                 {
191                     epilog.SetId(basicBlocks.Back()->Id() + 1u);
192                 }
193                 else
194                 {
195                     epilog.SetId(1u);
196                 }
197                 CreateProlog(machineCode);
198                 if (name == "function_DurationStr_1840BD75820836C5ECA040E3577AB0AE6BD3B54F")
199                 {
200                     int x = 0;
201                 }
202                 if (Flags.Get(Flag.debug))
203                 {
204                     formatter.WriteLine("function @" + name);
205                     formatter.WriteLine("{");
206                     formatter.IncIndent();
207                 }
208                 for (const UniquePtr<BasicBlock>& basicBlock : basicBlocks)
209                 {
210                     basicBlock->GenerateCode(machineCodeformatter);
211                 }
212                 if (!basicBlocks.IsEmpty())
213                 {
214                     const UniquePtr<BasicBlock>& lastBasicBlock = basicBlocks.Back();
215                     Instruction* lastInst = lastBasicBlock->GetLastInstruction();
216                     if (lastInst != null && lastInst->lineNumber != 0u)
217                     {
218                         machineCode.EmitLineNumberInfo();
219                     }
220                 }
221                 if (Flags.Get(Flag.debug))
222                 {
223                     formatter.DecIndent();
224                     formatter.WriteLine("}");
225                 }
226                 CreateEpilog(machineCode);
227                 frameSize = cast<ulong>(frameLocations.paramOffset);
228                 frameSizeOperand->SetValue(frameSize);
229             }
230             catch (const Exception& ex)
231             {
232                 throw Exception("error compiling function '" + name + "': " + ex.Message());
233             }
234         }
235         private void CreateProlog(MachineCode& machineCode)
236         {
237             MachineInstruction* funcInst = machineCode.GetInstruction(cmsx.assembly.FUNCname);
238             MachineInstruction* stoInst = machineCode.GetInstruction(cmsx.machine.STOnull);
239             stoInst->AddOperand(context.regs.GetFP());
240             stoInst->AddOperand(context.regs.GetSP());
241             stoInst->AddOperand(context.GetLiteralOperand(0u));
242             MachineInstruction* setInst = machineCode.GetInstruction(cmsx.assembly.SETnull);
243             setInst->AddOperand(context.regs.GetFP());
244             setInst->AddOperand(context.regs.GetSP());
245             MachineInstruction* inclInst = machineCode.GetInstruction(cmsx.machine.INCLnull);
246             inclInst->AddOperand(context.regs.GetSP());
247             frameSizeOperand = context.CreateLiteralOperand();
248             inclInst->AddOperand(frameSizeOperand);
249             prolog.SetEmpty(false);
250         }
251         private void CreateEpilog(MachineCode& machineCode)
252         {
253             MachineInstruction* setInst = machineCode.GetInstruction(cmsx.assembly.SETepilog.Name());
254             setInst->AddOperand(context.regs.GetSP());
255             setInst->AddOperand(context.regs.GetFP());
256             MachineInstruction* loadFPInst = machineCode.GetInstruction(cmsx.machine.LDOnull);
257             loadFPInst->AddOperand(context.regs.GetFP());
258             loadFPInst->AddOperand(context.regs.GetSP());
259             loadFPInst->AddOperand(context.GetLiteralOperand(0u));
260             machineCode.GetInstruction(cmsx.machine.RETnull);
261             machineCode.GetInstruction(cmsx.assembly.ENDFname);
262             epilog.SetEmpty(false);
263         }
264         public void CombineBasicBlocks()
265         {
266             List<UniquePtr<BasicBlock>> newBasicBlocks;
267             long n = basicBlocks.Count();
268             for (long i = 0; i < n; ++i;)
269             {
270                 UniquePtr<BasicBlock>& bb = basicBlocks[i];
271                 if (i < n - 1)
272                 {
273                     if (!bb->IsEmpty())
274                     {
275                         UniquePtr<BasicBlock>& next = basicBlocks[i + 1];
276                         if (next->Predecessors().Count() == 1 && next->Predecessors().Front() == bb.Get())
277                         {
278                             Instruction* lastInst = bb->GetLastInstruction();
279                             if (lastInst is JumpInstruction*)
280                             {
281                                 JumpInstruction* jump = cast<JumpInstruction*>(lastInst);
282                                 if (jump->targetBlock == next.Get())
283                                 {
284                                     bb->Instructions().RemoveLast();
285                                     for (UniquePtr<Instruction>& inst : next->Instructions())
286                                     {
287                                         inst->parent = bb.Get();
288                                         bb->Instructions().Add(Rvalue(inst));
289                                     }
290                                     ++i;
291                                 }
292                             }
293                         }
294                     }
295                 }
296                 newBasicBlocks.Add(Rvalue(bb));
297             }
298             Swap(basicBlocksnewBasicBlocks);
299         }
300         public Context& context;
301         public FunctionType* type;
302         public string name;
303         public AddressDescriptors addressDescriptors;
304         public FrameLocations frameLocations;
305         public BasicBlock prolog;
306         public BasicBlock epilog;
307         public MDStructRef* md;
308         public ulong frameSize;
309         public List<ParamInstruction*> regParams;
310         public List<UniquePtr<BasicBlock>> basicBlocks;
311         private List<UniquePtr<Value>> values;
312         private HashMap<uintIdValue*> idValueMap;
313         private HashMap<uintInstruction*> instructionMap;
314         private int nextInstructionIndex;
315         private int nextValueNumber;
316         private int nextArgIndex;
317         private LiteralOperand* frameSizeOperand;
318         private bool once;
319     }
320 }