Skip to content

Commit cba3abf

Browse files
vchuravyaviatesk
andauthored
SROA: Ensure that unused structs are preserved in ccall (#43408)
Co-authored-by: Shuhei Kadowaki <[email protected]>
1 parent fa8be6f commit cba3abf

File tree

2 files changed

+46
-4
lines changed

2 files changed

+46
-4
lines changed

base/compiler/ssair/passes.jl

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -852,13 +852,17 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse
852852
typ = typ::DataType
853853
# Partition defuses by field
854854
fielddefuse = SSADefUse[SSADefUse() for _ = 1:fieldcount(typ)]
855+
all_forwarded = true
855856
for use in defuse.uses
856857
stmt = ir[SSAValue(use)] # == `getfield` call
857858
# We may have discovered above that this use is dead
858859
# after the getfield elim of immutables. In that case,
859860
# it would have been deleted. That's fine, just ignore
860861
# the use in that case.
861-
stmt === nothing && continue
862+
if stmt === nothing
863+
all_forwarded = false
864+
continue
865+
end
862866
field = try_compute_fieldidx_stmt(ir, stmt::Expr, typ)
863867
field === nothing && @goto skip
864868
push!(fielddefuse[field].uses, use)
@@ -928,7 +932,12 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse
928932
end
929933
end
930934
preserve_uses === nothing && continue
931-
push!(intermediaries, newidx)
935+
if all_forwarded
936+
# this means all ccall preserves have been replaced with forwarded loads
937+
# so we can potentially eliminate the allocation, otherwise we must preserve
938+
# the whole allocation.
939+
push!(intermediaries, newidx)
940+
end
932941
# Insert the new preserves
933942
for (use, new_preserves) in preserve_uses
934943
ir[SSAValue(use)] = form_new_preserves(ir[SSAValue(use)]::Expr, intermediaries, new_preserves)
@@ -938,15 +947,16 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse
938947
end
939948
end
940949

941-
function form_new_preserves(origex::Expr, preserved::Vector{Int}, new_preserves::Vector{Any})
950+
function form_new_preserves(origex::Expr, intermediates::Vector{Int}, new_preserves::Vector{Any})
942951
newex = Expr(:foreigncall)
943952
nccallargs = length(origex.args[3]::SimpleVector)
944953
for i in 1:(6+nccallargs-1)
945954
push!(newex.args, origex.args[i])
946955
end
947956
for i in (6+nccallargs):length(origex.args)
948957
x = origex.args[i]
949-
if isa(x, SSAValue) && x.id in preserved
958+
# don't need to preserve intermediaries
959+
if isa(x, SSAValue) && x.id in intermediates
950960
continue
951961
end
952962
push!(newex.args, x)

test/compiler/irpasses.jl

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,3 +672,35 @@ let
672672
return Core.Compiler.widenconst(ft) !== typeof(typeassert)
673673
end
674674
end
675+
676+
let
677+
# Test for https://github.com/JuliaLang/julia/issues/43402
678+
# Ensure that structs required not used outside of the ccall,
679+
# still get listed in the ccall_preserves
680+
681+
src = @eval Module() begin
682+
@inline function effectful()
683+
s1 = Ref{Csize_t}()
684+
s2 = Ref{Csize_t}()
685+
ccall(:some_ccall, Cvoid,
686+
(Ref{Csize_t},Ref{Csize_t}),
687+
s1, s2)
688+
return s1[], s2[]
689+
end
690+
691+
code_typed() do
692+
s1, s2 = effectful()
693+
return s1
694+
end |> only |> first
695+
end
696+
697+
refs = map(Core.SSAValue, findall(x->x isa Expr && x.head == :new, src.code))
698+
some_ccall = findfirst(x -> x isa Expr && x.head == :foreigncall && x.args[1] == :(:some_ccall), src.code)
699+
@assert some_ccall !== nothing
700+
stmt = src.code[some_ccall]
701+
nccallargs = length(stmt.args[3]::Core.SimpleVector)
702+
preserves = stmt.args[6+nccallargs:end]
703+
@test length(refs) == 2
704+
@test length(preserves) == 2
705+
@test all(alloc -> alloc in preserves, refs)
706+
end

0 commit comments

Comments
 (0)