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

JuliaLang / julia / #37632

26 Sep 2023 06:44AM UTC coverage: 86.999% (-0.9%) from 87.914%
#37632

push

local

web-flow
inference: make `throw` block deoptimization concrete-eval friendly (#49235)

The deoptimization can sometimes destroy the effects analysis and
disable [semi-]concrete evaluation that is otherwise possible. This is
because the deoptimization was designed with the type domain
profitability in mind (#35982), and hasn't been adequately considering
the effects domain.

This commit makes the deoptimization aware of the effects domain more
and enables the `throw` block deoptimization only when the effects
already known to be ineligible for concrete-evaluation.

In our current effect system, `ALWAYS_FALSE`/`false` means that the
effect can not be refined to `ALWAYS_TRUE`/`true` anymore (unless given
user annotation later). Therefore we can enable the `throw` block
deoptimization without hindering the chance of concrete-evaluation when
any of the following conditions are met:
- `effects.consistent === ALWAYS_FALSE`
- `effects.effect_free === ALWAYS_FALSE`
- `effects.terminates === false`
- `effects.nonoverlayed === false`

Here are some numbers:

| Metric | master | this commit | #35982 reverted (set
`unoptimize_throw_blocks=false`) |

|-------------------------|-----------|-------------|--------------------------------------------|
| Base (seconds) | 15.579300 | 15.206645 | 15.296319 |
| Stdlibs (seconds) | 17.919013 | 17.667094 | 17.738128 |
| Total (seconds) | 33.499279 | 32.874737 | 33.035448 |
| Precompilation (seconds) | 49.967516 | 49.421121 | 49.999998 |
| First time `plot(rand(10,3))` [^1] | `2.476678 seconds (11.74 M
allocations)` | `2.430355 seconds (11.77 M allocations)` | `2.514874
seconds (11.64 M allocations)` |
| First time `solve(prob, QNDF())(5.0)` [^2] | `4.469492 seconds (15.32
M allocations)` | `4.499217 seconds (15.41 M allocations)` | `4.470772
seconds (15.38 M allocations)` |

[^1]: With disabling precompilation of Plots.jl.
[^2]: With disabling precompilation of OrdinaryDiffEq.

These numbers ma... (continued)

7 of 7 new or added lines in 1 file covered. (100.0%)

73407 of 84377 relevant lines covered (87.0%)

11275130.05 hits per line

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

75.84
/base/ryu/fixed.jl
1
function writefixed(buf, pos, v::T,
2,494✔
2
    precision=-1, plus=false, space=false, hash=false,
3
    decchar=UInt8('.'), trimtrailingzeros=false) where {T <: Base.IEEEFloat}
4
    @assert 0 < pos <= length(buf)
2,494✔
5
    startpos = pos
×
6
    x = Float64(v)
×
7
    pos = append_sign(x, plus, space, buf, pos)
2,522✔
8

9
    # special cases
10
    if x == 0
1,279✔
11
        buf[pos] = UInt8('0')
148✔
12
        pos += 1
148✔
13
        if precision > 0 && !trimtrailingzeros
148✔
14
            buf[pos] = decchar
145✔
15
            pos += 1
145✔
16
            for _ = 1:precision
290✔
17
                buf[pos] = UInt8('0')
255✔
18
                pos += 1
255✔
19
            end
365✔
20
        elseif hash
3✔
21
            buf[pos] = decchar
×
22
            pos += 1
×
23
        end
24
        return pos
148✔
25
    elseif isnan(x)
1,131✔
26
        buf[pos] = UInt8('N')
5✔
27
        buf[pos + 1] = UInt8('a')
5✔
28
        buf[pos + 2] = UInt8('N')
5✔
29
        return pos + 3
5✔
30
    elseif !isfinite(x)
1,126✔
31
        buf[pos] = UInt8('I')
7✔
32
        buf[pos + 1] = UInt8('n')
7✔
33
        buf[pos + 2] = UInt8('f')
7✔
34
        return pos + 3
7✔
35
    end
36

37
    bits = Core.bitcast(UInt64, x)
1,119✔
38
    mant = bits & MANTISSA_MASK
1,119✔
39
    exp = Int((bits >> 52) & EXP_MASK)
1,119✔
40

41
    if exp == 0 # subnormal
1,119✔
42
        e2 = 1 - 1023 - 52
×
43
        m2 = mant
×
44
    else
45
        e2 = exp - 1023 - 52
1,119✔
46
        m2 = (Int64(1) << 52) | mant
1,119✔
47
    end
48
    nonzero = false
1,119✔
49
    if e2 >= -52
1,119✔
50
        idx = e2 < 0 ? 0 : indexforexp(e2)
897✔
51
        p10bits = pow10bitsforindex(idx)
893✔
52
        len = lengthforindex(idx)
893✔
53
        i = len - 1
893✔
54
        while i >= 0
2,734✔
55
            j = p10bits - e2
1,841✔
56
            mula, mulb, mulc = POW10_SPLIT[POW10_OFFSET[idx + 1] + i + 1]
1,841✔
57
            digits = mulshiftmod1e9(m2 << 8, mula, mulb, mulc, j + 8)
1,841✔
58
            if nonzero
1,841✔
59
                pos = append_nine_digits(digits, buf, pos)
56✔
60
            elseif digits != 0
1,785✔
61
                olength = decimallength(digits)
1,786✔
62
                pos = append_c_digits(olength, digits, buf, pos)
893✔
63
                nonzero = true
×
64
            end
65
            i -= 1
1,841✔
66
        end
1,841✔
67
    end
68
    if !nonzero
1,119✔
69
        buf[pos] = UInt8('0')
226✔
70
        pos += 1
226✔
71
    end
72
    hasfractional = false
1,119✔
73
    if precision > 0 || hash
1,160✔
74
        buf[pos] = decchar
1,104✔
75
        pos += 1
1,104✔
76
        hasfractional = true
×
77
    end
78
    if e2 < 0
1,119✔
79
        idx = div(-e2, 16)
1,115✔
80
        blocks = div(precision, 9) + 1
1,115✔
81
        roundUp = 0
×
82
        i = 0
×
83
        if blocks <= MIN_BLOCK_2[idx + 1]
1,115✔
84
            i = blocks
×
85
            for _ = 1:precision
×
86
                buf[pos] = UInt8('0')
×
87
                pos += 1
×
88
            end
×
89
        elseif i < MIN_BLOCK_2[idx + 1]
1,115✔
90
            i = MIN_BLOCK_2[idx + 1]
×
91
            for _ = 1:(9 * i)
×
92
                buf[pos] = UInt8('0')
×
93
                pos += 1
×
94
            end
×
95
        end
96
        while i < blocks
1,130✔
97
            j = 120 + (-e2 - 16 * idx)
1,130✔
98
            p = POW10_OFFSET_2[idx + 1] + UInt32(i) - MIN_BLOCK_2[idx + 1]
1,130✔
99
            if p >= POW10_OFFSET_2[idx + 2]
1,130✔
100
                for _ = 1:(precision - 9 * i)
×
101
                    buf[pos] = UInt8('0')
×
102
                    pos += 1
×
103
                end
×
104
                break
×
105
            end
106
            mula, mulb, mulc = POW10_SPLIT_2[p + 1]
1,130✔
107
            digits = mulshiftmod1e9(m2 << 8, mula, mulb, mulc, j + 8)
1,130✔
108
            if i < blocks - 1
1,130✔
109
                pos = append_nine_digits(digits, buf, pos)
15✔
110
            else
111
                maximum = precision - 9 * i
1,115✔
112
                lastDigit = 0
×
113
                k = 0
×
114
                while k < 9 - maximum
9,023✔
115
                    # global digits, lastDigit, k
116
                    lastDigit = digits % 10
14,701✔
117
                    digits = div(digits, 10)
14,701✔
118
                    k += 1
7,908✔
119
                end
7,908✔
120
                if lastDigit != 5
2,230✔
121
                    roundUp = lastDigit > 5 ? 1 : 0
2,030✔
122
                else
123
                    requiredTwos = -e2 - precision - 1
100✔
124
                    trailingZeros = requiredTwos <= 0 || (requiredTwos < 60 && pow2(m2, requiredTwos))
200✔
125
                    roundUp = trailingZeros ? 2 : 1 # 2 means round only if odd
100✔
126
                end
127
                if maximum > 0
1,115✔
128
                    pos = append_c_digits(maximum, digits, buf, pos)
2,132✔
129
                end
130
                break
1,115✔
131
            end
132
            i += 1
15✔
133
        end
15✔
134
        if roundUp != 0
1,115✔
135
            roundPos = pos
×
136
            dotPos = 1
×
137
            while true
532✔
138
                roundPos -= 1
532✔
139
                if roundPos == (startpos - 1) || (buf[roundPos] == UInt8('-')) || (plus && buf[roundPos] == UInt8('+')) || (space && buf[roundPos] == UInt8(' '))
1,061✔
140
                    buf[pos] = UInt8('0')
5✔
141
                    buf[roundPos + 1] = UInt8('1')
5✔
142
                    if dotPos > 1
5✔
143
                        buf[dotPos] = UInt8('0')
5✔
144
                        buf[dotPos + 1] = decchar
5✔
145
                        hasfractional = true
×
146
                    end
147
                    pos += 1
5✔
148
                    break
×
149
                end
150
                c = roundPos > 0 ? buf[roundPos] : 0x00
527✔
151
                if c == decchar
527✔
152
                    dotPos = roundPos
×
153
                    continue
15✔
154
                elseif c == UInt8('9')
512✔
155
                    buf[roundPos] = UInt8('0')
71✔
156
                    roundUp = 1
×
157
                    continue
71✔
158
                else
159
                    if roundUp == 2 && UInt8(c) % 2 == 0
441✔
160
                        break
5✔
161
                    end
162
                    buf[roundPos] = c + 1
436✔
163
                    break
436✔
164
                end
165
            end
1,201✔
166
        end
167
    else
168
        for _ = 1:precision
4✔
169
            buf[pos] = UInt8('0')
×
170
            pos += 1
×
171
        end
×
172
    end
173
    if trimtrailingzeros && hasfractional
1,119✔
174
        while buf[pos - 1] == UInt8('0')
97✔
175
            pos -= 1
67✔
176
        end
67✔
177
        if buf[pos - 1] == decchar && !hash
30✔
178
            pos -= 1
13✔
179
        end
180
    end
181
    return pos
1,119✔
182
end
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

© 2025 Coveralls, Inc