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(*this, prologId), epilog(*this, epilogId), once(once_), md(md_), frameSize(0u)
15 {
16 }
17 public BasicBlock* AddBasicBlock(uint id)
18 {
19 BasicBlock* bb = new BasicBlock(*this, id);
20 basicBlocks.Add(UniquePtr<BasicBlock>(bb));
21 return bb;
22 }
23 public Value* MakeIdValue(int lineNumber, uint id, Type* type)
24 {
25 HashMap<uint, IdValue*>.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 id, Instruction* instruction)
55 {
56 HashMap<uint, Instruction*>.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 line, Value* 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<uint, Instruction*>.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& formatter, int 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(formatter, stage);
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.LINKONCE, null);
174 linkOnceInst->AddOperand(machineCode.context.GetSymbolOperand(name));
175 }
176 else
177 {
178 MachineInstruction* externInst = machineCode.GetInstruction(cmsx.assembly.EXTERN, null);
179 externInst->AddOperand(machineCode.context.GetSymbolOperand(name));
180 }
181 }
182 public void GenerateCode(MachineCode& machineCode, CodeFormatter& 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(machineCode, formatter);
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.FUNC, name);
238 MachineInstruction* stoInst = machineCode.GetInstruction(cmsx.machine.STO, null);
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.SET, null);
243 setInst->AddOperand(context.regs.GetFP());
244 setInst->AddOperand(context.regs.GetSP());
245 MachineInstruction* inclInst = machineCode.GetInstruction(cmsx.machine.INCL, null);
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.SET, epilog.Name());
254 setInst->AddOperand(context.regs.GetSP());
255 setInst->AddOperand(context.regs.GetFP());
256 MachineInstruction* loadFPInst = machineCode.GetInstruction(cmsx.machine.LDO, null);
257 loadFPInst->AddOperand(context.regs.GetFP());
258 loadFPInst->AddOperand(context.regs.GetSP());
259 loadFPInst->AddOperand(context.GetLiteralOperand(0u));
260 machineCode.GetInstruction(cmsx.machine.RET, null);
261 machineCode.GetInstruction(cmsx.assembly.ENDF, name);
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(basicBlocks, newBasicBlocks);
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<uint, IdValue*> idValueMap;
313 private HashMap<uint, Instruction*> instructionMap;
314 private int nextInstructionIndex;
315 private int nextValueNumber;
316 private int nextArgIndex;
317 private LiteralOperand* frameSizeOperand;
318 private bool once;
319 }
320 }