1 /**
2 Copyright: Copyright (c) 2017, Joakim Brännström. All rights reserved.
3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 
6 See: llvm-c/Core.h
7 
8  * Types have the following hierarchy:
9  *
10  *   types:
11  *     integer type
12  *     real type
13  *     function type
14  *     sequence types:
15  *       array type
16  *       pointer type
17  *       vector type
18  *     void type
19  *     label type
20  *     opaque type
21 */
22 module llvm_hiwrap.type.type;
23 
24 import llvm_hiwrap.types;
25 
26 struct Type {
27     import llvm : LLVMTypeRef, LLVMTypeKind, LLVMGetTypeKind;
28 
29     LxType type;
30     alias type this;
31 
32     /** Obtain the enumerated type of a Type instance.
33      *
34      * See: llvm-c/Core.h
35      */
36     LxTypeKind kind() nothrow {
37         auto r = LxTypeKind.Unknown;
38         try {
39             LLVMTypeKind tmp = LLVMGetTypeKind(rawPtr);
40             if (tmp >= LxTypeKind.min && tmp <= LxTypeKind.max)
41                 r = cast(LxTypeKind) tmp;
42         } catch (Exception e) {
43         }
44 
45         return r;
46     }
47 
48     bool isPrimitive() {
49         import std.algorithm : among;
50 
51         with (LxTypeKind) {
52             return kind.among(Void, Half, Float, Double, X86_FP80, FP128, PPC_FP128, Integer) != 0;
53         }
54     }
55 
56     bool isLabel() {
57         return kind == LxTypeKind.Label;
58     }
59 
60     bool isFunction() {
61         return kind == LxTypeKind.Function;
62     }
63 
64     bool isStruct() {
65         return kind == LxTypeKind.Struct;
66     }
67 
68     bool isArray() {
69         return kind == LxTypeKind.Array;
70     }
71 
72     bool isPointer() {
73         return kind == LxTypeKind.Pointer;
74     }
75 
76     bool isVector() {
77         return kind == LxTypeKind.Vector;
78     }
79 
80     bool isMetadata() {
81         return kind == LxTypeKind.Metadata;
82     }
83 
84     bool isToken() {
85         return kind == LxTypeKind.Token;
86     }
87 
88     bool isSequential() {
89         import std.algorithm : among;
90 
91         with (LxTypeKind) {
92             return kind.among(Array, Vector, Pointer) != 0;
93         }
94     }
95 
96     auto func() {
97         assert(isFunction);
98         import llvm_hiwrap.type.function_;
99 
100         return FunctionType(this);
101     }
102 
103     auto struct_() {
104         assert(isStruct);
105         import llvm_hiwrap.type.struct_;
106 
107         return StructType(this);
108     }
109 
110     // Note: exposing the specifics to make it easier to use correctly.
111     // Some function are only valid to use for array types.
112     LxArrayType array() {
113         return LxArrayType(asSequential);
114     }
115 
116     // Note: exposing the specifics to make it easier to use correctly.
117     // Some function are only valid to use for array types.
118     LxPointerType pointer() {
119         return LxPointerType(asSequential);
120     }
121 
122     // Note: exposing the specifics to make it easier to use correctly.
123     // Some function are only valid to use for array types.
124     LxVectorType vector() {
125         return LxVectorType(asSequential);
126     }
127 
128 private:
129     LxSequential asSequential() {
130         import llvm : LLVMGetElementType;
131 
132         assert(isSequential);
133         auto t = LLVMGetElementType(rawPtr);
134         return LxSequential(LxType(t));
135     }
136 }
137 
138 /**
139  * Sequential types represents "arrays" of types. This is a super class
140  * for array, vector, and pointer types.
141  *
142  * All elements in a sequential type have the same type.
143  */
144 struct LxSequentialImpl(LxTypeKind Kind) {
145     import llvm;
146 
147     LxType type;
148     alias type this;
149 
150     static if (Kind == LxTypeKind.Array) {
151         /** Obtain the length of an array type.
152          *
153          * This only works on types that represent arrays.
154          *
155          * TODO I am unsure if the LLVM documentation mean sequential or array
156          * when it states "only works for arrays".  Test what happens when the
157          * type is a pointer or vector.
158          */
159         @property size_t length() {
160             import std.traits : ReturnType;
161 
162             enum llvm_max_length = (ReturnType!LLVMGetArrayLength).max;
163             static assert(llvm_max_length <= size_t.max,
164                     "mismatch between LLVM API and the D length type");
165 
166             auto s = LLVMGetArrayLength(type);
167             return s;
168         }
169     } else static if (Kind == LxTypeKind.Pointer) {
170         /** Obtain the address space of a pointer type.
171          *
172          * This only works on types that represent pointers.
173          */
174         @property auto addressSpace() {
175             return LLVMGetPointerAddressSpace(type);
176         }
177     } else static if (Kind == LxTypeKind.Vector) {
178         /** Obtain the number of elements in a vector type.
179          *
180          * This only works on types that represent vectors.
181          */
182         @property size_t length() {
183             import std.traits : ReturnType;
184 
185             enum llvm_max_length = (ReturnType!LLVMGetVectorSize).max;
186             static assert(llvm_max_length <= size_t.max,
187                     "mismatch between LLVM API and the D length type");
188 
189             auto s = LLVMGetVectorSize(type);
190             return s;
191         }
192     }
193 }
194 
195 alias LxSequential = LxSequentialImpl!(LxTypeKind.Unknown);
196 alias LxArrayType = LxSequentialImpl!(LxTypeKind.Array);
197 alias LxPointerType = LxSequentialImpl!(LxTypeKind.Pointer);
198 alias LxVectorType = LxSequentialImpl!(LxTypeKind.Vector);