v_mov_b32_sdwa threw 'VOP1 SDWA destination selector ... is not
supported' when a byte source (src0_sel BYTE_0..3) met a partial
destination (dst_sel BYTE_0..3 or WORD_0/1): the VMovB32 rule allowed
only WORD and DWORD sources there. Every src0_sel, src0_sext, dst_sel
and dst_unused combination is now accepted. Translation already follows
RDNA2 for all of them (applyBitSourceModifiers, writeRawU32): the
selected field is zero- or sign-extended, and the result's low bits go
to the dst_sel field with the other bits zeroed, sign-extended above
and zeroed below, or preserved. Reserved selectors, dst_unused 3, and
neg/abs on sub-dword sources still throw.
agc_driver_sdwa_move_selectors runs all 294 combinations as wave32 and
wave64 on the GPU, plus the in-place byte broadcast under a partial
exec mask, which is not checked on subgroups narrower than 32 lanes,
as in the other EXEC-masked execution tests. agc_vop1_sdwa_move_decode
checks the decoded operands and the reserved encodings.
A loop whose exits have no common post-dominator, such as a normal exit
to one s_endpgm tail beside an early-out to a kill tail, got no merge
block, and Structurize threw "loop at block N has no structured
merge/continue". With three or more exits, detectNaturalLoops threw
first, on a lookup of InvalidControlFlowId.
Such a loop now leaves through one new merge block that dispatches on
route variables. They are cleared before the header and set on each
exit edge to a target other than the latch's exit. Inner loops are
routed first; a routing that would change the natural loops throws.
A loop-exit tail branch whose in-body target is the continue block no
longer merges there, which spirv-val rejects ("Header block ... is
contained in the loop construct ..., but its merge block ... is not").
The FLAT decoder took a scalar base address (SADDR) only from a
numbered SGPR pair, so global loads, stores and atomics and
global_load/store_dword_addtid with SADDR = vcc (106) threw "FLAT
scalar address register range overflow". LLVM's GFX10 global saddr
operand accepts s, vcc, ttmp, null and off.
A two-register base may now be VCC. The address translation already
reads it as VCC_LO:VCC_HI through offsetOperand. The same helper
serves the scratch SADDR, where vcc_lo becomes the 32-bit offset.
VCC_HI, M0, EXEC and the trap temporaries still throw.
SOP1 opcode 33 with SDST null keeps no return address, so it is exactly
s_setpc_b64; the decoder now reads it that way, as KytyPS5 does. A call
with a real destination still throws "unsupported SOP1 opcode 33".
GraphBuilder resolves two more jump shapes. A long branch is
s_getpc_b64 and s_add_u32/s_addc_u32 or s_sub_u32/s_subb_u32
immediates, also through vcc, all in one block. A dword jump table
branches to the table base minus an entry that s_load_dword reads at an
index bounded by s_min_u32 and scaled by 4; the resolver follows
register writes back through straight-line code, and anything else is
still refused. The code table load now also handles one-dword entries.
agc_shader_control_flow checks the decode, the graphs and the refusals;
the new agc_driver_scalar_swappc runs all shapes on the GPU.
clamp (and omod, ignored while f16 denormals are enabled) were refused or
dropped per op: v_{add,sub,subrev,mul,min,max}_f16, v_ldexp_f16,
v_frexp_mant_f16, v_cvt_norm_{i,u}16_f16, v_{max3,min3,med3,div_fixup}_f16.
They now share one clamp on the f16 bits (clampF16Bits).
Co-Authored-By: Claude <noreply@anthropic.com>
The resource materializer refused every atomic image descriptor whose
format was not 32_UINT. RDNA2 image atomics act on the raw dword and
the numeric format only affects addressing, so 32_SINT and 32_FLOAT
surfaces are now accepted with the Uint numeric class and run through
the existing integer atomics and float compare-exchange loops. Other
formats still throw, and the message now names the format.
DescriptorBinding gains imageAtomic, carried through the shader disk
cache (format version 4) and the resource content key. The driver
binds those elements through a cached R32_UINT view of R32_SINT and
R32_SFLOAT storage images.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
EmitDppTargetLane threw "DPP control 336 is not supported" for the
DPP16 row_share controls 0x150-0x15f. row_share:sel now reads lane
sel of the reading lane's own row, (lane & ~15) | sel, as the RDNA2
ISA defines it. The source never leaves the row, so the target is
always valid and an inactive source follows the existing fi and
bound_ctrl rule, as for row_xmask.
The new agc_driver_dpp16_row_share_xmask execution test covers
v_mov_b32, v_add_nc_u32, v_sub_nc_u32 and v_max_f32 with row_share
and row_xmask under a partial exec mask, with fi, bound_ctrl and
row/bank masks, as wave32 and wave64; row_xmask had no test before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GLOBAL opcode 0x34 subtracts the data register from a global dword and
clamps the result to zero, returning the previous value. It only exists
in the global segment, so the flat form throws in the decoder, and the
form without glc throws like buffer_atomic_csub does. The clamped
subtract is now a shared helper used by both opcodes.
Single rounding of the whole sum, f32 accumulator denormals flushed, NaN
picked on the bits, clamp ignored and the v_dot2c accumulator read from
the lane itself under DPP, all as measured on hardware.
Co-Authored-By: Claude <noreply@anthropic.com>
AMD hardware compares a sample_c reference against a color texture's red
channel; Vulkan defines comparison sampling only for depth formats, so the
driver refused any compare-sampled texture that is not R32 float or R16
unorm. PPSA21567 compares the same LESSEQUAL, clamp-to-border (opaque
white) sampler against a shadow map and against a 1x1 RGBA8 texture.
For a compare-sampled image whose format is not natively comparable, the
specialization records the paired sampler's compare function, filter,
addressing and border, and the view's reference clamp kind; the image then
binds as an ordinary color texture. The backend fetches the red channel,
applies wrap, clamp-to-edge or clamp-to-border addressing with the
sampler's texel-centre convention (border taps take the border's red),
compares, and blends four comparisons for bilinear filtering. Real depth
formats keep the native path.
Only sample_c / sample_c_lz on 2D and 2D array views, float/unorm/snorm
formats, wrap, clamp-to-edge or clamp-to-border, point or bilinear at one
level are implemented; half-border, the border color table and everything
else on this path throw. The reference clamp for unorm/snorm color formats
is not documented by AMD and is recorded in the technical debt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>