| 
					
				 | 
			
			
				@@ -0,0 +1,336 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "CodeGeneration.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <llvm/IR/LLVMContext.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <llvm/IR/LegacyPassManager.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <llvm/Transforms/IPO/PassManagerBuilder.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <llvm/IR/Type.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <llvm/IR/DerivedTypes.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <llvm/IR/Constants.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <llvm/IR/BasicBlock.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <llvm/IR/Verifier.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <llvm/IR/IRBuilder.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <llvm/IR/Attributes.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <llvm/Target/TargetMachine.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <llvm/Support/TargetRegistry.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <llvm/Support/TargetSelect.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <llvm/Support/FileSystem.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <llvm/Support/raw_os_ostream.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using namespace qlow; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static llvm::LLVMContext context; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+namespace qlow 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+namespace gen 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+std::unique_ptr<llvm::Module> generateModule(const sem::Semantic& semantic) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::Module; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::Function; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::Argument; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::Type; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::FunctionType; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::BasicBlock; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::Value; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::IRBuilder; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Logger& logger = Logger::getInstance(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#ifdef DEBUGGING 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        printf("creating llvm module\n");  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    std::unique_ptr<Module> module = llvm::make_unique<Module>("qlow_module", context); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // create llvm structs 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // TODO implement detection of circles 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for (auto& [name, cl] : semantic.getClasses()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        llvm::StructType* st; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        std::vector<llvm::Type*> fields; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#ifdef DEBUGGING 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        printf("creating llvm struct for %s\n", name.c_str()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int llvmStructIndex = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (auto& [name, field] : cl->fields) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            field->llvmStructIndex = llvmStructIndex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fields.push_back(field->type->getLlvmType(context)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (fields[fields.size() - 1] == nullptr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                throw "internal error: possible circular dependency"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            llvmStructIndex++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        st = llvm::StructType::create(context, fields, name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        cl->llvmType = st; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    llvm::AttrBuilder ab; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ab.addAttribute(llvm::Attribute::AttrKind::NoInline); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ab.addAttribute(llvm::Attribute::AttrKind::NoUnwind); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    //ab.addAttribute(llvm::Attribute::AttrKind::OptimizeNone); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    //ab.addAttribute(llvm::Attribute::AttrKind::UWTable); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ab.addAttribute("no-frame-pointer-elim", "true"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ab.addAttribute("no-frame-pointer-elim-non-leaf"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    llvm::AttributeSet as = llvm::AttributeSet::get(context, ab); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    std::vector<llvm::Function*> functions; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    auto verifyStream = llvm::raw_os_ostream(logger.debug()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // create all llvm functions 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for (auto& [name, cl] : objects.classes) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (auto& [name, method] : cl->methods) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Function* func = generateFunction(module.get(), method.get()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for (auto a : as) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                func->addFnAttr(a); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            functions.push_back(func); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for (auto& [name, method] : objects.functions) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Function* func = generateFunction(module.get(), method.get()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (auto a : as) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            func->addFnAttr(a); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        functions.push_back(func); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for (auto& [name, cl] : objects.classes){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (auto& [name, method] : cl->methods) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!method->body) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            FunctionGenerator fg(*method, module.get(), as); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Function* f = fg.generate(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.debug() << "verifying function: " << method->name << std::endl; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            bool corrupt = llvm::verifyFunction(*f, &verifyStream); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (corrupt) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                module->print(verifyStream, nullptr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                throw "corrupt llvm function"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#ifdef DEBUGGING 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            printf("verified function: %s\n", method->name.c_str()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for (auto& [name, method] : objects.functions) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (!method->body) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        FunctionGenerator fg(*method, module.get(), as); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Function* f = fg.generate(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.debug() << "verifying function: " << method->name << std::endl; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        bool corrupt = llvm::verifyFunction(*f, &verifyStream); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (corrupt) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            module->print(verifyStream, nullptr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            throw "corrupt llvm function"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#ifdef DEBUGGING 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        printf("verified function: %s\n", method->name.c_str()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return module; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+llvm::Function* generateFunction(llvm::Module* module, sem::Method* method) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::Function; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::Argument; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::Type; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::FunctionType; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Type* returnType; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (method->returnType) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        returnType = method->returnType->getLlvmType(context); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        returnType = llvm::Type::getVoidTy(context); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    std::vector<Type*> argumentTypes; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (method->thisExpression != nullptr) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Type* enclosingType = method->thisExpression->type->getLlvmType(context); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        argumentTypes.push_back(enclosingType); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for (auto& arg : method->arguments) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Type* argumentType = arg->type->getLlvmType(context); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        argumentTypes.push_back(argumentType); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    FunctionType* funcType = FunctionType::get( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        returnType, argumentTypes, false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#ifdef DEBUGGING 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    printf("looking up llvm type of %s\n", method->name.c_str()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (returnType == nullptr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        throw "invalid return type"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Function* func = Function::Create(funcType, Function::ExternalLinkage, method->name, module); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    method->llvmNode = func; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // linking alloca instances for funcs 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    auto argIterator = func->arg_begin(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (method->thisExpression != nullptr) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        method->thisExpression->allocaInst = &*argIterator; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Logger::getInstance().debug() << "allocaInst of this"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        argIterator++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    size_t argIndex = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for (; argIterator != func->arg_end(); argIterator++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (argIndex > method->arguments.size()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            throw "internal error"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        method->arguments[argIndex]->allocaInst = &*argIterator; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#ifdef DEBUGGING 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        printf("allocaInst of arg '%s': %p\n", method->arguments[argIndex]->name.c_str(), method->arguments[argIndex]->allocaInst); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        argIndex++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    //printf("UEEEEEEEE %s\n", method->name.c_str()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return func; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+void generateObjectFile(const std::string& filename, std::unique_ptr<llvm::Module> module, int optLevel) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::legacy::PassManager; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::PassManagerBuilder; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::raw_fd_ostream; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::Target; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::TargetMachine; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::TargetRegistry; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::TargetOptions; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Logger& logger = Logger::getInstance(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.debug() << "verifying mod" << std::endl; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    auto ostr = llvm::raw_os_ostream(logger.debug()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#ifdef DEBUGGING 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    module->print(ostr, nullptr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    bool broken = llvm::verifyModule(*module); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (broken) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        throw "invalid llvm module"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.debug() << "mod verified" << std::endl; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    llvm::InitializeAllTargetInfos(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    llvm::InitializeAllTargets(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    llvm::InitializeAllTargetMCs(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    llvm::InitializeAllAsmParsers(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    llvm::InitializeAllAsmPrinters(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    PassManager pm; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    int sizeLevel = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    PassManagerBuilder builder; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    builder.OptLevel = optLevel; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    builder.SizeLevel = sizeLevel; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (optLevel >= 2) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        builder.DisableUnitAtATime = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        builder.DisableUnrollLoops = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        builder.LoopVectorize = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        builder.SLPVectorize = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    builder.populateModulePassManager(pm); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const char cpu[] = "generic"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const char features[] = ""; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    std::string error; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    std::string targetTriple = llvm::sys::getDefaultTargetTriple(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const Target* target = TargetRegistry::lookupTarget(targetTriple, error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!target) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.debug() << "could not create target: " << error << std::endl; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        throw "internal error"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    TargetOptions targetOptions; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    auto relocModel = llvm::Optional<llvm::Reloc::Model>(llvm::Reloc::Model::PIC_); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    std::unique_ptr<TargetMachine> targetMachine( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        target->createTargetMachine(targetTriple, cpu, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            features, targetOptions, relocModel)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    std::error_code errorCode; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    raw_fd_ostream dest(filename, errorCode, llvm::sys::fs::F_None); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    targetMachine->addPassesToEmitFile(pm, dest, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//        llvm::LLVMTargetMachine::CGFT_ObjectFile, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        llvm::TargetMachine::CGFT_ObjectFile); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pm.run(*module); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    dest.flush(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    dest.close(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} // namespace gen 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} // namespace qlow 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+llvm::Function* qlow::gen::FunctionGenerator::generate(void) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::Function; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::Argument; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::Type; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::FunctionType; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::BasicBlock; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::Value; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    using llvm::IRBuilder; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#ifdef DEBUGGING 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    printf("generate function %s\n", method.name.c_str());  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Function* func = module->getFunction(method.name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (func == nullptr) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        throw "internal error: function not found"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    BasicBlock* bb = BasicBlock::Create(context, "entry", func); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pushBlock(bb); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    IRBuilder<> builder(context); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    builder.SetInsertPoint(bb); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for (auto& [name, var] : method.body->scope.getLocals()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (var.get() == nullptr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            throw "wtf null variable"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (var->type == nullptr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            throw "wtf null type"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        llvm::AllocaInst* v = builder.CreateAlloca(var->type->getLlvmType(context)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        var->allocaInst = v; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for (auto& statement : method.body->statements) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#ifdef DEBUGGING 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        printf("statement visit %s\n", statement->toString().c_str()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        statement->accept(statementVisitor, *this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#ifdef DEBUGGING 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    printf("End of Function\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    //Value* val = llvm::ConstantFP::get(context, llvm::APFloat(5.0)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    builder.SetInsertPoint(getCurrentBlock()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (method.returnType->equals(sem::NativeType(sem::NativeType::Type::VOID))) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (!getCurrentBlock()->getTerminator()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            builder.CreateRetVoid(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return func; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 |