mirror of https://github.com/exaloop/codon.git
Update pyextension codegen (WIP)
parent
c467645aec
commit
7d3f62c014
|
@ -369,9 +369,10 @@ int buildMode(const std::vector<const char *> &args, const std::string &argv0) {
|
||||||
lflags);
|
lflags);
|
||||||
break;
|
break;
|
||||||
case BuildKind::PyExtension:
|
case BuildKind::PyExtension:
|
||||||
compiler->getLLVMVisitor()->writeToPythonExtension(
|
compiler->getCache()->pyModule->name =
|
||||||
pyModule.empty() ? llvm::sys::path::stem(compiler->getInput()).str() : pyModule,
|
pyModule.empty() ? llvm::sys::path::stem(compiler->getInput()).str() : pyModule;
|
||||||
compiler->getModule(), filename);
|
compiler->getLLVMVisitor()->writeToPythonExtension(*compiler->getCache()->pyModule,
|
||||||
|
filename);
|
||||||
break;
|
break;
|
||||||
case BuildKind::Detect:
|
case BuildKind::Detect:
|
||||||
compiler->getLLVMVisitor()->compile(filename, argv0, libsVec, lflags);
|
compiler->getLLVMVisitor()->compile(filename, argv0, libsVec, lflags);
|
||||||
|
|
|
@ -655,65 +655,63 @@ llvm::Function *LLVMVisitor::createPyTryCatchWrapper(llvm::Function *func) {
|
||||||
return wrap;
|
return wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLVMVisitor::writeToPythonExtension(const std::string &name, const Module *module,
|
void LLVMVisitor::writeToPythonExtension(const PyModule &pymod,
|
||||||
const std::string &filename) {
|
const std::string &filename) {
|
||||||
// Construct PyMethodDef array
|
// Setup LLVM types & constants
|
||||||
|
auto *i64 = B->getInt64Ty();
|
||||||
|
auto *i32 = B->getInt32Ty();
|
||||||
auto *ptr = B->getInt8PtrTy();
|
auto *ptr = B->getInt8PtrTy();
|
||||||
|
auto *pyMethodDefType = llvm::StructType::create("PyMethodDef", ptr, ptr, i32, ptr);
|
||||||
|
auto *pyObjectType = llvm::StructType::create("PyObject", i64, ptr);
|
||||||
|
auto *pyModuleDefBaseType =
|
||||||
|
llvm::StructType::create("PyMethodDefBase", pyObjectType, ptr, i64, ptr);
|
||||||
|
auto *pyModuleDefType =
|
||||||
|
llvm::StructType::create("PyModuleDef", pyModuleDefBaseType, ptr, ptr, i64,
|
||||||
|
pyMethodDefType->getPointerTo(), ptr, ptr, ptr, ptr);
|
||||||
|
|
||||||
|
auto *zero64 = B->getInt64(0);
|
||||||
|
auto *zero32 = B->getInt32(0);
|
||||||
auto *null = llvm::Constant::getNullValue(ptr);
|
auto *null = llvm::Constant::getNullValue(ptr);
|
||||||
auto *pyMethodDefType = llvm::StructType::get(ptr, ptr, B->getInt32Ty(), ptr);
|
|
||||||
|
// Handle functions
|
||||||
std::vector<llvm::Constant *> pyMethods;
|
std::vector<llvm::Constant *> pyMethods;
|
||||||
|
for (auto &pyfunc : pymod.functions) {
|
||||||
for (auto *var : *module) {
|
auto llvmName = getNameForFunction(pyfunc.func);
|
||||||
auto *generated = cast<Func>(var);
|
|
||||||
if (!generated)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto *pyWrapAttr = generated->getAttribute<PythonWrapperAttribute>();
|
|
||||||
if (!pyWrapAttr)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto *original = pyWrapAttr->original;
|
|
||||||
auto llvmName = getNameForFunction(generated);
|
|
||||||
auto *llvmFunc = M->getFunction(llvmName);
|
auto *llvmFunc = M->getFunction(llvmName);
|
||||||
seqassertn(llvmFunc, "function {} not found in LLVM module", llvmName);
|
seqassertn(llvmFunc, "function {} not found in LLVM module", llvmName);
|
||||||
llvmFunc = createPyTryCatchWrapper(llvmFunc);
|
llvmFunc = createPyTryCatchWrapper(llvmFunc);
|
||||||
|
|
||||||
auto name = original->getUnmangledName();
|
|
||||||
if (ast::startswith(name, "._py_"))
|
|
||||||
name = name.substr(5);
|
|
||||||
auto *nameVar = new llvm::GlobalVariable(
|
auto *nameVar = new llvm::GlobalVariable(
|
||||||
*M, llvm::ArrayType::get(B->getInt8Ty(), name.length() + 1),
|
*M, llvm::ArrayType::get(B->getInt8Ty(), pyfunc.name.length() + 1),
|
||||||
/*isConstant=*/true, llvm::GlobalValue::PrivateLinkage,
|
/*isConstant=*/true, llvm::GlobalValue::PrivateLinkage,
|
||||||
llvm::ConstantDataArray::getString(*context, name), ".pyext_func_name");
|
llvm::ConstantDataArray::getString(*context, pyfunc.name), ".pyext_func_name");
|
||||||
nameVar->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
|
nameVar->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
|
||||||
|
|
||||||
auto *nameConst = llvm::ConstantExpr::getBitCast(nameVar, ptr);
|
|
||||||
auto *funcConst = llvm::ConstantExpr::getBitCast(llvmFunc, ptr);
|
|
||||||
auto numArgs = std::distance(original->arg_begin(), original->arg_end());
|
|
||||||
int flag = 0;
|
int flag = 0;
|
||||||
if (numArgs == 0) {
|
switch (pyfunc.nargs) {
|
||||||
|
case 0:
|
||||||
flag = PYEXT_METH_NOARGS;
|
flag = PYEXT_METH_NOARGS;
|
||||||
} else if (numArgs == 1) {
|
case 1:
|
||||||
flag = PYEXT_METH_O;
|
flag = PYEXT_METH_O;
|
||||||
} else {
|
default:
|
||||||
flag = PYEXT_METH_FASTCALL;
|
flag = PYEXT_METH_FASTCALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *flagConst = B->getInt32(flag);
|
auto *flagConst = B->getInt32(flag);
|
||||||
auto *docsConst = null;
|
auto *docsConst = null;
|
||||||
if (auto *docsAttr = original->getAttribute<DocstringAttribute>()) {
|
if (pyfunc.doc.empty()) {
|
||||||
auto docs = docsAttr->docstring;
|
|
||||||
auto *docsVar = new llvm::GlobalVariable(
|
auto *docsVar = new llvm::GlobalVariable(
|
||||||
*M, llvm::ArrayType::get(B->getInt8Ty(), docs.length() + 1),
|
*M, llvm::ArrayType::get(B->getInt8Ty(), pyfunc.doc.length() + 1),
|
||||||
/*isConstant=*/true, llvm::GlobalValue::PrivateLinkage,
|
/*isConstant=*/true, llvm::GlobalValue::PrivateLinkage,
|
||||||
llvm::ConstantDataArray::getString(*context, docs), ".pyext_docstring");
|
llvm::ConstantDataArray::getString(*context, pyfunc.doc), ".pyext_docstring");
|
||||||
docsVar->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
|
docsVar->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
|
||||||
docsConst = llvm::ConstantExpr::getBitCast(docsVar, ptr);
|
docsConst = llvm::ConstantExpr::getBitCast(docsVar, ptr);
|
||||||
}
|
}
|
||||||
pyMethods.push_back(llvm::ConstantStruct::get(pyMethodDefType, nameConst, funcConst,
|
pyMethods.push_back(llvm::ConstantStruct::get(pyMethodDefType, nameVar, llvmFunc,
|
||||||
flagConst, docsConst));
|
flagConst, docsConst));
|
||||||
}
|
}
|
||||||
pyMethods.push_back(
|
pyMethods.push_back(
|
||||||
llvm::ConstantStruct::get(pyMethodDefType, null, null, B->getInt32(0), null));
|
llvm::ConstantStruct::get(pyMethodDefType, null, null, zero32, null));
|
||||||
|
|
||||||
auto *pyMethodDefArrayType = llvm::ArrayType::get(pyMethodDefType, pyMethods.size());
|
auto *pyMethodDefArrayType = llvm::ArrayType::get(pyMethodDefType, pyMethods.size());
|
||||||
auto *pyMethodDefArray = new llvm::GlobalVariable(
|
auto *pyMethodDefArray = new llvm::GlobalVariable(
|
||||||
|
@ -722,31 +720,23 @@ void LLVMVisitor::writeToPythonExtension(const std::string &name, const Module *
|
||||||
llvm::ConstantArray::get(pyMethodDefArrayType, pyMethods), ".pyext_methods");
|
llvm::ConstantArray::get(pyMethodDefArrayType, pyMethods), ".pyext_methods");
|
||||||
|
|
||||||
// Construct PyModuleDef array
|
// Construct PyModuleDef array
|
||||||
auto *pyObjectType = llvm::StructType::get(B->getInt64Ty(), ptr);
|
|
||||||
auto *pyModuleDefBaseType =
|
|
||||||
llvm::StructType::get(pyObjectType, ptr, B->getInt64Ty(), ptr);
|
|
||||||
auto *pyModuleDefType =
|
|
||||||
llvm::StructType::get(pyModuleDefBaseType, ptr, ptr, B->getInt64Ty(),
|
|
||||||
pyMethodDefType->getPointerTo(), ptr, ptr, ptr, ptr);
|
|
||||||
|
|
||||||
auto *pyObjectConst = llvm::ConstantStruct::get(pyObjectType, B->getInt64(1), null);
|
auto *pyObjectConst = llvm::ConstantStruct::get(pyObjectType, B->getInt64(1), null);
|
||||||
auto *pyModuleDefBaseConst = llvm::ConstantStruct::get(
|
auto *pyModuleDefBaseConst = llvm::ConstantStruct::get(
|
||||||
pyModuleDefBaseType, pyObjectConst, null, B->getInt64(0), null);
|
pyModuleDefBaseType, pyObjectConst, null, B->getInt64(0), null);
|
||||||
|
|
||||||
auto *nameVar = new llvm::GlobalVariable(
|
auto *nameVar = new llvm::GlobalVariable(
|
||||||
*M, llvm::ArrayType::get(B->getInt8Ty(), name.length() + 1),
|
*M, llvm::ArrayType::get(B->getInt8Ty(), pymod.name.length() + 1),
|
||||||
/*isConstant=*/true, llvm::GlobalValue::PrivateLinkage,
|
/*isConstant=*/true, llvm::GlobalValue::PrivateLinkage,
|
||||||
llvm::ConstantDataArray::getString(*context, name), ".pyext_module_name");
|
llvm::ConstantDataArray::getString(*context, pymod.name), ".pyext_module_name");
|
||||||
nameVar->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
|
nameVar->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
|
||||||
auto nameConst = llvm::ConstantExpr::getBitCast(nameVar, ptr);
|
auto nameConst = llvm::ConstantExpr::getBitCast(nameVar, ptr);
|
||||||
|
|
||||||
auto *docsConst = null;
|
auto *docsConst = null;
|
||||||
if (auto *docsAttr = module->getAttribute<DocstringAttribute>()) {
|
if (!pymod.doc.empty()) {
|
||||||
auto docs = docsAttr->docstring;
|
|
||||||
auto *docsVar = new llvm::GlobalVariable(
|
auto *docsVar = new llvm::GlobalVariable(
|
||||||
*M, llvm::ArrayType::get(B->getInt8Ty(), docs.length() + 1),
|
*M, llvm::ArrayType::get(B->getInt8Ty(), pymod.doc.length() + 1),
|
||||||
/*isConstant=*/true, llvm::GlobalValue::PrivateLinkage,
|
/*isConstant=*/true, llvm::GlobalValue::PrivateLinkage,
|
||||||
llvm::ConstantDataArray::getString(*context, docs), ".pyext_docstring");
|
llvm::ConstantDataArray::getString(*context, pymod.doc), ".pyext_docstring");
|
||||||
docsVar->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
|
docsVar->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
|
||||||
docsConst = llvm::ConstantExpr::getBitCast(docsVar, ptr);
|
docsConst = llvm::ConstantExpr::getBitCast(docsVar, ptr);
|
||||||
}
|
}
|
||||||
|
@ -762,24 +752,23 @@ void LLVMVisitor::writeToPythonExtension(const std::string &name, const Module *
|
||||||
auto *pyModuleConst = llvm::ConstantExpr::getBitCast(pyModuleVar, ptr);
|
auto *pyModuleConst = llvm::ConstantExpr::getBitCast(pyModuleVar, ptr);
|
||||||
|
|
||||||
// Construct initialization hook
|
// Construct initialization hook
|
||||||
auto *pyModuleCreate = cast<llvm::Function>(
|
auto *pyModuleCreate = llvm::cast<llvm::Function>(
|
||||||
M->getOrInsertFunction("PyModule_Create2", ptr, ptr, B->getInt32Ty())
|
M->getOrInsertFunction("PyModule_Create2", ptr, ptr, i32).getCallee());
|
||||||
.getCallee());
|
|
||||||
pyModuleCreate->setDoesNotThrow();
|
pyModuleCreate->setDoesNotThrow();
|
||||||
|
|
||||||
auto *pyModuleInit =
|
auto *pyModuleInit = llvm::cast<llvm::Function>(
|
||||||
cast<llvm::Function>(M->getOrInsertFunction("PyInit_" + name, ptr).getCallee());
|
M->getOrInsertFunction("PyInit_" + pymod.name, ptr).getCallee());
|
||||||
auto *entry = llvm::BasicBlock::Create(*context, "entry", pyModuleInit);
|
auto *entry = llvm::BasicBlock::Create(*context, "entry", pyModuleInit);
|
||||||
B->SetInsertPoint(entry);
|
B->SetInsertPoint(entry);
|
||||||
if (auto *main = M->getFunction("main")) {
|
if (auto *main = M->getFunction("main")) {
|
||||||
main->setName(".main");
|
main->setName(".main");
|
||||||
B->CreateCall({main->getFunctionType(), main},
|
B->CreateCall({main->getFunctionType(), main}, {zero32, null});
|
||||||
{B->getInt32(0),
|
|
||||||
llvm::ConstantPointerNull::get(B->getInt8PtrTy()->getPointerTo())});
|
|
||||||
}
|
}
|
||||||
B->CreateRet(B->CreateCall(pyModuleCreate,
|
B->CreateRet(B->CreateCall(pyModuleCreate,
|
||||||
{pyModuleConst, B->getInt32(PYEXT_PYTHON_ABI_VERSION)}));
|
{pyModuleConst, B->getInt32(PYEXT_PYTHON_ABI_VERSION)}));
|
||||||
|
|
||||||
|
// TODO: Codegen types, methods, etc.
|
||||||
|
|
||||||
writeToObjectFile(filename);
|
writeToObjectFile(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "codon/cir/cir.h"
|
#include "codon/cir/cir.h"
|
||||||
#include "codon/cir/llvm/llvm.h"
|
#include "codon/cir/llvm/llvm.h"
|
||||||
|
#include "codon/cir/pyextension.h"
|
||||||
#include "codon/dsl/plugins.h"
|
#include "codon/dsl/plugins.h"
|
||||||
#include "codon/util/common.h"
|
#include "codon/util/common.h"
|
||||||
|
|
||||||
|
@ -345,14 +346,10 @@ public:
|
||||||
bool library = false,
|
bool library = false,
|
||||||
const std::vector<std::string> &libs = {},
|
const std::vector<std::string> &libs = {},
|
||||||
const std::string &lflags = "");
|
const std::string &lflags = "");
|
||||||
/// Writes module as Python extension object. Exposes
|
/// Writes module as Python extension object.
|
||||||
/// functions based on "PythonWrapperAttribute" attached
|
/// @param pymod extension module
|
||||||
/// to IR functions.
|
|
||||||
/// @param name the module's name
|
|
||||||
/// @param module the IR module
|
|
||||||
/// @param filename the file to write to
|
/// @param filename the file to write to
|
||||||
void writeToPythonExtension(const std::string &name, const Module *module,
|
void writeToPythonExtension(const PyModule &pymod, const std::string &filename);
|
||||||
const std::string &filename);
|
|
||||||
/// Runs optimization passes on module and writes the result
|
/// Runs optimization passes on module and writes the result
|
||||||
/// to the specified file. The output type is determined by
|
/// to the specified file. The output type is determined by
|
||||||
/// the file extension (.ll for LLVM IR, .bc for LLVM bitcode
|
/// the file extension (.ll for LLVM IR, .bc for LLVM bitcode
|
||||||
|
|
Loading…
Reference in New Issue