Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 37 additions & 9 deletions .github/workflows/Test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,34 +19,62 @@ jobs:
fail-fast: false
matrix:
version: ['1.10', '1.11', '1.12-nightly', 'nightly']
os: [ubuntu-latest, macOS-latest, windows-latest]
arch: [x64]
os: [ubuntu-24.04, ubuntu-24.04-arm, macOS-15, macOS-15-intel, windows-2025]
arch: [x64, arm64]
llvm_args: ['']
exclude:
# unsupported combinations
- os: ubuntu-24.04
arch: arm64
- os: windows-2025
arch: arm64
- os: ubuntu-24.04-arm
arch: x64
- os: macOS-15
arch: x64
- os: macOS-15-intel
arch: arm64
include:
# starting with Julia 1.10, we can enable opaque pointers
# from Julia 1.12 on, this is the default.
- version: '1.10'
os: 'ubuntu-latest'
os: 'ubuntu-24.04'
arch: 'x64'
llvm_args: '--opaque-pointers'
- version: '1.10'
os: 'macOS-latest'
os: 'ubuntu-24.04-arm'
arch: 'arm64'
llvm_args: '--opaque-pointers'
- version: '1.10'
os: 'macOS-15'
arch: 'arm64'
llvm_args: '--opaque-pointers'
- version: '1.10'
os: 'macOS-15-intel'
arch: 'x64'
llvm_args: '--opaque-pointers'
- version: '1.10'
os: 'windows-latest'
os: 'windows-2025'
arch: 'x64'
llvm_args: '--opaque-pointers'
- version: '1.11'
os: 'ubuntu-latest'
os: 'ubuntu-24.04'
arch: 'x64'
llvm_args: '--opaque-pointers'
- version: '1.11'
os: 'macOS-latest'
os: 'ubuntu-24.04-arm'
arch: 'arm64'
llvm_args: '--opaque-pointers'
- version: '1.11'
os: 'macOS-15'
arch: 'arm64'
llvm_args: '--opaque-pointers'
- version: '1.11'
os: 'macOS-15-intel'
arch: 'x64'
llvm_args: '--opaque-pointers'
- version: '1.11'
os: 'windows-latest'
os: 'windows-2025'
arch: 'x64'
llvm_args: '--opaque-pointers'
steps:
Expand Down Expand Up @@ -85,7 +113,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
os: [ubuntu-24.04]
arch: [x64]
llvm_args: ['', '--opaque-pointers']
include:
Expand Down
36 changes: 27 additions & 9 deletions src/jlgen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -321,10 +321,10 @@ CC.isoverlayed(::StackedMethodTable) = true
# no need to fall back to the parent method view
return result
end

parent_result = CC.findall(sig, table.parent; limit)::Union{Nothing, CC.MethodLookupResult}
parent_result === nothing && return nothing #too many matches

# merge the parent match results with the internal method table
return CC.MethodLookupResult(
CC.vcat(result.matches, parent_result.matches),
Expand Down Expand Up @@ -354,13 +354,13 @@ else
# no need to fall back to the parent method view
return CC.MethodMatchResult(result, true)
end

parent_result = CC.findall(sig, table.parent; limit)::Union{Nothing, CC.MethodMatchResult}
parent_result === nothing && return nothing #too many matches

overlayed = parent_result.overlayed | !CC.isempty(result)
parent_result = parent_result.matches::CC.MethodLookupResult

# merge the parent match results with the internal method table
return CC.MethodMatchResult(
CC.MethodLookupResult(
Expand Down Expand Up @@ -589,7 +589,11 @@ function ci_cache_populate(interp, cache, mi, min_world, max_world)
# now make sure everything has source code, if desired
mi = CC.get_ci_mi(callee)
if CC.use_const_api(callee)
src = CC.codeinfo_for_const(interp, mi, ci.rettype_const)
if VERSION >= v"1.13.0-DEV.1121"
src = CC.codeinfo_for_const(interp, mi, CC.WorldRange(callee.min_world, callee.max_world), callee.edges, callee.rettype_const)
else
src = CC.codeinfo_for_const(interp, mi, callee.rettype_const)
end
else
# TODO: typeinf_code could return something with different edges/ages/owner/abi (needing an update to callee), which we don't handle here
src = CC.typeinf_code(interp, mi, true)
Expand Down Expand Up @@ -801,11 +805,25 @@ function compile_method_instance(@nospecialize(job::CompilerJob))
end
end

if VERSION >= v"1.12.0-DEV.1703"
# on sufficiently recent versions of Julia, we can query the MIs compiled.
# this is required after the move to `invokce(::CodeInstance)`, because our
if VERSION >= v"1.13.0-DEV.1120"
# on sufficiently recent versions of Julia, we can query the CIs compiled.
# this is required after the move to `invoke(::CodeInstance)`, because our
# lookup function (used to populate method_instances) isn't always called then.

num_cis = Ref{Csize_t}(0)
@ccall jl_get_llvm_cis(native_code::Ptr{Cvoid}, num_cis::Ptr{Csize_t},
C_NULL::Ptr{Cvoid})::Nothing
resize!(method_instances, num_cis[])
@ccall jl_get_llvm_cis(native_code::Ptr{Cvoid}, num_cis::Ptr{Csize_t},
method_instances::Ptr{Cvoid})::Nothing

for (i, ci) in enumerate(method_instances)
method_instances[i] = ci.def::MethodInstance
end

elseif VERSION >= v"1.12.0-DEV.1703"
# slightly older versions of Julia used MIs directly

num_mis = Ref{Csize_t}(0)
@ccall jl_get_llvm_mis(native_code::Ptr{Cvoid}, num_mis::Ptr{Csize_t},
C_NULL::Ptr{Cvoid})::Nothing
Expand Down
15 changes: 9 additions & 6 deletions test/native.jl
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,10 @@ end
end

@testset "always_inline" begin
# XXX: broken by JuliaLang/julia#51599, see JuliaGPU/GPUCompiler.jl#527
# XXX: broken by JuliaLang/julia#51599, see JuliaGPU/GPUCompiler.jl#527.
# yet somehow this works on 1.12?
broken = VERSION >= v"1.13-"

mod = @eval module $(gensym())
import ..sink
expensive(x) = $(foldl((e, _) -> :($sink($e) + $sink(x)), 1:100; init=:x))
Expand All @@ -359,20 +362,20 @@ end
Native.code_llvm(mod.g, Tuple{Int64}; dump_module=true, kernel=true)
end

@test @filecheck begin
@test @filecheck(begin
check"CHECK-NOT: @{{(julia|j)_expensive_[0-9]+}}"
Native.code_llvm(mod.g, Tuple{Int64}; dump_module=true, kernel=true, always_inline=true)
end
end) broken=broken

@test @filecheck begin
check"CHECK: @{{(julia|j)_expensive_[0-9]+}}"
Native.code_llvm(mod.h, Tuple{Int64}; dump_module=true, kernel=true)
end

@test @filecheck begin
@test @filecheck(begin
check"CHECK-NOT: @{{(julia|j)_expensive_[0-9]+}}"
Native.code_llvm(mod.h, Tuple{Int64}; dump_module=true, kernel=true, always_inline=true)
end
end) broken=broken
end

@testset "function attributes" begin
Expand Down Expand Up @@ -659,7 +662,7 @@ end
a[1] = a[1]^2
return
end

function dkernel(a)
ptr = Enzyme.deferred_codegen(typeof(kernel), Tuple{Vector{Float64}})
ccall(ptr, Cvoid, (Vector{Float64},), a)
Expand Down
126 changes: 69 additions & 57 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -330,73 +330,85 @@ println("Testing finished in $elapsed")

# construct a testset to render the test results
o_ts = Test.DefaultTestSet("Overall")
Test.push_testset(o_ts)
completed_tests = Set{String}()
for (testname, (resp,)) in results
push!(completed_tests, testname)
if isa(resp, Test.DefaultTestSet)
Test.push_testset(resp)
Test.record(o_ts, resp)
Test.pop_testset()
elseif isa(resp, Tuple{Int,Int})
fake = Test.DefaultTestSet(testname)
for i in 1:resp[1]
Test.record(fake, Test.Pass(:test, nothing, nothing, nothing, nothing))
end
for i in 1:resp[2]
Test.record(fake, Test.Broken(:test, nothing))
end
Test.push_testset(fake)
Test.record(o_ts, fake)
Test.pop_testset()
elseif isa(resp, RemoteException) && isa(resp.captured.ex, Test.TestSetException)
println("Worker $(resp.pid) failed running test $(testname):")
Base.showerror(stdout, resp.captured)
println()
fake = Test.DefaultTestSet(testname)
for i in 1:resp.captured.ex.pass
Test.record(fake, Test.Pass(:test, nothing, nothing, nothing, nothing))
end
for i in 1:resp.captured.ex.broken
Test.record(fake, Test.Broken(:test, nothing))
end
for t in resp.captured.ex.errors_and_fails
Test.record(fake, t)
end
Test.push_testset(fake)
Test.record(o_ts, fake)
Test.pop_testset()
function with_testset(f, testset)
@static if VERSION >= v"1.13.0-DEV.1044"
Test.@with_testset testset f()
else
if !isa(resp, Exception)
resp = ErrorException(string("Unknown result type : ", typeof(resp)))
Test.push_testset(testset)
try
f()
finally
Test.pop_testset()
end
# If this test raised an exception that is not a remote testset exception,
# i.e. not a RemoteException capturing a TestSetException that means
# the test runner itself had some problem, so we may have hit a segfault,
# deserialization errors or something similar. Record this testset as Errored.
fake = Test.DefaultTestSet(testname)
Test.record(fake, Test.Error(:nontest_error, testname, nothing, Any[(resp, [])], LineNumberNode(1)))
Test.push_testset(fake)
Test.record(o_ts, fake)
Test.pop_testset()
end
end
for test in tests
(test in completed_tests) && continue
fake = Test.DefaultTestSet(test)
Test.record(fake, Test.Error(:test_interrupted, test, nothing,
[("skipped", [])], LineNumberNode(1)))
Test.push_testset(fake)
Test.record(o_ts, fake)
Test.pop_testset()
with_testset(o_ts) do
completed_tests = Set{String}()
for (testname, (resp,)) in results
push!(completed_tests, testname)
if isa(resp, Test.DefaultTestSet)
with_testset(resp) do
Test.record(o_ts, resp)
end
elseif isa(resp, Tuple{Int,Int})
fake = Test.DefaultTestSet(testname)
for i in 1:resp[1]
Test.record(fake, Test.Pass(:test, nothing, nothing, nothing, nothing))
end
for i in 1:resp[2]
Test.record(fake, Test.Broken(:test, nothing))
end
with_testset(fake) do
Test.record(o_ts, fake)
end
elseif isa(resp, RemoteException) && isa(resp.captured.ex, Test.TestSetException)
println("Worker $(resp.pid) failed running test $(testname):")
Base.showerror(stdout, resp.captured)
println()
fake = Test.DefaultTestSet(testname)
for i in 1:resp.captured.ex.pass
Test.record(fake, Test.Pass(:test, nothing, nothing, nothing, nothing))
end
for i in 1:resp.captured.ex.broken
Test.record(fake, Test.Broken(:test, nothing))
end
for t in resp.captured.ex.errors_and_fails
Test.record(fake, t)
end
with_testset(fake) do
Test.record(o_ts, fake)
end
else
if !isa(resp, Exception)
resp = ErrorException(string("Unknown result type : ", typeof(resp)))
end
# If this test raised an exception that is not a remote testset exception,
# i.e. not a RemoteException capturing a TestSetException that means
# the test runner itself had some problem, so we may have hit a segfault,
# deserialization errors or something similar. Record this testset as Errored.
fake = Test.DefaultTestSet(testname)
Test.record(fake, Test.Error(:nontest_error, testname, nothing, Base.ExceptionStack([(exception=resp,backtrace=[])]), LineNumberNode(1)))
with_testset(fake) do
Test.record(o_ts, fake)
end
end
end
for test in tests
(test in completed_tests) && continue
fake = Test.DefaultTestSet(test)
Test.record(fake, Test.Error(:test_interrupted, test, nothing, Base.ExceptionStack([(exception="skipped",backtrace=[])]), LineNumberNode(1)))
with_testset(fake) do
Test.record(o_ts, fake)
end
end
end
println()
Test.print_test_results(o_ts, 1)
if !o_ts.anynonpass
if (VERSION >= v"1.13.0-DEV.1037" && !Test.anynonpass(o_ts)) ||
(VERSION < v"1.13.0-DEV.1037" && !o_ts.anynonpass)
println(" \033[32;1mSUCCESS\033[0m")
else
println(" \033[31;1mFAILURE\033[0m\n")
Test.print_test_errors(o_ts)
throw(Test.FallbackTestSetException("Test run finished with errors"))
end

26 changes: 20 additions & 6 deletions test/setup.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ for file in readdir(joinpath(@__DIR__, "helpers"))
end
using .FileCheck

if VERSION >= v"1.13.0-DEV.1044"
using Base.ScopedValues
end


## entry point

function runtests(f, name)
old_print_setting = Test.TESTSET_PRINT_ENABLE[]
Test.TESTSET_PRINT_ENABLE[] = false

try
function inner()
# generate a temporary module to execute the tests in
mod_name = Symbol("Test", rand(1:100), "Main_", replace(name, '/' => '_'))
mod = @eval(Main, module $mod_name end)
Expand Down Expand Up @@ -61,8 +62,21 @@ function runtests(f, name)

GC.gc(true)
res
finally
Test.TESTSET_PRINT_ENABLE[] = old_print_setting
end

old_print_setting = Test.TESTSET_PRINT_ENABLE[]
@static if VERSION >= v"1.13.0-DEV.1044"
@with Test.TESTSET_PRINT_ENABLE=>false begin
inner()
end
else
old_print_setting = Test.TESTSET_PRINT_ENABLE[]
Test.TESTSET_PRINT_ENABLE[] = false
try
inner()
finally
Test.TESTSET_PRINT_ENABLE[] = old_print_setting
end
end
end

Expand Down
Loading