From 0223ab01b7bf76b3f329cd8975ac9c3ac80d039a Mon Sep 17 00:00:00 2001 From: Job Noorman Date: Tue, 19 Aug 2025 08:35:37 +0200 Subject: [PATCH] ir3/isa: add encoding for scalar predicates Predicate registers can be written from the scalar ALU by using a special cat2 encoding: if the dst is encoded as a0.c, the instruction will execute on the scalar ALU and write to p0.c. This commit follows the blob and disassembles scalar predicates as up0.c. The "u" presumably stands for "uniform". Signed-off-by: Job Noorman Part-of: --- src/freedreno/ir3/ir3_lexer.l | 4 ++++ src/freedreno/ir3/ir3_parser.y | 2 ++ src/freedreno/ir3/tests/disasm.c | 2 ++ src/freedreno/isa/encode.c | 12 ++++++++++++ src/freedreno/isa/ir3-cat2.xml | 32 +++++++++++++++++++++++++++++++- 5 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/freedreno/ir3/ir3_lexer.l b/src/freedreno/ir3/ir3_lexer.l index de4a087628b..aca583cab0b 100644 --- a/src/freedreno/ir3/ir3_lexer.l +++ b/src/freedreno/ir3/ir3_lexer.l @@ -95,6 +95,9 @@ static int parse_reg(const char *str) str++; num++; } + if (str[0] == 'u') { + str++; + } str++; if (str[0] == 't') { str++; @@ -178,6 +181,7 @@ static int parse_reg(const char *str) "a0.x" return T_A0; "a1.x" return T_A1; "p0."[xyzw] ir3_yylval.num = parse_reg(yytext); return T_P0; +"up0."[xyzw] ir3_yylval.num = parse_reg(yytext); return T_UP0; "w"[0-9]+ ir3_yylval.num = strtol(yytext+1, NULL, 10); return T_W; "s#"[0-9]+ ir3_yylval.num = strtol(yytext+2, NULL, 10); return T_SAMP; "t#"[0-9]+ ir3_yylval.num = strtol(yytext+2, NULL, 10); return T_TEX; diff --git a/src/freedreno/ir3/ir3_parser.y b/src/freedreno/ir3/ir3_parser.y index f17deb3978a..83f1d8bf4b9 100644 --- a/src/freedreno/ir3/ir3_parser.y +++ b/src/freedreno/ir3/ir3_parser.y @@ -773,6 +773,7 @@ static void print_token(FILE *file, int type, YYSTYPE value) %token T_A0 %token T_A1 %token T_P0 +%token T_UP0 %token T_W %token T_CAT1_TYPE_TYPE @@ -1613,6 +1614,7 @@ dst: T_REGISTER { $$ = new_dst($1, 0); } | T_A0 { $$ = new_dst((61 << 3), IR3_REG_HALF); } | T_A1 { $$ = new_dst((61 << 3) + 1, IR3_REG_HALF); } | T_P0 { $$ = new_dst((62 << 3) + $1, IR3_REG_PREDICATE); } +| T_UP0 { $$ = new_dst((62 << 3) + $1, IR3_REG_PREDICATE | IR3_REG_UNIFORM); } const: T_CONSTANT { $$ = new_src($1, IR3_REG_CONST); } diff --git a/src/freedreno/ir3/tests/disasm.c b/src/freedreno/ir3/tests/disasm.c index 698e28fc104..b9f0c735dce 100644 --- a/src/freedreno/ir3/tests/disasm.c +++ b/src/freedreno/ir3/tests/disasm.c @@ -117,6 +117,8 @@ static const struct test { INSTR_7XX(42380800_04010400, "(nop3) add.s r0.x, (last)r0.x, (last)r0.y"), INSTR_7XX(42930000_04000406, "cmps.u.ge r0.x, (last)r1.z, (last)r0.x"), + INSTR_7XX(429000f5_100600c1, "cmps.u.lt up0.y, r48.y, c1.z"), + /* cat3 */ INSTR_6XX(66000000_10421041, "sel.f16 hr0.x, hc16.y, hr0.x, hc16.z"), INSTR_6XX(64848109_109a9099, "(rpt1)sel.b32 r2.y, c38.y, (r)r2.y, c38.z"), diff --git a/src/freedreno/isa/encode.c b/src/freedreno/isa/encode.c index 1b1876b6e2f..114b73f49d8 100644 --- a/src/freedreno/isa/encode.c +++ b/src/freedreno/isa/encode.c @@ -130,6 +130,18 @@ extract_reg_uim(const struct ir3_register *reg) return reg->uim_val; } +static inline uint32_t +extract_dst_num(const struct ir3_register *reg) +{ + if (reg->flags & IR3_REG_UNIFORM) { + assert(reg->flags & IR3_REG_PREDICATE); + assert(reg_num(reg) == REG_P0); + return REG_A0; + } + + return reg_num(reg); +} + /** * This is a bit messy, to deal with the fact that the optional "s2en" * src is the first src, shifting everything else up by one. diff --git a/src/freedreno/isa/ir3-cat2.xml b/src/freedreno/isa/ir3-cat2.xml index e1901cc8e53..9c516fdabde 100644 --- a/src/freedreno/isa/ir3-cat2.xml +++ b/src/freedreno/isa/ir3-cat2.xml @@ -28,8 +28,38 @@ SOFTWARE. Cat2 Instructions: one and two src ALU instructions --> + + + + Predicate registers can be written from the scalar + ALU by using a special cat2 encoding: if the dst is + encoded as a0.c, the instruction will execute on the + scalar ALU and write to p0.c. + + + up0.{SWIZ} + + 111101 + + + + p0.{SWIZ} + + 111110 + + + r{GPR}.{SWIZ} + + + + + extract_dst_num(src) + src->num & 0x3 + + + - +