diff tools/binding/llvm/type.d @ 1273:1ba61de8796b

Committing LLVM binding for D as it currently exists in the SVN repository.
author Frits van Bommel <fvbommel wxs.nl>
date Mon, 27 Apr 2009 22:33:17 +0200
parents
children 4ff9ab0d472c
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/binding/llvm/type.d	Mon Apr 27 22:33:17 2009 +0200
@@ -0,0 +1,587 @@
+// 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());
+        
+        LLVMRefineAbstractType(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");
+    }
+}