The GPU ISA surface, and obSCEne's coverage of it
This is the GPU analogue of the CPU surface census
(surface.h, corpus.h): the AMD hardware's
special math operations, and how obSCEne reaches each one. It is the
list the hardware day diffs against - "probe every GPU op" needs a
statement of what every GPU op is.
The authority for the names is LLVM's open-source
IntrinsicsAMDGPU.td. The standard IEEE operations
(floor, add, mul,
fma, min, max, the roundings) are
not AMDGPU intrinsics and are listed separately under base ISA; the transcendentals, the
division sequence, decomposition and the packing conversions are the
intrinsic surface below.
How obSCEne reaches an op
- covered - an existing kernel's GLSL lowers to this op on RDNA.
- glsl - reachable through a GLSL builtin obSCEne does not yet call: a kernel to add.
- sequence - not isolable on its own; reached only as the driver's decomposition of a full-precision operation (the division primitives inside divf/rcp), whose end-to-end result the reference already checks.
- isa - not reachable from GLSL or as a sequence; would need hand-written SPIR-V or the intrinsic directly.
- na-cdna - CDNA/MI parts only, not the RDNA2 (gfx1033) in the Steam Deck; nothing to probe on the target.
Coverage
- 41 intrinsic operations enumerated, of which 33 exist on the RDNA2 target.
- 14 covered by an existing kernel.
- 0 reachable from GLSL but not yet probed - the next kernels to add.
- 3 reached only as the decomposition of full-precision division, not isolable.
- 16 reachable only through hand-written SPIR-V.
- 8 absent on the RDNA2 target.
Generated without
IntrinsicsAMDGPU.tdinstalled, so names were not cross-checked against the toolchain this run.
The intrinsic surface
| operation | category | on RDNA2 | obSCEne reaches it | note |
|---|---|---|---|---|
cos |
sfu | yes | covered:cos | v_cos_f32; likewise cos(2pix) |
exp2 |
sfu | yes | covered:exp2 | v_exp_f32 is exp2; obSCEne exp2 exercises it directly, exp composes it |
fract |
sfu | yes | covered:fract | v_fract_f32; note the hardware fract may differ from x-floor(x) at the boundary |
log |
sfu | yes | covered:log2 | v_log_f32 is log2, not natural log; obSCEne log2 exercises it directly, ln composes it |
log_clamp |
sfu | ? | isa | log with clamped output; SI/CI era, likely absent on RDNA2 |
rcp |
sfu | yes | covered:rcp | v_rcp_f32, the bare fast reciprocal; rcprelaxed pins it via RelaxedPrecision, while full-precision rcp exercises the correctly-rounded division sequence instead |
rcp_legacy |
sfu | ? | isa | legacy 0-for-inf reciprocal; pre-RDNA, likely absent on gfx1033 |
rsq |
sfu | yes | covered:rsq | v_rsq_f32; inversesqrt(x), already the fast SFU form at full precision |
rsq_clamp |
sfu | ? | isa | rsqrt with clamped output; SI/CI era, likely absent on RDNA2 |
rsq_legacy |
sfu | ? | isa | legacy rsqrt; pre-RDNA, likely absent |
sin |
sfu | yes | covered:sin | v_sin_f32; note the hardware op is sin(2pix) - the driver inserts the 1/2pi scale |
sqrt |
sfu | yes | covered:sqrt | v_sqrt_f32, the bare SFU sqrt; sqrtrelaxed pins it, while full-precision sqrt is correctly rounded |
div_fixup |
division | yes | sequence | final correction of the division result, incl. special cases; part of the divf/rcp sequence |
div_fmas |
division | yes | sequence | fma that also adds/subtracts based on the div_scale flag; part of the divf/rcp sequence |
div_scale |
division | yes | sequence | scales operands and reports the overflow flag div_fmas consumes; part of the full-precision divf/rcp sequence |
fdiv_fast |
division | yes | covered:divrelaxed | the fast, not-correctly-rounded division; divrelaxed pins it via RelaxedPrecision |
trig_preop |
division | yes | isa | the 2/pi table lookup that seeds large-argument sin/cos reduction |
frexp_exp |
decompose | yes | covered:frexpexp | exponent of frexp; the second half of the same builtin |
frexp_mant |
decompose | yes | covered:frexpmant | mantissa of frexp; GLSL frexp(x, out exp) returns it |
fma_legacy |
fused | ? | isa | legacy fma with 0*inf=0; pre-RDNA |
fmad_ftz |
fused | yes | isa | multiply-add that flushes denormals to zero |
fmul_legacy |
fused | ? | isa | legacy multiply with 0*inf=0; pre-RDNA |
fmed3 |
median | yes | isa | median(a,b,c); a GLSL clamp(x,lo,hi) may or may not lower to it |
cvt_f32_bf8 |
convert | no | na-cdna | bf8 to f32; CDNA3 (gfx940+) only |
cvt_f32_fp8 |
convert | no | na-cdna | fp8 to f32; CDNA3 only |
cvt_pk_bf8_f32 |
convert | no | na-cdna | f32 to packed bf8; CDNA3 only |
cvt_pk_f32_bf8 |
convert | no | na-cdna | packed bf8 to f32; CDNA3 only |
cvt_pk_f32_fp8 |
convert | no | na-cdna | packed fp8 to f32; CDNA3 only |
cvt_pk_fp8_f32 |
convert | no | na-cdna | f32 to packed fp8; CDNA3 only |
cvt_pk_i16 |
convert | yes | isa | pack two i32 to two i16, signed-saturating |
cvt_pk_u16 |
convert | yes | isa | pack two u32 to two u16, unsigned-saturating |
cvt_pk_u8_f32 |
convert | yes | isa | convert f32 to u8 and insert into a lane of a packed word |
cvt_pknorm_i16 |
convert | yes | covered:packsnorm | pack two f32 to two snorm16; GLSL packSnorm2x16 |
cvt_pknorm_u16 |
convert | yes | covered:packunorm | pack two f32 to two unorm16; GLSL packUnorm2x16 |
cvt_pkrtz |
convert | yes | covered:packhalf | pack two f32 to two f16, round-toward-zero; GLSL packHalf2x16 |
cvt_sr_bf8_f32 |
convert | no | na-cdna | f32 to bf8 with stochastic rounding; CDNA3 only |
cvt_sr_fp8_f32 |
convert | no | na-cdna | f32 to fp8 with stochastic rounding; CDNA3 only |
cubeid |
cubemap | yes | isa | selects the cubemap face index for a direction vector |
cubema |
cubemap | yes | isa | the major axis magnitude for cube face projection |
cubesc |
cubemap | yes | isa | s coordinate for cube face projection |
cubetc |
cubemap | yes | isa | t coordinate for cube face projection |
Base ISA (not intrinsics)
These obSCEne covers, but LLVM models them as generic float
operations rather than AMDGPU intrinsics, so they carry no
int_amdgcn_ name and are not part of the intrinsic surface
above.
| operation | obSCEne reaches it | note |
|---|---|---|
v_floor_f32 |
covered:floor | GLSL floor |
v_ceil_f32 |
covered:ceil | GLSL ceil |
v_trunc_f32 |
covered:trunc | GLSL trunc |
v_rndne_f32 |
covered:roundeven | GLSL roundEven; round ties-to-even |
v_min_f32 |
covered:minf | GLSL min |
v_max_f32 |
covered:maxf | GLSL max |
v_fma_f32 |
covered:fmaf | GLSL fma; the fused, non-legacy form |
v_cvt_i32_f32 |
covered:cvti | GLSL int(x) |
v_cvt_f16_f32 |
covered:half | GLSL packing to f16 and back |
v_cvt_f32_f16 |
covered:unpackhalf | GLSL unpackHalf2x16 (low half); f16->f32 decode, exact |
v_cvt_f32_u32 |
covered:unpackunorm | GLSL unpackUnorm2x16 (low half); low 16 bits / 65535 |
v_cvt_f32_i32 |
covered:unpacksnorm | GLSL unpackSnorm2x16 (low half); signed low 16 / 32767, clamped |
v_mul_f32 |
covered:ftz | GLSL x*0.5; probes flush-to-zero of a denormal result |
Integer / bit base ISA
Integer and bit operations, likewise generic LLVM operations rather than AMDGPU intrinsics, but each lowering to a dedicated RDNA integer instruction. All exact - the device must match bit for bit. This surface is the integer/bit breadth beyond the float intrinsic census, and grows as kernels are added.
| operation | obSCEne reaches it | note |
|---|---|---|
v_bcnt_u32_b32 |
covered:bitcount | GLSL bitCount; population count, 0..32 |
v_ffbh_u32 |
covered:findmsb | GLSL findMSB (unsigned); highest set bit or -1 |
v_ffbl_b32 |
covered:findlsb | GLSL findLSB; lowest set bit or -1 |
v_bfrev_b32 |
covered:bitreverse | GLSL bitfieldReverse; reverse the 32 bits |
v_bfe_u32 |
covered:bfe | GLSL bitfieldExtract (unsigned); fixed [8,16) field |
v_bfi_b32 |
covered:bfi | GLSL bitfieldInsert; fixed [8,16) field |