Skip to content

Commit

Permalink
track parallel regions
Browse files Browse the repository at this point in the history
  • Loading branch information
vchuravy committed Feb 17, 2019
1 parent ee50579 commit 530c0b7
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 26 deletions.
60 changes: 36 additions & 24 deletions base/compiler/ssair/driver.jl
Expand Up @@ -50,38 +50,50 @@ function normalize(@nospecialize(stmt), meta::Vector{Any})
return stmt
end

# TODO: Check that CFG edges don't leave or enter parallel regions
# Check no return statements in parallel regions
function mark_parallel_regions(code::Vector{Any})
regionmap = fill(-1, length(code))
regions = IdDict{Any, Int}()
cur_region = -1

idx = 1
while idx <= length(code)
stmt = code[idx]
regionmap[idx] = cur_region
if isa(stmt, DetachNode)
cur_region += 1
regions[(stmt::DetachNode).syncregion] = cur_region
regionmap[idx] = cur_region
elseif isa(stmt, ReattachNode)
# reattach should be in the same parallel region
@assert regions[(stmt::ReattachNode).syncregion] == cur_region
cur_region -= 1
elseif isa(stmt, SyncNode)
# SyncNode needs to be outside parallel region
@assert regions[(stmt::SyncNode).syncregion] > cur_region
end
idx += 1
end
return regionmap
end


function just_construct_ssa(ci::CodeInfo, code::Vector{Any}, nargs::Int, sv::OptimizationState)
# Go through and add an unreachable node after every
# Union{} call. Then reindex labels.
idx = 1
oldidx = 1
changemap = fill(0, length(code))
pregionmap = mark_parallel_regions(code)
while idx <= length(code)
if code[idx] isa Expr && ci.ssavaluetypes[idx] === Union{}
idx′ = idx
term = nothing
# TODO: We need to establish whether we are in a parallel region.
# this means that we are dominated by a DetachNode and dominate
# a ReattachNode with the same syncregion token.
# TODO: Unsure how to handle this with nested parallel regions
# TODO: this ignores the CFG
# TODO: Makes this more efficient
while idx′ <= length(code)
if isa(code[idx′], Union{ReturnNode, DetachNode, ReattachNode})
term = code[idx′]
break
end
idx′ += 1
end

if isa(term, ReattachNode)
# if the parallel region has an error, we can't place
# a unreachable (return of Union{}), since that would
# break the CFG, potentially we could say that a task
# throws an error could be removed entirely, but we
# would need to prove that nobody waits upon this task,
# e.g. that for the token there is no sync or the sync
# is dead.
if pregionmap[idx] > -1
# We are in a parallel region and can't place a return statement.
# Potentially we could say that a task that throws an error
# could be removed entirely, but we would need to prove that
# nobody waits upon this task, e.g. that for the token there is
# no sync or the sync is dead.
elseif !(idx < length(code) && isexpr(code[idx+1], :unreachable))
insert!(code, idx + 1, ReturnNode())
insert!(ci.codelocs, idx + 1, ci.codelocs[idx])
Expand Down
35 changes: 33 additions & 2 deletions test/tapir.jl
Expand Up @@ -32,9 +32,8 @@ macro sync(block)
var = esc(tokenname)
quote
let $var = @syncregion()
v = $(esc(block))
$(esc(block))
@sync_end($var)
v
end
end
end
Expand Down Expand Up @@ -133,6 +132,38 @@ function fib(N)
return x1[] + x2
end

###
# Interesting corner cases and broken IR
###

##
# Parallel regions with errors are tricky
# #1 detach within %sr, #2, #3
# #2 ...
# unreachable()
# reattach within %sr, #3
# #3 sync within %sr
#
# Normally a unreachable get's turned into a ReturnNode(),
# but that breaks the CFG. So we need to detect that we are
# in a parallel region.
#
# Question:
# - Can we elimante a parallel region that throws?
# Probably if the sync is dead as well. We could always
# use the serial projection and serially execute the region.

function vecadd_err(out, A, B)
@assert length(out) == length(A) == length(B)
@inbounds begin
@par for i in 1:length(out)
out[i] = A[i] + B[i]
error()
end
end
return out
end

# This function is broken due to the PhiNode
function fib2(N)
if N <= 1
Expand Down

0 comments on commit 530c0b7

Please sign in to comment.