ir3/isa: fix (dis)asm of ldg.a/stg.a on a6xx

We currently assume the implicit offset shift is always 2. However, this
shift is actually based on the type, making sure the offset fields are
in units of the type size. The full offset calculation is as follows:

    ((SRC2<<SRC2_SHIFT) + OFF)<<TYPE_SHIFT

Where SRC2, SRC2_SHIFT, and OFF are instruction fields while TYPE_SHIFT
is implicit and derived from the TYPE field.

This commit implements (dis)assembly support for this, adopting the
syntax used by the blob.

Signed-off-by: Job Noorman <jnoorman@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33503>
This commit is contained in:
Job Noorman
2025-02-12 07:29:03 +01:00
committed by Marge Bot
parent 5a8193e657
commit 96887a5ec1
3 changed files with 112 additions and 45 deletions
+33 -17
View File
@@ -305,6 +305,11 @@ static bool resolve_labels(void)
return true;
}
static unsigned cat6_type_shift()
{
return util_logbase2(type_size(instr->cat6.type) / 8);
}
#ifdef YYDEBUG
int yydebug;
#endif
@@ -782,7 +787,7 @@ static void print_token(FILE *file, int type, YYSTYPE value)
%type <tok> cat4_opc
%type <tok> cat5_opc cat5_samp cat5_tex cat5_type
%type <type> type
%type <unum> const_val
%type <unum> const_val cat6_src_shift
%error-verbose
@@ -1240,25 +1245,36 @@ cat6_dst_offset: offset { instr->cat6.dst_offset = $1; }
cat6_immed: integer { instr->cat6.iim_val = $1; }
cat6_a6xx_global_address_pt3:
'<' '<' integer offset '<' '<' integer {
assert($7 == 2);
new_src(0, IR3_REG_IMMED)->uim_val = $3 - 2;
new_src(0, IR3_REG_IMMED)->uim_val = $4;
}
| '+' cat6_reg_or_immed {
// Dummy src to smooth the difference between a6xx and a7xx
new_src(0, IR3_REG_IMMED)->uim_val = 0;
}
cat6_src_shift: '<' '<' integer {$$ = $3;}
| {$$ = 0;}
cat6_a6xx_global_address_pt2:
'(' src offset ')' '<' '<' integer {
assert($7 == 2);
new_src(0, IR3_REG_IMMED)->uim_val = 0;
new_src(0, IR3_REG_IMMED)->uim_val = $3;
'(' '(' '(' src cat6_src_shift ')' offset ')' '<' '<' integer ')' {
illegal_syntax_from(7, "pre-a7xx global offset syntax");
new_src(0, IR3_REG_IMMED)->uim_val = $5;
new_src(0, IR3_REG_IMMED)->uim_val = $7;
}
| '(' '(' src cat6_src_shift offset ')' '<' '<' integer ')' {
illegal_syntax_from(7, "pre-a7xx global offset syntax");
new_src(0, IR3_REG_IMMED)->uim_val = $4;
new_src(0, IR3_REG_IMMED)->uim_val = $5;
}
| '(' src cat6_src_shift ')' {
illegal_syntax_from(7, "pre-a7xx global offset syntax");
// The shift contains the implicit type shift, subtract it.
new_src(0, IR3_REG_IMMED)->uim_val = $3 - cat6_type_shift();
new_src(0, IR3_REG_IMMED)->uim_val = 0;
}
| src offset {
if (variant->compiler->gen < 7) {
new_src(0, IR3_REG_IMMED)->uim_val = 0;
new_src(0, IR3_REG_IMMED)->uim_val = $2;
} else {
new_src(0, IR3_REG_IMMED)->uim_val = $2;
// Dummy src to smooth the difference between a6xx and a7xx
new_src(0, IR3_REG_IMMED)->uim_val = 0;
}
}
| src cat6_a6xx_global_address_pt3
cat6_a6xx_global_address:
src_reg_or_const '+' cat6_a6xx_global_address_pt2
+11 -12
View File
@@ -205,9 +205,9 @@ static const struct test {
// TODO is this a real instruction? Or float -6.0 ?
// INSTR_6XX(c0c00000_00000000, "stg.f16 g[hr0.x], hr0.x, hr0.x", .parse_fail=true),
/* dEQP-GLES31.functional.tessellation.invariance.outer_edge_symmetry.isolines_equal_spacing_ccw */
INSTR_6XX(c0d20906_02800004, "stg.a.f32 g[r1.x+(r1.z)<<2], r0.z, 2"), /* stg.a.f32 g[r1.x+(r1.z<<2)], r0.z, 2 */
INSTR_6XX(c0da052e_01800042, "stg.a.s32 g[r0.z+(r11.z)<<2], r8.y, 1"), /* stg.a.s32 g[r0.z+(r11.z<<2)], r8.y, 1 */
INSTR_6XX(c0dc052e_01800042, "stg.a.u8 g[r0.z+(r11.z)<<2], hr8.y, 1"),
INSTR_6XX(c0d20906_02800004, "stg.a.f32 g[r1.x+(r1.z<<2)], r0.z, 2"),
INSTR_6XX(c0da052e_01800042, "stg.a.s32 g[r0.z+(r11.z<<2)], r8.y, 1"),
INSTR_6XX(c0dc052e_01800042, "stg.a.u8 g[r0.z+r11.z], hr8.y, 1"),
INSTR_6XX(c0ca0505_03800042, "stg.s32 g[r0.z+5], r8.y, 3"),
INSTR_6XX(c0ca0500_03800042, "stg.s32 g[r0.z], r8.y, 3"),
INSTR_6XX(c0ca0531_03800242, "stg.s32 g[r0.z+305], r8.y, 3"),
@@ -220,30 +220,29 @@ static const struct test {
INSTR_7XX(c0260207_00630100, "resbase.untyped.1d.u32.1.imm.base0 r1.w, 1"), /* resbase.u32.1d.mode4.base0 r1.w, 1 */
/* Customely crafted */
INSTR_6XX(c0d61104_01800228, "stg.a.u32 g[r2.x+(r1.x+1)<<2], r5.x, 1"),
INSTR_6XX(c0d61104_01802628, "stg.a.u32 g[r2.x+r1.x<<4+3<<2], r5.x, 1"),
INSTR_6XX(c0d61104_01800228, "stg.a.u32 g[r2.x+((r1.x+1)<<2)], r5.x, 1"),
INSTR_6XX(c0d61104_01802628, "stg.a.u32 g[r2.x+(((r1.x<<2)+3)<<2)], r5.x, 1"),
INSTR_7XX(c0d20505_07bfc006, "stg.a.f32 g[r0.z+r1.y+255], r0.w, 7"),
INSTR_7XX(c0d20507_04812006, "stg.a.f32 g[c0.z+r1.w+4], r0.w, 4"),
INSTR_6XX(c0020011_04c08023, "ldg.a.f32 r4.y, g[r0.z+(r4.y)<<2], 4"), /* ldg.a.f32 r4.y, g[r0.z+(r4.y<<2)], 4 */
INSTR_6XX(c0060006_01c18017, "ldg.a.u32 r1.z, g[r1.z+(r2.w)<<2], 1"), /* ldg.a.u32 r1.z, g[r1.z+(r2.w<<2)], 1 */
INSTR_6XX(c0020011_04c08023, "ldg.a.f32 r4.y, g[r0.z+(r4.y<<2)], 4"),
INSTR_6XX(c0060006_01c18017, "ldg.a.u32 r1.z, g[r1.z+(r2.w<<2)], 1"),
INSTR_6XX(c0060006_0181800f, "ldg.u32 r1.z, g[r1.z+7], 1"),
INSTR_6XX(c0060006_01818001, "ldg.u32 r1.z, g[r1.z], 1"),
INSTR_6XX(c0060003_0180c269, "ldg.u32 r0.w, g[r0.w+308], 1"),
INSTR_6XX(c0040003_0180c269, "ldg.u16 hr0.w, g[r0.w+308], 1"),
/* Found in TCS/TES shaders of GTA V */
INSTR_6XX(c0020007_03c1420f, "ldg.a.f32 r1.w, g[r1.y+(r1.w+1)<<2], 3"), /* ldg.a.f32 r1.w, g[r1.y+((r1.w+1)<<2)], 3 */
INSTR_6XX(c0020007_03c1420f, "ldg.a.f32 r1.w, g[r1.y+((r1.w+1)<<2)], 3"),
/* Customely crafted */
INSTR_6XX(c0020007_03c1740f, "ldg.a.f32 r1.w, g[r1.y+r1.w<<5+2<<2], 3"),
INSTR_6XX(c0020007_03c1740f, "ldg.a.f32 r1.w, g[r1.y+(((r1.w<<3)+2)<<2)], 3"),
INSTR_6XX(c0020011_04c08023, "ldg.a.f32 r4.y, g[r0.z+(r4.y)<<2], 4"), /* ldg.a.f32 r4.y, g[r0.z+(r4.y<<2)], 4 */
INSTR_6XX(c0060006_01c18017, "ldg.a.u32 r1.z, g[r1.z+(r2.w)<<2], 1"), /* ldg.a.u32 r1.z, g[r1.z+(r2.w<<2)], 1 */
INSTR_6XX(c0000006_01c18017, "ldg.a.f16 hr1.z, g[r1.z+(r2.w)<<2], 1"),
INSTR_6XX(c0000006_01c18017, "ldg.a.f16 hr1.z, g[r1.z+(r2.w<<1)], 1"),
INSTR_6XX(c0060006_0181800f, "ldg.u32 r1.z, g[r1.z+7], 1"),
INSTR_6XX(c0060006_01818001, "ldg.u32 r1.z, g[r1.z], 1"),
INSTR_6XX(c0060006_01c1b017, "ldg.a.u32 r1.z, g[r1.z+(r2.w<<5)], 1"),
INSTR_7XX(c0020411_04c08023, "ldg.a.f32 r4.y, g[r0.z+r4.y+2], 4"),
INSTR_7XX(c0004006_01c1a017, "ldg.a.f16 hr1.z, g[c1.z+r2.w+32], 1"),
+68 -16
View File
@@ -79,6 +79,14 @@ SOFTWARE.
<!-- TODO pull more fields up to this level, when they are common across sub-encodings -->
</bitset>
<expr name="#cat6-type-shift">
{TYPE} >= 6 ? 0 /* u8 */ : ({TYPE_HALF} ? 1 : 2);
</expr>
<expr name="#cat6-full-shift">
{TYPE_SHIFT} + {SRC2_SHIFT}
</expr>
<bitset name="#instruction-cat6-ldg" extends="#instruction-cat6-a3xx">
<pattern pos="0" >1</pattern>
<field low="14" high="21" name="SRC1" type="#cat6-src-const-or-gpr">
@@ -117,35 +125,64 @@ SOFTWARE.
<bitset name="ldg.a" extends="#instruction-cat6-ldg">
<doc>
LoaD Global
The 64b base address is stored in SRC1 (least significant bits)
and SRC1+1 (most significant bits).
An offset is added to the base address that is calculated as
follows:
((SRC2&lt;&lt;SRC2_SHIFT) + OFF)&lt;&lt;TYPE_SHIFT
TYPE_SHIFT is implicitly given by the TYPE field; it ensures
that the offset is in units of the type. Note that non
type-aligned accesses are still supported if SRC1 is not
aligned.
Note that although SRC2 is 32b, the calculation above does not
cause any 32b overflows: it behaves as if all values are
zero-extended to 64b first.
</doc>
<gen min="600" max="699"/>
<display>
{SY}{JP}{NAME}.{TYPE} {TYPE_HALF}{DST}, g[{SRC1}+({SRC2}{OFF})&lt;&lt;{SRC2_BYTE_SHIFT}], {SIZE}
{SY}{JP}{NAME}.{TYPE} {TYPE_HALF}{DST}, g[{SRC1}+((({SRC2}&lt;&lt;{SRC2_SHIFT}){OFF})&lt;&lt;{TYPE_SHIFT})], {SIZE}
</display>
<override>
<display>
{SY}{JP}{NAME}.{TYPE} {TYPE_HALF}{DST}, g[{SRC1}+{SRC2}&lt;&lt;{SRC2_BYTE_SHIFT}{OFF}&lt;&lt;2], {SIZE}
{SY}{JP}{NAME}.{TYPE} {TYPE_HALF}{DST}, g[{SRC1}+{SRC2}{OFF}], {SIZE}
</display>
<expr>{SRC2_ADD_DWORD_SHIFT} > 0</expr>
<expr>{TYPE_SHIFT} == 0</expr>
</override>
<override>
<display>
{SY}{JP}{NAME}.{TYPE} {TYPE_HALF}{DST}, g[{SRC1}+({SRC2}&lt;&lt;{FULL_SHIFT})], {SIZE}
</display>
<expr>{OFF} == 0</expr>
</override>
<override>
<display>
{SY}{JP}{NAME}.{TYPE} {TYPE_HALF}{DST}, g[{SRC1}+(({SRC2}{OFF})&lt;&lt;{TYPE_SHIFT})], {SIZE}
</display>
<expr>{SRC2_SHIFT} == 0</expr>
</override>
<field low="1" high="8" name="SRC2" type="#reg-gpr"/>
<field low="9" high="10" name="OFF" type="uoffset"/>
<assert pos="11" >0</assert>
<field low="12" high="13" name="SRC2_ADD_DWORD_SHIFT" type="uint"/>
<field low="12" high="13" name="SRC2_SHIFT" type="uint"/>
<pattern pos="22" >1</pattern> <!-- Reg offset ldg form -->
<pattern low="41" high="48">xxxxxxxx</pattern>
<derived name="SRC2_BYTE_SHIFT" width="3" type="uint">
<expr>{SRC2_ADD_DWORD_SHIFT} + 2</expr>
</derived>
<derived name="TYPE_SHIFT" type="uint" expr="#cat6-type-shift"/>
<derived name="FULL_SHIFT" type="uint" expr="#cat6-full-shift"/>
<encode>
<map name="SRC2">src->srcs[1]</map>
<map name="SRC2_ADD_DWORD_SHIFT">extract_reg_uim(src->srcs[2])</map>
<map name="SRC2_SHIFT">extract_reg_uim(src->srcs[2])</map>
<map name="OFF">extract_reg_uim(src->srcs[3])</map>
<map name="SIZE">extract_reg_uim(src->srcs[4])</map>
</encode>
@@ -260,28 +297,43 @@ SOFTWARE.
<bitset name="stg.a" extends="#instruction-cat6-stg">
<doc>
STore Global
See the doc of ldg.a for how the address is calculated.
</doc>
<gen min="600" max="699"/>
<display>
{SY}{JP}{NAME}.{TYPE} g[{SRC1}+({SRC2}{OFF})&lt;&lt;{DST_BYTE_SHIFT}], {TYPE_HALF}{SRC3}, {SIZE}
{SY}{JP}{NAME}.{TYPE} g[{SRC1}+((({SRC2}&lt;&lt;{SRC2_SHIFT}){OFF})&lt;&lt;{TYPE_SHIFT})], {TYPE_HALF}{SRC3}, {SIZE}
</display>
<override>
<display>
{SY}{JP}{NAME}.{TYPE} g[{SRC1}+{SRC2}&lt;&lt;{DST_BYTE_SHIFT}{OFF}&lt;&lt;2], {TYPE_HALF}{SRC3}, {SIZE}
{SY}{JP}{NAME}.{TYPE} g[{SRC1}+{SRC2}{OFF}], {TYPE_HALF}{SRC3}, {SIZE}
</display>
<expr>{SRC2_ADD_DWORD_SHIFT} > 0</expr>
<expr>{TYPE_SHIFT} == 0</expr>
</override>
<derived name="DST_BYTE_SHIFT" width="3" type="uint">
<expr>{SRC2_ADD_DWORD_SHIFT} + 2</expr>
</derived>
<override>
<display>
{SY}{JP}{NAME}.{TYPE} g[{SRC1}+({SRC2}&lt;&lt;{FULL_SHIFT})], {TYPE_HALF}{SRC3}, {SIZE}
</display>
<expr>{OFF} == 0</expr>
</override>
<override>
<display>
{SY}{JP}{NAME}.{TYPE} g[{SRC1}+(({SRC2}{OFF})&lt;&lt;{TYPE_SHIFT})], {TYPE_HALF}{SRC3}, {SIZE}
</display>
<expr>{SRC2_SHIFT} == 0</expr>
</override>
<derived name="TYPE_SHIFT" type="uint" expr="#cat6-type-shift"/>
<derived name="FULL_SHIFT" type="uint" expr="#cat6-full-shift"/>
<field low="9" high="10" name="OFF" type="uoffset"/>
<assert pos="11" >0</assert>
<field low="12" high="13" name="SRC2_ADD_DWORD_SHIFT" type="uint"/>
<field low="12" high="13" name="SRC2_SHIFT" type="uint"/>
<pattern low="14" high="21">xxxxxxxx</pattern>
<pattern low="22" high="23">1x</pattern>
<field low="32" high="39" name="SRC2" type="#reg-gpr"/>
@@ -289,7 +341,7 @@ SOFTWARE.
<encode>
<map name="SRC2">src->srcs[1]</map>
<map name="SRC2_ADD_DWORD_SHIFT">extract_reg_uim(src->srcs[2])</map>
<map name="SRC2_SHIFT">extract_reg_uim(src->srcs[2])</map>
<map name="OFF">extract_reg_uim(src->srcs[3])</map>
<map name="SRC3">src->srcs[4]</map>
<map name="SIZE">extract_reg_uim(src->srcs[5])</map>