From 27648efa2070e8db111908314d8b924d3717dbb0 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 10 Feb 2015 04:42:32 -0500 Subject: [PATCH] freedreno/ir3: fix failed assert in grouping Turns out there are scenarios where we need to insert mov's in "front" of an input. Triggered by shaders like: VERT DCL IN[0] DCL IN[1] DCL OUT[0], POSITION DCL OUT[1], GENERIC[9] DCL SAMP[0] DCL TEMP[0], LOCAL 0: MOV TEMP[0].xy, IN[1].xyyy 1: MOV TEMP[0].w, IN[1].wwww 2: TXF TEMP[0], TEMP[0], SAMP[0], 1D_ARRAY 3: MOV OUT[1], TEMP[0] 4: MOV OUT[0], IN[0] 5: END Signed-off-by: Rob Clark --- src/gallium/drivers/freedreno/ir3/ir3_group.c | 109 ++++++++++-------- 1 file changed, 63 insertions(+), 46 deletions(-) diff --git a/src/gallium/drivers/freedreno/ir3/ir3_group.c b/src/gallium/drivers/freedreno/ir3/ir3_group.c index da2142e69a8..a571e2e8eea 100644 --- a/src/gallium/drivers/freedreno/ir3/ir3_group.c +++ b/src/gallium/drivers/freedreno/ir3/ir3_group.c @@ -50,50 +50,7 @@ static bool check_stop(struct ir3_instruction *instr) return false; } -/* bleh.. we need to do the same group_n() thing for both inputs/outputs - * (where we have a simple instr[] array), and fanin nodes (where we have - * an extra indirection via reg->instr). - */ -struct group_ops { - struct ir3_instruction *(*get)(void *arr, int idx); - void (*set)(void *arr, int idx, struct ir3_instruction *instr); -}; - -static struct ir3_instruction *arr_get(void *arr, int idx) -{ - return ((struct ir3_instruction **)arr)[idx]; -} -static void arr_set_out(void *arr, int idx, struct ir3_instruction *instr) -{ - ((struct ir3_instruction **)arr)[idx] = instr; -} -static void arr_set_in(void *arr, int idx, struct ir3_instruction *instr) -{ - debug_printf("cannot insert mov before input!\n"); - debug_assert(0); -} -static struct group_ops arr_ops_out = { arr_get, arr_set_out }; -static struct group_ops arr_ops_in = { arr_get, arr_set_in }; - -static struct ir3_instruction *instr_get(void *arr, int idx) -{ - return ssa(((struct ir3_instruction *)arr)->regs[idx+1]); -} -static void instr_set(void *arr, int idx, struct ir3_instruction *instr) -{ - ((struct ir3_instruction *)arr)->regs[idx+1]->instr = instr; -} -static struct group_ops instr_ops = { instr_get, instr_set }; - - - -static bool conflicts(struct ir3_instruction *a, struct ir3_instruction *b) -{ - return (a && b) && (a != b); -} - -static struct ir3_instruction * -create_mov(struct ir3_instruction *instr) +static struct ir3_instruction * create_mov(struct ir3_instruction *instr) { struct ir3_instruction *mov; @@ -106,6 +63,67 @@ create_mov(struct ir3_instruction *instr) return mov; } +/* bleh.. we need to do the same group_n() thing for both inputs/outputs + * (where we have a simple instr[] array), and fanin nodes (where we have + * an extra indirection via reg->instr). + */ +struct group_ops { + struct ir3_instruction *(*get)(void *arr, int idx); + void (*insert_mov)(void *arr, int idx, struct ir3_instruction *instr); +}; + +static struct ir3_instruction *arr_get(void *arr, int idx) +{ + return ((struct ir3_instruction **)arr)[idx]; +} +static void arr_insert_mov_out(void *arr, int idx, struct ir3_instruction *instr) +{ + ((struct ir3_instruction **)arr)[idx] = create_mov(instr); +} +static void arr_insert_mov_in(void *arr, int idx, struct ir3_instruction *instr) +{ + /* so, we can't insert a mov in front of a meta:in.. and the downstream + * instruction already has a pointer to 'instr'. So we cheat a bit and + * morph the meta:in instruction into a mov and insert a new meta:in + * in front. + */ + struct ir3_instruction *in; + + debug_assert(instr->regs_count == 1); + + in = ir3_instr_create(instr->block, -1, OPC_META_INPUT); + in->inout.block = instr->block; + ir3_reg_create(in, instr->regs[0]->num, 0); + + /* create src reg for meta:in and fixup to now be a mov: */ + ir3_reg_create(instr, 0, IR3_REG_SSA)->instr = in; + instr->category = 1; + instr->opc = 0; + instr->cat1.src_type = TYPE_F32; + instr->cat1.dst_type = TYPE_F32; + + ((struct ir3_instruction **)arr)[idx] = in; +} +static struct group_ops arr_ops_out = { arr_get, arr_insert_mov_out }; +static struct group_ops arr_ops_in = { arr_get, arr_insert_mov_in }; + +static struct ir3_instruction *instr_get(void *arr, int idx) +{ + return ssa(((struct ir3_instruction *)arr)->regs[idx+1]); +} +static void instr_insert_mov(void *arr, int idx, struct ir3_instruction *instr) +{ + ((struct ir3_instruction *)arr)->regs[idx+1]->instr = create_mov(instr); +} +static struct group_ops instr_ops = { instr_get, instr_insert_mov }; + + + +static bool conflicts(struct ir3_instruction *a, struct ir3_instruction *b) +{ + return (a && b) && (a != b); +} + static void group_n(struct group_ops *ops, void *arr, unsigned n) { unsigned i, j; @@ -135,8 +153,7 @@ restart: conflict = true; if (conflict) { - instr = create_mov(instr); - ops->set(arr, i, instr); + ops->insert_mov(arr, i, instr); /* inserting the mov may have caused a conflict * against the previous: */