Skip to content

Commit

Permalink
Merge pull request #978 from tbennun/type-query-4
Browse files Browse the repository at this point in the history
Bindings: Query type kinds, derived types, and elements
  • Loading branch information
sklam authored Dec 8, 2023
2 parents e70590f + 80bb55b commit 4292eea
Show file tree
Hide file tree
Showing 12 changed files with 510 additions and 86 deletions.
49 changes: 49 additions & 0 deletions docs/source/user-guide/binding/type-references.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,65 @@ A wrapper around an LLVM type. The attributes available are:

This type's name, as a string.

* .. attribute:: is_struct

* ``True``---The type is a struct type
* ``False``---The type is not a struct type

* .. attribute:: is_pointer

* ``True``---The type is a pointer type
* ``False``---The type is not a pointer type

* .. attribute:: is_array

* ``True``---The type is an array type
* ``False``---The type is not an array type

* .. attribute:: is_vector

* ``True``---The type is a vector type
* ``False``---The type is not a vector type

* .. attribute:: is_function_vararg

* ``True``--- The function type accepts a variable number of arguments
* ``False``---The function type accepts a fixed number of arguments

* .. attribute:: elements

Returns an iterator over enclosing types. For example,
the elements of an array or members of a struct.

* .. attribute:: element_type

If the type is a pointer, return the pointed-to type. Raises a
ValueError if the type is not a pointer type.

* .. attribute:: element_count

Returns the number of elements in an array or a vector. For scalable
vectors, returns minimum number of elements. When the type is neither
an array nor a vector, raises exception.

* .. attribute:: type_width

Return the basic size of this type if it is a primitive type. These are
fixed by LLVM and are not target-dependent.
This will return zero if the type does not have a size or is not a
primitive type.

If this is a scalable vector type, the scalable property will be set and
the runtime size will be a positive integer multiple of the base size.

Note that this may not reflect the size of memory allocated for an
instance of the type or the number of bytes that are written when an
instance of the type is stored to memory.

* .. attribute:: type_kind

Returns the ``LLVMTypeKind`` enumeration of this type.

* .. method:: __str__(self)

Get the string IR representation of the type.
2 changes: 1 addition & 1 deletion ffi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ endif()

# Define our shared library
add_library(llvmlite SHARED assembly.cpp bitcode.cpp core.cpp initfini.cpp
module.cpp value.cpp executionengine.cpp transforms.cpp
module.cpp value.cpp executionengine.cpp transforms.cpp type.cpp
passmanagers.cpp targets.cpp dylib.cpp linker.cpp object_file.cpp
custom_passes.cpp orcjit.cpp memorymanager.cpp)

Expand Down
5 changes: 3 additions & 2 deletions ffi/Makefile.freebsd
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ LDFLAGS := $(LDFLAGS) $(LLVM_LDFLAGS) $(LD_FLTO_FLAGS)
LIBS = $(LLVM_LIBS)
INCLUDE = core.h
SRC = assembly.cpp bitcode.cpp core.cpp initfini.cpp module.cpp value.cpp \
executionengine.cpp transforms.cpp passmanagers.cpp targets.cpp dylib.cpp \
linker.cpp object_file.cpp orcjit.cpp custom_passes.cpp memorymanager.cpp
executionengine.cpp transforms.cpp passmanagers.cpp type.cpp targets.cpp \
dylib.cpp linker.cpp object_file.cpp orcjit.cpp custom_passes.cpp \
memorymanager.cpp
OUTPUT = libllvmlite.so

all: $(OUTPUT)
Expand Down
2 changes: 1 addition & 1 deletion ffi/Makefile.linux
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ LDFLAGS := $(LDFLAGS) $(LLVM_LDFLAGS) $(LD_FLTO_FLAGS)
LIBS = $(LLVM_LIBS)
INCLUDE = core.h
OBJ = assembly.o bitcode.o core.o initfini.o module.o value.o \
executionengine.o transforms.o passmanagers.o targets.o dylib.o \
executionengine.o transforms.o passmanagers.o targets.o type.o dylib.o \
linker.o object_file.o custom_passes.o orcjit.o memorymanager.o
OUTPUT = libllvmlite.so

Expand Down
5 changes: 3 additions & 2 deletions ffi/Makefile.osx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ LDFLAGS := $(LDFLAGS) $(EXPORT) $(LLVM_LDFLAGS)
LIBS = $(LLVM_LIBS)
INCLUDE = core.h
SRC = assembly.cpp bitcode.cpp core.cpp initfini.cpp module.cpp value.cpp \
executionengine.cpp transforms.cpp passmanagers.cpp targets.cpp dylib.cpp \
linker.cpp object_file.cpp custom_passes.cpp orcjit.cpp memorymanager.cpp
executionengine.cpp transforms.cpp passmanagers.cpp targets.cpp type.cpp \
dylib.cpp linker.cpp object_file.cpp custom_passes.cpp orcjit.cpp \
memorymanager.cpp
OUTPUT = libllvmlite.dylib
MACOSX_DEPLOYMENT_TARGET ?= 10.9

Expand Down
159 changes: 159 additions & 0 deletions ffi/type.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
#include "core.h"
#include "llvm-c/Core.h"
#include <string>

#include <iostream>

#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Type.h"

struct ElementIterator {
typedef llvm::ArrayRef<llvm::Type *>::iterator subtype_iterator;
subtype_iterator cur;
subtype_iterator end;
ElementIterator(subtype_iterator cur, subtype_iterator end)
: cur(cur), end(end) {}
};

struct OpaqueElementIterator;
typedef OpaqueElementIterator *LLVMElementIteratorRef;

namespace llvm {
static LLVMElementIteratorRef wrap(ElementIterator *GI) {
return reinterpret_cast<LLVMElementIteratorRef>(GI);
}

static ElementIterator *unwrap(LLVMElementIteratorRef GI) {
return reinterpret_cast<ElementIterator *>(GI);
}
} // namespace llvm

extern "C" {

API_EXPORT(LLVMElementIteratorRef)
LLVMPY_ElementIter(LLVMTypeRef Val) {
using namespace llvm;
llvm::Type *ty = llvm::unwrap(Val);
auto elements = ty->subtypes();
return wrap(new ElementIterator(elements.begin(), elements.end()));
}

API_EXPORT(LLVMTypeRef)
LLVMPY_ElementIterNext(LLVMElementIteratorRef GI) {
using namespace llvm;
ElementIterator *iter = unwrap(GI);
if (iter->cur != iter->end) {
const Type *ty = *(iter->cur);
iter->cur++;
return wrap(static_cast<const Type *>(ty));
} else {
return NULL;
}
}

API_EXPORT(void)
LLVMPY_DisposeElementIter(LLVMElementIteratorRef GI) {
delete llvm::unwrap(GI);
}

API_EXPORT(int)
LLVMPY_GetTypeKind(LLVMTypeRef Val) { return (int)LLVMGetTypeKind(Val); }

API_EXPORT(LLVMTypeRef)
LLVMPY_TypeOf(LLVMValueRef Val) { return LLVMTypeOf(Val); }

API_EXPORT(const char *)
LLVMPY_PrintType(LLVMTypeRef type) {
char *str = LLVMPrintTypeToString(type);
const char *out = LLVMPY_CreateString(str);
LLVMDisposeMessage(str);
return out;
}

API_EXPORT(const char *)
LLVMPY_GetTypeName(LLVMTypeRef type) {
// try to convert to a struct type, works for other derived
// types too
llvm::Type *unwrapped = llvm::unwrap(type);
llvm::StructType *ty = llvm::dyn_cast<llvm::StructType>(unwrapped);
if (ty && !ty->isLiteral()) {
return LLVMPY_CreateString(ty->getStructName().str().c_str());
}
return LLVMPY_CreateString("");
}

API_EXPORT(bool)
LLVMPY_TypeIsPointer(LLVMTypeRef type) {
return llvm::unwrap(type)->isPointerTy();
}

API_EXPORT(bool)
LLVMPY_TypeIsArray(LLVMTypeRef type) { return llvm::unwrap(type)->isArrayTy(); }

API_EXPORT(bool)
LLVMPY_TypeIsVector(LLVMTypeRef type) {
return llvm::unwrap(type)->isVectorTy();
}

API_EXPORT(bool)
LLVMPY_TypeIsStruct(LLVMTypeRef type) {
return llvm::unwrap(type)->isStructTy();
}

API_EXPORT(bool)
LLVMPY_IsFunctionVararg(LLVMTypeRef type) {
llvm::Type *unwrapped = llvm::unwrap(type);
llvm::FunctionType *ty = llvm::dyn_cast<llvm::FunctionType>(unwrapped);
if (ty != nullptr) {
return ty->isVarArg();
}
return false;
}

API_EXPORT(int)
LLVMPY_GetTypeElementCount(LLVMTypeRef type) {
llvm::Type *unwrapped = llvm::unwrap(type);
if (unwrapped->isArrayTy()) {
return unwrapped->getArrayNumElements();
}
if (unwrapped->isVectorTy()) {
// Fixed vector: get exact number of elements
llvm::FixedVectorType *fixedvec =
llvm::dyn_cast<llvm::FixedVectorType>(unwrapped);
if (fixedvec != nullptr) {
return fixedvec->getNumElements();
}

// Scalable vector: get minimum elements
llvm::ScalableVectorType *scalablevec =
llvm::dyn_cast<llvm::ScalableVectorType>(unwrapped);
if (scalablevec != nullptr) {
return scalablevec->getMinNumElements();
}
}
// Not an array nor vector
return -1;
}

API_EXPORT(uint64_t)
LLVMPY_GetTypeBitWidth(LLVMTypeRef type) {
llvm::Type *unwrapped = llvm::unwrap(type);
auto size = unwrapped->getPrimitiveSizeInBits();
return size.getFixedSize();
}

API_EXPORT(LLVMTypeRef)
LLVMPY_GetElementType(LLVMTypeRef type) {
llvm::Type *unwrapped = llvm::unwrap(type);
llvm::PointerType *ty = llvm::dyn_cast<llvm::PointerType>(unwrapped);
if (ty != nullptr) {
#if LLVM_VERSION_MAJOR < 14
return llvm::wrap(ty->getElementType());
#else
return llvm::wrap(ty->getPointerElementType());
#endif
}
return nullptr;
}

} // end extern "C"
38 changes: 0 additions & 38 deletions ffi/value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -403,44 +403,6 @@ LLVMPY_SetValueName(LLVMValueRef Val, const char *Name) {
API_EXPORT(LLVMModuleRef)
LLVMPY_GetGlobalParent(LLVMValueRef Val) { return LLVMGetGlobalParent(Val); }

API_EXPORT(LLVMTypeRef)
LLVMPY_TypeOf(LLVMValueRef Val) { return LLVMTypeOf(Val); }

API_EXPORT(const char *)
LLVMPY_PrintType(LLVMTypeRef type) {
char *str = LLVMPrintTypeToString(type);
const char *out = LLVMPY_CreateString(str);
LLVMDisposeMessage(str);
return out;
}

API_EXPORT(const char *)
LLVMPY_GetTypeName(LLVMTypeRef type) {
// try to convert to a struct type, works for other derived
// types too
llvm::Type *unwrapped = llvm::unwrap(type);
llvm::StructType *ty = llvm::dyn_cast<llvm::StructType>(unwrapped);
if (ty && !ty->isLiteral()) {
return LLVMPY_CreateString(ty->getStructName().str().c_str());
}
return LLVMPY_CreateString("");
}

API_EXPORT(bool)
LLVMPY_TypeIsPointer(LLVMTypeRef type) {
return llvm::unwrap(type)->isPointerTy();
}

API_EXPORT(LLVMTypeRef)
LLVMPY_GetElementType(LLVMTypeRef type) {
llvm::Type *unwrapped = llvm::unwrap(type);
llvm::PointerType *ty = llvm::dyn_cast<llvm::PointerType>(unwrapped);
if (ty != nullptr) {
return llvm::wrap(ty->getPointerElementType());
}
return nullptr;
}

API_EXPORT(void)
LLVMPY_SetLinkage(LLVMValueRef Val, int Linkage) {
LLVMSetLinkage(Val, (LLVMLinkage)Linkage);
Expand Down
1 change: 1 addition & 0 deletions llvmlite/binding/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from .targets import *
from .transforms import *
from .value import *
from .typeref import *
from .analysis import *
from .object_file import *
from .context import *
Expand Down
1 change: 1 addition & 0 deletions llvmlite/binding/ffi.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def _make_opaque_ref(name):
LLVMTargetMachineRef = _make_opaque_ref("LLVMTargetMachine")
LLVMMemoryBufferRef = _make_opaque_ref("LLVMMemoryBuffer")
LLVMAttributeListIterator = _make_opaque_ref("LLVMAttributeListIterator")
LLVMElementIterator = _make_opaque_ref("LLVMElementIterator")
LLVMAttributeSetIterator = _make_opaque_ref("LLVMAttributeSetIterator")
LLVMGlobalsIterator = _make_opaque_ref("LLVMGlobalsIterator")
LLVMFunctionsIterator = _make_opaque_ref("LLVMFunctionsIterator")
Expand Down
Loading

0 comments on commit 4292eea

Please sign in to comment.