| 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 |