@@ -23,10 +23,44 @@ function emit_block!(ctx::CGCtx, block::Block; skip_terminator::Bool=false)
2323 ctx. debug_emitter, ctx. sci, inst. ssa_idx; linkage_name= ln)
2424 end
2525 s = inst[:stmt ]
26- if s isa ControlFlowOp
27- emit_control_flow_op! (ctx, s, value_type (inst), inst. ssa_idx)
28- else
29- emit_statement! (ctx, s, inst. ssa_idx, value_type (inst))
26+ # Per-statement diagnostic boundary: an `IRError` from anywhere in
27+ # this statement's emission is recorded (with its kernel-side stack)
28+ # and the result poisoned, so emission continues and one compile can
29+ # report every problem. See compiler/codegen/errors.jl.
30+ ctx. current_ssa_idx = inst. ssa_idx
31+ ctx. touched_poison = false
32+ try
33+ if s isa ControlFlowOp
34+ emit_control_flow_op! (ctx, s, value_type (inst), inst. ssa_idx)
35+ else
36+ emit_statement! (ctx, s, inst. ssa_idx, value_type (inst))
37+ end
38+ # A successful statement that read a poisoned input still
39+ # yields a poison-derived value: taint it so failures further
40+ # down the dataflow chain are suppressed as cascades even when
41+ # intermediate statements emit fine.
42+ if ctx. touched_poison || reads_poison (ctx, s)
43+ push! (ctx. poisoned, inst. ssa_idx)
44+ end
45+ catch e
46+ if ! (e isa IRError)
47+ # Anything else escaping emission is a compiler bug, not a
48+ # kernel diagnostic: abort immediately (the context may be
49+ # inconsistent), but point the report at the offending
50+ # kernel statement and ask for an issue.
51+ e isa Union{InternalCompilerError, InterruptException} && rethrow ()
52+ throw (InternalCompilerError (source_location (ctx. sci, inst. ssa_idx),
53+ CapturedException (e, catch_backtrace ())))
54+ end
55+ ctx. current_ssa_idx = inst. ssa_idx
56+ # Suppress errors derived purely from an already-poisoned input;
57+ # keep only root causes. The static operand check backs up the
58+ # dynamic flag for emitters that throw before reading arguments.
59+ if ! (ctx. touched_poison || reads_poison (ctx, s))
60+ record_error! (ctx, e. msg)
61+ end
62+ push! (ctx. poisoned, inst. ssa_idx)
63+ ctx. values[inst. ssa_idx] = poison_value (ctx)
3064 end
3165 end
3266 if ! skip_terminator && terminator (block) != = nothing
@@ -62,17 +96,24 @@ function emit_if_op!(ctx::CGCtx, op::IfOp, @nospecialize(parent_result_type), ss
6296 cond_tv === nothing && throw (IRError (" Cannot resolve condition for IfOp" ))
6397
6498 # Determine result types from parent_result_type (token_order_pass! already
65- # updated the type to include any token carries via inst[:type] = …)
99+ # updated the type to include any token carries via inst[:type] = …).
100+ #
101+ # A non-representable result (typically `Any`/`Union{}` left when inference
102+ # could not pin a branch's tile down) is recorded but does NOT abort: we
103+ # substitute a poison type and still emit both regions, so the root cause
104+ # inside the branch (e.g. a non-constant tile shape) surfaces too. The IfOp
105+ # result is then marked poison to suppress the cascade at its consumers,
106+ # and the carry diagnostic itself is dropped again if the regions surface
107+ # errors of their own (prune_derived_errors! below).
66108 result_types = TypeId[]
109+ result_poisoned = false
110+ carry_mark = length (ctx. errors)
67111 if parent_result_type != = Nothing
68- if parent_result_type <: Tuple
69- for T in parent_result_type. parameters
70- push! (result_types, tile_type_for_julia! (ctx, T))
71- end
72- else
73- push! (result_types, tile_type_for_julia! (ctx, parent_result_type))
74- end
112+ Ts = parent_result_type <: Tuple ? collect (parent_result_type. parameters) :
113+ Any[parent_result_type]
114+ result_types, result_poisoned = collect_result_types! (ctx, Ts; context= " `if`/`else` result" )
75115 end
116+ carry_errors = carry_mark+ 1 : length (ctx. errors)
76117
77118 then_body = function (_)
78119 saved = copy (ctx. block_args)
@@ -87,8 +128,10 @@ function emit_if_op!(ctx::CGCtx, op::IfOp, @nospecialize(parent_result_type), ss
87128 empty! (ctx. block_args); merge! (ctx. block_args, saved)
88129 end
89130 results = encode_IfOp! (then_body, else_body, cb, result_types, cond_tv. v)
131+ prune_derived_errors! (ctx, carry_errors)
90132
91133 ctx. values[ssa_idx] = CGVal (results, parent_result_type)
134+ result_poisoned && push! (ctx. poisoned, ssa_idx)
92135end
93136
94137#= ============================================================================
@@ -120,9 +163,14 @@ function emit_for_op!(ctx::CGCtx, op::ForOp, @nospecialize(parent_result_type),
120163 push! (init_values, tv. v)
121164 end
122165
123- # Build result types uniformly from block args
166+ # Build result types uniformly from block args. A non-representable carry
167+ # (typically `Any`/`Union{}`) is recorded but does not abort: poison it and
168+ # still emit the body so the root cause inside the loop surfaces too.
124169 n_carries = length (body_blk. args)
125- result_types = TypeId[tile_type_for_julia! (ctx, arg. type) for arg in body_blk. args]
170+ carry_mark = length (ctx. errors)
171+ result_types, result_poisoned =
172+ collect_result_types! (ctx, (arg. type for arg in body_blk. args); context= " loop carry" )
173+ carry_errors = carry_mark+ 1 : length (ctx. errors)
126174
127175 body_builder = function (block_args)
128176 saved = copy (ctx. block_args)
@@ -144,8 +192,10 @@ function emit_for_op!(ctx::CGCtx, op::ForOp, @nospecialize(parent_result_type),
144192 end
145193 results = encode_ForOp! (body_builder, cb, result_types, iv_type,
146194 lower_tv. v, upper_tv. v, step_tv. v, init_values)
195+ prune_derived_errors! (ctx, carry_errors)
147196
148197 ctx. values[ssa_idx] = CGVal (results, parent_result_type)
198+ result_poisoned && push! (ctx. poisoned, ssa_idx)
149199end
150200
151201#= ============================================================================
@@ -164,7 +214,10 @@ function emit_loop_op!(ctx::CGCtx, op::LoopOp, @nospecialize(parent_result_type)
164214 end
165215
166216 n_carries = length (body_blk. args)
167- result_types = TypeId[tile_type_for_julia! (ctx, arg. type) for arg in body_blk. args]
217+ carry_mark = length (ctx. errors)
218+ result_types, result_poisoned =
219+ collect_result_types! (ctx, (arg. type for arg in body_blk. args); context= " loop carry" )
220+ carry_errors = carry_mark+ 1 : length (ctx. errors)
168221
169222 body_builder = function (block_args)
170223 saved = copy (ctx. block_args)
@@ -186,8 +239,10 @@ function emit_loop_op!(ctx::CGCtx, op::LoopOp, @nospecialize(parent_result_type)
186239 empty! (ctx. block_args); merge! (ctx. block_args, saved)
187240 end
188241 results = encode_LoopOp! (body_builder, cb, result_types, init_values)
242+ prune_derived_errors! (ctx, carry_errors)
189243
190244 ctx. values[ssa_idx] = CGVal (results, parent_result_type)
245+ result_poisoned && push! (ctx. poisoned, ssa_idx)
191246end
192247
193248#= ============================================================================
@@ -212,7 +267,10 @@ function emit_while_op!(ctx::CGCtx, op::WhileOp, @nospecialize(parent_result_typ
212267 end
213268
214269 n_carries = length (before_blk. args)
215- result_types = TypeId[tile_type_for_julia! (ctx, arg. type) for arg in before_blk. args]
270+ carry_mark = length (ctx. errors)
271+ result_types, result_poisoned =
272+ collect_result_types! (ctx, (arg. type for arg in before_blk. args); context= " loop carry" )
273+ carry_errors = carry_mark+ 1 : length (ctx. errors)
216274
217275 body_builder = function (block_args)
218276 saved = copy (ctx. block_args)
@@ -299,8 +357,10 @@ function emit_while_op!(ctx::CGCtx, op::WhileOp, @nospecialize(parent_result_typ
299357 empty! (ctx. block_args); merge! (ctx. block_args, saved)
300358 end
301359 results = encode_LoopOp! (body_builder, cb, result_types, init_values)
360+ prune_derived_errors! (ctx, carry_errors)
302361
303362 ctx. values[ssa_idx] = CGVal (results, parent_result_type)
363+ result_poisoned && push! (ctx. poisoned, ssa_idx)
304364end
305365
306366#= ============================================================================
0 commit comments