Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

optimizer: enable SROA with constant globals #42355

Merged
merged 1 commit into from
Sep 23, 2021
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
34 changes: 24 additions & 10 deletions base/compiler/ssair/passes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,27 @@ struct SSADefUse
end
SSADefUse() = SSADefUse(Int[], Int[], Int[])

try_compute_fieldidx_expr(typ::DataType, expr::Expr) = try_compute_fieldidx_args(typ, expr.args)
function try_compute_fieldidx_args(typ::DataType, args::Vector{Any})
field = args[3]
isa(field, QuoteNode) && (field = field.value)
function try_compute_field_stmt(compact::IncrementalCompact, stmt::Expr)
field = stmt.args[3]
# fields are usually literals, handle them manually
if isa(field, QuoteNode)
field = field.value
elseif isa(field, Int)
# try to resolve other constants, e.g. global reference
else
field = compact_exprtype(compact, field)
if isa(field, Const)
field = field.val
else
return nothing
end
end
isa(field, Union{Int, Symbol}) || return nothing
return field
end

function try_compute_fieldidx_stmt(compact::IncrementalCompact, stmt::Expr, typ::DataType)
field = try_compute_field_stmt(compact, stmt)
return try_compute_fieldidx(typ, field)
end

Expand Down Expand Up @@ -636,10 +652,8 @@ function getfield_elim_pass!(ir::IRCode)
else
continue
end
## Normalize the field argument to getfield/setfield
field = stmt.args[3]
isa(field, QuoteNode) && (field = field.value)
isa(field, Union{Int, Symbol}) || continue
field = try_compute_field_stmt(compact, stmt)
field === nothing && continue

struct_typ = unwrap_unionall(widenconst(compact_exprtype(compact, stmt.args[2])))
if isa(struct_typ, Union) && struct_typ <: Tuple
Expand Down Expand Up @@ -779,13 +793,13 @@ function getfield_elim_pass!(ir::IRCode)
# it would have been deleted. That's fine, just ignore
# the use in that case.
stmt === nothing && continue
field = try_compute_fieldidx_expr(typ, stmt)
field = try_compute_fieldidx_stmt(compact, stmt::Expr, typ)
field === nothing && (ok = false; break)
push!(fielddefuse[field].uses, use)
end
ok || continue
for use in defuse.defs
field = try_compute_fieldidx_expr(typ, ir[SSAValue(use)])
field = try_compute_fieldidx_stmt(compact, ir[SSAValue(use)]::Expr, typ)
field === nothing && (ok = false; break)
push!(fielddefuse[field].defs, use)
end
Expand Down
42 changes: 42 additions & 0 deletions test/compiler/irpasses.jl
Original file line number Diff line number Diff line change
Expand Up @@ -383,3 +383,45 @@ exc39508 = ErrorException("expected")
return err
end
@test test39508() === exc39508

let # `getfield_elim_pass!` should work with constant globals
# immutable pass
src = @eval Module() begin
const REF_FLD = :x
struct ImmutableRef{T}
x::T
end

code_typed((Int,)) do x
r = ImmutableRef{Int}(x) # should be eliminated
x = getfield(r, REF_FLD) # should be eliminated
return sin(x)
end |> only |> first
end
@test !any(src.code) do @nospecialize(stmt)
Meta.isexpr(stmt, :call) || return false
ft = Core.Compiler.argextype(stmt.args[1], src, Any[], src.slottypes)
return Core.Compiler.widenconst(ft) == typeof(getfield)
end
@test !any(src.code) do @nospecialize(stmt)
return Meta.isexpr(stmt, :new)
end

# mutable pass
src = @eval Module() begin
const REF_FLD = :x
code_typed() do
r = Ref{Int}(42) # should be eliminated
x = getfield(r, REF_FLD) # should be eliminated
return sin(x)
end |> only |> first
end
@test !any(src.code) do @nospecialize(stmt)
Meta.isexpr(stmt, :call) || return false
ft = Core.Compiler.argextype(stmt.args[1], src, Any[], src.slottypes)
return Core.Compiler.widenconst(ft) == typeof(getfield)
end
@test !any(src.code) do @nospecialize(stmt)
return Meta.isexpr(stmt, :new)
end
end