GCC Code Coverage Report


Directory: src/
File: src/codegen/gyoji-codegen-llvm.cpp
Date: 2025-10-15 09:43:47
Exec Total Coverage
Lines: 586 931 62.9%
Functions: 47 60 78.3%
Branches: 177 321 55.1%

Line Branch Exec Source
1 #include <gyoji-codegen.hpp>
2 #include "gyoji-codegen-private.hpp"
3
4 using namespace llvm::sys;
5 using namespace Gyoji::codegen;
6 using namespace Gyoji::mir;
7
8 30 CodeGeneratorLLVM::CodeGeneratorLLVM(
9 const Gyoji::context::CompilerContext & _compiler_context,
10 const Gyoji::mir::MIR & _mir
11 30 )
12 30 : context(std::make_unique<CodeGeneratorLLVMContext>(_compiler_context, _mir))
13 30 {}
14
15 30 CodeGeneratorLLVM::~CodeGeneratorLLVM()
16 30 {}
17
18 void
19 30 CodeGeneratorLLVM::initialize()
20 30 { context->initialize(); }
21
22 void
23 30 CodeGeneratorLLVM::generate()
24 30 { context->generate(); }
25
26 int
27 30 CodeGeneratorLLVM::output(const std::string & filename)
28 30 { return context->output(filename); }
29 /////////////////////////////////////
30 // CodeGeneratorLLVMContext
31 /////////////////////////////////////
32 30 CodeGeneratorLLVMContext::CodeGeneratorLLVMContext(
33 const Gyoji::context::CompilerContext & _compiler_context,
34 const Gyoji::mir::MIR & _mir
35 30 )
36 30 : compiler_context(_compiler_context)
37 30 , mir(_mir)
38 30 {}
39 30 CodeGeneratorLLVMContext::~CodeGeneratorLLVMContext()
40 30 {}
41
42 void
43 30 CodeGeneratorLLVMContext::initialize()
44 {
45 // Open a new context and module.
46 30 TheContext = std::make_unique<llvm::LLVMContext>();
47 30 TheModule = std::make_unique<llvm::Module>("gyoji LLVM Code Generator", *TheContext);
48 // Create a new builder for the module.
49 30 Builder = std::make_unique<llvm::IRBuilder<>>(*TheContext);
50
51 // register_type_builtins();
52 // register_operator_builtins();
53 30 }
54
55 llvm::Function *
56 266 CodeGeneratorLLVMContext::create_function(const Function & function)
57 {
58 // Make the function type: double(double,double) etc.
59 266 std::vector<llvm::Type *> llvm_arguments;
60 266 const std::vector<FunctionArgument> & function_arguments = function.get_arguments();
61
62
2/2
✓ Branch 5 taken 520 times.
✓ Branch 6 taken 266 times.
786 for (const auto & semantic_arg : function_arguments) {
63 520 llvm::Type *atype = types[semantic_arg.get_type()->get_name()];
64 520 llvm_arguments.push_back(atype);
65 }
66
67 266 llvm::Type* return_value_type = types[function.get_return_type()->get_name()];
68
69 llvm::FunctionType *FT =
70 266 llvm::FunctionType::get(return_value_type, llvm_arguments, false);
71
72 llvm::Function *F =
73 266 llvm::Function::Create(FT, llvm::Function::ExternalLinkage, function.get_name(), TheModule.get());
74
75 // Set names for all arguments.
76 266 unsigned Idx = 0;
77
2/2
✓ Branch 3 taken 520 times.
✓ Branch 4 taken 266 times.
786 for (auto &Arg : F->args()) {
78 520 const auto & semantic_arg = function_arguments.at(Idx++);
79 520 Arg.setName(semantic_arg.get_name());
80 }
81
82 532 return F;
83 266 }
84
85 /// CreateEntryBlockAlloca - Create an alloca instruction in the entry block of
86 /// the function. This is used for mutable variables etc.
87 llvm::AllocaInst *CodeGeneratorLLVMContext::CreateEntryBlockAlloca(
88 llvm::Function *TheFunction,
89 const llvm::StringRef & VarName
90 )
91 {
92 llvm::IRBuilder<> TmpB(&TheFunction->getEntryBlock(),
93 TheFunction->getEntryBlock().begin()
94 );
95 return TmpB.CreateAlloca(llvm::Type::getDoubleTy(*TheContext), nullptr, VarName);
96 }
97
98 /**
99 * An enum type is "almost" a primitive type.
100 * It always resolves to a u32 on the physical host
101 * but carries some slightly different semantics.
102 */
103 llvm::Type *
104 CodeGeneratorLLVMContext::create_type_enum(const Gyoji::mir::Type *enumtype)
105 {
106 return llvm::Type::getInt32Ty(*TheContext);
107 }
108
109 llvm::Type *
110 4 CodeGeneratorLLVMContext::create_type_composite(const Gyoji::mir::Type *compositetype)
111 {
112 4 std::vector<llvm::Type*> members;
113
114 // Note that this relies on the fact that
115 // the members are in order and equal to the
116 // 'index' of the member. Yes, this is a bit
117 // of a hacky way to do that.
118
2/2
✓ Branch 5 taken 10 times.
✓ Branch 6 taken 4 times.
14 for (const auto & member : compositetype->get_members()) {
119 10 members.push_back(create_type(member.get_type()));
120 }
121
122 4 llvm::Type *llvm_type = llvm::StructType::create(*TheContext, members, compositetype->get_name());
123 4 types.insert(std::pair<std::string, llvm::Type*>(
124 4 compositetype->get_name(),
125 llvm_type
126 )
127 );
128 8 return llvm_type;
129 4 }
130
131 llvm::Type *
132 64 CodeGeneratorLLVMContext::create_type_pointer(const Gyoji::mir::Type *pointertype)
133 {
134 64 const Gyoji::mir::Type * pointer_target = pointertype->get_pointer_target();
135 llvm::Type * llvm_type =
136 64 llvm::PointerType::get(create_type(pointer_target),
137 0 // Address space (default to 0? This seems unclean, llvm!)
138 64 );
139 64 types.insert(std::pair<std::string, llvm::Type*>(
140 64 pointertype->get_name(),
141 llvm_type
142 )
143 );
144 64 return llvm_type;
145 }
146
147 llvm::Type *
148 CodeGeneratorLLVMContext::create_type_reference(const Gyoji::mir::Type *referencetype)
149 {
150 const Gyoji::mir::Type * pointer_target = referencetype->get_pointer_target();
151 llvm::Type * llvm_type =
152 llvm::PointerType::get(create_type(pointer_target),
153 0 // Address space (default to 0? This seems unclean, llvm!)
154 );
155 types.insert(std::pair<std::string, llvm::Type*>(
156 referencetype->get_name(),
157 llvm_type
158 )
159 );
160 return llvm_type;
161 }
162
163 llvm::Type *
164 2 CodeGeneratorLLVMContext::create_type_array(const Gyoji::mir::Type *array_type)
165 {
166 2 const Gyoji::mir::Type * element_type = array_type->get_pointer_target();
167 llvm::Type * llvm_element_type =
168 2 llvm::PointerType::get(create_type(element_type),
169 0 // Address space (default to 0? This seems unclean, llvm!)
170 );
171 2 llvm::Type *llvm_array_type = llvm::ArrayType::get(llvm_element_type, array_type->get_array_length());
172
173 2 types.insert(std::pair<std::string, llvm::Type*>(
174 2 array_type->get_name(),
175 llvm_array_type
176 )
177 );
178 2 return llvm_array_type;
179 }
180
181 llvm::Type *
182 118 CodeGeneratorLLVMContext::create_type_function_pointer(const Gyoji::mir::Type *fptr_type)
183 {
184 118 const Gyoji::mir::Type *mir_return_type = fptr_type->get_return_type();
185 118 llvm::Type *llvm_return_type = create_type(mir_return_type);
186
187 118 const std::vector<Gyoji::mir::Argument> & mir_args = fptr_type->get_argument_types();
188
189 118 std::vector<llvm::Type *> llvm_fptr_args;
190
2/2
✓ Branch 4 taken 190 times.
✓ Branch 5 taken 118 times.
308 for (const auto & mir_arg : mir_args) {
191 190 llvm_fptr_args.push_back(create_type(mir_arg.get_type()));
192 }
193
194 118 llvm::ArrayRef<llvm::Type *> llvm_args_ref(llvm_fptr_args);
195 118 llvm::FunctionType *llvm_fptr_type = llvm::FunctionType::get(llvm_return_type, llvm_args_ref, false);
196
197 118 types.insert(std::pair<std::string, llvm::Type*>(
198 118 fptr_type->get_name(),
199 llvm_fptr_type
200 )
201 );
202 236 return llvm_fptr_type;
203 118 }
204
205 /**
206 * These are the truly primitive types.
207 * They are defined in the language
208 * and have their basis in physical computing
209 * units (number of bits).
210 */
211 llvm::Type *
212 360 CodeGeneratorLLVMContext::create_type_primitive(const Type *primitive)
213 {
214 llvm::Type *llvm_type;
215
216
12/13
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 30 times.
✓ Branch 4 taken 30 times.
✓ Branch 5 taken 30 times.
✓ Branch 6 taken 30 times.
✓ Branch 7 taken 30 times.
✓ Branch 8 taken 30 times.
✓ Branch 9 taken 30 times.
✓ Branch 10 taken 30 times.
✓ Branch 11 taken 30 times.
✓ Branch 12 taken 30 times.
✗ Branch 13 not taken.
360 switch (primitive->get_type()) {
217 // Unsigned integer types
218 30 case Type::TYPE_PRIMITIVE_u8:
219 30 llvm_type = llvm::Type::getInt8Ty(*TheContext);
220 30 break;
221 30 case Type::TYPE_PRIMITIVE_u16:
222 30 llvm_type = llvm::Type::getInt16Ty(*TheContext);
223 30 break;
224 30 case Type::TYPE_PRIMITIVE_u32:
225 30 llvm_type = llvm::Type::getInt32Ty(*TheContext);
226 30 break;
227 30 case Type::TYPE_PRIMITIVE_u64:
228 30 llvm_type = llvm::Type::getInt64Ty(*TheContext);
229 30 break;
230
231 // Signed integer types
232 30 case Type::TYPE_PRIMITIVE_i8:
233 30 llvm_type = llvm::Type::getInt8Ty(*TheContext);
234 30 break;
235 30 case Type::TYPE_PRIMITIVE_i16:
236 30 llvm_type = llvm::Type::getInt16Ty(*TheContext);
237 30 break;
238 30 case Type::TYPE_PRIMITIVE_i32:
239 30 llvm_type = llvm::Type::getInt32Ty(*TheContext);
240 30 break;
241 30 case Type::TYPE_PRIMITIVE_i64:
242 30 llvm_type = llvm::Type::getInt64Ty(*TheContext);
243 30 break;
244 30 case Type::TYPE_PRIMITIVE_f32:
245 30 llvm_type = llvm::Type::getFloatTy(*TheContext);
246 30 break;
247 30 case Type::TYPE_PRIMITIVE_f64:
248 30 llvm_type = llvm::Type::getDoubleTy(*TheContext);
249 30 break;
250 // "Special" types
251 30 case Type::TYPE_PRIMITIVE_bool:
252 30 llvm_type = llvm::Type::getInt32Ty(*TheContext);
253 30 break;
254 30 case Type::TYPE_PRIMITIVE_void:
255 30 llvm_type = llvm::Type::getVoidTy(*TheContext);
256 30 break;
257 default:
258 fprintf(stderr, "Compiler BUG! Unknown primitive type passed to code generator\n");
259 exit(1);
260 }
261
262 360 types.insert(std::pair<std::string, llvm::Type*>(
263 360 primitive->get_name(),
264 llvm_type
265 )
266 );
267 360 return llvm_type;
268 }
269
270 llvm::Type *
271 932 CodeGeneratorLLVMContext::create_type(const Type * type)
272 {
273 // First, check if we have (recursively)
274 // defined this type already. Skip it if we have.
275 // This is not a duplicate definition because the
276 // type resolver will already have checked for that
277 // case and reject any truly duplicate types.
278 932 const auto it = types.find(type->get_name());
279
2/2
✓ Branch 2 taken 384 times.
✓ Branch 3 taken 548 times.
932 if (it != types.end()) {
280 384 return it->second;
281 }
282
283
2/2
✓ Branch 1 taken 360 times.
✓ Branch 2 taken 188 times.
548 if (type->is_primitive()) {
284 360 return create_type_primitive(type);
285 }
286
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 188 times.
188 else if (type->is_enum()) {
287 return create_type_enum(type);
288 }
289
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 184 times.
188 else if (type->is_composite()) {
290 4 return create_type_composite(type);
291 }
292
2/2
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 120 times.
184 else if (type->is_pointer()) {
293 64 return create_type_pointer(type);
294 }
295
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 120 times.
120 else if (type->is_reference()) {
296 return create_type_reference(type);
297 }
298
2/2
✓ Branch 1 taken 118 times.
✓ Branch 2 taken 2 times.
120 else if (type->is_function_pointer()) {
299 118 return create_type_function_pointer(type);
300 }
301
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 else if (type->is_array()) {
302 2 return create_type_array(type);
303 }
304 fprintf(stderr, "Compiler BUG! Unknown type type passed to code generator %s\n", type->get_name().c_str());
305 exit(1);
306 return nullptr;
307 }
308
309 void
310 30 CodeGeneratorLLVMContext::create_types(const MIR & _mir)
311 {
312
2/2
✓ Branch 7 taken 548 times.
✓ Branch 8 taken 30 times.
578 for (const auto & type_el : _mir.get_types().get_types()) {
313 548 const Type * type = type_el.second.get();
314
315 // We can safely skip generating incomplete
316 // types without raising an error because
317 // the analysis stage will alert us if there
318 // is an incomplete type that is used
319 // in another type or in a method/function.
320
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 548 times.
548 if (!type->is_complete()) {
321 continue;
322 }
323 548 create_type(type);
324 }
325 30 }
326
327
328 void
329 30 CodeGeneratorLLVMContext::generate()
330 {
331 30 create_types(mir);
332
333 30 const Functions & functions = mir.get_functions();
334
2/2
✓ Branch 6 taken 266 times.
✓ Branch 7 taken 30 times.
296 for (auto const & function : functions.get_functions()) {
335 266 fprintf(stderr, " - Generating function %s\n", function->get_name().c_str());
336 266 generate_function(*function);
337 }
338 30 }
339
340 // Global symbols
341 void
342 66 CodeGeneratorLLVMContext::generate_operation_function_call(
343 std::map<size_t, llvm::Value *> & tmp_values,
344 const Gyoji::mir::Function & mir_function,
345 const Gyoji::mir::OperationFunctionCall & operation
346 )
347 {
348
349 // First argument of this operand is the function to call.
350 66 size_t function_operand = operation.get_operands().at(0);
351 66 llvm::Value *llvm_function = tmp_values[function_operand];
352
353 // The remaining operands are the values to pass to it.
354 66 std::vector<llvm::Value *> llvm_args;
355 66 const std::vector<size_t> & operands = operation.get_operands();;
356
2/2
✓ Branch 1 taken 52 times.
✓ Branch 2 taken 66 times.
118 for (size_t i = 0; i < operands.size()-1; i++) {
357 52 llvm::Value *llvm_arg = tmp_values[operands.at(i+1)];
358 52 llvm_args.push_back(llvm_arg);
359 }
360 66 const Type *mir_type = mir_function.tmpvar_get(function_operand);
361 66 llvm::Type *llvm_fptr_type = types[mir_type->get_name()];
362
363 66 Builder->CreateCall((llvm::FunctionType*)llvm_fptr_type, (llvm::Function*)llvm_function, llvm_args);
364
365 66 }
366
367 void
368 66 CodeGeneratorLLVMContext::generate_operation_symbol(
369 std::map<size_t, llvm::Value *> & tmp_values,
370 const Gyoji::mir::Function & mir_function,
371 const Gyoji::mir::OperationSymbol & operation
372 )
373 {
374 66 std::string symbol_name = operation.get_symbol_name();
375 66 const Gyoji::mir::Symbol *symbol = mir.get_symbols().get_symbol(symbol_name);
376
377 66 llvm::Type *fptr_type = types[symbol->get_type()->get_name()];
378
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 if (fptr_type == nullptr) {
379 fprintf(stderr, "Could not find function pointer type for %s\n", symbol->get_type()->get_name().c_str());
380 exit(1);
381 }
382
383 // TODO : We handle functions here,
384 // but we should also handle global variables
385 // when we get to it, even though globals
386 // and statics are evil incarnate.
387
388 66 llvm::Function *F = TheModule->getFunction(symbol_name);
389
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 26 times.
66 if (F == nullptr) {
390 40 F = llvm::Function::Create((llvm::FunctionType*)fptr_type, llvm::Function::ExternalLinkage, symbol_name, TheModule.get());
391
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (F == nullptr) {
392 fprintf(stderr, "Could not find function for symbol %s\n", symbol_name.c_str());
393 exit(1);
394 }
395 }
396
397 66 tmp_values.insert(std::pair(operation.get_result(), F));
398 66 }
399
400 // Cast operations
401 void
402 136 CodeGeneratorLLVMContext::generate_operation_widen_numeric(
403 std::map<size_t, llvm::Value *> & tmp_values,
404 const Gyoji::mir::Function & mir_function,
405 const Gyoji::mir::OperationCast & operation
406 )
407 {
408 136 size_t a = operation.get_a();
409 136 const Gyoji::mir::Type *atype = mir_function.tmpvar_get(a);
410
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 136 times.
136 if (!atype->is_numeric()) {
411 compiler_context
412 .get_errors()
413 .add_simple_error(
414 operation.get_source_ref(),
415 "Compiler bug! Invalid operand for add operator.",
416 std::string("Invalid operands for add operation. Operand must be a numeric type, but were ") + atype->get_name()
417 );
418 return;
419 }
420 136 llvm::Value *value_a = tmp_values[a];
421 136 llvm::Type *llvm_cast_type = types[operation.get_cast_type()->get_name()];
422
2/2
✓ Branch 1 taken 120 times.
✓ Branch 2 taken 16 times.
136 if (atype->is_integer()) {
423 120 llvm::Value *sum = Builder->CreateIntCast(value_a, llvm_cast_type, atype->is_signed());
424 120 tmp_values.insert(std::pair(operation.get_result(), sum));
425 }
426 else {
427 16 llvm::Value *sum = Builder->CreateFPCast(value_a, llvm_cast_type);
428 16 tmp_values.insert(std::pair(operation.get_result(), sum));
429 }
430 }
431
432 // Indirect access
433 void
434 10 CodeGeneratorLLVMContext::generate_operation_array_index(
435 std::map<size_t, llvm::Value *> & tmp_values,
436 std::map<size_t, llvm::Value *> & tmp_lvalues,
437 const Gyoji::mir::Function & mir_function,
438 const Gyoji::mir::OperationArrayIndex & operation
439 )
440 {
441 10 size_t array_tmpvar = operation.get_a();
442 10 size_t index_tmpvar = operation.get_b();
443
444 10 const Gyoji::mir::Type *mir_array_type = mir_function.tmpvar_get(array_tmpvar);
445 10 const Gyoji::mir::Type *mir_array_element_type = mir_array_type->get_pointer_target();
446 10 llvm::Type *llvm_array_type = types[mir_array_type->get_name()];
447 10 llvm::Type *llvm_array_element_type = types[mir_array_element_type->get_name()];
448
449 10 llvm::Value *array_lvalue = tmp_lvalues[array_tmpvar];
450 10 llvm::Value *index_value = tmp_values[index_tmpvar];
451
452 10 std::vector<llvm::Value *> indices;
453 10 indices.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(*TheContext), 0L));
454 10 indices.push_back(index_value);
455 10 llvm::Value *addressofelement = Builder->CreateInBoundsGEP(llvm_array_type, array_lvalue, indices);
456 10 llvm::Value *value = Builder->CreateLoad(llvm_array_element_type, addressofelement);
457
458 10 tmp_lvalues.insert(std::pair(operation.get_result(), addressofelement));
459 10 tmp_values.insert(std::pair(operation.get_result(), value));
460 10 }
461 void
462 12 CodeGeneratorLLVMContext::generate_operation_dot(
463 std::map<size_t, llvm::Value *> & tmp_values,
464 std::map<size_t, llvm::Value *> & tmp_lvalues,
465 const Gyoji::mir::Function & mir_function,
466 const Gyoji::mir::OperationDot & operation
467 )
468 {
469 12 size_t a = operation.get_a();
470 // The type is a class
471 12 const Gyoji::mir::Type *mir_class_type = mir_function.tmpvar_get(a);
472 12 llvm::Type *llvm_class_type = types[mir_class_type->get_name()];
473
474 12 const std::string & member_name = operation.get_member_name();
475 12 const TypeMember *member = mir_class_type->member_get(member_name);
476 12 size_t member_index = member->get_index();
477
478 12 llvm::Value *value_a = tmp_lvalues[a];
479 12 llvm::Value *result = Builder->CreateConstInBoundsGEP2_32(llvm_class_type, value_a, 0, member_index);
480 12 llvm::Value *value = Builder->CreateLoad(types[member->get_type()->get_name()], result);
481
482 12 tmp_lvalues.insert(std::pair(operation.get_result(), result));
483 12 tmp_values.insert(std::pair(operation.get_result(), value));
484 12 }
485
486 // Variable access
487 void
488 1180 CodeGeneratorLLVMContext::generate_operation_local_variable(
489 std::map<size_t, llvm::Value *> & tmp_values,
490 std::map<size_t, llvm::Value *> & tmp_lvalues,
491 const Gyoji::mir::Function & mir_function,
492 const Gyoji::mir::OperationLocalVariable & operation
493 )
494 {
495 1180 llvm::Type *type = types[operation.get_var_type()->get_name()];
496 1180 llvm::Value *variable_ptr = local_variables[operation.get_symbol_name()];
497 1180 llvm::Value *value = Builder->CreateLoad(type, variable_ptr);
498 1180 tmp_lvalues.insert(std::pair(operation.get_result(), variable_ptr));
499 1180 tmp_values.insert(std::pair(operation.get_result(), value));
500 1180 }
501 void
502 310 CodeGeneratorLLVMContext::generate_operation_local_declare(
503 std::map<size_t, llvm::Value *> & tmp_values,
504 const Gyoji::mir::Function & mir_function,
505 const Gyoji::mir::OperationLocalDeclare & operation
506 )
507 {
508 310 llvm::Type *type = types[operation.get_variable_type()->get_name()];
509 310 llvm::Value *value = Builder->CreateAlloca(type, nullptr, operation.get_variable());
510 310 local_variables[operation.get_variable()] = value;
511 310 }
512 void
513 906 CodeGeneratorLLVMContext::generate_operation_local_undeclare(
514 std::map<size_t, llvm::Value *> & tmp_values,
515 const Gyoji::mir::Function & mir_function,
516 const Gyoji::mir::OperationLocalUndeclare & operation
517 )
518 906 { /* There's nothing to implement here, this is just an MIR thing. */ }
519
520 // Literals
521 void
522 8 CodeGeneratorLLVMContext::generate_operation_literal_char(
523 std::map<size_t, llvm::Value *> & tmp_values,
524 const Gyoji::mir::Function & mir_function,
525 const Gyoji::mir::OperationLiteralChar & operation
526 )
527 {
528 8 char c = operation.get_literal_char();
529 8 llvm::Value * result = llvm::ConstantInt::get(llvm::Type::getInt8Ty(*TheContext), c);
530 8 tmp_values.insert(std::pair(operation.get_result(), result));
531 8 }
532 void
533 10 CodeGeneratorLLVMContext::generate_operation_literal_string(
534 std::map<size_t, llvm::Value *> & tmp_values,
535 const Gyoji::mir::Function & mir_function,
536 const Gyoji::mir::OperationLiteralString & operation
537 )
538 {
539 10 llvm::Constant *string_constant = llvm::ConstantDataArray::getString(*TheContext, operation.get_literal_string());
540 llvm::GlobalVariable* v = new llvm::GlobalVariable(
541 10 *TheModule,
542 string_constant->getType(),
543 true,
544 llvm::GlobalValue::InternalLinkage,
545 string_constant
546 20 );
547
548 10 tmp_values.insert(std::pair(operation.get_result(), v));
549 10 }
550 void
551 222 CodeGeneratorLLVMContext::generate_operation_literal_int(
552 std::map<size_t, llvm::Value *> & tmp_values,
553 const Gyoji::mir::Function & mir_function,
554 const Gyoji::mir::OperationLiteralInt & operation
555 )
556 {
557 llvm::Value *value;
558
8/9
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 146 times.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 10 times.
✓ Branch 6 taken 6 times.
✓ Branch 7 taken 8 times.
✓ Branch 8 taken 10 times.
✗ Branch 9 not taken.
222 switch (operation.get_literal_type()) {
559 10 case Type::TYPE_PRIMITIVE_u8:
560 {
561 10 value = Builder->getInt8(operation.get_literal_u8());
562 }
563 10 break;
564 14 case Type::TYPE_PRIMITIVE_u16:
565 {
566 14 value = Builder->getInt16(operation.get_literal_u16());
567 }
568 14 break;
569 146 case Type::TYPE_PRIMITIVE_u32:
570 {
571 146 value = Builder->getInt32(operation.get_literal_u32());
572 }
573 146 break;
574 18 case Type::TYPE_PRIMITIVE_u64:
575 {
576 18 value = Builder->getInt64(operation.get_literal_u64());
577 }
578 18 break;
579 10 case Type::TYPE_PRIMITIVE_i8:
580 {
581 10 value = Builder->getInt8(operation.get_literal_i8());
582 }
583 10 break;
584 6 case Type::TYPE_PRIMITIVE_i16:
585 {
586 6 value = Builder->getInt16(operation.get_literal_i16());
587 }
588 6 break;
589 8 case Type::TYPE_PRIMITIVE_i32:
590 {
591 8 value = Builder->getInt32(operation.get_literal_i32());
592 }
593 8 break;
594 10 case Type::TYPE_PRIMITIVE_i64:
595 {
596 10 value = Builder->getInt64(operation.get_literal_i64());
597 }
598 10 break;
599 default:
600 compiler_context
601 .get_errors()
602 .add_simple_error(
603 operation.get_source_ref(),
604 "Compiler bug! Invalid operand for literal int.",
605 std::string("Literal int has unknown type") + std::to_string(operation.get_literal_type())
606 );
607 return;
608 }
609 222 tmp_values.insert(std::pair(operation.get_result(), value));
610 }
611 void
612 6 CodeGeneratorLLVMContext::generate_operation_literal_float(
613 std::map<size_t, llvm::Value *> & tmp_values,
614 const Gyoji::mir::Function & mir_function,
615 const Gyoji::mir::OperationLiteralFloat & operation
616 )
617 {
618
2/3
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
6 switch (operation.get_literal_type()) {
619 2 case Type::TYPE_PRIMITIVE_f32:
620 {
621 2 llvm::Type* llvm_type = llvm::Type::getFloatTy(*TheContext);
622 2 llvm::Value * result = llvm::ConstantFP::get(llvm_type, operation.get_literal_float());
623 2 tmp_values.insert(std::pair(operation.get_result(), result));
624 }
625 2 break;
626 4 case Type::TYPE_PRIMITIVE_f64:
627 {
628 4 llvm::Type *llvm_type = llvm::Type::getDoubleTy(*TheContext);
629 4 llvm::Value * result = llvm::ConstantFP::get(llvm_type, operation.get_literal_double());
630 4 tmp_values.insert(std::pair(operation.get_result(), result));
631 }
632 4 break;
633 default:
634 compiler_context
635 .get_errors()
636 .add_simple_error(
637 operation.get_source_ref(),
638 "Compiler bug! Invalid operand for literal float.",
639 std::string("Literal float has unknown type") + std::to_string(operation.get_literal_type())
640 );
641 return;
642 }
643 }
644
645 void
646 CodeGeneratorLLVMContext::generate_operation_literal_bool(
647 std::map<size_t, llvm::Value *> & tmp_values,
648 const Gyoji::mir::Function & mir_function,
649 const Gyoji::mir::OperationLiteralBool & operation
650 )
651 {
652 llvm::Value * result = llvm::ConstantInt::get(llvm::Type::getInt32Ty(*TheContext), operation.get_literal_bool() ? 1 : 0);
653 tmp_values.insert(std::pair(operation.get_result(), result));
654 }
655 void
656 CodeGeneratorLLVMContext::generate_operation_literal_null(
657 std::map<size_t, llvm::Value *> & tmp_values,
658 const Gyoji::mir::Function & mir_function,
659 const Gyoji::mir::OperationLiteralNull & operation
660 )
661 {
662 llvm::Type * llvm_void_type = create_type(mir.get_types().get_type("u8"));
663 llvm::PointerType * llvm_voidstar_type =
664 llvm::PointerType::get(llvm_void_type,
665 0 // Address space (default to 0? This seems unclean, llvm!)
666 );
667 llvm::Value *result = llvm::ConstantPointerNull::get(llvm_voidstar_type);
668 tmp_values.insert(std::pair(operation.get_result(), result));
669 }
670
671
672 // Unary operations
673 void
674 8 CodeGeneratorLLVMContext::generate_operation_addressof(
675 std::map<size_t, llvm::Value *> & tmp_values,
676 std::map<size_t, llvm::Value *> & tmp_lvalues,
677 const Gyoji::mir::Function & mir_function,
678 const Gyoji::mir::OperationUnary & operation
679 )
680 {
681 // The type is a class
682 8 const auto & found = tmp_lvalues.find(operation.get_a());
683
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
8 if (found == tmp_lvalues.end()) {
684 fprintf(stderr, "This is not an lvalue\n");
685 exit(2);
686 }
687 // Addressof returns a value (a pointer value)
688 // but itself is not an lvalue because it cannot
689 // be assigned to.
690 8 tmp_values.insert(std::pair(operation.get_result(), found->second));
691 8 }
692
693 void
694 12 CodeGeneratorLLVMContext::generate_operation_dereference(
695 std::map<size_t, llvm::Value *> & tmp_values,
696 std::map<size_t, llvm::Value *> & tmp_lvalues,
697 const Gyoji::mir::Function & mir_function,
698 const Gyoji::mir::OperationUnary & operation
699 )
700 {
701
702 12 size_t a = operation.get_a();
703 // The type is a class
704 12 const Gyoji::mir::Type *mir_pointer_type = mir_function.tmpvar_get(a);
705
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 if (!mir_pointer_type->is_pointer()) {
706 fprintf(stderr, "Address of thing being referenced is not a pointer\n");
707 exit(1);
708 }
709 12 const Gyoji::mir::Type *mir_pointer_target = mir_pointer_type->get_pointer_target();
710 12 llvm::Type *llvm_pointer_target = types[mir_pointer_target->get_name()];
711
712 12 llvm::Value *value_a = tmp_values[a];
713 12 llvm::Value *result = Builder->CreateLoad(llvm_pointer_target, value_a);
714
715 12 tmp_lvalues.insert(std::pair(operation.get_result(), value_a));
716 12 tmp_values.insert(std::pair(operation.get_result(), result));
717 12 }
718
719 void
720 CodeGeneratorLLVMContext::generate_operation_arithmetic_negate(
721 std::map<size_t, llvm::Value *> & tmp_values,
722 const Gyoji::mir::Function & mir_function,
723 const Gyoji::mir::OperationUnary & operation
724 )
725 {
726 size_t a = operation.get_a();
727 const Gyoji::mir::Type *atype = mir_function.tmpvar_get(a);
728 if (!atype->is_signed()) {
729 compiler_context
730 .get_errors()
731 .add_simple_error(
732 operation.get_source_ref(),
733 "Compiler bug! Invalid operand arithmetic negate",
734 std::string("Operand to arithmetic negate must be a signed integer but was ") + atype->get_name()
735 );
736 return;
737 }
738
739 llvm::Value * avalue = tmp_values[a];
740 llvm::Value * result = Builder->CreateNeg(avalue);
741 tmp_values.insert(std::pair(operation.get_result(), result));
742 }
743 void
744 CodeGeneratorLLVMContext::generate_operation_bitwise_not(
745 std::map<size_t, llvm::Value *> & tmp_values,
746 const Gyoji::mir::Function & mir_function,
747 const Gyoji::mir::OperationUnary & operation
748 )
749 {
750 size_t a = operation.get_a();
751 const Gyoji::mir::Type *atype = mir_function.tmpvar_get(a);
752 if (!atype->is_unsigned()) {
753 compiler_context
754 .get_errors()
755 .add_simple_error(
756 operation.get_source_ref(),
757 "Compiler bug! Invalid operand bitwise not",
758 std::string("Operand to bitwise not must be an unsigned integer but was ") + atype->get_name()
759 );
760 return;
761 }
762
763 llvm::Value * avalue = tmp_values[a];
764 llvm::Value * result = Builder->CreateNot(avalue);
765 tmp_values.insert(std::pair(operation.get_result(), result));
766 }
767
768 void
769 2 CodeGeneratorLLVMContext::generate_operation_logical_not(
770 std::map<size_t, llvm::Value *> & tmp_values,
771 const Gyoji::mir::Function & mir_function,
772 const Gyoji::mir::OperationUnary & operation
773 )
774 {
775 2 size_t a = operation.get_a();
776 2 const Gyoji::mir::Type *atype = mir_function.tmpvar_get(a);
777
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (!atype->is_bool()) {
778 compiler_context
779 .get_errors()
780 .add_simple_error(
781 operation.get_source_ref(),
782 "Compiler bug! Invalid operand logical not",
783 std::string("Operand to logical not must be a bool but was ") + atype->get_name()
784 );
785 return;
786 }
787
788 2 llvm::Value * avalue = tmp_values[a];
789 2 llvm::Value * result = Builder->CreateNot(avalue);
790 2 tmp_values.insert(std::pair(operation.get_result(), result));
791 }
792
793 void
794 8 CodeGeneratorLLVMContext::generate_operation_sizeof_type(
795 std::map<size_t, llvm::Value *> & tmp_values,
796 std::map<size_t, llvm::Value *> & tmp_lvalues,
797 const Gyoji::mir::Function & mir_function,
798 const Gyoji::mir::OperationSizeofType & operation
799 )
800 {
801 8 llvm::Type *llvm_type = types[operation.get_type()->get_name()];
802 8 llvm::Value * result = llvm::ConstantInt::get(llvm::Type::getInt64Ty(*TheContext), TheModule->getDataLayout().getTypeAllocSize(llvm_type));
803 8 tmp_values.insert(std::pair(operation.get_result(), result));
804 8 }
805
806
807 // Binary operations: arithmetic
808 void
809 60 CodeGeneratorLLVMContext::generate_operation_add(
810 std::map<size_t, llvm::Value *> & tmp_values,
811 const Gyoji::mir::Function & mir_function,
812 const Gyoji::mir::OperationBinary & operation
813 )
814 {
815 60 size_t a = operation.get_a();
816 60 size_t b = operation.get_b();
817 60 const Gyoji::mir::Type *atype = mir_function.tmpvar_get(a);
818 60 const Gyoji::mir::Type *btype = mir_function.tmpvar_get(b);
819
3/6
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 60 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 60 times.
60 if (!atype->is_numeric() || !btype->is_numeric()) {
820 compiler_context
821 .get_errors()
822 .add_simple_error(
823 operation.get_source_ref(),
824 "Compiler bug! Invalid operand for add operator.",
825 std::string("Invalid operands for add operation. Operand must be a numeric type, but were ") + atype->get_name() + std::string(" and ") + btype->get_name()
826 );
827 return;
828 }
829 60 llvm::Value *value_a = tmp_values[a];
830 60 llvm::Value *value_b = tmp_values[b];
831
832
5/6
✓ Branch 1 taken 52 times.
✓ Branch 2 taken 8 times.
✓ Branch 4 taken 52 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 52 times.
✓ Branch 7 taken 8 times.
60 if (atype->is_integer() && btype->is_integer()) {
833 52 llvm::Value *sum = Builder->CreateAdd(value_a, value_b);
834 52 tmp_values.insert(std::pair(operation.get_result(), sum));
835 }
836
3/6
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
8 else if (atype->is_float() && btype->is_float()) {
837 8 llvm::Value *sum = Builder->CreateFAdd(value_a, value_b);
838 8 tmp_values.insert(std::pair(operation.get_result(), sum));
839 }
840 else {
841 compiler_context
842 .get_errors()
843 .add_simple_error(
844 operation.get_source_ref(),
845 "Compiler bug! Invalid operand for add operator.",
846 std::string("Operands must be both integer or floating-point primitive types but were ") + atype->get_name() + std::string(" and ") + btype->get_name()
847 );
848 return;
849 }
850 }
851
852 void
853 48 CodeGeneratorLLVMContext::generate_operation_subtract(
854 std::map<size_t, llvm::Value *> & tmp_values,
855 const Gyoji::mir::Function & mir_function,
856 const Gyoji::mir::OperationBinary & operation
857 )
858 {
859 48 size_t a = operation.get_a();
860 48 size_t b = operation.get_b();
861 48 const Gyoji::mir::Type *atype = mir_function.tmpvar_get(a);
862 48 const Gyoji::mir::Type *btype = mir_function.tmpvar_get(b);
863
3/6
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 48 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 48 times.
48 if (!atype->is_numeric() || !btype->is_numeric()) {
864 compiler_context
865 .get_errors()
866 .add_simple_error(
867 operation.get_source_ref(),
868 "Compiler bug! Invalid operand for subtract operator.",
869 std::string("Invalid operands for subtract operation. Operand must be a numeric type, but were ") + atype->get_name() + std::string(" and ") + btype->get_name()
870 );
871 return;
872 }
873 48 llvm::Value *value_a = tmp_values[a];
874 48 llvm::Value *value_b = tmp_values[b];
875
876
5/6
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 8 times.
✓ Branch 4 taken 40 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 40 times.
✓ Branch 7 taken 8 times.
48 if (atype->is_integer() && btype->is_integer()) {
877 40 llvm::Value *sum = Builder->CreateSub(value_a, value_b);
878 40 tmp_values.insert(std::pair(operation.get_result(), sum));
879 }
880
3/6
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
8 else if (atype->is_float() && btype->is_float()) {
881 8 llvm::Value *sum = Builder->CreateFSub(value_a, value_b);
882 8 tmp_values.insert(std::pair(operation.get_result(), sum));
883 }
884 else {
885 compiler_context
886 .get_errors()
887 .add_simple_error(
888 operation.get_source_ref(),
889 "Compiler bug! Invalid operand for subtract operator.",
890 std::string("Operands must be both integer or both floating-point but were ") + atype->get_name() + std::string(" and ") + btype->get_name()
891 );
892 return;
893 }
894 }
895
896 void
897 48 CodeGeneratorLLVMContext::generate_operation_multiply(
898 std::map<size_t, llvm::Value *> & tmp_values,
899 const Gyoji::mir::Function & mir_function,
900 const Gyoji::mir::OperationBinary & operation
901 )
902 {
903 48 size_t a = operation.get_a();
904 48 size_t b = operation.get_b();
905 48 const Gyoji::mir::Type *atype = mir_function.tmpvar_get(a);
906 48 const Gyoji::mir::Type *btype = mir_function.tmpvar_get(b);
907
3/6
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 48 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 48 times.
48 if (!atype->is_numeric() || !atype->is_numeric()) {
908 compiler_context
909 .get_errors()
910 .add_simple_error(
911 operation.get_source_ref(),
912 "Compiler bug! Invalid operand for add operator.",
913 std::string("Invalid operands for add operation. Operand must be a numeric type, but were ") + atype->get_name() + std::string(" and ") + btype->get_name()
914 );
915 return;
916 }
917 48 llvm::Value *value_a = tmp_values[a];
918 48 llvm::Value *value_b = tmp_values[b];
919
920
5/6
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 8 times.
✓ Branch 4 taken 40 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 40 times.
✓ Branch 7 taken 8 times.
48 if (atype->is_integer() && atype->is_integer()) {
921 40 llvm::Value *sum = Builder->CreateMul(value_a, value_b);
922 40 tmp_values.insert(std::pair(operation.get_result(), sum));
923 }
924
3/6
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
8 else if (atype->is_float() && atype->is_float()) {
925 8 llvm::Value *sum = Builder->CreateFMul(value_a, value_b);
926 8 tmp_values.insert(std::pair(operation.get_result(), sum));
927 }
928 else {
929 compiler_context
930 .get_errors()
931 .add_simple_error(
932 operation.get_source_ref(),
933 "Compiler bug! Invalid operand for add operator.",
934 std::string("Operands must be both integer or floating-point primitive types but were ") + atype->get_name() + std::string(" and ") + btype->get_name()
935 );
936 return;
937 }
938 }
939
940 void
941 48 CodeGeneratorLLVMContext::generate_operation_divide(
942 std::map<size_t, llvm::Value *> & tmp_values,
943 const Gyoji::mir::Function & mir_function,
944 const Gyoji::mir::OperationBinary & operation
945 )
946 {
947 48 size_t a = operation.get_a();
948 48 size_t b = operation.get_b();
949 48 const Gyoji::mir::Type *atype = mir_function.tmpvar_get(a);
950 48 const Gyoji::mir::Type *btype = mir_function.tmpvar_get(b);
951
3/6
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 48 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 48 times.
48 if (!atype->is_numeric() || !btype->is_numeric()) {
952 compiler_context
953 .get_errors()
954 .add_simple_error(
955 operation.get_source_ref(),
956 "Compiler bug! Invalid operand for divide operator.",
957 std::string("Invalid operands for divide operation. Operand must be a numeric type, but were ") + atype->get_name() + std::string(" and ") + btype->get_name()
958 );
959 return;
960 }
961 48 llvm::Value *value_a = tmp_values[a];
962 48 llvm::Value *value_b = tmp_values[b];
963
964
5/6
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 8 times.
✓ Branch 4 taken 40 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 40 times.
✓ Branch 7 taken 8 times.
48 if (atype->is_integer() && atype->is_integer()) {
965
5/6
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 20 times.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 20 times.
✓ Branch 7 taken 20 times.
40 if (atype->is_signed() && btype->is_signed()) {
966 20 llvm::Value *sum = Builder->CreateSDiv(value_a, value_b);
967 20 tmp_values.insert(std::pair(operation.get_result(), sum));
968 }
969
3/6
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 20 times.
✗ Branch 7 not taken.
20 else if (atype->is_unsigned() && btype->is_unsigned()) {
970 20 llvm::Value *sum = Builder->CreateUDiv(value_a, value_b);
971 20 tmp_values.insert(std::pair(operation.get_result(), sum));
972 }
973 else {
974 compiler_context
975 .get_errors()
976 .add_simple_error(
977 operation.get_source_ref(),
978 "Compiler bug! Invalid operand for divide operator.",
979 std::string("Operands must be both signed or unsigned integers but were ") + atype->get_name() + std::string(" and ") + btype->get_name()
980 );
981 }
982 }
983
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 else if (atype->is_float()) {
984 8 llvm::Value *sum = Builder->CreateFDiv(value_a, value_b);
985 8 tmp_values.insert(std::pair(operation.get_result(), sum));
986 }
987 else {
988 compiler_context
989 .get_errors()
990 .add_simple_error(
991 operation.get_source_ref(),
992 "Compiler bug! Invalid operand for divide operator.",
993 std::string("Operands must be integer or floating-point primitive types but were ") + atype->get_name() + std::string(" and ") + btype->get_name()
994 );
995 return;
996 }
997 }
998 void
999 42 CodeGeneratorLLVMContext::generate_operation_modulo(
1000 std::map<size_t, llvm::Value *> & tmp_values,
1001 const Gyoji::mir::Function & mir_function,
1002 const Gyoji::mir::OperationBinary & operation
1003 )
1004 {
1005 42 size_t a = operation.get_a();
1006 42 size_t b = operation.get_b();
1007 42 const Gyoji::mir::Type *atype = mir_function.tmpvar_get(a);
1008 42 const Gyoji::mir::Type *btype = mir_function.tmpvar_get(b);
1009
3/6
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 42 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 42 times.
42 if (!atype->is_integer() || !btype->is_integer()) {
1010 compiler_context
1011 .get_errors()
1012 .add_simple_error(
1013 operation.get_source_ref(),
1014 "Compiler bug! Invalid operand for modulo operator.",
1015 std::string("Invalid operands for modulo operation. Operand must be a integer type, but were ") + atype->get_name() + std::string(" and ") + btype->get_name()
1016 );
1017 return;
1018 }
1019 42 llvm::Value *value_a = tmp_values[a];
1020 42 llvm::Value *value_b = tmp_values[b];
1021
1022
5/6
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 22 times.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 20 times.
✓ Branch 7 taken 22 times.
42 if (atype->is_signed() && btype->is_signed()) {
1023 20 llvm::Value *sum = Builder->CreateSRem(value_a, value_b);
1024 20 tmp_values.insert(std::pair(operation.get_result(), sum));
1025 }
1026
3/6
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 22 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 22 times.
✗ Branch 7 not taken.
22 else if (atype->is_unsigned() && btype->is_unsigned()) {
1027 22 llvm::Value *sum = Builder->CreateURem(value_a, value_b);
1028 22 tmp_values.insert(std::pair(operation.get_result(), sum));
1029 }
1030 else {
1031 compiler_context
1032 .get_errors()
1033 .add_simple_error(
1034 operation.get_source_ref(),
1035 "Compiler bug! Invalid operand for modulo operator.",
1036 std::string("Invalid operands for modulo operation. Operand must be a both signed or both unsigned, but were ") +
1037 atype->get_name() + std::string(" and ") + btype->get_name()
1038 );
1039 }
1040 }
1041
1042 // Binary operations: logical
1043 void
1044 CodeGeneratorLLVMContext::generate_operation_logical_and(
1045 std::map<size_t, llvm::Value *> & tmp_values,
1046 const Gyoji::mir::Function & mir_function,
1047 const Gyoji::mir::OperationBinary & operation
1048 )
1049 {
1050 size_t a = operation.get_a();
1051 size_t b = operation.get_b();
1052 const Gyoji::mir::Type *atype = mir_function.tmpvar_get(a);
1053 const Gyoji::mir::Type *btype = mir_function.tmpvar_get(b);
1054 if (!atype->is_bool() || !btype->is_bool()) {
1055 compiler_context
1056 .get_errors()
1057 .add_simple_error(
1058 operation.get_source_ref(),
1059 "Compiler bug! Invalid operand for logical and operator.",
1060 std::string("Invalid operands for and operation. Operand must be a bool type, but were ") + atype->get_name() + std::string(" and ") + btype->get_name()
1061 );
1062 return;
1063 }
1064 llvm::Value *value_a = tmp_values[a];
1065 llvm::Value *value_b = tmp_values[b];
1066
1067 llvm::Value *sum = Builder->CreateAnd(value_a, value_b);
1068 tmp_values.insert(std::pair(operation.get_result(), sum));
1069
1070 }
1071
1072 void
1073 CodeGeneratorLLVMContext::generate_operation_logical_or(
1074 std::map<size_t, llvm::Value *> & tmp_values,
1075 const Gyoji::mir::Function & mir_function,
1076 const Gyoji::mir::OperationBinary & operation
1077 )
1078 {
1079 size_t a = operation.get_a();
1080 size_t b = operation.get_b();
1081 const Gyoji::mir::Type *atype = mir_function.tmpvar_get(a);
1082 const Gyoji::mir::Type *btype = mir_function.tmpvar_get(b);
1083 if (!atype->is_bool() || !btype->is_bool()) {
1084 compiler_context
1085 .get_errors()
1086 .add_simple_error(
1087 operation.get_source_ref(),
1088 "Compiler bug! Invalid operand for logical or operator.",
1089 std::string("Invalid operands for logical or operation. Operands must be bool, but were ") + atype->get_name() + std::string(" and ") + btype->get_name()
1090 );
1091 return;
1092 }
1093 llvm::Value *value_a = tmp_values[a];
1094 llvm::Value *value_b = tmp_values[b];
1095
1096 llvm::Value *sum = Builder->CreateOr(value_a, value_b);
1097 tmp_values.insert(std::pair(operation.get_result(), sum));
1098 }
1099
1100
1101 // Binary operations: bitwise
1102 void
1103 CodeGeneratorLLVMContext::generate_operation_bitwise_and(
1104 std::map<size_t, llvm::Value *> & tmp_values,
1105 const Gyoji::mir::Function & mir_function,
1106 const Gyoji::mir::OperationBinary & operation
1107 )
1108 {
1109 size_t a = operation.get_a();
1110 size_t b = operation.get_b();
1111 const Gyoji::mir::Type *atype = mir_function.tmpvar_get(a);
1112 const Gyoji::mir::Type *btype = mir_function.tmpvar_get(b);
1113 if (!atype->is_unsigned() || !btype->is_unsigned()) {
1114 compiler_context
1115 .get_errors()
1116 .add_simple_error(
1117 operation.get_source_ref(),
1118 "Compiler bug! Invalid operand for bitwise and operator.",
1119 std::string("Invalid operands for logical and operation. Operands must be unsigned, but were ") + atype->get_name() + std::string(" and ") + btype->get_name()
1120 );
1121 return;
1122 }
1123 llvm::Value *value_a = tmp_values[a];
1124 llvm::Value *value_b = tmp_values[b];
1125
1126 llvm::Value *sum = Builder->CreateAnd(value_a, value_b);
1127 tmp_values.insert(std::pair(operation.get_result(), sum));
1128 }
1129
1130 void
1131 CodeGeneratorLLVMContext::generate_operation_bitwise_or(
1132 std::map<size_t, llvm::Value *> & tmp_values,
1133 const Gyoji::mir::Function & mir_function,
1134 const Gyoji::mir::OperationBinary & operation
1135 )
1136 {
1137 size_t a = operation.get_a();
1138 size_t b = operation.get_b();
1139 const Gyoji::mir::Type *atype = mir_function.tmpvar_get(a);
1140 const Gyoji::mir::Type *btype = mir_function.tmpvar_get(b);
1141 if (!atype->is_unsigned() || !btype->is_unsigned()) {
1142 compiler_context
1143 .get_errors()
1144 .add_simple_error(
1145 operation.get_source_ref(),
1146 "Compiler bug! Invalid operand for bitwise or operator.",
1147 std::string("Invalid operands for logical or operation. Operands must be unsigned, but were ") + atype->get_name() + std::string(" and ") + btype->get_name()
1148 );
1149 return;
1150 }
1151 llvm::Value *value_a = tmp_values[a];
1152 llvm::Value *value_b = tmp_values[b];
1153
1154 llvm::Value *sum = Builder->CreateOr(value_a, value_b);
1155 tmp_values.insert(std::pair(operation.get_result(), sum));
1156 }
1157
1158 void
1159 CodeGeneratorLLVMContext::generate_operation_bitwise_xor(
1160 std::map<size_t, llvm::Value *> & tmp_values,
1161 const Gyoji::mir::Function & mir_function,
1162 const Gyoji::mir::OperationBinary & operation
1163 )
1164 {
1165 size_t a = operation.get_a();
1166 size_t b = operation.get_b();
1167 const Gyoji::mir::Type *atype = mir_function.tmpvar_get(a);
1168 const Gyoji::mir::Type *btype = mir_function.tmpvar_get(b);
1169 if (!atype->is_unsigned() || !btype->is_unsigned()) {
1170 compiler_context
1171 .get_errors()
1172 .add_simple_error(
1173 operation.get_source_ref(),
1174 "Compiler bug! Invalid operand for bitwise xor operator.",
1175 std::string("Invalid operands for logical xor operation. Operands must be unsigned, but were ") + atype->get_name() + std::string(" and ") + btype->get_name()
1176 );
1177 return;
1178 }
1179 llvm::Value *value_a = tmp_values[a];
1180 llvm::Value *value_b = tmp_values[b];
1181
1182 llvm::Value *sum = Builder->CreateXor(value_a, value_b);
1183 tmp_values.insert(std::pair(operation.get_result(), sum));
1184 }
1185
1186 void
1187 CodeGeneratorLLVMContext::generate_operation_shift(
1188 std::map<size_t, llvm::Value *> & tmp_values,
1189 const Gyoji::mir::Function & mir_function,
1190 const Gyoji::mir::OperationBinary & operation
1191 )
1192 {
1193 size_t a = operation.get_a();
1194 size_t b = operation.get_b();
1195 const Gyoji::mir::Type *atype = mir_function.tmpvar_get(a);
1196 const Gyoji::mir::Type *btype = mir_function.tmpvar_get(b);
1197 if (!atype->is_unsigned() || !btype->is_unsigned()) {
1198 compiler_context
1199 .get_errors()
1200 .add_simple_error(
1201 operation.get_source_ref(),
1202 "Compiler bug! Invalid operand for bitwise shift left operator.",
1203 std::string("Invalid operands for logical shift left operation. Operands must be unsigned, but were ") + atype->get_name() + std::string(" and ") + btype->get_name()
1204 );
1205 return;
1206 }
1207 llvm::Value *value_a = tmp_values[a];
1208 llvm::Value *value_b = tmp_values[b];
1209
1210 unsigned short mask = 0x07;
1211 size_t a_size = atype->get_primitive_size();
1212 switch (a_size) {
1213 case 8:
1214 mask = 0x07;
1215 break;
1216 case 16:
1217 mask = 0x0f;
1218 break;
1219 case 32:
1220 mask = 0x1f;
1221 break;
1222 case 64:
1223 mask = 0x3f;
1224 break;
1225 default:
1226 compiler_context
1227 .get_errors()
1228 .add_simple_error(
1229 operation.get_source_ref(),
1230 "Compiler bug! Invalid operand for bitwise shift left operator.",
1231 std::string("Invalid operands for logical shift left operation. Left operand must be 8, 16, 32, or 64 bits but operands were ") + atype->get_name() + std::string(" and ") + btype->get_name()
1232 );
1233 return;
1234 }
1235
1236 // Here, if the right-hand argument
1237 // must be less than the number of bits in the
1238 // right hand argument, so in order to make sure
1239 // that's the case, we need to mask the right-hand
1240 // argument appropriately.
1241 llvm::Value *shr_bits_mask = Builder->getInt8(mask);
1242 llvm::Value *shr_bits = Builder->CreateAnd(value_b, shr_bits_mask);
1243 llvm::Value *shifted_value;
1244 if (operation.get_type() == Operation::OP_SHIFT_LEFT) {
1245 shifted_value = Builder->CreateShl(value_a, value_b);
1246 }
1247 else {
1248 shifted_value = Builder->CreateLShr(value_a, shr_bits);
1249 }
1250 tmp_values.insert(std::pair(operation.get_result(), shifted_value));
1251 }
1252
1253 // Binary operations: comparisons
1254 void
1255 38 CodeGeneratorLLVMContext::generate_operation_comparison(
1256 std::map<size_t, llvm::Value *> & tmp_values,
1257 const Gyoji::mir::Function & mir_function,
1258 const Gyoji::mir::OperationBinary & operation
1259 )
1260 {
1261 38 size_t a = operation.get_a();
1262 38 size_t b = operation.get_b();
1263 38 Operation::OperationType type = operation.get_type();
1264
1265 38 const Gyoji::mir::Type *atype = mir_function.tmpvar_get(a);
1266 38 const Gyoji::mir::Type *btype = mir_function.tmpvar_get(b);
1267
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 38 times.
38 if (atype->get_name() != btype->get_name()) {
1268 compiler_context
1269 .get_errors()
1270 .add_simple_error(
1271 operation.get_source_ref(),
1272 "Compiler bug! Invalid operand for comparison operator.",
1273 std::string("Invalid operands for comparison operation. Operands must be the same type, but were ") + atype->get_name() + std::string(" and ") + btype->get_name()
1274 );
1275 return;
1276 }
1277
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 38 times.
38 if (atype->is_void()) {
1278 compiler_context
1279 .get_errors()
1280 .add_simple_error(
1281 operation.get_source_ref(),
1282 "Compiler bug! Invalid operand for comparison operation.",
1283 std::string("The operands of a comparison must not be void, but were: a= ") + atype->get_name() + std::string(" b=") + btype->get_name()
1284 );
1285 return;
1286 }
1287
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 38 times.
38 if (atype->is_composite()) {
1288 compiler_context
1289 .get_errors()
1290 .add_simple_error(
1291 operation.get_source_ref(),
1292 "Compiler bug! Invalid operand for comparison operation.",
1293 std::string("The operands of a comparison must not be composite structures or classes, but were: a= ") + atype->get_name() + std::string(" b=") + btype->get_name()
1294 );
1295 return;
1296 }
1297 38 if (
1298
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 38 times.
76 (atype->is_pointer() || atype->is_reference())
1299
2/6
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 38 times.
76 &&
1300 !(type == Operation::OP_COMPARE_EQUAL ||
1301 type == Operation::OP_COMPARE_NOT_EQUAL)
1302 ) {
1303 compiler_context
1304 .get_errors()
1305 .add_simple_error(
1306 operation.get_source_ref(),
1307 "Compiler bug! Invalid operand for comparison operation.",
1308 std::string("The operands of a comparison of pointers and references may not be used except for equality comparisions, but were: a= ") +
1309 atype->get_name() + std::string(" b=") + btype->get_name()
1310 );
1311 return;
1312 }
1313
1314 38 llvm::Value *value_a = tmp_values[a];
1315 38 llvm::Value *value_b = tmp_values[b];
1316
1317 38 llvm::Value * result = nullptr;
1318
1319
3/7
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 18 times.
✗ Branch 6 not taken.
38 switch (type) {
1320 6 case Operation::OP_COMPARE_LESS:
1321
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (atype->is_float()) {
1322 result = Builder->CreateFCmpULT(value_a, value_b);
1323 }
1324
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 else if (atype->is_signed()) {
1325 result = Builder->CreateICmpSLT(value_a, value_b);
1326 }
1327 else {
1328 6 result = Builder->CreateICmpULT(value_a, value_b);
1329 }
1330 6 break;
1331 case Operation::OP_COMPARE_GREATER:
1332 if (atype->is_float()) {
1333 result = Builder->CreateFCmpUGT(value_a, value_b);
1334 }
1335 else if (atype->is_signed()) {
1336 result = Builder->CreateICmpSGT(value_a, value_b);
1337 }
1338 else {
1339 result = Builder->CreateICmpUGT(value_a, value_b);
1340 }
1341 break;
1342 case Operation::OP_COMPARE_LESS_EQUAL:
1343 if (atype->is_float()) {
1344 result = Builder->CreateFCmpULE(value_a, value_b);
1345 }
1346 else if (atype->is_signed()) {
1347 result = Builder->CreateICmpSLE(value_a, value_b);
1348 }
1349 else {
1350 result = Builder->CreateICmpULE(value_a, value_b);
1351 }
1352 break;
1353 case Operation::OP_COMPARE_GREATER_EQUAL:
1354 if (atype->is_float()) {
1355 result = Builder->CreateFCmpUGE(value_a, value_b);
1356 }
1357 else if (atype->is_signed()) {
1358 result = Builder->CreateICmpSGE(value_a, value_b);
1359 }
1360 else {
1361 result = Builder->CreateICmpUGE(value_a, value_b);
1362 }
1363 break;
1364 14 case Operation::OP_COMPARE_EQUAL:
1365
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
14 if (atype->is_float()) {
1366 result = Builder->CreateFCmpUEQ(value_a, value_b);
1367 }
1368 else {
1369 14 result = Builder->CreateICmpEQ(value_a, value_b);
1370 }
1371 14 break;
1372 18 case Operation::OP_COMPARE_NOT_EQUAL:
1373
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
18 if (atype->is_float()) {
1374 result = Builder->CreateFCmpUNE(value_a, value_b);
1375 }
1376 else {
1377 18 result = Builder->CreateICmpNE(value_a, value_b);
1378 }
1379 18 break;
1380 default:
1381 compiler_context
1382 .get_errors()
1383 .add_simple_error(
1384 operation.get_source_ref(),
1385 "Compiler bug! Invalid operand for comparison operation.",
1386 std::string("Unknown operand type")
1387 );
1388 }
1389 38 tmp_values.insert(std::pair(operation.get_result(), result));
1390 }
1391
1392 // Binary operations: assignments
1393 void
1394 386 CodeGeneratorLLVMContext::generate_operation_assign(
1395 std::map<size_t, llvm::Value *> & tmp_values,
1396 std::map<size_t, llvm::Value *> & tmp_lvalues,
1397 const Gyoji::mir::Function & mir_function,
1398 const Gyoji::mir::OperationBinary & operation
1399 )
1400 {
1401 386 llvm::Value *lvalue = tmp_lvalues[operation.get_a()];
1402 386 llvm::Value *value_b = tmp_values[operation.get_b()];
1403 386 llvm::Value *b_value = Builder->CreateStore(value_b, lvalue);
1404
1405 // TODO: Assigning an lvalue results in an lvalue.
1406 386 const auto & b_lvalue = tmp_lvalues.find(operation.get_b());
1407
2/2
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 380 times.
386 if (b_lvalue != tmp_lvalues.end()) {
1408 6 tmp_lvalues.insert(std::pair(operation.get_result(), b_lvalue->second));
1409 }
1410
1411 386 tmp_values.insert(std::pair(operation.get_result(), b_value));
1412 386 }
1413
1414 // Branch and flow control
1415 void
1416 38 CodeGeneratorLLVMContext::generate_operation_jump_conditional(
1417 std::map<size_t, llvm::Value *> & tmp_values,
1418 const Gyoji::mir::Function & mir_function,
1419 const Gyoji::mir::OperationJumpConditional & operation
1420 )
1421 {
1422 38 llvm::Value *condition = tmp_values[operation.get_operands().at(0)];
1423 38 llvm::BasicBlock *bbIf = blocks[operation.get_operands().at(1)];
1424 38 llvm::BasicBlock *bbElse = blocks[operation.get_operands().at(2)];
1425 38 Builder->CreateCondBr(condition, bbIf, bbElse);
1426 38 }
1427 void
1428 40 CodeGeneratorLLVMContext::generate_operation_jump(
1429 std::map<size_t, llvm::Value *> & tmp_values,
1430 const Gyoji::mir::Function & mir_function,
1431 const Gyoji::mir::OperationJump & operation
1432 )
1433 {
1434 40 llvm::BasicBlock *target = blocks[operation.get_operands().at(0)];
1435 40 Builder->CreateBr(target);
1436 40 }
1437
1438 llvm::Value *
1439 282 CodeGeneratorLLVMContext::generate_operation_return(
1440 std::map<size_t, llvm::Value *> & tmp_values,
1441 const Gyoji::mir::Function & mir_function,
1442 const Gyoji::mir::OperationReturn & operation
1443 )
1444 {
1445 282 llvm::Value *value = tmp_values[operation.get_operands().at(0)];
1446 282 Builder->CreateRet(value);
1447 282 return value;
1448 }
1449
1450 llvm::Value *
1451 2 CodeGeneratorLLVMContext::generate_operation_return_void(
1452 std::map<size_t, llvm::Value *> & tmp_values,
1453 const Gyoji::mir::Function & mir_function,
1454 const Gyoji::mir::OperationReturnVoid & operation
1455 )
1456 {
1457 2 fprintf(stderr, "Returning void\n");
1458 2 llvm::Value *value = tmp_values[operation.get_operands().at(0)];
1459 2 Builder->CreateRetVoid();
1460 2 return value;
1461 }
1462
1463 llvm::Value *
1464 362 CodeGeneratorLLVMContext::generate_basic_block(
1465 const Gyoji::mir::Function & mir_function,
1466 const Gyoji::mir::BasicBlock & mir_block
1467 )
1468 {
1469 362 std::map<size_t, llvm::Value *> tmp_values;
1470 362 std::map<size_t, llvm::Value *> tmp_lvalues;
1471
1472 362 llvm::Value *return_value = nullptr;
1473
1474
2/2
✓ Branch 6 taken 3994 times.
✓ Branch 7 taken 362 times.
4356 for (const auto & operation_el : mir_block.get_operations()) {
1475 3994 const Operation & operation = *operation_el;
1476
27/38
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 66 times.
✓ Branch 3 taken 136 times.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 12 times.
✓ Branch 6 taken 1180 times.
✓ Branch 7 taken 310 times.
✓ Branch 8 taken 906 times.
✓ Branch 9 taken 8 times.
✓ Branch 10 taken 10 times.
✓ Branch 11 taken 222 times.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 8 times.
✓ Branch 16 taken 12 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✓ Branch 19 taken 2 times.
✓ Branch 20 taken 60 times.
✓ Branch 21 taken 48 times.
✓ Branch 22 taken 48 times.
✓ Branch 23 taken 48 times.
✓ Branch 24 taken 42 times.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✓ Branch 31 taken 38 times.
✓ Branch 32 taken 386 times.
✓ Branch 33 taken 8 times.
✓ Branch 34 taken 38 times.
✓ Branch 35 taken 40 times.
✓ Branch 36 taken 282 times.
✓ Branch 37 taken 2 times.
✗ Branch 38 not taken.
3994 switch (operation.get_type()) {
1477 // Global symbols
1478 66 case Operation::OP_FUNCTION_CALL:
1479 66 generate_operation_function_call(tmp_values, mir_function, (const OperationFunctionCall &)operation);
1480 66 break;
1481 66 case Operation::OP_SYMBOL:
1482 66 generate_operation_symbol(tmp_values, mir_function, (const OperationSymbol &)operation);
1483 66 break;
1484 // Cast operations
1485 136 case Operation::OP_WIDEN_SIGNED:
1486 case Operation::OP_WIDEN_UNSIGNED:
1487 case Operation::OP_WIDEN_FLOAT:
1488 136 generate_operation_widen_numeric(tmp_values, mir_function, (const OperationCast &)operation);
1489 136 break;
1490 // Indirect access
1491 10 case Operation::OP_ARRAY_INDEX:
1492 10 generate_operation_array_index(tmp_values, tmp_lvalues, mir_function, (const OperationArrayIndex &)operation);
1493 10 break;
1494 12 case Operation::OP_DOT:
1495 12 generate_operation_dot(tmp_values, tmp_lvalues, mir_function, (const OperationDot &)operation);
1496 12 break;
1497 1180 case Operation::OP_LOCAL_VARIABLE:
1498 1180 generate_operation_local_variable(tmp_values, tmp_lvalues, mir_function, (const OperationLocalVariable &)operation);
1499 1180 break;
1500 310 case Operation::OP_LOCAL_DECLARE:
1501 310 generate_operation_local_declare(tmp_values, mir_function, (const OperationLocalDeclare &)operation);
1502 310 break;
1503 906 case Operation::OP_LOCAL_UNDECLARE:
1504 906 generate_operation_local_undeclare(tmp_values, mir_function, (const OperationLocalUndeclare &)operation);
1505 906 break;
1506 8 case Operation::OP_LITERAL_CHAR:
1507 8 generate_operation_literal_char(tmp_values, mir_function, (const OperationLiteralChar &)operation);
1508 8 break;
1509 10 case Operation::OP_LITERAL_STRING:
1510 10 generate_operation_literal_string(tmp_values, mir_function, (const OperationLiteralString &)operation);
1511 10 break;
1512 222 case Operation::OP_LITERAL_INT:
1513 222 generate_operation_literal_int(tmp_values, mir_function, (const OperationLiteralInt &)operation);
1514 222 break;
1515 6 case Operation::OP_LITERAL_FLOAT:
1516 6 generate_operation_literal_float(tmp_values, mir_function, (const OperationLiteralFloat &)operation);
1517 6 break;
1518 case Operation::OP_LITERAL_BOOL:
1519 generate_operation_literal_bool(tmp_values, mir_function, (const OperationLiteralBool &)operation);
1520 break;
1521 case Operation::OP_LITERAL_NULL:
1522 generate_operation_literal_null(tmp_values, mir_function, (const OperationLiteralNull &)operation);
1523 break;
1524
1525 // Unary operations
1526 8 case Operation::OP_ADDRESSOF:
1527 8 generate_operation_addressof(tmp_values, tmp_lvalues, mir_function, (const OperationUnary &)operation);
1528 8 break;
1529 12 case Operation::OP_DEREFERENCE:
1530 12 generate_operation_dereference(tmp_values, tmp_lvalues, mir_function, (const OperationUnary &)operation);
1531 12 break;
1532 case Operation::OP_NEGATE:
1533 generate_operation_arithmetic_negate(tmp_values, mir_function, (const OperationUnary &)operation);
1534 break;
1535 case Operation::OP_BITWISE_NOT:
1536 generate_operation_bitwise_not(tmp_values, mir_function, (const OperationUnary &)operation);
1537 break;
1538 2 case Operation::OP_LOGICAL_NOT:
1539 2 generate_operation_logical_not(tmp_values, mir_function, (const OperationUnary &)operation);
1540 2 break;
1541 // Binary operations
1542 60 case Operation::OP_ADD:
1543 60 generate_operation_add(tmp_values, mir_function, (const OperationBinary &)operation);
1544 60 break;
1545 48 case Operation::OP_SUBTRACT:
1546 48 generate_operation_subtract(tmp_values, mir_function, (const OperationBinary &)operation);
1547 48 break;
1548 48 case Operation::OP_MULTIPLY:
1549 48 generate_operation_multiply(tmp_values, mir_function, (const OperationBinary &)operation);
1550 48 break;
1551 48 case Operation::OP_DIVIDE:
1552 48 generate_operation_divide(tmp_values, mir_function, (const OperationBinary &)operation);
1553 48 break;
1554 42 case Operation::OP_MODULO:
1555 42 generate_operation_modulo(tmp_values, mir_function, (const OperationBinary &)operation);
1556 42 break;
1557 case Operation::OP_LOGICAL_AND:
1558 generate_operation_logical_and(tmp_values, mir_function, (const OperationBinary &)operation);
1559 break;
1560 case Operation::OP_LOGICAL_OR:
1561 generate_operation_logical_or(tmp_values, mir_function, (const OperationBinary &)operation);
1562 break;
1563 case Operation::OP_BITWISE_AND:
1564 generate_operation_bitwise_and(tmp_values, mir_function, (const OperationBinary &)operation);
1565 break;
1566 case Operation::OP_BITWISE_OR:
1567 generate_operation_bitwise_xor(tmp_values, mir_function, (const OperationBinary &)operation);
1568 break;
1569 case Operation::OP_BITWISE_XOR:
1570 generate_operation_bitwise_xor(tmp_values, mir_function, (const OperationBinary &)operation);
1571 break;
1572 case Operation::OP_SHIFT_LEFT:
1573 case Operation::OP_SHIFT_RIGHT:
1574 generate_operation_shift(tmp_values, mir_function, (const OperationBinary &)operation);
1575 break;
1576 // Binary operations: comparisons
1577 38 case Operation::OP_COMPARE_LESS:
1578 case Operation::OP_COMPARE_GREATER:
1579 case Operation::OP_COMPARE_LESS_EQUAL:
1580 case Operation::OP_COMPARE_GREATER_EQUAL:
1581 case Operation::OP_COMPARE_EQUAL:
1582 case Operation::OP_COMPARE_NOT_EQUAL:
1583 38 generate_operation_comparison(tmp_values, mir_function, (const OperationBinary &)operation);
1584 38 break;
1585 386 case Operation::OP_ASSIGN:
1586 386 generate_operation_assign(tmp_values, tmp_lvalues, mir_function, (const OperationBinary &)operation);
1587 386 break;
1588 8 case Operation::OP_SIZEOF_TYPE:
1589 8 generate_operation_sizeof_type(tmp_values, tmp_lvalues, mir_function, (const OperationSizeofType &)operation);
1590 8 break;
1591 38 case Operation::OP_JUMP_CONDITIONAL:
1592 38 generate_operation_jump_conditional(tmp_values, mir_function, (const OperationJumpConditional &)operation);
1593 38 break;
1594 40 case Operation::OP_JUMP:
1595 40 generate_operation_jump(tmp_values, mir_function, (const OperationJump &)operation);
1596 40 break;
1597 282 case Operation::OP_RETURN:
1598 282 return_value = generate_operation_return(tmp_values, mir_function, (const OperationReturn &)operation);
1599 282 break;
1600 2 case Operation::OP_RETURN_VOID:
1601 2 return_value = generate_operation_return_void(tmp_values, mir_function, (const OperationReturnVoid &)operation);
1602 2 break;
1603 }
1604 }
1605 724 return return_value;
1606 362 }
1607
1608
1609 void
1610 266 CodeGeneratorLLVMContext::generate_function(const Gyoji::mir::Function & function)
1611 {
1612 // Transfer ownership of the prototype to the FunctionProtos map, but keep a
1613 // reference to it for use below.
1614 266 llvm::Function *TheFunction = create_function(function);
1615
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 266 times.
266 if (!TheFunction) {
1616 fprintf(stderr, "Function declaration not found\n");
1617 }
1618
1619 // Record the function arguments in the NamedValues map.
1620 266 llvm::BasicBlock *BB = llvm::BasicBlock::Create(*TheContext, "entry", TheFunction);
1621 266 Builder->SetInsertPoint(BB);
1622
1623 266 size_t i = 0;
1624
2/2
✓ Branch 6 taken 520 times.
✓ Branch 7 taken 266 times.
786 for (const auto & function_argument : function.get_arguments()) {
1625 // Create an alloca for this variable.
1626 520 llvm::IRBuilder<> TmpB(&TheFunction->getEntryBlock(),
1627 1040 TheFunction->getEntryBlock().begin());
1628 1040 llvm::AllocaInst *argument_alloca = TmpB.CreateAlloca(
1629 520 types[function_argument.get_type()->get_name()],
1630 nullptr,
1631 function_argument.get_name()
1632 );
1633
1634 520 llvm::Argument *arg = TheFunction->getArg(i);
1635 520 Builder->CreateStore(arg, argument_alloca);
1636
1637 // Add arguments to variable symbol table.
1638 520 local_variables[function_argument.get_name()] = argument_alloca;
1639 520 i++;
1640 520 }
1641
1642 266 llvm::Value *return_value = nullptr;
1643
1644
2/2
✓ Branch 6 taken 362 times.
✓ Branch 7 taken 266 times.
628 for (const auto & block_it : function.get_blocks()) {
1645 1086 std::string block_name = std::string("BB") + std::to_string(block_it.first);
1646 362 llvm::BasicBlock *BB = llvm::BasicBlock::Create(*TheContext, block_name, TheFunction);
1647 362 blocks[block_it.first] = BB;
1648 362 }
1649 // Jump from the entry block into the first 'real' block.
1650 266 Builder->CreateBr(blocks[0]);
1651
1652
2/2
✓ Branch 6 taken 362 times.
✓ Branch 7 taken 266 times.
628 for (const auto & block_it : function.get_blocks()) {
1653 // Create a new basic block to start insertion into.
1654 362 llvm::BasicBlock *BB = blocks[block_it.first];
1655 362 Builder->SetInsertPoint(BB);
1656 362 llvm::Value *return_value_block = generate_basic_block(function, *block_it.second);
1657
1658 // Technically, we should be using 'PHI'
1659 // here and reconciling multiple possible
1660 // return paths.
1661
2/2
✓ Branch 0 taken 282 times.
✓ Branch 1 taken 80 times.
362 if (return_value_block != nullptr) {
1662 282 return_value = return_value_block;
1663 }
1664 }
1665
1666 // This should not be required. We should
1667 // enforce this through the analysis layer
1668 // and reject programs that may return without
1669 // defining a return value.
1670 #if 0
1671 if (return_value == nullptr) {
1672 Builder->CreateRet(
1673 Builder->getInt32(0x1000)
1674 );
1675 }
1676 #endif
1677
1678 // Validate the generated code, checking for consistency.
1679 266 verifyFunction(*TheFunction);
1680
1681 266 local_variables.clear();
1682 266 }
1683
1684
1685 int
1686 30 CodeGeneratorLLVMContext::output(const std::string & filename)
1687 {
1688 using namespace llvm;
1689 // Initialize the target registry etc.
1690 30 InitializeAllTargetInfos();
1691 30 InitializeAllTargets();
1692 30 InitializeAllTargetMCs();
1693 30 InitializeAllAsmParsers();
1694 30 InitializeAllAsmPrinters();
1695
1696 30 auto TargetTriple = sys::getDefaultTargetTriple();
1697 30 TheModule->setTargetTriple(TargetTriple);
1698
1699 30 std::string Error;
1700 30 auto Target = TargetRegistry::lookupTarget(TargetTriple, Error);
1701
1702 // Print an error and exit if we couldn't find the requested target.
1703 // This generally occurs if we've forgotten to initialise the
1704 // TargetRegistry or we have a bogus target triple.
1705
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (!Target) {
1706 errs() << Error;
1707 return 1;
1708 }
1709
1710 30 auto CPU = "generic";
1711 30 auto Features = "";
1712
1713 30 TargetOptions opt;
1714 60 auto TheTargetMachine = Target->createTargetMachine(
1715 30 TargetTriple, CPU, Features, opt, Reloc::PIC_);
1716
1717 30 TheModule->setDataLayout(TheTargetMachine->createDataLayout());
1718
1719 30 std::error_code EC;
1720 30 raw_fd_ostream dest(filename, EC, sys::fs::OF_None);
1721
1722
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
30 if (EC) {
1723 errs() << "Could not open file: " << EC.message();
1724 return 1;
1725 }
1726
1727 30 llvm::raw_fd_ostream llvm_ll_ostream(filename + std::string(".ll"), EC);
1728 30 TheModule->print(llvm_ll_ostream, nullptr);
1729
1730 // For now, until we have a cmdline parser
1731 // we will default to no optimization so we
1732 // can actually follow the generated assembly.
1733 // When we want to run a 'real' build, we will
1734 // want to turn on better optimizations.
1735 30 TheTargetMachine->setOptLevel(CodeGenOptLevel::None);
1736
1737 30 legacy::PassManager pass;
1738 30 auto FileType = CodeGenFileType::ObjectFile;
1739
1740
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
30 if (TheTargetMachine->addPassesToEmitFile(pass, dest, nullptr, FileType)) {
1741 errs() << "TheTargetMachine can't emit a file of this type";
1742 return 1;
1743 }
1744
1745 30 pass.run(*TheModule);
1746 30 dest.flush();
1747
1748 30 outs() << "Wrote " << filename << "\n";
1749
1750 30 return 0;
1751 30 }
1752