Skip to content

Commit 3a36e1a

Browse files
authored
sroa: Don't use unwrapped type for type constraint (JuliaLang#50499)
In SROA, when we lift getfields over branches (ifelse or phi), we try to exclude branches that we know to not contribute by their types. However, we were incorrectly using the `unwrap_unionall`'ed version of the type. Type intersection has a bunch of fallbacks for free typevars, but the results are not necessarily correct (e.g. in the test case where `hasintersect(Wrap1{Wrap{Int}}, Wrap1{Wrap{T}})` gives false). We should ideally get around to just making type-quries for things with free typevars an error, but for now, just fix the particular issue in sroa, by using the non-unwrapped type.
1 parent b26f3b2 commit 3a36e1a

File tree

2 files changed

+27
-8
lines changed

2 files changed

+27
-8
lines changed

base/compiler/ssair/passes.jl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,25 +1105,25 @@ function sroa_pass!(ir::IRCode, inlining::Union{Nothing,InliningState}=nothing)
11051105
# analyze `getfield` / `isdefined` / `setfield!` call
11061106
val = stmt.args[2]
11071107
end
1108-
struct_typ = unwrap_unionall(widenconst(argextype(val, compact)))
1108+
struct_typ = widenconst(argextype(val, compact))
1109+
struct_typ_unwrapped = unwrap_unionall(struct_typ)
11091110
if isa(struct_typ, Union) && struct_typ <: Tuple
1110-
struct_typ = unswitchtupleunion(struct_typ)
1111+
struct_typ_unwrapped = unswitchtupleunion(struct_typ_unwrapped)
11111112
end
1112-
if isa(struct_typ, Union) && is_isdefined
1113+
if isa(struct_typ_unwrapped, Union) && is_isdefined
11131114
lift_comparison!(isdefined, compact, idx, stmt, lifting_cache, 𝕃ₒ)
11141115
continue
11151116
end
1116-
isa(struct_typ, DataType) || continue
1117+
isa(struct_typ_unwrapped, DataType) || continue
11171118

1118-
struct_typ.name.atomicfields == C_NULL || continue # TODO: handle more
1119+
struct_typ_unwrapped.name.atomicfields == C_NULL || continue # TODO: handle more
11191120
if !((field_ordering === :unspecified) ||
11201121
(field_ordering isa Const && field_ordering.val === :not_atomic))
11211122
continue
11221123
end
11231124

1124-
11251125
# analyze this mutable struct here for the later pass
1126-
if ismutabletype(struct_typ)
1126+
if ismutabletype(struct_typ_unwrapped)
11271127
isa(val, SSAValue) || continue
11281128
let intermediaries = SPCSet()
11291129
callback = IntermediaryCollector(intermediaries)
@@ -1153,7 +1153,7 @@ function sroa_pass!(ir::IRCode, inlining::Union{Nothing,InliningState}=nothing)
11531153
end
11541154

11551155
# perform SROA on immutable structs here on
1156-
field = try_compute_fieldidx_stmt(compact, stmt, struct_typ)
1156+
field = try_compute_fieldidx_stmt(compact, stmt, struct_typ_unwrapped)
11571157
field === nothing && continue
11581158

11591159
leaves, visited_philikes = collect_leaves(compact, val, struct_typ, 𝕃ₒ, phi_or_ifelse_predecessors)

test/compiler/irpasses.jl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,3 +1371,22 @@ struct TParamTypeofTest2{S,T}
13711371
end
13721372
tparam_typeof_test_elim2(x, y) = TParamTypeofTest2(x, y).x
13731373
@test fully_eliminated(tparam_typeof_test_elim2, Tuple{Any,Any})
1374+
1375+
# Test that sroa doesn't get confused by free type parameters in struct types
1376+
struct Wrap1{T}
1377+
x::T
1378+
@eval @inline (T::Type{Wrap1{X}} where X)(x) = $(Expr(:new, :T, :x))
1379+
end
1380+
Wrap1(x) = Wrap1{typeof(x)}(x)
1381+
1382+
function wrap1_wrap1_ifelse(b, x, w1)
1383+
w2 = Wrap1(Wrap1(x))
1384+
w3 = Wrap1(typeof(w1)(w1.x))
1385+
Core.ifelse(b, w3, w2).x.x
1386+
end
1387+
function wrap1_wrap1_wrapper(b, x, y)
1388+
w1 = Base.inferencebarrier(Wrap1(y))::Wrap1{<:Union{Int, Float64}}
1389+
wrap1_wrap1_ifelse(b, x, w1)
1390+
end
1391+
@test wrap1_wrap1_wrapper(true, 1, 1.0) === 1.0
1392+
@test wrap1_wrap1_wrapper(false, 1, 1.0) === 1

0 commit comments

Comments
 (0)