*/
#include "brw_vec4.h"
+#include "brw_cfg.h"
#include "glsl/ir_uniform.h"
-extern "C" {
#include "program/sampler.h"
-}
namespace brw {
-vec4_instruction::vec4_instruction(vec4_visitor *v,
- enum opcode opcode, dst_reg dst,
- src_reg src0, src_reg src1, src_reg src2)
+vec4_instruction::vec4_instruction(enum opcode opcode, const dst_reg &dst,
+ const src_reg &src0, const src_reg &src1,
+ const src_reg &src2)
{
this->opcode = opcode;
this->dst = dst;
this->no_dd_check = false;
this->writes_accumulator = false;
this->conditional_mod = BRW_CONDITIONAL_NONE;
- this->sampler = 0;
- this->texture_offset = 0;
+ this->predicate = BRW_PREDICATE_NONE;
+ this->predicate_inverse = false;
this->target = 0;
+ this->regs_written = (dst.file == BAD_FILE ? 0 : 1);
this->shadow_compare = false;
- this->ir = v->base_ir;
+ this->ir = NULL;
this->urb_write_flags = BRW_URB_WRITE_NO_FLAGS;
this->header_present = false;
+ this->flag_subreg = 0;
this->mlen = 0;
this->base_mrf = 0;
this->offset = 0;
- this->annotation = v->current_annotation;
+ this->annotation = NULL;
}
vec4_instruction *
vec4_visitor::emit(vec4_instruction *inst)
{
+ inst->ir = this->base_ir;
+ inst->annotation = this->current_annotation;
+
this->instructions.push_tail(inst);
return inst;
}
vec4_instruction *
-vec4_visitor::emit_before(vec4_instruction *inst, vec4_instruction *new_inst)
+vec4_visitor::emit_before(bblock_t *block, vec4_instruction *inst,
+ vec4_instruction *new_inst)
{
new_inst->ir = inst->ir;
new_inst->annotation = inst->annotation;
- inst->insert_before(new_inst);
+ inst->insert_before(block, new_inst);
return inst;
}
vec4_instruction *
-vec4_visitor::emit(enum opcode opcode, dst_reg dst,
- src_reg src0, src_reg src1, src_reg src2)
+vec4_visitor::emit(enum opcode opcode, const dst_reg &dst, const src_reg &src0,
+ const src_reg &src1, const src_reg &src2)
{
- return emit(new(mem_ctx) vec4_instruction(this, opcode, dst,
- src0, src1, src2));
+ return emit(new(mem_ctx) vec4_instruction(opcode, dst, src0, src1, src2));
}
vec4_instruction *
-vec4_visitor::emit(enum opcode opcode, dst_reg dst, src_reg src0, src_reg src1)
+vec4_visitor::emit(enum opcode opcode, const dst_reg &dst, const src_reg &src0,
+ const src_reg &src1)
{
- return emit(new(mem_ctx) vec4_instruction(this, opcode, dst, src0, src1));
+ return emit(new(mem_ctx) vec4_instruction(opcode, dst, src0, src1));
}
vec4_instruction *
-vec4_visitor::emit(enum opcode opcode, dst_reg dst, src_reg src0)
+vec4_visitor::emit(enum opcode opcode, const dst_reg &dst, const src_reg &src0)
{
- return emit(new(mem_ctx) vec4_instruction(this, opcode, dst, src0));
+ return emit(new(mem_ctx) vec4_instruction(opcode, dst, src0));
}
vec4_instruction *
-vec4_visitor::emit(enum opcode opcode, dst_reg dst)
+vec4_visitor::emit(enum opcode opcode, const dst_reg &dst)
{
- return emit(new(mem_ctx) vec4_instruction(this, opcode, dst));
+ return emit(new(mem_ctx) vec4_instruction(opcode, dst));
}
vec4_instruction *
vec4_visitor::emit(enum opcode opcode)
{
- return emit(new(mem_ctx) vec4_instruction(this, opcode, dst_reg()));
+ return emit(new(mem_ctx) vec4_instruction(opcode, dst_reg()));
}
#define ALU1(op) \
vec4_instruction * \
- vec4_visitor::op(dst_reg dst, src_reg src0) \
+ vec4_visitor::op(const dst_reg &dst, const src_reg &src0) \
{ \
- return new(mem_ctx) vec4_instruction(this, BRW_OPCODE_##op, dst, \
- src0); \
+ return new(mem_ctx) vec4_instruction(BRW_OPCODE_##op, dst, src0); \
}
#define ALU2(op) \
vec4_instruction * \
- vec4_visitor::op(dst_reg dst, src_reg src0, src_reg src1) \
+ vec4_visitor::op(const dst_reg &dst, const src_reg &src0, \
+ const src_reg &src1) \
{ \
- return new(mem_ctx) vec4_instruction(this, BRW_OPCODE_##op, dst, \
- src0, src1); \
+ return new(mem_ctx) vec4_instruction(BRW_OPCODE_##op, dst, \
+ src0, src1); \
}
#define ALU2_ACC(op) \
vec4_instruction * \
- vec4_visitor::op(dst_reg dst, src_reg src0, src_reg src1) \
+ vec4_visitor::op(const dst_reg &dst, const src_reg &src0, \
+ const src_reg &src1) \
{ \
- vec4_instruction *inst = new(mem_ctx) vec4_instruction(this, \
+ vec4_instruction *inst = new(mem_ctx) vec4_instruction( \
BRW_OPCODE_##op, dst, src0, src1); \
- inst->writes_accumulator = true; \
- return inst; \
+ inst->writes_accumulator = true; \
+ return inst; \
}
#define ALU3(op) \
vec4_instruction * \
- vec4_visitor::op(dst_reg dst, src_reg src0, src_reg src1, src_reg src2)\
+ vec4_visitor::op(const dst_reg &dst, const src_reg &src0, \
+ const src_reg &src1, const src_reg &src2) \
{ \
assert(brw->gen >= 6); \
- return new(mem_ctx) vec4_instruction(this, BRW_OPCODE_##op, dst, \
+ return new(mem_ctx) vec4_instruction(BRW_OPCODE_##op, dst, \
src0, src1, src2); \
}
/** Gen4 predicated IF. */
vec4_instruction *
-vec4_visitor::IF(uint32_t predicate)
+vec4_visitor::IF(enum brw_predicate predicate)
{
vec4_instruction *inst;
- inst = new(mem_ctx) vec4_instruction(this, BRW_OPCODE_IF);
+ inst = new(mem_ctx) vec4_instruction(BRW_OPCODE_IF);
inst->predicate = predicate;
return inst;
/** Gen6 IF with embedded comparison. */
vec4_instruction *
-vec4_visitor::IF(src_reg src0, src_reg src1, uint32_t condition)
+vec4_visitor::IF(src_reg src0, src_reg src1,
+ enum brw_conditional_mod condition)
{
assert(brw->gen == 6);
resolve_ud_negate(&src0);
resolve_ud_negate(&src1);
- inst = new(mem_ctx) vec4_instruction(this, BRW_OPCODE_IF, dst_null_d(),
+ inst = new(mem_ctx) vec4_instruction(BRW_OPCODE_IF, dst_null_d(),
src0, src1);
inst->conditional_mod = condition;
* the flag register with the packed 16 bits of the result.
*/
vec4_instruction *
-vec4_visitor::CMP(dst_reg dst, src_reg src0, src_reg src1, uint32_t condition)
+vec4_visitor::CMP(dst_reg dst, src_reg src0, src_reg src1,
+ enum brw_conditional_mod condition)
{
vec4_instruction *inst;
- /* original gen4 does type conversion to the destination type
- * before before comparison, producing garbage results for floating
- * point comparisons.
+ /* Take the instruction:
+ *
+ * CMP null<d> src0<f> src1<f>
+ *
+ * Original gen4 does type conversion to the destination type before
+ * comparison, producing garbage results for floating point comparisons.
+ *
+ * The destination type doesn't matter on newer generations, so we set the
+ * type to match src0 so we can compact the instruction.
*/
- if (brw->gen == 4) {
- dst.type = src0.type;
- if (dst.file == HW_REG)
- dst.fixed_hw_reg.type = dst.type;
- }
+ dst.type = src0.type;
+ if (dst.file == HW_REG)
+ dst.fixed_hw_reg.type = dst.type;
resolve_ud_negate(&src0);
resolve_ud_negate(&src1);
- inst = new(mem_ctx) vec4_instruction(this, BRW_OPCODE_CMP, dst, src0, src1);
+ inst = new(mem_ctx) vec4_instruction(BRW_OPCODE_CMP, dst, src0, src1);
inst->conditional_mod = condition;
return inst;
}
vec4_instruction *
-vec4_visitor::SCRATCH_READ(dst_reg dst, src_reg index)
+vec4_visitor::SCRATCH_READ(const dst_reg &dst, const src_reg &index)
{
vec4_instruction *inst;
- inst = new(mem_ctx) vec4_instruction(this, SHADER_OPCODE_GEN4_SCRATCH_READ,
+ inst = new(mem_ctx) vec4_instruction(SHADER_OPCODE_GEN4_SCRATCH_READ,
dst, index);
inst->base_mrf = 14;
inst->mlen = 2;
}
vec4_instruction *
-vec4_visitor::SCRATCH_WRITE(dst_reg dst, src_reg src, src_reg index)
+vec4_visitor::SCRATCH_WRITE(const dst_reg &dst, const src_reg &src,
+ const src_reg &index)
{
vec4_instruction *inst;
- inst = new(mem_ctx) vec4_instruction(this, SHADER_OPCODE_GEN4_SCRATCH_WRITE,
+ inst = new(mem_ctx) vec4_instruction(SHADER_OPCODE_GEN4_SCRATCH_WRITE,
dst, src, index);
inst->base_mrf = 13;
inst->mlen = 3;
dst_reg expanded = dst_reg(this, glsl_type::vec4_type);
expanded.type = src.type;
- emit(MOV(expanded, src));
+ emit(VEC4_OPCODE_UNPACK_UNIFORM, expanded, src);
return src_reg(expanded);
}
src_reg
vec4_visitor::fix_math_operand(src_reg src)
{
+ if (brw->gen < 6 || brw->gen >= 8 || src.file == BAD_FILE)
+ return src;
+
/* The gen6 math instruction ignores the source modifiers --
* swizzle, abs, negate, and at least some parts of the register
* region description.
return src_reg(expanded);
}
-void
-vec4_visitor::emit_math1_gen6(enum opcode opcode, dst_reg dst, src_reg src)
-{
- src = fix_math_operand(src);
-
- if (brw->gen == 6 && dst.writemask != WRITEMASK_XYZW) {
- /* The gen6 math instruction must be align1, so we can't do
- * writemasks.
- */
- dst_reg temp_dst = dst_reg(this, glsl_type::vec4_type);
-
- emit(opcode, temp_dst, src);
-
- emit(MOV(dst, src_reg(temp_dst)));
- } else {
- emit(opcode, dst, src);
- }
-}
-
-void
-vec4_visitor::emit_math1_gen4(enum opcode opcode, dst_reg dst, src_reg src)
-{
- vec4_instruction *inst = emit(opcode, dst, src);
- inst->base_mrf = 1;
- inst->mlen = 1;
-}
-
-void
-vec4_visitor::emit_math(opcode opcode, dst_reg dst, src_reg src)
-{
- switch (opcode) {
- case SHADER_OPCODE_RCP:
- case SHADER_OPCODE_RSQ:
- case SHADER_OPCODE_SQRT:
- case SHADER_OPCODE_EXP2:
- case SHADER_OPCODE_LOG2:
- case SHADER_OPCODE_SIN:
- case SHADER_OPCODE_COS:
- break;
- default:
- assert(!"not reached: bad math opcode");
- return;
- }
-
- if (brw->gen >= 6) {
- return emit_math1_gen6(opcode, dst, src);
- } else {
- return emit_math1_gen4(opcode, dst, src);
- }
-}
-
-void
-vec4_visitor::emit_math2_gen6(enum opcode opcode,
- dst_reg dst, src_reg src0, src_reg src1)
-{
- src0 = fix_math_operand(src0);
- src1 = fix_math_operand(src1);
-
- if (brw->gen == 6 && dst.writemask != WRITEMASK_XYZW) {
- /* The gen6 math instruction must be align1, so we can't do
- * writemasks.
- */
- dst_reg temp_dst = dst_reg(this, glsl_type::vec4_type);
- temp_dst.type = dst.type;
-
- emit(opcode, temp_dst, src0, src1);
-
- emit(MOV(dst, src_reg(temp_dst)));
- } else {
- emit(opcode, dst, src0, src1);
- }
-}
-
-void
-vec4_visitor::emit_math2_gen4(enum opcode opcode,
- dst_reg dst, src_reg src0, src_reg src1)
-{
- vec4_instruction *inst = emit(opcode, dst, src0, src1);
- inst->base_mrf = 1;
- inst->mlen = 2;
-}
-
void
vec4_visitor::emit_math(enum opcode opcode,
- dst_reg dst, src_reg src0, src_reg src1)
+ const dst_reg &dst,
+ const src_reg &src0, const src_reg &src1)
{
- switch (opcode) {
- case SHADER_OPCODE_POW:
- case SHADER_OPCODE_INT_QUOTIENT:
- case SHADER_OPCODE_INT_REMAINDER:
- break;
- default:
- assert(!"not reached: unsupported binary math opcode");
- return;
- }
+ vec4_instruction *math =
+ emit(opcode, dst, fix_math_operand(src0), fix_math_operand(src1));
- if (brw->gen >= 6) {
- return emit_math2_gen6(opcode, dst, src0, src1);
- } else {
- return emit_math2_gen4(opcode, dst, src0, src1);
+ if (brw->gen == 6 && dst.writemask != WRITEMASK_XYZW) {
+ /* MATH on Gen6 must be align1, so we can't do writemasks. */
+ math->dst = dst_reg(this, glsl_type::vec4_type);
+ math->dst.type = dst.type;
+ emit(MOV(dst, src_reg(math->dst)));
+ } else if (brw->gen < 6) {
+ math->base_mrf = 1;
+ math->mlen = src1.file == BAD_FILE ? 1 : 2;
}
}
void
vec4_visitor::emit_pack_half_2x16(dst_reg dst, src_reg src0)
{
- if (brw->gen < 7)
- assert(!"ir_unop_pack_half_2x16 should be lowered");
+ if (brw->gen < 7) {
+ unreachable("ir_unop_pack_half_2x16 should be lowered");
+ }
assert(dst.type == BRW_REGISTER_TYPE_UD);
assert(src0.type == BRW_REGISTER_TYPE_F);
void
vec4_visitor::emit_unpack_half_2x16(dst_reg dst, src_reg src0)
{
- if (brw->gen < 7)
- assert(!"ir_unop_unpack_half_2x16 should be lowered");
+ if (brw->gen < 7) {
+ unreachable("ir_unop_unpack_half_2x16 should be lowered");
+ }
assert(dst.type == BRW_REGISTER_TYPE_F);
assert(src0.type == BRW_REGISTER_TYPE_UD);
}
void
-vec4_visitor::visit_instructions(const exec_list *list)
+vec4_visitor::emit_unpack_unorm_4x8(const dst_reg &dst, src_reg src0)
{
- foreach_list(node, list) {
- ir_instruction *ir = (ir_instruction *)node;
+ /* Instead of splitting the 32-bit integer, shifting, and ORing it back
+ * together, we can shift it by <0, 8, 16, 24>. The packed integer immediate
+ * is not suitable to generate the shift values, but we can use the packed
+ * vector float and a type-converting MOV.
+ */
+ dst_reg shift(this, glsl_type::uvec4_type);
+ emit(MOV(shift, src_reg(0x00, 0x60, 0x70, 0x78)));
+
+ dst_reg shifted(this, glsl_type::uvec4_type);
+ src0.swizzle = BRW_SWIZZLE_XXXX;
+ emit(SHR(shifted, src0, src_reg(shift)));
+
+ shifted.type = BRW_REGISTER_TYPE_UB;
+ dst_reg f(this, glsl_type::vec4_type);
+ emit(VEC4_OPCODE_MOV_BYTES, f, src_reg(shifted));
+
+ emit(MUL(dst, src_reg(f), src_reg(1.0f / 255.0f)));
+}
+
+void
+vec4_visitor::emit_unpack_snorm_4x8(const dst_reg &dst, src_reg src0)
+{
+ /* Instead of splitting the 32-bit integer, shifting, and ORing it back
+ * together, we can shift it by <0, 8, 16, 24>. The packed integer immediate
+ * is not suitable to generate the shift values, but we can use the packed
+ * vector float and a type-converting MOV.
+ */
+ dst_reg shift(this, glsl_type::uvec4_type);
+ emit(MOV(shift, src_reg(0x00, 0x60, 0x70, 0x78)));
+
+ dst_reg shifted(this, glsl_type::uvec4_type);
+ src0.swizzle = BRW_SWIZZLE_XXXX;
+ emit(SHR(shifted, src0, src_reg(shift)));
+
+ shifted.type = BRW_REGISTER_TYPE_B;
+ dst_reg f(this, glsl_type::vec4_type);
+ emit(VEC4_OPCODE_MOV_BYTES, f, src_reg(shifted));
+
+ dst_reg scaled(this, glsl_type::vec4_type);
+ emit(MUL(scaled, src_reg(f), src_reg(1.0f / 127.0f)));
+
+ dst_reg max(this, glsl_type::vec4_type);
+ emit_minmax(BRW_CONDITIONAL_GE, max, src_reg(scaled), src_reg(-1.0f));
+ emit_minmax(BRW_CONDITIONAL_L, dst, src_reg(max), src_reg(1.0f));
+}
+
+void
+vec4_visitor::emit_pack_unorm_4x8(const dst_reg &dst, const src_reg &src0)
+{
+ dst_reg saturated(this, glsl_type::vec4_type);
+ vec4_instruction *inst = emit(MOV(saturated, src0));
+ inst->saturate = true;
+
+ dst_reg scaled(this, glsl_type::vec4_type);
+ emit(MUL(scaled, src_reg(saturated), src_reg(255.0f)));
+
+ dst_reg rounded(this, glsl_type::vec4_type);
+ emit(RNDE(rounded, src_reg(scaled)));
+ dst_reg u(this, glsl_type::uvec4_type);
+ emit(MOV(u, src_reg(rounded)));
+
+ src_reg bytes(u);
+ emit(VEC4_OPCODE_PACK_BYTES, dst, bytes);
+}
+
+void
+vec4_visitor::emit_pack_snorm_4x8(const dst_reg &dst, const src_reg &src0)
+{
+ dst_reg max(this, glsl_type::vec4_type);
+ emit_minmax(BRW_CONDITIONAL_GE, max, src0, src_reg(-1.0f));
+
+ dst_reg min(this, glsl_type::vec4_type);
+ emit_minmax(BRW_CONDITIONAL_L, min, src_reg(max), src_reg(1.0f));
+
+ dst_reg scaled(this, glsl_type::vec4_type);
+ emit(MUL(scaled, src_reg(min), src_reg(127.0f)));
+
+ dst_reg rounded(this, glsl_type::vec4_type);
+ emit(RNDE(rounded, src_reg(scaled)));
+
+ dst_reg i(this, glsl_type::ivec4_type);
+ emit(MOV(i, src_reg(rounded)));
+
+ src_reg bytes(i);
+ emit(VEC4_OPCODE_PACK_BYTES, dst, bytes);
+}
+
+void
+vec4_visitor::visit_instructions(const exec_list *list)
+{
+ foreach_in_list(ir_instruction, ir, list) {
base_ir = ir;
ir->accept(this);
}
}
return size;
case GLSL_TYPE_SAMPLER:
- /* Samplers take up one slot in UNIFORMS[], but they're baked in
- * at link time.
+ /* Samplers take up no register space, since they're baked in at
+ * link time.
*/
- return 1;
+ return 0;
case GLSL_TYPE_ATOMIC_UINT:
return 0;
case GLSL_TYPE_IMAGE:
case GLSL_TYPE_VOID:
+ case GLSL_TYPE_DOUBLE:
case GLSL_TYPE_ERROR:
case GLSL_TYPE_INTERFACE:
- assert(0);
- break;
+ unreachable("not reached");
}
return 0;
}
-int
-vec4_visitor::virtual_grf_alloc(int size)
-{
- if (virtual_grf_array_size <= virtual_grf_count) {
- if (virtual_grf_array_size == 0)
- virtual_grf_array_size = 16;
- else
- virtual_grf_array_size *= 2;
- virtual_grf_sizes = reralloc(mem_ctx, virtual_grf_sizes, int,
- virtual_grf_array_size);
- virtual_grf_reg_map = reralloc(mem_ctx, virtual_grf_reg_map, int,
- virtual_grf_array_size);
- }
- virtual_grf_reg_map[virtual_grf_count] = virtual_grf_reg_count;
- virtual_grf_reg_count += size;
- virtual_grf_sizes[virtual_grf_count] = size;
- return virtual_grf_count++;
-}
-
src_reg::src_reg(class vec4_visitor *v, const struct glsl_type *type)
{
init();
this->file = GRF;
- this->reg = v->virtual_grf_alloc(type_size(type));
+ this->reg = v->alloc.allocate(type_size(type));
if (type->is_array() || type->is_record()) {
this->swizzle = BRW_SWIZZLE_NOOP;
this->type = brw_type_for_base_type(type);
}
+src_reg::src_reg(class vec4_visitor *v, const struct glsl_type *type, int size)
+{
+ assert(size > 0);
+
+ init();
+
+ this->file = GRF;
+ this->reg = v->alloc.allocate(type_size(type) * size);
+
+ this->swizzle = BRW_SWIZZLE_NOOP;
+
+ this->type = brw_type_for_base_type(type);
+}
+
dst_reg::dst_reg(class vec4_visitor *v, const struct glsl_type *type)
{
init();
this->file = GRF;
- this->reg = v->virtual_grf_alloc(type_size(type));
+ this->reg = v->alloc.allocate(type_size(type));
if (type->is_array() || type->is_record()) {
this->writemask = WRITEMASK_XYZW;
int i;
for (i = 0; i < uniform_vector_size[uniforms]; i++) {
- stage_prog_data->param[uniforms * 4 + i] = &components->f;
+ stage_prog_data->param[uniforms * 4 + i] = components;
components++;
}
for (; i < 4; i++) {
- static float zero = 0;
+ static gl_constant_value zero = { 0.0 };
stage_prog_data->param[uniforms * 4 + i] = &zero;
}
this->userplane[i] = dst_reg(UNIFORM, this->uniforms);
this->userplane[i].type = BRW_REGISTER_TYPE_F;
for (int j = 0; j < 4; ++j) {
- stage_prog_data->param[this->uniforms * 4 + j] = &clip_planes[i][j];
+ stage_prog_data->param[this->uniforms * 4 + j] =
+ (gl_constant_value *) &clip_planes[i][j];
}
++this->uniforms;
}
void
vec4_visitor::setup_builtin_uniform_values(ir_variable *ir)
{
- const ir_state_slot *const slots = ir->state_slots;
- assert(ir->state_slots != NULL);
+ const ir_state_slot *const slots = ir->get_state_slots();
+ assert(slots != NULL);
- for (unsigned int i = 0; i < ir->num_state_slots; i++) {
+ for (unsigned int i = 0; i < ir->get_num_state_slots(); i++) {
/* This state reference has already been setup by ir_to_mesa,
* but we'll get the same index back here. We can reference
* ParameterValues directly, since unlike brw_fs.cpp, we never
*/
int index = _mesa_add_state_reference(this->prog->Parameters,
(gl_state_index *)slots[i].tokens);
- float *values = &this->prog->Parameters->ParameterValues[index][0].f;
+ gl_constant_value *values =
+ &this->prog->Parameters->ParameterValues[index][0];
assert(this->uniforms < uniform_array_size);
this->uniform_vector_size[this->uniforms] = 0;
}
void
-vec4_visitor::emit_bool_to_cond_code(ir_rvalue *ir, uint32_t *predicate)
+vec4_visitor::emit_bool_to_cond_code(ir_rvalue *ir,
+ enum brw_predicate *predicate)
{
ir_expression *expr = ir->as_expression();
*predicate = BRW_PREDICATE_NORMAL;
- if (expr) {
- src_reg op[2];
+ if (expr && expr->operation != ir_binop_ubo_load) {
+ src_reg op[3];
vec4_instruction *inst;
- assert(expr->get_num_operands() <= 2);
+ assert(expr->get_num_operands() <= 3);
for (unsigned int i = 0; i < expr->get_num_operands(); i++) {
expr->operands[i]->accept(this);
op[i] = this->result;
break;
case ir_binop_logic_xor:
- inst = emit(XOR(dst_null_d(), op[0], op[1]));
- inst->conditional_mod = BRW_CONDITIONAL_NZ;
+ if (brw->gen <= 5) {
+ src_reg temp = src_reg(this, ir->type);
+ emit(XOR(dst_reg(temp), op[0], op[1]));
+ inst = emit(AND(dst_null_d(), temp, src_reg(1)));
+ } else {
+ inst = emit(XOR(dst_null_d(), op[0], op[1]));
+ }
+ inst->conditional_mod = BRW_CONDITIONAL_NZ;
break;
case ir_binop_logic_or:
- inst = emit(OR(dst_null_d(), op[0], op[1]));
- inst->conditional_mod = BRW_CONDITIONAL_NZ;
+ if (brw->gen <= 5) {
+ src_reg temp = src_reg(this, ir->type);
+ emit(OR(dst_reg(temp), op[0], op[1]));
+ inst = emit(AND(dst_null_d(), temp, src_reg(1)));
+ } else {
+ inst = emit(OR(dst_null_d(), op[0], op[1]));
+ }
+ inst->conditional_mod = BRW_CONDITIONAL_NZ;
break;
case ir_binop_logic_and:
- inst = emit(AND(dst_null_d(), op[0], op[1]));
- inst->conditional_mod = BRW_CONDITIONAL_NZ;
+ if (brw->gen <= 5) {
+ src_reg temp = src_reg(this, ir->type);
+ emit(AND(dst_reg(temp), op[0], op[1]));
+ inst = emit(AND(dst_null_d(), temp, src_reg(1)));
+ } else {
+ inst = emit(AND(dst_null_d(), op[0], op[1]));
+ }
+ inst->conditional_mod = BRW_CONDITIONAL_NZ;
break;
case ir_unop_f2b:
break;
case ir_binop_all_equal:
+ if (brw->gen <= 5) {
+ resolve_bool_comparison(expr->operands[0], &op[0]);
+ resolve_bool_comparison(expr->operands[1], &op[1]);
+ }
inst = emit(CMP(dst_null_d(), op[0], op[1], BRW_CONDITIONAL_Z));
*predicate = BRW_PREDICATE_ALIGN16_ALL4H;
break;
case ir_binop_any_nequal:
+ if (brw->gen <= 5) {
+ resolve_bool_comparison(expr->operands[0], &op[0]);
+ resolve_bool_comparison(expr->operands[1], &op[1]);
+ }
inst = emit(CMP(dst_null_d(), op[0], op[1], BRW_CONDITIONAL_NZ));
*predicate = BRW_PREDICATE_ALIGN16_ANY4H;
break;
case ir_unop_any:
+ if (brw->gen <= 5) {
+ resolve_bool_comparison(expr->operands[0], &op[0]);
+ }
inst = emit(CMP(dst_null_d(), op[0], src_reg(0), BRW_CONDITIONAL_NZ));
*predicate = BRW_PREDICATE_ALIGN16_ANY4H;
break;
case ir_binop_lequal:
case ir_binop_equal:
case ir_binop_nequal:
+ if (brw->gen <= 5) {
+ resolve_bool_comparison(expr->operands[0], &op[0]);
+ resolve_bool_comparison(expr->operands[1], &op[1]);
+ }
emit(CMP(dst_null_d(), op[0], op[1],
brw_conditional_for_comparison(expr->operation)));
break;
+ case ir_triop_csel: {
+ /* Expand the boolean condition into the flag register. */
+ inst = emit(MOV(dst_null_d(), op[0]));
+ inst->conditional_mod = BRW_CONDITIONAL_NZ;
+
+ /* Select which boolean to return. */
+ dst_reg temp(this, expr->operands[1]->type);
+ inst = emit(BRW_OPCODE_SEL, temp, op[1], op[2]);
+ inst->predicate = BRW_PREDICATE_NORMAL;
+
+ /* Expand the result to a condition code. */
+ inst = emit(MOV(dst_null_d(), src_reg(temp)));
+ inst->conditional_mod = BRW_CONDITIONAL_NZ;
+ break;
+ }
+
default:
- assert(!"not reached");
- break;
+ unreachable("not reached");
}
return;
}
resolve_ud_negate(&this->result);
- if (brw->gen >= 6) {
- vec4_instruction *inst = emit(AND(dst_null_d(),
- this->result, src_reg(1)));
- inst->conditional_mod = BRW_CONDITIONAL_NZ;
- } else {
- vec4_instruction *inst = emit(MOV(dst_null_d(), this->result));
- inst->conditional_mod = BRW_CONDITIONAL_NZ;
- }
+ vec4_instruction *inst = emit(AND(dst_null_d(), this->result, src_reg(1)));
+ inst->conditional_mod = BRW_CONDITIONAL_NZ;
}
/**
{
ir_expression *expr = ir->condition->as_expression();
- if (expr) {
- src_reg op[2];
+ if (expr && expr->operation != ir_binop_ubo_load) {
+ src_reg op[3];
dst_reg temp;
- assert(expr->get_num_operands() <= 2);
+ assert(expr->get_num_operands() <= 3);
for (unsigned int i = 0; i < expr->get_num_operands(); i++) {
expr->operands[i]->accept(this);
op[i] = this->result;
emit(IF(BRW_PREDICATE_ALIGN16_ANY4H));
return;
+ case ir_triop_csel: {
+ /* Expand the boolean condition into the flag register. */
+ vec4_instruction *inst = emit(MOV(dst_null_d(), op[0]));
+ inst->conditional_mod = BRW_CONDITIONAL_NZ;
+
+ /* Select which boolean to return. */
+ dst_reg temp(this, expr->operands[1]->type);
+ inst = emit(BRW_OPCODE_SEL, temp, op[1], op[2]);
+ inst->predicate = BRW_PREDICATE_NORMAL;
+
+ emit(IF(src_reg(temp), src_reg(0), BRW_CONDITIONAL_NZ));
+ return;
+ }
+
default:
- assert(!"not reached");
- emit(IF(op[0], src_reg(0), BRW_CONDITIONAL_NZ));
- return;
+ unreachable("not reached");
}
return;
}
switch (ir->data.mode) {
case ir_var_shader_in:
+ assert(ir->data.location != -1);
reg = new(mem_ctx) dst_reg(ATTR, ir->data.location);
break;
case ir_var_shader_out:
+ assert(ir->data.location != -1);
reg = new(mem_ctx) dst_reg(this, ir->type);
for (int i = 0; i < type_size(ir->type); i++) {
* ir_binop_ubo_load expressions and not ir_dereference_variable for UBO
* variables, so no need for them to be in variable_ht.
*
- * Atomic counters take no uniform storage, no need to do
- * anything here.
+ * Some uniforms, such as samplers and atomic counters, have no actual
+ * storage, so we should ignore them.
*/
- if (ir->is_in_uniform_block() || ir->type->contains_atomic())
+ if (ir->is_in_uniform_block() || type_size(ir->type) == 0)
return;
/* Track how big the whole uniform variable is, in case we need to put a
break;
default:
- assert(!"not reached");
+ unreachable("not reached");
}
reg->type = brw_type_for_base_type(ir->type);
void
-vec4_visitor::visit(ir_function_signature *ir)
+vec4_visitor::visit(ir_function_signature *)
{
- assert(0);
- (void)ir;
+ unreachable("not reached");
}
void
const ir_function_signature *sig;
exec_list empty;
- sig = ir->matching_signature(NULL, &empty);
+ sig = ir->matching_signature(NULL, &empty, false);
assert(sig);
}
}
-bool
-vec4_visitor::try_emit_sat(ir_expression *ir)
-{
- ir_rvalue *sat_src = ir->as_rvalue_to_saturate();
- if (!sat_src)
- return false;
-
- sat_src->accept(this);
- src_reg src = this->result;
-
- this->result = src_reg(this, ir->type);
- vec4_instruction *inst;
- inst = emit(MOV(dst_reg(this->result), src));
- inst->saturate = true;
-
- return true;
-}
-
bool
vec4_visitor::try_emit_mad(ir_expression *ir)
{
if (ir->type->base_type != GLSL_TYPE_FLOAT)
return false;
- ir_rvalue *nonmul = ir->operands[1];
- ir_expression *mul = ir->operands[0]->as_expression();
+ ir_rvalue *nonmul;
+ ir_expression *mul;
+ bool mul_negate, mul_abs;
- if (!mul || mul->operation != ir_binop_mul) {
- nonmul = ir->operands[0];
- mul = ir->operands[1]->as_expression();
+ for (int i = 0; i < 2; i++) {
+ mul_negate = false;
+ mul_abs = false;
- if (!mul || mul->operation != ir_binop_mul)
- return false;
+ mul = ir->operands[i]->as_expression();
+ nonmul = ir->operands[1 - i];
+
+ if (mul && mul->operation == ir_unop_abs) {
+ mul = mul->operands[0]->as_expression();
+ mul_abs = true;
+ } else if (mul && mul->operation == ir_unop_neg) {
+ mul = mul->operands[0]->as_expression();
+ mul_negate = true;
+ }
+
+ if (mul && mul->operation == ir_binop_mul)
+ break;
}
+ if (!mul || mul->operation != ir_binop_mul)
+ return false;
+
nonmul->accept(this);
src_reg src0 = fix_3src_operand(this->result);
mul->operands[0]->accept(this);
src_reg src1 = fix_3src_operand(this->result);
+ src1.negate ^= mul_negate;
+ src1.abs = mul_abs;
+ if (mul_abs)
+ src1.negate = false;
mul->operands[1]->accept(this);
src_reg src2 = fix_3src_operand(this->result);
+ src2.abs = mul_abs;
+ if (mul_abs)
+ src2.negate = false;
this->result = src_reg(this, ir->type);
emit(BRW_OPCODE_MAD, dst_reg(this->result), src0, src1, src2);
bool
vec4_visitor::try_emit_b2f_of_compare(ir_expression *ir)
{
+ /* This optimization relies on CMP setting the destination to 0 when
+ * false. Early hardware only sets the least significant bit, and
+ * leaves the other bits undefined. So we can't use it.
+ */
+ if (brw->gen < 6)
+ return false;
+
ir_expression *const cmp = ir->operands[0]->as_expression();
if (cmp == NULL)
}
void
-vec4_visitor::emit_bool_comparison(unsigned int op,
- dst_reg dst, src_reg src0, src_reg src1)
-{
- /* original gen4 does destination conversion before comparison. */
- if (brw->gen < 5)
- dst.type = src0.type;
-
- emit(CMP(dst, src0, src1, brw_conditional_for_comparison(op)));
-
- dst.type = BRW_REGISTER_TYPE_D;
- emit(AND(dst, src_reg(dst), src_reg(0x1)));
-}
-
-void
-vec4_visitor::emit_minmax(uint32_t conditionalmod, dst_reg dst,
+vec4_visitor::emit_minmax(enum brw_conditional_mod conditionalmod, dst_reg dst,
src_reg src0, src_reg src1)
{
vec4_instruction *inst;
vec4_visitor::visit(ir_expression *ir)
{
unsigned int operand;
- src_reg op[Elements(ir->operands)];
- src_reg result_src;
- dst_reg result_dst;
+ src_reg op[ARRAY_SIZE(ir->operands)];
vec4_instruction *inst;
- if (try_emit_sat(ir))
- return;
-
if (ir->operation == ir_binop_add) {
if (try_emit_mad(ir))
return;
return;
}
+ /* Storage for our result. Ideally for an assignment we'd be using
+ * the actual storage for the result here, instead.
+ */
+ dst_reg result_dst(this, ir->type);
+ src_reg result_src(result_dst);
+
+ if (ir->operation == ir_triop_csel) {
+ ir->operands[1]->accept(this);
+ op[1] = this->result;
+ ir->operands[2]->accept(this);
+ op[2] = this->result;
+
+ enum brw_predicate predicate;
+ emit_bool_to_cond_code(ir->operands[0], &predicate);
+ inst = emit(BRW_OPCODE_SEL, result_dst, op[1], op[2]);
+ inst->predicate = predicate;
+ this->result = result_src;
+ return;
+ }
+
for (operand = 0; operand < ir->get_num_operands(); operand++) {
this->result.file = BAD_FILE;
ir->operands[operand]->accept(this);
assert(!ir->operands[operand]->type->is_matrix());
}
- int vector_elements = ir->operands[0]->type->vector_elements;
- if (ir->operands[1]) {
- vector_elements = MAX2(vector_elements,
- ir->operands[1]->type->vector_elements);
- }
-
- this->result.file = BAD_FILE;
-
- /* Storage for our result. Ideally for an assignment we'd be using
- * the actual storage for the result here, instead.
- */
- result_src = src_reg(this, ir->type);
- /* convenience for the emit functions below. */
- result_dst = dst_reg(result_src);
/* If nothing special happens, this is the result. */
this->result = result_src;
- /* Limit writes to the channels that will be used by result_src later.
- * This does limit this temp's use as a temporary for multi-instruction
- * sequences.
- */
- result_dst.writemask = (1 << ir->type->vector_elements) - 1;
switch (ir->operation) {
case ir_unop_logic_not:
- /* Note that BRW_OPCODE_NOT is not appropriate here, since it is
- * ones complement of the whole register, not just bit 0.
- */
- emit(XOR(result_dst, op[0], src_reg(1)));
+ emit(NOT(result_dst, op[0]));
break;
case ir_unop_neg:
op[0].negate = !op[0].negate;
break;
case ir_unop_exp:
case ir_unop_log:
- assert(!"not reached: should be handled by ir_explog_to_explog2");
- break;
+ unreachable("not reached: should be handled by ir_explog_to_explog2");
case ir_unop_sin:
case ir_unop_sin_reduced:
emit_math(SHADER_OPCODE_SIN, result_dst, op[0]);
break;
case ir_unop_dFdx:
+ case ir_unop_dFdx_coarse:
+ case ir_unop_dFdx_fine:
case ir_unop_dFdy:
- assert(!"derivatives not valid in vertex shader");
- break;
+ case ir_unop_dFdy_coarse:
+ case ir_unop_dFdy_fine:
+ unreachable("derivatives not valid in vertex shader");
case ir_unop_bitfield_reverse:
emit(BFREV(result_dst, op[0]));
case ir_unop_find_lsb:
emit(FBL(result_dst, op[0]));
break;
+ case ir_unop_saturate:
+ inst = emit(MOV(result_dst, op[0]));
+ inst->saturate = true;
+ break;
case ir_unop_noise:
- assert(!"not reached: should be handled by lower_noise");
- break;
+ unreachable("not reached: should be handled by lower_noise");
case ir_binop_add:
emit(ADD(result_dst, op[0], op[1]));
break;
case ir_binop_sub:
- assert(!"not reached: should be handled by ir_sub_to_add_neg");
- break;
+ unreachable("not reached: should be handled by ir_sub_to_add_neg");
case ir_binop_mul:
if (brw->gen < 8 && ir->type->is_integer()) {
else
emit(MUL(result_dst, op[0], op[1]));
} else {
- struct brw_reg acc = retype(brw_acc_reg(), result_dst.type);
+ struct brw_reg acc = retype(brw_acc_reg(8), result_dst.type);
emit(MUL(acc, op[0], op[1]));
emit(MACH(dst_null_d(), op[0], op[1]));
}
break;
case ir_binop_imul_high: {
- struct brw_reg acc = retype(brw_acc_reg(), result_dst.type);
+ struct brw_reg acc = retype(brw_acc_reg(8), result_dst.type);
emit(MUL(acc, op[0], op[1]));
emit(MACH(result_dst, op[0], op[1]));
emit_math(SHADER_OPCODE_INT_QUOTIENT, result_dst, op[0], op[1]);
break;
case ir_binop_carry: {
- struct brw_reg acc = retype(brw_acc_reg(), BRW_REGISTER_TYPE_UD);
+ struct brw_reg acc = retype(brw_acc_reg(8), BRW_REGISTER_TYPE_UD);
emit(ADDC(dst_null_ud(), op[0], op[1]));
emit(MOV(result_dst, src_reg(acc)));
break;
}
case ir_binop_borrow: {
- struct brw_reg acc = retype(brw_acc_reg(), BRW_REGISTER_TYPE_UD);
+ struct brw_reg acc = retype(brw_acc_reg(8), BRW_REGISTER_TYPE_UD);
emit(SUBB(dst_null_ud(), op[0], op[1]));
emit(MOV(result_dst, src_reg(acc)));
break;
}
case ir_binop_mod:
- /* Floating point should be lowered by MOD_TO_FRACT in the compiler. */
+ /* Floating point should be lowered by MOD_TO_FLOOR in the compiler. */
assert(ir->type->is_integer());
emit_math(SHADER_OPCODE_INT_REMAINDER, result_dst, op[0], op[1]);
break;
case ir_binop_gequal:
case ir_binop_equal:
case ir_binop_nequal: {
+ if (brw->gen <= 5) {
+ resolve_bool_comparison(ir->operands[0], &op[0]);
+ resolve_bool_comparison(ir->operands[1], &op[1]);
+ }
emit(CMP(result_dst, op[0], op[1],
brw_conditional_for_comparison(ir->operation)));
- emit(AND(result_dst, result_src, src_reg(0x1)));
break;
}
case ir_binop_all_equal:
+ if (brw->gen <= 5) {
+ resolve_bool_comparison(ir->operands[0], &op[0]);
+ resolve_bool_comparison(ir->operands[1], &op[1]);
+ }
+
/* "==" operator producing a scalar boolean. */
if (ir->operands[0]->type->is_vector() ||
ir->operands[1]->type->is_vector()) {
emit(CMP(dst_null_d(), op[0], op[1], BRW_CONDITIONAL_Z));
emit(MOV(result_dst, src_reg(0)));
- inst = emit(MOV(result_dst, src_reg(1)));
+ inst = emit(MOV(result_dst, src_reg((int)ctx->Const.UniformBooleanTrue)));
inst->predicate = BRW_PREDICATE_ALIGN16_ALL4H;
} else {
emit(CMP(result_dst, op[0], op[1], BRW_CONDITIONAL_Z));
- emit(AND(result_dst, result_src, src_reg(0x1)));
}
break;
case ir_binop_any_nequal:
+ if (brw->gen <= 5) {
+ resolve_bool_comparison(ir->operands[0], &op[0]);
+ resolve_bool_comparison(ir->operands[1], &op[1]);
+ }
+
/* "!=" operator producing a scalar boolean. */
if (ir->operands[0]->type->is_vector() ||
ir->operands[1]->type->is_vector()) {
emit(CMP(dst_null_d(), op[0], op[1], BRW_CONDITIONAL_NZ));
emit(MOV(result_dst, src_reg(0)));
- inst = emit(MOV(result_dst, src_reg(1)));
+ inst = emit(MOV(result_dst, src_reg((int)ctx->Const.UniformBooleanTrue)));
inst->predicate = BRW_PREDICATE_ALIGN16_ANY4H;
} else {
emit(CMP(result_dst, op[0], op[1], BRW_CONDITIONAL_NZ));
- emit(AND(result_dst, result_src, src_reg(0x1)));
}
break;
case ir_unop_any:
+ if (brw->gen <= 5) {
+ resolve_bool_comparison(ir->operands[0], &op[0]);
+ }
emit(CMP(dst_null_d(), op[0], src_reg(0), BRW_CONDITIONAL_NZ));
emit(MOV(result_dst, src_reg(0)));
- inst = emit(MOV(result_dst, src_reg(1)));
+ inst = emit(MOV(result_dst, src_reg((int)ctx->Const.UniformBooleanTrue)));
inst->predicate = BRW_PREDICATE_ALIGN16_ANY4H;
break;
case ir_unop_i2u:
case ir_unop_u2i:
case ir_unop_u2f:
- case ir_unop_b2f:
- case ir_unop_b2i:
case ir_unop_f2i:
case ir_unop_f2u:
emit(MOV(result_dst, op[0]));
break;
+ case ir_unop_b2i:
+ emit(AND(result_dst, op[0], src_reg(1)));
+ break;
+ case ir_unop_b2f:
+ if (brw->gen <= 5) {
+ resolve_bool_comparison(ir->operands[0], &op[0]);
+ }
+ op[0].type = BRW_REGISTER_TYPE_D;
+ result_dst.type = BRW_REGISTER_TYPE_D;
+ emit(AND(result_dst, op[0], src_reg(0x3f800000u)));
+ result_dst.type = BRW_REGISTER_TYPE_F;
+ break;
case ir_unop_f2b:
- case ir_unop_i2b: {
emit(CMP(result_dst, op[0], src_reg(0.0f), BRW_CONDITIONAL_NZ));
- emit(AND(result_dst, result_src, src_reg(1)));
break;
- }
+ case ir_unop_i2b:
+ emit(CMP(result_dst, op[0], src_reg(0), BRW_CONDITIONAL_NZ));
+ break;
case ir_unop_trunc:
emit(RNDZ(result_dst, op[0]));
break;
- case ir_unop_ceil:
- op[0].negate = !op[0].negate;
- inst = emit(RNDD(result_dst, op[0]));
- this->result.negate = true;
+ case ir_unop_ceil: {
+ src_reg tmp = src_reg(this, ir->type);
+ op[0].negate = !op[0].negate;
+ emit(RNDD(dst_reg(tmp), op[0]));
+ tmp.negate = true;
+ emit(MOV(result_dst, tmp));
+ }
break;
case ir_unop_floor:
inst = emit(RNDD(result_dst, op[0]));
emit_minmax(BRW_CONDITIONAL_L, result_dst, op[0], op[1]);
break;
case ir_binop_max:
- emit_minmax(BRW_CONDITIONAL_G, result_dst, op[0], op[1]);
+ emit_minmax(BRW_CONDITIONAL_GE, result_dst, op[0], op[1]);
break;
case ir_binop_pow:
break;
case ir_binop_ubo_load: {
- ir_constant *uniform_block = ir->operands[0]->as_constant();
+ ir_constant *const_uniform_block = ir->operands[0]->as_constant();
ir_constant *const_offset_ir = ir->operands[1]->as_constant();
unsigned const_offset = const_offset_ir ? const_offset_ir->value.u[0] : 0;
src_reg offset;
src_reg packed_consts = src_reg(this, glsl_type::vec4_type);
packed_consts.type = result.type;
- src_reg surf_index =
- src_reg(prog_data->base.binding_table.ubo_start + uniform_block->value.u[0]);
+ src_reg surf_index;
+
+ if (const_uniform_block) {
+ /* The block index is a constant, so just emit the binding table entry
+ * as an immediate.
+ */
+ surf_index = src_reg(prog_data->base.binding_table.ubo_start +
+ const_uniform_block->value.u[0]);
+ } else {
+ /* The block index is not a constant. Evaluate the index expression
+ * per-channel and add the base UBO index; the generator will select
+ * a value from any live channel.
+ */
+ surf_index = src_reg(this, glsl_type::uint_type);
+ emit(ADD(dst_reg(surf_index), op[0],
+ src_reg(prog_data->base.binding_table.ubo_start)));
+
+ /* Assume this may touch any UBO. It would be nice to provide
+ * a tighter bound, but the array information is already lowered away.
+ */
+ brw_mark_surface_used(&prog_data->base,
+ prog_data->base.binding_table.ubo_start +
+ shader_prog->NumUniformBlocks - 1);
+ }
+
if (const_offset_ir) {
if (brw->gen >= 8) {
/* Store the offset in a GRF so we can send-from-GRF. */
emit(MOV(grf_offset, offset));
- emit(new(mem_ctx) vec4_instruction(this,
- VS_OPCODE_PULL_CONSTANT_LOAD_GEN7,
- dst_reg(packed_consts),
- surf_index,
- src_reg(grf_offset)));
+ vec4_instruction *pull =
+ emit(new(mem_ctx) vec4_instruction(VS_OPCODE_PULL_CONSTANT_LOAD_GEN7,
+ dst_reg(packed_consts),
+ surf_index,
+ src_reg(grf_offset)));
+ pull->mlen = 1;
} else {
vec4_instruction *pull =
- emit(new(mem_ctx) vec4_instruction(this,
- VS_OPCODE_PULL_CONSTANT_LOAD,
+ emit(new(mem_ctx) vec4_instruction(VS_OPCODE_PULL_CONSTANT_LOAD,
dst_reg(packed_consts),
surf_index,
offset));
const_offset % 16 / 4,
const_offset % 16 / 4);
- /* UBO bools are any nonzero int. We store bools as either 0 or 1. */
+ /* UBO bools are any nonzero int. We need to convert them to use the
+ * value of true stored in ctx->Const.UniformBooleanTrue.
+ */
if (ir->type->base_type == GLSL_TYPE_BOOL) {
emit(CMP(result_dst, packed_consts, src_reg(0u),
BRW_CONDITIONAL_NZ));
- emit(AND(result_dst, result, src_reg(0x1)));
} else {
emit(MOV(result_dst, packed_consts));
}
}
case ir_binop_vector_extract:
- assert(!"should have been lowered by vec_index_to_cond_assign");
- break;
+ unreachable("should have been lowered by vec_index_to_cond_assign");
case ir_triop_fma:
op[0] = fix_3src_operand(op[0]);
break;
case ir_triop_csel:
- emit(CMP(dst_null_d(), op[0], src_reg(0), BRW_CONDITIONAL_NZ));
- inst = emit(BRW_OPCODE_SEL, result_dst, op[1], op[2]);
- inst->predicate = BRW_PREDICATE_NORMAL;
+ unreachable("already handled above");
break;
case ir_triop_bfi:
break;
case ir_triop_vector_insert:
- assert(!"should have been lowered by lower_vector_insert");
- break;
+ unreachable("should have been lowered by lower_vector_insert");
case ir_quadop_bitfield_insert:
- assert(!"not reached: should be handled by "
+ unreachable("not reached: should be handled by "
"bitfield_insert_to_bfm_bfi\n");
- break;
case ir_quadop_vector:
- assert(!"not reached: should be handled by lower_quadop_vector");
- break;
+ unreachable("not reached: should be handled by lower_quadop_vector");
case ir_unop_pack_half_2x16:
emit_pack_half_2x16(result_dst, op[0]);
case ir_unop_unpack_half_2x16:
emit_unpack_half_2x16(result_dst, op[0]);
break;
- case ir_unop_pack_snorm_2x16:
+ case ir_unop_unpack_unorm_4x8:
+ emit_unpack_unorm_4x8(result_dst, op[0]);
+ break;
+ case ir_unop_unpack_snorm_4x8:
+ emit_unpack_snorm_4x8(result_dst, op[0]);
+ break;
+ case ir_unop_pack_unorm_4x8:
+ emit_pack_unorm_4x8(result_dst, op[0]);
+ break;
case ir_unop_pack_snorm_4x8:
+ emit_pack_snorm_4x8(result_dst, op[0]);
+ break;
+ case ir_unop_pack_snorm_2x16:
case ir_unop_pack_unorm_2x16:
- case ir_unop_pack_unorm_4x8:
case ir_unop_unpack_snorm_2x16:
- case ir_unop_unpack_snorm_4x8:
case ir_unop_unpack_unorm_2x16:
- case ir_unop_unpack_unorm_4x8:
- assert(!"not reached: should be handled by lower_packing_builtins");
- break;
+ unreachable("not reached: should be handled by lower_packing_builtins");
case ir_unop_unpack_half_2x16_split_x:
case ir_unop_unpack_half_2x16_split_y:
case ir_binop_pack_half_2x16_split:
- assert(!"not reached: should not occur in vertex shader");
- break;
+ case ir_unop_interpolate_at_centroid:
+ case ir_binop_interpolate_at_sample:
+ case ir_binop_interpolate_at_offset:
+ unreachable("not reached: should not occur in vertex shader");
case ir_binop_ldexp:
- assert(!"not reached: should be handled by ldexp_to_arith()");
- break;
+ unreachable("not reached: should be handled by ldexp_to_arith()");
+ case ir_unop_d2f:
+ case ir_unop_f2d:
+ case ir_unop_d2i:
+ case ir_unop_i2d:
+ case ir_unop_d2u:
+ case ir_unop_u2d:
+ case ir_unop_d2b:
+ case ir_unop_pack_double_2x32:
+ case ir_unop_unpack_double_2x32:
+ case ir_unop_frexp_sig:
+ case ir_unop_frexp_exp:
+ unreachable("fp64 todo");
}
}
void
vec4_visitor::emit_block_move(dst_reg *dst, src_reg *src,
- const struct glsl_type *type, uint32_t predicate)
+ const struct glsl_type *type,
+ enum brw_predicate predicate)
{
if (type->base_type == GLSL_TYPE_STRUCT) {
for (unsigned int i = 0; i < type->length; i++) {
vec4_visitor::visit(ir_assignment *ir)
{
dst_reg dst = get_assignment_lhs(ir->lhs, this);
- uint32_t predicate = BRW_PREDICATE_NONE;
+ enum brw_predicate predicate = BRW_PREDICATE_NONE;
if (!ir->lhs->type->is_scalar() &&
!ir->lhs->type->is_vector()) {
vec4_visitor::emit_constant_values(dst_reg *dst, ir_constant *ir)
{
if (ir->type->base_type == GLSL_TYPE_STRUCT) {
- foreach_list(node, &ir->components) {
- ir_constant *field_value = (ir_constant *)node;
-
+ foreach_in_list(ir_constant, field_value, &ir->components) {
emit_constant_values(dst, field_value);
}
return;
emit(MOV(*dst, src_reg(ir->value.u[i])));
break;
case GLSL_TYPE_BOOL:
- emit(MOV(*dst, src_reg(ir->value.b[i])));
+ emit(MOV(*dst,
+ src_reg(ir->value.b[i] != 0 ? (int)ctx->Const.UniformBooleanTrue
+ : 0)));
break;
default:
- assert(!"Non-float/uint/int/bool constant");
- break;
+ unreachable("Non-float/uint/int/bool constant");
}
remaining_writemask &= ~dst->writemask;
ir->actual_parameters.get_head());
ir_variable *location = deref->variable_referenced();
unsigned surf_index = (prog_data->base.binding_table.abo_start +
- location->data.atomic.buffer_index);
+ location->data.binding);
/* Calculate the surface offset */
src_reg offset(this, glsl_type::uint_type);
!strcmp("__intrinsic_atomic_predecrement", callee)) {
visit_atomic_counter_intrinsic(ir);
} else {
- assert(!"Unsupported intrinsic.");
+ unreachable("Unsupported intrinsic.");
}
}
src_reg
-vec4_visitor::emit_mcs_fetch(ir_texture *ir, src_reg coordinate, int sampler)
+vec4_visitor::emit_mcs_fetch(ir_texture *ir, src_reg coordinate, src_reg sampler)
{
- vec4_instruction *inst = new(mem_ctx) vec4_instruction(this, SHADER_OPCODE_TXF_MCS);
+ vec4_instruction *inst =
+ new(mem_ctx) vec4_instruction(SHADER_OPCODE_TXF_MCS,
+ dst_reg(this, glsl_type::uvec4_type));
inst->base_mrf = 2;
inst->mlen = 1;
- inst->sampler = sampler;
- inst->dst = dst_reg(this, glsl_type::uvec4_type);
- inst->dst.writemask = WRITEMASK_XYZW;
+ inst->src[1] = sampler;
/* parameters are: u, v, r, lod; lod will always be zero due to api restrictions */
int param_base = inst->base_mrf;
return src_reg(inst->dst);
}
+static bool
+is_high_sampler(struct brw_context *brw, src_reg sampler)
+{
+ if (brw->gen < 8 && !brw->is_haswell)
+ return false;
+
+ return sampler.file != IMM || sampler.fixed_hw_reg.dw1.ud >= 16;
+}
+
void
vec4_visitor::visit(ir_texture *ir)
{
- int sampler =
+ uint32_t sampler =
_mesa_get_sampler_uniform_value(ir->sampler, shader_prog, prog);
+ ir_rvalue *nonconst_sampler_index =
+ _mesa_get_sampler_array_nonconst_index(ir->sampler);
+
+ /* Handle non-constant sampler array indexing */
+ src_reg sampler_reg;
+ if (nonconst_sampler_index) {
+ /* The highest sampler which may be used by this operation is
+ * the last element of the array. Mark it here, because the generator
+ * doesn't have enough information to determine the bound.
+ */
+ uint32_t array_size = ir->sampler->as_dereference_array()
+ ->array->type->array_size();
+
+ uint32_t max_used = sampler + array_size - 1;
+ if (ir->op == ir_tg4 && brw->gen < 8) {
+ max_used += prog_data->base.binding_table.gather_texture_start;
+ } else {
+ max_used += prog_data->base.binding_table.texture_start;
+ }
+
+ brw_mark_surface_used(&prog_data->base, max_used);
+
+ /* Emit code to evaluate the actual indexing expression */
+ nonconst_sampler_index->accept(this);
+ dst_reg temp(this, glsl_type::uint_type);
+ emit(ADD(temp, this->result, src_reg(sampler)))
+ ->force_writemask_all = true;
+ sampler_reg = src_reg(temp);
+ } else {
+ /* Single sampler, or constant array index; the indexing expression
+ * is just an immediate.
+ */
+ sampler_reg = src_reg(sampler);
+ }
+
/* When tg4 is used with the degenerate ZERO/ONE swizzles, don't bother
* emitting anything other than setting up the constant result.
*/
sample_index_type = ir->lod_info.sample_index->type;
if (brw->gen >= 7 && key->tex.compressed_multisample_layout_mask & (1<<sampler))
- mcs = emit_mcs_fetch(ir, coordinate, sampler);
+ mcs = emit_mcs_fetch(ir, coordinate, sampler_reg);
else
mcs = src_reg(0u);
break;
break;
}
- vec4_instruction *inst = NULL;
+ enum opcode opcode;
switch (ir->op) {
- case ir_tex:
- case ir_txl:
- inst = new(mem_ctx) vec4_instruction(this, SHADER_OPCODE_TXL);
- break;
- case ir_txd:
- inst = new(mem_ctx) vec4_instruction(this, SHADER_OPCODE_TXD);
- break;
- case ir_txf:
- inst = new(mem_ctx) vec4_instruction(this, SHADER_OPCODE_TXF);
- break;
- case ir_txf_ms:
- inst = new(mem_ctx) vec4_instruction(this, SHADER_OPCODE_TXF_CMS);
- break;
- case ir_txs:
- inst = new(mem_ctx) vec4_instruction(this, SHADER_OPCODE_TXS);
- break;
- case ir_tg4:
- if (has_nonconstant_offset)
- inst = new(mem_ctx) vec4_instruction(this, SHADER_OPCODE_TG4_OFFSET);
- else
- inst = new(mem_ctx) vec4_instruction(this, SHADER_OPCODE_TG4);
- break;
- case ir_query_levels:
- inst = new(mem_ctx) vec4_instruction(this, SHADER_OPCODE_TXS);
- break;
+ case ir_tex: opcode = SHADER_OPCODE_TXL; break;
+ case ir_txl: opcode = SHADER_OPCODE_TXL; break;
+ case ir_txd: opcode = SHADER_OPCODE_TXD; break;
+ case ir_txf: opcode = SHADER_OPCODE_TXF; break;
+ case ir_txf_ms: opcode = SHADER_OPCODE_TXF_CMS; break;
+ case ir_txs: opcode = SHADER_OPCODE_TXS; break;
+ case ir_tg4: opcode = has_nonconstant_offset
+ ? SHADER_OPCODE_TG4_OFFSET : SHADER_OPCODE_TG4; break;
+ case ir_query_levels: opcode = SHADER_OPCODE_TXS; break;
case ir_txb:
- assert(!"TXB is not valid for vertex shaders.");
- break;
+ unreachable("TXB is not valid for vertex shaders.");
case ir_lod:
- assert(!"LOD is not valid for vertex shaders.");
- break;
+ unreachable("LOD is not valid for vertex shaders.");
default:
- assert(!"Unrecognized tex op");
+ unreachable("Unrecognized tex op");
}
- if (ir->offset != NULL && ir->op != ir_txf)
- inst->texture_offset = brw_texture_offset(ctx, ir->offset->as_constant());
+ vec4_instruction *inst = new(mem_ctx) vec4_instruction(
+ opcode, dst_reg(this, ir->type));
+
+ if (ir->offset != NULL && !has_nonconstant_offset) {
+ inst->offset =
+ brw_texture_offset(ctx, ir->offset->as_constant()->value.i,
+ ir->offset->type->vector_elements);
+ }
/* Stuff the channel select bits in the top of the texture offset */
if (ir->op == ir_tg4)
- inst->texture_offset |= gather_channel(ir, sampler) << 16;
+ inst->offset |= gather_channel(ir, sampler) << 16;
/* The message header is necessary for:
* - Gen4 (always)
+ * - Gen9+ for selecting SIMD4x2
* - Texel offsets
* - Gather channel selection
* - Sampler indices too large to fit in a 4-bit value.
*/
inst->header_present =
- brw->gen < 5 || inst->texture_offset != 0 || ir->op == ir_tg4 ||
- sampler >= 16;
+ brw->gen < 5 || brw->gen >= 9 ||
+ inst->offset != 0 || ir->op == ir_tg4 ||
+ is_high_sampler(brw, sampler_reg);
inst->base_mrf = 2;
inst->mlen = inst->header_present + 1; /* always at least one */
- inst->sampler = sampler;
- inst->dst = dst_reg(this, ir->type);
inst->dst.writemask = WRITEMASK_XYZW;
inst->shadow_compare = ir->shadow_comparitor != NULL;
+ inst->src[1] = sampler_reg;
+
/* MRF for the first parameter */
int param_base = inst->base_mrf + inst->header_present;
} else if (ir->op == ir_txf_ms) {
emit(MOV(dst_reg(MRF, param_base + 1, sample_index_type, WRITEMASK_X),
sample_index));
- if (brw->gen >= 7)
+ if (brw->gen >= 7) {
/* MCS data is in the first channel of `mcs`, but we need to get it into
* the .y channel of the second vec4 of params, so replicate .x across
* the whole vec4 and then mask off everything except .y
mcs.swizzle = BRW_SWIZZLE_XXXX;
emit(MOV(dst_reg(MRF, param_base + 1, glsl_type::uint_type, WRITEMASK_Y),
mcs));
+ }
inst->mlen++;
} else if (ir->op == ir_txd) {
const glsl_type *type = lod_type;
* Set up the gather channel based on the swizzle, for gather4.
*/
uint32_t
-vec4_visitor::gather_channel(ir_texture *ir, int sampler)
+vec4_visitor::gather_channel(ir_texture *ir, uint32_t sampler)
{
ir_constant *chan = ir->lod_info.component->as_constant();
int swiz = GET_SWZ(key->tex.swizzles[sampler], chan->value.i[0]);
case SWIZZLE_Z: return 2;
case SWIZZLE_W: return 3;
default:
- assert(!"Not reached"); /* zero, one swizzles handled already */
- return 0;
+ unreachable("Not reached"); /* zero, one swizzles handled already */
}
}
void
-vec4_visitor::swizzle_result(ir_texture *ir, src_reg orig_val, int sampler)
+vec4_visitor::swizzle_result(ir_texture *ir, src_reg orig_val, uint32_t sampler)
{
int s = key->tex.swizzles[sampler];
void
vec4_visitor::visit(ir_return *)
{
- assert(!"not reached");
+ unreachable("not reached");
}
void
vec4_visitor::visit(ir_discard *)
{
- assert(!"not reached");
+ unreachable("not reached");
}
void
if (brw->gen == 6) {
emit_if_gen6(ir);
} else {
- uint32_t predicate;
+ enum brw_predicate predicate;
emit_bool_to_cond_code(ir->condition, &predicate);
emit(IF(predicate));
}
void
vec4_visitor::visit(ir_emit_vertex *)
{
- assert(!"not reached");
+ unreachable("not reached");
}
void
vec4_visitor::visit(ir_end_primitive *)
{
- assert(!"not reached");
+ unreachable("not reached");
}
void
}
void
-vec4_visitor::emit_psiz_and_flags(struct brw_reg reg)
+vec4_visitor::emit_psiz_and_flags(dst_reg reg)
{
if (brw->gen < 6 &&
((prog_data->vue_map.slots_valid & VARYING_BIT_PSIZ) ||
} else {
emit(MOV(retype(reg, BRW_REGISTER_TYPE_D), src_reg(0)));
if (prog_data->vue_map.slots_valid & VARYING_BIT_PSIZ) {
- emit(MOV(brw_writemask(reg, WRITEMASK_W),
- src_reg(output_reg[VARYING_SLOT_PSIZ])));
+ dst_reg reg_w = reg;
+ reg_w.writemask = WRITEMASK_W;
+ emit(MOV(reg_w, src_reg(output_reg[VARYING_SLOT_PSIZ])));
}
if (prog_data->vue_map.slots_valid & VARYING_BIT_LAYER) {
- emit(MOV(retype(brw_writemask(reg, WRITEMASK_Y), BRW_REGISTER_TYPE_D),
- src_reg(output_reg[VARYING_SLOT_LAYER])));
+ dst_reg reg_y = reg;
+ reg_y.writemask = WRITEMASK_Y;
+ reg_y.type = BRW_REGISTER_TYPE_D;
+ emit(MOV(reg_y, src_reg(output_reg[VARYING_SLOT_LAYER])));
}
if (prog_data->vue_map.slots_valid & VARYING_BIT_VIEWPORT) {
- emit(MOV(retype(brw_writemask(reg, WRITEMASK_Z), BRW_REGISTER_TYPE_D),
- src_reg(output_reg[VARYING_SLOT_VIEWPORT])));
+ dst_reg reg_z = reg;
+ reg_z.writemask = WRITEMASK_Z;
+ reg_z.type = BRW_REGISTER_TYPE_D;
+ emit(MOV(reg_z, src_reg(output_reg[VARYING_SLOT_VIEWPORT])));
}
}
}
}
}
-void
+vec4_instruction *
vec4_visitor::emit_generic_urb_slot(dst_reg reg, int varying)
{
assert (varying < VARYING_SLOT_MAX);
reg.type = output_reg[varying].type;
current_annotation = output_reg_annotation[varying];
/* Copy the register, saturating if necessary */
- vec4_instruction *inst = emit(MOV(reg,
- src_reg(output_reg[varying])));
- if ((varying == VARYING_SLOT_COL0 ||
- varying == VARYING_SLOT_COL1 ||
- varying == VARYING_SLOT_BFC0 ||
- varying == VARYING_SLOT_BFC1) &&
- key->clamp_vertex_color) {
- inst->saturate = true;
- }
+ return emit(MOV(reg, src_reg(output_reg[varying])));
}
void
-vec4_visitor::emit_urb_slot(int mrf, int varying)
+vec4_visitor::emit_urb_slot(dst_reg reg, int varying)
{
- struct brw_reg hw_reg = brw_message_reg(mrf);
- dst_reg reg = dst_reg(MRF, mrf);
reg.type = BRW_REGISTER_TYPE_F;
switch (varying) {
case VARYING_SLOT_PSIZ:
+ {
/* PSIZ is always in slot 0, and is coupled with other flags. */
current_annotation = "indices, point width, clip flags";
- emit_psiz_and_flags(hw_reg);
+ emit_psiz_and_flags(reg);
break;
+ }
case BRW_VARYING_SLOT_NDC:
current_annotation = "NDC";
emit(MOV(reg, src_reg(output_reg[BRW_VARYING_SLOT_NDC])));
case BRW_VARYING_SLOT_PAD:
/* No need to write to this slot */
break;
+ case VARYING_SLOT_COL0:
+ case VARYING_SLOT_COL1:
+ case VARYING_SLOT_BFC0:
+ case VARYING_SLOT_BFC1: {
+ /* These built-in varyings are only supported in compatibility mode,
+ * and we only support GS in core profile. So, this must be a vertex
+ * shader.
+ */
+ assert(stage == MESA_SHADER_VERTEX);
+ vec4_instruction *inst = emit_generic_urb_slot(reg, varying);
+ if (((struct brw_vs_prog_key *) key)->clamp_vertex_color)
+ inst->saturate = true;
+ break;
+ }
+
default:
emit_generic_urb_slot(reg, varying);
break;
mrf = base_mrf + 1;
for (; slot < prog_data->vue_map.num_slots; ++slot) {
- emit_urb_slot(mrf++, prog_data->vue_map.slot_to_varying[slot]);
+ emit_urb_slot(dst_reg(MRF, mrf++),
+ prog_data->vue_map.slot_to_varying[slot]);
/* If this was max_usable_mrf, we can't fit anything more into this
* URB WRITE.
src_reg
-vec4_visitor::get_scratch_offset(vec4_instruction *inst,
+vec4_visitor::get_scratch_offset(bblock_t *block, vec4_instruction *inst,
src_reg *reladdr, int reg_offset)
{
/* Because we store the values to scratch interleaved like our
if (reladdr) {
src_reg index = src_reg(this, glsl_type::int_type);
- emit_before(inst, ADD(dst_reg(index), *reladdr, src_reg(reg_offset)));
- emit_before(inst, MUL(dst_reg(index),
- index, src_reg(message_header_scale)));
+ emit_before(block, inst, ADD(dst_reg(index), *reladdr,
+ src_reg(reg_offset)));
+ emit_before(block, inst, MUL(dst_reg(index), index,
+ src_reg(message_header_scale)));
return index;
} else {
}
src_reg
-vec4_visitor::get_pull_constant_offset(vec4_instruction *inst,
+vec4_visitor::get_pull_constant_offset(bblock_t * block, vec4_instruction *inst,
src_reg *reladdr, int reg_offset)
{
if (reladdr) {
src_reg index = src_reg(this, glsl_type::int_type);
- emit_before(inst, ADD(dst_reg(index), *reladdr, src_reg(reg_offset)));
+ emit_before(block, inst, ADD(dst_reg(index), *reladdr,
+ src_reg(reg_offset)));
/* Pre-gen6, the message header uses byte offsets instead of vec4
* (16-byte) offset units.
*/
if (brw->gen < 6) {
- emit_before(inst, MUL(dst_reg(index), index, src_reg(16)));
+ emit_before(block, inst, MUL(dst_reg(index), index, src_reg(16)));
}
return index;
} else if (brw->gen >= 8) {
/* Store the offset in a GRF so we can send-from-GRF. */
src_reg offset = src_reg(this, glsl_type::int_type);
- emit_before(inst, MOV(dst_reg(offset), src_reg(reg_offset)));
+ emit_before(block, inst, MOV(dst_reg(offset), src_reg(reg_offset)));
return offset;
} else {
int message_header_scale = brw->gen < 6 ? 16 : 1;
* @base_offset is measured in 32-byte units (the size of a register).
*/
void
-vec4_visitor::emit_scratch_read(vec4_instruction *inst,
+vec4_visitor::emit_scratch_read(bblock_t *block, vec4_instruction *inst,
dst_reg temp, src_reg orig_src,
int base_offset)
{
int reg_offset = base_offset + orig_src.reg_offset;
- src_reg index = get_scratch_offset(inst, orig_src.reladdr, reg_offset);
+ src_reg index = get_scratch_offset(block, inst, orig_src.reladdr,
+ reg_offset);
- emit_before(inst, SCRATCH_READ(temp, index));
+ emit_before(block, inst, SCRATCH_READ(temp, index));
}
/**
* @base_offset is measured in 32-byte units (the size of a register).
*/
void
-vec4_visitor::emit_scratch_write(vec4_instruction *inst, int base_offset)
+vec4_visitor::emit_scratch_write(bblock_t *block, vec4_instruction *inst,
+ int base_offset)
{
int reg_offset = base_offset + inst->dst.reg_offset;
- src_reg index = get_scratch_offset(inst, inst->dst.reladdr, reg_offset);
+ src_reg index = get_scratch_offset(block, inst, inst->dst.reladdr,
+ reg_offset);
/* Create a temporary register to store *inst's result in.
*
write->predicate = inst->predicate;
write->ir = inst->ir;
write->annotation = inst->annotation;
- inst->insert_after(write);
+ inst->insert_after(block, write);
inst->dst.file = temp.file;
inst->dst.reg = temp.reg;
void
vec4_visitor::move_grf_array_access_to_scratch()
{
- int scratch_loc[this->virtual_grf_count];
-
- for (int i = 0; i < this->virtual_grf_count; i++) {
- scratch_loc[i] = -1;
- }
+ int scratch_loc[this->alloc.count];
+ memset(scratch_loc, -1, sizeof(scratch_loc));
/* First, calculate the set of virtual GRFs that need to be punted
* to scratch due to having any array access on them, and where in
* scratch.
*/
- foreach_list(node, &this->instructions) {
- vec4_instruction *inst = (vec4_instruction *)node;
-
+ foreach_block_and_inst(block, vec4_instruction, inst, cfg) {
if (inst->dst.file == GRF && inst->dst.reladdr &&
scratch_loc[inst->dst.reg] == -1) {
scratch_loc[inst->dst.reg] = c->last_scratch;
- c->last_scratch += this->virtual_grf_sizes[inst->dst.reg];
+ c->last_scratch += this->alloc.sizes[inst->dst.reg];
}
for (int i = 0 ; i < 3; i++) {
if (src->file == GRF && src->reladdr &&
scratch_loc[src->reg] == -1) {
scratch_loc[src->reg] = c->last_scratch;
- c->last_scratch += this->virtual_grf_sizes[src->reg];
+ c->last_scratch += this->alloc.sizes[src->reg];
}
}
}
* we may generate a new scratch_write instruction after the one
* we're processing.
*/
- foreach_list_safe(node, &this->instructions) {
- vec4_instruction *inst = (vec4_instruction *)node;
-
+ foreach_block_and_inst_safe(block, vec4_instruction, inst, cfg) {
/* Set up the annotation tracking for new generated instructions. */
base_ir = inst->ir;
current_annotation = inst->annotation;
if (inst->dst.file == GRF && scratch_loc[inst->dst.reg] != -1) {
- emit_scratch_write(inst, scratch_loc[inst->dst.reg]);
+ emit_scratch_write(block, inst, scratch_loc[inst->dst.reg]);
}
for (int i = 0 ; i < 3; i++) {
dst_reg temp = dst_reg(this, glsl_type::vec4_type);
- emit_scratch_read(inst, temp, inst->src[i],
+ emit_scratch_read(block, inst, temp, inst->src[i],
scratch_loc[inst->src[i].reg]);
inst->src[i].file = temp.file;
* from the pull constant buffer (surface) at @base_offset to @temp.
*/
void
-vec4_visitor::emit_pull_constant_load(vec4_instruction *inst,
+vec4_visitor::emit_pull_constant_load(bblock_t *block, vec4_instruction *inst,
dst_reg temp, src_reg orig_src,
int base_offset)
{
int reg_offset = base_offset + orig_src.reg_offset;
src_reg index = src_reg(prog_data->base.binding_table.pull_constants_start);
- src_reg offset = get_pull_constant_offset(inst, orig_src.reladdr, reg_offset);
+ src_reg offset = get_pull_constant_offset(block, inst, orig_src.reladdr,
+ reg_offset);
vec4_instruction *load;
if (brw->gen >= 7) {
dst_reg grf_offset = dst_reg(this, glsl_type::int_type);
grf_offset.type = offset.type;
- emit_before(inst, MOV(grf_offset, offset));
+ emit_before(block, inst, MOV(grf_offset, offset));
- load = new(mem_ctx) vec4_instruction(this,
- VS_OPCODE_PULL_CONSTANT_LOAD_GEN7,
+ load = new(mem_ctx) vec4_instruction(VS_OPCODE_PULL_CONSTANT_LOAD_GEN7,
temp, index, src_reg(grf_offset));
+ load->mlen = 1;
} else {
- load = new(mem_ctx) vec4_instruction(this, VS_OPCODE_PULL_CONSTANT_LOAD,
+ load = new(mem_ctx) vec4_instruction(VS_OPCODE_PULL_CONSTANT_LOAD,
temp, index, offset);
load->base_mrf = 14;
load->mlen = 1;
}
- emit_before(inst, load);
+ emit_before(block, inst, load);
}
/**
vec4_visitor::move_uniform_array_access_to_pull_constants()
{
int pull_constant_loc[this->uniforms];
-
- for (int i = 0; i < this->uniforms; i++) {
- pull_constant_loc[i] = -1;
- }
+ memset(pull_constant_loc, -1, sizeof(pull_constant_loc));
+ bool nested_reladdr;
/* Walk through and find array access of uniforms. Put a copy of that
* uniform in the pull constant buffer.
* Note that we don't move constant-indexed accesses to arrays. No
* testing has been done of the performance impact of this choice.
*/
- foreach_list_safe(node, &this->instructions) {
- vec4_instruction *inst = (vec4_instruction *)node;
+ do {
+ nested_reladdr = false;
- for (int i = 0 ; i < 3; i++) {
- if (inst->src[i].file != UNIFORM || !inst->src[i].reladdr)
- continue;
+ foreach_block_and_inst_safe(block, vec4_instruction, inst, cfg) {
+ for (int i = 0 ; i < 3; i++) {
+ if (inst->src[i].file != UNIFORM || !inst->src[i].reladdr)
+ continue;
- int uniform = inst->src[i].reg;
+ int uniform = inst->src[i].reg;
- /* If this array isn't already present in the pull constant buffer,
- * add it.
- */
- if (pull_constant_loc[uniform] == -1) {
- const float **values = &stage_prog_data->param[uniform * 4];
+ if (inst->src[i].reladdr->reladdr)
+ nested_reladdr = true; /* will need another pass */
- pull_constant_loc[uniform] = stage_prog_data->nr_pull_params / 4;
+ /* If this array isn't already present in the pull constant buffer,
+ * add it.
+ */
+ if (pull_constant_loc[uniform] == -1) {
+ const gl_constant_value **values =
+ &stage_prog_data->param[uniform * 4];
- assert(uniform < uniform_array_size);
- for (int j = 0; j < uniform_size[uniform] * 4; j++) {
- stage_prog_data->pull_param[stage_prog_data->nr_pull_params++]
- = values[j];
- }
- }
+ pull_constant_loc[uniform] = stage_prog_data->nr_pull_params / 4;
- /* Set up the annotation tracking for new generated instructions. */
- base_ir = inst->ir;
- current_annotation = inst->annotation;
+ assert(uniform < uniform_array_size);
+ for (int j = 0; j < uniform_size[uniform] * 4; j++) {
+ stage_prog_data->pull_param[stage_prog_data->nr_pull_params++]
+ = values[j];
+ }
+ }
- dst_reg temp = dst_reg(this, glsl_type::vec4_type);
+ /* Set up the annotation tracking for new generated instructions. */
+ base_ir = inst->ir;
+ current_annotation = inst->annotation;
- emit_pull_constant_load(inst, temp, inst->src[i],
- pull_constant_loc[uniform]);
+ dst_reg temp = dst_reg(this, glsl_type::vec4_type);
- inst->src[i].file = temp.file;
- inst->src[i].reg = temp.reg;
- inst->src[i].reg_offset = temp.reg_offset;
- inst->src[i].reladdr = NULL;
+ emit_pull_constant_load(block, inst, temp, inst->src[i],
+ pull_constant_loc[uniform]);
+
+ inst->src[i].file = temp.file;
+ inst->src[i].reg = temp.reg;
+ inst->src[i].reg_offset = temp.reg_offset;
+ inst->src[i].reladdr = NULL;
+ }
}
- }
+ } while (nested_reladdr);
/* Now there are no accesses of the UNIFORM file with a reladdr, so
* no need to track them as larger-than-vec4 objects. This will be
*reg = temp;
}
+/**
+ * Resolve the result of a Gen4-5 CMP instruction to a proper boolean.
+ *
+ * CMP on Gen4-5 only sets the LSB of the result; the rest are undefined.
+ * If we need a proper boolean value, we have to fix it up to be 0 or ~0.
+ */
+void
+vec4_visitor::resolve_bool_comparison(ir_rvalue *rvalue, src_reg *reg)
+{
+ assert(brw->gen <= 5);
+
+ if (!rvalue->type->is_boolean())
+ return;
+
+ src_reg and_result = src_reg(this, rvalue->type);
+ src_reg neg_result = src_reg(this, rvalue->type);
+ emit(AND(dst_reg(and_result), *reg, src_reg(1)));
+ emit(MOV(dst_reg(neg_result), negate(and_result)));
+ *reg = neg_result;
+}
+
vec4_visitor::vec4_visitor(struct brw_context *brw,
struct brw_vec4_compile *c,
struct gl_program *prog,
- const struct brw_vec4_prog_key *key,
- struct brw_vec4_prog_data *prog_data,
+ const struct brw_vue_prog_key *key,
+ struct brw_vue_prog_data *prog_data,
struct gl_shader_program *shader_prog,
gl_shader_stage stage,
void *mem_ctx,
- bool debug_flag,
bool no_spills,
shader_time_shader_type st_base,
shader_time_shader_type st_written,
fail_msg(NULL),
first_non_payload_grf(0),
need_all_constants_in_pull_buffer(false),
- debug_flag(debug_flag),
no_spills(no_spills),
st_base(st_base),
st_written(st_written),
this->virtual_grf_start = NULL;
this->virtual_grf_end = NULL;
- this->virtual_grf_sizes = NULL;
- this->virtual_grf_count = 0;
- this->virtual_grf_reg_map = NULL;
- this->virtual_grf_reg_count = 0;
- this->virtual_grf_array_size = 0;
- this->live_intervals_valid = false;
+ this->live_intervals = NULL;
this->max_grf = brw->gen >= 7 ? GEN7_MRF_HACK_START : BRW_MAX_GRF;
va_start(va, format);
msg = ralloc_vasprintf(mem_ctx, format, va);
va_end(va);
- msg = ralloc_asprintf(mem_ctx, "vec4 compile failed: %s\n", msg);
+ msg = ralloc_asprintf(mem_ctx, "%s compile failed: %s\n", stage_abbrev, msg);
this->fail_msg = msg;
- if (debug_flag) {
+ if (debug_enabled) {
fprintf(stderr, "%s", msg);
}
}