1
2
3
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
36 GenerateExitFunctionCode(*currentFunction);
37 emitter->CreateRet(returnValue);
38 lastInstructionWasRet = true;
39 }
40 else
41 {
42 ExitBlocks(nullptr);
43
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(lp, exceptionTypeId);
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(lp, exPtrIndex);
186 emitter->CreateStore(exPtr, exPtrAlloca);
187 std::vector<unsigned int> exIdIndex;
188 exIdIndex.push_back(1);
189 void* exId = emitter->CreateExtractValue(lp, exIdIndex);
190 void* exIdAlloca = emitter->CreateAlloca(emitter->GetIrTypeForInt());
191 MoveAllocaIntoEntryBlock(exIdAlloca);
192 emitter->CreateStore(exId, exIdAlloca);
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", llvmEHTypeIdForType, true);
201 std::vector<void*> llvmEHTypeIdForArgs;
202 llvmEHTypeIdForArgs.push_back(emitter->CreateBitCast(exceptionTypeId, emitter->GetIrTypeForVoidPtrType()));
203 void* ehSelector = emitter->CreateCall(llvmEHTypeIdFor, llvmEHTypeIdForArgs);
204 void* match = emitter->CreateICmpEQ(loadedExId, ehSelector);
205 void* beginCatchBlock = emitter->CreateBasicBlock("handlers");
206 void* resumeBlock = emitter->CreateBasicBlock("resume");
207 emitter->CreateCondBr(match, beginCatchBlock, resumeBlock);
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", cxaBeginCatchType, true);
213 std::vector<void*> cxaBeginCatchArgs;
214 void* loadedExPtr = emitter->CreateLoad(exPtrAlloca);
215 cxaBeginCatchArgs.push_back(loadedExPtr);
216 void* cxaBeginCatchValue = emitter->CreateCall(cxaBeginCatch, cxaBeginCatchArgs);
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", handleExceptionFunctionType, true);
232 void* handleThisEx = emitter->CreateCall(handleException, handleExceptionArgs);
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(handleThisEx, thisHandlerTarget, nextHandlerTarget);
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", cxaEndCatchType, true);
250 std::vector<void*> cxaEndCatchArgs;
251 void* cxaEndCatchValue = emitter->CreateCall(cxaEndCatch, cxaEndCatchArgs);
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), loadedExPtrForResume, exPtrIndex);
258 void* resume2 = emitter->CreateInsertValue(resume1, loadedExIdForResume, exIdIndex);
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", rethrowFunctionType, false);
274 std::vector<void*> rethrowArgs;
275 emitter->CreateCall(cxaRethrowFunction, rethrowArgs);
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(cleanupBlock, handlerBlock, currentPad);
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", personalityFunctionType, true);
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 } }