diff options
author | Rob Clark <[email protected]> | 2015-02-10 04:42:32 -0500 |
---|---|---|
committer | Rob Clark <[email protected]> | 2015-03-08 17:42:43 -0400 |
commit | 27648efa2070e8db111908314d8b924d3717dbb0 (patch) | |
tree | c6c96b1aca2809b23d49bb2c521548041dae4967 /src/gallium | |
parent | 72d4f6c67f8a96956a1a8eeb90449231ba8e0940 (diff) |
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 <[email protected]>
Diffstat (limited to 'src/gallium')
-rw-r--r-- | src/gallium/drivers/freedreno/ir3/ir3_group.c | 71 |
1 files changed, 44 insertions, 27 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,40 +50,72 @@ static bool check_stop(struct ir3_instruction *instr) return false; } +static struct ir3_instruction * create_mov(struct ir3_instruction *instr) +{ + struct ir3_instruction *mov; + + mov = ir3_instr_create(instr->block, 1, 0); + mov->cat1.src_type = TYPE_F32; + mov->cat1.dst_type = TYPE_F32; + ir3_reg_create(mov, 0, 0); /* dst */ + ir3_reg_create(mov, 0, IR3_REG_SSA)->instr = 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 (*set)(void *arr, int idx, struct ir3_instruction *instr); + 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_set_out(void *arr, int idx, struct ir3_instruction *instr) +static void arr_insert_mov_out(void *arr, int idx, struct ir3_instruction *instr) { - ((struct ir3_instruction **)arr)[idx] = instr; + ((struct ir3_instruction **)arr)[idx] = create_mov(instr); } -static void arr_set_in(void *arr, int idx, struct ir3_instruction *instr) +static void arr_insert_mov_in(void *arr, int idx, struct ir3_instruction *instr) { - debug_printf("cannot insert mov before input!\n"); - debug_assert(0); + /* 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_set_out }; -static struct group_ops arr_ops_in = { arr_get, arr_set_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_set(void *arr, int idx, struct ir3_instruction *instr) +static void instr_insert_mov(void *arr, int idx, struct ir3_instruction *instr) { - ((struct ir3_instruction *)arr)->regs[idx+1]->instr = instr; + ((struct ir3_instruction *)arr)->regs[idx+1]->instr = create_mov(instr); } -static struct group_ops instr_ops = { instr_get, instr_set }; +static struct group_ops instr_ops = { instr_get, instr_insert_mov }; @@ -92,20 +124,6 @@ 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) -{ - struct ir3_instruction *mov; - - mov = ir3_instr_create(instr->block, 1, 0); - mov->cat1.src_type = TYPE_F32; - mov->cat1.dst_type = TYPE_F32; - ir3_reg_create(mov, 0, 0); /* dst */ - ir3_reg_create(mov, 0, IR3_REG_SSA)->instr = instr; - - return mov; -} - 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: */ |