Skip to content

Commit 2c5db93

Browse files
authored
Merge pull request #260 from maleadt/tb/optimize
Optimizations
2 parents b4dfdfc + d7823fa commit 2c5db93

File tree

11 files changed

+139
-78
lines changed

11 files changed

+139
-78
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ jobs:
6565
julia --project=deps -e 'using Pkg; Pkg.instantiate()'
6666
julia --project=deps deps/build_local.jl
6767
# test
68-
- uses: julia-actions/julia-runtest@v1
68+
- name: Run tests
69+
run: |
70+
julia --project -e 'using Pkg; Pkg.test(; julia_args=`-g2`)'
6971
# process results
7072
- uses: julia-actions/julia-processcoverage@v1
7173
- uses: codecov/codecov-action@v1

src/core/basicblock.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export BasicBlock, unsafe_delete!,
55
@checked struct BasicBlock <: Value
66
ref::API.LLVMValueRef
77
end
8-
identify(::Type{Value}, ::Val{API.LLVMBasicBlockValueKind}) = BasicBlock
8+
register(BasicBlock, API.LLVMBasicBlockValueKind)
99

1010
BasicBlock(ref::API.LLVMBasicBlockRef) = BasicBlock(API.LLVMBasicBlockAsValue(ref))
1111
Base.unsafe_convert(::Type{API.LLVMBasicBlockRef}, bb::BasicBlock) = API.LLVMValueAsBasicBlock(bb)

src/core/function.jl

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export unsafe_delete!,
55
entry
66

77
# forward declaration of Function in src/core/basicblock.jl
8-
identify(::Type{Value}, ::Val{API.LLVMFunctionValueKind}) = Function
8+
register(Function, API.LLVMFunctionValueKind)
99

1010
Function(mod::Module, name::String, ft::FunctionType) =
1111
Function(API.LLVMAddFunction(mod, name, ft))
@@ -81,7 +81,7 @@ export Argument, parameters
8181
@checked struct Argument <: Value
8282
ref::API.LLVMValueRef
8383
end
84-
identify(::Type{Value}, ::Val{API.LLVMArgumentValueKind}) = Argument
84+
register(Argument, API.LLVMArgumentValueKind)
8585

8686
struct FunctionParameterSet <: AbstractVector{Argument}
8787
f::Function
@@ -115,24 +115,39 @@ end
115115

116116
export blocks
117117

118-
struct FunctionBlockSet
118+
struct FunctionBlockSet <: AbstractVector{BasicBlock}
119119
f::Function
120+
cache::Vector{API.LLVMValueRef}
121+
122+
FunctionBlockSet(f::Function) = new(f, BasicBlock[])
120123
end
121124

122125
blocks(f::Function) = FunctionBlockSet(f)
123126

124-
Base.eltype(::FunctionBlockSet) = BasicBlock
125-
126-
function Base.iterate(iter::FunctionBlockSet, state=API.LLVMGetFirstBasicBlock(iter.f))
127-
state == C_NULL ? nothing : (BasicBlock(state), API.LLVMGetNextBasicBlock(state))
128-
end
127+
Base.size(iter::FunctionBlockSet) = (Int(API.LLVMCountBasicBlocks(iter.f)),)
129128

130129
Base.first(iter::FunctionBlockSet) = BasicBlock(API.LLVMGetFirstBasicBlock(iter.f))
131130
Base.last(iter::FunctionBlockSet) = BasicBlock(API.LLVMGetLastBasicBlock(iter.f))
132131

133-
Base.isempty(iter::FunctionBlockSet) = length(iter) == 0
132+
function Base.iterate(iter::FunctionBlockSet, state=API.LLVMGetFirstBasicBlock(iter.f))
133+
state == C_NULL ? nothing : (BasicBlock(state), API.LLVMGetNextBasicBlock(state))
134+
end
134135

135-
Base.length(iter::FunctionBlockSet) = API.LLVMCountBasicBlocks(iter.f)
136+
# provide a random access interface by maintaining a cache of blocks
137+
function Base.getindex(iter::FunctionBlockSet, i::Int)
138+
i <= 0 && throw(BoundsError(iter, i))
139+
i == 1 && return first(iter)
140+
while i > length(iter.cache)
141+
next = if isempty(iter.cache)
142+
iterate(iter)
143+
else
144+
iterate(iter, iter.cache[end])
145+
end
146+
next === nothing && throw(BoundsError(iter, i))
147+
push!(iter.cache, next[2])
148+
end
149+
return BasicBlock(iter.cache[i-1])
150+
end
136151

137152
# NOTE: optimized `collect`
138153
function Base.collect(iter::FunctionBlockSet)

src/core/instructions.jl

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,26 @@ export Instruction, unsafe_delete!,
44
predicate_int, predicate_real
55

66
# forward definition of Instruction in src/core/value/constant.jl
7-
identify(::Type{Value}, ::Val{API.LLVMInstructionValueKind}) = Instruction
8-
9-
identify(::Type{Instruction}, ref::API.LLVMValueRef) =
10-
identify(Instruction, Val{API.LLVMGetInstructionOpcode(ref)}())
11-
identify(::Type{Instruction}, ::Val{K}) where {K} = error("Unknown instruction kind $K")
7+
register(Instruction, API.LLVMInstructionValueKind)
8+
9+
const instruction_opcodes = Vector{Type}(fill(Nothing, typemax(API.LLVMOpcode)+1))
10+
function identify(::Type{Instruction}, ref::API.LLVMValueRef)
11+
opcode = API.LLVMGetInstructionOpcode(ref)
12+
typ = @inbounds instruction_opcodes[opcode+1]
13+
typ === Nothing && error("Unknown type opcode $opcode")
14+
return typ
15+
end
16+
function register(T::Type{<:Instruction}, opcode::API.LLVMOpcode)
17+
instruction_opcodes[opcode+1] = T
18+
end
1219

13-
@inline function refcheck(::Type{T}, ref::API.LLVMValueRef) where T<:Instruction
20+
function refcheck(::Type{T}, ref::API.LLVMValueRef) where T<:Instruction
1421
ref==C_NULL && throw(UndefRefError())
15-
T′ = identify(Instruction, ref)
16-
if T != T′
17-
error("invalid conversion of $T′ instruction reference to $T")
22+
if Base.JLOptions().debug_level >= 2
23+
T′ = identify(Instruction, ref)
24+
if T != T′
25+
error("invalid conversion of $T′ instruction reference to $T")
26+
end
1827
end
1928
end
2029

@@ -115,7 +124,7 @@ for op in opcodes
115124
@checked struct $typename <: Instruction
116125
ref::API.LLVMValueRef
117126
end
118-
identify(::Type{Instruction}, ::Val{API.$enum}) = $typename
127+
register($typename, API.$enum)
119128
end
120129
end
121130

src/core/metadata.jl

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,24 @@ abstract type Metadata end
55

66
Base.unsafe_convert(::Type{API.LLVMMetadataRef}, md::Metadata) = md.ref
77

8-
identify(::Type{Metadata}, ref::API.LLVMMetadataRef) =
9-
identify(Metadata, Val{API.LLVMGetMetadataKind(ref)}())
10-
identify(::Type{Metadata}, ::Val{K}) where {K} = error("Unknown metadata kind $K")
8+
const metadata_kinds = Vector{Type}(fill(Nothing, typemax(API.LLVMMetadataKind)+1))
9+
function identify(::Type{Metadata}, ref::API.LLVMMetadataRef)
10+
kind = API.LLVMGetMetadataKind(ref)
11+
typ = @inbounds metadata_kinds[kind+1]
12+
typ === Nothing && error("Unknown metadata kind $kind")
13+
return typ
14+
end
15+
function register(T::Type{<:Metadata}, kind::API.LLVMMetadataKind)
16+
metadata_kinds[kind+1] = T
17+
end
1118

12-
@inline function refcheck(::Type{T}, ref::API.LLVMMetadataRef) where T<:Metadata
19+
function refcheck(::Type{T}, ref::API.LLVMMetadataRef) where T<:Metadata
1320
ref==C_NULL && throw(UndefRefError())
14-
T′ = identify(Metadata, ref)
15-
if T != T′
16-
error("invalid conversion of $T′ metadata reference to $T")
21+
if Base.JLOptions().debug_level >= 2
22+
T′ = identify(Metadata, ref)
23+
if T != T′
24+
error("invalid conversion of $T′ metadata reference to $T")
25+
end
1726
end
1827
end
1928

@@ -37,7 +46,7 @@ end
3746
@checked struct MetadataAsValue <: Value
3847
ref::API.LLVMValueRef
3948
end
40-
identify(::Type{Value}, ::Val{API.LLVMMetadataAsValueValueKind}) = MetadataAsValue
49+
register(MetadataAsValue, API.LLVMMetadataAsValueValueKind)
4150

4251
Value(md::Metadata; ctx::Context) = MetadataAsValue(API.LLVMMetadataAsValue(ctx, md))
4352

@@ -52,12 +61,12 @@ abstract type ValueAsMetadata <: Metadata end
5261
@checked struct ConstantAsMetadata <: ValueAsMetadata
5362
ref::API.LLVMMetadataRef
5463
end
55-
identify(::Type{Metadata}, ::Val{API.LLVMConstantAsMetadataMetadataKind}) = ConstantAsMetadata
64+
register(ConstantAsMetadata, API.LLVMConstantAsMetadataMetadataKind)
5665

5766
@checked struct LocalAsMetadata <: ValueAsMetadata
5867
ref::API.LLVMMetadataRef
5968
end
60-
identify(::Type{Metadata}, ::Val{API.LLVMLocalAsMetadataMetadataKind}) = LocalAsMetadata
69+
register(LocalAsMetadata, API.LLVMLocalAsMetadataMetadataKind)
6170

6271
# NOTE: this can be used to both pack e.g. constants as metadata, and to extract the
6372
# metadata from an MetadataAsValue, so we don't type-assert narrowly here
@@ -73,7 +82,7 @@ export MDString
7382
@checked struct MDString <: Metadata
7483
ref::API.LLVMMetadataRef
7584
end
76-
identify(::Type{Metadata}, ::Val{API.LLVMMDStringMetadataKind}) = MDString
85+
register(MDString, API.LLVMMDStringMetadataKind)
7786

7887
MDString(val::String; ctx::Context) =
7988
MDString(API.LLVMMDStringInContext2(ctx, val, length(val)))
@@ -106,7 +115,7 @@ export MDTuple
106115
@checked struct MDTuple <: MDNode
107116
ref::API.LLVMMetadataRef
108117
end
109-
identify(::Type{Metadata}, ::Val{API.LLVMMDTupleMetadataKind}) = MDTuple
118+
register(MDTuple, API.LLVMMDTupleMetadataKind)
110119

111120
# MDTuples are commonly referred to as MDNodes, so keep that name
112121
MDNode(mds::Vector{<:Metadata}; ctx::Context) =

src/core/type.jl

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,24 @@ Base.eltype(typ::LLVMType) = Any
77

88
Base.unsafe_convert(::Type{API.LLVMTypeRef}, typ::LLVMType) = typ.ref
99

10-
identify(::Type{LLVMType}, ref::API.LLVMTypeRef) =
11-
identify(LLVMType, Val{API.LLVMGetTypeKind(ref)}())
12-
identify(::Type{LLVMType}, ::Val{K}) where {K} = error("Unknown type kind $K")
10+
const type_kinds = Vector{Type}(fill(Nothing, typemax(API.LLVMTypeKind)+1))
11+
function identify(::Type{LLVMType}, ref::API.LLVMTypeRef)
12+
kind = API.LLVMGetTypeKind(ref)
13+
typ = @inbounds type_kinds[kind+1]
14+
typ === Nothing && error("Unknown type kind $kind")
15+
return typ
16+
end
17+
function register(T::Type{<:LLVMType}, kind::API.LLVMTypeKind)
18+
type_kinds[kind+1] = T
19+
end
1320

14-
@inline function refcheck(::Type{T}, ref::API.LLVMTypeRef) where T<:LLVMType
21+
function refcheck(::Type{T}, ref::API.LLVMTypeRef) where T<:LLVMType
1522
ref==C_NULL && throw(UndefRefError())
16-
T′ = identify(LLVMType, ref)
17-
if T != T′
18-
error("invalid conversion of $T′ type reference to $T")
23+
if Base.JLOptions().debug_level >= 2
24+
T′ = identify(LLVMType, ref)
25+
if T != T′
26+
error("invalid conversion of $T′ type reference to $T")
27+
end
1928
end
2029
end
2130

@@ -45,7 +54,7 @@ export width
4554
@checked struct IntegerType <: LLVMType
4655
ref::API.LLVMTypeRef
4756
end
48-
identify(::Type{LLVMType}, ::Val{API.LLVMIntegerTypeKind}) = IntegerType
57+
register(IntegerType, API.LLVMIntegerTypeKind)
4958

5059
for T in [:Int1, :Int8, :Int16, :Int32, :Int64, :Int128]
5160
jl_fname = Symbol(T, :Type)
@@ -79,7 +88,7 @@ for T in [:Half, :Float, :Double]
7988
@checked struct $api_typename <: FloatingPointType
8089
ref::API.LLVMTypeRef
8190
end
82-
identify(::Type{LLVMType}, ::Val{API.$enumkind}) = $api_typename
91+
register($api_typename, API.$enumkind)
8392

8493
$jl_fname(ctx::Context) =
8594
$api_typename(API.$(Symbol(api_fname, :InContext))(ctx))
@@ -94,7 +103,7 @@ export isvararg, return_type, parameters
94103
@checked struct FunctionType <: LLVMType
95104
ref::API.LLVMTypeRef
96105
end
97-
identify(::Type{LLVMType}, ::Val{API.LLVMFunctionTypeKind}) = FunctionType
106+
register(FunctionType, API.LLVMFunctionTypeKind)
98107

99108
FunctionType(rettyp::LLVMType, params::Vector{<:LLVMType}=LLVMType[];
100109
vararg::Core.Bool=false) =
@@ -133,7 +142,7 @@ Base.eltype(typ::SequentialType) = LLVMType(API.LLVMGetElementType(typ))
133142
@checked struct PointerType <: SequentialType
134143
ref::API.LLVMTypeRef
135144
end
136-
identify(::Type{LLVMType}, ::Val{API.LLVMPointerTypeKind}) = PointerType
145+
register(PointerType, API.LLVMPointerTypeKind)
137146

138147
function PointerType(eltyp::LLVMType, addrspace=0)
139148
return PointerType(API.LLVMPointerType(eltyp, addrspace))
@@ -146,7 +155,7 @@ addrspace(ptrtyp::PointerType) =
146155
@checked struct ArrayType <: SequentialType
147156
ref::API.LLVMTypeRef
148157
end
149-
identify(::Type{LLVMType}, ::Val{API.LLVMArrayTypeKind}) = ArrayType
158+
register(ArrayType, API.LLVMArrayTypeKind)
150159

151160
function ArrayType(eltyp::LLVMType, count)
152161
return ArrayType(API.LLVMArrayType(eltyp, count))
@@ -160,7 +169,7 @@ Base.isempty(@nospecialize(T::ArrayType)) = length(T) == 0 || isempty(eltype(T))
160169
@checked struct VectorType <: SequentialType
161170
ref::API.LLVMTypeRef
162171
end
163-
identify(::Type{LLVMType}, ::Val{API.LLVMVectorTypeKind}) = VectorType
172+
register(VectorType, API.LLVMVectorTypeKind)
164173

165174
function VectorType(eltyp::LLVMType, count)
166175
return VectorType(API.LLVMVectorType(eltyp, count))
@@ -176,7 +185,7 @@ export name, ispacked, isopaque, elements!
176185
@checked struct StructType <: SequentialType
177186
ref::API.LLVMTypeRef
178187
end
179-
identify(::Type{LLVMType}, ::Val{API.LLVMStructTypeKind}) = StructType
188+
register(StructType, API.LLVMStructTypeKind)
180189

181190
function StructType(name::String; ctx::Context)
182191
return StructType(API.LLVMStructCreateNamed(ctx, name))
@@ -237,28 +246,28 @@ end
237246
@checked struct VoidType <: LLVMType
238247
ref::API.LLVMTypeRef
239248
end
240-
identify(::Type{LLVMType}, ::Val{API.LLVMVoidTypeKind}) = VoidType
249+
register(VoidType, API.LLVMVoidTypeKind)
241250

242251
VoidType(ctx::Context) = VoidType(API.LLVMVoidTypeInContext(ctx))
243252

244253
@checked struct LabelType <: LLVMType
245254
ref::API.LLVMTypeRef
246255
end
247-
identify(::Type{LLVMType}, ::Val{API.LLVMLabelTypeKind}) = LabelType
256+
register(LabelType, API.LLVMLabelTypeKind)
248257

249258
LabelType(ctx::Context) = LabelType(API.LLVMLabelTypeInContext(ctx))
250259

251260
@checked struct MetadataType <: LLVMType
252261
ref::API.LLVMTypeRef
253262
end
254-
identify(::Type{LLVMType}, ::Val{API.LLVMMetadataTypeKind}) = MetadataType
263+
register(MetadataType, API.LLVMMetadataTypeKind)
255264

256265
MetadataType(ctx::Context) = MetadataType(API.LLVMMetadataTypeInContext(ctx))
257266

258267
@checked struct TokenType <: LLVMType
259268
ref::API.LLVMTypeRef
260269
end
261-
identify(::Type{LLVMType}, ::Val{API.LLVMTokenTypeKind}) = TokenType
270+
register(TokenType, API.LLVMTokenTypeKind)
262271

263272
TokenType(ctx::Context) = TokenType(API.LLVMTokenTypeInContext(ctx))
264273

src/core/value.jl

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,24 @@ abstract type Value end
88

99
Base.unsafe_convert(::Type{API.LLVMValueRef}, val::Value) = val.ref
1010

11-
identify(::Type{Value}, ref::API.LLVMValueRef) =
12-
identify(Value, Val{API.LLVMGetValueKind(ref)}())
13-
identify(::Type{Value}, ::Val{K}) where {K} = error("Unknown value kind $K")
11+
const value_kinds = Vector{Type}(fill(Nothing, typemax(API.LLVMValueKind)+1))
12+
function identify(::Type{Value}, ref::API.LLVMValueRef)
13+
kind = API.LLVMGetValueKind(ref)
14+
typ = @inbounds value_kinds[kind+1]
15+
typ === Nothing && error("Unknown value kind $kind")
16+
return typ
17+
end
18+
function register(T::Type{<:Value}, kind::API.LLVMValueKind)
19+
value_kinds[kind+1] = T
20+
end
1421

15-
@inline function refcheck(::Type{T}, ref::API.LLVMValueRef) where T<:Value
22+
function refcheck(::Type{T}, ref::API.LLVMValueRef) where T<:Value
1623
ref==C_NULL && throw(UndefRefError())
17-
T′ = identify(Value, ref)
18-
if T != T′
19-
error("invalid conversion of $T′ value reference to $T")
24+
if Base.JLOptions().debug_level >= 2
25+
T′ = identify(Value, ref)
26+
if T != T′
27+
error("invalid conversion of $T′ value reference to $T")
28+
end
2029
end
2130
end
2231

0 commit comments

Comments
 (0)