diff --git a/backports.cpp b/backports.cpp index c3d80a1..f08ff18 100644 --- a/backports.cpp +++ b/backports.cpp @@ -48,3 +48,16 @@ LLVMMemoryBufferRef LLVMGoWriteThinLTOBitcodeToMemoryBuffer(LLVMModuleRef M) { #endif return llvm::wrap(llvm::MemoryBuffer::getMemBufferCopy(OS.str()).release()); } + +#if LLVM_VERSION_MAJOR < 15 + +// This is backported because version 14 supports opaque +// pointers but I presume if you try to access the element +// type it will crash. So this backport prevents that by +// allowing to check if the pointer is opaque before trying +// to access the element type. +LLVMBool LLVMPointerTypeIsOpaque(LLVMTypeRef Ty) { + return llvm::unwrap(Ty)->isOpaquePointerTy(); +} + +#endif \ No newline at end of file diff --git a/backports.h b/backports.h index d5b9a9c..aff8fe9 100644 --- a/backports.h +++ b/backports.h @@ -14,6 +14,19 @@ LLVMMemoryBufferRef LLVMGoWriteThinLTOBitcodeToMemoryBuffer(LLVMModuleRef M); LLVMMetadataRef LLVMGoDIBuilderCreateExpression(LLVMDIBuilderRef Builder, uint64_t *Addr, size_t Length); +#if LLVM_VERSION_MAJOR < 15 +/** + * Determine whether a pointer is opaque. + * + * True if this is an instance of an opaque PointerType. + * + * @see llvm::Type::isOpaquePointerTy() + */ +LLVMBool LLVMPointerTypeIsOpaque(LLVMTypeRef Ty); + +#endif + + #ifdef __cplusplus } #endif /* defined(__cplusplus) */ diff --git a/ir.go b/ir.go index 28595b1..73b96a2 100644 --- a/ir.go +++ b/ir.go @@ -16,11 +16,14 @@ package llvm #include "llvm-c/Core.h" #include "llvm-c/Comdat.h" #include "IRBindings.h" +#include "backports.h" #include */ import "C" -import "unsafe" -import "errors" +import ( + "errors" + "unsafe" +) type ( // We use these weird structs here because *Ref types are pointers and @@ -665,6 +668,7 @@ func (t Type) StructSetBody(elementTypes []Type, packed bool) { } func (t Type) IsStructPacked() bool { return C.LLVMIsPackedStruct(t.C) != 0 } +func (t Type) IsStructOpaque() bool { return C.LLVMIsOpaqueStruct(t.C) != 0 } func (t Type) StructElementTypesCount() int { return int(C.LLVMCountStructElementTypes(t.C)) } func (t Type) StructElementTypes() []Type { out := make([]Type, t.StructElementTypesCount()) @@ -676,7 +680,12 @@ func (t Type) StructElementTypes() []Type { // Operations on array, pointer, and vector types (sequence types) func (t Type) Subtypes() (ret []Type) { - ret = make([]Type, C.LLVMGetNumContainedTypes(t.C)) + num := C.LLVMGetNumContainedTypes(t.C) + if num == 0 { + // prevent a crash at &ret[0] if there are no subtypes + return nil + } + ret = make([]Type, num) C.LLVMGetSubtypes(t.C, llvmTypeRefPtr(&ret[0])) return } @@ -694,7 +703,19 @@ func VectorType(elementType Type, elementCount int) (t Type) { return } -func (t Type) ElementType() (rt Type) { rt.C = C.LLVMGetElementType(t.C); return } +// IsPointerOpaque checks if the pointer is an opaque pointer. +// +// see llvm::Type::isOpaquePointerTy() +func (t Type) IsPointerOpaque() bool { return C.LLVMPointerTypeIsOpaque(t.C) != 0 } + +// ElementType returns the type of the element for arrays, pointers and vectors. +// +// see llvm::SequentialType::getElementType() +func (t Type) ElementType() (rt Type) { + rt.C = C.LLVMGetElementType(t.C) + return +} + func (t Type) ArrayLength() int { return int(C.LLVMGetArrayLength(t.C)) } func (t Type) PointerAddressSpace() int { return int(C.LLVMGetPointerAddressSpace(t.C)) } func (t Type) VectorSize() int { return int(C.LLVMGetVectorSize(t.C)) }