From 96887a5ec1ee061e087c0deb185d43033f6f63f2 Mon Sep 17 00:00:00 2001 From: Job Noorman Date: Wed, 12 Feb 2025 07:29:03 +0100 Subject: [PATCH] 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< Part-of: --- src/freedreno/ir3/ir3_parser.y | 50 ++++++++++++------- src/freedreno/ir3/tests/disasm.c | 23 +++++---- src/freedreno/isa/ir3-cat6.xml | 84 ++++++++++++++++++++++++++------ 3 files changed, 112 insertions(+), 45 deletions(-) diff --git a/src/freedreno/ir3/ir3_parser.y b/src/freedreno/ir3/ir3_parser.y index ea24aabb56e..b46e3b9826d 100644 --- a/src/freedreno/ir3/ir3_parser.y +++ b/src/freedreno/ir3/ir3_parser.y @@ -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 cat4_opc %type cat5_opc cat5_samp cat5_tex cat5_type %type type -%type const_val +%type 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 diff --git a/src/freedreno/ir3/tests/disasm.c b/src/freedreno/ir3/tests/disasm.c index 6dbc4da5d6f..a0385ae6d8e 100644 --- a/src/freedreno/ir3/tests/disasm.c +++ b/src/freedreno/ir3/tests/disasm.c @@ -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"), diff --git a/src/freedreno/isa/ir3-cat6.xml b/src/freedreno/isa/ir3-cat6.xml index d5b47122fb5..6d377c3998a 100644 --- a/src/freedreno/isa/ir3-cat6.xml +++ b/src/freedreno/isa/ir3-cat6.xml @@ -79,6 +79,14 @@ SOFTWARE. + + {TYPE} >= 6 ? 0 /* u8 */ : ({TYPE_HALF} ? 1 : 2); + + + + {TYPE_SHIFT} + {SRC2_SHIFT} + + 1 @@ -117,35 +125,64 @@ SOFTWARE. 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<<SRC2_SHIFT) + OFF)<<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. - {SY}{JP}{NAME}.{TYPE} {TYPE_HALF}{DST}, g[{SRC1}+({SRC2}{OFF})<<{SRC2_BYTE_SHIFT}], {SIZE} + {SY}{JP}{NAME}.{TYPE} {TYPE_HALF}{DST}, g[{SRC1}+((({SRC2}<<{SRC2_SHIFT}){OFF})<<{TYPE_SHIFT})], {SIZE} - {SY}{JP}{NAME}.{TYPE} {TYPE_HALF}{DST}, g[{SRC1}+{SRC2}<<{SRC2_BYTE_SHIFT}{OFF}<<2], {SIZE} + {SY}{JP}{NAME}.{TYPE} {TYPE_HALF}{DST}, g[{SRC1}+{SRC2}{OFF}], {SIZE} - {SRC2_ADD_DWORD_SHIFT} > 0 + {TYPE_SHIFT} == 0 + + + + + {SY}{JP}{NAME}.{TYPE} {TYPE_HALF}{DST}, g[{SRC1}+({SRC2}<<{FULL_SHIFT})], {SIZE} + + {OFF} == 0 + + + + + {SY}{JP}{NAME}.{TYPE} {TYPE_HALF}{DST}, g[{SRC1}+(({SRC2}{OFF})<<{TYPE_SHIFT})], {SIZE} + + {SRC2_SHIFT} == 0 0 - + 1 xxxxxxxx - - {SRC2_ADD_DWORD_SHIFT} + 2 - + + src->srcs[1] - extract_reg_uim(src->srcs[2]) + extract_reg_uim(src->srcs[2]) extract_reg_uim(src->srcs[3]) extract_reg_uim(src->srcs[4]) @@ -260,28 +297,43 @@ SOFTWARE. STore Global + + See the doc of ldg.a for how the address is calculated. - {SY}{JP}{NAME}.{TYPE} g[{SRC1}+({SRC2}{OFF})<<{DST_BYTE_SHIFT}], {TYPE_HALF}{SRC3}, {SIZE} + {SY}{JP}{NAME}.{TYPE} g[{SRC1}+((({SRC2}<<{SRC2_SHIFT}){OFF})<<{TYPE_SHIFT})], {TYPE_HALF}{SRC3}, {SIZE} - {SY}{JP}{NAME}.{TYPE} g[{SRC1}+{SRC2}<<{DST_BYTE_SHIFT}{OFF}<<2], {TYPE_HALF}{SRC3}, {SIZE} + {SY}{JP}{NAME}.{TYPE} g[{SRC1}+{SRC2}{OFF}], {TYPE_HALF}{SRC3}, {SIZE} - {SRC2_ADD_DWORD_SHIFT} > 0 + {TYPE_SHIFT} == 0 - - {SRC2_ADD_DWORD_SHIFT} + 2 - + + + {SY}{JP}{NAME}.{TYPE} g[{SRC1}+({SRC2}<<{FULL_SHIFT})], {TYPE_HALF}{SRC3}, {SIZE} + + {OFF} == 0 + + + + + {SY}{JP}{NAME}.{TYPE} g[{SRC1}+(({SRC2}{OFF})<<{TYPE_SHIFT})], {TYPE_HALF}{SRC3}, {SIZE} + + {SRC2_SHIFT} == 0 + + + + 0 - + xxxxxxxx 1x @@ -289,7 +341,7 @@ SOFTWARE. src->srcs[1] - extract_reg_uim(src->srcs[2]) + extract_reg_uim(src->srcs[2]) extract_reg_uim(src->srcs[3]) src->srcs[4] extract_reg_uim(src->srcs[5])