• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37997

29 Jan 2025 02:08AM UTC coverage: 17.283% (-68.7%) from 85.981%
#37997

push

local

web-flow
bpart: Start enforcing min_world for global variable definitions (#57150)

This is the analog of #57102 for global variables. Unlike for consants,
there is no automatic global backdate mechanism. The reasoning for this
is that global variables can be declared at any time, unlike constants
which can only be decalared once their value is available. As a result
code patterns using `Core.eval` to declare globals are rarer and likely
incorrect.

1 of 22 new or added lines in 3 files covered. (4.55%)

31430 existing lines in 188 files now uncovered.

7903 of 45728 relevant lines covered (17.28%)

98663.7 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

46.88
/base/simdloop.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
# Support for @simd for
4

5
module SimdLoop
6

7
export @simd, simd_outer_range, simd_inner_length, simd_index
8

9
# Error thrown from ill-formed uses of @simd
10
struct SimdError <: Exception
11
    msg::String
12
end
13

14
# Parse iteration space expression
15
#       symbol '=' range
16
#       symbol 'in' range
UNCOV
17
function parse_iteration_space(x)
×
UNCOV
18
    (isa(x, Expr) && (x.head === :(=) || x.head === :in)) || throw(SimdError("= or in expected"))
×
UNCOV
19
    length(x.args) == 2 || throw(SimdError("simd range syntax is wrong"))
×
UNCOV
20
    isa(x.args[1], Symbol) || throw(SimdError("simd loop index must be a symbol"))
×
UNCOV
21
    x.args # symbol, range
×
22
end
23

24
# reject invalid control flow statements in @simd loop body
UNCOV
25
function check_body!(x::Expr)
×
UNCOV
26
    if x.head === :break || x.head === :continue
×
UNCOV
27
        throw(SimdError("$(x.head) is not allowed inside a @simd loop body"))
×
UNCOV
28
    elseif x.head === :macrocall && x.args[1] === Symbol("@goto")
×
UNCOV
29
        throw(SimdError("@goto is not allowed inside a @simd loop body"))
×
30
    end
UNCOV
31
    for arg in x.args
×
UNCOV
32
        check_body!(arg)
×
UNCOV
33
    end
×
UNCOV
34
    return true
×
35
end
36
check_body!(x::QuoteNode) = check_body!(x.value)
×
37
check_body!(x) = true
×
38

39
# @simd splits a for loop into two loops: an outer scalar loop and
40
# an inner loop marked with :loopinfo. The simd_... functions define
41
# the splitting.
42
# Custom iterators that do not support random access cannot support
43
# vectorization. In order to be compatible with `@simd` annotated loops,
44
#they should override `simd_inner_length(v::MyIter, j) = 1`,
45
#`simd_outer_range(v::MyIter) = v`, and `simd_index(v::MyIter, j, i) = j`.
46

47
# Get range for outer loop.
UNCOV
48
simd_outer_range(r) = 0:0
×
49

50
# Get trip count for inner loop.
51
@inline simd_inner_length(r, j) = Base.length(r)
10✔
52

53
# Construct user-level element from original range, outer loop index j, and inner loop index i.
54
@inline simd_index(r, j, i) = (@inbounds ret = r[i+firstindex(r)]; ret)
517,341✔
55

56
# Compile Expr x in context of @simd.
57
function compile(x, ivdep)
58
    (isa(x, Expr) && x.head === :for) || throw(SimdError("for loop expected"))
59
    length(x.args) == 2 || throw(SimdError("1D for loop expected"))
60
    check_body!(x)
61

62
    var,range = parse_iteration_space(x.args[1])
63
    r = gensym("r") # Range value
64
    j = gensym("i") # Iteration variable for outer loop
65
    n = gensym("n") # Trip count for inner loop
66
    i = gensym("i") # Trip index for inner loop
67
    quote
68
        # Evaluate range value once, to enhance type and data flow analysis by optimizers.
69
        let $r = $range
47,700✔
70
            for $j in Base.simd_outer_range($r)
42,080✔
71
                let $n = Base.simd_inner_length($r,$j)
42,087✔
72
                    if zero($n) < $n
47,873✔
73
                        # Lower loop in way that seems to work best for LLVM 3.3 vectorizer.
74
                        let $i = zero($n)
42,080✔
75
                            while $i < $n
565,214✔
76
                                local $var = Base.simd_index($r,$j,$i)
517,341✔
77
                                $(x.args[2])        # Body of loop
517,349✔
78
                                $i += 1
517,341✔
79
                                $(Expr(:loopinfo, Symbol("julia.simdloop"), ivdep))  # Mark loop as SIMD loop
517,341✔
80
                            end
517,341✔
81
                        end
82
                    end
83
                end
84
            end
42,087✔
85
        end
86
        nothing
42,080✔
87
    end
88
end
89

90
"""
91
    @simd
92

93
Annotate a `for` loop to allow the compiler to take extra liberties to allow loop re-ordering
94

95
!!! warning
96
    This feature is experimental and could change or disappear in future versions of Julia.
97
    Incorrect use of the `@simd` macro may cause unexpected results.
98

99
The object iterated over in a `@simd for` loop should be a one-dimensional range.
100
By using `@simd`, you are asserting several properties of the loop:
101

102
* It is safe to execute iterations in arbitrary or overlapping order, with special consideration for reduction variables.
103
* Floating-point operations on reduction variables can be reordered or contracted, possibly causing different results than without `@simd`.
104

105
In many cases, Julia is able to automatically vectorize inner for loops without the use of `@simd`.
106
Using `@simd` gives the compiler a little extra leeway to make it possible in more situations. In
107
either case, your inner loop should have the following properties to allow vectorization:
108

109
* The loop must be an innermost loop
110
* The loop body must be straight-line code. Therefore, [`@inbounds`](@ref) is
111
    currently needed for all array accesses. The compiler can sometimes turn
112
    short `&&`, `||`, and `?:` expressions into straight-line code if it is safe
113
    to evaluate all operands unconditionally. Consider using the [`ifelse`](@ref)
114
    function instead of `?:` in the loop if it is safe to do so.
115
* Accesses must have a stride pattern and cannot be "gathers" (random-index
116
    reads) or "scatters" (random-index writes).
117
* The stride should be unit stride.
118

119
!!! note
120
    The `@simd` does not assert by default that the loop is completely free of loop-carried
121
    memory dependencies, which is an assumption that can easily be violated in generic code.
122
    If you are writing non-generic code, you can use `@simd ivdep for ... end` to also assert that:
123

124
* There exists no loop-carried memory dependencies
125
* No iteration ever waits on a previous iteration to make forward progress.
126
"""
127
macro simd(forloop)
128
    esc(compile(forloop, nothing))
129
end
130

131
macro simd(ivdep, forloop)
132
    if ivdep === :ivdep
133
        esc(compile(forloop, Symbol("julia.ivdep")))
134
    else
135
        throw(SimdError("Only ivdep is valid as the first argument to @simd"))
136
    end
137
end
138

139
end # module SimdLoop
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc