@@ -46,12 +46,12 @@ const WideInteger = Union{Int64, UInt64}
46
46
ConstantInt (typ:: IntegerType , val:: WideInteger , signed= false ) =
47
47
ConstantInt (API. LLVMConstInt (typ, reinterpret (Culonglong, val),
48
48
convert (Bool, signed)))
49
- const SmallInteger = Union{Int8, Int16, Int32, UInt8, UInt16, UInt32}
49
+ const SmallInteger = Union{Core . Bool, Int8, Int16, Int32, UInt8, UInt16, UInt32}
50
50
ConstantInt (typ:: IntegerType , val:: SmallInteger , signed= false ) =
51
51
ConstantInt (typ, convert (Int64, val), signed)
52
52
53
53
function ConstantInt (typ:: IntegerType , val:: Integer , signed= false )
54
- valbits = ceil (Int, log2 (abs (val))) + 1
54
+ valbits = ceil (Int, log2 (abs (val))) + 1 # FIXME : doesn't work for val=0
55
55
numwords = ceil (Int, valbits / 64 )
56
56
words = Vector {Culonglong} (undef, numwords)
57
57
for i in 1 : numwords
@@ -67,12 +67,18 @@ function ConstantInt(val::T, ctx::Context) where T<:SizeableInteger
67
67
return ConstantInt (typ, val, T<: Signed )
68
68
end
69
69
70
+ # Booleans are encoded with a single bit, so we can't use sizeof
71
+ ConstantInt (val:: Core.Bool , ctx:: Context ) = ConstantInt (Int1Type (ctx), val ? 1 : 0 )
72
+
70
73
Base. convert (:: Type{T} , val:: ConstantInt ) where {T<: Unsigned } =
71
74
convert (T, API. LLVMConstIntGetZExtValue (val))
72
75
73
76
Base. convert (:: Type{T} , val:: ConstantInt ) where {T<: Signed } =
74
77
convert (T, API. LLVMConstIntGetSExtValue (val))
75
78
79
+ # Booleans aren't Signed or Unsigned
80
+ Base. convert (:: Type{Core.Bool} , val:: ConstantInt ) = convert (Int, val) != 0
81
+
76
82
77
83
@checked struct ConstantFP <: Constant
78
84
ref:: API.LLVMValueRef
@@ -93,7 +99,7 @@ Base.convert(::Type{T}, val::ConstantFP) where {T<:AbstractFloat} =
93
99
convert (T, API. LLVMConstRealGetDouble (val, Ref {API.LLVMBool} ()))
94
100
95
101
96
- # # aggregate
102
+ # # aggregate zero
97
103
98
104
export ConstantAggregateZero
99
105
@@ -102,53 +108,174 @@ export ConstantAggregateZero
102
108
end
103
109
identify (:: Type{Value} , :: Val{API.LLVMConstantAggregateZeroValueKind} ) = ConstantAggregateZero
104
110
105
- # there currently seems to be no function in the LLVM-C interface which returns a
106
- # ConstantAggregateZero value directly, but values can occur through calls to LLVMConstNull
107
-
111
+ # array interface
112
+ # FIXME : can we reuse the ::ConstantArray functionality with ConstantAggregateZero values?
113
+ # probably works fine if we just get rid of the refcheck
114
+ Base. eltype (caz:: ConstantAggregateZero ) = eltype (llvmtype (caz))
115
+ Base. size (caz:: ConstantAggregateZero ) = (0 ,)
116
+ Base. length (caz:: ConstantAggregateZero ) = 0
117
+ Base. axes (caz:: ConstantAggregateZero ) = (Base. OneTo (0 ),)
118
+ Base. collect (caz:: ConstantAggregateZero ) = Value[]
108
119
109
- # # constant expressions
110
120
111
- export ConstantExpr, ConstantAggregate, ConstantArray, ConstantStruct, ConstantVector, InlineAsm
112
-
113
- @checked struct ConstantExpr <: Constant
114
- ref:: API.LLVMValueRef
115
- end
116
- identify (:: Type{Value} , :: Val{API.LLVMConstantExprValueKind} ) = ConstantExpr
121
+ # # regular aggregate
117
122
118
123
abstract type ConstantAggregate <: Constant end
119
124
125
+ # arrays
126
+
120
127
@checked struct ConstantArray <: ConstantAggregate
121
128
ref:: API.LLVMValueRef
122
129
end
123
130
identify (:: Type{Value} , :: Val{API.LLVMConstantArrayValueKind} ) = ConstantArray
124
131
identify (:: Type{Value} , :: Val{API.LLVMConstantDataArrayValueKind} ) = ConstantArray
125
132
126
- ConstantArray (typ:: LLVMType , data:: Vector{T} ) where {T<: Constant } =
127
- ConstantArray (API. LLVMConstArray (typ, data, length (data)))
128
- ConstantArray (typ:: IntegerType , data:: Vector{T} ) where {T<: Integer } =
129
- ConstantArray (typ, map (x-> ConstantInt (convert (T,x),context (typ)), data))
130
- ConstantArray (typ:: FloatingPointType , data:: Vector{T} ) where {T<: AbstractFloat } =
131
- ConstantArray (typ, map (x-> ConstantFP (convert (T,x),context (typ)), data))
133
+ ConstantArrayOrAggregateZero (value) = Value (value):: Union{ConstantArray,ConstantAggregateZero}
132
134
133
- Base. getindex (ca:: ConstantArray , idx:: Integer ) =
134
- API. LLVMGetElementAsConstant (ca, idx- 1 )
135
- Base. length (ca:: ConstantArray ) = length (llvmtype (ca))
135
+ # generic constructor taking an array of constants
136
+ function ConstantArray (typ:: LLVMType , data:: AbstractArray{T,N} = T[]) where {T<: Constant ,N}
137
+ @assert all (x-> x== typ, llvmtype .(data))
138
+
139
+ if N == 1
140
+ return ConstantArrayOrAggregateZero (API. LLVMConstArray (typ, Array (data), length (data)))
141
+ end
142
+
143
+ if VERSION >= v " 1.1"
144
+ ca_vec = map (x-> ConstantArray (typ, x), eachslice (data, dims= 1 ))
145
+ else
146
+ ca_vec = map (x-> ConstantArray (typ, x), (view (data, i, ntuple (d-> (:), N- 1 )... ) for i in axes (data, 1 )))
147
+ end
148
+ ca_typ = llvmtype (first (ca_vec))
149
+
150
+ return ConstantArray (API. LLVMConstArray (ca_typ, ca_vec, length (ca_vec)))
151
+ end
152
+
153
+ # shorthands with arrays of plain Julia data
154
+ # FIXME : duplicates the ConstantInt/ConstantFP conversion rules
155
+ ConstantArray (data:: AbstractArray{T,N} , ctx:: Context = GlobalContext ()) where {T<: Integer ,N} =
156
+ ConstantArray (IntType (sizeof (T)* 8 , ctx), ConstantInt .(data, Ref (ctx)))
157
+ ConstantArray (data:: AbstractArray{Core.Bool,N} , ctx:: Context = GlobalContext ()) where {N} =
158
+ ConstantArray (Int1Type (ctx), ConstantInt .(data, Ref (ctx)))
159
+ ConstantArray (data:: AbstractArray{Float16,N} , ctx:: Context = GlobalContext ()) where {N} =
160
+ ConstantArray (HalfType (ctx), ConstantFP .(data, Ref (ctx)))
161
+ ConstantArray (data:: AbstractArray{Float32,N} , ctx:: Context = GlobalContext ()) where {N} =
162
+ ConstantArray (FloatType (ctx), ConstantFP .(data, Ref (ctx)))
163
+ ConstantArray (data:: AbstractArray{Float64,N} , ctx:: Context = GlobalContext ()) where {N} =
164
+ ConstantArray (DoubleType (ctx), ConstantFP .(data, Ref (ctx)))
165
+
166
+ # convert back to known array types
167
+ function Base. collect (ca:: ConstantArray )
168
+ constants = Array {Value} (undef, size (ca))
169
+ for I in CartesianIndices (size (ca))
170
+ @inbounds constants[I] = ca[Tuple (I)... ]
171
+ end
172
+ return constants
173
+ end
174
+
175
+ # array interface
136
176
Base. eltype (ca:: ConstantArray ) = eltype (llvmtype (ca))
137
- Base. convert (:: Type{Array{T,1}} , ca:: ConstantArray ) where {T<: Integer } =
138
- [convert (T,ConstantInt (ca[i])) for i in 1 : length (ca)]
139
- Base. convert (:: Type{Array{T,1}} , ca:: ConstantArray ) where {T<: AbstractFloat } =
140
- [convert (T,ConstantFP (ca[i])) for i in 1 : length (ca)]
177
+ function Base. size (ca:: ConstantArray )
178
+ dims = Int[]
179
+ typ = llvmtype (ca)
180
+ while typ isa ArrayType
181
+ push! (dims, length (typ))
182
+ typ = eltype (typ)
183
+ end
184
+ return Tuple (dims)
185
+ end
186
+ Base. length (ca:: ConstantArray ) = prod (size (ca))
187
+ Base. axes (ca:: ConstantArray ) = Base. OneTo .(size (ca))
188
+
189
+ function Base. getindex (ca:: ConstantArray , idx:: Integer... )
190
+ # multidimensional arrays are represented by arrays of arrays,
191
+ # which we need to 'peel back' by looking at the operand sets.
192
+ # for the final dimension, we use LLVMGetElementAsConstant
193
+ @boundscheck Base. checkbounds_indices (Base. Bool, axes (ca), idx) ||
194
+ throw (BoundsError (ca, idx))
195
+ I = CartesianIndices (size (ca))[idx... ]
196
+ for i in Tuple (I)
197
+ if isempty (operands (ca))
198
+ ca = LLVM. Value (API. LLVMGetElementAsConstant (ca, i- 1 ))
199
+ else
200
+ ca = (Base. @_propagate_inbounds_meta ; operands (ca)[i])
201
+ end
202
+ end
203
+ return ca
204
+ end
205
+
206
+ # structs
141
207
142
208
@checked struct ConstantStruct <: ConstantAggregate
143
209
ref:: API.LLVMValueRef
144
210
end
145
211
identify (:: Type{Value} , :: Val{API.LLVMConstantStructValueKind} ) = ConstantStruct
146
212
213
+ ConstantStructOrAggregateZero (value) = Value (value):: Union{ConstantStruct,ConstantAggregateZero}
214
+
215
+ # anonymous
216
+ ConstantStruct (values:: Vector{<:Constant} ; packed:: Core.Bool = false ) =
217
+ ConstantStructOrAggregateZero (API. LLVMConstStruct (values, length (values), convert (Bool, packed)))
218
+ ConstantStruct (values:: Vector{<:Constant} , ctx:: Context ; packed:: Core.Bool = false ) =
219
+ ConstantStructOrAggregateZero (API. LLVMConstStructInContext (ctx, values, length (values), convert (Bool, packed)))
220
+
221
+ # named
222
+ ConstantStruct (typ:: StructType , values:: Vector{<:Constant} ) =
223
+ ConstantStructOrAggregateZero (API. LLVMConstNamedStruct (typ, values, length (values)))
224
+
225
+ # create a ConstantStruct from a Julia object
226
+ function ConstantStruct (value:: T , ctx:: Context = GlobalContext (); name= String (nameof (T)),
227
+ anonymous:: Core.Bool = false , packed:: Core.Bool = false ) where {T}
228
+ isbitstype (T) || throw (ArgumentError (" Can only create a ConstantStruct from an isbits struct" ))
229
+ isprimitivetype (T) && throw (ArgumentError (" Cannot create a ConstantStruct from a primitive value" ))
230
+
231
+ constants = Vector {Constant} ()
232
+ for fieldname in fieldnames (T)
233
+ field = getfield (value, fieldname)
234
+
235
+ if isa (field, Integer)
236
+ push! (constants, ConstantInt (field, ctx))
237
+ elseif isa (field, AbstractFloat)
238
+ push! (constants, ConstantFP (field, ctx))
239
+ else # TODO : nested structs?
240
+ throw (ArgumentError (" only structs with boolean, integer and floating point fields are allowed" ))
241
+ end
242
+ end
243
+
244
+ if anonymous
245
+ ConstantStruct (constants, ctx; packed= packed)
246
+ elseif haskey (types (ctx), name)
247
+ typ = types (ctx)[name]
248
+ if collect (elements (typ)) != llvmtype .(constants)
249
+ throw (ArgumentError (" Cannot create struct $name {$(join (llvmtype .(constants), " , " )) } as it is already defined in this context as {$(join (elements (typ), " , " )) }." ))
250
+ end
251
+ ConstantStruct (typ, constants)
252
+ else
253
+ typ = StructType (name, ctx)
254
+ elements! (typ, llvmtype .(constants))
255
+ ConstantStruct (typ, constants)
256
+ end
257
+ end
258
+
259
+ # vectors
260
+
147
261
@checked struct ConstantVector <: ConstantAggregate
148
262
ref:: API.LLVMValueRef
149
263
end
150
264
identify (:: Type{Value} , :: Val{API.LLVMConstantVectorValueKind} ) = ConstantVector
151
265
266
+
267
+ # # constant expressions
268
+
269
+ export ConstantExpr, ConstantAggregate, ConstantArray, ConstantStruct, ConstantVector, InlineAsm
270
+
271
+ @checked struct ConstantExpr <: Constant
272
+ ref:: API.LLVMValueRef
273
+ end
274
+ identify (:: Type{Value} , :: Val{API.LLVMConstantExprValueKind} ) = ConstantExpr
275
+
276
+
277
+ # # inline assembly
278
+
152
279
@checked struct InlineAsm <: Constant
153
280
ref:: API.LLVMValueRef
154
281
end
0 commit comments