1
2
3
4
5
6 #include <cmajor/codegenwin/WindowsCodeGenerator.hpp>
7 #include <cmajor/binder/BoundStatement.hpp>
8 #include <cmajor/binder/BoundFunction.hpp>
9 #include <cmajor/symbols/Exception.hpp>
10
11 namespace cmajor { namespace codegenwin {
12
13 using namespace cmajor::binder;
14
15 WindowsCodeGenerator::WindowsCodeGenerator(cmajor::ir::EmittingContext& emittingContext_) : LlvmCodeGenerator(emittingContext_)
16 {
17 }
18
19 void WindowsCodeGenerator::Visit(BoundReturnStatement& boundReturnStatement)
20 {
21 emitter->SetCurrentDebugLocation(boundReturnStatement.GetSpan());
22 destructorCallGenerated = false;
23 lastInstructionWasRet = false;
24 basicBlockOpen = false;
25 SetTarget(&boundReturnStatement);
26 Pad* prevCurrentPad = currentPad;
27 while (currentPad != nullptr)
28 {
29 void* returnTarget = emitter->CreateBasicBlock("return");
30 emitter->CreateCatchRet(currentPad->value, returnTarget);
31 emitter->SetCurrentBasicBlock(returnTarget);
32 currentPad = currentPad->parent;
33 }
34 BoundFunctionCall* returnFunctionCall = boundReturnStatement.ReturnFunctionCall();
35 if (returnFunctionCall)
36 {
37 returnFunctionCall->Accept(*this);
38 void* returnValue = emitter->Stack().Pop();
39 if (sequenceSecond)
40 {
41 sequenceSecond->SetGenerated();
42 sequenceSecond->Accept(*this);
43 }
44 ExitBlocks(nullptr);
45 GenerateExitFunctionCode(*currentFunction);
46 emitter->CreateRet(returnValue);
47 lastInstructionWasRet = true;
48 }
49 else
50 {
51 ExitBlocks(nullptr);
52 GenerateExitFunctionCode(*currentFunction);
53 emitter->CreateRetVoid();
54 lastInstructionWasRet = true;
55 }
56 BoundCompoundStatement* body = currentFunction->Body();
57 BoundStatement* lastStatement = nullptr;
58 if (!body->Statements().empty())
59 {
60 lastStatement = body->Statements().back().get();
61 }
62 if (lastStatement && lastStatement != &boundReturnStatement)
63 {
64 void* nextBlock = emitter->CreateBasicBlock("next");
65 emitter->SetCurrentBasicBlock(nextBlock);
66 basicBlockOpen = true;
67 lastInstructionWasRet = false;
68 }
69 currentPad = prevCurrentPad;
70 }
71
72 void WindowsCodeGenerator::Visit(BoundGotoCaseStatement& boundGotoCaseStatement)
73 {
74 emitter->SetCurrentDebugLocation(boundGotoCaseStatement.GetSpan());
75 destructorCallGenerated = false;
76 lastInstructionWasRet = false;
77 basicBlockOpen = false;
78 SetTarget(&boundGotoCaseStatement);
79 Assert(breakTargetBlock, "break target not set");
80 Pad* prevCurrentPad = currentPad;
81 BoundStatement* parent = currentBlock;
82 while (currentPad != nullptr && parent && parent != breakTargetBlock)
83 {
84 if (parent->GetBoundNodeType() == BoundNodeType::boundTryStatement)
85 {
86 void* fromCatchTarget = emitter->CreateBasicBlock("fromCatch");
87 emitter->CreateCatchRet(currentPad->value, fromCatchTarget);
88 emitter->SetCurrentBasicBlock(fromCatchTarget);
89 currentPad = currentPad->parent;
90 }
91 parent = parent->Parent();
92 }
93 ExitBlocks(breakTargetBlock);
94 IntegralValue integralCaseValue(boundGotoCaseStatement.CaseValue());
95 auto it = currentCaseMap->find(integralCaseValue);
96 if (it != currentCaseMap->cend())
97 {
98 void* caseDest = it->second;
99 emitter->CreateBr(caseDest);
100 }
101 else
102 {
103 throw Exception("case not found", boundGotoCaseStatement.GetSpan(), boundGotoCaseStatement.ModuleId());
104 }
105 currentPad = prevCurrentPad;
106 }
107
108 void WindowsCodeGenerator::Visit(BoundGotoDefaultStatement& boundGotoDefaultStatement)
109 {
110 emitter->SetCurrentDebugLocation(boundGotoDefaultStatement.GetSpan());
111 destructorCallGenerated = false;
112 lastInstructionWasRet = false;
113 basicBlockOpen = false;
114 SetTarget(&boundGotoDefaultStatement);
115 Assert(breakTargetBlock, "break target not set");
116 Pad* prevCurrentPad = currentPad;
117 BoundStatement* parent = currentBlock;
118 while (currentPad != nullptr && parent && parent != breakTargetBlock)
119 {
120 if (parent->GetBoundNodeType() == BoundNodeType::boundTryStatement)
121 {
122 void* fromCatchTarget = emitter->CreateBasicBlock("fromCatch");
123 emitter->CreateCatchRet(currentPad->value, fromCatchTarget);
124 emitter->SetCurrentBasicBlock(fromCatchTarget);
125 currentPad = currentPad->parent;
126 }
127 parent = parent->Parent();
128 }
129 ExitBlocks(breakTargetBlock);
130 if (defaultDest)
131 {
132 emitter->CreateBr(defaultDest);
133 }
134 else
135 {
136 throw Exception("no default destination", boundGotoDefaultStatement.GetSpan(), boundGotoDefaultStatement.ModuleId());
137 }
138 currentPad = prevCurrentPad;
139 }
140
141 void WindowsCodeGenerator::Visit(BoundBreakStatement& boundBreakStatement)
142 {
143 emitter->SetCurrentDebugLocation(boundBreakStatement.GetSpan());
144 destructorCallGenerated = false;
145 lastInstructionWasRet = false;
146 basicBlockOpen = false;
147 SetTarget(&boundBreakStatement);
148 Assert(breakTarget && breakTargetBlock, "break target not set");
149 Pad* prevCurrentPad = currentPad;
150 BoundStatement* parent = currentBlock;
151 while (currentPad != nullptr && parent && parent != breakTargetBlock)
152 {
153 if (parent->GetBoundNodeType() == BoundNodeType::boundTryStatement)
154 {
155 void* fromCatchTarget = emitter->CreateBasicBlock("fromCatch");
156 emitter->CreateCatchRet(currentPad->value, fromCatchTarget);
157 emitter->SetCurrentBasicBlock(fromCatchTarget);
158 currentPad = currentPad->parent;
159 }
160 parent = parent->Parent();
161 }
162 ExitBlocks(breakTargetBlock);
163 emitter->CreateBr(breakTarget);
164 void* nextBlock = emitter->CreateBasicBlock("next");
165 emitter->SetCurrentBasicBlock(nextBlock);
166 basicBlockOpen = true;
167 currentPad = prevCurrentPad;
168 }
169
170 void WindowsCodeGenerator::Visit(BoundContinueStatement& boundContinueStatement)
171 {
172 emitter->SetCurrentDebugLocation(boundContinueStatement.GetSpan());
173 destructorCallGenerated = false;
174 lastInstructionWasRet = false;
175 basicBlockOpen = false;
176 SetTarget(&boundContinueStatement);
177 Assert(continueTarget && continueTargetBlock, "continue target not set");
178 Pad* prevCurrentPad = currentPad;
179 BoundStatement* parent = currentBlock;
180 while (currentPad != nullptr && parent && parent != continueTargetBlock)
181 {
182 if (parent->GetBoundNodeType() == BoundNodeType::boundTryStatement)
183 {
184 void* fromCatchTarget = emitter->CreateBasicBlock("fromCatch");
185 emitter->CreateCatchRet(currentPad->value, fromCatchTarget);
186 emitter->SetCurrentBasicBlock(fromCatchTarget);
187 currentPad = currentPad->parent;
188 }
189 parent = parent->Parent();
190 }
191 ExitBlocks(continueTargetBlock);
192 emitter->CreateBr(continueTarget);
193 void* nextBlock = emitter->CreateBasicBlock("next");
194 emitter->SetCurrentBasicBlock(nextBlock);
195 basicBlockOpen = true;
196 currentPad = prevCurrentPad;
197 }
198
199 void WindowsCodeGenerator::Visit(BoundGotoStatement& boundGotoStatement)
200 {
201 emitter->SetCurrentDebugLocation(boundGotoStatement.GetSpan());
202 destructorCallGenerated = false;
203 lastInstructionWasRet = false;
204 basicBlockOpen = false;
205 SetTarget(&boundGotoStatement);
206 Pad* prevCurrentPad = currentPad;
207 BoundStatement* parent = currentBlock;
208 while (currentPad != nullptr && parent && parent != boundGotoStatement.TargetBlock())
209 {
210 if (parent->GetBoundNodeType() == BoundNodeType::boundTryStatement)
211 {
212 void* fromCatchTarget = emitter->CreateBasicBlock("fromCatch");
213 emitter->CreateCatchRet(currentPad->value, fromCatchTarget);
214 emitter->SetCurrentBasicBlock(fromCatchTarget);
215 currentPad = currentPad->parent;
216 }
217 parent = parent->Parent();
218 }
219 ExitBlocks(boundGotoStatement.TargetBlock());
220 auto it = labeledStatementMap.find(boundGotoStatement.TargetStatement());
221 if (it != labeledStatementMap.cend())
222 {
223 void* target = it->second;
224 emitter->CreateBr(target);
225 }
226 else
227 {
228 throw Exception("goto target not found", boundGotoStatement.GetSpan(), boundGotoStatement.ModuleId());
229 }
230 void* nextBlock = emitter->CreateBasicBlock("next");
231 emitter->SetCurrentBasicBlock(nextBlock);
232 basicBlockOpen = true;
233 currentPad = prevCurrentPad;
234 }
235
236 void WindowsCodeGenerator::Visit(BoundTryStatement& boundTryStatement)
237 {
238 ClearFlags();
239 SetTarget(&boundTryStatement);
240 void* prevHandlerBlock = handlerBlock;
241 void* prevCleanupBlock = cleanupBlock;
242 handlerBlock = emitter->CreateBasicBlock("handlers");
243 cleanupBlock = nullptr;
244 boundTryStatement.TryBlock()->Accept(*this);
245 void* nextTarget = emitter->CreateBasicBlock("next");
246 emitter->CreateBr(nextTarget);
247 emitter->SetCurrentBasicBlock(handlerBlock);
248 handlerBlock = prevHandlerBlock;
249 Pad* parentPad = currentPad;
250 void* catchSwitch = nullptr;
251 if (parentPad == nullptr)
252 {
253 catchSwitch = emitter->CreateCatchSwitch(prevHandlerBlock);
254 }
255 else
256 {
257 catchSwitch = emitter->CreateCatchSwitchWithParent(parentPad->value, prevHandlerBlock);
258 }
259 Pad* pad = new Pad();
260 pads.push_back(std::unique_ptr<Pad>(pad));
261 pad->parent = parentPad;
262 pad->value = catchSwitch;
263 currentPad = pad;
264 void* catchPadTarget = emitter->CreateBasicBlock("catchpad");
265 emitter->AddHandlerToCatchSwitch(catchSwitch, catchPadTarget);
266 emitter->SetCurrentBasicBlock(catchPadTarget);
267 std::vector<void*> catchPadArgs;
268 catchPadArgs.push_back(emitter->CreateDefaultIrValueForVoidPtrType());
269 catchPadArgs.push_back(emitter->CreateIrValueForInt(64));
270 catchPadArgs.push_back(emitter->CreateDefaultIrValueForVoidPtrType());
271 void* catchPad = emitter->CreateCatchPad(currentPad->value, catchPadArgs);
272 currentPad->value = catchPad;
273 void* catchTarget = emitter->CreateBasicBlock("catch");
274 void* resumeTarget = emitter->CreateBasicBlock("resume");
275 emitter->CreateBr(catchTarget);
276 int n = boundTryStatement.Catches().size();
277 for (int i = 0; i < n; ++i)
278 {
279 const std::std::unique_ptr<BoundCatchStatement>&boundCatchStatement=boundTryStatement.Catches()[i];
280 emitter->SetCurrentBasicBlock(catchTarget);
281 std::vector<void*> handleExceptionParamTypes;
282 handleExceptionParamTypes.push_back(emitter->GetIrTypeForVoidPtrType());
283 void* handleExceptionFunctionType = emitter->GetIrTypeForFunction(emitter->GetIrTypeForBool(), handleExceptionParamTypes);
284 std::vector<void*> handleExceptionArgs;
285 UuidValue uuidValue(boundCatchStatement->GetSpan(), boundCatchStatement->ModuleId(), boundCatchStatement->CatchedTypeUuidId());
286 void* catchTypeIdValue = uuidValue.IrValue(*emitter);
287 handleExceptionArgs.push_back(catchTypeIdValue);
288 void* handleException = emitter->GetOrInsertFunction("RtHandleException", handleExceptionFunctionType, true);
289 void* handleThisEx = nullptr;
290 if (currentPad == nullptr)
291 {
292 handleThisEx = emitter->CreateCall(handleException, handleExceptionArgs);
293 }
294 else
295 {
296 std::vector<void*> bundles;
297 bundles.push_back(currentPad->value);
298 handleThisEx = emitter->CreateCallInst(handleException, handleExceptionArgs, bundles, boundCatchStatement->GetSpan());
299 }
300 void* nextHandlerTarget = nullptr;
301 if (i < n - 1)
302 {
303 catchTarget = emitter->CreateBasicBlock("catch");
304 nextHandlerTarget = catchTarget;
305 }
306 else
307 {
308 nextHandlerTarget = resumeTarget;
309 }
310 void* thisHandlerTarget = emitter->CreateBasicBlock("handler");
311 emitter->CreateCondBr(handleThisEx, thisHandlerTarget, nextHandlerTarget);
312 emitter->SetCurrentBasicBlock(thisHandlerTarget);
313 boundCatchStatement->CatchBlock()->Accept(*this);
314 emitter->CreateCatchRet(currentPad->value, nextTarget);
315 }
316 emitter->SetCurrentBasicBlock(resumeTarget);
317 std::vector<void*> cxxThrowFunctionParamTypes;
318 cxxThrowFunctionParamTypes.push_back(emitter->GetIrTypeForVoidPtrType());
319 cxxThrowFunctionParamTypes.push_back(emitter->GetIrTypeForVoidPtrType());
320 void* cxxThrowFunctionType = emitter->GetIrTypeForFunction(emitter->GetIrTypeForVoid(), cxxThrowFunctionParamTypes);
321 void* cxxThrowFunction = emitter->GetOrInsertFunction("_CxxThrowException", cxxThrowFunctionType, false);
322 std::vector<void*> rethrowArgs;
323 rethrowArgs.push_back(emitter->CreateDefaultIrValueForVoidPtrType());
324 rethrowArgs.push_back(emitter->CreateDefaultIrValueForVoidPtrType());
325 std::vector<void*> bundles;
326 bundles.push_back(currentPad->value);
327 emitter->CreateCallInstToBasicBlock(cxxThrowFunction, rethrowArgs, bundles, resumeTarget, Span());
328 emitter->CreateBr(nextTarget);
329 currentPad = parentPad;
330 emitter->SetCurrentBasicBlock(nextTarget);
331 basicBlockOpen = true;
332 cleanupBlock = prevCleanupBlock;
333 }
334
335 void WindowsCodeGenerator::Visit(BoundRethrowStatement& boundRethrowStatement)
336 {
337 emitter->SetCurrentDebugLocation(boundRethrowStatement.GetSpan());
338 destructorCallGenerated = false;
339 lastInstructionWasRet = false;
340 basicBlockOpen = false;
341 SetTarget(&boundRethrowStatement);
342 boundRethrowStatement.ReleaseCall()->Accept(*this);
343 if (emitter->DIBuilder())
344 {
345 emitter->SetCurrentDebugLocation(boundRethrowStatement.GetSpan());
346 }
347 std::vector<void*> cxxThrowFunctionParamTypes;
348 cxxThrowFunctionParamTypes.push_back(emitter->GetIrTypeForVoidPtrType());
349 cxxThrowFunctionParamTypes.push_back(emitter->GetIrTypeForVoidPtrType());
350 void* cxxThrowFunctionType = emitter->GetIrTypeForFunction(emitter->GetIrTypeForVoid(), cxxThrowFunctionParamTypes);
351 void* cxxThrowFunction = emitter->GetOrInsertFunction("_CxxThrowException", cxxThrowFunctionType, false);
352 std::vector<void*> rethrowArgs;
353 rethrowArgs.push_back(emitter->CreateDefaultIrValueForVoidPtrType());
354 rethrowArgs.push_back(emitter->CreateDefaultIrValueForVoidPtrType());
355 std::vector<void*> bundles;
356 bundles.push_back(currentPad->value);
357 void* callInst = emitter->CreateCallInst(cxxThrowFunction, rethrowArgs, bundles, boundRethrowStatement.GetSpan());
358 }
359
360 void WindowsCodeGenerator::CreateCleanup()
361 {
362 cleanupBlock = emitter->CreateBasicBlock("cleanup");
363 BoundCompoundStatement* targetBlock = nullptr;
364 BoundStatement* parent = currentBlock->Parent();
365 while (parent && parent->GetBoundNodeType() != BoundNodeType::boundTryStatement)
366 {
367 parent = parent->Parent();
368 }
369 if (parent)
370 {
371 targetBlock = parent->Block();
372 }
373 cmajor::codegenllvm::Cleanup* cleanup = new cmajor::codegenllvm::Cleanup(cleanupBlock, handlerBlock, currentPad);
374 int n = blocks.size();
375 for (int i = n - 1; i >= 0; --i)
376 {
377 BoundCompoundStatement* block = blocks[i];
378 if (block == targetBlock)
379 {
380 break;
381 }
382 auto it = blockDestructionMap.find(block);
383 if (it != blockDestructionMap.cend())
384 {
385 std::std::vector<std::std::unique_ptr<BoundFunctionCall>>&destructorCallVec=it->second;
386 int nd = destructorCallVec.size();
387 for (int i = nd - 1; i >= 0; --i)
388 {
389 std::std::unique_ptr<BoundFunctionCall>&destructorCall=destructorCallVec[i];
390 if (destructorCall)
391 {
392 cleanup->destructors.push_back(std::unique_ptr<BoundFunctionCall>(static_cast<BoundFunctionCall*>(destructorCall->Clone())));
393 }
394 }
395 }
396 }
397 cleanups.push_back(std::unique_ptr<cmajor::codegenllvm::Cleanup>(cleanup));
398 newCleanupNeeded = false;
399 }
400
401 void* WindowsCodeGenerator::GetPersonalityFunction() const
402 {
403 void* personalityFunctionType = emitter->GetIrTypeForVariableParamFunction(emitter->GetIrTypeForInt());
404 void* personalityFunction = emitter->GetOrInsertFunction("__CxxFrameHandler3", personalityFunctionType, false);
405 return personalityFunction;
406 }
407
408 void WindowsCodeGenerator::GenerateCodeForCleanups()
409 {
410 for (const std::std::unique_ptr<cmajor::codegenllvm::Cleanup>&cleanup : cleanups)
411 {
412 emitter->SetCurrentBasicBlock(cleanup->cleanupBlock);
413 Pad* parentPad = cleanup->currentPad;
414 void* cleanupPad = nullptr;
415 if (parentPad)
416 {
417 std::vector<void*> args;
418 cleanupPad = emitter->CreateCleanupPadWithParent(parentPad->value, args);
419 }
420 else
421 {
422 std::vector<void*> args;
423 cleanupPad = emitter->CreateCleanupPad(args);
424 }
425 Pad pad;
426 pad.parent = parentPad;
427 pad.value = cleanupPad;
428 currentPad = &pad;
429 for (const std::std::unique_ptr<BoundFunctionCall>&destructorCall : cleanup->destructors)
430 {
431 destructorCall->Accept(*this);
432 }
433 void* unwindTarget = cleanup->handlerBlock;
434 emitter->CreateCleanupRet(cleanupPad, unwindTarget);
435 }
436 }
437
438 } }
439