#
# Copyright (c) 2008-10, Mahadevan R All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#  * Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
#
#  * Redistributions in binary form must reproduce the above copyright notice,
#    this list of conditions and the following disclaimer in the documentation
#    and/or other materials provided with the distribution.
#
#  * Neither the name of this software, nor the names of its
#    contributors may be used to endorse or promote products derived from
#    this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#

"""Core classes of LLVM.

The llvm.core module contains classes and constants required to build the
in-memory intermediate representation (IR) data structures."""


import llvm                 # top-level, for common stuff
import llvm._core as _core  # C wrappers
import llvm._util as _util  # utility functions


#===----------------------------------------------------------------------===
# Enumerations
#===----------------------------------------------------------------------===

# type kinds (LLVMTypeKind enum)
TYPE_VOID       = 0
TYPE_HALF       = 1
TYPE_FLOAT      = 2
TYPE_DOUBLE     = 3
TYPE_X86_FP80   = 4
TYPE_FP128      = 5
TYPE_PPC_FP128  = 6
TYPE_LABEL      = 7
TYPE_INTEGER    = 8
TYPE_FUNCTION   = 9
TYPE_STRUCT     = 10
TYPE_ARRAY      = 11
TYPE_POINTER    = 12
TYPE_VECTOR     = 13
TYPE_METADATA   = 14
TYPE_X86_MMX    = 15


# value IDs (llvm::Value::ValueTy enum)
VALUE_ARGUMENT                          = 0
VALUE_BASIC_BLOCK                       = 1
VALUE_FUNCTION                          = 2
VALUE_GLOBAL_ALIAS                      = 3
VALUE_GLOBAL_VARIABLE                   = 4
VALUE_UNDEF_VALUE                       = 5
VALUE_BLOCK_ADDRESS                     = 6
VALUE_CONSTANT_EXPR                     = 7
VALUE_CONSTANT_AGGREGATE_ZERO           = 8
VALUE_CONSTANT_DATA_ARRAY               = 9
VALUE_CONSTANT_DATA_VECTOR              = 10
VALUE_CONSTANT_INT                      = 11
VALUE_CONSTANT_FP                       = 12
VALUE_CONSTANT_ARRAY                    = 13
VALUE_CONSTANT_STRUCT                   = 14
VALUE_CONSTANT_VECTOR                   = 15
VALUE_CONSTANT_POINTER_NULL             = 16
VALUE_MD_NODE                           = 17
VALUE_MD_STRING                         = 18
VALUE_INLINE_ASM                        = 19
VALUE_PSEUDO_SOURCE_VALUE               = 20
VALUE_FIXED_STACK_PSEUDO_SOURCE_VALUE   = 21
VALUE_INSTRUCTION                       = 22

# instruction opcodes (from include/llvm/Instruction.def)
OPCODE_RET            = 1
OPCODE_BR             = 2
OPCODE_SWITCH         = 3
OPCODE_INDIRECT_BR    = 4
OPCODE_INVOKE         = 5
OPCODE_RESUME         = 6
OPCODE_UNREACHABLE    = 7
OPCODE_ADD            = 8
OPCODE_FADD           = 9
OPCODE_SUB            = 10
OPCODE_FSUB           = 11
OPCODE_MUL            = 12
OPCODE_FMUL           = 13
OPCODE_UDIV           = 14
OPCODE_SDIV           = 15
OPCODE_FDIV           = 16
OPCODE_UREM           = 17
OPCODE_SREM           = 18
OPCODE_FREM           = 19
OPCODE_SHL            = 20
OPCODE_LSHR           = 21
OPCODE_ASHR           = 22
OPCODE_AND            = 23
OPCODE_OR             = 24
OPCODE_XOR            = 25
OPCODE_ALLOCA         = 26
OPCODE_LOAD           = 27
OPCODE_STORE          = 28
OPCODE_GETELEMENTPTR  = 29
OPCODE_FENCE          = 30
OPCODE_ATOMICCMPXCHG  = 31
OPCODE_ATOMICRMW      = 32
OPCODE_TRUNC          = 33
OPCODE_ZEXT           = 34
OPCODE_SEXT           = 35
OPCODE_FPTOUI         = 36
OPCODE_FPTOSI         = 37
OPCODE_UITOFP         = 38
OPCODE_SITOFP         = 39
OPCODE_FPTRUNC        = 40
OPCODE_FPEXT          = 41
OPCODE_PTRTOINT       = 42
OPCODE_INTTOPTR       = 43
OPCODE_BITCAST        = 44
OPCODE_ICMP           = 45
OPCODE_FCMP           = 46
OPCODE_PHI            = 47
OPCODE_CALL           = 48
OPCODE_SELECT         = 49
OPCODE_USEROP1        = 50
OPCODE_USEROP2        = 51
OPCODE_VAARG          = 52
OPCODE_EXTRACTELEMENT = 53
OPCODE_INSERTELEMENT  = 54
OPCODE_SHUFFLEVECTOR  = 55
OPCODE_EXTRACTVALUE   = 56
OPCODE_INSERTVALUE    = 57
OPCODE_LANDINGPAD     = 58

# calling conventions
CC_C             = 0
CC_FASTCALL      = 8
CC_COLDCALL      = 9
CC_GHC           = 10
CC_X86_STDCALL   = 64
CC_X86_FASTCALL  = 65
CC_ARM_APCS      = 66
CC_ARM_AAPCS     = 67
CC_ARM_AAPCS_VFP = 68
CC_MSP430_INTR   = 69
CC_X86_THISCALL  = 70
CC_PTX_KERNEL    = 71
CC_PTX_DEVICE    = 72
CC_MBLAZE_INTR   = 73
CC_MBLAZE_SVOL   = 74


# int predicates
ICMP_EQ         = 32
ICMP_NE         = 33
ICMP_UGT        = 34
ICMP_UGE        = 35
ICMP_ULT        = 36
ICMP_ULE        = 37
ICMP_SGT        = 38
ICMP_SGE        = 39
ICMP_SLT        = 40
ICMP_SLE        = 41

# same as ICMP_xx, for backward compatibility
IPRED_EQ        = ICMP_EQ
IPRED_NE        = ICMP_NE
IPRED_UGT       = ICMP_UGT
IPRED_UGE       = ICMP_UGE
IPRED_ULT       = ICMP_ULT
IPRED_ULE       = ICMP_ULE
IPRED_SGT       = ICMP_SGT
IPRED_SGE       = ICMP_SGE
IPRED_SLT       = ICMP_SLT
IPRED_SLE       = ICMP_SLE

# real predicates
FCMP_FALSE      = 0
FCMP_OEQ        = 1
FCMP_OGT        = 2
FCMP_OGE        = 3
FCMP_OLT        = 4
FCMP_OLE        = 5
FCMP_ONE        = 6
FCMP_ORD        = 7
FCMP_UNO        = 8
FCMP_UEQ        = 9
FCMP_UGT        = 10
FCMP_UGE        = 11
FCMP_ULT        = 12
FCMP_ULE        = 13
FCMP_UNE        = 14
FCMP_TRUE       = 15

# real predicates
RPRED_FALSE     = FCMP_FALSE
RPRED_OEQ       = FCMP_OEQ
RPRED_OGT       = FCMP_OGT
RPRED_OGE       = FCMP_OGE
RPRED_OLT       = FCMP_OLT
RPRED_OLE       = FCMP_OLE
RPRED_ONE       = FCMP_ONE
RPRED_ORD       = FCMP_ORD
RPRED_UNO       = FCMP_UNO
RPRED_UEQ       = FCMP_UEQ
RPRED_UGT       = FCMP_UGT
RPRED_UGE       = FCMP_UGE
RPRED_ULT       = FCMP_ULT
RPRED_ULE       = FCMP_ULE
RPRED_UNE       = FCMP_UNE
RPRED_TRUE      = FCMP_TRUE

# linkages (see llvm-c/Core.h)
LINKAGE_EXTERNAL                        = 0
LINKAGE_AVAILABLE_EXTERNALLY            = 1
LINKAGE_LINKONCE_ANY                    = 2
LINKAGE_LINKONCE_ODR                    = 3
LINKAGE_WEAK_ANY                        = 4
LINKAGE_WEAK_ODR                        = 5
LINKAGE_APPENDING                       = 6
LINKAGE_INTERNAL                        = 7
LINKAGE_PRIVATE                         = 8
LINKAGE_DLLIMPORT                       = 9
LINKAGE_DLLEXPORT                       = 10
LINKAGE_EXTERNAL_WEAK                   = 11
LINKAGE_GHOST                           = 12
LINKAGE_COMMON                          = 13
LINKAGE_LINKER_PRIVATE                  = 14
LINKAGE_LINKER_PRIVATE_WEAK             = 15
LINKAGE_LINKER_PRIVATE_WEAK_DEF_AUTO    = 16

# visibility (see llvm/GlobalValue.h)
VISIBILITY_DEFAULT   = 0
VISIBILITY_HIDDEN    = 1
VISIBILITY_PROTECTED = 2

# parameter attributes (see llvm/Attributes.h)
ATTR_NONE               = 0
ATTR_ZEXT               = 1
ATTR_SEXT               = 2
ATTR_NO_RETURN          = 4
ATTR_IN_REG             = 8
ATTR_STRUCT_RET         = 16
ATTR_NO_UNWIND          = 32
ATTR_NO_ALIAS           = 64
ATTR_BY_VAL             = 128
ATTR_NEST               = 256
ATTR_READ_NONE          = 512
ATTR_READONLY           = 1024
ATTR_NO_INLINE          = 1<<11
ATTR_ALWAYS_INLINE      = 1<<12
ATTR_OPTIMIZE_FOR_SIZE  = 1<<13
ATTR_STACK_PROTECT      = 1<<14
ATTR_STACK_PROTECT_REQ  = 1<<15
ATTR_ALIGNMENT          = 1<<16
ATTR_NO_CAPTURE         = 1<<21
ATTR_NO_REDZONE         = 1<<22
ATTR_NO_IMPLICIT_FLOAT  = 1<<23
ATTR_NAKED              = 1<<24
ATTR_INLINE_HINT        = 1<<25
ATTR_STACK_ALIGNMENT    = 7<<26
ATTR_HOTPATCH           = 1<<29

# intrinsic IDs
from llvm._intrinsic_ids import *


#===----------------------------------------------------------------------===
# Helpers (for internal use)
#===----------------------------------------------------------------------===

def check_is_type(obj):         _util.check_gen(obj, Type)
def check_is_type_struct(obj):  _util.check_gen(obj, StructType)
def check_is_value(obj):        _util.check_gen(obj, Value)
def check_is_constant(obj):     _util.check_gen(obj, Constant)
def check_is_function(obj):     _util.check_gen(obj, Function)
def check_is_basic_block(obj):  _util.check_gen(obj, BasicBlock)
def check_is_module(obj):       _util.check_gen(obj, Module)

def unpack_types(objlst):     return _util.unpack_gen(objlst, check_is_type)
def unpack_values(objlst):    return _util.unpack_gen(objlst, check_is_value)
def unpack_constants(objlst): return _util.unpack_gen(objlst, check_is_constant)

def unpack_values_or_none(objlst):
    return _util.unpack_gen_allow_none(objlst, check_is_value)

def check_is_callable(obj):
    if isinstance(obj, Function):
        return
    typ = obj.type
    if isinstance(typ, PointerType) and \
        isinstance(typ.pointee, FunctionType):
        return
    raise TypeError("argument is neither a function nor a function pointer")

def _to_int(v):
    if v:
        return 1
    else:
        return 0


#===----------------------------------------------------------------------===
# Module
#===----------------------------------------------------------------------===

class Module(llvm.Ownable, llvm.Cacheable):
    """A Module instance stores all the information related to an LLVM module.

    Modules are the top level container of all other LLVM Intermediate
    Representation (IR) objects. Each module directly contains a list of
    globals variables, a list of functions, a list of libraries (or
    other modules) this module depends on, a symbol table, and various
    data about the target's characteristics.

    Construct a Module only using the static methods defined below, *NOT*
    using the constructor. A correct usage is:

    module_obj = Module.new('my_module')
    """

    @staticmethod
    def new(id):
        """Create a new Module instance.

        Creates an instance of Module, having the id `id'.
        """
        return Module(_core.LLVMModuleCreateWithName(id))

    @staticmethod
    def from_bitcode(fileobj_or_str):
        """Create a Module instance from the contents of a bitcode
        file.

        fileobj_or_str -- takes a file-like object or string that contains
                          a module represented in bitcode.
        """

        if isinstance(fileobj_or_str, _util.unicode_type):
            data = fileobj_or_str.encode('utf-8')
        elif isinstance(fileobj_or_str, bytes):
            data = fileobj_or_str
        else:
            data = fileobj_or_str.read()
        ret = _core.LLVMGetModuleFromBitcode(data)
        if not ret:
            raise llvm.LLVMException("Unable to create module from bitcode")
        elif _util.isstring(ret):
            raise llvm.LLVMException(ret)
        else:
            return Module(ret)

    @staticmethod
    def from_assembly(fileobj_or_str):
        """Create a Module instance from the contents of an LLVM
        assembly (.ll) file.


        fileobj_or_str -- takes a file-like object or string that contains
                          a module represented in llvm-ir assembly.
        """

        if isinstance(fileobj_or_str, _util.unicode_type):
            data = fileobj_or_str.encode('utf-8')
        elif isinstance(fileobj_or_str, bytes):
            data = fileobj_or_str
        else:
            data = fileobj_or_str.read()
            if isinstance(data, _util.unicode_type):
                data = data.encode()
        ret = _core.LLVMGetModuleFromAssembly(data)
        if not ret:
            raise llvm.LLVMException("Unable to create module from assembly")
        elif isinstance(ret, str):
            raise llvm.LLVMException(ret)
        else:
            return Module(ret)

    def __init__(self, ptr):
        """DO NOT CALL DIRECTLY.

        Use the static method `Module.new' instead.
        """
        llvm.Ownable.__init__(self, ptr, _core.LLVMDisposeModule)

    def __str__(self):
        """Text representation of a module.

        Returns the textual representation (`llvm assembly') of the
        module. Use it like this:

        ll = str(module_obj)
        print module_obj     # same as `print ll'
        """
        return _core.LLVMDumpModuleToString(self.ptr)

    def __eq__(self, rhs):
        if isinstance(rhs, Module):
            return str(self) == str(rhs)
        else:
            return False

    def __ne__(self, rhs):
        return not self == rhs

    def _get_target(self):
        return _core.LLVMGetTarget(self.ptr)

    def _set_target(self, value):
        return _core.LLVMSetTarget(self.ptr, value)

    target = property(_get_target, _set_target,
        """The target triple string describing the target host."""
    )

    def _get_data_layout(self):
        return _core.LLVMGetDataLayout(self.ptr)

    def _set_data_layout(self, value):
        _core.LLVMSetDataLayout(self.ptr, value)

    data_layout = property(_get_data_layout, _set_data_layout,
        """The data layout string for the module's target platform.

        The data layout strings is an encoded representation of
        the type sizes and alignments expected by this module.
        """
    )

    @property
    def pointer_size(self):
        """Pointer size of target platform.

        Can be 0, 32 or 64. Zero represents
        llvm::Module::AnyPointerSize."""
        return _core.LLVMModuleGetPointerSize(self.ptr)

    def link_in(self, other):
        """Link the `other' module into this one.

        The `other' module is linked into this one such that types,
        global variables, function, etc. are matched and resolved.

        The `other' module is no longer valid after this method is
        invoked, all refs to it should be dropped.

        In the future, this API might be replaced with a full-fledged
        Linker class.
        """
        check_is_module(other)
        other.forget() # remove it from object cache
        ret = _core.LLVMLinkModules(self.ptr, other.ptr)
        if isinstance(ret, str):
            raise llvm.LLVMException(ret)
        # Do not try to destroy the other module's llvm::Module*.
        other._own(llvm.DummyOwner())

    def get_type_named(self, name):
        """Return a Type object with the given name."""
        ptr  = _core.LLVMGetTypeByName(self.ptr, name)
        if ptr:
            kind = _core.LLVMGetTypeKind(ptr)
            return _make_type(ptr, kind)
        return None

    def add_global_variable(self, ty, name, addrspace=0):
        """Add a global variable of given type with given name."""
        return GlobalVariable.new(self, ty, name, addrspace)

    def get_global_variable_named(self, name):
        """Return a GlobalVariable object for the given name."""
        return GlobalVariable.get(self, name)

    @property
    def global_variables(self):
        """All global variables in this module."""
        return _util.wrapiter(_core.LLVMGetFirstGlobal,
            _core.LLVMGetNextGlobal, self.ptr, _make_value)

    def add_function(self, ty, name):
        """Add a function of given type with given name."""
        return Function.new(self, ty, name)

    def get_function_named(self, name):
        """Return a Function object representing function with given name."""
        return Function.get(self, name)

    def get_or_insert_function(self, ty, name):
        """Like get_function_named(), but does add_function() first, if
        function is not present."""
        return Function.get_or_insert(self, ty, name)

    @property
    def functions(self):
        """All functions in this module."""
        return _util.wrapiter(_core.LLVMGetFirstFunction,
            _core.LLVMGetNextFunction, self.ptr, _make_value)

    def verify(self):
        """Verify module.

        Checks module for errors. Raises `llvm.LLVMException' on any
        error."""
        ret = _core.LLVMVerifyModule(self.ptr)
        if ret != "":
            raise llvm.LLVMException(ret)

    def to_bitcode(self, fileobj=None):
        """Write bitcode representation of module to given file-like
        object.

        fileobj -- A file-like object to where the bitcode is written.
                   If it is None, the bitcode is returned.

        Return value -- Returns None if fileobj is not None.
                        Otherwise, return the bitcode as a bytestring.
        """

        data = _core.LLVMGetBitcodeFromModule(self.ptr)
        if not data:
            raise llvm.LLVMException("Unable to create bitcode")
        if fileobj is not None:
            fileobj.write(data)
        else:
            return data

    def add_library(self, name):
        return _core.LLVMModuleAddLibrary(self.ptr, name)

    def _get_id(self):
        return _core.LLVMGetModuleIdentifier(self.ptr)

    def _set_id(self, string):
        _core.LLVMSetModuleIdentifier(self.ptr, string)

    id = property(_get_id, _set_id)

    def to_native_object(self, fileobj=None):
        '''Outputs the byte string of the module as native object code

        If a fileobj is given, the output is written to it;
        Otherwise, the output is returned
        '''
        data = _core.LLVMGetNativeCodeFromModule(self.ptr, 0)
        if fileobj is not None:
            fileobj.write(data)
        else:
            return data

    def to_native_assembly(self, fileobj=None):
        '''Outputs the byte string of the module as native assembly code

        If a fileobj is given, the output is written to it;
        Otherwise, the output is returned
        '''
        data = _core.LLVMGetNativeCodeFromModule(self.ptr, 1)
        if fileobj is not None:
            fileobj.write(data)
        else:
            return data

    def get_or_insert_named_metadata(self, name):
        ptr = _core.LLVMModuleGetOrInsertNamedMetaData(self.ptr, name)
        return NamedMetaData(ptr)

    def get_named_metadata(self, name):
        ptr = _core.LLVMModuleGetNamedMetaData(self.ptr, name)
        return NamedMetaData(ptr)

    def clone(self):
        return Module(_core.LLVMCloneModule(self.ptr))

#===----------------------------------------------------------------------===
# Types
#===----------------------------------------------------------------------===

class Type(object):
    """Represents a type, like a 32-bit integer or an 80-bit x86 float.

    Use one of the static methods to create an instance. Example:
      ty = Type.double()
    """

    @staticmethod
    def int(bits=32):
        """Create an integer type having the given bit width."""
        if bits == 1:
            return _make_type(_core.LLVMInt1Type(), TYPE_INTEGER)
        elif bits == 8:
            return _make_type(_core.LLVMInt8Type(), TYPE_INTEGER)
        elif bits == 16:
            return _make_type(_core.LLVMInt16Type(), TYPE_INTEGER)
        elif bits == 32:
            return _make_type(_core.LLVMInt32Type(), TYPE_INTEGER)
        elif bits == 64:
            return _make_type(_core.LLVMInt64Type(), TYPE_INTEGER)
        else:
            bits = int(bits) # bits must be an int
            return _make_type(_core.LLVMIntType(bits), TYPE_INTEGER)

    @staticmethod
    def float():
        """Create a 32-bit floating point type."""
        return _make_type(_core.LLVMFloatType(), TYPE_FLOAT)

    @staticmethod
    def double():
        """Create a 64-bit floating point type."""
        return _make_type(_core.LLVMDoubleType(), TYPE_DOUBLE)

    @staticmethod
    def x86_fp80():
        """Create a 80-bit x86 floating point type."""
        return _make_type(_core.LLVMX86FP80Type(), TYPE_X86_FP80)

    @staticmethod
    def fp128():
        """Create a 128-bit floating point type (with 112-bit
        mantissa)."""
        return _make_type(_core.LLVMFP128Type(), TYPE_FP128)

    @staticmethod
    def ppc_fp128():
        """Create a 128-bit floating point type (two 64-bits)."""
        return _make_type(_core.LLVMPPCFP128Type(), TYPE_PPC_FP128)

    @staticmethod
    def function(return_ty, param_tys, var_arg=False):
        """Create a function type.

        Creates a function type that returns a value of type
        `return_ty', takes arguments of types as given in the iterable
        `param_tys'. Set `var_arg' to True (default is False) for a
        variadic function."""
        check_is_type(return_ty)
        var_arg = _to_int(var_arg) # ensure int
        params = unpack_types(param_tys)
        return _make_type(_core.LLVMFunctionType(return_ty.ptr, params,
                    var_arg), TYPE_FUNCTION)

    @staticmethod
    def opaque(name):
        """Create a opaque StructType"""
        if not name:
            raise llvm.LLVMException("Must specify a name")

        objptr = _core.LLVMStructTypeIdentified(name)
        return _make_type(objptr, TYPE_STRUCT)

    @staticmethod
    def struct(element_tys, name=''): # not packed
        """Create a (unpacked) structure type.

        Creates a structure type with elements of types as given in the
        iterable `element_tys'. This method creates a unpacked
        structure. For a packed one, use the packed_struct() method.

        If name is not '', creates a identified type;
        otherwise, creates a literal type."""
        return Type.__struct(element_tys, packed=False, name=name)

    @staticmethod
    def packed_struct(element_tys, name=''):
        """Create a (packed) structure type.

        Creates a structure type with elements of types as given in the
        iterable `element_tys'. This method creates a packed
        structure. For an unpacked one, use the struct() method.

        If name is not '', creates a identified type;
        otherwise, creates a literal type."""
        return Type.__struct(element_tys, packed=True, name=name)

    @staticmethod
    def __struct(element_tys, packed, name):
        elems = unpack_types(element_tys)
        packed = int(bool(packed))

        if name: # create Identified StructType
            objptr = _core.LLVMStructTypeIdentified(name)
            _core.LLVMSetStructBody(objptr, elems, packed)
        else:        # create Literal StructType
            objptr = _core.LLVMStructType(elems, packed)

        return _make_type(objptr, TYPE_STRUCT)


    @staticmethod
    def array(element_ty, count):
        """Create an array type.

        Creates a type for an array of elements of type `element_ty',
        having 'count' elements."""
        check_is_type(element_ty)
        count = int(count) # must be an int
        return _make_type(_core.LLVMArrayType(element_ty.ptr, count),
                    TYPE_ARRAY)

    @staticmethod
    def pointer(pointee_ty, addr_space=0):
        """Create a pointer type.

        Creates a pointer type, which can point to values of type
        `pointee_ty', in the address space `addr_space'."""
        check_is_type(pointee_ty)
        addr_space = int(addr_space) # must be an int
        return _make_type(_core.LLVMPointerType(pointee_ty.ptr,
                    addr_space), TYPE_POINTER)

    @staticmethod
    def vector(element_ty, count):
        """Create a vector type.

        Creates a type for a vector of elements of type `element_ty',
        having `count' elements."""
        check_is_type(element_ty)
        count = int(count) # must be an int
        return _make_type(_core.LLVMVectorType(element_ty.ptr, count),
                    TYPE_VECTOR)

    @staticmethod
    def void():
        """Create a void type.

        Represents the `void' type."""
        return _make_type(_core.LLVMVoidType(), TYPE_VOID)

    @staticmethod
    def label():
        """Create a label type."""
        return _make_type(_core.LLVMLabelType(), TYPE_LABEL)

    def __init__(self, ptr, kind):
        """DO NOT CALL DIRECTLY.

        Use one of the static methods instead."""
        self.ptr = ptr
        self.kind = kind
        """An enum (int) value denoting which type this is.

        Use the symbolic constants TYPE_* defined in llvm.core
        module."""

    def __str__(self):
        """Text representation of a type.

        Returns the textual representation (`llvm assembly') of the type."""
        return _core.LLVMDumpTypeToString(self.ptr)

    def __eq__(self, rhs):
        if isinstance(rhs, Type):
            return str(self) == str(rhs)
        else:
            return False

    def __ne__(self, rhs):
        return not self == rhs


class IntegerType(Type):
    """Represents an integer type."""

    @property
    def width(self):
        """The width of the integer type, in bits."""
        return _core.LLVMGetIntTypeWidth(self.ptr)


class FunctionType(Type):
    """Represents a function type."""

    @property
    def return_type(self):
        """The type of the value returned by this function."""
        ptr  = _core.LLVMGetReturnType(self.ptr)
        kind = _core.LLVMGetTypeKind(ptr)
        return _make_type(ptr, kind)

    @property
    def vararg(self):
        """True if this function is variadic."""
        return _core.LLVMIsFunctionVarArg(self.ptr) != 0

    @property
    def args(self):
        """An iterable that yields Type objects, representing the types of the
        arguments accepted by this function, in order."""
        pp = _core.LLVMGetFunctionTypeParams(self.ptr)
        return [ _make_type(p, _core.LLVMGetTypeKind(p)) for p in pp ]

    @property
    def arg_count(self):
        """Number of arguments accepted by this function.

        Same as len(obj.args), but faster."""
        return _core.LLVMCountParamTypes(self.ptr)


class StructType(Type):
    """Represents a structure type."""

    @property
    def element_count(self):
        """Number of elements (members) in the structure.

        Same as len(obj.elements), but faster."""
        return _core.LLVMCountStructElementTypes(self.ptr)

    @property
    def elements(self):
        """An iterable that yieldsd Type objects, representing the types of the
        elements (members) of the structure, in order."""
        pp = _core.LLVMGetStructElementTypes(self.ptr)
        return [ _make_type(p, _core.LLVMGetTypeKind(p)) for p in pp ]

    def set_body(self, elems, packed=False):
        """Filled the body of a opaque type.
        """
        # check
        if not self.is_opaque:
            raise llvm.LLVMException("Body is already defined.")

        # prepare arguments
        elems = unpack_types(elems)
        if packed:
            packed = 1
        else:
            packed = 0

        # call c API
        _core.LLVMSetStructBody(self.ptr, elems, packed)

    @property
    def packed(self):
        """True if the structure is packed, False otherwise."""
        return _core.LLVMIsPackedStruct(self.ptr) != 0

    def _set_name(self, name):
        _core.LLVMSetStructName(self.ptr, name)

    def _get_name(self):
        return _core.LLVMGetStructName(self.ptr)

    name = property(_get_name, _set_name)

    @property
    def is_literal(self):
        return bool(_core.LLVMIsLiteralStruct(self.ptr))

    @property
    def is_identified(self):
        return not _core.LLVMIsLiteralStruct(self.ptr)

    @property
    def is_opaque(self):
        return bool(_core.LLVMIsOpaqueStruct(self.ptr))

class ArrayType(Type):
    """Represents an array type."""

    @property
    def element(self):
        ptr  = _core.LLVMGetElementType(self.ptr)
        kind = _core.LLVMGetTypeKind(ptr)
        return _make_type(ptr, kind)

    @property
    def count(self):
        return _core.LLVMGetArrayLength(self.ptr)


class PointerType(Type):

    @property
    def pointee(self):
        ptr = _core.LLVMGetElementType(self.ptr)
        kind = _core.LLVMGetTypeKind(ptr)
        return _make_type(ptr, kind)

    @property
    def address_space(self):
        return _core.LLVMGetPointerAddressSpace(self.ptr)


class VectorType(Type):

    @property
    def element(self):
        ptr  = _core.LLVMGetElementType(self.ptr)
        kind = _core.LLVMGetTypeKind(ptr)
        return _make_type(ptr, kind)

    @property
    def count(self):
        return _core.LLVMGetVectorSize(self.ptr)


#===----------------------------------------------------------------------===
# Type factory method
#===----------------------------------------------------------------------===

# type ID -> class map
__class_for_typeid = {
    TYPE_INTEGER     : IntegerType,
    TYPE_FUNCTION    : FunctionType,
    TYPE_STRUCT      : StructType,
    TYPE_ARRAY       : ArrayType,
    TYPE_POINTER     : PointerType,
    TYPE_VECTOR      : VectorType,
}

def _make_type(ptr, kind):
    class_obj = __class_for_typeid.get(kind)
    if class_obj:
        return class_obj(ptr, kind)
    else:
        # "generic" type
        return Type(ptr, kind)


#===----------------------------------------------------------------------===
# Values
#===----------------------------------------------------------------------===

class Value(llvm.Cacheable):

    def __init__(self, ptr):
        self.ptr = ptr

    def __str__(self):
        return _core.LLVMDumpValueToString(self.ptr)

    def __eq__(self, rhs):
        if isinstance(rhs, Value):
            return str(self) == str(rhs)
        else:
            return False

    def __ne__(self, rhs):
        return not self == rhs

    def _get_name(self):
        return _core.LLVMGetValueName(self.ptr)

    def _set_name(self, value):
        return _core.LLVMSetValueName(self.ptr, value)

    name = property(_get_name, _set_name)

    @property
    def value_id(self):
        return _core.LLVMValueGetID(self.ptr)

    @property
    def type(self):
        ptr  = _core.LLVMTypeOf(self.ptr)
        kind = _core.LLVMGetTypeKind(ptr)
        return _make_type(ptr, kind)

    @property
    def use_count(self):
        return _core.LLVMValueGetNumUses(self.ptr)

    @property
    def uses(self):
        return [ _make_value(v) for v in _core.LLVMValueGetUses(self.ptr) ]


class User(Value):

    @property
    def operand_count(self):
        return _core.LLVMUserGetNumOperands(self.ptr)

    @property
    def operands(self):
        """Yields operands of this instruction."""
        return [self._get_operand(i) for i in range(self.operand_count)]

    def _get_operand(self, i):
        return _make_value(_core.LLVMUserGetOperand(self.ptr, i))


class Constant(User):

    @staticmethod
    def null(ty):
        check_is_type(ty)
        return _make_value(_core.LLVMConstNull(ty.ptr))

    @staticmethod
    def all_ones(ty):
        check_is_type(ty)
        return _make_value(_core.LLVMConstAllOnes(ty.ptr))

    @staticmethod
    def undef(ty):
        check_is_type(ty)
        return _make_value(_core.LLVMGetUndef(ty.ptr))

    @staticmethod
    def int(ty, value):
        check_is_type(ty)
        return _make_value(_core.LLVMConstInt(ty.ptr, value, 0))

    @staticmethod
    def int_signextend(ty, value):
        check_is_type(ty)
        return _make_value(_core.LLVMConstInt(ty.ptr, value, 1))

    @staticmethod
    def real(ty, value):
        check_is_type(ty)
        if isinstance(value, str):
            return _make_value(_core.LLVMConstRealOfString(ty.ptr, value))
        else:
            return _make_value(_core.LLVMConstReal(ty.ptr, value))

    @staticmethod
    def string(strval): # dont_null_terminate=True
        return _make_value(_core.LLVMConstString(strval, 1))

    @staticmethod
    def stringz(strval): # dont_null_terminate=False
        return _make_value(_core.LLVMConstString(strval, 0))

    @staticmethod
    def array(ty, consts):
        check_is_type(ty)
        const_ptrs = unpack_constants(consts)
        return _make_value(_core.LLVMConstArray(ty.ptr, const_ptrs))

    @staticmethod
    def struct(consts): # not packed
        const_ptrs = unpack_constants(consts)
        return _make_value(_core.LLVMConstStruct(const_ptrs, 0))

    @staticmethod
    def packed_struct(consts):
        const_ptrs = unpack_constants(consts)
        return _make_value(_core.LLVMConstStruct(const_ptrs, 1))

    @staticmethod
    def vector(consts):
        const_ptrs = unpack_constants(consts)
        return _make_value(_core.LLVMConstVector(const_ptrs))

    @staticmethod
    def sizeof(ty):
        check_is_type(ty)
        return _make_value(_core.LLVMSizeOf(ty.ptr))

    def neg(self):
        return _make_value(_core.LLVMConstNeg(self.ptr))

    def not_(self):
        return _make_value(_core.LLVMConstNot(self.ptr))

    def add(self, rhs):
        check_is_constant(rhs)
        return _make_value(_core.LLVMConstAdd(self.ptr, rhs.ptr))

    def fadd(self, rhs):
        check_is_constant(rhs)
        return _make_value(_core.LLVMConstFAdd(self.ptr, rhs.ptr))

    def sub(self, rhs):
        check_is_constant(rhs)
        return _make_value(_core.LLVMConstSub(self.ptr, rhs.ptr))

    def fsub(self, rhs):
        check_is_constant(rhs)
        return _make_value(_core.LLVMConstFSub(self.ptr, rhs.ptr))

    def mul(self, rhs):
        check_is_constant(rhs)
        return _make_value(_core.LLVMConstMul(self.ptr, rhs.ptr))

    def fmul(self, rhs):
        check_is_constant(rhs)
        return _make_value(_core.LLVMConstFMul(self.ptr, rhs.ptr))

    def udiv(self, rhs):
        check_is_constant(rhs)
        return _make_value(_core.LLVMConstUDiv(self.ptr, rhs.ptr))

    def sdiv(self, rhs):
        check_is_constant(rhs)
        return _make_value(_core.LLVMConstSDiv(self.ptr, rhs.ptr))

    def fdiv(self, rhs):
        check_is_constant(rhs)
        return _make_value(_core.LLVMConstFDiv(self.ptr, rhs.ptr))

    def urem(self, rhs):
        check_is_constant(rhs)
        return _make_value(_core.LLVMConstURem(self.ptr, rhs.ptr))

    def srem(self, rhs):
        check_is_constant(rhs)
        return _make_value(_core.LLVMConstSRem(self.ptr, rhs.ptr))

    def frem(self, rhs):
        check_is_constant(rhs)
        return _make_value(_core.LLVMConstFRem(self.ptr, rhs.ptr))

    def and_(self, rhs):
        check_is_constant(rhs)
        return _make_value(_core.LLVMConstAnd(self.ptr, rhs.ptr))

    def or_(self, rhs):
        check_is_constant(rhs)
        return _make_value(_core.LLVMConstOr(self.ptr, rhs.ptr))

    def xor(self, rhs):
        check_is_constant(rhs)
        return _make_value(_core.LLVMConstXor(self.ptr, rhs.ptr))

    def icmp(self, int_pred, rhs):
        check_is_constant(rhs)
        return _make_value(_core.LLVMConstICmp(int_pred, self.ptr, rhs.ptr))

    def fcmp(self, real_pred, rhs):
        check_is_constant(rhs)
        return _make_value(_core.LLVMConstFCmp(real_pred, self.ptr, rhs.ptr))

    def shl(self, rhs):
        check_is_constant(rhs)
        return _make_value(_core.LLVMConstShl(self.ptr, rhs.ptr))

    def lshr(self, rhs):
        check_is_constant(rhs)
        return _make_value(_core.LLVMConstLShr(self.ptr, rhs.ptr))

    def ashr(self, rhs):
        check_is_constant(rhs)
        return _make_value(_core.LLVMConstAShr(self.ptr, rhs.ptr))

    def gep(self, indices):
        index_ptrs = unpack_constants(indices)
        return _make_value(_core.LLVMConstGEP(self.ptr, index_ptrs))

    def trunc(self, ty):
        check_is_type(ty)
        return _make_value(_core.LLVMConstTrunc(self.ptr, ty.ptr))

    def sext(self, ty):
        check_is_type(ty)
        return _make_value(_core.LLVMConstSExt(self.ptr, ty.ptr))

    def zext(self, ty):
        check_is_type(ty)
        return _make_value(_core.LLVMConstZExt(self.ptr, ty.ptr))

    def fptrunc(self, ty):
        check_is_type(ty)
        return _make_value(_core.LLVMConstFPTrunc(self.ptr, ty.ptr))

    def fpext(self, ty):
        check_is_type(ty)
        return _make_value(_core.LLVMConstFPExt(self.ptr, ty.ptr))

    def uitofp(self, ty):
        check_is_type(ty)
        return _make_value(_core.LLVMConstUIToFP(self.ptr, ty.ptr))

    def sitofp(self, ty):
        check_is_type(ty)
        return _make_value(_core.LLVMConstSIToFP(self.ptr, ty.ptr))

    def fptoui(self, ty):
        check_is_type(ty)
        return _make_value(_core.LLVMConstFPToUI(self.ptr, ty.ptr))

    def fptosi(self, ty):
        check_is_type(ty)
        return _make_value(_core.LLVMConstFPToSI(self.ptr, ty.ptr))

    def ptrtoint(self, ty):
        check_is_type(ty)
        return _make_value(_core.LLVMConstPtrToInt(self.ptr, ty.ptr))

    def inttoptr(self, ty):
        check_is_type(ty)
        return _make_value(_core.LLVMConstIntToPtr(self.ptr, ty.ptr))

    def bitcast(self, ty):
        check_is_type(ty)
        return _make_value(_core.LLVMConstBitCast(self.ptr, ty.ptr))

    def select(self, true_const, false_const):
        check_is_constant(true_const)
        check_is_constant(false_const)
        return _make_value(
            _core.LLVMConstSelect(self.ptr, true_const.ptr, false_const.ptr))

    def extract_element(self, index): # note: self must be a _vector_ constant
        check_is_constant(index)
        return _make_value(
            _core.LLVMConstExtractElement(self.ptr, index.ptr))

    def insert_element(self, value, index):
        # note: self must be a _vector_ constant
        check_is_constant(value)
        check_is_constant(index)
        return _make_value(
            _core.LLVMConstInsertElement(self.ptr, value.ptr, index.ptr))

    def shuffle_vector(self, vector_b, mask):
        # note: self must be a _vector_ constant
        check_is_constant(vector_b)
        # note: vector_b must be a _vector_ constant
        check_is_constant(mask)
        return _make_value(
            _core.LLVMConstShuffleVector(self.ptr, vector_b.ptr, mask.ptr))


class ConstantExpr(Constant):
    @property
    def opcode(self):
        return _core.LLVMGetConstExprOpcode(self.ptr)

    @property
    def opcode_name(self):
        return _core.LLVMGetConstExprOpcodeName(self.ptr)


class ConstantAggregateZero(Constant):
    pass


class ConstantDataArray(Constant):
    pass


class ConstantDataVector(Constant):
    pass

class ConstantInt(Constant):
    @property
    def z_ext_value(self):
        '''Obtain the zero extended value for an integer constant value.'''
        # Warning: assertion failure when value does not fit in 64 bits
        return _core.LLVMConstIntGetZExtValue(self.ptr)

    @property
    def s_ext_value(self):
        '''Obtain the sign extended value for an integer constant value.'''
        # Warning: assertion failure when value does not fit in 64 bits
        return _core.LLVMConstIntGetSExtValue(self.ptr)


class ConstantFP(Constant):
    pass


class ConstantArray(Constant):
    pass


class ConstantStruct(Constant):
    pass


class ConstantVector(Constant):
    pass


class ConstantPointerNull(Constant):
    pass


class UndefValue(Constant):
    pass


class GlobalValue(Constant):

    def __init__(self, ptr):
        Constant.__init__(self, ptr)
        # Hang on to the module, don't let it die before we do.
        # It is nice to have just a map of functions without
        # retaining a ref to the owning module.
        self._module_obj = self.module

    def _delete(self):
        # Called in subclass delete() methods.
        self._module_obj = None

    def _get_linkage(self):
        return _core.LLVMGetLinkage(self.ptr)
    def _set_linkage(self, value):
        _core.LLVMSetLinkage(self.ptr, value)
    linkage = property(_get_linkage, _set_linkage)

    def _get_section(self):
        return _core.LLVMGetSection(self.ptr)
    def _set_section(self, value):
        return _core.LLVMSetSection(self.ptr, value)
    section = property(_get_section, _set_section)

    def _get_visibility(self):
        return _core.LLVMGetVisibility(self.ptr)
    def _set_visibility(self, value):
        return _core.LLVMSetVisibility(self.ptr, value)
    visibility = property(_get_visibility, _set_visibility)

    def _get_alignment(self):
        return _core.LLVMGetAlignment(self.ptr)
    def _set_alignment(self, value):
        return _core.LLVMSetAlignment(self.ptr, value)
    alignment = property(_get_alignment, _set_alignment)

    @property
    def is_declaration(self):
        return _core.LLVMIsDeclaration(self.ptr) != 0

    @property
    def module(self):
        return Module(_core.LLVMGetGlobalParent(self.ptr))

class GlobalVariable(GlobalValue):

    @staticmethod
    def new(module, ty, name, addrspace=0):
        check_is_module(module)
        check_is_type(ty)
        return _make_value(_core.LLVMAddGlobalInAddressSpace(module.ptr, ty.ptr, name, addrspace))

    @staticmethod
    def get(module, name):
        check_is_module(module)
        ptr = _core.LLVMGetNamedGlobal(module.ptr, name)
        if not ptr:
            raise llvm.LLVMException("no global named `%s`" % name)
        return _make_value(ptr)

    def delete(self):
        self._delete()
        _core.LLVMDeleteGlobal(self.ptr)
        self.forget()
        self.ptr = None

    def _get_initializer(self):
        if _core.LLVMHasInitializer(self.ptr):
            return _make_value(_core.LLVMGetInitializer(self.ptr))
        else:
            return None

    def _set_initializer(self, const):
        check_is_constant(const)
        _core.LLVMSetInitializer(self.ptr, const.ptr)

    def _del_initializer(self):
        check_is_constant(const)

    initializer = property(_get_initializer, _set_initializer)

    def _get_is_global_constant(self):
        return _core.LLVMIsGlobalConstant(self.ptr)

    def _set_is_global_constant(self, value):
        value = _to_int(value)
        _core.LLVMSetGlobalConstant(self.ptr, value)

    global_constant = \
        property(_get_is_global_constant, _set_is_global_constant)

    def _get_thread_local(self):
        return bool(_core.LLVMIsThreadLocal(self.ptr))
    def _set_thread_local(self, value):
        value = _to_int(value)
        _core.LLVMSetThreadLocal(self.ptr, value)

    thread_local = property(_get_thread_local, _set_thread_local)

class Argument(Value):

    def add_attribute(self, attr):
        _core.LLVMAddAttribute(self.ptr, attr)

    def remove_attribute(self, attr):
        _core.LLVMRemoveAttribute(self.ptr, attr)

    def _set_alignment(self, align):
        _core.LLVMSetParamAlignment(self.ptr, align)

    def _get_alignment(self):
        return _core.LLVMGetParamAlignment(self.ptr)

    alignment = \
        property(_get_alignment, _set_alignment)


class Function(GlobalValue):

    @staticmethod
    def new(module, func_ty, name):
        check_is_module(module)
        check_is_type(func_ty)
        return _make_value(_core.LLVMAddFunction(module.ptr, name,
            func_ty.ptr))

    @staticmethod
    def get_or_insert(module, func_ty, name):
        check_is_module(module)
        check_is_type(func_ty)
        return _make_value(_core.LLVMModuleGetOrInsertFunction(module.ptr,
            name, func_ty.ptr))

    @staticmethod
    def get(module, name):
        check_is_module(module)
        ptr = _core.LLVMGetNamedFunction(module.ptr, name)
        if not ptr:
            raise llvm.LLVMException("no function named `%s`" % name)
        return _make_value(ptr)

    @staticmethod
    def intrinsic(module, intrinsic_id, types):
        check_is_module(module)
        ptrs = unpack_types(types)
        return _make_value(
            _core.LLVMGetIntrinsic(module.ptr, intrinsic_id, ptrs))

    def delete(self):
        self._delete()
        _core.LLVMDeleteFunction(self.ptr)
        self.forget()
        self.ptr = None

    @property
    def intrinsic_id(self):
        return _core.LLVMGetIntrinsicID(self.ptr)

    def _get_cc(self): return _core.LLVMGetFunctionCallConv(self.ptr)
    def _set_cc(self, value): _core.LLVMSetFunctionCallConv(self.ptr, value)
    calling_convention = property(_get_cc, _set_cc)

    def _get_coll(self): return _core.LLVMGetGC(self.ptr)
    def _set_coll(self, value): _core.LLVMSetGC(self.ptr, value)
    collector = property(_get_coll, _set_coll)

    # the nounwind attribute:
    def _get_does_not_throw(self): return _core.LLVMGetDoesNotThrow(self.ptr)
    def _set_does_not_throw(self,value):  _core.LLVMSetDoesNotThrow(self.ptr, value)
    does_not_throw = property(_get_does_not_throw, _set_does_not_throw)

    @property
    def args(self):
        return _util.wrapiter(_core.LLVMGetFirstParam,
            _core.LLVMGetNextParam, self.ptr, _make_value)

    @property
    def basic_block_count(self):
        return _core.LLVMCountBasicBlocks(self.ptr)

    @property
    def entry_basic_block(self):
        if self.basic_block_count == 0:
            return None
        return _make_value(_core.LLVMGetEntryBasicBlock(self.ptr))

    def get_entry_basic_block(self):
        """Deprecated, use entry_basic_block property."""
        return self.entry_basic_block

    def append_basic_block(self, name):
        return _make_value(_core.LLVMAppendBasicBlock(self.ptr, name))

    @property
    def basic_blocks(self):
        return _util.wrapiter(_core.LLVMGetFirstBasicBlock,
            _core.LLVMGetNextBasicBlock, self.ptr, _make_value)

    def viewCFG(self):
        return _core.LLVMViewFunctionCFG(self.ptr)

    def add_attribute(self, attr):
        _core.LLVMAddFunctionAttr(self.ptr, attr)

    def remove_attribute(self, attr):
        _core.LLVMRemoveFunctionAttr(self.ptr, attr)

    def viewCFGOnly(self):
        return _core.LLVMViewFunctionCFGOnly(self.ptr)

    def verify(self):
        # Although we're just asking LLVM to return the success or
        # failure, it appears to print result to stderr and abort.
        return _core.LLVMVerifyFunction(self.ptr) != 0

#===----------------------------------------------------------------------===
# InlineAsm
#===----------------------------------------------------------------------===

class InlineAsm(Value):
    @staticmethod
    def get(functype, asm, constrains, side_effect=False,
                   align_stack=False, dialect=0):
        assert dialect == 0, "LLVM 3.1 does not implement dialect selection"
        check_is_type(functype)
        pycap = _core.LLVMGetFunctionFromInlineAsm(functype.ptr, asm,
                                                   constrains, int(side_effect),
                                                   int(align_stack), dialect)
        return _make_value(pycap)

#===----------------------------------------------------------------------===
# MetaData
#===----------------------------------------------------------------------===

class MetaData(Value):
    @staticmethod
    def get(module, values):
        '''
        values -- must be an iterable of Constant or None. None is treated as "null".
        '''
        vs = unpack_values_or_none(values)
        ptr = _core.LLVMMetaDataGet(module.ptr, vs)
        return MetaData(ptr)

    @staticmethod
    def get_named_operands(module, name):
        lst = _core.LLVMGetNamedMetadataOperands(module.ptr, name)
        return [MetaData(ptr) for ptr in lst]

    @staticmethod
    def add_named_operand(module, name, operand):
        _core.LLVMAddNamedMetadataOperand(module.ptr, name, operand.ptr)

    @property
    def operand_count(self):
        return _core.LLVMMetaDataGetNumOperands(self.ptr)

    @property
    def operands(self):
        """Yields operands of this metadata."""
        return [self._get_operand(i) for i in range(self.operand_count)]

    def _get_operand(self, i):
        val = _core.LLVMMetaDataGetOperand(self.ptr, i)
        if val: # metadata operands can be None
            return _make_value(val)

class MetaDataString(Value):
    @staticmethod
    def get(module, s):
        ptr = _core.LLVMMetaDataStringGet(module.ptr, s)
        return MetaDataString(ptr)

    @property
    def string(self):
        '''Same as MDString::getString'''
        return self.name

class NamedMetaData(llvm.Cacheable):
    @staticmethod
    def get_or_insert(mod, name):
        return mod.get_or_insert_named_metadata(name)

    @staticmethod
    def get(mod, name):
        return mod.get_named_metadata(name)

    def __init__(self, ptr):
        self.ptr = ptr

    def delete(self):
        _core.LLVMEraseNamedMetaData(self.ptr)

    @property
    def name(self):
        return _core.LLVMNamedMetaDataGetName(self.ptr)

    def __str__(self):
        return _core.LLVMDumpNamedMDToString(self.ptr)

    def add(self, operand):
        _core.LLVMNamedMetaDataAddOperand(self.ptr, operand.ptr)

#===----------------------------------------------------------------------===
# Instruction
#===----------------------------------------------------------------------===

class Instruction(User):

    @property
    def basic_block(self):
        return _make_value(_core.LLVMGetInstructionParent(self.ptr))

    @property
    def is_terminator(self):
        return _core.LLVMInstIsTerminator(self.ptr) != 0

    @property
    def is_binary_op(self):
        return _core.LLVMInstIsBinaryOp(self.ptr) != 0

    @property
    def is_shift(self):
        return _core.LLVMInstIsShift(self.ptr) != 0

    @property
    def is_cast(self):
        return _core.LLVMInstIsCast(self.ptr) != 0

    @property
    def is_logical_shift(self):
        return _core.LLVMInstIsLogicalShift(self.ptr) != 0

    @property
    def is_arithmetic_shift(self):
        return _core.LLVMInstIsArithmeticShift(self.ptr) != 0

    @property
    def is_associative(self):
        return _core.LLVMInstIsAssociative(self.ptr) != 0

    @property
    def is_commutative(self):
        return _core.LLVMInstIsCommutative(self.ptr) != 0

    @property
    def is_volatile(self):
        """True if this is a volatile load or store."""
        return _core.LLVMInstIsVolatile(self.ptr) != 0

    def set_volatile(self, flag):
        return _core.LLVMSetVolatile(self.ptr, int(bool(flag)))

    def set_metadata(self, kind, metadata):
        return _core.LLVMInstSetMetaData(self.ptr, kind, metadata.ptr)

    @property
    def opcode(self):
        return _core.LLVMInstGetOpcode(self.ptr)

    @property
    def opcode_name(self):
        return _core.LLVMInstGetOpcodeName(self.ptr)


class CallOrInvokeInstruction(Instruction):

    def _get_cc(self): return _core.LLVMGetInstructionCallConv(self.ptr)
    def _set_cc(self, value): _core.LLVMSetInstructionCallConv(self.ptr, value)
    calling_convention = property(_get_cc, _set_cc)

    def add_parameter_attribute(self, idx, attr):
        _core.LLVMAddInstrAttribute(self.ptr, idx, attr)

    def remove_parameter_attribute(self, idx, attr):
        _core.LLVMRemoveInstrAttribute(self.ptr, idx, attr)

    def set_parameter_alignment(self, idx, align):
        _core.LLVMSetInstrParamAlignment(self.ptr, idx, align)

    def _get_called_function(self):
        function = _core.LLVMInstGetCalledFunction(self.ptr)
        if function: # Return value can be None on indirect call/invoke
            return _make_value(function)

    def _set_called_function(self, function):
        _core.LLVMInstSetCalledFunction(self.ptr, function.ptr)

    called_function = property(_get_called_function, _set_called_function)

    # tail call is valid only for 'call', not 'invoke'
    # disabled for now
    #def _get_tc(self): return _core.LLVMIsTailCall(self.ptr)
    #def _set_tc(self, value): _core.LLVMSetTailCall(self.ptr, value)
    #tail_call = property(_get_tc, _set_tc)


class PHINode(Instruction):

    @property
    def incoming_count(self):
        return _core.LLVMCountIncoming(self.ptr)

    def add_incoming(self, value, block):
        check_is_value(value)
        check_is_basic_block(block)
        _core.LLVMAddIncoming1(self.ptr, value.ptr, block.ptr)

    def get_incoming_value(self, idx):
        return _make_value(_core.LLVMGetIncomingValue(self.ptr, idx))

    def get_incoming_block(self, idx):
        return _make_value(_core.LLVMGetIncomingBlock(self.ptr, idx))


class SwitchInstruction(Instruction):

    def add_case(self, const, bblk):
        check_is_constant(const) # and has to be an int too
        check_is_basic_block(bblk)
        _core.LLVMAddCase(self.ptr, const.ptr, bblk.ptr)


class CompareInstruction(Instruction):

    @property
    def predicate(self):
        return _core.LLVMCmpInstGetPredicate(self.ptr)


#===----------------------------------------------------------------------===
# Basic block
#===----------------------------------------------------------------------===

class BasicBlock(Value):

    def insert_before(self, name):
        return _make_value(_core.LLVMInsertBasicBlock(self.ptr, name))

    def delete(self):
        _core.LLVMDeleteBasicBlock(self.ptr)
        self.forget()
        self.ptr = None

    @property
    def function(self):
        func_ptr = _core.LLVMGetBasicBlockParent(self.ptr)
        return _make_value(func_ptr)

    @property
    def instructions(self):
        return _util.wrapiter(_core.LLVMGetFirstInstruction,
            _core.LLVMGetNextInstruction, self.ptr, _make_value)


#===----------------------------------------------------------------------===
# Value factory method
#===----------------------------------------------------------------------===

# value ID -> class map
__class_for_valueid = {
    VALUE_ARGUMENT                        : Argument,
    VALUE_BASIC_BLOCK                     : BasicBlock,
    VALUE_FUNCTION                        : Function,
    VALUE_GLOBAL_ALIAS                    : GlobalValue,
    VALUE_GLOBAL_VARIABLE                 : GlobalVariable,
    VALUE_UNDEF_VALUE                     : UndefValue,
    VALUE_CONSTANT_EXPR                   : ConstantExpr,
    VALUE_CONSTANT_AGGREGATE_ZERO         : ConstantAggregateZero,
    VALUE_CONSTANT_DATA_ARRAY             : ConstantDataArray,
    VALUE_CONSTANT_DATA_VECTOR            : ConstantDataVector,
    VALUE_CONSTANT_INT                    : ConstantInt,
    VALUE_CONSTANT_FP                     : ConstantFP,
    VALUE_CONSTANT_ARRAY                  : ConstantArray,
    VALUE_CONSTANT_STRUCT                 : ConstantStruct,
    VALUE_CONSTANT_VECTOR                 : ConstantVector,
    VALUE_CONSTANT_POINTER_NULL           : ConstantPointerNull,
    VALUE_MD_NODE                         : MetaData,
    VALUE_MD_STRING                       : MetaDataString,
    VALUE_INLINE_ASM                      : InlineAsm,
    VALUE_INSTRUCTION + OPCODE_PHI        : PHINode,
    VALUE_INSTRUCTION + OPCODE_CALL       : CallOrInvokeInstruction,
    VALUE_INSTRUCTION + OPCODE_INVOKE     : CallOrInvokeInstruction,
    VALUE_INSTRUCTION + OPCODE_SWITCH     : SwitchInstruction,
    VALUE_INSTRUCTION + OPCODE_ICMP       : CompareInstruction,
    VALUE_INSTRUCTION + OPCODE_FCMP       : CompareInstruction
}

def _make_value(ptr):
    kind = _core.LLVMValueGetID(ptr)
    # based on kind, create one of the Value subclasses
    class_obj = __class_for_valueid.get(kind)
    if class_obj:
        return class_obj(ptr)
    elif kind > VALUE_INSTRUCTION:
        # "generic" instruction
        return Instruction(ptr)
    else:
        # "generic" value
        return Value(ptr)


#===----------------------------------------------------------------------===
# Builder
#===----------------------------------------------------------------------===

class Builder(object):

    @staticmethod
    def new(basic_block):
        check_is_basic_block(basic_block)
        b = Builder(_core.LLVMCreateBuilder())
        b.position_at_end(basic_block)
        return b

    def __init__(self, ptr):
        self.ptr = ptr

    def __del__(self):
        _core.LLVMDisposeBuilder(self.ptr)

    def position_at_beginning(self, bblk):
        """Position the builder at the beginning of the given block.

        Next instruction inserted will be first one in the block."""
        check_is_basic_block(bblk)
        # Avoids using "blk.instructions", which will fetch all the
        # instructions into a list. Don't try this at home, though.
        inst_ptr = _core.LLVMGetFirstInstruction(bblk.ptr)
        if inst_ptr:
            # Issue #10: inst_ptr can be None if b/b has no insts.
            inst = _make_value(inst_ptr)
            self.position_before(inst)

    def position_at_end(self, bblk):
        """Position the builder at the end of the given block.

        Next instruction inserted will be last one in the block."""
        _core.LLVMPositionBuilderAtEnd(self.ptr, bblk.ptr)

    def position_before(self, instr):
        """Position the builder before the given instruction.

        The instruction can belong to a basic block other than the
        current one."""
        _core.LLVMPositionBuilderBefore(self.ptr, instr.ptr)

    @property
    def block(self):
        """Deprecated, use basic_block property instead."""
        return _make_value(_core.LLVMGetInsertBlock(self.ptr))

    @property
    def basic_block(self):
        """The basic block where the builder is positioned."""
        return _make_value(_core.LLVMGetInsertBlock(self.ptr))

    # terminator instructions

    def ret_void(self):
        return _make_value(_core.LLVMBuildRetVoid(self.ptr))

    def ret(self, value):
        check_is_value(value)
        return _make_value(_core.LLVMBuildRet(self.ptr, value.ptr))

    def ret_many(self, values):
        vs = unpack_values(values)
        return _make_value(_core.LLVMBuildRetMultiple(self.ptr, vs))

    def branch(self, bblk):
        check_is_basic_block(bblk)
        return _make_value(_core.LLVMBuildBr(self.ptr, bblk.ptr))

    def cbranch(self, if_value, then_blk, else_blk):
        check_is_value(if_value)
        check_is_basic_block(then_blk)
        check_is_basic_block(else_blk)
        return _make_value(
            _core.LLVMBuildCondBr(self.ptr,
                if_value.ptr, then_blk.ptr, else_blk.ptr))

    def switch(self, value, else_blk, n=10):
        check_is_value(value)  # value has to be of any 'int' type
        check_is_basic_block(else_blk)
        return _make_value(
            _core.LLVMBuildSwitch(self.ptr, value.ptr, else_blk.ptr, n))

    def invoke(self, func, args, then_blk, catch_blk, name=""):
        check_is_callable(func)
        check_is_basic_block(then_blk)
        check_is_basic_block(catch_blk)
        args2 = unpack_values(args)
        return _make_value(
            _core.LLVMBuildInvoke(self.ptr, func.ptr, args2,
                then_blk.ptr, catch_blk.ptr, name))

    def unreachable(self):
        return _make_value(_core.LLVMBuildUnreachable(self.ptr))

    # arithmethic, bitwise and logical

    def add(self, lhs, rhs, name=""):
        check_is_value(lhs)
        check_is_value(rhs)
        return _make_value(_core.LLVMBuildAdd(self.ptr, lhs.ptr, rhs.ptr, name))

    def fadd(self, lhs, rhs, name=""):
        check_is_value(lhs)
        check_is_value(rhs)
        return _make_value(_core.LLVMBuildFAdd(self.ptr, lhs.ptr, rhs.ptr, name))

    def sub(self, lhs, rhs, name=""):
        check_is_value(lhs)
        check_is_value(rhs)
        return _make_value(_core.LLVMBuildSub(self.ptr, lhs.ptr, rhs.ptr, name))

    def fsub(self, lhs, rhs, name=""):
        check_is_value(lhs)
        check_is_value(rhs)
        return _make_value(_core.LLVMBuildFSub(self.ptr, lhs.ptr, rhs.ptr, name))

    def mul(self, lhs, rhs, name=""):
        check_is_value(lhs)
        check_is_value(rhs)
        return _make_value(_core.LLVMBuildMul(self.ptr, lhs.ptr, rhs.ptr, name))

    def fmul(self, lhs, rhs, name=""):
        check_is_value(lhs)
        check_is_value(rhs)
        return _make_value(_core.LLVMBuildFMul(self.ptr, lhs.ptr, rhs.ptr, name))

    def udiv(self, lhs, rhs, name=""):
        check_is_value(lhs)
        check_is_value(rhs)
        return _make_value(
            _core.LLVMBuildUDiv(self.ptr, lhs.ptr, rhs.ptr, name))

    def sdiv(self, lhs, rhs, name=""):
        check_is_value(lhs)
        check_is_value(rhs)
        return _make_value(
            _core.LLVMBuildSDiv(self.ptr, lhs.ptr, rhs.ptr, name))

    def fdiv(self, lhs, rhs, name=""):
        check_is_value(lhs)
        check_is_value(rhs)
        return _make_value(
            _core.LLVMBuildFDiv(self.ptr, lhs.ptr, rhs.ptr, name))

    def urem(self, lhs, rhs, name=""):
        check_is_value(lhs)
        check_is_value(rhs)
        return _make_value(
            _core.LLVMBuildURem(self.ptr, lhs.ptr, rhs.ptr, name))

    def srem(self, lhs, rhs, name=""):
        check_is_value(lhs)
        check_is_value(rhs)
        return _make_value(
            _core.LLVMBuildSRem(self.ptr, lhs.ptr, rhs.ptr, name))

    def frem(self, lhs, rhs, name=""):
        check_is_value(lhs)
        check_is_value(rhs)
        return _make_value(
            _core.LLVMBuildFRem(self.ptr, lhs.ptr, rhs.ptr, name))

    def shl(self, lhs, rhs, name=""):
        check_is_value(lhs)
        check_is_value(rhs)
        return _make_value(
            _core.LLVMBuildShl(self.ptr, lhs.ptr, rhs.ptr, name))

    def lshr(self, lhs, rhs, name=""):
        check_is_value(lhs)
        check_is_value(rhs)
        return _make_value(
            _core.LLVMBuildLShr(self.ptr, lhs.ptr, rhs.ptr, name))

    def ashr(self, lhs, rhs, name=""):
        check_is_value(lhs)
        check_is_value(rhs)
        return _make_value(
            _core.LLVMBuildAShr(self.ptr, lhs.ptr, rhs.ptr, name))

    def and_(self, lhs, rhs, name=""):
        check_is_value(lhs)
        check_is_value(rhs)
        return _make_value(
            _core.LLVMBuildAnd(self.ptr, lhs.ptr, rhs.ptr, name))

    def or_(self, lhs, rhs, name=""):
        check_is_value(lhs)
        check_is_value(rhs)
        return _make_value(
            _core.LLVMBuildOr(self.ptr, lhs.ptr, rhs.ptr, name))

    def xor(self, lhs, rhs, name=""):
        check_is_value(lhs)
        check_is_value(rhs)
        return _make_value(
            _core.LLVMBuildXor(self.ptr, lhs.ptr, rhs.ptr, name))

    def neg(self, val, name=""):
        check_is_value(val)
        return _make_value(_core.LLVMBuildNeg(self.ptr, val.ptr, name))

    def not_(self, val, name=""):
        check_is_value(val)
        return _make_value(_core.LLVMBuildNot(self.ptr, val.ptr, name))

    # memory

    def malloc(self, ty, name=""):
        check_is_type(ty)
        return _make_value(_core.LLVMBuildMalloc(self.ptr, ty.ptr, name))

    def malloc_array(self, ty, size, name=""):
        check_is_type(ty)
        check_is_value(size)
        return _make_value(
            _core.LLVMBuildArrayMalloc(self.ptr, ty.ptr, size.ptr, name))

    def alloca(self, ty, name=""):
        check_is_type(ty)
        return _make_value(_core.LLVMBuildAlloca(self.ptr, ty.ptr, name))

    def alloca_array(self, ty, size, name=""):
        check_is_type(ty)
        check_is_value(size)
        return _make_value(
            _core.LLVMBuildArrayAlloca(self.ptr, ty.ptr, size.ptr, name))

    def free(self, ptr):
        check_is_value(ptr)
        return _make_value(_core.LLVMBuildFree(self.ptr, ptr.ptr))

    def load(self, ptr, name="", align=0, volatile=False, invariant=False):
        check_is_value(ptr)
        inst = _make_value(_core.LLVMBuildLoad(self.ptr, ptr.ptr, name))
        if align:
            _core.LLVMLdSetAlignment(inst.ptr, align)
        if volatile:
            inst.set_volatile(volatile)
        if invariant:
            mod = self.basic_block.function.module
            md = MetaData.get(mod, []) # empty metadata node
            inst.set_metadata('invariant.load', md)
        return inst

    def store(self, value, ptr, align=0, volatile=False):
        check_is_value(value)
        check_is_value(ptr)
        inst = _make_value(_core.LLVMBuildStore(self.ptr, value.ptr, ptr.ptr))
        if align:
            _core.LLVMStSetAlignment(inst.ptr, align)
        if volatile:
            inst.set_volatile(volatile)
        return inst

    def gep(self, ptr, indices, name=""):
        check_is_value(ptr)
        index_ptrs = unpack_values(indices)
        return _make_value(
            _core.LLVMBuildGEP(self.ptr, ptr.ptr, index_ptrs, name))

    # casts and extensions

    def trunc(self, value, dest_ty, name=""):
        check_is_value(value)
        check_is_type(dest_ty)
        return _make_value(
            _core.LLVMBuildTrunc(self.ptr, value.ptr, dest_ty.ptr, name))

    def zext(self, value, dest_ty, name=""):
        check_is_value(value)
        check_is_type(dest_ty)
        return _make_value(
            _core.LLVMBuildZExt(self.ptr, value.ptr, dest_ty.ptr, name))

    def sext(self, value, dest_ty, name=""):
        check_is_value(value)
        check_is_type(dest_ty)
        return _make_value(
            _core.LLVMBuildSExt(self.ptr, value.ptr, dest_ty.ptr, name))

    def fptoui(self, value, dest_ty, name=""):
        check_is_value(value)
        check_is_type(dest_ty)
        return _make_value(
            _core.LLVMBuildFPToUI(self.ptr, value.ptr, dest_ty.ptr, name))

    def fptosi(self, value, dest_ty, name=""):
        check_is_value(value)
        check_is_type(dest_ty)
        return _make_value(
            _core.LLVMBuildFPToSI(self.ptr, value.ptr, dest_ty.ptr, name))

    def uitofp(self, value, dest_ty, name=""):
        check_is_value(value)
        check_is_type(dest_ty)
        return _make_value(
            _core.LLVMBuildUIToFP(self.ptr, value.ptr, dest_ty.ptr, name))

    def sitofp(self, value, dest_ty, name=""):
        check_is_value(value)
        check_is_type(dest_ty)
        return _make_value(
            _core.LLVMBuildSIToFP(self.ptr, value.ptr, dest_ty.ptr, name))

    def fptrunc(self, value, dest_ty, name=""):
        check_is_value(value)
        check_is_type(dest_ty)
        return _make_value(
            _core.LLVMBuildFPTrunc(self.ptr, value.ptr, dest_ty.ptr, name))

    def fpext(self, value, dest_ty, name=""):
        check_is_value(value)
        check_is_type(dest_ty)
        return _make_value(
            _core.LLVMBuildFPExt(self.ptr, value.ptr, dest_ty.ptr, name))

    def ptrtoint(self, value, dest_ty, name=""):
        check_is_value(value)
        check_is_type(dest_ty)
        return _make_value(
            _core.LLVMBuildPtrToInt(self.ptr, value.ptr, dest_ty.ptr, name))

    def inttoptr(self, value, dest_ty, name=""):
        check_is_value(value)
        check_is_type(dest_ty)
        return _make_value(
            _core.LLVMBuildIntToPtr(self.ptr, value.ptr, dest_ty.ptr, name))

    def bitcast(self, value, dest_ty, name=""):
        check_is_value(value)
        check_is_type(dest_ty)
        return _make_value(
            _core.LLVMBuildBitCast(self.ptr, value.ptr, dest_ty.ptr, name))

    # comparisons

    def icmp(self, ipred, lhs, rhs, name=""):
        check_is_value(lhs)
        check_is_value(rhs)
        return _make_value(
            _core.LLVMBuildICmp(self.ptr, ipred, lhs.ptr, rhs.ptr, name))

    def fcmp(self, rpred, lhs, rhs, name=""):
        check_is_value(lhs)
        check_is_value(rhs)
        return _make_value(
            _core.LLVMBuildFCmp(self.ptr, rpred, lhs.ptr, rhs.ptr, name))

    # misc

    def extract_value(self, retval, idx, name=""):
        check_is_value(retval)
        return _make_value(
            _core.LLVMBuildGetResult(self.ptr, retval.ptr, idx, name))

    # obsolete synonym for extract_value
    getresult = extract_value

    def insert_value(self, retval, rhs, idx, name=""):
        check_is_value(retval)
        check_is_value(rhs)
        return _make_value(
            _core.LLVMBuildInsertValue(self.ptr, retval.ptr, rhs.ptr, idx,
                                       name))

    def phi(self, ty, name=""):
        check_is_type(ty)
        return _make_value(_core.LLVMBuildPhi(self.ptr, ty.ptr, name))

    def call(self, fn, args, name=""):
        check_is_callable(fn)

        err_template = 'Argument type mismatch: expected %s but got %s'
        for i, (t, v) in enumerate(zip(fn.type.pointee.args, args)):
            if  t != v.type:
                raise TypeError(err_template % (t, v.type))
        arg_ptrs = unpack_values(args)
        return _make_value(
            _core.LLVMBuildCall(self.ptr, fn.ptr, arg_ptrs, name))

    def select(self, cond, then_value, else_value, name=""):
        check_is_value(cond)
        check_is_value(then_value)
        check_is_value(else_value)
        return _make_value(
            _core.LLVMBuildSelect(self.ptr, cond.ptr,
                then_value.ptr, else_value.ptr, name))

    def vaarg(self, list_val, ty, name=""):
        check_is_value(list_val)
        check_is_type(ty)
        return _make_value(
            _core.LLVMBuildVAArg(self.ptr, list_val.ptr, ty.ptr, name))

    def extract_element(self, vec_val, idx_val, name=""):
        check_is_value(vec_val)
        check_is_value(idx_val)
        return _make_value(
            _core.LLVMBuildExtractElement(self.ptr, vec_val.ptr,
                idx_val.ptr, name))

    def insert_element(self, vec_val, elt_val, idx_val, name=""):
        check_is_value(vec_val)
        check_is_value(elt_val)
        check_is_value(idx_val)
        return _make_value(
            _core.LLVMBuildInsertElement(self.ptr, vec_val.ptr,
                elt_val.ptr, idx_val.ptr, name))

    def shuffle_vector(self, vecA, vecB, mask, name=""):
        check_is_value(vecA)
        check_is_value(vecB)
        check_is_value(mask)
        return _make_value(
            _core.LLVMBuildShuffleVector(self.ptr,
                vecA.ptr, vecB.ptr, mask.ptr, name))

    # atomics

    def atomic_cmpxchg(self, ptr, old, new, ordering, crossthread=True):
        check_is_value(ptr)
        check_is_value(old)
        check_is_value(new)
        inst = _core.LLVMBuildAtomicCmpXchg(self.ptr, ptr.ptr, old.ptr, new.ptr,
                                            ordering.lower(),
                                            int(bool(crossthread)))
        return _make_value(inst)

    def atomic_rmw(self, op, ptr, val, ordering, crossthread=True):
        check_is_value(ptr)
        check_is_value(val)
        inst = _core.LLVMBuildAtomicRMW(self.ptr, op.lower(), ptr.ptr, val.ptr,
                                        ordering.lower(), int(bool(crossthread)))
        return _make_value(inst)

    def atomic_xchg(self, *args, **kwargs):
        return self.atomic_rmw('xchg', *args, **kwargs)

    def atomic_add(self, *args, **kwargs):
        return self.atomic_rmw('add', *args, **kwargs)

    def atomic_sub(self, *args, **kwargs):
        return self.atomic_rmw('sub', *args, **kwargs)

    def atomic_and(self, *args, **kwargs):
        return self.atomic_rmw('and', *args, **kwargs)

    def atomic_nand(self, *args, **kwargs):
        return self.atomic_rmw('nand', *args, **kwargs)

    def atomic_or(self, *args, **kwargs):
        return self.atomic_rmw('or', *args, **kwargs)

    def atomic_xor(self, *args, **kwargs):
        return self.atomic_rmw('xor', *args, **kwargs)

    def atomic_max(self, *args, **kwargs):
        return self.atomic_rmw('max', *args, **kwargs)

    def atomic_min(self, *args, **kwargs):
        return self.atomic_rmw('min', *args, **kwargs)

    def atomic_umax(self, *args, **kwargs):
        return self.atomic_rmw('umax', *args, **kwargs)

    def atomic_umin(self, *args, **kwargs):
        return self.atomic_rmw('umin', *args, **kwargs)


    def atomic_load(self, ptr, ordering, align=1, crossthread=True,
                    volatile=False, name=""):
        check_is_value(ptr)
        inst = _make_value(_core.LLVMBuildAtomicLoad(
                                    self.ptr, ptr.ptr, int(align),
                                    ordering.lower(), int(bool(crossthread))))
        if volatile:
            inst.set_volatile(volatile)
        if inst:
            inst.name = name
        return inst

    def atomic_store(self, value, ptr, ordering, align=1, crossthread=True,
                     volatile=False):
        check_is_value(value)
        check_is_value(ptr)
        inst = _make_value(_core.LLVMBuildAtomicStore(
                                    self.ptr, ptr.ptr, value.ptr, int(align),
                                    ordering.lower(), int(bool(crossthread))))
        if volatile:
            inst.set_volatile(volatile)
        return inst

    def fence(self, ordering, crossthread=True):
        inst = _make_value(_core.LLVMBuildFence(self.ptr, ordering.lower(),
                                                int(bool(crossthread))))
        return inst

#===----------------------------------------------------------------------===
# Memory buffer
#===----------------------------------------------------------------------===

class MemoryBuffer(object):

    @staticmethod
    def from_file(fname):
        ret = _core.LLVMCreateMemoryBufferWithContentsOfFile(fname)
        if isinstance(ret, str):
            return (None, ret)
        else:
            obj = MemoryBuffer(ret)
            return (obj, "")

    @staticmethod
    def from_stdin():
        ret = _core.LLVMCreateMemoryBufferWithSTDIN()
        if isinstance(ret, str):
            return (None, ret)
        else:
            obj = MemoryBuffer(ret)
            return (obj, "")

    def __init__(self, ptr):
        self.ptr = ptr

    def __del__(self):
        _core.LLVMDisposeMemoryBuffer(self.ptr)


#===----------------------------------------------------------------------===
# Misc
#===----------------------------------------------------------------------===

def load_library_permanently(filename):
    """Load a shared library.

    Load the given shared library (filename argument specifies the full
    path of the .so file) using LLVM. Symbols from these are available
    from the execution engine thereafter."""

    ret = _core.LLVMLoadLibraryPermanently(filename)
    if isinstance(ret, str):
        raise llvm.LLVMException(ret)

def inline_function(call):
    check_is_value(call)
    return bool(_core.LLVMInlineFunction(call.ptr))

def parse_environment_options(progname, envname):
    _core.LLVMParseEnvOpts(progname, envname)

#===----------------------------------------------------------------------===
# Initialization
#===----------------------------------------------------------------------===
if _core.LLVMInitializeNativeTarget():
    raise llvm.LLVMException("No native target!?")
if _core.LLVMInitializeNativeTargetAsmPrinter():
    # should this be an optional feature?
    # should user trigger the initialization?
    raise llvm.LLVMException("No native asm printer!?")


HAS_PTX = HAS_NVPTX = False
if True: # use PTX?
    try:
        _core.LLVMInitializePTXTarget()
        _core.LLVMInitializePTXTargetInfo()
        _core.LLVMInitializePTXTargetMC()
        _core.LLVMInitializePTXAsmPrinter()
        HAS_PTX = True
    except AttributeError:
        try:
            _core.LLVMInitializeNVPTXTarget()
            _core.LLVMInitializeNVPTXTargetInfo()
            _core.LLVMInitializeNVPTXTargetMC()
            _core.LLVMInitializeNVPTXAsmPrinter()
            HAS_NVPTX = True
        except AttributeError:
            pass


