1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  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->valuereturnTarget);
 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->valuefromCatchTarget);
 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->valuefromCatchTarget);
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->valuefromCatchTarget);
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->valuefromCatchTarget);
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->valuefromCatchTarget);
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->valueprevHandlerBlock);
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(catchSwitchcatchPadTarget);
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->valuecatchPadArgs);
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"handleExceptionFunctionTypetrue);
289         void* handleThisEx = nullptr;
290         if (currentPad == nullptr)
291         {
292             handleThisEx = emitter->CreateCall(handleExceptionhandleExceptionArgs);
293         }
294         else
295         {
296             std::vector<void*> bundles;
297             bundles.push_back(currentPad->value);
298             handleThisEx = emitter->CreateCallInst(handleExceptionhandleExceptionArgsbundlesboundCatchStatement->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(handleThisExthisHandlerTargetnextHandlerTarget);
312         emitter->SetCurrentBasicBlock(thisHandlerTarget);
313         boundCatchStatement->CatchBlock()->Accept(*this);
314         emitter->CreateCatchRet(currentPad->valuenextTarget);
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"cxxThrowFunctionTypefalse);
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(cxxThrowFunctionrethrowArgsbundlesresumeTargetSpan());
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"cxxThrowFunctionTypefalse);
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(cxxThrowFunctionrethrowArgsbundlesboundRethrowStatement.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(cleanupBlockhandlerBlockcurrentPad);
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"personalityFunctionTypefalse);
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->valueargs);
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(cleanupPadunwindTarget);
435     }
436 }
437 
438 } } // namespace cmajor::codegenwin
439