Skip to content
This repository has been archived by the owner on Nov 8, 2022. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Ehsan Totoni committed Dec 11, 2015
2 parents 707a617 + a8d0efc commit cc6ba6f
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 72 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ script:
- julia --code-coverage=user test/runtests.jl
# Run examples.
- julia examples/black-scholes/black-scholes.jl
- julia --code-coverage=user --inline=no examples/black-scholes/black-scholes.jl
- julia --code-coverage=user examples/black-scholes/black-scholes.jl
- julia --code-coverage=user examples/boltzmann/boltzmann.jl
- julia --code-coverage=user examples/gaussian-blur/gaussian-blur.jl
- julia --code-coverage=user examples/harris/harris.jl
Expand Down
8 changes: 6 additions & 2 deletions examples/black-scholes/black-scholes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ THE POSSIBILITY OF SUCH DAMAGE.
using ParallelAccelerator
using DocOpt

function cndf2(in::Array{Float64,1})
@acc begin

@inline function cndf2(in::Array{Float64,1})
out = 0.5 .+ 0.5 .* erf(0.707106781 .* in)
return out
end

@acc function blackscholes(sptprice::Array{Float64,1},
function blackscholes(sptprice::Array{Float64,1},
strike::Array{Float64,1},
rate::Array{Float64,1},
volatility::Array{Float64,1},
Expand All @@ -49,6 +51,8 @@ end
put = call .- futureValue .+ sptprice
end

end

function run(iterations)
sptprice = Float64[ 42.0 for i = 1:iterations ]
initStrike = Float64[ 40.0 + (i / iterations) for i = 1:iterations ]
Expand Down
9 changes: 8 additions & 1 deletion src/api-capture.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,19 @@ function process_node(node, state, top_level_number, is_top_level, read)
tmpvar = gensym()
node.head = :block
node.args = Any[
Expr(:(=), tmpvar, Expr(:call, ref_assign_map[head],
Expr(:(=), tmpvar, Expr(:call, GlobalRef(API, ref_assign_map[head]),
Expr(:call, GlobalRef(API, :getindex), lhs, idx...),
rhs)),
Expr(:call, GlobalRef(API, :setindex!), lhs, tmpvar, idx...),
tmpvar]

elseif haskey(ref_assign_map, head)
# x += ...
lhs = node.args[1]
rhs = node.args[2]
tmpvar = gensym()
node.head = :(=)
node.args = Any[ lhs, Expr(:call, GlobalRef(API, ref_assign_map[head]), lhs, rhs) ]
elseif node.head == :ref
node.head = :call
node.args = Any[GlobalRef(API, :getindex), node.args...]
Expand Down
20 changes: 12 additions & 8 deletions src/api.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ eval(x) = Core.eval(API, x)
Base.setindex!(A, args...)
end

function setindex!(A, args...)
@inline function setindex!(A, args...)
Base.setindex!(A, args...)
end

@noinline function getindex{T}(A::DenseArray{T}, args...)
Base.getindex(A, args...)
end

function getindex(A, args...)
@inline function getindex(A, args...)
Base.getindex(A, args...)
end

Expand All @@ -62,7 +62,7 @@ for f in unary_operators
@noinline function ($f){T<:Number}(A::DenseArray{T})
(Base.$f)(A)
end
function ($f)(A...)
@inline function ($f)(A...)
(Base.$f)(A...)
end
end
Expand All @@ -73,14 +73,14 @@ for f in unary_map_operators
@noinline function ($f){T<:Number}(A::T)
(Base.$f)(A)
end
function ($f)(A...)
@inline function ($f)(A...)
(Base.$f)(A...)
end
end
end

# Binary operators/functions
const binary_map_operators = Symbol[
const binary_map_operators = Symbol[ :*,
:-, :+, :.+, :.-, :.*, :./, :.\, :.%, :.>, :.<, :.<=, :.>=, :.==, :.<<, :.>>, :.^,
:div, :mod, :rem, :&, :|, :$, :min, :max]

Expand All @@ -94,11 +94,15 @@ for f in binary_operators
@noinline function ($f){T}(B::DenseArray{T}, A::T)
(Base.$f)(B, A)
end
@noinline function ($f){T}(A::DenseArray{T}, B::DenseArray{T})
end
if f != :*
@eval @noinline function ($f){T}(A::DenseArray{T}, B::DenseArray{T})
(Base.$f)(A, B)
end
function ($f)(A, B)
(Base.$f)(A, B)
end
@eval begin
@inline function ($f)(args...)
(Base.$f)(args...)
end
end
end
Expand Down
5 changes: 3 additions & 2 deletions src/cgen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,8 @@ tokenXlate = Dict(
'^' => "hat",
'|' => "bar",
'&' => "amp",
'=' => "eq"
'=' => "eq",
'\\' => "backslash"
)

replacedTokens = Set("#")
Expand Down Expand Up @@ -750,12 +751,12 @@ function canonicalize(tok)
global scrubbedTokens
s = string(tok)
s = replace(s, scrubbedTokens, "")
s = replace(s, r"^[^a-zA-Z]", "_")
s = replace(s, replacedTokens, "p")
s = replace(s, "", "del")
for (k,v) in tokenXlate
s = replace(s, k, v)
end
s = replace(s, r"[^a-zA-Z0-9]", "_")
s
end

Expand Down
145 changes: 87 additions & 58 deletions src/domain-ir.jl
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,7 @@ function from_call(state::IRState, env::IREnv, expr::Expr)
fun = from_expr(state, env_, fun)
dprintln(env,"from_call: new fun=", fun)
(fun_, args_) = normalize_callname(state, env, fun, args)
dprintln(env,"normalized callname: ", fun_)
result = translate_call(state, env, typ, :call, fun, args, fun_, args_)
result
end
Expand Down Expand Up @@ -886,7 +887,17 @@ end

# Fix Julia inconsistencies in call before we pattern match
function normalize_callname(state::IRState, env, fun::GlobalRef, args)
return normalize_callname(state, env, fun.name, args)
fun = Base.resolve(fun, force=true)
if is(fun.mod, API) || is(fun.mod, API.Stencil)
return normalize_callname(state, env, fun.name, args)
elseif is(fun.mod, Base.Random) && (is(fun.name, :rand!) || is(fun.name, :randn!))
if is(fun.name, :rand!)
splice!(args,3)
end
return (fun.name, args)
else
return (fun, args)
end
end

function normalize_callname(state::IRState, env, fun::Symbol, args)
Expand Down Expand Up @@ -930,10 +941,6 @@ function normalize_callname(state::IRState, env, fun::Symbol, args)
if haskey(liftOps, fun) # lift operation to array level
fun = liftOps[fun]
end
elseif fun==:rand!
# remove third argument.
# it is Base.arraylen that we can't handle well and don't need for translation
splice!(args,3)
end
return (fun, args)
end
Expand Down Expand Up @@ -1005,7 +1012,13 @@ function inline_select(env, state, arr)
return arr
end

# translate a function call to domain IR if it matches
# translate a function call to domain IR if it matches Symbol.
# things handled as Symbols are:
# those captured in ParallelAPI, or
# those that can be TopNode, or
# those from Core.Intrinsics, or
# those that are DomainIR specific, such as :alloc, or
# a few exceptions.
function translate_call(state, env, typ, head, oldfun, oldargs, fun::Symbol, args::Array{Any,1})
local env_ = nextEnv(env)
expr = nothing
Expand All @@ -1018,39 +1031,18 @@ function translate_call(state, env, typ, head, oldfun, oldargs, fun::Symbol, arg
dprintln(env, "verifyMapOps -> ", verifyMapOps(state, fun, args))
if verifyMapOps(state, fun, args) && (isarray(typ) || isbitarray(typ))
return translate_call_map(state,env_,typ, fun, args)
elseif is(fun, :afoldl) && haskey(afoldlDict, typeOfOpr(state, args[1]))
opr, reorder = specializeOp(afoldlDict[typeOfOpr(state, args[1])], [typ, typ])
dprintln(env, "afoldl operator detected = ", args[1], " opr = ", opr)
expr = Base.afoldl((x,y)->mk_expr(typ, :call, opr, reorder([x, y])...), args[2:end]...)
dprintln(env, "translated expr = ", expr)
elseif is(fun, :cartesianarray)
return translate_call_cartesianarray(state,env_,typ, args)
elseif is(fun, :runStencil)
return translate_call_runstencil(state,env_,args)
elseif is(fun, :parallel_for)
return translate_call_parallel_for(state,env_,args)
elseif is(fun, :copy)
args = normalize_args(state, env_, args[1:1])
dprintln(env,"got copy, args=", args)
expr = mk_copy(args[1])
expr.typ = typ
elseif in(fun, topOpsTypeFix) && is(typ, Any) && length(args) > 0
typ = translate_call_typefix(state, env, typ, fun, args)
elseif is(fun, :getfield) && length(args) == 2 && isa(args[1], GenSym) &&
(args[2] == QuoteNode(:stop) || args[2] == QuoteNode(:start) || args[2] == QuoteNode(:step))
# Shortcut range object access
rTyp = getType(args[1], state.linfo)
rExpr = lookupConstDefForArg(state, args[1])
if isrange(rTyp) && isa(rExpr, Expr)
(start, step, final) = from_range(rExpr)
fname = args[2].value
if is(fname, :stop)
return final
elseif is(fname, :start)
return start
else
return step
end
elseif haskey(reduceOps, fun)
args = normalize_args(state, env_, args)
if length(args)==1
return translate_call_reduce(state, env_, typ, fun, args)
end
elseif is(fun, :arraysize)
args = normalize_args(state, env_, args)
Expand All @@ -1072,34 +1064,25 @@ function translate_call(state, env, typ, head, oldfun, oldargs, fun::Symbol, arg
assert(isa(elemTyp, DataType))
expr = mk_alloc(state, elemTyp, args)
expr.typ = typ
elseif is(fun, :broadcast_shape)
dprintln(env, "got ", fun)
args = normalize_args(state, env_, args)
expr = mk_expr(typ, :assertEqShape, args...)
elseif is(fun, :checkbounds)
dprintln(env, "got ", fun, " args = ", args)
if length(args) == 2
return translate_call_checkbounds(state,env_,args)
end
elseif is(fun, :sitofp) || is(fun, :fpext) # typefix hack!
typ = isa(args[1], Type) ? args[1] : eval(args[1])
elseif is(fun, :getindex) || is(fun, :setindex!)
expr = translate_call_getsetindex(state,env_,typ,fun,args)
elseif is(fun, :assign_bool_scalar_1d!) || # args = (array, scalar_value, bitarray)
is(fun, :assign_bool_vector_1d!) # args = (array, getindex_bool_1d(array, bitarray), bitarray)
return translate_call_assign_bool(state,env_,typ,fun, args)
elseif is(fun, :fill!)
return translate_call_fill!(state, env_, typ, args)
elseif is(fun, :_getindex!) # see if we can turn getindex! back into getindex
if isa(args[1], Expr) && args[1].head == :call && args[1].args[1] == TopNode(:ccall) &&
(args[1].args[2] == :jl_new_array ||
(isa(args[1].args[2], QuoteNode) && args[1].args[2].value == :jl_new_array))
expr = mk_expr(typ, :call, :getindex, args[2:end]...)
end
elseif haskey(reduceOps, fun)
args = normalize_args(state, env_, args)
if length(args)==1
return translate_call_reduce(state, env_, typ, fun, args)
elseif is(fun, :getfield) && length(args) == 2 && isa(args[1], GenSym) &&
(args[2] == QuoteNode(:stop) || args[2] == QuoteNode(:start) || args[2] == QuoteNode(:step))
# Shortcut range object access
rTyp = getType(args[1], state.linfo)
rExpr = lookupConstDefForArg(state, args[1])
if isrange(rTyp) && isa(rExpr, Expr)
(start, step, final) = from_range(rExpr)
fname = args[2].value
if is(fname, :stop)
return final
elseif is(fname, :start)
return start
else
return step
end
end
elseif in(fun, ignoreSet)
else
Expand Down Expand Up @@ -1577,7 +1560,7 @@ function translate_call_parallel_for(state, env, args::Array{Any,1})
return mk_parallel_for(loopvars, ranges, domF)
end

# translate a function call to domain IR if it matches
# translate a function call to domain IR if it matches GlobalRef.
function translate_call(state, env, typ, head, oldfun, oldargs, fun::GlobalRef, args)
local env_ = nextEnv(env)
expr = nothing
Expand All @@ -1586,7 +1569,53 @@ function translate_call(state, env, typ, head, oldfun, oldargs, fun::GlobalRef,
#if isa(fun, GlobalRef) && fun.mod == Main
# fun = fun.name
# end
if is(fun.mod, Base.Math)
if is(fun.mod, Core.Intrinsics) || (is(fun.mod, Core) &&
(is(fun.name, :Array) || is(fun.name, :arraysize) || is(fun.name, :getfield)))
expr = translate_call(state, env, typ, head, fun, oldargs, fun.name, args)
elseif is(fun.mod, Base)
if is(fun.name, :afoldl) && haskey(afoldlDict, typeOfOpr(state, args[1]))
opr, reorder = specializeOp(afoldlDict[typeOfOpr(state, args[1])], [typ, typ])
dprintln(env, "afoldl operator detected = ", args[1], " opr = ", opr)
expr = Base.afoldl((x,y)->mk_expr(typ, :call, opr, reorder([x, y])...), args[2:end]...)
dprintln(env, "translated expr = ", expr)
elseif is(fun.name, :copy)
args = normalize_args(state, env_, args[1:1])
dprintln(env,"got copy, args=", args)
expr = mk_copy(args[1])
expr.typ = typ
elseif is(fun.name, :broadcast_shape)
dprintln(env, "got ", fun.name)
args = normalize_args(state, env_, args)
expr = mk_expr(typ, :assertEqShape, args...)
elseif is(fun.name, :checkbounds)
dprintln(env, "got ", fun.name, " args = ", args)
if length(args) == 2
expr = translate_call_checkbounds(state,env_,args)
end
elseif is(fun.name, :getindex) || is(fun.name, :setindex!) # not a domain operator, but still, sometimes need to shortcut it
expr = translate_call_getsetindex(state,env_,typ,fun,args)
elseif is(fun.name, :assign_bool_scalar_1d!) || # args = (array, scalar_value, bitarray)
is(fun.name, :assign_bool_vector_1d!) # args = (array, getindex_bool_1d(array, bitarray), bitarray)
expr = translate_call_assign_bool(state,env_,typ,fun.name, args)
elseif is(fun.name, :fill!)
return translate_call_fill!(state, env_, typ, args)
elseif is(fun.name, :_getindex!) # see if we can turn getindex! back into getindex
if isa(args[1], Expr) && args[1].head == :call && args[1].args[1] == TopNode(:ccall) &&
(args[1].args[2] == :jl_new_array ||
(isa(args[1].args[2], QuoteNode) && args[1].args[2].value == :jl_new_array))
expr = mk_expr(typ, :call, :getindex, args[2:end]...)
end
#-
elseif haskey(reduceOps, fun.name)
args = normalize_args(state, env_, args)
if length(args)==1
expr = translate_call_reduce(state, env_, typ, fun, args)
end
-#
end
elseif is(fun.mod, Base.Random) #skip, let cgen handle it
elseif is(fun.mod, Base.LinAlg) #skip, let cgen handle it
elseif is(fun.mod, Base.Math)
# NOTE: we simply bypass all math functions for now
dprintln(env,"by pass math function ", fun, ", typ=", typ)
# Fix return type of math functions
Expand Down Expand Up @@ -1662,7 +1691,7 @@ function from_expr(state::IRState, env::IREnv, ast::Union{SymbolNode,Symbol})
def = lookupDefInAllScopes(state, name)
if is(def, nothing) && isdefined(env.cur_module, name) && ccall(:jl_is_const, Int32, (Any, Any), env.cur_module, name) == 1
def = getfield(env.cur_module, name)
if isbits(def)
if isbits(def) && isa(def, IntrinsicFunction)
return def
end
end
Expand Down

0 comments on commit cc6ba6f

Please sign in to comment.