view tools/binding/llvm/type.d @ 1351:8d501abecd24

Initial (but disabled) fix for ticket #294 , the actual part that fixes the bug is in a #if 0 block as I'm afraid it will cause regressions. I'm most likely not going to be around tonight, and maybe not tomorrow as well, so I'm pushing it in case someone wants to run some serious testing/investigate the problem noted in llvmhelpers.cpp : realignOffset .
author Tomas Lindquist Olsen <tomas.l.olsen gmail com>
date Thu, 14 May 2009 17:20:17 +0200
parents 4ff9ab0d472c
children
line wrap: on
line source

// Written in the D programming language by Tomas Lindquist Olsen 2008
// Binding of llvm.c.Core types for D.
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
module llvm.type;

import llvm.c.Core;
import llvm.c.Ext;

import llvm.util;

// we need free
version(Tango) {
    import tango.stdc.stdlib;
}
else {
    import std.c.stdlib;
}


/**
 * Each value in the IR has a type, an instance of [lltype]. See the
 * llvm::Type class.
 */
class Type
{
    /// global registry for 1:1 mapping of LLVMTypeRef's -> Type's
    private static Type[LLVMTypeRef] registry;
    ///
    alias LLVMTypeKind Kind;
    ///
    private LLVMTypeRef type;
    // used to detect if the kind of type has changed after refinement
    private const Kind cached_kind;
    ///
    private this(LLVMTypeRef t) {
        assert(t !is null);
        type = t;
        cached_kind = kind;
        assert((t in registry) is null, "Duplicate type");
        registry[t] = this;
        if (isAbstract())
            registerAbstractType();
    }
    ///
    void registerAbstractType() {
        static extern(C) void onTypeRefine(void* old, LLVMTypeRef newTypeRef) {
            Type T = cast(Type) old;
            registry.remove(T.type);
            
            if (LLVMGetTypeKind(newTypeRef) == T.cached_kind) {
                // The kind of type didn't change, so try to update and
                // recycle the Type by updating the LLVMTypeRef.
                T.type = newTypeRef;
                if (newTypeRef in registry) {
                    // We can't update the Type if it already exists
                    // but is abstract since doing so requires we pass
                    // a pointer to an object that will be stored where
                    // the GC can't see it. (If it's not in the registry
                    // it's safe because we'll put a reference in there
                    // for the GC to find, and if it's not abstract
                    // there's no need for the pointer to get out)
                    if (T.isAbstract())
                        T.type = null;
                } else {
                    registry[newTypeRef] = T;
                    // This callback only gets called once per type. If
                    // we recycle the old Type object for another
                    // abstract type we need to re-register it with the
                    // new LLVMTypeRef.
                    if (T.isAbstract())
                        T.registerAbstractType();
                }
            } else {
                // Kind of type has changed, invalidate the old object.
                T.type = null;
                // The new Type will get entered into the registry when
                // it's first needed.
            }
        }
        
        // Make sure we there's a reference to the passed object that
        // the GC can see in the registry.
        auto p = this.type in registry;
        assert((p !is null) && (*p is this), "Can't safely register an abstract type that isn't in the registry");
        
        LLVMRegisterAbstractTypeCallback(this.type,
                                         cast(void*) *p,
                                         &onTypeRefine);
    }
    ///
    char[] toString() {
        auto cstr = LLVMTypeToString(type);
        auto result = from_stringz(cstr).dup;
        free(cstr);
        return result;
    }
    ///
    Kind kind() {
        return LLVMGetTypeKind(type);
    }
    ///
    bool isAbstract() {
        return LLVMIsTypeAbstract(type) != 0;
    }
    /** Note: may invalidate the current object. Returns the refined Type
     *  if it can, or null otherwise.
     */
    Type refineAbstractType(Type to) {
        assert(isAbstract());
        
        LLVMRefineType(type, to.type);
        
        // Either type will do. Go through the registry to try to use the
        // "canonical" Type object for the type.
        if (type != null && to.type != null) {
            assert(type == to.type, "After refinement they should be equal, right?");
            return registry[type];
        } else if (type != null) {
            return registry[type];
        } else if (to.type != null) {
            return registry[to.type];
        }
        // Both types were invalidated. Is this even possible?
        return null;
    }
    ///
    static IntegerType IntType(uint bits) {
        return IntegerType.Get(bits);
    }
    ///
    static const Type Void,Label;
    ///
    static const IntegerType Int1, Int8, Int16, Int32, Int64, Size_t;
    ///
    static const RealType Float,Double,X86_FP80, FP128, PPC_FP128;
    ///
    static this()
    {
        Void = new Type(LLVMVoidType());
        Label = new Type(LLVMLabelType());

        Int1  = new IntegerType(LLVMInt1Type());
        Int8  = new IntegerType(LLVMInt8Type());
        Int16 = new IntegerType(LLVMInt16Type());
        Int32 = new IntegerType(LLVMInt32Type());
        Int64 = new IntegerType(LLVMInt64Type());
        if (size_t.sizeof == 4)
            Size_t = Int32;
        else
            Size_t = Int64;

        Float     = new RealType(LLVMFloatType());
        Double    = new RealType(LLVMDoubleType());
        X86_FP80  = new RealType(LLVMX86FP80Type());
        FP128     = new RealType(LLVMFP128Type());
        PPC_FP128 = new RealType(LLVMPPCFP128Type());
    }
    ///
    LLVMTypeRef ll()
    {
        return type;
    }
    ///
    void dump()
    {
        LLVMDumpType(type);
    }
    ///
    bool isBasic()
    {
        auto k = kind;
        if (k == Kind.Struct || k == Kind.Array || k == Kind.Function)
            return false;
        return true;
    }
}

///
class IntegerType : Type
{
    ///
    private this(LLVMTypeRef t)
    {
        super(t);
    }
    ///
    static IntegerType Get(uint nbits)
    {
        if (nbits == 1)
            return Type.Int1;
        else if (nbits == 8)
            return Type.Int8;
        else if (nbits == 16)
            return Type.Int16;
        else if (nbits == 32)
            return Type.Int32;
        else if (nbits == 64)
            return Type.Int64;
        else
        {
            auto t = LLVMIntType(nbits);
            auto ptr = t in registry;
            if (ptr !is null)
                return cast(IntegerType)*ptr;
            auto it = new IntegerType(t);
            return it;
        }
    }
    ///
    uint numBits()
    {
        return LLVMGetIntTypeWidth(type);
    }
}

///
class RealType : Type
{
    ///
    private this(LLVMTypeRef t)
    {
        super(t);
    }
}

///
class FunctionType : Type
{
    ///
    private Type ret;
    private const Type[] params;
    ///
    protected this(LLVMTypeRef t, Type r, Type[] pars)
    {
        super(t);
        ret = r;
        params = pars;
    }
    ///
    static FunctionType Get(Type r, Type[] pars, bool vararg=false)
    {
        auto p = new LLVMTypeRef[pars.length];
        foreach(i,v; pars) p[i] = v.ll;
        auto t = LLVMFunctionType(r.ll, p.ptr, p.length, vararg);
        auto ptr = t in registry;
        if (ptr !is null)
            return cast(FunctionType)*ptr;
        auto ft = new FunctionType(t, r, pars);
        return ft;
    }
    ///
    bool isVarArg()
    {
        return (LLVMIsFunctionVarArg(type) != 0);
    }
    ///
    Type returnType()
    {
        if (!ret.type)
            ret = getTypeOf(LLVMGetReturnType(type));
        
        return ret;
    }
    ///
    Type[] paramTypes()
    {
        foreach (par ; params) {
            if (!par.type) {
                updateParams();
            }
        }
        return params;
    }
    ///
    Type getParamType(uint idx)
    {
        auto par = params[idx];
        if (!par.type) {
            updateParams();
            par = params[idx];
        }
        return params[idx];
    }
    ///
    uint numParams()
    {
        return params.length;
    }
    /** Called when one or more of the parameter types have been
     *  invalidated.
     */
    private void updateParams() {
        assert (LLVMCountParamTypes(type) == params.length);
        auto llparams = new LLVMTypeRef[params.length];
        LLVMGetParamTypes(type, llparams.ptr);
        foreach (idx, llpar ; llparams) {
            params[idx] = getTypeOf(llpar);
        }
    }
}

///
class StructType : Type
{
    ///
    private this(LLVMTypeRef t)
    {
        super(t);
    }
    ///
    static StructType Get(Type[] elems, bool packed=false)
    {
        auto tys = new LLVMTypeRef[elems.length];
        foreach(i,e; elems) tys[i] = e.ll;
        auto t = LLVMStructType(tys.ptr, tys.length, packed);
        auto ptr = t in registry;
        if (ptr !is null)
            return cast(StructType)*ptr;
        auto st = new StructType(t);
        return st;
    }
    ///
    bool packed()
    {
        return (LLVMIsPackedStruct(type) != 0);
    }
    ///
    uint numElements()
    {
        return LLVMCountStructElementTypes(type);
    }
    ///
    Type[] elementTypes()
    {
        auto n = numElements();
        auto dst = new LLVMTypeRef[n];
        LLVMGetStructElementTypes(type, dst.ptr);
        auto e = new Type[n];
        for(auto i=0; i<n; i++)
            e[i] = getTypeOf(dst[i]);
        return e;
    }
}

///
abstract class SequenceType : Type
{
    ///
    private Type elemty;
    ///
    private this(LLVMTypeRef t, Type elemty)
    {
        super(t);
        this.elemty = elemty;
    }
    ///
    Type elementType()
    {
        if (!elemty.type)
            elemty = getTypeOf(LLVMGetElementType(type));
        return elemty;
    }
}

///
class PointerType : SequenceType
{
    ///
    private const uint addrSpace;
    ///
    protected this(LLVMTypeRef t, Type e, uint as)
    {
        super(t, e);
        addrSpace = as;
    }
    ///
    static PointerType Get(Type e, uint as=0)
    {
        auto t = LLVMPointerType(e.ll, as);
        auto ptr = t in registry;
        if (ptr !is null)
            return cast(PointerType)*ptr;
        auto pt = new PointerType(t, e, as);
        return pt;
    }
    ///
    uint addressSpace()
    {
        return addrSpace;
    }
}

///
class ArrayType : SequenceType
{
    ///
    private const uint arrlen;
    ///
    protected this(LLVMTypeRef t, Type e, uint l)
    {
        super(t, e);
        arrlen = l;
    }
    ///
    static ArrayType Get(Type e, uint l)
    {
        auto t = LLVMArrayType(e.ll, l);
        auto ptr = t in registry;
        if (ptr !is null) return cast(ArrayType)*ptr;
        auto at = new ArrayType(t, e, l);
        return at;
    }
    ///
    uint length()
    {
        return arrlen;
    }
}

///
class VectorType : SequenceType
{
    ///
    private const uint vecsz;
    ///
    protected this(LLVMTypeRef t, Type e, uint s)
    {
        super(t, e);
        vecsz = s;
    }
    ///
    static VectorType Get(Type e, uint s)
    {
        auto t = LLVMVectorType(e.ll, s);
        auto ptr = t in registry;
        if (ptr !is null) return cast(VectorType)*ptr;
        auto at = new VectorType(t, e, s);
        return at;
    }
    ///
    uint vectorSize()
    {
        return vecsz;
    }
}

///
class OpaqueType : Type
{
    ///
    private this(LLVMTypeRef t)
    {
        super(t);
    }
    ///
    static OpaqueType Get()
    {
        auto t = LLVMOpaqueType();
        auto ot = new OpaqueType(t);
        return ot;
    }
    ///
    private static OpaqueType Get(LLVMTypeRef t)
    {
        auto ptr = t in registry;
        if (ptr !is null)
            return cast(OpaqueType)*ptr;
        auto ot = new OpaqueType(t);
        return ot;
    }
}

///
class TypeHandle
{
    ///
    private LLVMTypeHandleRef handle;
    ///
    this()
    {
        handle = LLVMCreateTypeHandle(LLVMOpaqueType());
    }
    ///
    Type resolve()
    {
        assert(handle !is null);
        auto t = LLVMResolveTypeHandle(handle);
        return getTypeOf(t);
    }
    ///
    void refine(Type to)
    {
        assert(handle !is null);
        auto t = LLVMResolveTypeHandle(handle);
        LLVMRefineType(t, to.ll);
    }
    ///
    void dispose()
    {
        assert(handle !is null);
        LLVMDisposeTypeHandle(handle);
        handle = null;
    }
    ///
    ~this()
    {
        if (handle)
        {
            // Safe because handle isn't on the GC heap and isn't exposed.
            dispose();
        }
    }
}

///
Type getTypeOf(LLVMValueRef v)
{
    return getTypeOf(LLVMTypeOf(v));
}

///
Type getTypeOf(LLVMTypeRef ty)
{
    // first check the registry
    auto ptr = ty in Type.registry;
    if (ptr !is null) return *ptr;

    // reconstruct D type from C type and query it
    auto kind = LLVMGetTypeKind(ty);
    switch(kind)
    {
    case Type.Kind.Integer:
        auto bw = LLVMGetIntTypeWidth(ty);
        return Type.IntType(bw);

    case Type.Kind.Pointer:
        auto e = LLVMGetElementType(ty);
        auto a = LLVMGetPointerAddressSpace(ty);
        return PointerType.Get(getTypeOf(e), a);

    case Type.Kind.Struct:
        auto t = new StructType(ty);
        return t;
        // was broken for recursive types ...
        /*auto n = LLVMCountStructElementTypes(ty);
        auto e = new LLVMTypeRef[n];
        LLVMGetStructElementTypes(ty, e.ptr);
        auto p = LLVMIsPackedStruct(ty);
        auto t = new Type[n];
        foreach(i,et; e) t[i] = getTypeOf(et);
        return StructType.Get(t,p!=0);*/

    case Type.Kind.Opaque:
        return OpaqueType.Get(ty);

    case Type.Kind.Function:
        auto llr = LLVMGetReturnType(ty);
        auto lla = new LLVMTypeRef[LLVMCountParamTypes(ty)];
        LLVMGetParamTypes(ty, lla.ptr);
        auto args = new Type[lla.length];
        foreach(i,a; lla) args[i] = getTypeOf(a);
        int isvararg = LLVMIsFunctionVarArg(ty);
        return FunctionType.Get(getTypeOf(llr), args, isvararg!=0);

    case Type.Kind.Array:
        auto lle = LLVMGetElementType(ty);
        auto len = LLVMGetArrayLength(ty);
        return ArrayType.Get(getTypeOf(lle), len);

    case Type.Kind.Vector:
        auto lle = LLVMGetElementType(ty);
        auto sz = LLVMGetVectorSize(ty);
        return VectorType.Get(getTypeOf(lle), sz);

    case Type.Kind.Void:
    case Type.Kind.Float:
    case Type.Kind.Double:
    case Type.Kind.X86_FP80:
    case Type.Kind.FP128:
    case Type.Kind.PPC_FP128:
    case Type.Kind.Label:
        assert(0, "basic type not in registry");
    }
}