From b2ba0d79019ff45bbc91850a361cb4a60c28db60 Mon Sep 17 00:00:00 2001 From: Mason Bially Date: Sun, 10 Jun 2018 20:32:02 -0700 Subject: [PATCH] Finishing minimum compilation on windows. --- src/backendllvm/LlvmBackend.cpp | 11 +- src/backendllvm/LlvmBackend.h | 2 +- src/backendllvm/LlvmCompiler.cpp | 243 +++++++++++++++++++++++------ src/backendllvm/LlvmCompiler.h | 144 ++++++++++++++--- src/backendllvm/LlvmSubroutine.cpp | 8 +- src/backendllvm/all.cpp | 38 +++-- 6 files changed, 360 insertions(+), 86 deletions(-) diff --git a/src/backendllvm/LlvmBackend.cpp b/src/backendllvm/LlvmBackend.cpp index 36c792f..a3fd51b 100644 --- a/src/backendllvm/LlvmBackend.cpp +++ b/src/backendllvm/LlvmBackend.cpp @@ -31,14 +31,17 @@ CRAFT_DEFINE(LlvmBackend) _.defaults(); } -std::string LlvmBackend::mangledName(instance bindable) +std::string LlvmBackend::mangledName(instance bindable, std::string const& postFix) { auto binding = bindable->getBinding(); auto module = binding->getScope()->getSemantics()->getModule(); // TODO ensure more than 2 @ is an error for any real symbol // TODO add type specialization here? - return fmt::format("{1}@@@{0}", module->uri(), binding->getSymbol()->getDisplay()); + if (postFix.empty()) + return fmt::format("{1}@@@{0}", module->uri(), binding->getSymbol()->getDisplay()); + else + return fmt::format("{1}@@@{0}:::{2}", module->uri(), binding->getSymbol()->getDisplay(), postFix); } LlvmBackend::LlvmBackend(instance lisp) @@ -131,10 +134,6 @@ LlvmBackendProvider::LlvmBackendProvider() llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); llvm::InitializeNativeTargetAsmParser(); - - llvm::InitializeAllTargets(); - llvm::InitializeAllTargetMCs(); - llvm::InitializeAllAsmPrinters(); } instance<> LlvmBackendProvider::init(instance ns) const diff --git a/src/backendllvm/LlvmBackend.h b/src/backendllvm/LlvmBackend.h index 851d10c..0943a5b 100644 --- a/src/backendllvm/LlvmBackend.h +++ b/src/backendllvm/LlvmBackend.h @@ -58,7 +58,7 @@ namespace lisp public: using JitModule = decltype(_compileLayer)::ModuleHandleT; - CULTLANG_BACKENDLLVM_EXPORTED static std::string mangledName(instance); + CULTLANG_BACKENDLLVM_EXPORTED static std::string mangledName(instance, std::string const& postFix = ""); public: diff --git a/src/backendllvm/LlvmCompiler.cpp b/src/backendllvm/LlvmCompiler.cpp index 5586fce..b98ccca 100644 --- a/src/backendllvm/LlvmCompiler.cpp +++ b/src/backendllvm/LlvmCompiler.cpp @@ -10,6 +10,15 @@ using namespace craft::lisp; using namespace llvm; using namespace llvm::orc; +CRAFT_DEFINE(SLlvmAbi) +{ + _.defaults(); +} + +/****************************************************************************** +** LlvmCompiler +******************************************************************************/ + CRAFT_DEFINE(LlvmCompiler) { _.defaults(); @@ -23,8 +32,11 @@ LlvmCompiler::LlvmCompiler(instance backend) type_instanceMetaHeader = llvm::StructType::create(_backend->context, "!instancemetaheader"); type_instanceMetaHeader->setBody({ type_anyPtr, type_anyPtr, type_anyPtr, type_anyPtr }); type_anyInstance = llvm::StructType::get(_backend->context, { llvm::PointerType::get(type_instanceMetaHeader, 0), type_anyPtr }); +} - state = new CompilerState(); +void LlvmCompiler::craft_setupInstance() +{ + _state = instance::make(craft_instance()); } instance LlvmCompiler::getBackend() @@ -34,36 +46,7 @@ instance LlvmCompiler::getBackend() void LlvmCompiler::compile(instance node) { - try - { - auto res = _fn_system_compile.getFeature()->execute(_fn_system_compile, { craft_instance(), node }); - } - catch (std::exception const& ex) - { - _backend->getNamespace()->getEnvironment()->log()->warn("Compiler does not support node `{1}`, default returned: {0}", ex.what(), node); - } -} - -void LlvmCompiler::compile_setModule(instance module) -{ - state->currentModule = module; - state->codeModule = module->require()->getIr().get(); -} -void LlvmCompiler::compile_setFunction(instance func) -{ - auto name = LlvmBackend::mangledName(func); - - state->codeFunction = llvm::Function::Create( - getLlvmType(func->subroutine_signature()), - llvm::Function::ExternalLinkage, - name, - state->codeModule); - - if (state->irBuilder != nullptr) delete state->irBuilder; - state->irBuilder = new llvm::IRBuilder<>(_backend->context); - - auto block = llvm::BasicBlock::Create(_backend->context, name, state->codeFunction); - state->irBuilder->SetInsertPoint(block); + _state->compile(node); } LlvmCompiler::_TypeCacheEntry LlvmCompiler::_getTypeCache(types::TypeId type) @@ -108,46 +91,216 @@ llvm::FunctionType* LlvmCompiler::getLlvmType(types::ExpressionStore signature) if (!arrow->input->kind().isType()) throw stdext::exception("getLlvmType(): malformed expression (not tuple)."); auto tuple = (ExpressionTuple*)arrow->input; + // TODO windows ABI + args.push_back(llvm::PointerType::get(getLlvmType(arrow->output), 0)); + for (auto arg : tuple->entries) { args.push_back(getLlvmType(arg)); } - return_ = getLlvmType(arrow->output); + //return_ = getLlvmType(arrow->output); + return_ = llvm::Type::getVoidTy(_backend->context); + + auto ret = llvm::FunctionType::get(return_, args, false); + + return ret; +} + +void LlvmCompiler::builtin_validateSpecialForms(instance module) +{ + _fn_system_compile = module->get()->lookup(Symbol::makeSymbol("compile"))->getSite()->valueAst(); +} + +/****************************************************************************** +** LlvmCompileState +******************************************************************************/ + +CRAFT_DEFINE(LlvmCompileState) +{ + _.defaults(); +} + +LlvmCompileState::LlvmCompileState(instance compiler) +{ + _compiler = compiler; + + context = &getCompiler()->getBackend()->context; + irBuilder = nullptr; + lastReturnedValue = nullptr; + codeModule = nullptr; + codeFunction = nullptr; +} + +void LlvmCompileState::craft_setupInstance() +{ + _abi = instance::make(craft_instance()); +} + +instance LlvmCompileState::getCompiler() const +{ + return _compiler; +} + +void LlvmCompileState::compile(instance node) +{ + auto _mm_compiler = _compiler->_fn_system_compile; + + try + { + auto res = _mm_compiler.getFeature()->execute(_mm_compiler, { craft_instance(), _abi, node }); + } + catch (std::exception const& ex) + { + getCompiler()->getBackend() + ->getNamespace()->getEnvironment() + ->log()->warn("Compiler does not support node `{1}`, default returned: {0}", ex.what(), node); + } +} + +void LlvmCompileState::setModule(instance module) +{ + currentModule = module; + codeModule = module->require()->getIr().get(); +} +void LlvmCompileState::setFunction(instance func) +{ + currentFunction = func; + auto name = LlvmBackend::mangledName(func, _abi->abiName()); + + codeFunction = llvm::Function::Create( + getCompiler()->getLlvmType(func->subroutine_signature()), + llvm::Function::ExternalLinkage, + name, + codeModule); + + if (irBuilder != nullptr) delete irBuilder; + irBuilder = new llvm::IRBuilder<>(*context); + + auto block = llvm::BasicBlock::Create(*context, name, codeFunction); + irBuilder->SetInsertPoint(block); - return llvm::FunctionType::get(return_, args, false); + _abi->doFunctionPre(); } -llvm::Value* LlvmCompiler::build_instanceAsConstant(instance<> inst) +llvm::Value* LlvmCompileState::genInstanceAsConstant(instance<> inst) { - auto entry = _getTypeCache(inst.typeId()); + auto entry = _compiler->_getTypeCache(inst.typeId()); return llvm::ConstantStruct::getAnon( { - llvm::ConstantExpr::getIntToPtr(llvm::ConstantInt::get(llvm::Type::getInt64Ty(_backend->context), (uint64_t)inst.asInternalPointer()), llvm::PointerType::get(type_instanceMetaHeader, 0)), - llvm::ConstantExpr::getIntToPtr(llvm::ConstantInt::get(llvm::Type::getInt64Ty(_backend->context), (uint64_t)inst.get()), llvm::PointerType::get(entry.opaque_struct, 0)) + llvm::ConstantExpr::getIntToPtr( + llvm::ConstantInt::get( + llvm::Type::getInt64Ty(*context), + (uint64_t)inst.asInternalPointer()), + llvm::PointerType::get(_compiler->type_instanceMetaHeader, 0)), + llvm::ConstantExpr::getIntToPtr( + llvm::ConstantInt::get( + llvm::Type::getInt64Ty(*context), + (uint64_t)inst.get()), + llvm::PointerType::get(entry.opaque_struct, 0)) }); } -llvm::Value* LlvmCompiler::build_instanceCast(llvm::Value* value, TypeId type) +llvm::Value* LlvmCompileState::genInstanceCast(llvm::Value* value, TypeId type) { - _TypeCacheEntry* entry = nullptr; - if (type != types::None) entry = &_getTypeCache(type); + LlvmCompiler::_TypeCacheEntry* entry = nullptr; + if (type != types::None) entry = &_compiler->_getTypeCache(type); - auto const targetPtrType = (entry == nullptr) ? type_anyPtr : llvm::PointerType::get(entry->opaque_struct, 0); + auto const targetPtrType = (entry == nullptr) ? _compiler->type_anyPtr : llvm::PointerType::get(entry->opaque_struct, 0); if (auto *vconst = dyn_cast(value)) { return llvm::ConstantStruct::getAnon( { - llvm::ConstantExpr::getExtractValue(vconst, { 0 }), - llvm::ConstantExpr::getBitCast(llvm::ConstantExpr::getExtractValue(vconst, { 1 }), targetPtrType) + llvm::ConstantExpr::getExtractValue(vconst,{ 0 }), + llvm::ConstantExpr::getBitCast(llvm::ConstantExpr::getExtractValue(vconst,{ 1 }), targetPtrType) }); } else throw stdext::exception("Runtime casting not supported yet."); } -void LlvmCompiler::builtin_validateSpecialForms(instance module) +void LlvmCompileState::genReturn(llvm::Value* v) { - _fn_system_compile = module->get()->lookup(Symbol::makeSymbol("compile"))->getSite()->valueAst(); + _abi->genReturn(v); +} + +/****************************************************************************** +** LlvmAbiBase +******************************************************************************/ + +CRAFT_DEFINE(LlvmAbiBase) +{ + _.use().byCasting(); + + _.defaults(); +} + +LlvmAbiBase::LlvmAbiBase(instance compileState) +{ + _c = compileState; +} + +std::string LlvmAbiBase::abiName() +{ + return ""; +} + +void LlvmAbiBase::doFunctionPre() +{ + +} +void LlvmAbiBase::doFunctionPost() +{ + +} + +void LlvmAbiBase::genReturn(llvm::Value* v) +{ + _c->irBuilder->CreateRet(v); +} + +/****************************************************************************** +** LlvmAbiWindows +******************************************************************************/ + +CRAFT_DEFINE(LlvmAbiWindows) +{ + _.parent(); + + _.defaults(); +} + +LlvmAbiWindows::LlvmAbiWindows(instance compileState) + : LlvmAbiBase(compileState) +{ + +} + +std::string LlvmAbiWindows::abiName() +{ + return "windows"; +} + +void LlvmAbiWindows::doFunctionPre() +{ + _c->codeFunction->addAttribute(1, llvm::Attribute::StructRet); +} + +void LlvmAbiWindows::genReturn(llvm::Value* v) +{ + // Assert struct return + + auto ret = _c->codeFunction->arg_begin() + 0; + + if (auto *vconst = dyn_cast(v)) + { + _c->irBuilder->CreateStore(vconst, ret); + } + else + { + auto callee = llvm::Intrinsic::getDeclaration(_c->codeModule, llvm::Intrinsic::memcpy, {}); + } + + _c->irBuilder->CreateRetVoid(); } diff --git a/src/backendllvm/LlvmCompiler.h b/src/backendllvm/LlvmCompiler.h index 5d40259..e98d086 100644 --- a/src/backendllvm/LlvmCompiler.h +++ b/src/backendllvm/LlvmCompiler.h @@ -5,13 +5,36 @@ namespace craft { namespace lisp { + /****************************************************************************** + ** SLlvmAbi + ******************************************************************************/ + + class SLlvmAbi + : public craft::types::Aspect + { + CULTLANG_BACKENDLLVM_EXPORTED CRAFT_LEGACY_FEATURE_DECLARE(craft::lisp::SLlvmAbi, "llvm.abi", types::FactoryAspectManager); + + public: + CULTLANG_BACKENDLLVM_EXPORTED virtual std::string abiName() = 0; + + CULTLANG_BACKENDLLVM_EXPORTED virtual void doFunctionPre() = 0; + CULTLANG_BACKENDLLVM_EXPORTED virtual void doFunctionPost() = 0; + + CULTLANG_BACKENDLLVM_EXPORTED virtual void genReturn(llvm::Value*) = 0; + }; + + /****************************************************************************** + ** LlvmCompiler + ******************************************************************************/ + class LlvmCompiler : public virtual craft::types::Object { CULTLANG_BACKENDLLVM_EXPORTED CRAFT_OBJECT_DECLARE(craft::lisp::LlvmCompiler); protected: - friend LlvmBackend; + friend class LlvmBackend; + friend class LlvmCompileState; instance _backend; llvm::Type* type_anyPtr; @@ -26,18 +49,7 @@ namespace lisp std::map _typeCache; - public: - struct CompilerState - { - instance currentModule; - llvm::Module* codeModule; - llvm::Function* codeFunction; - - llvm::IRBuilder<>* irBuilder; - llvm::Value* lastReturnedValue; - }; - - CompilerState* state; + instance _state; private: instance _fn_system_compile; @@ -46,13 +58,12 @@ namespace lisp public: CULTLANG_BACKENDLLVM_EXPORTED LlvmCompiler(instance backend); + CULTLANG_BACKENDLLVM_EXPORTED void craft_setupInstance(); CULTLANG_BACKENDLLVM_EXPORTED instance getBackend(); public: CULTLANG_BACKENDLLVM_EXPORTED void compile(instance node); - CULTLANG_BACKENDLLVM_EXPORTED void compile_setModule(instance module); - CULTLANG_BACKENDLLVM_EXPORTED void compile_setFunction(instance func); CULTLANG_BACKENDLLVM_EXPORTED llvm::Type* getLlvmInstanceType(types::TypeId type); CULTLANG_BACKENDLLVM_EXPORTED llvm::Type* getLlvmValueType(types::TypeId type); @@ -60,13 +71,110 @@ namespace lisp CULTLANG_BACKENDLLVM_EXPORTED llvm::Type* getLlvmType(types::IExpression* node); CULTLANG_BACKENDLLVM_EXPORTED llvm::FunctionType* getLlvmType(types::ExpressionStore signature); - CULTLANG_BACKENDLLVM_EXPORTED llvm::Value* build_instanceAsConstant(instance<> inst); - CULTLANG_BACKENDLLVM_EXPORTED llvm::Value* build_instanceCast(llvm::Value*, types::TypeId type); - public: // Ensures the module has everything the interpreter needs CULTLANG_BACKENDLLVM_EXPORTED void builtin_validateSpecialForms(instance module); }; + /****************************************************************************** + ** LlvmCompileState + ******************************************************************************/ + + class LlvmCompileState + : public virtual craft::types::Object + { + CULTLANG_BACKENDLLVM_EXPORTED CRAFT_OBJECT_DECLARE(craft::lisp::LlvmCompileState); + private: + instance _compiler; + instance _abi; + + public: + llvm::LLVMContext* context; + + instance currentModule; + llvm::Module* codeModule; + instance currentFunction; + llvm::Function* codeFunction; + + llvm::IRBuilder<>* irBuilder; + llvm::Value* lastReturnedValue; + + public: + CULTLANG_BACKENDLLVM_EXPORTED LlvmCompileState(instance compiler); + CULTLANG_BACKENDLLVM_EXPORTED void craft_setupInstance(); + + CULTLANG_BACKENDLLVM_EXPORTED instance getCompiler() const; + + CULTLANG_BACKENDLLVM_EXPORTED void setAbi(instance<>); + CULTLANG_BACKENDLLVM_EXPORTED instance<> getAbi(); + + public: + CULTLANG_BACKENDLLVM_EXPORTED void compile(instance node); + + CULTLANG_BACKENDLLVM_EXPORTED void setModule(instance module); + CULTLANG_BACKENDLLVM_EXPORTED void setFunction(instance func); + + // compile helpers + public: + CULTLANG_BACKENDLLVM_EXPORTED llvm::Value* genInstanceAsConstant(instance<> inst); + CULTLANG_BACKENDLLVM_EXPORTED llvm::Value* genInstanceCast(llvm::Value*, types::TypeId type); + CULTLANG_BACKENDLLVM_EXPORTED void genReturn(llvm::Value*); + + // Forwarding helpers + public: + inline llvm::Type* getLlvmInstanceType(types::TypeId type) const { return getCompiler()->getLlvmInstanceType(type); } + inline llvm::Type* getLlvmValueType(types::TypeId type) const { return getCompiler()->getLlvmValueType(type); } + inline llvm::Type* getLlvmValuePointerType(types::TypeId type) const { return getCompiler()->getLlvmValuePointerType(type); } + inline llvm::Type* getLlvmType(types::IExpression* node) const { return getCompiler()->getLlvmType(node); } + inline llvm::FunctionType* getLlvmType(types::ExpressionStore signature) const { return getCompiler()->getLlvmType(signature); } + + }; + + /****************************************************************************** + ** LlvmAbiBase + ******************************************************************************/ + + // Base ABI / pure llvm abi + class LlvmAbiBase + : public virtual craft::types::Object + , public craft::types::Implements + { + CULTLANG_BACKENDLLVM_EXPORTED CRAFT_OBJECT_DECLARE(craft::lisp::LlvmAbiBase); + + protected: + instance _c; + + public: + CULTLANG_BACKENDLLVM_EXPORTED LlvmAbiBase(instance compileState); + + public: + CULTLANG_BACKENDLLVM_EXPORTED virtual std::string abiName() override; + + CULTLANG_BACKENDLLVM_EXPORTED virtual void doFunctionPre() override; + CULTLANG_BACKENDLLVM_EXPORTED virtual void doFunctionPost() override; + + CULTLANG_BACKENDLLVM_EXPORTED virtual void genReturn(llvm::Value*) override; + }; + + /****************************************************************************** + ** LlvmAbiWindows + ******************************************************************************/ + + // Windows ABI + class LlvmAbiWindows + : public LlvmAbiBase + { + CULTLANG_BACKENDLLVM_EXPORTED CRAFT_OBJECT_DECLARE(craft::lisp::LlvmAbiWindows); + + public: + CULTLANG_BACKENDLLVM_EXPORTED LlvmAbiWindows(instance compileState); + + public: + CULTLANG_BACKENDLLVM_EXPORTED virtual std::string abiName() override; + + CULTLANG_BACKENDLLVM_EXPORTED virtual void doFunctionPre() override; + + CULTLANG_BACKENDLLVM_EXPORTED virtual void genReturn(llvm::Value*) override; + }; }} diff --git a/src/backendllvm/LlvmSubroutine.cpp b/src/backendllvm/LlvmSubroutine.cpp index d6c25f9..de80ad4 100644 --- a/src/backendllvm/LlvmSubroutine.cpp +++ b/src/backendllvm/LlvmSubroutine.cpp @@ -44,10 +44,11 @@ LlvmBackend::JitModule LlvmSubroutine::specialize(std::vector* types) auto backend = _module->getBackend(); auto function = _ast.asFeature(); - auto name = LlvmBackend::mangledName(function); + auto name = LlvmBackend::mangledName(function, "windows"); auto type = backend->getCompiler()->getLlvmType(function->subroutine_signature()); auto proto_func = _module->getIr()->getFunction(name); + _module->getIr()->dump(); auto ir = std::make_shared(_module->getModule()->uri(), backend->context); ir->setDataLayout(backend->_dl); @@ -55,9 +56,10 @@ LlvmBackend::JitModule LlvmSubroutine::specialize(std::vector* types) auto func = llvm::Function::Create(type, llvm::Function::ExternalLinkage, name, ir.get()); + // TODO: specialize for ABI type?? llvm::ValueToValueMapTy vvmap; auto funcArgIt = func->arg_begin(); - for (auto const& it : func->args()) + for (auto const& it : proto_func->args()) if (vvmap.count(&it) == 0) { funcArgIt->setName(it.getName()); @@ -113,7 +115,7 @@ LlvmBackend::JitModule LlvmSubroutine::specialize(std::vector* types) instance<> LlvmSubroutine::invoke(GenericInvoke const& invk) { auto function = _ast.asFeature(); - auto name = LlvmBackend::mangledName(function); + auto name = LlvmBackend::mangledName(function, "windows"); specialize(); diff --git a/src/backendllvm/all.cpp b/src/backendllvm/all.cpp index 1697268..9f90cbc 100644 --- a/src/backendllvm/all.cpp +++ b/src/backendllvm/all.cpp @@ -49,7 +49,7 @@ void cultlang::backendllvm::make_llvm_bindings(instance module) GenericInvoke invoke(args.args.size()); std::copy(args.args.begin(), args.args.end(), std::back_inserter(invoke.args)); - sub->invoke(invoke); + return sub->invoke(invoke); } else throw stdext::exception("`{0}` is not a callable object.", node); }); @@ -59,37 +59,49 @@ void cultlang::backendllvm::make_llvm_bindings(instance module) // LLVM - Compiler // sem->builtin_implementMultiMethod("compile", - [](instance compiler, instance ast) + [](instance c, instance abi, instance ast) { auto value = ast->getValue(); - compiler->state->lastReturnedValue = compiler->build_instanceAsConstant(value); + c->lastReturnedValue = c->genInstanceAsConstant(value); }); sem->builtin_implementMultiMethod("compile", - [](instance compiler, instance ast) + [](instance c, instance abi, instance ast) { - compiler->compile_setModule(ast->getSemantics()->getModule()); - compiler->compile_setFunction(ast); + c->setModule(ast->getSemantics()->getModule()); + c->setFunction(ast); // TODO read through args, set names - compiler->compile(ast->bodyAst()); + c->compile(ast->bodyAst()); - compiler->state->irBuilder->CreateRet( - compiler->build_instanceCast( - compiler->state->lastReturnedValue, - types::None)); + c->genReturn(c->genInstanceCast(c->lastReturnedValue, types::None)); }); sem->builtin_implementMultiMethod("compile", - [](instance compiler, instance ast) + [](instance c, instance abi, instance ast) { auto count = ast->statementCount(); for (auto i = 0; i < count; i++) { - compiler->compile(ast->statementAst(i)); + c->compile(ast->statementAst(i)); } // The last returned value is implictly set here }); + sem->builtin_implementMultiMethod("compile", + [](instance c, instance abi, instance ast) + { + auto count = ast->argCount(); + + std::vector args; + args.reserve(count); + + for (auto i = 0; i < count; ++i) + { + c->compile(ast->argAst(i)); + args.push_back(c->lastReturnedValue); + } + + }); /* sem->builtin_implementMultiMethod("compile",