Skip to content

Commit

Permalink
add @constprop for compatibility to 1.7
Browse files Browse the repository at this point in the history
This also adds a depwarn for `@aggressive_constprop`, which seemed
sensible to me, given that it will be removed in 1.8.

replaces #42125
  • Loading branch information
simeonschaub committed Sep 17, 2021
1 parent c9f4de0 commit e4ae48f
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 20 deletions.
24 changes: 12 additions & 12 deletions base/char.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ represents a valid Unicode character.
"""
Char

@aggressive_constprop (::Type{T})(x::Number) where {T<:AbstractChar} = T(UInt32(x))
@aggressive_constprop AbstractChar(x::Number) = Char(x)
@aggressive_constprop (::Type{T})(x::AbstractChar) where {T<:Union{Number,AbstractChar}} = T(codepoint(x))
@aggressive_constprop (::Type{T})(x::AbstractChar) where {T<:Union{Int32,Int64}} = codepoint(x) % T
@constprop :aggressive (::Type{T})(x::Number) where {T<:AbstractChar} = T(UInt32(x))
@constprop :aggressive AbstractChar(x::Number) = Char(x)
@constprop :aggressive (::Type{T})(x::AbstractChar) where {T<:Union{Number,AbstractChar}} = T(codepoint(x))
@constprop :aggressive (::Type{T})(x::AbstractChar) where {T<:Union{Int32,Int64}} = codepoint(x) % T
(::Type{T})(x::T) where {T<:AbstractChar} = x

"""
Expand All @@ -75,7 +75,7 @@ return a different-sized integer (e.g. `UInt8`).
"""
function codepoint end

@aggressive_constprop codepoint(c::Char) = UInt32(c)
@constprop :aggressive codepoint(c::Char) = UInt32(c)

struct InvalidCharError{T<:AbstractChar} <: Exception
char::T
Expand Down Expand Up @@ -124,7 +124,7 @@ See also [`decode_overlong`](@ref) and [`show_invalid`](@ref).
"""
isoverlong(c::AbstractChar) = false

@aggressive_constprop function UInt32(c::Char)
@constprop :aggressive function UInt32(c::Char)
# TODO: use optimized inline LLVM
u = bitcast(UInt32, c)
u < 0x80000000 && return u >> 24
Expand All @@ -148,7 +148,7 @@ that support overlong encodings should implement `Base.decode_overlong`.
"""
function decode_overlong end

@aggressive_constprop function decode_overlong(c::Char)
@constprop :aggressive function decode_overlong(c::Char)
u = bitcast(UInt32, c)
l1 = leading_ones(u)
t0 = trailing_zeros(u) & 56
Expand All @@ -158,7 +158,7 @@ function decode_overlong end
((u & 0x007f0000) >> 4) | ((u & 0x7f000000) >> 6)
end

@aggressive_constprop function Char(u::UInt32)
@constprop :aggressive function Char(u::UInt32)
u < 0x80 && return bitcast(Char, u << 24)
u < 0x00200000 || throw_code_point_err(u)
c = ((u << 0) & 0x0000003f) | ((u << 2) & 0x00003f00) |
Expand All @@ -169,14 +169,14 @@ end
bitcast(Char, c)
end

@aggressive_constprop @noinline UInt32_cold(c::Char) = UInt32(c)
@aggressive_constprop function (T::Union{Type{Int8},Type{UInt8}})(c::Char)
@constprop :aggressive @noinline UInt32_cold(c::Char) = UInt32(c)
@constprop :aggressive function (T::Union{Type{Int8},Type{UInt8}})(c::Char)
i = bitcast(Int32, c)
i 0 ? ((i >>> 24) % T) : T(UInt32_cold(c))
end

@aggressive_constprop @noinline Char_cold(b::UInt32) = Char(b)
@aggressive_constprop function Char(b::Union{Int8,UInt8})
@constprop :aggressive @noinline Char_cold(b::UInt32) = Char(b)
@constprop :aggressive function Char(b::Union{Int8,UInt8})
0 b 0x7f ? bitcast(Char, (b % UInt32) << 24) : Char_cold(UInt32(b))
end

Expand Down
14 changes: 14 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -262,4 +262,18 @@ end
# This function was marked as experimental and not exported.
@deprecate catch_stack(task=current_task(); include_bt=true) current_exceptions(task; backtrace=include_bt) false

"""
@aggressive_constprop ex
@aggressive_constprop(ex)
`@aggressive_constprop` requests more aggressive interprocedural constant
propagation for the annotated function. For a method where the return type
depends on the value of the arguments, this can yield improved inference results
at the cost of additional compile time.
"""
macro aggressive_constprop(ex)
depwarn("use `@constprop :aggressive ex` instead of `@aggressive_constprop ex`", :var"@aggressive_constprop")
esc(isa(ex, Expr) ? pushmeta!(ex, :aggressive_constprop) : ex)
end

# END 1.7 deprecations
25 changes: 17 additions & 8 deletions base/expr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -240,16 +240,25 @@ macro pure(ex)
end

"""
@aggressive_constprop ex
@aggressive_constprop(ex)
@constprop setting ex
@constprop(setting, ex)
`@aggressive_constprop` requests more aggressive interprocedural constant
propagation for the annotated function. For a method where the return type
depends on the value of the arguments, this can yield improved inference results
at the cost of additional compile time.
`@constprop` controls the mode of interprocedural constant propagation for the
annotated function. Only `:aggressive` is supported in 1.7:
- `@constprop :aggressive ex`: apply constant propagation aggressively.
For a method where the return type depends on the value of the arguments,
this can yield improved inference results at the cost of additional compile time.
`@constprop :none ex` is a no-op, but is allowed for compatibility with Julia 1.8.
"""
macro aggressive_constprop(ex)
esc(isa(ex, Expr) ? pushmeta!(ex, :aggressive_constprop) : ex)
macro constprop(setting, ex)
if isa(setting, QuoteNode)
setting = setting.value
end
setting === :aggressive && return esc(isa(ex, Expr) ? pushmeta!(ex, :aggressive_constprop) : ex)
setting === :none && return esc(ex)
throw(ArgumentError("@constprop $setting not supported"))
end

"""
Expand Down
6 changes: 6 additions & 0 deletions test/compiler/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3172,14 +3172,20 @@ f_inf_error_bottom(x::Vector) = isempty(x) ? error(x[1]) : x
# @aggressive_constprop
@noinline g_nonaggressive(y, x) = Val{x}()
@noinline @Base.aggressive_constprop g_aggressive(y, x) = Val{x}()
@noinline @Base.constprop :none g_nonaggressive2(y, x) = Val{x}()
@noinline @Base.constprop :aggressive g_aggressive2(y, x) = Val{x}()

f_nonaggressive(x) = g_nonaggressive(x, 1)
f_aggressive(x) = g_aggressive(x, 1)
f_nonaggressive2(x) = g_nonaggressive2(x, 1)
f_aggressive2(x) = g_aggressive2(x, 1)

# The first test just makes sure that improvements to the compiler don't
# render the annotation effectless.
@test Base.return_types(f_nonaggressive, Tuple{Int})[1] == Val
@test Base.return_types(f_aggressive, Tuple{Int})[1] == Val{1}
@test Base.return_types(f_nonaggressive2, Tuple{Int})[1] == Val
@test Base.return_types(f_aggressive2, Tuple{Int})[1] == Val{1}

function splat_lotta_unions()
a = Union{Tuple{Int},Tuple{String,Vararg{Int}},Tuple{Int,Vararg{Int}}}[(2,)][1]
Expand Down

0 comments on commit e4ae48f

Please sign in to comment.