GCC Code Coverage Report


Directory: src/
File: src/codegen/gyoji-codegen-llvm.cpp
Date: 2025-10-24 11:14:59
Exec Total Coverage
Lines: 595 977 60.9%
Functions: 47 62 75.8%
Branches: 194 350 55.4%

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