diff options
Diffstat (limited to 'src/mesa/program/ir_to_mesa.cpp')
-rw-r--r-- | src/mesa/program/ir_to_mesa.cpp | 159 |
1 files changed, 152 insertions, 7 deletions
diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp index a5b17bb..786fdfb 100644 --- a/src/mesa/program/ir_to_mesa.cpp +++ b/src/mesa/program/ir_to_mesa.cpp @@ -295,6 +295,8 @@ public: bool process_move_condition(ir_rvalue *ir); + void copy_propagate(void); + void *mem_ctx; }; @@ -1574,7 +1576,13 @@ ir_to_mesa_visitor::visit(ir_dereference_record *ir) break; offset += type_size(struct_type->fields.structure[i].type); } - this->result.swizzle = swizzle_for_size(ir->type->vector_elements); + + /* If the type is smaller than a vec4, replicate the last channel out. */ + if (ir->type->is_scalar() || ir->type->is_vector()) + this->result.swizzle = swizzle_for_size(ir->type->vector_elements); + else + this->result.swizzle = SWIZZLE_NOOP; + this->result.index += offset; } @@ -2171,9 +2179,14 @@ ir_to_mesa_visitor::visit(ir_discard *ir) { struct gl_fragment_program *fp = (struct gl_fragment_program *)this->prog; - assert(ir->condition == NULL); /* FINISHME */ + if (ir->condition) { + ir->condition->accept(this); + this->result.negate = ~this->result.negate; + ir_to_mesa_emit_op1(ir, OPCODE_KIL, ir_to_mesa_undef_dst, this->result); + } else { + ir_to_mesa_emit_op0(ir, OPCODE_KIL_NV); + } - ir_to_mesa_emit_op0(ir, OPCODE_KIL_NV); fp->UsesKill = GL_TRUE; } @@ -2610,6 +2623,133 @@ set_uniform_initializers(struct gl_context *ctx, talloc_free(mem_ctx); } +/* + * On a basic block basis, tracks available PROGRAM_TEMPORARY register + * channels for copy propagation and updates following instructions to + * use the original versions. + * + * The ir_to_mesa_visitor lazily produces code assuming that this pass + * will occur. As an example, a TXP production before this pass: + * + * 0: MOV TEMP[1], INPUT[4].xyyy; + * 1: MOV TEMP[1].w, INPUT[4].wwww; + * 2: TXP TEMP[2], TEMP[1], texture[0], 2D; + * + * and after: + * + * 0: MOV TEMP[1], INPUT[4].xyyy; + * 1: MOV TEMP[1].w, INPUT[4].wwww; + * 2: TXP TEMP[2], INPUT[4].xyyw, texture[0], 2D; + * + * which allows for dead code elimination on TEMP[1]'s writes. + */ +void +ir_to_mesa_visitor::copy_propagate(void) +{ + ir_to_mesa_instruction **acp = talloc_zero_array(mem_ctx, + ir_to_mesa_instruction *, + this->next_temp * 4); + + foreach_iter(exec_list_iterator, iter, this->instructions) { + ir_to_mesa_instruction *inst = (ir_to_mesa_instruction *)iter.get(); + + /* First, do any copy propagation possible into the src regs. */ + for (int r = 0; r < 3; r++) { + ir_to_mesa_instruction *first = NULL; + bool good = true; + int acp_base = inst->src_reg[r].index * 4; + + if (inst->src_reg[r].file != PROGRAM_TEMPORARY || + inst->src_reg[r].reladdr) + continue; + + /* See if we can find entries in the ACP consisting of MOVs + * from the same src register for all the swizzled channels + * of this src register reference. + */ + for (int i = 0; i < 4; i++) { + int src_chan = GET_SWZ(inst->src_reg[r].swizzle, i); + ir_to_mesa_instruction *copy_chan = acp[acp_base + src_chan]; + + if (!copy_chan) { + good = false; + break; + } + + if (!first) { + first = copy_chan; + } else { + if (first->src_reg[0].file != copy_chan->src_reg[0].file || + first->src_reg[0].index != copy_chan->src_reg[0].index) { + good = false; + break; + } + } + } + + if (good) { + /* We've now validated that we can copy-propagate to + * replace this src register reference. Do it. + */ + inst->src_reg[r].file = first->src_reg[0].file; + inst->src_reg[r].index = first->src_reg[0].index; + + int swizzle = 0; + for (int i = 0; i < 4; i++) { + int src_chan = GET_SWZ(inst->src_reg[r].swizzle, i); + ir_to_mesa_instruction *copy_inst = acp[acp_base + src_chan]; + swizzle |= (GET_SWZ(copy_inst->src_reg[0].swizzle, src_chan) << + (3 * i)); + } + inst->src_reg[r].swizzle = swizzle; + } + } + + switch (inst->op) { + case OPCODE_BGNLOOP: + case OPCODE_ENDLOOP: + case OPCODE_ELSE: + case OPCODE_ENDIF: + /* End of a basic block, clear the ACP entirely. */ + memset(acp, 0, sizeof(*acp) * this->next_temp * 4); + break; + + default: + /* Continuing the block, clear any written channels from + * the ACP. + */ + if (inst->dst_reg.file == PROGRAM_TEMPORARY) { + if (inst->dst_reg.reladdr) { + memset(acp, 0, sizeof(*acp) * this->next_temp * 4); + } else { + for (int i = 0; i < 4; i++) { + if (inst->dst_reg.writemask & (1 << i)) { + acp[4 * inst->dst_reg.index + i] = NULL; + } + } + } + } + break; + } + + /* If this is a copy, add it to the ACP. */ + if (inst->op == OPCODE_MOV && + inst->dst_reg.file == PROGRAM_TEMPORARY && + !inst->dst_reg.reladdr && + !inst->saturate && + !inst->src_reg[0].reladdr && + !inst->src_reg[0].negate) { + for (int i = 0; i < 4; i++) { + if (inst->dst_reg.writemask & (1 << i)) { + acp[4 * inst->dst_reg.index + i] = inst; + } + } + } + } + + talloc_free(acp); +} + /** * Convert a shader's GLSL IR into a Mesa gl_program. @@ -2709,6 +2849,8 @@ get_mesa_program(struct gl_context *ctx, mesa_instruction_annotation = talloc_array(v.mem_ctx, ir_instruction *, num_instructions); + v.copy_propagate(); + /* Convert ir_mesa_instructions into prog_instructions. */ mesa_inst = mesa_instructions; @@ -2849,8 +2991,9 @@ _mesa_ir_link_shader(struct gl_context *ctx, struct gl_shader_program *prog) /* Lowering */ do_mat_op_to_vec(ir); - lower_instructions(ir, MOD_TO_FRACT | DIV_TO_MUL_RCP | EXP_TO_EXP2 - | LOG_TO_LOG2); + lower_instructions(ir, (MOD_TO_FRACT | DIV_TO_MUL_RCP | EXP_TO_EXP2 + | LOG_TO_LOG2 + | ((options->EmitNoPow) ? POW_TO_EXP2 : 0))); progress = do_lower_jumps(ir, true, true, options->EmitNoMainReturn, options->EmitNoCont, options->EmitNoLoops) || progress; @@ -2858,8 +3001,10 @@ _mesa_ir_link_shader(struct gl_context *ctx, struct gl_shader_program *prog) progress = lower_quadop_vector(ir, true) || progress; - if (options->EmitNoIfs) - progress = do_if_to_cond_assign(ir) || progress; + if (options->EmitNoIfs) { + progress = lower_discard(ir) || progress; + progress = lower_if_to_cond_assign(ir) || progress; + } if (options->EmitNoNoise) progress = lower_noise(ir) || progress; |