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         }
43         catch (Exception e) {
44         }
45 
46         return r;
47     }
48 
49     bool isPrimitive() {
50         import std.algorithm : among;
51 
52         with (LxTypeKind) {
53             return kind.among(Void, Half, Float, Double, X86_FP80, FP128, PPC_FP128, Integer) != 0;
54         }
55     }
56 
57     bool isLabel() {
58         return kind == LxTypeKind.Label;
59     }
60 
61     bool isFunction() {
62         return kind == LxTypeKind.Function;
63     }
64 
65     bool isStruct() {
66         return kind == LxTypeKind.Struct;
67     }
68 
69     bool isArray() {
70         return kind == LxTypeKind.Array;
71     }
72 
73     bool isPointer() {
74         return kind == LxTypeKind.Pointer;
75     }
76 
77     bool isVector() {
78         return kind == LxTypeKind.Vector;
79     }
80 
81     bool isMetadata() {
82         return kind == LxTypeKind.Metadata;
83     }
84 
85     bool isToken() {
86         return kind == LxTypeKind.Token;
87     }
88 
89     bool isSequential() {
90         import std.algorithm : among;
91 
92         with (LxTypeKind) {
93             return kind.among(Array, Vector, Pointer) != 0;
94         }
95     }
96 
97     auto func() {
98         assert(isFunction);
99         import llvm_hiwrap.type.function_;
100 
101         return FunctionType(this);
102     }
103 
104     auto struct_() {
105         assert(isStruct);
106         import llvm_hiwrap.type.struct_;
107 
108         return StructType(this);
109     }
110 
111     // Note: exposing the specifics to make it easier to use correctly.
112     // Some function are only valid to use for array types.
113     LxArrayType array() {
114         return LxArrayType(asSequential);
115     }
116 
117     // Note: exposing the specifics to make it easier to use correctly.
118     // Some function are only valid to use for array types.
119     LxPointerType pointer() {
120         return LxPointerType(asSequential);
121     }
122 
123     // Note: exposing the specifics to make it easier to use correctly.
124     // Some function are only valid to use for array types.
125     LxVectorType vector() {
126         return LxVectorType(asSequential);
127     }
128 
129 private:
130     LxSequential asSequential() {
131         import llvm : LLVMGetElementType;
132 
133         assert(isSequential);
134         auto t = LLVMGetElementType(rawPtr);
135         return LxSequential(LxType(t));
136     }
137 }
138 
139 /**
140  * Sequential types represents "arrays" of types. This is a super class
141  * for array, vector, and pointer types.
142  *
143  * All elements in a sequential type have the same type.
144  */
145 struct LxSequentialImpl(LxTypeKind Kind) {
146     import llvm;
147 
148     LxType type;
149     alias type this;
150 
151     static if (Kind == LxTypeKind.Array) {
152         /** Obtain the length of an array type.
153          *
154          * This only works on types that represent arrays.
155          *
156          * TODO I am unsure if the LLVM documentation mean sequential or array
157          * when it states "only works for arrays".  Test what happens when the
158          * type is a pointer or vector.
159          */
160         @property size_t length() {
161             import std.traits : ReturnType;
162 
163             enum llvm_max_length = (ReturnType!LLVMGetArrayLength).max;
164             static assert(llvm_max_length <= size_t.max,
165                     "mismatch between LLVM API and the D length type");
166 
167             auto s = LLVMGetArrayLength(type);
168             return s;
169         }
170     } else static if (Kind == LxTypeKind.Pointer) {
171         /** Obtain the address space of a pointer type.
172          *
173          * This only works on types that represent pointers.
174          */
175         @property auto addressSpace() {
176             return LLVMGetPointerAddressSpace(type);
177         }
178     } else static if (Kind == LxTypeKind.Vector) {
179         /** Obtain the number of elements in a vector type.
180          *
181          * This only works on types that represent vectors.
182          */
183         @property size_t length() {
184             import std.traits : ReturnType;
185 
186             enum llvm_max_length = (ReturnType!LLVMGetVectorSize).max;
187             static assert(llvm_max_length <= size_t.max,
188                     "mismatch between LLVM API and the D length type");
189 
190             auto s = LLVMGetVectorSize(type);
191             return s;
192         }
193     }
194 }
195 
196 alias LxSequential = LxSequentialImpl!(LxTypeKind.Unknown);
197 alias LxArrayType = LxSequentialImpl!(LxTypeKind.Array);
198 alias LxPointerType = LxSequentialImpl!(LxTypeKind.Pointer);
199 alias LxVectorType = LxSequentialImpl!(LxTypeKind.Vector);