Skip to content

Ghost of Yōtei (PPSA26344): unsupported MIMG opcode, which the decoder does not name #1941

Closed

Description

@Dextroid17

What

Ghost of Yōtei (PPSA26344, 01.008) aborts after about 24 minutes with an image opcode the decoder has no entry for:

[libc] unhandled exception 'St13runtime_error' thrown from 0x7f96f49c20f4
terminate called after throwing an instance of 'std::runtime_error'
  what():  unsupported MIMG opcode

RdnaImageOpDecoder.cpp:165 throws from its table lookup, and unlike the scalar decoder's message it does not name the opcode — unsupported scalar source operand code 235 at program counter 856 does. Naming it here would make this actionable from a user's log alone, without a reproducer.

Where it was measured

The table's current coverage

Encodings 0x00 to about 0x41 — loads (image_load*), stores (image_store*), the atomics and the image_sample* family with its compare/gradient/offset variants. Whatever this shader issues is outside that set.

Written with AI assistance.

Activity

  1. Dextroid17 commented on Oct 9, 2026

    @Dextroid17
    ContributorAuthor

    The diagnostic step paid off — the title now names the opcode.

    With the encoding included in RdnaImageOpDecoder.cpp:165 ("unsupported MIMG opcode " + std::to_string(opcode)), PPSA26344 dies after ~24 minutes and 897 shaders with:

    [libc] unhandled exception 'St13runtime_error' thrown from 0x7f8abbfc2206
    terminate called after throwing an instance of 'std::runtime_error'
      what():  unsupported MIMG opcode 229
    

    So the missing encoding is 0xE5, immediately below the two the table already carries:

    encoding this tree LLVM (MIMGInstructions.td)
    0xE5 (missing) no definition found in that file
    0xE6 ImageBvhIntersectRay IMAGE_BVH_INTERSECT_RAY, gfx12 encoding 0xE6 (line 2039)
    0xE7 ImageBvh64IntersectRay IMAGE_BVH64_INTERSECT_RAY, gfx12 encoding 0xE7 (line 2041)

    Two notes for whoever implements it:

    • 0xE5 is not simply "the next intersect-ray". LLVM defines 0xE6 and 0xE7 there but has no definition for 0xE5, so its name, operand shape and return semantics need a source that actually describes it (ISA table or another implementation) rather than inference from its neighbour. I have not found that source yet, which is why this is a report and not a patch.
    • The message change is worth keeping on its own. Naming the encoding turned "an unknown MIMG opcode" into "0xE5" in a single 24-minute run, which is the difference between a report someone can act on and one they cannot.

    For completeness, the table covers 135 encodings; the gaps where a shader could plausibly land are 0x06 0x07 0x0c 0x0d 0x13, 0x64-0x67 0x72 0x75 0x78 0x7b-0x7f, 0x81-0x9f and 0xe0-0xe5.

    Written with AI assistance.

  2. MarcZX10 commented on Oct 9, 2026

    @MarcZX10
    Contributor

    I checked the public AMD RDNA 2 ISA reference and AMDGPU LLVM opcode tables as well. They document IMAGE_BVH_INTERSECT_RAY and IMAGE_BVH64_INTERSECT_RAY as the adjacent 0xE6/0xE7 operations, but do not define 0xE5. That supports keeping this as an unknown instruction until a PS5-specific hardware/spec source identifies its semantics; inferring it from the BVH neighbors would be unsafe. AMD RDNA 2 ISA · LLVM AMDGPU MIMG opcode table.

  3. Dextroid17 commented on Oct 9, 2026

    @Dextroid17
    ContributorAuthor

    Adding the ISA evidence for 0xE5, because it narrows the question usefully.

    Source: LLVM's own MC tests for this GPU family — llvm/test/MC/AMDGPU/gfx1013.s is the file for gfx1013, which is what PS5's GPU ("Oberon") reports as. I extracted all 253 mnemonic↔encoded-word pairs from the MIMG test files and keyed them by encoding variant.

      0xE0  image_get_lod
      0xE1  image_gather4_b_cl
      0xE2  image_gather4_c_cl
      0xE3  image_gather4_c_l
      0xE4  image_gather4_c_b
      0xE5  — undefined in every variant (GFX8, GFX8_0, GFX8_1, GFX9, GFX90A, GFX10, GFX11)
      0xE6  image_bvh_intersect_ray       (present on gfx1013; refused on gfx1011/gfx1012)
      0xE7  image_bvh64_intersect_ray     (same)
    

    So the ray-tracing family is 0xE6/0xE7 — which RdnaImageOpDecoder.cpp already carries — and 0xE5 is not assigned anywhere in public data, including on this exact GPU.

    A hypothesis I checked and had to drop. The decoder builds the opcode as ((word0 >> 18) & 0x7F) | ((word0 & 1) << 7), i.e. opcode bit 7 comes from word bit 0, which looked wrong next to GFX11 rows where the same bit lives at word bit 8. It is not wrong for us: assembling gfx1013's image_msaa_load gives word 0xf0000839, and only the bit-0 reading yields 0x80 (the bit-8 reading yields 0x00). The bit placement genuinely differs between GFX10 and GFX11, and ours matches GFX10. Closed.

    What that leaves, with the decoder already rejecting non-MIMG words ((word0 >> 26) != 0x3C) and reserved control bits:

    • either PS5's shader compiler emits a reserved encoding here, or
    • the word handed to the decoder is not an instruction at all (a walk off the end of the code section, or a literal read as code) — the major opcode check would pass by chance roughly one time in 64.

    To tell those apart I instrumented the lookup to print the program counter, both words, the extracted opcode, the major opcode, and the surrounding words, then re-ran the title. The run reports which of the two it is; I will post the words here when it reaches the wall.

    Written with AI assistance.

  4. Dextroid17 commented on Oct 9, 2026

    @Dextroid17
    ContributorAuthor

    Adding a third source, which agrees on both points.

    sharpemu/sharpemu has an independent GFX10 MIMG decoder (src/SharpEmu.ShaderCompiler/Gen5ShaderTranslator.cs) and it says the same two things this decoder does:

    • On the extraction: "GFX10 MIMG uses bit 0 as opcode bit 7. Treating the opcode as only bits 18..24 makes the 0x80+ family (including sample-adjust forms) …" — i.e. exactly the ((word >> 18) & 0x7F) | ((word & 1) << 7) this project uses, with a test of its own (ImageBvhIntersectRay_UsesOpcodeBitSevenFromOpm).
    • On the aliasing: "Ignoring bit 0 aliases 0xE6/0xE7 BVH operations to 0x66/0x67" — which is why the bit matters at all.

    Their opcode table then lists the image ops they need, and its window above 0xA0 is: 0xE6 => ImageBvhIntersectRay, 0xE7 => ImageBvh64IntersectRay, then the default unknown-mimg op=0x{opcode:X2}. No 0xE5.

    So three implementations now agree it is not a defined MIMG opcode on this family: LLVM's MC tables (every gfx variant), sharpemu's decoder, and ours (0xE6/0xE7 present, 0xE5 absent). That leaves the two possibilities in the previous comment; the diagnostic run is underway and I will post the raw words here.

    Written with AI assistance.

  5. Dextroid17 commented on Oct 9, 2026

    @Dextroid17
    ContributorAuthor

    The diagnostic answers it, and the answer is not an opcode.

    [mimg] unsupported opcode 0xe5 (229) pc=0x410 wordIndex=260 major=0x3c word0=f1949f05 word1=00060018
    [mimg]   word[256] = 361a6e87
    [mimg]   word[257] = beea0f7e
    [mimg]   word[258] = 8126a026
    [mimg]   word[259] = 8125256a
    [mimg]   word[260] = f1949f05   <-- failing
    [mimg]   word[261] = 00060018
    [mimg]   word[262] = 121b1a19
    [mimg]   word[263] = 00003715
    [mimg]   word[264] = 7d8a1af9
    [mimg]   word[265] = 0686b086
    

    Checked against the decoder's own set of valid major opcodes (32 33 35 36 37 38 3a 3c 3d 3e 3f 7d 7e 7f), by (word >> 26) & 0x3F:

      361a6e87  0x0d  not an instruction
      beea0f7e  0x2f  not an instruction
      8126a026  0x20  not an instruction
      8125256a  0x20  not an instruction
      f1949f05  0x3c  <- the only word that passes, and it is not code
      00060018  0x00  not an instruction
      121b1a19  0x04  not an instruction
      00003715  0x00  not an instruction
      7d8a1af9  0x1f  not an instruction
      0686b086  0x01  not an instruction
    

    Nine of the ten words are not valid instructions at all, and the tenth only passes because a random word has roughly one chance in sixty-four of carrying 0x3C in bits 31:26 — after which its opcode field happened to land on the one gap in the table. So unsupported MIMG opcode 229 is a coincidence, not a missing ISA operation. Two supporting points: 0xE5 is also absent from LLVM's gfx1013 tables and from sharpemu's decoder, and ray-intersection instructions would be meaningless here anyway — Oberon has no ray-tracing hardware, so a PS5 title never emits them.

    The defect is therefore a desync: the decode walked into non-code. Either the code span handed to the decoder extends past the shader's instruction section, or an earlier instruction was consumed with the wrong size and every word after it started at the wrong boundary. The ten-word window cannot tell those apart, so I instrumented the failure to dump the whole code span once and am re-running; locating the last valid instruction boundary in that dump should name the instruction whose size we get wrong.

    I will post the desync point here and narrow this issue accordingly — its subject changes from "missing opcode" to "the walk leaves the code section". Leaving it open in the meantime.

    Written with AI assistance.

  6. Dextroid17 commented on Oct 9, 2026

    @Dextroid17
    ContributorAuthor

    Correction to my previous comment, before anyone acts on it.

    I claimed "nine of the ten words are not valid instructions" using (word >> 26) & 0x3F against the major
    opcodes I found by grepping the decoder. That test was wrong. The decoder's own family rule
    (GetRdnaInstructionFamily) has three branches, not one:

    • bit31 == 0 → the short VOP forms (VOP2 by default, VOP1/VOPC by bits 25:30);
    • bits 31:30 == 10 → the SOP family, selected by (word >> 23) & 0x7F;
    • otherwise → the long-form majors (VINTRP VOP3P VOP3 DS FLAT MUBUF MTBUF MIMG SMEM EXP).

    Re-evaluated with that rule, all ten words are legal instruction starts (361a6e87 VOP2, beea0f7e SOP1,
    8126a026 SOP2, 8125256a SOP2, f1949f05 MIMG, then VOP2/SOP-family words). So the window is not evidence
    of reading non-code.

    Worse, that test has almost no power either way: any word with bit31 clear is accepted as VOP2, which is
    roughly half of all random words. It cannot separate code from data.

    What still stands, unchanged:

    • 0xE5 is not a defined MIMG opcode in LLVM's tables for any gfx variant, nor in sharpemu's decoder.
    • This project's table carries 0xE6/0xE7 (and sharpemu names them) but has no 0xE5.
    • The title reached program counter 0x410 with word f1949f05, whose encoded word is the same shape as
      image_bvh64_intersect_ray (f19c9f01, opcode 0xE7) and image_bvh_intersect_ray (f1989f01, 0xE6) —
      one step below them in that consecutive group.

    So the open question is still "reserved encoding, or a walk that is off", and the test that separates them is
    a walk trace (index, family, opcode and word count per instruction), not a window of raw words. I have the
    code-span dump in flight and will post the trace next.

    Written with AI assistance.

  7. EdouardSence commented on Oct 9, 2026

    @EdouardSence
    Contributor

    Same instruction here on AMD, reached about 15 s after boot instead of about 24 min. That makes it quick to reproduce for whoever looks at it.

    llvm-mc from ROCm 7.2.4 (-mcpu=gfx1013, gfx1030, gfx1010) also rejects these words as invalid instruction encoding, so I agree it's best kept unknown until there's a PS5-specific source.

    Tested and written by Claude (AI assistant) on a contributor's machine.

  8. Dextroid17 commented on Oct 9, 2026

    @Dextroid17
    ContributorAuthor

    Status update: the affected shaders no longer abort the title. #2257 defers them (the opcode is named in the reason, and they still throw when a draw needs them), measured on PPSA26344 — before: terminate … unsupported MIMG opcode 229; after: could not be prepared at registration (unsupported MIMG opcode 229) and the title carries on.

    That does not close this issue: 0xE5 remains unidentified, so the shaders are still not compiled. Also worth recording from the offline work: the failing word is reproducible from the title's own shader store (cache_ps5/all_shaders.xpps, code word 260), which makes this cheap to re-check without running the game.

  9. Dextroid17 commented on Oct 9, 2026

    @Dextroid17
    ContributorAuthor

    Import-coverage audit for this title, for anyone picking up the wall above.

    Reproduced with the documented pipeline (docs/user/USAGE.md):

    relinker --registry decrypted/eboot.bin app.elf
    python3 tools/import_audit.py app.registry.json --libs build/core/libs/libs --modules decrypted/sce_module
    

    Result for PPSA26344's executable:

    • 822 references, 702 unique imports
    • 527 implemented · 39 stub · 136 provided by the title's own modules · 0 absent
    • 0 missing libraries, 0 library mismatches

    So nothing the executable imports is unresolved. The residual risk in the import path is the 39 NIDs that are only stubs — they abort when called. The ones that bear on rendering all live in this project's own libSceAgc.prx:

    • sceAgcGetDefaultCxStateFlat — AAeX-U5-P3M
    • sceAgcAcbSetFlip — ebixW91gpPw
    • sceAgcAcbWaitUntilSafeForRendering — GPbUp9jXQa8
    • sceAgcDebugRaiseException — T6xuVw0KUJo

    Corroborated independently: all four are exactly 23-byte exports in the relinked module (readelf --dyn-syms over its 281 exported FUNCs: min 5, median 39, p90 231, max 3061), i.e. one shared generated stub body — matching import_audit's stub classification from a different direction.

    The other 35 are libScePsml (MFSR, 10), libSceVoiceQoS (11), five sceCoredump* in libkernel, sceAjmBatchJobControl, and a few audio/NP/system-service NIDs.

    Expectation, not a measured fact: once this title gets past the shader decode above and reaches presentation, sceAgcAcbSetFlip / sceAgcAcbWaitUntilSafeForRendering are the next things it can trip over, since it does import them. No run of ours has reached a draw yet, and the logs show no stub abort — consistent with those stubs sitting after this wall rather than before it.

    Written with AI assistance.

  10. Dextroid17 commented on Oct 9, 2026

    @Dextroid17
    ContributorAuthor

    Follow-up: the classification above is now confirmed at the source level, not only by export size.

    Decompiling that export in our own relinked module with Ghidra (address = dynsym value + image base 0x100000; passing the raw NID as a procedure selector is rejected, the address works):

    undefined8 sceAgcGetDefaultCxStateFlat(void)
    {
        NotImplemented_nid_no_patch("sceAgcGetDefaultCxStateFlat");
        return 0;
    }

    That is exactly the stub class as docs/user/USAGE.md defines it — the whole function calls NotImplemented_nid_no_patch and throws when the title calls it. So for AAeX-U5-P3M the audit's classification and the object code agree; the remaining three AGC stubs are byte-identical 23-byte exports, i.e. the same body.

    Written with AI assistance.

  11. EdouardSence commented on Oct 9, 2026

    @EdouardSence
    Contributor

    For the two flip stubs in that list: #1585 implements sceAgcAcbSetFlip and sceAgcAcbWaitUntilSafeForRendering, with the compute-queue flip and rendering-wait packets and tests. So if Yōtei reaches them, #1585 is the PR to stack.

    Written by Claude (AI assistant) on a contributor's machine.

  12. EdouardSence commented on Oct 9, 2026

    @EdouardSence
    Contributor

    Correction to my last comment: #1585 was closed this morning, because no title was shown to reach those two functions on main. It can be reopened with a title ID and log line. So if Yōtei reaches sceAgcAcbSetFlip or sceAgcAcbWaitUntilSafeForRendering, that log line is what it needs.

    Written by Claude (AI assistant) on a contributor's machine.

  13. Dextroid17 commented on Oct 9, 2026

    @Dextroid17
    ContributorAuthor

    The two decoders agree on the span, and the runtime's own dumped window pins where the span starts — so the "walk that is off" horn is not supported.

    Method (offline; the title's own shader store, no game run). The log for this wall prints pc=0x410 wordIndex=260 and the words at indices 256..265. That ten-word sequence occurs exactly once in cache_ps5/all_shaders.xpps, at offset 3235660 = 3234636 + 256*4. The runtime's wordIndex is by construction the index into the code array (pc = wordIndex*4, code[0] = the decode start), so matching that window to a unique file offset pins the decode start at file offset 3234636 and the failing word f1949f05 at index 260 (offset 3235676). (The span's word 0 is bfa00003 = s_inst_prefetch 0x3, a normal prologue.)

    I walked that 320-word span two ways:

    1. the project's own RdnaInstructionDecoder, built standalone, calling DecodeRdnaInstruction in a loop; and
    2. llvm-mc -disassemble -arch=amdgcn -mcpu=gfx1013 --show-encoding (LLVM 23.1.1).

    The two walks are position-identical for all 196 instructions up to the failure: comparing the ordered boundary sequences (LLVM's per-instruction byte counts from --show-encoding against the project's per-instruction indices) gives zero mismatches, and LLVM's last instruction ends exactly at word 260. Mnemonics agree at the tail:

      word 257  s_bcnt1_i32_b32 vcc_lo, exec_lo
      word 258  s_add_i32 s38, s38, 32
      word 259  s_add_i32 s37, vcc_lo, s37     <- last instruction before the failure
      word 260  f1949f05                        <- the failure
    

    No unconditional branch and no s_endpgm precedes word 260 — every branch before it is conditional — so 260 sits on the fall-through path of valid code.

    What 260 is. MIMG-major ((w>>26) == 0x3C) with opcode ((w>>18)&0x7f)|((w&1)<<7) = 0xE5, which the project's own table does not define (RdnaImageOpDecoder.cpp carries 0xE6/0xE7 but not 0xE5), and which llvm-mc rejects as invalid instruction encoding. Not a one-off: the store carries 38 MIMG-major 0xE5 words (f1949f05 ×34, f1962969 ×4).

    Why it cannot be a size bug. MIMG's width is 2 + nsa, and nsa = (word0 >> 1) & 3 is read from word0 independently of the opcode lookup — so an unknown opcode can only throw, never change the width the walk consumes.

    Where that leaves #1941. The failure is consistent with a reserved/undocumented MIMG opcode, not a decoder that consumed the wrong number of words; identifying 0xE5 still needs a hardware or spec source, as before. No change is posted for this.

    Reproduce (Linux, g++ and llvm-mc):

    # the failing shader's span: 320 words from the decode start
    dd if=all_shaders.xpps of=span.bin bs=1 skip=3234636 count=1280
    
    # the project's decoder, in a loop over DecodeRdnaInstruction
    g++ -std=c++20 -O0 \
      -I core/shader/recompiler -I core/shader/recompiler/RdnaDecoder/include \
      -I core/shader/recompiler/IntermediateRepresentation/include \
      -I core/shader/recompiler/ControlFlow/include -I core/shader/recompiler/Optimization/include \
      -I core/shader/recompiler/SpirvBackend/include -I core/shader/recompiler/Translation/include \
      walk.cpp core/shader/recompiler/RdnaDecoder/src/*.cpp -o walk && ./walk span.bin 0 320
    
    # LLVM's boundaries + encodings over the same bytes
    python3 -c "d=open('span.bin','rb').read()[:260*4]; print(' '.join('0x%02x'%b for b in d))" \
      | llvm-mc -disassemble -arch=amdgcn -mcpu=gfx1013 --show-encoding

    Written with AI assistance.

  14. Dextroid17 commented on Oct 10, 2026

    @Dextroid17
    ContributorAuthor

    This one can be closed out: 0xE5 is the fifth member of the gather4 family the enumeration above already lists.

    Reading the title's own shader store (cache_ps5/all_shaders.xpps), all 38 4-byte-aligned sites whose extracted opcode is 0xE5 decode on gfx1100 as image_gather4_c_b_cl — the raw bytes as they sit in the file, not a reconstruction:

    @0x0731c0  69 29 96 f1 00 03 0c 00 01 00 00 00 d1 4a 09 9e   (f1962969)
               image_gather4_c_b_cl  v[3:4], [v0, v1, v0, v0, v[0:1]], s[48:55], s[0:3] dmask:0x9 dim:SQ_RSRC_IMG_3D dlc d16
    
    @0x0dcb6c  05 9f 94 f1 01 01 07 00 02 16 17 11 0e 23 00 00   (f1949f05)
               image_gather4_c_b_cl  v[1:4], [v1, v2, v22, v23, v17], s[28:35], s[0:3] dmask:0xf dim:SQ_RSRC_IMG_2D slc r128
    

    34 sites are the first word, 4 are the second. gfx1013 and gfx1030 reject the same bytes — the same "encoding absent from the table" situation as the rest of this family, which is why nothing in LLVM's MIMG tables names it.

    It lines up exactly with the enumeration in the comment above:

    0xE0  image_get_lod
    0xE1  image_gather4_b_cl      0xE2  image_gather4_c_cl
    0xE3  image_gather4_c_l       0xE4  image_gather4_c_b
    0xE5  <- the fifth gather
    

    Those four are, in order, AMD's RDNA3 numbering for 97–100, and 101 there is IMAGE_GATHER4_C_B_CL. The whole get_lod-plus-five-gathers block sits at 0x60–0x65 on RDNA3 and at 0xE0–0xE5 on this enumeration, so 0xE5 is that block's last member.

    So the correction to my own earlier "undefined in every variant": undefined in LLVM's tables, yes, but the instruction is identifiable — it is not an anonymous gap beside the BVH pair.

    Caveat worth keeping: no table defines 0xE5 for gfx1013 itself, so this rests on the family ordering plus the gfx1100 decode. Whoever implements it should validate the semantics rather than trust the neighbour.

    Written with AI assistance.

  15. Dextroid17 commented on Oct 10, 2026

    @Dextroid17
    ContributorAuthor

    Correction to my comment above, before anyone acts on it.

    I said 0xE5 is the fifth member of the gather4 sequence listed there. The ordering is what does not hold up, and the check is cheap:

    constructed MIMG words, disassembled with llvm-mc:
      0xE0-0xE5   ->  v_illegal            on gfx1010, gfx1013, gfx1030
      0x60        ->  image_get_lod        on gfx1010, gfx1013, gfx1030
      0x61        ->  image_gather4h       on gfx1010, gfx1013, gfx1030
      0x4E        ->  image_gather4_c_b_cl on gfx1010, gfx1013, gfx1030
    

    The known encodings decode, so the words are well formed — and every 0xE0–0xE5 value is illegal on this GPU family.

    It is not illegal everywhere, though: gfx1100 decodes all six, as image_gather4_cl at 0xE0 and the five gathers image_gather4_b_cl, _c_cl, _c_l, _c_b, _c_b_cl at 0xE1–0xE5. So the block is a real gfx11 block, not a gfx1013 one, and my "fifth member" reading borrowed gfx11's numbering for a gfx1013 shader. That borrowed numbering is the unsupported step.

    It matters because the sourced gfx1013 encoding of the same operation is different: LLVM's assembler encodes image_gather4_c_b_cl on gfx1013 as word 0xf138010a, opcode 0x4E — which this table already carries, and main has it. So the operation is implemented and its gfx1013 encoding is known. 0xE5 is something else.

    The title's bytes are gfx1100-shaped: all 38 sites decode on gfx1100 as image_gather4_c_b_cl, and gfx1010/gfx1013/gfx1030 reject the same raw bytes.

    On the trial build, corrected: with a local mapping for 0xE0–0xE5 the refusals stopped being unsupported MIMG opcode 229 (9 → 0) and became unsupported or reserved MIMG control bits (0 → 9) — the same nine shaders, and the deferred total was unchanged at 121, so nothing was actually unblocked. The check that fails there is word0 against the class's reserved mask (bit 12 for f1949f05, bit 6 for f1962969) rather than word1: word1's mask is bits 26–29, and bits 16–18 are the resource field. Bit 12 is the gradient-count field, which a gather must not set — evidence that the word is not a gather at all. That mapping is an unconfirmed local experiment; I am not proposing it here.

    So 0xE5 is still unidentified, and the open question is now sharper: why does a gfx1013 title emit a gfx11-shaped MIMG word instead of the gfx1013 encoding of the operation? The project's hardware oracle needs an AMD device and my box is NVIDIA, so I cannot run it — that is where I would look next.

    Written with AI assistance.

  16. Dextroid17 commented on Oct 10, 2026

    @Dextroid17
    ContributorAuthor

    Leaving the next step here so the issue stays actionable rather than parked on my inference.

    docs/dev/HW_ORACLE.md says other RDNA2 parts (gfx103x) share the MIMG encodings with this GPU, so tools/hw-oracle/ on any AMD RDNA2 card under Linux can answer what a table cannot: whether 0xE5 is accepted on real silicon and what it does. It needs the amdgpu driver with read access to /dev/kfd and a ROCm runtime, so my NVIDIA box cannot run it and I am not asking anyone on this thread to.

    The question worth putting to the oracle is the one the title raises: a gfx1013 title emits words that only gfx1100's tables decode (as image_gather4_c_b_cl), while gfx1013's own encoding of that operation is 0x4E and is already implemented here. Until something outside LLVM's tables says what 0xE5 means, this stays open.

    Written with AI assistance.

  17. Dextroid17 commented on Oct 10, 2026

    @Dextroid17
    ContributorAuthor

    Following the comment above with the measurement I should have led with, plus two corrections to it.

    This store is gfx10-family, and 0xE5 is an unassigned opcode inside it. Disassembling each encoding's real sites on both families (llvm-mc, -triple=amdgcn, raw bytes, up to six aligned sites each):

    encoding   gfx1030 (gfx10 family)             gfx1100 (gfx11)
    0x60       image_get_lod (5/6)             |  image_gather4_cl (6/6)
    0xA3       image_sample_d_cl_g16 (6/6)     |  image_sample_c_b (6/6)
    0xE8       image_sample_cd_g16 (2/3)       |  - (0/3)
    0xE6       image_bvh_intersect_ray (3/6)   |  - (0/6)
    0xE7       image_bvh64_intersect_ray (3/4) |  - (0/4)
    0xE1       - (0/2)                         |  image_gather4_b_cl (1/2)
    0xE5       - (0/6, and 0/38 in a full pass) |  image_gather4_c_b_cl (2/6, 38/38 full)
    

    The decisive rows are 0xE6/0xE7. In LLVM's tables IMAGE_BVH_INTERSECT_RAY is mimgopc<gfx11=0x19, gfx10m=0xe6> and IMAGE_BVH64_INTERSECT_RAY is <0x1a, 0xe7>: the gfx10 family uses 0xE6/0xE7, gfx11 moved them to 0x19/0x1A. Those words decode only on gfx1030 and gfx1013, never on gfx1100 — so this is a gfx10-family store.

    That also explains the 0xE5 words, and why the gfx1100 name is a coincidence rather than an identification. The gfx10 opcode space is 8-bit with the top bit carried in word0 bit 0 — which is how 0xE6/0xE7 exist at all — so these words are opcode 0xE5. gfx11 reads a clean 8-bit field at bits 25:18, where the same bits are 0x65, and gfx11's IMAGE_GATHER4_C_B_CL is 0x65. Same bit pattern, two field positions, different answers. The store is gfx10-family, so 0xE5 is the reading that applies — and nothing assigns it. It sits immediately below the only two opcodes that are gfx1013-specific.

    Two corrections to the comment above, since it is the one that will be read first:

    • It says the trial build's failure "is word0 bit 12, the gradient-count field, which a gather must not set". That is wrong. This store contains words that genuinely decode as image_gather4* on gfx1030 with bit 12 set, so bit 12 is not a field gathers are barred from; the failing check is word0 against the reserved mask for the op class, and the meaning I put on that bit does not hold. Withdrawn.
    • "The title's bytes are gfx1100-shaped" is true only of the 0xE5 words. It reads as though it covers the whole store, and the store is gfx10-family.

    So 0xE5 is an unassigned gfx10-family opcode sitting beside the two gfx1013-only BVH ops — the shape of a gfx1013-specific extension that the public tables do not carry. Settling it needs the hardware oracle on an AMD RDNA2 device rather than another reading of the bits.

    Written with AI assistance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions