Add member codegen

pull/335/head
A. R. Shajii 2023-02-12 10:54:43 -05:00
parent 7c4c4a416f
commit b336fc6617
2 changed files with 110 additions and 63 deletions

View File

@ -560,6 +560,8 @@ constexpr int PYEXT_METH_FASTCALL = 0x0080;
constexpr int PYEXT_METH_METHOD = 0x0200;
// https://github.com/python/cpython/blob/main/Include/modsupport.h
constexpr int PYEXT_PYTHON_ABI_VERSION = 1013;
// https://github.com/python/cpython/blob/main/Include/descrobject.h
constexpr int PYEXT_READONLY = 1;
} // namespace
llvm::Function *LLVMVisitor::createPyTryCatchWrapper(llvm::Function *func) {
@ -670,6 +672,8 @@ void LLVMVisitor::writeToPythonExtension(const PyModule &pymod,
auto *pyModuleDefType =
llvm::StructType::create("PyModuleDef", pyModuleDefBaseType, ptr, ptr, i64,
pyMethodDefType->getPointerTo(), ptr, ptr, ptr, ptr);
auto *pyMemberDefType =
llvm::StructType::create("PyMemberDef", ptr, i32, i64, i32, ptr);
auto *pyGetSetDefType =
llvm::StructType::create("PyGetSetDef", ptr, ptr, ptr, ptr, ptr);
std::vector<llvm::Type *> pyNumberMethodsFields(36, ptr);
@ -730,7 +734,10 @@ void LLVMVisitor::writeToPythonExtension(const PyModule &pymod,
return var;
};
auto pyFunctions = [&](const std::vector<PyFunction> &functions) {
auto pyFunctions = [&](const std::vector<PyFunction> &functions) -> llvm::Constant * {
if (functions.empty())
return null;
std::vector<llvm::Constant *> pyMethods;
for (auto &pyfunc : functions) {
int flag = 0;
@ -759,7 +766,40 @@ void LLVMVisitor::writeToPythonExtension(const PyModule &pymod,
return pyMethodDefArray;
};
auto pyGetSet = [&](const std::vector<PyGetSet> &getset) {
auto pyMembers = [&](const std::vector<PyMember> &members,
llvm::StructType *type) -> llvm::Constant * {
if (members.empty())
return null;
std::vector<llvm::Constant *> pyMemb;
for (auto &memb : members) {
// Calculate offset by creating const GEP into null ptr
std::vector<llvm::Constant *> indexes = {zero64, B->getInt64(1)};
for (auto idx : memb.indexes) {
indexes.push_back(B->getInt64(idx));
}
auto offset = llvm::ConstantExpr::getPtrToInt(
llvm::ConstantExpr::getGetElementPtr(type, null, indexes), i64);
pyMemb.push_back(llvm::ConstantStruct::get(
pyMemberDefType, pyString(memb.name), B->getInt32(memb.type), offset,
B->getInt32(memb.readonly ? PYEXT_READONLY : 0), pyString(memb.doc)));
}
pyMemb.push_back(
llvm::ConstantStruct::get(pyMemberDefType, null, zero32, zero64, zero32, null));
auto *pyMemberDefArrayType = llvm::ArrayType::get(pyMemberDefType, pyMemb.size());
auto *pyMemberDefArray = new llvm::GlobalVariable(
*M, pyMemberDefArrayType,
/*isConstant=*/false, llvm::GlobalValue::PrivateLinkage,
llvm::ConstantArray::get(pyMemberDefArrayType, pyMemb), ".pyext_members");
return pyMemberDefArray;
};
auto pyGetSet = [&](const std::vector<PyGetSet> &getset) -> llvm::Constant * {
if (getset.empty())
return null;
std::vector<llvm::Constant *> pyGS;
for (auto &gs : getset) {
pyGS.push_back(llvm::ConstantStruct::get(pyGetSetDefType, pyString(gs.name),
@ -894,51 +934,51 @@ void LLVMVisitor::writeToPythonExtension(const PyModule &pymod,
B->getInt64(pySize), // tp_basicsize
zero64, // tp_itemsize
free, // tp_dealloc
zero64, // tp_vectorcall_offset
null, // tp_getattr
null, // tp_setattr
null, // tp_as_async
pyFunc(pytype.repr), // tp_repr
numberSlotsConst, // tp_as_number
sequenceSlotsConst, // tp_as_sequence
null, // tp_as_mapping
pyFunc(pytype.hash), // tp_hash
pyFunc(pytype.call), // tp_call
pyFunc(pytype.str), // tp_str
null, // tp_getattro
null, // tp_setattro
null, // tp_as_buffer
zero64, // tp_vectorcall_offset
null, // tp_getattr
null, // tp_setattr
null, // tp_as_async
pyFunc(pytype.repr), // tp_repr
numberSlotsConst, // tp_as_number
sequenceSlotsConst, // tp_as_sequence
null, // tp_as_mapping
pyFunc(pytype.hash), // tp_hash
pyFunc(pytype.call), // tp_call
pyFunc(pytype.str), // tp_str
null, // tp_getattro
null, // tp_setattro
null, // tp_as_buffer
zero64, // tp_flags
pyString(pytype.doc), // tp_doc
null, // tp_traverse
null, // tp_clear
pyFunc(pytype.cmp), // tp_richcompare
zero64, // tp_weaklistoffset
pyFunc(pytype.iter), // tp_iter
pyFunc(pytype.iternext), // tp_iternext
pyFunctions(pytype.methods), // tp_methods
null, // tp_members
pyGetSet(pytype.getset), // tp_getset
null, // tp_base
null, // tp_dict
null, // tp_descr_get
null, // tp_descr_set
zero64, // tp_dictoffset
pyFunc(pytype.init), // tp_init
alloc, // tp_alloc
null, // tp_new
free, // tp_free
null, // tp_is_gc
null, // tp_bases
null, // tp_mro
null, // tp_cache
null, // tp_subclasses
null, // tp_weaklist
null, // tp_del
zero32, // tp_version_tag
pyFunc(pytype.del), // tp_finalize
null, // tp_vectorcall
B->getInt8(0), // tp_watched
null, // tp_traverse
null, // tp_clear
pyFunc(pytype.cmp), // tp_richcompare
zero64, // tp_weaklistoffset
pyFunc(pytype.iter), // tp_iter
pyFunc(pytype.iternext), // tp_iternext
pyFunctions(pytype.methods), // tp_methods
pyMembers(pytype.members, objectType), // tp_members
pyGetSet(pytype.getset), // tp_getset
null, // tp_base
null, // tp_dict
null, // tp_descr_get
null, // tp_descr_set
zero64, // tp_dictoffset
pyFunc(pytype.init), // tp_init
alloc, // tp_alloc
null, // tp_new
free, // tp_free
null, // tp_is_gc
null, // tp_bases
null, // tp_mro
null, // tp_cache
null, // tp_subclasses
null, // tp_weaklist
null, // tp_del
zero32, // tp_version_tag
pyFunc(pytype.del), // tp_finalize
null, // tp_vectorcall
B->getInt8(0), // tp_watched
};
auto *pyTypeObjectVar = new llvm::GlobalVariable(

View File

@ -22,30 +22,37 @@ struct PyFunction {
struct PyMember {
enum Type {
SHORT,
INT,
LONG,
FLOAT,
DOUBLE,
STRING,
OBJECT,
OBJECT_EX,
CHAR,
BYTE,
UBYTE,
UINT,
USHORT,
ULONG,
BOOL,
LONGLONG,
ULONGLONG,
PYSSIZET
SHORT = 0,
INT = 1,
LONG = 2,
FLOAT = 3,
DOUBLE = 4,
STRING = 5,
OBJECT = 6,
CHAR = 7,
BYTE = 8,
UBYTE = 9,
USHORT = 10,
UINT = 11,
ULONG = 12,
STRING_INPLACE = 13,
BOOL = 14,
OBJECT_EX = 16,
LONGLONG = 17,
ULONGLONG = 18,
PYSSIZET = 19,
};
std::string name;
std::string doc;
Type type = Type::SHORT;
bool readonly = false;
/// Indexes of the member. For example, in the
/// tuple (a, (b, c, (d,))), 'a' would have indexes
/// [0], 'b' would have indexes [1, 0], 'c' would
/// have indexes [1, 1], and 'd' would have indexes
/// [1, 2, 0]. This corresponds to an LLVM GEP.
std::vector<int> indexes;
};
struct PyGetSet {