Skip to content

Commit 05a318f

Browse files
committed
Support for empty constant arrays and structs.
1 parent bf750ef commit 05a318f

File tree

2 files changed

+41
-9
lines changed

2 files changed

+41
-9
lines changed

src/core/value/constant.jl

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,14 @@ export ConstantAggregateZero
102102
end
103103
identify(::Type{Value}, ::Val{API.LLVMConstantAggregateZeroValueKind}) = ConstantAggregateZero
104104

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
105+
# array interface
106+
# FIXME: can we reuse the ::ConstantArray functionality with ConstantAggregateZero values?
107+
# probably works fine if we just get rid of the refcheck
108+
Base.eltype(caz::ConstantAggregateZero) = eltype(llvmtype(caz))
109+
Base.size(caz::ConstantAggregateZero) = (0,)
110+
Base.length(caz::ConstantAggregateZero) = 0
111+
Base.axes(caz::ConstantAggregateZero) = (Base.OneTo(0),)
112+
Base.collect(caz::ConstantAggregateZero) = Value[]
107113

108114

109115
## regular aggregate
@@ -118,13 +124,15 @@ end
118124
identify(::Type{Value}, ::Val{API.LLVMConstantArrayValueKind}) = ConstantArray
119125
identify(::Type{Value}, ::Val{API.LLVMConstantDataArrayValueKind}) = ConstantArray
120126

127+
ConstantArrayOrAggregateZero(value) = Value(value)::Union{ConstantArray,ConstantAggregateZero}
128+
121129
# generic constructor taking an array of constants
122130
function ConstantArray(data::AbstractArray{<:Constant,N},
123131
typ::LLVMType=llvmtype(first(data))) where {N}
124132
@assert all(x->x==typ, llvmtype.(data))
125133

126134
if N == 1
127-
return ConstantArray(API.LLVMConstArray(typ, Array(data), length(data)))
135+
return ConstantArrayOrAggregateZero(API.LLVMConstArray(typ, Array(data), length(data)))
128136
end
129137

130138
if VERSION >= v"1.1"
@@ -156,7 +164,6 @@ function Base.collect(ca::ConstantArray)
156164
return constants
157165
end
158166

159-
160167
# array interface
161168
Base.eltype(ca::ConstantArray) = eltype(llvmtype(ca))
162169
function Base.size(ca::ConstantArray)
@@ -195,20 +202,24 @@ end
195202
end
196203
identify(::Type{Value}, ::Val{API.LLVMConstantStructValueKind}) = ConstantStruct
197204

205+
ConstantStructOrAggregateZero(value) = Value(value)::Union{ConstantStruct,ConstantAggregateZero}
206+
198207
# anonymous
199208
ConstantStruct(values::Vector{<:Constant}; packed::Core.Bool=false) =
200-
ConstantStruct(API.LLVMConstStruct(values, length(values), convert(Bool, packed)))
209+
ConstantStructOrAggregateZero(API.LLVMConstStruct(values, length(values), convert(Bool, packed)))
201210
ConstantStruct(values::Vector{<:Constant}, ctx::Context; packed::Core.Bool=false) =
202-
ConstantStruct(API.LLVMConstStructInContext(ctx, values, length(values), convert(Bool, packed)))
211+
ConstantStructOrAggregateZero(API.LLVMConstStructInContext(ctx, values, length(values), convert(Bool, packed)))
203212

204213
# named
205214
ConstantStruct(typ::StructType, values::Vector{<:Constant}) =
206-
ConstantStruct(API.LLVMConstNamedStruct(typ, values, length(values)))
215+
ConstantStructOrAggregateZero(API.LLVMConstNamedStruct(typ, values, length(values)))
207216

208217
# create a ConstantStruct from a Julia object
209218
function ConstantStruct(value::T, ctx::Context=GlobalContext(); name=String(nameof(T)),
210219
anonymous::Core.Bool=false, packed::Core.Bool=false) where {T}
211220
isbitstype(T) || throw(ArgumentError("Can only create a ConstantStruct from an isbits struct"))
221+
isprimitivetype(T) && throw(ArgumentError("Cannot create a ConstantStruct from a primitive value"))
222+
212223
constants = Vector{Constant}()
213224
for fieldname in fieldnames(T)
214225
field = getfield(value, fieldname)

test/core.jl

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ struct TestStruct
44
z::Float16
55
end
66

7+
struct TestSingleton
8+
end
9+
710
@testset "core" begin
811

912
@testset "context" begin
@@ -418,6 +421,14 @@ Context() do ctx
418421
@test ca[1] == ConstantFP(vec[1], ctx)
419422
@test collect(ca) == ConstantFP.(vec, Ref(ctx))
420423
end
424+
let
425+
# tests for ConstantAggregateZero, constructed indirectly.
426+
# should behave similarly to ConstantArray since it can get returned there.
427+
ca = ConstantArray(Int[], ctx)
428+
@test size(ca) == (0,)
429+
@test length(ca) == 0
430+
@test isempty(collect(ca))
431+
end
421432

422433
# multidimensional
423434
let
@@ -455,7 +466,7 @@ Context() do ctx
455466
end
456467
let
457468
test_struct = TestStruct(false, 52, -2.5)
458-
constant_struct = ConstantStruct(test_struct, ctx; anonymous=false)
469+
constant_struct = ConstantStruct(test_struct, ctx)
459470
constant_struct_type = llvmtype(constant_struct)
460471

461472
@test constant_struct_type isa LLVM.StructType
@@ -467,7 +478,17 @@ Context() do ctx
467478
]
468479
@test collect(operands(constant_struct)) == expected_operands
469480

470-
@test_throws ArgumentError ConstantStruct(test_struct, ctx; anonymous=false)
481+
@test_throws ArgumentError ConstantStruct(test_struct, ctx)
482+
end
483+
let
484+
test_struct = TestSingleton()
485+
constant_struct = ConstantStruct(test_struct, ctx)
486+
constant_struct_type = llvmtype(constant_struct)
487+
488+
@test isempty(operands(constant_struct))
489+
end
490+
let
491+
@test_throws ArgumentError ConstantStruct(1, ctx)
471492
end
472493

473494
end

0 commit comments

Comments
 (0)