From 4b3f58701c68812b43aa198f111a10a04f446b14 Mon Sep 17 00:00:00 2001 From: Job Noorman Date: Thu, 26 Jun 2025 11:35:54 +0200 Subject: [PATCH] ir3/isa: add isaspec definition for movs movs works like subgroupBroadcast/OpGroupNonUniformBroadcast. The fiber id can either be an immediate or a value in a0.x. In the latter case, the value has to be dynamically uniform or else the behavior is undefined. The dst register has to be shared or else the behavior seems to be equivalent to a normal mov (i.e., the fiber id is not taken into account anymore). movs can do a cov on the broadcasted value. It works exactly like a normal cov except that using u8 as the src type does not seem to work at all. Signed-off-by: Job Noorman Part-of: --- src/freedreno/ir3/disasm-a3xx.c | 1 + src/freedreno/ir3/instr-a3xx.h | 3 ++ src/freedreno/ir3/ir3_lexer.l | 1 + src/freedreno/ir3/ir3_parser.y | 7 +++++ src/freedreno/ir3/tests/disasm.c | 3 ++ src/freedreno/isa/encode.c | 6 ++++ src/freedreno/isa/ir3-cat1.xml | 47 ++++++++++++++++++++++++++++++-- 7 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/freedreno/ir3/disasm-a3xx.c b/src/freedreno/ir3/disasm-a3xx.c index 6c80e37ea70..8d684a6608d 100644 --- a/src/freedreno/ir3/disasm-a3xx.c +++ b/src/freedreno/ir3/disasm-a3xx.c @@ -185,6 +185,7 @@ static const struct opc_info { OPC(1, OPC_SWZ, swz), OPC(1, OPC_SCT, sct), OPC(1, OPC_GAT, gat), + OPC(1, OPC_MOVS, movs), OPC(1, OPC_BALLOT_MACRO, ballot.macro), OPC(1, OPC_ANY_MACRO, any.macro), OPC(1, OPC_ALL_MACRO, all.macro), diff --git a/src/freedreno/ir3/instr-a3xx.h b/src/freedreno/ir3/instr-a3xx.h index 5807c817bab..d387113a74d 100644 --- a/src/freedreno/ir3/instr-a3xx.h +++ b/src/freedreno/ir3/instr-a3xx.h @@ -82,6 +82,7 @@ typedef enum { /* category 1: */ OPC_MOV = _OPC(1, 0), OPC_MOVP = _OPC(1, 1), + OPC_MOVS = _OPC(1, 2), /* swz, gat, sct */ OPC_MOVMSK = _OPC(1, 3), @@ -98,6 +99,8 @@ typedef enum { OPC_MOV_GPR = _OPC(1, 42), OPC_MOV_RELGPR = _OPC(1, 43), OPC_MOV_RELCONST = _OPC(1, 44), + OPC_MOVS_IMMED = _OPC(1, 45), + OPC_MOVS_A0 = _OPC(1, 46), /* Macros that expand to an if statement + move */ OPC_BALLOT_MACRO = _OPC(1, 50), diff --git a/src/freedreno/ir3/ir3_lexer.l b/src/freedreno/ir3/ir3_lexer.l index 6c1916aafb2..c4a064d03f0 100644 --- a/src/freedreno/ir3/ir3_lexer.l +++ b/src/freedreno/ir3/ir3_lexer.l @@ -223,6 +223,7 @@ static int parse_reg(const char *str) "swz" return TOKEN(T_OP_SWZ); "gat" return TOKEN(T_OP_GAT); "sct" return TOKEN(T_OP_SCT); +"movs" return TOKEN(T_OP_MOVS); ("f16"|"f32"|"u16"|"u32"|"s16"|"s32"|"u8"|"u8_32"|"u64"){2} ir3_yylval.str = yytext; return T_CAT1_TYPE_TYPE; /* category 2: */ diff --git a/src/freedreno/ir3/ir3_parser.y b/src/freedreno/ir3/ir3_parser.y index e215ec2dd6f..95f2b0baf94 100644 --- a/src/freedreno/ir3/ir3_parser.y +++ b/src/freedreno/ir3/ir3_parser.y @@ -502,6 +502,7 @@ static void print_token(FILE *file, int type, YYSTYPE value) %token T_OP_SWZ %token T_OP_GAT %token T_OP_SCT +%token T_OP_MOVS /* category 2: */ %token T_OP_ADD_F @@ -1040,6 +1041,11 @@ cat1_gat: T_OP_GAT '.' T_CAT1_TYPE_TYPE { parse_type_type(new_instr(OPC cat1_sct: T_OP_SCT '.' T_CAT1_TYPE_TYPE { parse_type_type(new_instr(OPC_SCT), $3); } dst_reg ',' dst_reg ',' dst_reg ',' dst_reg ',' src_reg +movs_invocation: uinteger { new_src(0, IR3_REG_IMMED)->uim_val = $1; } +| src_a0 + +cat1_movs: T_OP_MOVS '.' T_CAT1_TYPE_TYPE { parse_type_type(new_instr(OPC_MOVS), $3); } dst_reg ',' src_reg ',' movs_invocation + /* NOTE: cat1 can also *write* to relative gpr */ cat1_instr: cat1_movmsk | cat1_mova1 @@ -1049,6 +1055,7 @@ cat1_instr: cat1_movmsk | cat1_sct | cat1_opc dst_reg ',' cat1_src | cat1_opc relative_gpr_dst ',' cat1_src +| cat1_movs cat2_opc_1src: T_OP_ABSNEG_F { new_instr(OPC_ABSNEG_F); } | T_OP_ABSNEG_S { new_instr(OPC_ABSNEG_S); } diff --git a/src/freedreno/ir3/tests/disasm.c b/src/freedreno/ir3/tests/disasm.c index 1c18dfecea2..a37bd187b34 100644 --- a/src/freedreno/ir3/tests/disasm.c +++ b/src/freedreno/ir3/tests/disasm.c @@ -93,6 +93,9 @@ static const struct test { INSTR_7XX(2004c005_00000405, "cov.f32u32 r1.y, (last)r1.y"), + INSTR_7XX(200440c0_ae800004, "movs.f32f32 r48.x, r1.x, 93"), + INSTR_7XX(201100c0_c000040b, "movs.s16s16 hr48.x, (last)hr2.w, a0.x"), + /* cat2 */ INSTR_6XX(40104002_0c210001, "add.f hr0.z, r0.y, c"), INSTR_6XX(40b80804_10408004, "(nop3) cmps.f.lt r1.x, (abs)r1.x, c16.x"), diff --git a/src/freedreno/isa/encode.c b/src/freedreno/isa/encode.c index bf227e2c36c..1b1876b6e2f 100644 --- a/src/freedreno/isa/encode.c +++ b/src/freedreno/isa/encode.c @@ -79,6 +79,12 @@ __instruction_case(struct encode_state *s, const struct ir3_instruction *instr) } else { return OPC_MOV_GPR; } + } else if (instr->opc == OPC_MOVS) { + if (instr->srcs[1]->flags & IR3_REG_IMMED) { + return OPC_MOVS_IMMED; + } else { + return OPC_MOVS_A0; + } } else if (instr->opc == OPC_DEMOTE) { return OPC_KILL; } else if (s->compiler->gen >= 6) { diff --git a/src/freedreno/isa/ir3-cat1.xml b/src/freedreno/isa/ir3-cat1.xml index 15bd97f9514..a120515aed8 100644 --- a/src/freedreno/isa/ir3-cat1.xml +++ b/src/freedreno/isa/ir3-cat1.xml @@ -277,7 +277,7 @@ SOFTWARE. 01 - + @@ -285,7 +285,6 @@ SOFTWARE. 00 - 000000000000000000000 00 @@ -293,6 +292,50 @@ SOFTWARE. + + 000000000000000000000 + + + + + movs works like subgroupBroadcast/OpGroupNonUniformBroadcast. + The fiber id can either be an immediate or a value in a0.x. In + the latter case, the value has to be dynamically uniform or else + the behavior is undefined. The dst register has to be shared or + else the behavior seems to be equivalent to a normal mov (i.e., + the fiber id is not taken into account anymore). + + movs can do a cov on the broadcasted value. It works exactly + like a normal cov except that using u8 as the src type does not + seem to work at all. + + + 000000000000 + 1 + + + + + {SY}{SS}{JP}{REPEAT}{UL}movs.{SRC_TYPE}{DST_TYPE} {ROUND}{DST_HALF}{DST}, {SRC}, {INVOCATION} + + + + 0 + + + extract_reg_uim(src->srcs[1]) + + + + + + {SY}{SS}{JP}{REPEAT}{UL}movs.{SRC_TYPE}{DST_TYPE} {ROUND}{DST_HALF}{DST}, {SRC}, a0.x + + + 0000000 + 1 + + 1 00000000000000000000