diff --git a/docs/source/development.rst b/docs/source/development.rst index 8f1ed1e..80b37cd 100644 --- a/docs/source/development.rst +++ b/docs/source/development.rst @@ -80,3 +80,14 @@ As a contrast, the following went smooth. In conclusion, it is suggested that classes which do self memory control shouldn't be appeared as a default argument of some functions. + + +Resources / References +---------------------- + +LLVM online reference are all of the latest version. To view reference of a certain version, +please manually build the docs. + +- `LLVM C API doxygen `_ +- `LLVM Reference Manual `_ + diff --git a/example/parse_ir_assmebly.py b/example/parse_ir_assmebly.py index 0081bbd..e95b0e8 100644 --- a/example/parse_ir_assmebly.py +++ b/example/parse_ir_assmebly.py @@ -27,7 +27,15 @@ m = utils.parse_assembly(asm_str) for f in m.functions: - print(f'Function: {f.name}/`{f.type}`') - m = f.parent + print(f'Function | name: "{f.name}", type: "{f.type}"') + module = f.parent + # assert m == module assert f.kind == core.ValueKind.Function - print(f"Functoin attributes: {}") + print() + for i, a in enumerate(f.args, 1): + print(f'Argument | name: "{a.name}", type: "{a.type}"') + attrs = f.get_attributes_at_index(i) + print(f"\tattrs: {attrs}") + + print("\n----------------------------\n") + diff --git a/src/llvm/Core/iterator.cpp b/src/llvm/Core/iterator.cpp index a8b10b5..7be9326 100644 --- a/src/llvm/Core/iterator.cpp +++ b/src/llvm/Core/iterator.cpp @@ -9,7 +9,7 @@ using namespace nb::literals; void bindIterators(nb::module_ &m) { BIND_ITERATOR_CLASS(PyUseIterator, "UseIterator") BIND_ITERATOR_CLASS(PyBasicBlockIterator, "BasicBlockIterator") - BIND_ITERATOR_CLASS(PyArgumentIterator, "ArgumentIterator") + // BIND_ITERATOR_CLASS(PyArgumentIterator, "ArgumentIterator") BIND_ITERATOR_CLASS(PyInstructionIterator, "InstructionIterator") BIND_ITERATOR_CLASS(PyGlobalVariableIterator, "GlobalVariableIterator") BIND_ITERATOR_CLASS(PyGlobalIFuncIterator, "GlobalIFuncIterator") diff --git a/src/llvm/Core/type.cpp b/src/llvm/Core/type.cpp index 8c2b1e0..e3c0fd6 100644 --- a/src/llvm/Core/type.cpp +++ b/src/llvm/Core/type.cpp @@ -17,7 +17,24 @@ template using optional = std::optional; void bindTypeClasses(nb::module_ &m) { - nb::class_(m, "Type", "Type") + auto TypeClass = nb::class_(m, "Type", "Type"); + auto TypeIntClass = nb::class_(m, "IntType", "IntType"); + auto TypeRealClass = nb::class_(m, "RealType", "RealType"); + auto TypeFunctionClass = nb::class_ (m, "FunctionType", "FunctionType"); + auto TypeStructClass = nb::class_ (m, "StructType", "StructType"); + auto TypeSequenceClass = nb::class_(m, "SequenceType", "SequenceType"); + auto TypeArrayClass = nb::class_(m, "ArrayType", "ArrayType"); + auto TypePointerClass = nb::class_(m, "PointerType", "PointerType"); + auto TypeVectorClass = nb::class_(m, "VectorType", "VectorType"); + auto TypeVoidClass = nb::class_(m, "VoidType", "VoidType"); + auto TypeLabelClass = nb::class_(m, "LabelType", "LabelType"); + auto TypeX86MMXClass = nb::class_(m, "X86MMXType", "X86MMXType"); + auto TypeX86AMXClass = nb::class_(m, "X86AMXType", "X86AMXType"); + auto TypeTokenClass = nb::class_(m, "TokenType", "TokenType"); + auto TypeMetadataClass = nb::class_(m, "MetadataType", "MetadataType"); + auto TypeTargetExtClass = nb::class_(m, "TargetExtType", "TargetExtType"); + + TypeClass .def("__repr__", [](PyType &self) { auto kind = get_repr_str(LLVMGetTypeKind(self.get())); @@ -80,24 +97,8 @@ void bindTypeClasses(nb::module_ &m) { return LLVMDumpType(self.get()); }, "Dump a representation of a type to stderr."); - - auto TypeIntClass = nb::class_(m, "IntType", "IntType"); - auto TypeRealClass = nb::class_(m, "RealType", "RealType"); - auto TypeFunctionClass = nb::class_ (m, "FunctionType", "FunctionType"); - auto TypeStructClass = nb::class_ (m, "StructType", "StructType"); - auto TypeSequenceClass = nb::class_(m, "SequenceType", "SequenceType"); - auto TypeArrayClass = nb::class_(m, "ArrayType", "ArrayType"); - auto TypePointerClass = nb::class_(m, "PointerType", "PointerType"); - auto TypeVectorClass = nb::class_(m, "VectorType", "VectorType"); - auto TypeVoidClass = nb::class_(m, "VoidType", "VoidType"); - auto TypeLabelClass = nb::class_(m, "LabelType", "LabelType"); - auto TypeX86MMXClass = nb::class_(m, "X86MMXType", "X86MMXType"); - auto TypeX86AMXClass = nb::class_(m, "X86AMXType", "X86AMXType"); - auto TypeTokenClass = nb::class_(m, "TokenType", "TokenType"); - auto TypeMetadataClass = nb::class_(m, "MetadataType", "MetadataType"); - auto TypeTargetExtClass = nb::class_(m, "TargetExtType", "TargetExtType"); - + TypeIntClass .def("__repr__", [](PyTypeInt &self) { diff --git a/src/llvm/Core/value.cpp b/src/llvm/Core/value.cpp index 8e2a8f5..0ae510d 100644 --- a/src/llvm/Core/value.cpp +++ b/src/llvm/Core/value.cpp @@ -18,8 +18,8 @@ using optional = std::optional; void bindValueClasses(nb::module_ &m) { - auto ValueClass = nb::class_(m, "Value", "Value"); - + auto ValueClass = nb::class_> + (m, "Value", "Value"); nb::class_(m, "MetadataAsValue", "MetadataAsValue"); auto MDNodeValueClass = nb::class_ (m, "MDNodeValue", "MDNodeValue"); @@ -696,7 +696,7 @@ void bindValueClasses(nb::module_ &m) { }, "index"_a, "Obtain the operand bundle attached to this instruction at the given index.") - .def("set_param_alignment", + .def("set_arg_alignment", [](PyCallBase &self, LLVMAttributeIndex idx, unsigned align) { return LLVMSetInstrParamAlignment(self.get(), idx, align); }, @@ -1086,34 +1086,29 @@ void bindValueClasses(nb::module_ &m) { .def_prop_ro("debug_loc_line", [](PyFunction &f) { return LLVMGetDebugLocLine(f.get()); }, "Return the line number of the debug location for this value") - .def_prop_ro("param_num", + .def_prop_ro("arg_num", [](PyFunction &self) { return LLVMCountParams(self.get()); }) - .def_prop_ro("params", - [](PyFunction &self) { - unsigned param_num = LLVMCountParams(self.get()); - std::vector params(param_num); - LLVMGetParams(self.get(), params.data()); - WRAP_VECTOR_FROM_DEST(PyArgument, param_num, res, params); - return res; - }) - .def_prop_ro("first_param", + .def_prop_ro("first_arg", [](PyFunction &self) -> optional { auto res = LLVMGetFirstParam(self.get()); WRAP_OPTIONAL_RETURN(res, PyArgument); }) - .def_prop_ro("last_param", + .def_prop_ro("last_arg", [](PyFunction &self) -> optional { auto res = LLVMGetLastParam(self.get()); WRAP_OPTIONAL_RETURN(res, PyArgument); }) - // .def_prop_ro("params", // also have the same name method - // [](PyFunction &self) { - // auto res = LLVMGetFirstParam(self.get()); - // return PyArgumentIterator(PyArgument(res)); - // }) - .def("get_param", + .def_prop_ro("args", + [](PyFunction &self) { + unsigned param_num = LLVMCountParams(self.get()); + std::vector params(param_num); + LLVMGetParams(self.get(), params.data()); + WRAP_VECTOR_FROM_DEST(PyArgument, param_num, res, params); + return res; + }) + .def("get_arg", [](PyFunction &self, unsigned index) { return PyArgument(LLVMGetParam(self.get(), index)); }, diff --git a/src/llvm/_types.h b/src/llvm/_types.h index fb59437..cb25960 100644 --- a/src/llvm/_types.h +++ b/src/llvm/_types.h @@ -1,3 +1,7 @@ +// For type/value class hierarchy see doxygen/group__LLVMCCore.html +// +// ==================================== + #ifndef LLVMPYM__TYPES_H #define LLVMPYM__TYPES_H @@ -20,7 +24,7 @@ #define DEFINE_PY_WRAPPER_CLASS(ClassName, UnderlyingType) \ - class ClassName { \ + class ClassName: public PyLLVMObject { \ public: \ explicit ClassName(UnderlyingType raw) \ : raw(raw) {} \ @@ -34,7 +38,7 @@ }; #define DEFINE_PY_WRAPPER_CLASS_POLYMORPHIC(ClassName, UnderlyingType) \ - class ClassName { \ + class ClassName: public PyLLVMObject { \ public: \ virtual ~ClassName() = default; \ explicit ClassName(UnderlyingType raw) \ @@ -245,6 +249,31 @@ enum class PyLLVMFastMathFlags { All = LLVMFastMathAll }; +template +class PyLLVMObject { +public: + virtual ~PyLLVMObject() = default; + + UnderlyingType get() const { + return const_cast(static_cast(this))->get(); + } + + bool __bool__() const { + UnderlyingType raw = static_cast(get()); + if (!raw) return false; + return true; + } + + // `__equal__` and `__hash__` works well on pointer type UnderlyingType + bool __equal__(const PyLLVMObject& other) const { + return this->get() == other.get(); + } + + std::size_t __hash__() const { + return std::hash{}(this->get()); + } +}; + DEFINE_PY_WRAPPER_CLASS_POLYMORPHIC(PyValue, LLVMValueRef) DEFINE_PY_WRAPPER_CLASS_POLYMORPHIC(PyType, LLVMTypeRef) @@ -309,7 +338,7 @@ DEFINE_DIRECT_SUB_CLASS(PyPassManagerBase, PyFunctionPassManager); DEFINE_ITERATOR_CLASS(PyUseIterator, PyUse, LLVMGetNextUse) DEFINE_ITERATOR_CLASS(PyBasicBlockIterator, PyBasicBlock, LLVMGetNextBasicBlock) -DEFINE_ITERATOR_CLASS(PyArgumentIterator, PyArgument, LLVMGetNextParam) +// DEFINE_ITERATOR_CLASS(PyArgumentIterator, PyArgument, LLVMGetNextParam) DEFINE_ITERATOR_CLASS(PyInstructionIterator, PyInstruction, LLVMGetNextInstruction) DEFINE_ITERATOR_CLASS(PyGlobalVariableIterator, PyGlobalVariable, LLVMGetNextGlobal) DEFINE_ITERATOR_CLASS(PyGlobalIFuncIterator, PyGlobalIFunc, LLVMGetNextGlobalIFunc) diff --git a/src/llvmpym_ext.cpp b/src/llvmpym_ext.cpp index 562d816..9ae5183 100644 --- a/src/llvmpym_ext.cpp +++ b/src/llvmpym_ext.cpp @@ -2,6 +2,7 @@ #include "llvm/Core.h" #include "llvm/ErrorHandling.h" #include "llvm/Utils.h" +#include "llvm/_types.h" namespace nb = nanobind; using namespace nb::literals; @@ -10,6 +11,12 @@ using namespace nb::literals; NB_MODULE(llvmpym_ext, m) { m.doc() = "LLVM Python Native Extension"; + nb::class_> + (m, "LLVMObject", "The base of for all LLVM object classes.") + .def("__bool__", &PyLLVMObject::__bool__) + .def("__eq__", &PyLLVMObject::__equal__) + .def("__hash__", &PyLLVMObject::__hash__); + auto coreModule = m.def_submodule("core", "LLVM Core"); populateCore(coreModule); diff --git a/tests/test_core.py b/tests/test_core.py index 21e9564..6fdf6e2 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -42,3 +42,9 @@ def test_module(self): pass +class TestEquality: + # TODO + def test_value(self): + x = ConstantInt(IntType.GlobalInt32, 100, True) + y = ConstantInt(IntType.GlobalInt32, 100, True) + assert x == y