i965: Handle negated unsigned immediate values in constant propagation.

Negation of UD/UW sources behaves the same as for D/W sources, taking
the two's complement of the source, except for bitwise logical
operations on Gen8 and up which take the one's complement.  Fixes
crash in a GLSL shader with subtraction of two unsigned values.

Reviewed-by: Matt Turner <mattst88@gmail.com>
This commit is contained in:
Francisco Jerez 2015-02-06 14:38:20 +02:00
parent 64fde7b31c
commit aef83957e1
3 changed files with 19 additions and 19 deletions

View file

@ -453,13 +453,15 @@ fs_visitor::try_constant_propagate(fs_inst *inst, acp_entry *entry)
val.type = inst->src[i].type; val.type = inst->src[i].type;
if (inst->src[i].abs) { if (inst->src[i].abs) {
if (!brw_abs_immediate(val.type, &val.fixed_hw_reg)) { if ((brw->gen >= 8 && is_logic_op(inst->opcode)) ||
!brw_abs_immediate(val.type, &val.fixed_hw_reg)) {
continue; continue;
} }
} }
if (inst->src[i].negate) { if (inst->src[i].negate) {
if (!brw_negate_immediate(val.type, &val.fixed_hw_reg)) { if ((brw->gen >= 8 && is_logic_op(inst->opcode)) ||
!brw_negate_immediate(val.type, &val.fixed_hw_reg)) {
continue; continue;
} }
} }

View file

@ -625,9 +625,11 @@ brw_negate_immediate(enum brw_reg_type type, struct brw_reg *reg)
{ {
switch (type) { switch (type) {
case BRW_REGISTER_TYPE_D: case BRW_REGISTER_TYPE_D:
case BRW_REGISTER_TYPE_UD:
reg->dw1.d = -reg->dw1.d; reg->dw1.d = -reg->dw1.d;
return true; return true;
case BRW_REGISTER_TYPE_W: case BRW_REGISTER_TYPE_W:
case BRW_REGISTER_TYPE_UW:
reg->dw1.d = -(int16_t)reg->dw1.ud; reg->dw1.d = -(int16_t)reg->dw1.ud;
return true; return true;
case BRW_REGISTER_TYPE_F: case BRW_REGISTER_TYPE_F:
@ -639,12 +641,6 @@ brw_negate_immediate(enum brw_reg_type type, struct brw_reg *reg)
case BRW_REGISTER_TYPE_UB: case BRW_REGISTER_TYPE_UB:
case BRW_REGISTER_TYPE_B: case BRW_REGISTER_TYPE_B:
unreachable("no UB/B immediates"); unreachable("no UB/B immediates");
case BRW_REGISTER_TYPE_UD:
case BRW_REGISTER_TYPE_UW:
/* Presumably the negate modifier on an unsigned source is the same as
* on a signed source but it would be nice to confirm.
*/
assert(!"unimplemented: negate UD/UW immediate");
case BRW_REGISTER_TYPE_UV: case BRW_REGISTER_TYPE_UV:
case BRW_REGISTER_TYPE_V: case BRW_REGISTER_TYPE_V:
assert(!"unimplemented: negate UV/V immediate"); assert(!"unimplemented: negate UV/V immediate");

View file

@ -95,6 +95,15 @@ swizzle_vf_imm(unsigned vf4, unsigned swizzle)
return ret.vf4; return ret.vf4;
} }
static bool
is_logic_op(enum opcode opcode)
{
return (opcode == BRW_OPCODE_AND ||
opcode == BRW_OPCODE_OR ||
opcode == BRW_OPCODE_XOR ||
opcode == BRW_OPCODE_NOT);
}
static bool static bool
try_constant_propagate(struct brw_context *brw, vec4_instruction *inst, try_constant_propagate(struct brw_context *brw, vec4_instruction *inst,
int arg, struct copy_entry *entry) int arg, struct copy_entry *entry)
@ -114,13 +123,15 @@ try_constant_propagate(struct brw_context *brw, vec4_instruction *inst,
return false; return false;
if (inst->src[arg].abs) { if (inst->src[arg].abs) {
if (!brw_abs_immediate(value.type, &value.fixed_hw_reg)) { if ((brw->gen >= 8 && is_logic_op(inst->opcode)) ||
!brw_abs_immediate(value.type, &value.fixed_hw_reg)) {
return false; return false;
} }
} }
if (inst->src[arg].negate) { if (inst->src[arg].negate) {
if (!brw_negate_immediate(value.type, &value.fixed_hw_reg)) { if ((brw->gen >= 8 && is_logic_op(inst->opcode)) ||
!brw_negate_immediate(value.type, &value.fixed_hw_reg)) {
return false; return false;
} }
} }
@ -225,15 +236,6 @@ try_constant_propagate(struct brw_context *brw, vec4_instruction *inst,
return false; return false;
} }
static bool
is_logic_op(enum opcode opcode)
{
return (opcode == BRW_OPCODE_AND ||
opcode == BRW_OPCODE_OR ||
opcode == BRW_OPCODE_XOR ||
opcode == BRW_OPCODE_NOT);
}
static bool static bool
try_copy_propagate(struct brw_context *brw, vec4_instruction *inst, try_copy_propagate(struct brw_context *brw, vec4_instruction *inst,
int arg, struct copy_entry *entry, int reg) int arg, struct copy_entry *entry, int reg)