Add: julia-0.6.2
Former-commit-id: ccc667cf67d569f3fb3df39aa57c2134755a7551
This commit is contained in:
92
julia-0.6.2/share/julia/base/simdloop.jl
Normal file
92
julia-0.6.2/share/julia/base/simdloop.jl
Normal file
@@ -0,0 +1,92 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
# Support for @simd for
|
||||
|
||||
module SimdLoop
|
||||
|
||||
export @simd, simd_outer_range, simd_inner_length, simd_index
|
||||
|
||||
# Error thrown from ill-formed uses of @simd
|
||||
mutable struct SimdError <: Exception
|
||||
msg::String
|
||||
end
|
||||
|
||||
# Parse iteration space expression
|
||||
# symbol '=' range
|
||||
# symbol 'in' range
|
||||
function parse_iteration_space(x)
|
||||
(isa(x, Expr) && (x.head == :(=) || x.head == :in)) || throw(SimdError("= or in expected"))
|
||||
length(x.args) == 2 || throw(SimdError("simd range syntax is wrong"))
|
||||
isa(x.args[1], Symbol) || throw(SimdError("simd loop index must be a symbol"))
|
||||
x.args # symbol, range
|
||||
end
|
||||
|
||||
# reject invalid control flow statements in @simd loop body
|
||||
function check_body!(x::Expr)
|
||||
if x.head === :break || x.head == :continue
|
||||
throw(SimdError("$(x.head) is not allowed inside a @simd loop body"))
|
||||
elseif x.head === :macrocall && x.args[1] === Symbol("@goto")
|
||||
throw(SimdError("$(x.args[1]) is not allowed inside a @simd loop body"))
|
||||
end
|
||||
for arg in x.args
|
||||
check_body!(arg)
|
||||
end
|
||||
return true
|
||||
end
|
||||
check_body!(x::QuoteNode) = check_body!(x.value)
|
||||
check_body!(x) = true
|
||||
|
||||
# @simd splits a for loop into two loops: an outer scalar loop and
|
||||
# an inner loop marked with :simdloop. The simd_... functions define
|
||||
# the splitting.
|
||||
|
||||
# Get range for outer loop.
|
||||
simd_outer_range(r) = 0:0
|
||||
|
||||
# Get trip count for inner loop.
|
||||
@inline simd_inner_length(r,j::Int) = length(r)
|
||||
|
||||
# Construct user-level element from original range, outer loop index j, and inner loop index i.
|
||||
@inline simd_index(r,j::Int,i) = (@inbounds ret = r[i+1]; ret)
|
||||
|
||||
# Compile Expr x in context of @simd.
|
||||
function compile(x)
|
||||
(isa(x, Expr) && x.head == :for) || throw(SimdError("for loop expected"))
|
||||
length(x.args) == 2 || throw(SimdError("1D for loop expected"))
|
||||
check_body!(x)
|
||||
|
||||
var,range = parse_iteration_space(x.args[1])
|
||||
r = gensym("r") # Range value
|
||||
j = gensym("i") # Iteration variable for outer loop
|
||||
n = gensym("n") # Trip count for inner loop
|
||||
i = gensym("i") # Trip index for inner loop
|
||||
quote
|
||||
# Evaluate range value once, to enhance type and data flow analysis by optimizers.
|
||||
let $r = $range
|
||||
for $j in Base.simd_outer_range($r)
|
||||
let $n = Base.simd_inner_length($r,$j)
|
||||
if zero($n) < $n
|
||||
# Lower loop in way that seems to work best for LLVM 3.3 vectorizer.
|
||||
let $i = zero($n)
|
||||
while $i < $n
|
||||
local $var = Base.simd_index($r,$j,$i)
|
||||
$(x.args[2]) # Body of loop
|
||||
$i += 1
|
||||
$(Expr(:simdloop)) # Mark loop as SIMD loop
|
||||
end
|
||||
end
|
||||
# Set index to last value just like a regular for loop would
|
||||
$var = last($r)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
nothing
|
||||
end
|
||||
end
|
||||
|
||||
macro simd(forloop)
|
||||
esc(compile(forloop))
|
||||
end
|
||||
|
||||
end # module SimdLoop
|
||||
Reference in New Issue
Block a user