Skip to content

Commit

Permalink
Merge branch 'master' into rationalize_irrational
Browse files Browse the repository at this point in the history
  • Loading branch information
nsajko authored Feb 4, 2025
2 parents 7609e3c + 79ce168 commit eb44451
Show file tree
Hide file tree
Showing 32 changed files with 420 additions and 202 deletions.
4 changes: 4 additions & 0 deletions Compiler/src/ssair/passes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1511,6 +1511,10 @@ function sroa_pass!(ir::IRCode, inlining::Union{Nothing,InliningState}=nothing)
used_ssas[x.id] -= 1
end
ir = complete(compact)
# remove any use that has been optimized away by the DCE
for (intermediaries, defuse) in values(defuses)
filter!(x -> ir[SSAValue(x.idx)][:stmt] !== nothing, defuse.uses)
end
sroa_mutables!(ir, defuses, used_ssas, lazydomtree, inlining)
return ir
else
Expand Down
14 changes: 14 additions & 0 deletions Compiler/src/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2454,6 +2454,9 @@ const _SPECIAL_BUILTINS = Any[
Core._apply_iterate,
]

# Types compatible with fpext/fptrunc
const CORE_FLOAT_TYPES = Union{Core.BFloat16, Float16, Float32, Float64}

function isdefined_effects(𝕃::AbstractLattice, argtypes::Vector{Any})
# consistent if the first arg is immutable
na = length(argtypes)
Expand Down Expand Up @@ -2867,6 +2870,17 @@ function intrinsic_exct(𝕃::AbstractLattice, f::IntrinsicFunction, argtypes::V
if !(isprimitivetype(ty) && isprimitivetype(xty))
return ErrorException
end

# fpext and fptrunc have further restrictions on the allowed types.
if f === Intrinsics.fpext &&
!(ty <: CORE_FLOAT_TYPES && xty <: CORE_FLOAT_TYPES && Core.sizeof(ty) > Core.sizeof(xty))
return ErrorException
end
if f === Intrinsics.fptrunc &&
!(ty <: CORE_FLOAT_TYPES && xty <: CORE_FLOAT_TYPES && Core.sizeof(ty) < Core.sizeof(xty))
return ErrorException
end

return Union{}
end

Expand Down
11 changes: 11 additions & 0 deletions Compiler/test/effects.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1384,3 +1384,14 @@ end |> Compiler.is_nothrow
@test Base.infer_effects() do
@ccall unsafecall()::Cvoid
end == Compiler.EFFECTS_UNKNOWN

# fpext
@test Compiler.intrinsic_nothrow(Core.Intrinsics.fpext, Any[Type{Float32}, Float16])
@test Compiler.intrinsic_nothrow(Core.Intrinsics.fpext, Any[Type{Float64}, Float16])
@test Compiler.intrinsic_nothrow(Core.Intrinsics.fpext, Any[Type{Float64}, Float32])
@test !Compiler.intrinsic_nothrow(Core.Intrinsics.fpext, Any[Type{Float16}, Float16])
@test !Compiler.intrinsic_nothrow(Core.Intrinsics.fpext, Any[Type{Float16}, Float32])
@test !Compiler.intrinsic_nothrow(Core.Intrinsics.fpext, Any[Type{Float32}, Float32])
@test !Compiler.intrinsic_nothrow(Core.Intrinsics.fpext, Any[Type{Float32}, Float64])
@test !Compiler.intrinsic_nothrow(Core.Intrinsics.fpext, Any[Type{Int32}, Float16])
@test !Compiler.intrinsic_nothrow(Core.Intrinsics.fpext, Any[Type{Float32}, Int16])
12 changes: 12 additions & 0 deletions Compiler/test/irpasses.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2030,3 +2030,15 @@ let code = Any[
ir = Compiler.domsort_ssa!(ir, domtree)
Compiler.verify_ir(ir)
end

# https://github.com/JuliaLang/julia/issues/57141
# don't eliminate `setfield!` when the field is to be used
let src = code_typed1(()) do
ref = Ref{Any}()
ref[] = 0
@assert isdefined(ref, :x)
inner() = ref[] + 1
(inner(), ref[])
end
@test count(iscall((src, setfield!)), src.code) == 1
end
2 changes: 1 addition & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Language changes
behavior. Infinite loops that actually do things (e.g. have side effects
or sleep) were never and are still not undefined behavior. ([#52999])

- It is now an error to mark a symbol as both `public` and `export`ed.
- It is now an error to mark a binding as both `public` and `export`ed.
([#53664])

Compiler/Runtime improvements
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.12.0-DEV
1.13.0-DEV
2 changes: 1 addition & 1 deletion base/Base_compiler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -234,13 +234,13 @@ include("abstractarray.jl")
include("baseext.jl")

include("c.jl")
include("ntuple.jl")
include("abstractset.jl")
include("bitarray.jl")
include("bitset.jl")
include("abstractdict.jl")
include("iddict.jl")
include("idset.jl")
include("ntuple.jl")
include("iterators.jl")
using .Iterators: zip, enumerate, only
using .Iterators: Flatten, Filter, product # for generators
Expand Down
21 changes: 0 additions & 21 deletions base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -777,27 +777,6 @@ struct GeneratedFunctionStub
spnames::SimpleVector
end

# invoke and wrap the results of @generated expression
function (g::GeneratedFunctionStub)(world::UInt, source::LineNumberNode, @nospecialize args...)
# args is (spvals..., argtypes...)
body = g.gen(args...)
file = source.file
file isa Symbol || (file = :none)
lam = Expr(:lambda, Expr(:argnames, g.argnames...).args,
Expr(:var"scope-block",
Expr(:block,
source,
Expr(:meta, :push_loc, file, :var"@generated body"),
Expr(:return, body),
Expr(:meta, :pop_loc))))
spnames = g.spnames
if spnames === svec()
return lam
else
return Expr(Symbol("with-static-parameters"), lam, spnames...)
end
end

# If the generator is a subtype of this trait, inference caches the generated unoptimized
# code, sacrificing memory space to improve the performance of subsequent inferences.
# This tradeoff is not appropriate in general cases (e.g., for `GeneratedFunctionStub`s
Expand Down
43 changes: 43 additions & 0 deletions base/expr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1654,3 +1654,46 @@ end
function quoted(@nospecialize(x))
return is_self_quoting(x) ? x : QuoteNode(x)
end

# Implementation of generated functions
function generated_body_to_codeinfo(ex::Expr, defmod::Module, isva::Bool)
ci = ccall(:jl_expand, Any, (Any, Any), ex, defmod)
if !isa(ci, CodeInfo)
if isa(ci, Expr) && ci.head === :error
error("syntax: $(ci.args[1])")
end
error("The function body AST defined by this @generated function is not pure. This likely means it contains a closure, a comprehension or a generator.")
end
ci.isva = isva
code = ci.code
bindings = IdSet{Core.Binding}()
for i = 1:length(code)
stmt = code[i]
if isa(stmt, GlobalRef)
push!(bindings, convert(Core.Binding, stmt))
end
end
if !isempty(bindings)
ci.edges = Core.svec(bindings...)
end
return ci
end

# invoke and wrap the results of @generated expression
function (g::Core.GeneratedFunctionStub)(world::UInt, source::Method, @nospecialize args...)
# args is (spvals..., argtypes...)
body = g.gen(args...)
file = source.file
file isa Symbol || (file = :none)
lam = Expr(:lambda, Expr(:argnames, g.argnames...).args,
Expr(:var"scope-block",
Expr(:block,
LineNumberNode(Int(source.line), source.file),
Expr(:meta, :push_loc, file, :var"@generated body"),
Expr(:return, body),
Expr(:meta, :pop_loc))))
spnames = g.spnames
return generated_body_to_codeinfo(spnames === Core.svec() ? lam : Expr(Symbol("with-static-parameters"), lam, spnames...),
typename(typeof(g.gen)).module,
source.isva)
end
22 changes: 12 additions & 10 deletions base/invalidation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -93,26 +93,28 @@ function scan_edge_list(ci::Core.CodeInstance, binding::Core.Binding)
end

function invalidate_method_for_globalref!(gr::GlobalRef, method::Method, invalidated_bpart::Core.BindingPartition, new_max_world::UInt)
invalidate_all = false
binding = convert(Core.Binding, gr)
if isdefined(method, :source)
src = _uncompressed_ir(method)
binding = convert(Core.Binding, gr)
old_stmts = src.code
invalidate_all = should_invalidate_code_for_globalref(gr, src)
for mi in specializations(method)
isdefined(mi, :cache) || continue
ci = mi.cache
while true
if ci.max_world > new_max_world && (invalidate_all || scan_edge_list(ci, binding))
ccall(:jl_invalidate_code_instance, Cvoid, (Any, UInt), ci, new_max_world)
end
isdefined(ci, :next) || break
ci = ci.next
end
for mi in specializations(method)
isdefined(mi, :cache) || continue
ci = mi.cache
while true
if ci.max_world > new_max_world && (invalidate_all || scan_edge_list(ci, binding))
ccall(:jl_invalidate_code_instance, Cvoid, (Any, UInt), ci, new_max_world)
end
isdefined(ci, :next) || break
ci = ci.next
end
end
end

function invalidate_code_for_globalref!(gr::GlobalRef, invalidated_bpart::Core.BindingPartition, new_max_world::UInt)
b = convert(Core.Binding, gr)
try
valid_in_valuepos = false
foreach_module_mtable(gr.mod, new_max_world) do mt::Core.MethodTable
Expand Down
5 changes: 4 additions & 1 deletion base/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3078,7 +3078,10 @@ function create_expr_cache(pkg::PkgId, input::String, output::String, output_o::
cpu_target = nothing
end
push!(opts, "--output-ji", output)
isassigned(PRECOMPILE_TRACE_COMPILE) && push!(opts, "--trace-compile=$(PRECOMPILE_TRACE_COMPILE[])")
if isassigned(PRECOMPILE_TRACE_COMPILE)
push!(opts, "--trace-compile=$(PRECOMPILE_TRACE_COMPILE[])")
push!(opts, "--trace-compile-timing")
end

io = open(pipeline(addenv(`$(julia_cmd(;cpu_target)::Cmd)
$(flags)
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
f9258e97e2f478f66a4e63ed008a6953
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3ed43673c69b8ee549bf5b63d9a6d814f9638269fc0b12d7f7c735581757f1627a3dcd1f242f8fde2cbde1509b43d261191a9a0bb019e22759cb019936ae949e

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
d3e705f029ba3d81bd0725c2cb0b2e46
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ef8c37b056fb6dfc3c8b1b542d65d6ffdfdc1f41a08da5307ad1c3e7ce9fe0030ac4132c9d30af0e850964842d9b330e2f950bb49dd6dd0fd5b30592f8173477
28 changes: 14 additions & 14 deletions doc/src/manual/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,22 @@ On the other hand, language *interoperability* is extremely useful: we want to e
### How does Julia define its public API?

Julia's public [API](https://en.wikipedia.org/wiki/API) is the behavior described in
documentation of public symbols from `Base` and the standard libraries. Functions,
documentation of public bindings from `Base` and the standard libraries. Functions,
types, and constants are not part of the public API if they are not public, even if
they have docstrings or are described in the documentation. Further, only the documented
behavior of public symbols is part of the public API. Undocumented behavior of public
symbols is internal.
behavior of public bindings is part of the public API. Undocumented behavior of public
bindings is internal.

Public symbols are those marked with either `public foo` or `export foo`.
Public bindings are those marked with either `public foo` or `export foo`.

In other words:

- Documented behavior of public symbols is part of the public API.
- Undocumented behavior of public symbols is not part of the public API.
- Documented behavior of private symbols is not part of the public API.
- Undocumented behavior of private symbols is not part of the public API.
- Documented behavior of public bindings is part of the public API.
- Undocumented behavior of public bindings is not part of the public API.
- Documented behavior of private bindings is not part of the public API.
- Undocumented behavior of private bindings is not part of the public API.

You can get a complete list of the public symbols from a module with `names(MyModule)`.
You can get a complete list of the public bindings from a module with `names(MyModule)`.

Package authors are encouraged to define their public API similarly.

Expand Down Expand Up @@ -253,21 +253,21 @@ the variables `A` and `x` were distinct bindings referring to the same mutable `
### Can I use `using` or `import` inside a function?

No, you are not allowed to have a `using` or `import` statement inside a function. If you want
to import a module but only use its symbols inside a specific function or set of functions, you
to import a module but only use its bindings inside a specific function or set of functions, you
have two options:

1. Use `import`:

```julia
import Foo
function bar(...)
# ... refer to Foo symbols via Foo.baz ...
# ... refer to Foo bindings via Foo.baz ...
end
```

This loads the module `Foo` and defines a variable `Foo` that refers to the module, but does not
import any of the other symbols from the module into the current namespace. You refer to the
`Foo` symbols by their qualified names `Foo.bar` etc.
import any of the other bindings from the module into the current namespace. You refer to the
`Foo` bindings by their qualified names `Foo.bar` etc.
2. Wrap your function in a module:

```julia
Expand All @@ -281,7 +281,7 @@ have two options:
using Bar
```

This imports all the symbols from `Foo`, but only inside the module `Bar`.
This imports all the bindings from `Foo`, but only inside the module `Bar`.

### What does the `...` operator do?

Expand Down
23 changes: 15 additions & 8 deletions src/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -672,16 +672,23 @@ static jl_cgval_t generic_cast(
uint32_t nb = jl_datatype_size(jlto);
Type *to = bitstype_to_llvm((jl_value_t*)jlto, ctx.builder.getContext(), true);
Type *vt = bitstype_to_llvm(v.typ, ctx.builder.getContext(), true);
if (toint)
to = INTT(to, DL);
else
to = FLOATT(to);
if (fromint)
vt = INTT(vt, DL);
else
vt = FLOATT(vt);

// fptrunc fpext depend on the specific floating point format to work
// correctly, and so do not pun their argument types.
if (!(f == fpext || f == fptrunc)) {
if (toint)
to = INTT(to, DL);
else
to = FLOATT(to);
if (fromint)
vt = INTT(vt, DL);
else
vt = FLOATT(vt);
}

if (!to || !vt)
return emit_runtime_call(ctx, f, argv, 2);

Value *from = emit_unbox(ctx, vt, v, v.typ);
if (!CastInst::castIsValid(Op, from, to))
return emit_runtime_call(ctx, f, argv, 2);
Expand Down
1 change: 0 additions & 1 deletion src/jl_exported_funcs.inc
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@
XX(jl_exit_on_sigint) \
XX(jl_exit_threaded_region) \
XX(jl_expand) \
XX(jl_expand_and_resolve) \
XX(jl_expand_stmt) \
XX(jl_expand_stmt_with_loc) \
XX(jl_expand_with_loc) \
Expand Down
1 change: 1 addition & 0 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,7 @@ JL_DLLEXPORT jl_code_info_t *jl_new_code_info_uninit(void);
JL_DLLEXPORT void jl_resolve_definition_effects_in_ir(jl_array_t *stmts, jl_module_t *m, jl_svec_t *sparam_vals, jl_value_t *binding_edge,
int binding_effects);
JL_DLLEXPORT void jl_maybe_add_binding_backedge(jl_globalref_t *gr, jl_module_t *defining_module, jl_value_t *edge);
JL_DLLEXPORT void jl_add_binding_backedge(jl_binding_t *b, jl_value_t *edge);

int get_next_edge(jl_array_t *list, int i, jl_value_t** invokesig, jl_code_instance_t **caller) JL_NOTSAFEPOINT;
int set_next_edge(jl_array_t *list, int i, jl_value_t *invokesig, jl_code_instance_t *caller);
Expand Down
Loading

0 comments on commit eb44451

Please sign in to comment.