1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <cmajor/codegenlinux/LinuxCodeGenerator.hpp>
  7 #include <cmajor/binder/BoundStatement.hpp>
  8 #include <cmajor/binder/BoundFunction.hpp>
  9 #include <cmajor/symbols/Exception.hpp>
 10 
 11 namespace cmajor { namespace codegenlinux {
 12 
 13 LinuxCodeGenerator::LinuxCodeGenerator(cmajor::ir::EmittingContext& emittingContext_) : LlvmCodeGenerator(emittingContext_)
 14 {
 15 }
 16 
 17 void LinuxCodeGenerator::Visit(BoundReturnStatement& boundReturnStatement)
 18 {
 19     emitter->SetCurrentDebugLocation(boundReturnStatement.GetSpan());
 20     destructorCallGenerated = false;
 21     lastInstructionWasRet = false;
 22     basicBlockOpen = false;
 23     SetTarget(&boundReturnStatement);
 24     BoundFunctionCall* returnFunctionCall = boundReturnStatement.ReturnFunctionCall();
 25     if (returnFunctionCall)
 26     {
 27         returnFunctionCall->Accept(*this);
 28         void* returnValue = emitter->Stack().Pop();
 29         if (sequenceSecond)
 30         {
 31             sequenceSecond->SetGenerated();
 32             sequenceSecond->Accept(*this);
 33         }
 34         ExitBlocks(nullptr);
 35         //CreateExitFunctionCall();
 36         GenerateExitFunctionCode(*currentFunction);
 37         emitter->CreateRet(returnValue);
 38         lastInstructionWasRet = true;
 39     }
 40     else
 41     {
 42         ExitBlocks(nullptr);
 43         //CreateExitFunctionCall();
 44         GenerateExitFunctionCode(*currentFunction);
 45         emitter->CreateRetVoid();
 46         lastInstructionWasRet = true;
 47     }
 48     BoundCompoundStatement* body = currentFunction->Body();
 49     BoundStatement* lastStatement = nullptr;
 50     if (!body->Statements().empty())
 51     {
 52         lastStatement = body->Statements().back().get();
 53     }
 54     if (lastStatement && lastStatement != &boundReturnStatement)
 55     {
 56         void* nextBlock = emitter->CreateBasicBlock("next");
 57         emitter->SetCurrentBasicBlock(nextBlock);
 58         basicBlockOpen = true;
 59         lastInstructionWasRet = false;
 60     }
 61 }
 62 
 63 void LinuxCodeGenerator::Visit(BoundGotoCaseStatement& boundGotoCaseStatement)
 64 {
 65     emitter->SetCurrentDebugLocation(boundGotoCaseStatement.GetSpan());
 66     destructorCallGenerated = false;
 67     lastInstructionWasRet = false;
 68     basicBlockOpen = false;
 69     SetTarget(&boundGotoCaseStatement);
 70     Assert(breakTargetBlock"break target not set");
 71     ExitBlocks(breakTargetBlock);
 72     IntegralValue integralCaseValue(boundGotoCaseStatement.CaseValue());
 73     auto it = currentCaseMap->find(integralCaseValue);
 74     if (it != currentCaseMap->cend())
 75     {
 76         void* caseDest = it->second;
 77         emitter->CreateBr(caseDest);
 78     }
 79     else
 80     {
 81         throw Exception("case not found"boundGotoCaseStatement.GetSpan()boundGotoCaseStatement.ModuleId());
 82     }
 83 }
 84 
 85 void LinuxCodeGenerator::Visit(BoundGotoDefaultStatement& boundGotoDefaultStatement)
 86 {
 87     emitter->SetCurrentDebugLocation(boundGotoDefaultStatement.GetSpan());
 88     destructorCallGenerated = false;
 89     lastInstructionWasRet = false;
 90     basicBlockOpen = false;
 91     SetTarget(&boundGotoDefaultStatement);
 92     Assert(breakTargetBlock"break target not set");
 93     ExitBlocks(breakTargetBlock);
 94     if (defaultDest)
 95     {
 96         emitter->CreateBr(defaultDest);
 97     }
 98     else
 99     {
100         throw Exception("no default destination"boundGotoDefaultStatement.GetSpan()boundGotoDefaultStatement.ModuleId());
101     }
102 }
103 
104 void LinuxCodeGenerator::Visit(BoundBreakStatement& boundBreakStatement)
105 {
106     emitter->SetCurrentDebugLocation(boundBreakStatement.GetSpan());
107     destructorCallGenerated = false;
108     lastInstructionWasRet = false;
109     basicBlockOpen = false;
110     SetTarget(&boundBreakStatement);
111     Assert(breakTarget && breakTargetBlock"break target not set");
112     ExitBlocks(breakTargetBlock);
113     emitter->CreateBr(breakTarget);
114     void* nextBlock = emitter->CreateBasicBlock("next");
115     emitter->SetCurrentBasicBlock(nextBlock);
116     basicBlockOpen = true;
117 }
118 
119 void LinuxCodeGenerator::Visit(BoundContinueStatement& boundContinueStatement)
120 {
121     emitter->SetCurrentDebugLocation(boundContinueStatement.GetSpan());
122     destructorCallGenerated = false;
123     lastInstructionWasRet = false;
124     basicBlockOpen = false;
125     SetTarget(&boundContinueStatement);
126     Assert(continueTarget && continueTargetBlock"continue target not set");
127     ExitBlocks(continueTargetBlock);
128     emitter->CreateBr(continueTarget);
129     void* nextBlock = emitter->CreateBasicBlock("next");
130     emitter->SetCurrentBasicBlock(nextBlock);
131     basicBlockOpen = true;
132 }
133 
134 void LinuxCodeGenerator::Visit(BoundGotoStatement& boundGotoStatement)
135 {
136     emitter->SetCurrentDebugLocation(boundGotoStatement.GetSpan());
137     destructorCallGenerated = false;
138     lastInstructionWasRet = false;
139     basicBlockOpen = false;
140     SetTarget(&boundGotoStatement);
141     ExitBlocks(boundGotoStatement.TargetBlock());
142     auto it = labeledStatementMap.find(boundGotoStatement.TargetStatement());
143     if (it != labeledStatementMap.cend())
144     {
145         void* target = it->second;
146         emitter->CreateBr(target);
147     }
148     else
149     {
150         throw Exception("goto target not found"boundGotoStatement.GetSpan()boundGotoStatement.ModuleId());
151     }
152     void* nextBlock = emitter->CreateBasicBlock("next");
153     emitter->SetCurrentBasicBlock(nextBlock);
154     basicBlockOpen = true;
155 }
156 
157 void LinuxCodeGenerator::Visit(BoundTryStatement& boundTryStatement)
158 {
159     ClearFlags();
160     SetTarget(&boundTryStatement);
161     void* prevHandlerBlock = handlerBlock;
162     void* prevCleanupBlock = cleanupBlock;
163     handlerBlock = emitter->CreateBasicBlock("lpad");
164     cleanupBlock = nullptr;
165     boundTryStatement.TryBlock()->Accept(*this);
166     void* nextTarget = emitter->CreateBasicBlock("next");
167     emitter->CreateBr(nextTarget);
168     emitter->SetCurrentBasicBlock(handlerBlock);
169     handlerBlock = prevHandlerBlock;
170     std::vector<void*> lpElemTypes;
171     lpElemTypes.push_back(emitter->GetIrTypeForVoidPtrType());
172     lpElemTypes.push_back(emitter->GetIrTypeForInt());
173     void* lpType = emitter->GetIrTypeForClassType(lpElemTypes);
174     void* lp = emitter->CreateLandingPad(lpType);
175     std::vector<void*> exTypeInfoElemTypes;
176     exTypeInfoElemTypes.push_back(emitter->GetIrTypeForVoidPtrType());
177     exTypeInfoElemTypes.push_back(emitter->GetIrTypeForVoidPtrType());
178     void* exTypeInfoType = emitter->GetIrTypeForClassType(exTypeInfoElemTypes);
179     void* exceptionTypeId = emitter->GetOrInsertGlobal("_ZTIN6cmajor2eh9ExceptionE"exTypeInfoType);
180     emitter->AddClauseToLangdingPad(lpexceptionTypeId);
181     std::vector<unsigned int> exPtrIndex;
182     exPtrIndex.push_back(0);
183     void* exPtrAlloca = emitter->CreateAlloca(emitter->GetIrTypeForVoidPtrType());
184     MoveAllocaIntoEntryBlock(exPtrAlloca);
185     void* exPtr = emitter->CreateExtractValue(lpexPtrIndex);
186     emitter->CreateStore(exPtrexPtrAlloca);
187     std::vector<unsigned int> exIdIndex;
188     exIdIndex.push_back(1);
189     void* exId = emitter->CreateExtractValue(lpexIdIndex);
190     void* exIdAlloca = emitter->CreateAlloca(emitter->GetIrTypeForInt());
191     MoveAllocaIntoEntryBlock(exIdAlloca);
192     emitter->CreateStore(exIdexIdAlloca);
193     void* testBlock = emitter->CreateBasicBlock("test");
194     emitter->CreateBr(testBlock);
195     emitter->SetCurrentBasicBlock(testBlock);
196     void* loadedExId = emitter->CreateLoad(exIdAlloca);
197     std::vector<void*> llvmEhParamTypes;
198     llvmEhParamTypes.push_back(emitter->GetIrTypeForVoidPtrType());
199     void* llvmEHTypeIdForType = emitter->GetIrTypeForFunction(emitter->GetIrTypeForInt()llvmEhParamTypes);
200     void* llvmEHTypeIdFor = emitter->GetOrInsertFunction("llvm.eh.typeid.for"llvmEHTypeIdForTypetrue);
201     std::vector<void*> llvmEHTypeIdForArgs;
202     llvmEHTypeIdForArgs.push_back(emitter->CreateBitCast(exceptionTypeIdemitter->GetIrTypeForVoidPtrType()));
203     void* ehSelector = emitter->CreateCall(llvmEHTypeIdForllvmEHTypeIdForArgs);
204     void* match = emitter->CreateICmpEQ(loadedExIdehSelector);
205     void* beginCatchBlock = emitter->CreateBasicBlock("handlers");
206     void* resumeBlock = emitter->CreateBasicBlock("resume");
207     emitter->CreateCondBr(matchbeginCatchBlockresumeBlock);
208     emitter->SetCurrentBasicBlock(beginCatchBlock);
209     std::vector<void*> cxaBeginCatchParamTypes;
210     cxaBeginCatchParamTypes.push_back(emitter->GetIrTypeForVoidPtrType());
211     void* cxaBeginCatchType = emitter->GetIrTypeForFunction(emitter->GetIrTypeForVoidPtrType()cxaBeginCatchParamTypes);
212     void* cxaBeginCatch = emitter->GetOrInsertFunction("__cxa_begin_catch"cxaBeginCatchTypetrue);
213     std::vector<void*> cxaBeginCatchArgs;
214     void* loadedExPtr = emitter->CreateLoad(exPtrAlloca);
215     cxaBeginCatchArgs.push_back(loadedExPtr);
216     void* cxaBeginCatchValue = emitter->CreateCall(cxaBeginCatchcxaBeginCatchArgs);
217     void* catchTarget = emitter->CreateBasicBlock("catch");
218     emitter->CreateBr(catchTarget);
219     int n = boundTryStatement.Catches().size();
220     for (int i = 0; i < n; ++i)
221     {
222         const std::std::unique_ptr<BoundCatchStatement>&boundCatchStatement=boundTryStatement.Catches()[i];
223         emitter->SetCurrentBasicBlock(catchTarget);
224         std::vector<void*> handleExceptionParamTypes;
225         handleExceptionParamTypes.push_back(emitter->GetIrTypeForVoidPtrType());
226         void* handleExceptionFunctionType = emitter->GetIrTypeForFunction(emitter->GetIrTypeForBool()handleExceptionParamTypes);
227         std::vector<void*> handleExceptionArgs;
228         UuidValue uuidValue(boundCatchStatement->GetSpan()boundCatchStatement->ModuleId()boundCatchStatement->CatchedTypeUuidId());
229         void* catchTypeIdValue = uuidValue.IrValue(*emitter);
230         handleExceptionArgs.push_back(catchTypeIdValue);
231         void* handleException = emitter->GetOrInsertFunction("RtHandleException"handleExceptionFunctionTypetrue);
232         void* handleThisEx = emitter->CreateCall(handleExceptionhandleExceptionArgs);
233         void* nextHandlerTarget = nullptr;
234         if (i < n - 1)
235         {
236             catchTarget = emitter->CreateBasicBlock("catch");
237             nextHandlerTarget = catchTarget;
238         }
239         else
240         {
241             nextHandlerTarget = resumeBlock;
242         }
243         void* thisHandlerTarget = emitter->CreateBasicBlock("handler");
244         emitter->CreateCondBr(handleThisExthisHandlerTargetnextHandlerTarget);
245         emitter->SetCurrentBasicBlock(thisHandlerTarget);
246         boundCatchStatement->CatchBlock()->Accept(*this);
247         std::vector<void*> cxaEndCatchParamTypes;
248         void* cxaEndCatchType = emitter->GetIrTypeForFunction(emitter->GetIrTypeForVoid()cxaEndCatchParamTypes);
249         void* cxaEndCatch = emitter->GetOrInsertFunction("__cxa_end_catch"cxaEndCatchTypetrue);
250         std::vector<void*> cxaEndCatchArgs;
251         void* cxaEndCatchValue = emitter->CreateCall(cxaEndCatchcxaEndCatchArgs);
252         emitter->CreateBr(nextTarget);
253     }
254     emitter->SetCurrentBasicBlock(resumeBlock);
255     void* loadedExPtrForResume = emitter->CreateLoad(exPtrAlloca);
256     void* loadedExIdForResume = emitter->CreateLoad(exIdAlloca);
257     void* resume1 = emitter->CreateInsertValue(emitter->CreateUndefValue(lpType)loadedExPtrForResumeexPtrIndex);
258     void* resume2 = emitter->CreateInsertValue(resume1loadedExIdForResumeexIdIndex);
259     emitter->CreateResume(resume2);
260     emitter->SetCurrentBasicBlock(nextTarget);
261     basicBlockOpen = true;
262 }
263 
264 void LinuxCodeGenerator::Visit(BoundRethrowStatement& boundRethrowStatement)
265 {
266     emitter->SetCurrentDebugLocation(boundRethrowStatement.GetSpan());
267     destructorCallGenerated = false;
268     lastInstructionWasRet = false;
269     basicBlockOpen = false;
270     SetTarget(&boundRethrowStatement);
271     boundRethrowStatement.ReleaseCall()->Accept(*this);
272     void* rethrowFunctionType = emitter->GetIrTypeForFunction(emitter->GetIrTypeForVoid()std::vector<void*>());
273     void* cxaRethrowFunction = emitter->GetOrInsertFunction("__cxa_rethrow"rethrowFunctionTypefalse);
274     std::vector<void*> rethrowArgs;
275     emitter->CreateCall(cxaRethrowFunctionrethrowArgs);
276 }
277 
278 void LinuxCodeGenerator::CreateCleanup()
279 {
280     cleanupBlock = emitter->CreateBasicBlock("cleanup");
281     BoundCompoundStatement* targetBlock = nullptr;
282     BoundStatement* parent = currentBlock->Parent();
283     while (parent && parent->GetBoundNodeType() != BoundNodeType::boundTryStatement)
284     {
285         parent = parent->Parent();
286     }
287     if (parent)
288     {
289         targetBlock = parent->Block();
290     }
291     cmajor::codegenllvm::Cleanup* cleanup = new cmajor::codegenllvm::Cleanup(cleanupBlockhandlerBlockcurrentPad);
292     int n = blocks.size();
293     for (int i = n - 1; i >= 0; --i)
294     {
295         BoundCompoundStatement* block = blocks[i];
296         if (block == targetBlock)
297         {
298             break;
299         }
300         auto it = blockDestructionMap.find(block);
301         if (it != blockDestructionMap.cend())
302         {
303             std::std::vector<std::std::unique_ptr<BoundFunctionCall>>&destructorCallVec=it->second;
304             int nd = destructorCallVec.size();
305             for (int i = nd - 1; i >= 0; --i)
306             {
307                 std::std::unique_ptr<BoundFunctionCall>&destructorCall=destructorCallVec[i];
308                 if (destructorCall)
309                 {
310                     cleanup->destructors.push_back(std::unique_ptr<BoundFunctionCall>(static_cast<BoundFunctionCall*>(destructorCall->Clone())));
311                 }
312             }
313         }
314     }
315     cleanups.push_back(std::unique_ptr<cmajor::codegenllvm::Cleanup>(cleanup));
316     newCleanupNeeded = false;
317 }
318 
319 void* LinuxCodeGenerator::GetPersonalityFunction() const
320 {
321     void* personalityFunctionType = emitter->GetIrTypeForVariableParamFunction(emitter->GetIrTypeForInt());
322     void* personalityFunction = emitter->GetOrInsertFunction("__gxx_personality_v0"personalityFunctionTypetrue);
323     return personalityFunction;
324 }
325 
326 void LinuxCodeGenerator::GenerateCodeForCleanups()
327 {
328     for (const std::std::unique_ptr<cmajor::codegenllvm::Cleanup>&cleanup : cleanups)
329     {
330         emitter->SetCurrentBasicBlock(cleanup->cleanupBlock);
331         std::vector<void*> lpElemTypes;
332         lpElemTypes.push_back(emitter->GetIrTypeForVoidPtrType());
333         lpElemTypes.push_back(emitter->GetIrTypeForInt());
334         void* lpType = emitter->GetIrTypeForClassType(lpElemTypes);
335         void* lp = emitter->CreateLandingPad(lpType);
336         emitter->SetLandindPadAsCleanup(lp);
337         for (const std::std::unique_ptr<BoundFunctionCall>&destructorCall : cleanup->destructors)
338         {
339             destructorCall->Accept(*this);
340         }
341         emitter->CreateResume(lp);
342     }
343 }
344 
345 } } // namespace cmajor::codegenlinux