i965/vec4: implement fsign() for doubles

v2: use a MOV with a conditional_mod instead of a CMP, like we do in d2b, to skip
    loading a double immediate.

v3: Fix comment (Matt)

Reviewed-by: Matt Turner <mattst88@gmail.com>
This commit is contained in:
Iago Toral Quiroga 2016-02-05 10:12:57 +01:00 committed by Samuel Iglesias Gonsálvez
parent 6e570619e0
commit 1816ae8f68
1 changed files with 49 additions and 15 deletions

View File

@ -1769,24 +1769,58 @@ vec4_visitor::nir_emit_alu(nir_alu_instr *instr)
unreachable("not reached: should have been lowered");
case nir_op_fsign:
/* AND(val, 0x80000000) gives the sign bit.
*
* Predicated OR ORs 1.0 (0x3f800000) with the sign bit if val is not
* zero.
*/
emit(CMP(dst_null_f(), op[0], brw_imm_f(0.0f), BRW_CONDITIONAL_NZ));
if (type_sz(op[0].type) < 8) {
/* AND(val, 0x80000000) gives the sign bit.
*
* Predicated OR ORs 1.0 (0x3f800000) with the sign bit if val is not
* zero.
*/
emit(CMP(dst_null_f(), op[0], brw_imm_f(0.0f), BRW_CONDITIONAL_NZ));
op[0].type = BRW_REGISTER_TYPE_UD;
dst.type = BRW_REGISTER_TYPE_UD;
emit(AND(dst, op[0], brw_imm_ud(0x80000000u)));
op[0].type = BRW_REGISTER_TYPE_UD;
dst.type = BRW_REGISTER_TYPE_UD;
emit(AND(dst, op[0], brw_imm_ud(0x80000000u)));
inst = emit(OR(dst, src_reg(dst), brw_imm_ud(0x3f800000u)));
inst->predicate = BRW_PREDICATE_NORMAL;
dst.type = BRW_REGISTER_TYPE_F;
inst = emit(OR(dst, src_reg(dst), brw_imm_ud(0x3f800000u)));
inst->predicate = BRW_PREDICATE_NORMAL;
dst.type = BRW_REGISTER_TYPE_F;
if (instr->dest.saturate) {
inst = emit(MOV(dst, src_reg(dst)));
inst->saturate = true;
if (instr->dest.saturate) {
inst = emit(MOV(dst, src_reg(dst)));
inst->saturate = true;
}
} else {
/* For doubles we do the same but we need to consider:
*
* - We use a MOV with conditional_mod instead of a CMP so that we can
* skip loading a 0.0 immediate. We use a source modifier on the
* source of the MOV so that we flush denormalized values to 0.
* Since we want to compare against 0, this won't alter the result.
* - We need to extract the high 32-bit of each DF where the sign
* is stored.
* - We need to produce a DF result.
*/
/* Check for zero */
src_reg value = op[0];
value.abs = true;
inst = emit(MOV(dst_null_df(), value));
inst->conditional_mod = BRW_CONDITIONAL_NZ;
/* AND each high 32-bit channel with 0x80000000u */
dst_reg tmp = dst_reg(this, glsl_type::uvec4_type);
emit(VEC4_OPCODE_PICK_HIGH_32BIT, tmp, op[0]);
emit(AND(tmp, src_reg(tmp), brw_imm_ud(0x80000000u)));
/* Add 1.0 to each channel, predicated to skip the cases where the
* channel's value was 0
*/
inst = emit(OR(tmp, src_reg(tmp), brw_imm_ud(0x3f800000u)));
inst->predicate = BRW_PREDICATE_NORMAL;
/* Now convert the result from float to double */
emit_conversion_to_double(dst, src_reg(tmp), instr->dest.saturate,
BRW_REGISTER_TYPE_F);
}
break;