• 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

73.96
/base/ryu/shortest.jl
1
"""
2
    b, e10 = reduce_shortest(f[, maxsignif])
3

4
Reduce to shortest decimal representation where `abs(f) == b * 10^e10` and `b` is an
5
integer. If a `maxsignif` argument is provided, then `b < maxsignif`.
6
"""
7
@inline function reduce_shortest(f::T, maxsignif=nothing) where {T}
190,757✔
8
    U = uinttype(T)
×
9
    uf = reinterpret(U, f)
180,205✔
10
    m = uf & significand_mask(T)
180,205✔
11
    e = ((uf & exponent_mask(T)) >> significand_bits(T)) % Int
180,205✔
12

13
    ## Step 1
14
    #  mf * 2^ef == f
15
    mf = (one(U) << significand_bits(T)) | m
180,205✔
16
    ef = e - exponent_bias(T) - significand_bits(T)
180,205✔
17
    f_isinteger = mf & ((one(U) << -ef) - one(U)) == 0
180,205✔
18

19
    if ef > 0 || ef < -Base.significand_bits(T) || !f_isinteger
360,404✔
20
        # fixup subnormals
21
        if e == 0
163,643✔
22
            ef = 1 - exponent_bias(T) - significand_bits(T)
×
23
            mf = m
×
24
        end
25

26
        ## Step 2
27
        #  u * 2^e2 == (f + prevfloat(f))/2
28
        #  v * 2^e2 == f
29
        #  w * 2^e2 == (f + nextfloat(f))/2
30
        e2 = ef - 2
163,643✔
31
        mf_iseven = iseven(mf) # trailing bit of significand is zero
163,643✔
32

33
        v = U(4) * mf
163,643✔
34
        w = v + U(2)
163,643✔
35
        u_shift_half = m == 0 && e > 1 # if first element of binade, other than first normal one
163,643✔
36
        u = v - U(2) + u_shift_half
163,643✔
37

38
        ## Step 3
39
        #  a == floor(u * 2^e2 / 10^e10), exact if a_allzero
40
        #  b == floor(v * 2^e2 / 10^e10), exact if b_allzero
41
        #  c == floor(w * 2^e2 / 10^e10)
42
        a_allzero = false
×
43
        b_allzero = false
×
44
        b_lastdigit = 0x00
×
45
        if e2 >= 0
163,643✔
46
            q = log10pow2(e2) - (T == Float64 ? (e2 > 3) : 0)
6✔
47
            e10 = q
×
48
            k = pow5_inv_bitcount(T) + pow5bits(q) - 1
6✔
49
            i = -e2 + q + k
6✔
50
            a, b, c = mulshiftinvsplit(T, u, v, w, q, i)
6✔
51
            if T == Float32 || T == Float16
×
52
                if q != 0 && div(c - 1, 10) <= div(a, 10)
5✔
53
                    l = pow5_inv_bitcount(T) + pow5bits(q - 1) - 1
×
54
                    mul = pow5invsplit_lookup(T, q-1)
×
55
                    b_lastdigit = (mulshift(v, mul, -e2 + q - 1 + l) % 10) % UInt8
×
56
                end
57
            end
58
            if q <= qinvbound(T)
6✔
59
                if ((v % UInt32) - 5 * div(v, 5)) == 0
6✔
60
                    b_allzero = pow5(v, q)
3✔
61
                elseif mf_iseven
3✔
62
                    a_allzero = pow5(u, q)
2✔
63
                else
64
                    c -= pow5(w, q)
7✔
65
                end
66
            end
67
        else
68
            q = log10pow5(-e2) - (T == Float64 ? (-e2 > 1) : 0)
163,637✔
69
            e10 = q + e2
163,637✔
70
            i = -e2 - q
163,637✔
71
            k = pow5bits(i) - pow5_bitcount(T)
163,637✔
72
            j = q - k
163,637✔
73
            a, b, c = mulshiftsplit(T, u, v, w, i, j)
163,637✔
74
            if T == Float32 || T == Float16
×
75
                if q != 0 && div(c - 1, 10) <= div(a, 10)
61,177✔
76
                    j = q - 1 - (pow5bits(i + 1) - pow5_bitcount(T))
9,407✔
77
                    mul = pow5split_lookup(T, i+1)
9,407✔
78
                    b_lastdigit = (mulshift(v, mul, j) % 10) % UInt8
9,407✔
79
                end
80
            end
81
            if q <= 1
163,637✔
82
                b_allzero = true
×
83
                if mf_iseven
×
84
                    a_allzero = !u_shift_half
×
85
                else
86
                    c -= 1
×
87
                end
88
            elseif q < qbound(T)
163,637✔
89
                b_allzero = pow2(v, q - (T != Float64))
163,219✔
90
            end
91
        end
92

93
        ## Step 4: reduction
94
        if a_allzero || b_allzero
327,285✔
95
            # a) slow loop
96
            while true
19,583✔
97
                c_div10 = div(c, 10)
19,613✔
98
                a_div10 = div(a, 10)
19,609✔
99
                if c_div10 <= a_div10
19,613✔
100
                    break
1,148✔
101
                end
102
                a_mod10 = (a % UInt32) - UInt32(10) * (a_div10 % UInt32)
18,457✔
103
                b_div10 = div(b, 10)
18,457✔
104
                b_mod10 = (b % UInt32) - UInt32(10) * (b_div10 % UInt32)
18,457✔
105
                a_allzero &= a_mod10 == 0
18,435✔
106
                b_allzero &= b_lastdigit == 0
18,435✔
107
                b_lastdigit = b_mod10 % UInt8
18,435✔
108
                b = b_div10
×
109
                c = c_div10
×
110
                a = a_div10
×
111
                e10 += 1
18,435✔
112
            end
18,435✔
113
            if a_allzero
1,148✔
114
                while true
×
115
                    a_div10 = div(a, 10)
×
116
                    a_mod10 = (a % UInt32) - UInt32(10) * (a_div10 % UInt32)
×
117
                    if a_mod10 != 0 && (maxsignif === nothing || b < maxsignif)
×
118
                        break
×
119
                    end
120
                    c_div10 = div(c, 10)
×
121
                    b_div10 = div(b, 10)
×
122
                    b_mod10 = (b % UInt32) - UInt32(10) * (b_div10 % UInt32)
×
123
                    b_allzero &= b_lastdigit == 0
×
124
                    b_lastdigit = b_mod10 % UInt8
×
125
                    b = b_div10
×
126
                    c = c_div10
×
127
                    a = a_div10
×
128
                    e10 += 1
×
129
                end
×
130
            end
131
            if b_allzero && b_lastdigit == 5 && iseven(b)
1,148✔
132
                b_lastdigit = UInt8(4)
×
133
            end
134
            roundup = (b == a && (!mf_iseven || !a_allzero)) || b_lastdigit >= 5
2,295✔
135
        else
136
            # b) specialized for common case (99% Float64, 96% Float32)
137
            roundup = b_lastdigit >= 5
61,178✔
138
            c_div100 = div(c, 100)
223,673✔
139
            a_div100 = div(a, 100)
162,495✔
140
            if c_div100 > a_div100
223,673✔
141
                b_div100 = div(b, 100)
100,116✔
142
                b_mod100 = (b % UInt32) - UInt32(100) * (b_div100 % UInt32)
100,116✔
143
                roundup = b_mod100 >= 50
100,116✔
144
                b = b_div100
×
145
                c = c_div100
×
146
                a = a_div100
×
147
                e10 += 2
100,116✔
148
            end
149
            while true
410,972✔
150
                c_div10 = div(c, 10)
514,769✔
151
                a_div10 = div(a, 10)
466,405✔
152
                if c_div10 <= a_div10
514,769✔
153
                    break
162,495✔
154
                end
155
                b_div10 = div(b, 10)
250,070✔
156
                b_mod10 = (b % UInt32) - UInt32(10) * (b_div10 % UInt32)
250,070✔
157
                roundup = b_mod10 >= 5
248,477✔
158
                b = b_div10
×
159
                c = c_div10
×
160
                a = a_div10
×
161
                e10 += 1
248,477✔
162
            end
248,477✔
163
            roundup = (b == a || roundup)
216,335✔
164
        end
165
        if maxsignif !== nothing && b > maxsignif
215,477✔
166
            # reduce to max significant digits
167
            while true
1,095,003✔
168
                b_div10 = div(b, 10)
1,238,859✔
169
                b_mod10 = (b % UInt32) - UInt32(10) * (b_div10 % UInt32)
1,238,859✔
170
                if b <= maxsignif
1,238,859✔
171
                    break
139,267✔
172
                end
173
                b = b_div10
×
174
                roundup = (b_allzero && iseven(b)) ? b_mod10 > 5 : b_mod10 >= 5
1,911,472✔
175
                b_allzero &= b_mod10 == 0
955,736✔
176
                e10 += 1
955,736✔
177
            end
955,736✔
178
            b = b + roundup
195,247✔
179

180
            # remove trailing zeros
181
            while true
154,895✔
182
                b_div10 = div(b, 10)
217,205✔
183
                b_mod10 = (b % UInt32) - UInt32(10) * (b_div10 % UInt32)
217,205✔
184
                if b_mod10 != 0
154,895✔
185
                    break
139,267✔
186
                end
187
                b = b_div10
×
188
                e10 += 1
15,628✔
189
            end
154,895✔
190
        else
191
            b = b + roundup
169,239✔
192
        end
193
    else
194
        # c) specialized f an integer < 2^53
195
        b = mf >> -ef
16,562✔
196
        e10 = 0
×
197

198
        if maxsignif !== nothing && b > maxsignif
13,329✔
199
            b_allzero = true
×
200
            # reduce to max significant digits
201
            while true
×
202
                b_div10 = div(b, 10)
×
203
                b_mod10 = (b % UInt32) - UInt32(10) * (b_div10 % UInt32)
×
204
                if b <= maxsignif
×
205
                    break
×
206
                end
207
                b = b_div10
×
208
                roundup = (b_allzero && iseven(b)) ? b_mod10 > 5 : b_mod10 >= 5
×
209
                b_allzero &= b_mod10 == 0
×
210
                e10 += 1
×
211
            end
×
212
            b = b + roundup
×
213
        end
214
        while true
17,083✔
215
            b_div10 = div(b, 10)
17,083✔
216
            b_mod10 = (b % UInt32) - UInt32(10) * (b_div10 % UInt32)
17,083✔
217
            if b_mod10 != 0
17,083✔
218
                break
16,562✔
219
            end
220
            b = b_div10
×
221
            e10 += 1
521✔
222
        end
521✔
223
    end
224
    return b, e10
180,205✔
225
end
226

227
function writeshortest(buf::Vector{UInt8}, pos, x::T,
465,941✔
228
                       plus=false, space=false, hash=true,
229
                       precision=-1, expchar=UInt8('e'), padexp=false, decchar=UInt8('.'),
230
                       typed=false, compact=false) where {T}
231
    @assert 0 < pos <= length(buf)
465,941✔
232
    # special cases
233
    if x == 0
465,933✔
234
        if typed && x isa Float16
281,359✔
235
            @inbounds buf[pos] = UInt8('F')
2✔
236
            @inbounds buf[pos + 1] = UInt8('l')
2✔
237
            @inbounds buf[pos + 2] = UInt8('o')
2✔
238
            @inbounds buf[pos + 3] = UInt8('a')
2✔
239
            @inbounds buf[pos + 4] = UInt8('t')
2✔
240
            @inbounds buf[pos + 5] = UInt8('1')
2✔
241
            @inbounds buf[pos + 6] = UInt8('6')
2✔
242
            @inbounds buf[pos + 7] = UInt8('(')
2✔
243
            pos += 8
2✔
244
        end
245
        pos = append_sign(x, plus, space, buf, pos)
562,703✔
246
        @inbounds buf[pos] = UInt8('0')
281,359✔
247
        pos += 1
281,359✔
248
        if hash
281,359✔
249
            @inbounds buf[pos] = decchar
281,359✔
250
            pos += 1
281,359✔
251
        end
252
        if precision == -1
281,359✔
253
            @inbounds buf[pos] = UInt8('0')
281,359✔
254
            pos += 1
281,359✔
255
            if typed && x isa Float32
281,359✔
256
                @inbounds buf[pos] = UInt8('f')
360✔
257
                @inbounds buf[pos + 1] = UInt8('0')
360✔
258
                pos += 2
360✔
259
            end
260
            if typed && x isa Float16
281,359✔
261
                @inbounds buf[pos] = UInt8(')')
2✔
262
                pos += 1
2✔
263
            end
264
            return pos
281,359✔
265
        end
266
        while hash && precision > 1
×
267
            @inbounds buf[pos] = UInt8('0')
×
268
            pos += 1
×
269
            precision -= 1
×
270
        end
×
271
        if typed && x isa Float32
×
272
            @inbounds buf[pos] = UInt8('f')
×
273
            @inbounds buf[pos + 1] = UInt8('0')
×
274
            pos += 2
×
275
        end
276
        if typed && x isa Float16
×
277
            @inbounds buf[pos] = UInt8(')')
×
278
            pos += 1
×
279
        end
280
        return pos
×
281
    elseif isnan(x)
184,574✔
282
        pos = append_sign(x, plus, space, buf, pos)
3,582✔
283
        @inbounds buf[pos] = UInt8('N')
1,791✔
284
        @inbounds buf[pos + 1] = UInt8('a')
1,791✔
285
        @inbounds buf[pos + 2] = UInt8('N')
1,791✔
286
        if typed
1,791✔
287
            if x isa Float32
×
288
                @inbounds buf[pos + 3] = UInt8('3')
2✔
289
                @inbounds buf[pos + 4] = UInt8('2')
2✔
290
            elseif x isa Float16
×
291
                @inbounds buf[pos + 3] = UInt8('1')
2✔
292
                @inbounds buf[pos + 4] = UInt8('6')
2✔
293
            end
294
        end
295
        return pos + 3 + (typed && x isa Union{Float32, Float16} ? 2 : 0)
1,791✔
296
    elseif !isfinite(x)
182,783✔
297
        pos = append_sign(x, plus, space, buf, pos)
4,364✔
298
        @inbounds buf[pos] = UInt8('I')
2,578✔
299
        @inbounds buf[pos + 1] = UInt8('n')
2,578✔
300
        @inbounds buf[pos + 2] = UInt8('f')
2,578✔
301
        if typed
2,578✔
302
            if x isa Float32
×
303
                @inbounds buf[pos + 3] = UInt8('3')
2✔
304
                @inbounds buf[pos + 4] = UInt8('2')
2✔
305
            elseif x isa Float16
×
306
                @inbounds buf[pos + 3] = UInt8('1')
3✔
307
                @inbounds buf[pos + 4] = UInt8('6')
3✔
308
            end
309
        end
310
        return pos + 3 + (typed && x isa Union{Float32, Float16} ? 2 : 0)
2,578✔
311
    end
312

313
    output, nexp = reduce_shortest(x, compact ? 999_999 : nothing)
183,359✔
314

315
    if typed && x isa Float16
180,205✔
316
        @inbounds buf[pos] = UInt8('F')
6✔
317
        @inbounds buf[pos + 1] = UInt8('l')
6✔
318
        @inbounds buf[pos + 2] = UInt8('o')
6✔
319
        @inbounds buf[pos + 3] = UInt8('a')
6✔
320
        @inbounds buf[pos + 4] = UInt8('t')
6✔
321
        @inbounds buf[pos + 5] = UInt8('1')
6✔
322
        @inbounds buf[pos + 6] = UInt8('6')
6✔
323
        @inbounds buf[pos + 7] = UInt8('(')
6✔
324
        pos += 8
6✔
325
    end
326
    pos = append_sign(x, plus, space, buf, pos)
305,759✔
327

328
    olength = decimallength(output)
297,412✔
329
    exp_form = true
×
330
    pt = nexp + olength
180,205✔
331
    if -4 < pt <= (precision == -1 ? (T == Float16 ? 3 : 6) : precision) &&
196,774✔
332
        !(pt >= olength && abs(mod(x + 0.05, 10^(pt - olength)) - 0.05) > 0.05)
333
        exp_form = false
×
334
        if pt <= 0
177,415✔
335
            @inbounds buf[pos] = UInt8('0')
133,748✔
336
            pos += 1
133,748✔
337
            @inbounds buf[pos] = decchar
133,748✔
338
            pos += 1
133,748✔
339
            for _ = 1:abs(pt)
161,406✔
340
                @inbounds buf[pos] = UInt8('0')
30,528✔
341
                pos += 1
30,528✔
342
            end
33,398✔
343
        # elseif pt >= olength
344
            # nothing to do at this point
345
        # else
346
            # nothing to do at this point
347
        end
348
    else
349
        # make space for decchar
350
        pos += 1
2,790✔
351
    end
352

353
    append_c_digits(olength, output, buf, pos)
241,045✔
354

355
    if !exp_form
180,205✔
356
        if pt <= 0
177,415✔
357
            pos += olength
133,748✔
358
            precision -= olength
133,748✔
359
        elseif pt >= olength
43,667✔
360
            pos += olength
16,565✔
361
            precision -= olength
16,565✔
362
            for _ = 1:nexp
16,959✔
363
                @inbounds buf[pos] = UInt8('0')
515✔
364
                pos += 1
515✔
365
                precision -= 1
515✔
366
            end
636✔
367
            if hash
16,565✔
368
                @inbounds buf[pos] = decchar
16,565✔
369
                pos += 1
16,565✔
370
                if precision < 0
16,565✔
371
                    @inbounds buf[pos] = UInt8('0')
16,565✔
372
                    pos += 1
16,565✔
373
                end
374
            end
375
        else
376
            pointoff = olength - abs(nexp)
27,102✔
377
            # shift bytes after pointoff to make room for decchar
378
            ptr = pointer(buf)
27,102✔
379
            memmove(ptr + pos + pointoff, ptr + pos + pointoff - 1, olength - pointoff + 1)
27,102✔
380
            @inbounds buf[pos + pointoff] = decchar
27,102✔
381
            pos += olength + 1
27,102✔
382
            precision -= olength
27,102✔
383
        end
384
        if hash
177,415✔
385
            while precision > 0
177,415✔
386
                @inbounds buf[pos] = UInt8('0')
×
387
                pos += 1
×
388
                precision -= 1
×
389
            end
×
390
        end
391
        if typed && x isa Float32
177,415✔
392
            @inbounds buf[pos] = UInt8('f')
1,734✔
393
            @inbounds buf[pos + 1] = UInt8('0')
1,734✔
394
            pos += 2
113,266✔
395
        end
396
    else
397
        # move leading digit into place
398
        @inbounds buf[pos - 1] = buf[pos]
2,790✔
399
        if olength > 1 || hash
4,558✔
400
            @inbounds buf[pos] = decchar
2,790✔
401
            pos += olength
2,790✔
402
            precision -= olength
2,790✔
403
        end
404
        if hash
2,790✔
405
            if olength == 1
2,790✔
406
                @inbounds buf[pos] = UInt8('0')
1,768✔
407
                pos += 1
1,768✔
408
            end
409
            while precision > 0
2,790✔
410
                @inbounds buf[pos] = UInt8('0')
×
411
                pos += 1
×
412
                precision -= 1
×
413
            end
×
414
        end
415

416
        @inbounds buf[pos] = expchar
2,790✔
417
        pos += 1
2,790✔
418
        exp2 = nexp + olength - 1
2,790✔
419
        if exp2 < 0
2,790✔
420
            @inbounds buf[pos] = UInt8('-')
2,774✔
421
            pos += 1
2,774✔
422
            exp2 = -exp2
2,774✔
423
        elseif padexp
16✔
424
            @inbounds buf[pos] = UInt8('+')
×
425
            pos += 1
×
426
        end
427

428
        if exp2 >= 100
2,790✔
429
            c = exp2 % 10
6✔
430
            @inbounds d100 = DIGIT_TABLE16[(div(exp2, 10) % Int) + 1]
6✔
431
            @inbounds buf[pos] = d100 % UInt8
6✔
432
            @inbounds buf[pos + 1] = (d100 >> 0x8) % UInt8
6✔
433
            @inbounds buf[pos + 2] = UInt8('0') + (c % UInt8)
6✔
434
            pos += 3
6✔
435
        elseif exp2 >= 10
2,784✔
436
            @inbounds d100 = DIGIT_TABLE16[(exp2 % Int) + 1]
725✔
437
            @inbounds buf[pos] = d100 % UInt8
725✔
438
            @inbounds buf[pos + 1] = (d100 >> 0x8) % UInt8
725✔
439
            pos += 2
725✔
440
        else
441
            if padexp
2,059✔
442
                @inbounds buf[pos] = UInt8('0')
×
443
                pos += 1
×
444
            end
445
            @inbounds buf[pos] = UInt8('0') + (exp2 % UInt8)
2,059✔
446
            pos += 1
2,059✔
447
        end
448
    end
449
    if typed && x isa Float16
180,205✔
450
        @inbounds buf[pos] = UInt8(')')
6✔
451
        pos += 1
6✔
452
    end
453

454
    return pos
180,205✔
455
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