Skip to content

Commit c3cf5a1

Browse files
authored
@ test_inlined macro for testing complete inlining of a call tree (#686)
1 parent ec7b6a8 commit c3cf5a1

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

test/initializers.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ SA_test_hcat(x,T) = SA{T}[1 x x]
1818
@test @inferred(SA_test_hcat(2.0)) === SMatrix{1,3,Float64}((1,2,2))
1919
@test @inferred(SA_test_hcat(2,Float32)) === SMatrix{1,3,Float32}((1,2,2))
2020

21+
# hvcat needs to be in a function for the row argument to constant propagate
2122
SA_test_hvcat(x) = SA[1 x x;
2223
x 2 x]
2324
SA_test_hvcat(x,T) = SA{T}[1 x x;
@@ -36,6 +37,11 @@ SA_test_hvcat(x,T) = SA{T}[1 x x;
3637
@test SA_F64[1, 2] === SVector{2,Float64}((1,2))
3738
@test SA_F32[1, 2] === SVector{2,Float32}((1,2))
3839

40+
@test_inlined SA[1,2]
41+
@test_inlined SA[1 2]
42+
@test_inlined SA[1;2]
43+
@test_inlined SA_test_hvcat(3)
44+
3945
# https://github.com/JuliaArrays/StaticArrays.jl/pull/685
4046
@test Union{}[] isa Vector{Union{}}
4147
@test Base.typed_vcat(Union{}) isa Vector{Union{}}

test/testutil.jl

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,57 @@ end
3636
function test_expand_error(ex)
3737
@test_throws LoadError macroexpand(@__MODULE__, ex)
3838
end
39+
40+
mutable struct ErrorCounterTestSet <: Test.AbstractTestSet
41+
passcount::Int
42+
errorcount::Int
43+
failcount::Int
44+
end
45+
ErrorCounterTestSet(args...; kws...) = ErrorCounterTestSet(0,0,0)
46+
Test.finish(ts::ErrorCounterTestSet) = ts
47+
Test.record(ts::ErrorCounterTestSet, ::Test.Pass) = (ts.passcount += 1)
48+
Test.record(ts::ErrorCounterTestSet, ::Test.Error) = (ts.errorcount += 1)
49+
Test.record(ts::ErrorCounterTestSet, ::Test.Fail) = (ts.failcount += 1)
50+
51+
"""
52+
@test_inlined f(x,y, ...)
53+
54+
Check that the (optimized) llvm code generated for the expression
55+
`f(x,y,...)` contains no `call` instructions.
56+
57+
Note that LLVM IR can contain `call` instructions to intrinsics which don't
58+
make it into the native code, so this can be overly eager in declaring a
59+
a lack of complete inlining.
60+
"""
61+
macro test_inlined(ex)
62+
ex_orig = ex
63+
ex = macroexpand(@__MODULE__, :(@code_llvm $ex))
64+
expr = quote
65+
code_str = sprint() do io
66+
code_llvm(io, $(map(esc, ex.args[2:end])...))
67+
end
68+
# Crude detection of call instructions remaining within what should be
69+
# fully inlined code.
70+
#
71+
# TODO: Figure out some better pattern matching; LLVM IR can contain
72+
# calls to intrinsics, so this will sometimes/often fail even when the
73+
# native code has no call instructions.
74+
@test !occursin("call", code_str)
75+
end
76+
@assert expr.args[4].head == :macrocall
77+
expr.args[4].args[2] = __source__
78+
expr
79+
end
80+
81+
should_be_inlined(x) = x*x
82+
@noinline _should_not_be_inlined(x) = x*x
83+
should_not_be_inlined(x) = _should_not_be_inlined(x)
84+
85+
@testset "@test_inlined" begin
86+
@test_inlined should_be_inlined(1)
87+
ts = @testset ErrorCounterTestSet "" begin
88+
@test_inlined should_not_be_inlined(1)
89+
end
90+
@test ts.errorcount == 0 && ts.failcount == 1 && ts.passcount == 0
91+
end
92+

0 commit comments

Comments
 (0)