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 |