Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions src/compiler/codegen/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -102,16 +102,6 @@ Optionally stores a compile-time constant value.
ghost_value(@nospecialize(jltype)) = CGVal(nothing, TypeId(-1), jltype, Int[], nothing, nothing, nothing)
ghost_value(@nospecialize(jltype), constant) = CGVal(nothing, TypeId(-1), jltype, Int[], nothing, Some(constant), nothing)

"""
constant_value(jltype, type_id, constant) -> CGVal

Deferred constant: has a Tile IR type but no bytecode value yet.
Materialized (ConstantOp emitted) on demand at SSA lookup time.
Parallel to Julia's non-ghost cgval from mark_julia_const.
"""
constant_value(@nospecialize(jltype), type_id::TypeId, constant) =
CGVal(nothing, type_id, jltype, Int[], nothing, Some(constant), nothing)

"""
tuple_value(jltype, component_refs, component_constants) -> CGVal

Expand Down
28 changes: 4 additions & 24 deletions src/compiler/codegen/values.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,7 @@ Emit/resolve a value reference to a CGVal using multiple dispatch.
function emit_value!(ctx::CGCtx, ssa::SSAValue)
tv = ctx[ssa]
tv !== nothing || throw(IRError("SSAValue %$(ssa.id) not found in context"))
return maybe_materialize!(ctx, ssa, tv)
end

"""
maybe_materialize!(ctx, ssa, tv) -> CGVal

Materialize a deferred constant into bytecode on demand.
Only acts on CGVals with `type_id != TypeId(-1)` and no value yet (deferred constants).
"""
function maybe_materialize!(ctx::CGCtx, ssa::SSAValue, tv::CGVal)
tv.v !== nothing && return tv # already materialized
tv.type_id == TypeId(-1) && return tv # ghost — nothing to materialize
tv.constant === nothing && return tv # no constant to materialize

val = something(tv.constant)
bytes = constant_to_bytes(val, CC.widenconst(tv.jltype))
v = encode_ConstantOp!(ctx.cb, tv.type_id, bytes)
materialized = CGVal(v, tv.type_id, tv.jltype, Int[], nothing, tv.constant, nothing)
ctx[ssa] = materialized
return materialized
return tv
end
emit_value!(ctx::CGCtx, arg::Argument) = ctx[arg]
emit_value!(ctx::CGCtx, slot::SlotNumber) = ctx[slot]
Expand Down Expand Up @@ -81,13 +62,12 @@ end
function emit_value!(ctx::CGCtx, ref::GlobalRef)
val = getfield(ref.mod, ref.name)
T = typeof(val)
# Ghost types have no materializable representation.
# Non-ghost types with a Tile IR type become deferred constants (materialized on demand).
# Everything else (functions, enums, etc.) is compile-time only → ghost.
if !is_ghost_type(T)
type_id = tile_type_for_julia!(ctx, T; throw_error=false)
if type_id !== nothing
return constant_value(T, type_id, val)
bytes = constant_to_bytes(val, T)
v = encode_ConstantOp!(ctx.cb, type_id, bytes)
return CGVal(v, type_id, T, Int[], nothing, Some(val), nothing)
end
end
ghost_value(T, val)
Expand Down
39 changes: 39 additions & 0 deletions test/codegen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2174,6 +2174,45 @@ const _CODEGEN_TEST_FLOAT64 = 3.14159
end
end
end

@testset "scalar arg multiplied by external constant" begin
# Regression test for issue #77: scalar × global constant failed
# because encode_MulFOp! received Nothing from the ghost-wrapped GlobalRef.
@test @filecheck begin
@check_label "entry"
code_tiled(Tuple{ct.TileArray{Float32,1,spec1d}, Float32}) do a, scale
pid = ct.bid(1)
tile = ct.load(a, pid, (16,))
@check "constant <f32"
@check "mulf"
total_scale = scale * _CODEGEN_TEST_FLOAT32
@check "broadcast"
@check "mulf"
Base.donotdelete(tile .* total_scale)
return
end
end
end

@testset "external constant as first operand in scalar addition" begin
# Regression test for issue #77: global constant used in scalar arithmetic
# must emit a ConstantOp, not a ghost value. Tests GlobalRef as the first
# operand (LHS) to cover both operand positions.
@test @filecheck begin
@check_label "entry"
code_tiled(Tuple{ct.TileArray{Float32,1,spec1d}, Float32}) do a, offset
pid = ct.bid(1)
tile = ct.load(a, pid, (16,))
@check "constant <f32"
@check "addf"
total = _CODEGEN_TEST_FLOAT32 + offset
@check "broadcast"
@check "addf"
Base.donotdelete(tile .+ total)
return
end
end
end
end

#=============================================================================
Expand Down
25 changes: 25 additions & 0 deletions test/execution.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1361,6 +1361,31 @@ end

end

const _EXEC_TEST_GLOBAL_CONST = Float32(1 / log(2))

@testset "global constant arithmetic" begin
# Regression test for issue #77: scalar × global constant failed during codegen.
function global_const_arith_kernel(a::ct.TileArray{Float32,1},
b::ct.TileArray{Float32,1},
scale::Float32)
pid = ct.bid(1)
tile = ct.load(a, pid, (16,))
total_scale = scale * _EXEC_TEST_GLOBAL_CONST
ct.store(b, pid, tile .* total_scale)
return
end

n = 1024
tile_size = 16
scale = 2.5f0
a = CUDA.rand(Float32, n)
b = CUDA.zeros(Float32, n)

ct.launch(global_const_arith_kernel, cld(n, tile_size), a, b, scale)

@test Array(b) ≈ Array(a) .* (scale * _EXEC_TEST_GLOBAL_CONST)
end

@testset "tile broadcasting" begin

@testset "1D broadcast: (1,) .+ (128,)" begin
Expand Down