Skip to content

Commit

Permalink
Fully outline all GlobalRefs (#56746)
Browse files Browse the repository at this point in the history
This is an alternative to #56714 that goes in the opposite direction -
just outline all GlobalRefs during lowering. It is a lot simpler that
#56714 at the cost of some size increase. Numbers:

sys.so .ldata size:
This PR: 159.8 MB
Master: 158.9 MB

I don't have numbers of #56714, because it's not fully complete.
Additionally, it's possible that restricting GlobalRefs from arguments
position would let us use a more efficient encoding in the future.
  • Loading branch information
Keno authored Dec 7, 2024
1 parent 184ad5b commit 3a68b03
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 79 deletions.
9 changes: 4 additions & 5 deletions Compiler/test/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3031,14 +3031,13 @@ end

# issue #28279
# ensure that lowering doesn't move these into statement position, which would require renumbering
using Base: +, -
function f28279(b::Bool)
@eval function f28279(b::Bool)
let i = 1
while i > b
i -= 1
while $(>)(i, b)
i = $(-)(i, 1)
end
if b end
return i + 1
return $(+)(i, 1)
end
end
code28279 = code_lowered(f28279, (Bool,))[1].code
Expand Down
10 changes: 6 additions & 4 deletions doc/src/base/reflection.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,12 @@ as assignments, branches, and calls:
```jldoctest; setup = (using Base: +, sin)
julia> Meta.lower(@__MODULE__, :( [1+2, sin(0.5)] ))
:($(Expr(:thunk, CodeInfo(
1 ─ %1 = dynamic 1 + 2
│ %2 = dynamic sin(0.5)
│ %3 = dynamic Base.vect(%1, %2)
└── return %3
1 ─ %1 = :+
│ %2 = dynamic (%1)(1, 2)
│ %3 = sin
│ %4 = dynamic (%3)(0.5)
│ %5 = dynamic Base.vect(%2, %4)
└── return %5
))))
```

Expand Down
37 changes: 0 additions & 37 deletions src/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,42 +181,6 @@ static value_t fl_defined_julia_global(fl_context_t *fl_ctx, value_t *args, uint
return (bpart != NULL && decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)) == BINDING_KIND_GLOBAL) ? fl_ctx->T : fl_ctx->F;
}

static value_t fl_nothrow_julia_global(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
{
// tells whether a var is defined, in the sense that accessing it is nothrow
// can take either a symbol or a module and a symbol
jl_ast_context_t *ctx = jl_ast_ctx(fl_ctx);
jl_module_t *mod = ctx->module;
jl_sym_t *var = NULL;
if (nargs == 1) {
(void)tosymbol(fl_ctx, args[0], "nothrow-julia-global");
var = scmsym_to_julia(fl_ctx, args[0]);
}
else {
argcount(fl_ctx, "nothrow-julia-global", nargs, 2);
value_t argmod = args[0];
if (iscvalue(argmod) && cv_class((cvalue_t*)ptr(argmod)) == jl_ast_ctx(fl_ctx)->jvtype) {
mod = *(jl_module_t**)cv_data((cvalue_t*)ptr(argmod));
JL_GC_PROMISE_ROOTED(mod);
} else {
if (!iscons(argmod) || !issymbol(car_(argmod)) || scmsym_to_julia(fl_ctx, car_(argmod)) != jl_thismodule_sym) {
lerrorf(fl_ctx, fl_ctx->ArgError, "nothrow-julia-global: Unknown globalref module kind");
}
}
(void)tosymbol(fl_ctx, args[1], "nothrow-julia-global");
var = scmsym_to_julia(fl_ctx, args[1]);
}
jl_binding_t *b = jl_get_module_binding(mod, var, 0);
jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age);
jl_ptr_kind_union_t pku = jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age);
if (!bpart)
return fl_ctx->F;
if (jl_bkind_is_some_guard(decode_restriction_kind(pku)))
return fl_ctx->F;
return (jl_bkind_is_some_constant(decode_restriction_kind(pku)) ?
decode_restriction_value(pku) : jl_atomic_load_relaxed(&b->value)) != NULL ? fl_ctx->T : fl_ctx->F;
}

// Used to generate a unique suffix for a given symbol (e.g. variable or type name)
// first argument contains a stack of method definitions seen so far by `closure-convert` in flisp.
// if the top of the stack is non-NIL, we use it to augment the suffix so that it becomes
Expand Down Expand Up @@ -288,7 +252,6 @@ static jl_value_t *scm_to_julia_(fl_context_t *fl_ctx, value_t e, jl_module_t *m

static const builtinspec_t julia_flisp_ast_ext[] = {
{ "defined-julia-global", fl_defined_julia_global }, // TODO: can we kill this safepoint
{ "nothrow-julia-global", fl_nothrow_julia_global },
{ "current-julia-module-counter", fl_module_unique_name },
{ "julia-scalar?", fl_julia_scalar },
{ NULL, NULL }
Expand Down
1 change: 0 additions & 1 deletion src/jlfrontend.scm
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@

;; this is overwritten when we run in actual julia
(define (defined-julia-global v) #f)
(define (nothrow-julia-global v) #f)

;; parser entry points

Expand Down
1 change: 0 additions & 1 deletion src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -4356,7 +4356,6 @@ f(x) = yt(x)

(define (valid-ir-argument? e)
(or (simple-atom? e)
(and (globalref? e) (nothrow-julia-global (cadr e) (caddr e)))
(and (pair? e)
(memq (car e) '(quote inert top core
slot static_parameter)))))
Expand Down
5 changes: 3 additions & 2 deletions stdlib/Test/src/Test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1965,8 +1965,9 @@ Arguments
#self#::Core.Const(f)
a::Int64
Body::UNION{FLOAT64, INT64}
1 ─ %1 = (a > 1)::Bool
└── goto #3 if not %1
1 ─ %1 = :>::Core.Const(>)
│ %2 = (%1)(a, 1)::Bool
└── goto #3 if not %2
2 ─ return 1
3 ─ return 1.0
Expand Down
61 changes: 38 additions & 23 deletions test/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7435,6 +7435,7 @@ end
@test isa(Core.eval(@__MODULE__, :(Bar31062(()))), Bar31062)
@test precompile(identity, (Foo31062,))

using Core: SSAValue
ftype_eval = Ref(0)
FieldTypeA = String
FieldTypeE = UInt32
Expand All @@ -7458,27 +7459,41 @@ let fc = FieldConvert(1.0, [2.0], 0x3, 0x4, 0x5)
end
@test ftype_eval[] == 1
let code = code_lowered(FieldConvert)[1].code
local fc_global_ssa, sp1_ssa, apply_type_ssa, field_type_ssa,
field_type2_ssa, field_type4_ssa, field_type5_ssa,
slot_read_1, slot_read_2, slot_read_3, slot_read_4,
new_ssa
@test code[(fc_global_ssa = 1;)] == GlobalRef(@__MODULE__, :FieldConvert)
@test code[(sp1_ssa = 2;)] == Expr(:static_parameter, 1)
@test code[(apply_type_ssa = 3;)] == Expr(:call, GlobalRef(Core, :apply_type), Core.SSAValue(fc_global_ssa), GlobalRef(@__MODULE__, :FieldTypeA), Core.SSAValue(sp1_ssa))
@test code[(field_type_ssa = 4;)] == Expr(:call, GlobalRef(Core, :fieldtype), Core.SSAValue(apply_type_ssa), 1)
@test code[10] == Expr(:(=), Core.SlotNumber(10), Expr(:call, GlobalRef(Base, :convert), Core.SSAValue(field_type_ssa), Core.SlotNumber(10)))
@test code[(slot_read_1 = 11;)] == Core.SlotNumber(10)
@test code[(field_type2_ssa = 12;)] == Expr(:call, GlobalRef(Core, :fieldtype), Core.SSAValue(apply_type_ssa), 2)
@test code[18] == Expr(:(=), Core.SlotNumber(9), Expr(:call, GlobalRef(Base, :convert), Core.SSAValue(field_type2_ssa), Core.SlotNumber(9)))
@test code[(slot_read_2 = 19;)] == Core.SlotNumber(9)
@test code[(field_type4_ssa = 20;)] == Expr(:call, GlobalRef(Core, :fieldtype), Core.SSAValue(apply_type_ssa), 4)
@test code[26] == Expr(:(=), Core.SlotNumber(8), Expr(:call, GlobalRef(Base, :convert), Core.SSAValue(field_type4_ssa), Core.SlotNumber(8)))
@test code[(slot_read_3 = 27;)] == Core.SlotNumber(8)
@test code[(field_type5_ssa = 28;)] == Expr(:call, GlobalRef(Core, :fieldtype), Core.SSAValue(apply_type_ssa), 5)
@test code[34] == Expr(:(=), Core.SlotNumber(7), Expr(:call, GlobalRef(Base, :convert), Core.SSAValue(field_type5_ssa), Core.SlotNumber(7)))
@test code[(slot_read_4 = 35;)] == Core.SlotNumber(7)
@test code[(new_ssa = 36;)] == Expr(:new, Core.SSAValue(apply_type_ssa), Core.SSAValue(slot_read_1), Core.SSAValue(slot_read_2), Core.SlotNumber(4), Core.SSAValue(slot_read_3), Core.SSAValue(slot_read_4))
@test code[37] == Core.ReturnNode(Core.SSAValue(new_ssa))
calls = Vector{Pair{SSAValue, Expr}}(undef, 0)
for i = 1:length(code)
expr = code[i]
if Meta.isexpr(expr, :call) || (Meta.isexpr(expr, :(=)) && Meta.isexpr(expr.args[2], :call))
push!(calls, SSAValue(i)=>expr)
end
end

function is_globalref(arg, gr)
while isa(arg, SSAValue)
arg = code[arg.id]
end
arg == gr
end

# calls[1]
@test all(is_globalref.(calls[1][2].args[1:3], (GlobalRef(Core, :apply_type), GlobalRef(@__MODULE__, :FieldConvert), GlobalRef(@__MODULE__, :FieldTypeA))))

# calls[2]
@test all(is_globalref.(calls[2][2].args[1:1], (GlobalRef(Core, :fieldtype),)))
@test all(calls[2][2].args[2:3] .== (calls[1][1], 1))

# calls[3] - isa

# calls[4]
let calle = calls[4][2]
@test Meta.isexpr(calle, :(=))
call = calle.args[2]
@test is_globalref(call.args[1], GlobalRef(Base, :convert))
@test call.args[2] == calls[2][1]
end

# calls[5]
@test all(is_globalref.(calls[5][2].args[1:1], (GlobalRef(Core, :fieldtype),)))
@test all(calls[5][2].args[2:3] .== (calls[1][1], 2))
end

# Issue #32820
Expand Down Expand Up @@ -8156,7 +8171,7 @@ end
@test Core.Compiler.is_foldable(Base.infer_effects(length, (Core.SimpleVector,)))
@test Core.Compiler.is_foldable(Base.infer_effects(getindex, (Core.SimpleVector,Int)))

# Test that a nothrow-globalref doesn't get outlined during lowering
# Test that a the lowering of nothrow globalref
module WellKnownGlobal
global well_known = 1
end
Expand All @@ -8165,7 +8180,7 @@ macro insert_global()
end
check_globalref_lowering() = @insert_global
let src = code_lowered(check_globalref_lowering)[1]
@test length(src.code) == 2
@test length(src.code) == 4
end

# Test correctness of widen_diagonal
Expand Down
12 changes: 6 additions & 6 deletions test/staged.jl
Original file line number Diff line number Diff line change
Expand Up @@ -270,12 +270,12 @@ end

# PR #23168

function f23168(a, x)
@eval function f23168(a, x)
push!(a, 1)
if @generated
:(y = x + x)
:(y = $(+)(x, x))
else
y = 2x
y = $(*)(2, x)
end
push!(a, y)
if @generated
Expand All @@ -290,9 +290,9 @@ end
let a = Any[]
@test f23168(a, 3) == (6, Int)
@test a == [1, 6, 3]
@test occursin(" + ", string(code_lowered(f23168, (Vector{Any},Int))))
@test occursin("2 * ", string(Base.uncompressed_ir(first(methods(f23168)))))
@test occursin("2 * ", string(code_lowered(f23168, (Vector{Any},Int), generated=false)))
@test occursin("(+)(", string(code_lowered(f23168, (Vector{Any},Int))))
@test occursin("(*)(2", string(Base.uncompressed_ir(first(methods(f23168)))))
@test occursin("(*)(2", string(code_lowered(f23168, (Vector{Any},Int), generated=false)))
@test occursin("Base.add_int", string(code_typed(f23168, (Vector{Any},Int))))
end

Expand Down

2 comments on commit 3a68b03

@DilumAluthge
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nanosoldier runtests(["PackageCompiler"])

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The package evaluation job you requested has completed - possible issues were detected.
The full report is available.

Please sign in to comment.