Skip to content

Commit

Permalink
Fix bug when inlining pending nodes
Browse files Browse the repository at this point in the history
While working on IR, we give pending nodes SSA ids after the main
body of the function, and then we drop them in place during compaction.
Inlining was using thse IDs to try to determine which basic block
we're currently inlining into, but for pending blocks it was looking
at the raw ID rather than the insertion position, corrupting the CFG.

Fixes #37555
Fixes #37182

(cherry picked from commit ace08d8)
  • Loading branch information
Keno authored and vchuravy committed Oct 22, 2020
1 parent 3ee6dd7 commit 066b0d2
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 6 deletions.
12 changes: 6 additions & 6 deletions base/compiler/ssair/inlining.jl
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,12 @@ function inline_into_block!(state::CFGInliningState, block::Int)
return
end

function cfg_inline_item!(item::InliningTodo, state::CFGInliningState, from_unionsplit::Bool=false)
function cfg_inline_item!(ir::IRCode, item::InliningTodo, state::CFGInliningState, from_unionsplit::Bool=false)
inlinee_cfg = item.ir.cfg
# Figure out if we need to split the BB
need_split_before = false
need_split = true
block = block_for_inst(state.cfg, item.idx)
block = block_for_inst(ir, item.idx)
inline_into_block!(state, block)

if !isempty(inlinee_cfg.blocks[1].preds)
Expand Down Expand Up @@ -212,7 +212,7 @@ function cfg_inline_item!(item::InliningTodo, state::CFGInliningState, from_unio
end
end

function cfg_inline_unionsplit!(item::UnionSplit, state::CFGInliningState)
function cfg_inline_unionsplit!(ir::IRCode, item::UnionSplit, state::CFGInliningState)
block = block_for_inst(state.cfg, item.idx)
inline_into_block!(state, block)
from_bbs = Int[]
Expand All @@ -227,7 +227,7 @@ function cfg_inline_unionsplit!(item::UnionSplit, state::CFGInliningState)
push!(state.new_cfg_blocks[end].preds, cond_bb)
push!(state.new_cfg_blocks[cond_bb].succs, cond_bb+1)
if isa(case, InliningTodo) && !case.linear_inline_eligible
cfg_inline_item!(case, state, true)
cfg_inline_item!(ir, case, state, true)
end
bb = length(state.new_cfg_blocks)
push!(from_bbs, bb)
Expand Down Expand Up @@ -501,12 +501,12 @@ function batch_inline!(todo::Vector{Any}, ir::IRCode, linetable::Vector{LineInfo
state = CFGInliningState(ir)
for item in todo
if isa(item, UnionSplit)
cfg_inline_unionsplit!(item::UnionSplit, state)
cfg_inline_unionsplit!(ir, item::UnionSplit, state)
else
item = item::InliningTodo
# A linear inline does not modify the CFG
item.linear_inline_eligible && continue
cfg_inline_item!(item, state)
cfg_inline_item!(ir, item, state)
end
end
finish_cfg_inline!(state)
Expand Down
7 changes: 7 additions & 0 deletions base/compiler/ssair/ir.jl
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,13 @@ end
copy(code::IRCode) = IRCode(code, copy_exprargs(code.stmts), copy(code.types),
copy(code.lines), copy(code.flags), copy(code.cfg), copy(code.new_nodes))

function block_for_inst(ir::IRCode, inst::Int)
if inst > length(ir.stmts)
inst = ir.new_nodes.info[inst - length(ir.stmts)].pos
end
block_for_inst(ir.cfg, inst)
end

function getindex(x::IRCode, s::SSAValue)
if s.id <= length(x.stmts)
return x.stmts[s.id]
Expand Down
21 changes: 21 additions & 0 deletions test/compiler/inline.jl
Original file line number Diff line number Diff line change
Expand Up @@ -288,3 +288,24 @@ f_inline_global_getindex() = _a_global_array[1]
let ci = code_typed(f_inline_global_getindex, Tuple{})[1].first
@test any(x->(isexpr(x, :call) && x.args[1] === GlobalRef(Base, :arrayref)), ci.code)
end

# Issue #29114 & #36087 - Inlining of non-tuple splats
f_29115(x) = (x...,)
@test @allocated(f_29115(1)) == 0
@test @allocated(f_29115(1=>2)) == 0
let ci = code_typed(f_29115, Tuple{Int64})[1].first
@test length(ci.code) == 2 && isexpr(ci.code[1], :call) &&
ci.code[1].args[1] === GlobalRef(Core, :tuple)
end
let ci = code_typed(f_29115, Tuple{Pair{Int64, Int64}})[1].first
@test length(ci.code) == 4 && isexpr(ci.code[1], :call) &&
ci.code[end-1].args[1] === GlobalRef(Core, :tuple)
end

# Issue #37182 & #37555 - Inlining of pending nodes
function f37555(x::Int; kwargs...)
@assert x < 10
+(x, kwargs...)
end
@test f37555(1) == 1

0 comments on commit 066b0d2

Please sign in to comment.