summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@gmail.com>2014-08-14 20:21:46 +1000
committerTopi Pohjolainen <topi.pohjolainen@intel.com>2014-11-11 11:15:01 +0200
commit835d6f5880252dc99ec1d2dc60f21c27aa06ef75 (patch)
treeed7355bf0d06f9841182c57c1bee75d619d49e31
parente8c99e39961e6359a29bf5178df97e14b2d4f23e (diff)
downloadmesa-835d6f5880252dc99ec1d2dc60f21c27aa06ef75.tar.gz
glsl: lower double optional passes
These lowering passes are optional for the backend to request, currently the TGSI softpipe backend most likely the r600g backend would want to use these passes as is. They aim to hit the gallium opcodes from the standard rounding/truncation functions. Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--src/glsl/ir_optimization.h1
-rw-r--r--src/glsl/lower_instructions.cpp210
2 files changed, 211 insertions, 0 deletions
diff --git a/src/glsl/ir_optimization.h b/src/glsl/ir_optimization.h
index e25857ac579..ca49d1e9029 100644
--- a/src/glsl/ir_optimization.h
+++ b/src/glsl/ir_optimization.h
@@ -41,6 +41,7 @@
#define CARRY_TO_ARITH 0x200
#define BORROW_TO_ARITH 0x400
#define SAT_TO_CLAMP 0x800
+#define DOPS_TO_DFRAC 0x800
/**
* \see class lower_packing_builtins_visitor
diff --git a/src/glsl/lower_instructions.cpp b/src/glsl/lower_instructions.cpp
index 556b60727fd..64fe9647cc2 100644
--- a/src/glsl/lower_instructions.cpp
+++ b/src/glsl/lower_instructions.cpp
@@ -42,6 +42,7 @@
* - CARRY_TO_ARITH
* - BORROW_TO_ARITH
* - SAT_TO_CLAMP
+ * - DOPS_TO_DFRAC
*
* SUB_TO_ADD_NEG:
* ---------------
@@ -109,6 +110,9 @@
* -------------
* Converts ir_unop_saturate into min(max(x, 0.0), 1.0)
*
+ * DOPS_TO_DFRAC:
+ * --------------
+ * Converts double trunc, ceil, floor, round to fract
*/
#include "main/core.h" /* for M_LOG2E */
@@ -148,6 +152,11 @@ private:
void sat_to_clamp(ir_expression *);
void double_dot_to_fma(ir_expression *);
void double_lrp(ir_expression *);
+ void dceil_to_dfrac(ir_expression *);
+ void dfloor_to_dfrac(ir_expression *);
+ void dround_even_to_dfrac(ir_expression *);
+ void dtrunc_to_dfrac(ir_expression *);
+ void dsign_to_csel(ir_expression *);
};
} /* anonymous namespace */
@@ -583,6 +592,182 @@ lower_instructions_visitor::double_lrp(ir_expression *ir)
this->progress = true;
}
+void
+lower_instructions_visitor::dceil_to_dfrac(ir_expression *ir)
+{
+ /*
+ * frtemp = frac(x);
+ * temp = sub(x, frtemp);
+ * result = temp + ((frtemp != 0.0) ? 1.0 : 0.0);
+ */
+ ir_instruction &i = *base_ir;
+ ir_constant *zero = new(ir) ir_constant(0.0, ir->operands[0]->type->vector_elements);
+ ir_constant *one = new(ir) ir_constant(1.0, ir->operands[0]->type->vector_elements);
+ ir_variable *frtemp = new(ir) ir_variable(ir->operands[0]->type, "frtemp",
+ ir_var_temporary);
+ ir_variable *temp = new(ir) ir_variable(ir->operands[0]->type, "temp",
+ ir_var_temporary);
+ ir_variable *t2 = new(ir) ir_variable(ir->operands[0]->type, "t2",
+ ir_var_temporary);
+
+ i.insert_before(frtemp);
+ i.insert_before(assign(frtemp, fract(ir->operands[0])));
+
+ i.insert_before(temp);
+ i.insert_before(assign(temp, sub(ir->operands[0]->clone(ir, NULL), frtemp)));
+
+ i.insert_before(t2);
+ i.insert_before(assign(t2, csel(nequal(frtemp, zero), one, zero->clone(ir, NULL))));
+ ir->operation = ir_binop_add;
+ ir->operands[0] = new(ir) ir_dereference_variable(temp);
+ ir->operands[1] = new(ir) ir_dereference_variable(t2);
+}
+
+void
+lower_instructions_visitor::dfloor_to_dfrac(ir_expression *ir)
+{
+ /*
+ * frtemp = frac(x);
+ * result = sub(x, frtemp);
+ */
+ ir_instruction &i = *base_ir;
+ ir_variable *frtemp = new(ir) ir_variable(ir->operands[0]->type, "frtemp",
+ ir_var_temporary);
+
+ i.insert_before(frtemp);
+ i.insert_before(assign(frtemp, fract(ir->operands[0]->clone(ir, NULL))));
+
+ ir->operation = ir_binop_sub;
+ ir->operands[1] = new(ir) ir_dereference_variable(frtemp);
+}
+void
+lower_instructions_visitor::dround_even_to_dfrac(ir_expression *ir)
+{
+ /*
+ * insane but works
+ * temp = x + 0.5;
+ * frtemp = frac(temp);
+ * t2 = sub(temp, frtemp);
+ * if (frac(x) == 0.5)
+ * result = frac(t2 * 0.5) == 0 ? t2 : t2 - 1;
+ * else
+ * result = t2;
+
+ */
+ const unsigned vec_elem = ir->type->vector_elements;
+ const glsl_type *bvec = glsl_type::get_instance(GLSL_TYPE_BOOL, vec_elem, 1);
+ ir_instruction &i = *base_ir;
+ ir_variable *frtemp = new(ir) ir_variable(ir->operands[0]->type, "frtemp",
+ ir_var_temporary);
+ ir_variable *temp = new(ir) ir_variable(ir->operands[0]->type, "temp",
+ ir_var_temporary);
+ ir_variable *t2 = new(ir) ir_variable(ir->operands[0]->type, "t2",
+ ir_var_temporary);
+ ir_variable *t3 = new(ir) ir_variable(bvec, "t3",
+ ir_var_temporary);
+ ir_variable *t4 = new(ir) ir_variable(bvec, "t4",
+ ir_var_temporary);
+ ir_variable *t5 = new(ir) ir_variable(ir->operands[0]->type, "t5",
+ ir_var_temporary);
+ ir_constant *p5 = new(ir) ir_constant(0.5, ir->operands[0]->type->vector_elements);
+ ir_constant *one = new(ir) ir_constant(1.0, ir->operands[0]->type->vector_elements);
+ ir_constant *zero = new(ir) ir_constant(0.0, ir->operands[0]->type->vector_elements);
+
+ i.insert_before(temp);
+ i.insert_before(assign(temp, add(ir->operands[0], p5)));
+
+ i.insert_before(frtemp);
+ i.insert_before(assign(frtemp, fract(temp)));
+
+ i.insert_before(t2);
+ i.insert_before(assign(t2, sub(temp, frtemp)));
+
+ i.insert_before(t3);
+ i.insert_before(assign(t3, equal(fract(ir->operands[0]->clone(ir, NULL)), p5->clone(ir, NULL))));
+
+ i.insert_before(t4);
+ i.insert_before(assign(t4, equal(fract(mul(t2, p5->clone(ir, NULL))), zero)));
+
+ i.insert_before(t5);
+ i.insert_before(assign(t5, csel(t4, t2, sub(t2, one))));
+
+ ir->operation = ir_triop_csel;
+ ir->operands[0] = new(ir) ir_dereference_variable(t3);
+ ir->operands[1] = new(ir) ir_dereference_variable(t5);
+ ir->operands[2] = new(ir) ir_dereference_variable(t2);
+}
+
+void
+lower_instructions_visitor::dtrunc_to_dfrac(ir_expression *ir)
+{
+ /*
+ * frtemp = frac(x);
+ * temp = sub(x, frtemp);
+ * if (x >= 0)
+ * result = temp;
+ * else
+ * result = temp + (frtemp == 0.0) ? 0 : 1;
+ */
+ const unsigned vec_elem = ir->type->vector_elements;
+ const glsl_type *bvec = glsl_type::get_instance(GLSL_TYPE_BOOL, vec_elem, 1);
+ ir_instruction &i = *base_ir;
+
+ ir_constant *zero = new(ir) ir_constant(0.0, ir->operands[0]->type->vector_elements);
+ ir_constant *one = new(ir) ir_constant(1.0, ir->operands[0]->type->vector_elements);
+ ir_variable *frtemp = new(ir) ir_variable(ir->operands[0]->type, "frtemp",
+ ir_var_temporary);
+ ir_variable *temp = new(ir) ir_variable(ir->operands[0]->type, "temp",
+ ir_var_temporary);
+ ir_variable *t2 = new(ir) ir_variable(bvec, "t2",
+ ir_var_temporary);
+ ir_variable *t3 = new(ir) ir_variable(ir->operands[0]->type, "t3",
+ ir_var_temporary);
+
+ i.insert_before(frtemp);
+ i.insert_before(assign(frtemp, fract(ir->operands[0])));
+ i.insert_before(temp);
+ i.insert_before(assign(temp, sub(ir->operands[0]->clone(ir, NULL), frtemp)));
+
+ i.insert_before(t2);
+ i.insert_before(assign(t2, less(ir->operands[0]->clone(ir, NULL), zero)));
+
+ i.insert_before(t3);
+ i.insert_before(assign(t3, add(temp, csel(equal(frtemp, zero->clone(ir, NULL)), zero->clone(ir, NULL), one))));
+
+ ir->operation = ir_triop_csel;
+ ir->operands[0] = new(ir) ir_dereference_variable(t2);
+ ir->operands[1] = new(ir) ir_dereference_variable(t3);
+ ir->operands[2] = new(ir) ir_dereference_variable(temp);
+
+ this->progress = true;
+}
+
+void
+lower_instructions_visitor::dsign_to_csel(ir_expression *ir)
+{
+ /*
+ * temp = x > 0.0 ? 1.0 : 0.0;
+ * result = x < 0.0 ? -1.0 : temp;
+ */
+ ir_instruction &i = *base_ir;
+ ir_variable *temp = new(ir) ir_variable(ir->operands[0]->type, "temp",
+ ir_var_temporary);
+ ir_constant *zero = new(ir) ir_constant(0.0, ir->operands[0]->type->vector_elements);
+ ir_constant *one = new(ir) ir_constant(1.0, ir->operands[0]->type->vector_elements);
+ ir_constant *negone = new(ir) ir_constant(-1.0, ir->operands[0]->type->vector_elements);
+ ir_variable *t2 = new(ir) ir_variable(ir->operands[0]->type, "t2",
+ ir_var_temporary);
+ i.insert_before(temp);
+ i.insert_before(assign(temp, csel(greater(ir->operands[0], zero), one, zero->clone(ir, NULL))));
+
+ i.insert_before(t2);
+ i.insert_before(assign(t2, less(ir->operands[0]->clone(ir, NULL), zero->clone(ir, NULL))));
+ ir->operation = ir_triop_csel;
+ ir->operands[0] = new(ir) ir_dereference_variable(t2);
+ ir->operands[1] = negone;
+ ir->operands[2] = new(ir) ir_dereference_variable(temp);
+}
+
ir_visitor_status
lower_instructions_visitor::visit_leave(ir_expression *ir)
{
@@ -652,6 +837,31 @@ lower_instructions_visitor::visit_leave(ir_expression *ir)
sat_to_clamp(ir);
break;
+ case ir_unop_trunc:
+ if (lowering(DOPS_TO_DFRAC) && ir->type->is_double())
+ dtrunc_to_dfrac(ir);
+ break;
+
+ case ir_unop_ceil:
+ if (lowering(DOPS_TO_DFRAC) && ir->type->is_double())
+ dceil_to_dfrac(ir);
+ break;
+
+ case ir_unop_floor:
+ if (lowering(DOPS_TO_DFRAC) && ir->type->is_double())
+ dfloor_to_dfrac(ir);
+ break;
+
+ case ir_unop_round_even:
+ if (lowering(DOPS_TO_DFRAC) && ir->type->is_double())
+ dround_even_to_dfrac(ir);
+ break;
+
+ case ir_unop_sign:
+ if (lowering(DOPS_TO_DFRAC) && ir->type->is_double())
+ dsign_to_csel(ir);
+ break;
+
default:
return visit_continue;
}