glsl: Lower ir_binop_pow to a sequence of EXP2 and LOG2
authorIan Romanick <ian.d.romanick@intel.com>
Thu, 25 Nov 2010 06:21:10 +0000 (22:21 -0800)
committerIan Romanick <ian.d.romanick@intel.com>
Wed, 1 Dec 2010 20:01:13 +0000 (12:01 -0800)
src/glsl/ir_optimization.h
src/glsl/lower_instructions.cpp
src/mesa/main/mtypes.h
src/mesa/program/ir_to_mesa.cpp

index 1048ff982e0ebface0b26a87c14c00a8461b8812..f264265f4b14b673dca8f515f9cb2d4e59e5d935 100644 (file)
@@ -32,8 +32,9 @@
 #define SUB_TO_ADD_NEG 0x01
 #define DIV_TO_MUL_RCP 0x02
 #define EXP_TO_EXP2    0x04
-#define LOG_TO_LOG2    0x08
-#define MOD_TO_FRACT   0x10
+#define POW_TO_EXP2    0x08
+#define LOG_TO_LOG2    0x10
+#define MOD_TO_FRACT   0x20
 
 bool do_common_optimization(exec_list *ir, bool linked, unsigned max_unroll_iterations);
 
index 0d9374d73bd74f04cf80a239a07ac44e36391924..a5f61f213d056d8098083bdd2a479c292861b1e7 100644 (file)
@@ -33,6 +33,7 @@
  * - SUB_TO_ADD_NEG
  * - DIV_TO_MUL_RCP
  * - EXP_TO_EXP2
+ * - POW_TO_EXP2
  * - LOG_TO_LOG2
  * - MOD_TO_FRACT
  *
  * do have base 2 versions, so this pass converts exp and log to exp2
  * and log2 operations.
  *
+ * POW_TO_EXP2:
+ * -----------
+ * Many older GPUs don't have an x**y instruction.  For these GPUs, convert
+ * x**y to 2**(y * log2(x)).
+ *
  * MOD_TO_FRACT:
  * -------------
  * Breaks an ir_unop_mod expression down to (op1 * fract(op0 / op1))
@@ -91,6 +97,7 @@ private:
    void div_to_mul_rcp(ir_expression *);
    void mod_to_fract(ir_expression *);
    void exp_to_exp2(ir_expression *);
+   void pow_to_exp2(ir_expression *);
    void log_to_log2(ir_expression *);
 };
 
@@ -180,6 +187,20 @@ lower_instructions_visitor::exp_to_exp2(ir_expression *ir)
    this->progress = true;
 }
 
+void
+lower_instructions_visitor::pow_to_exp2(ir_expression *ir)
+{
+   ir_expression *const log2_x =
+      new(ir) ir_expression(ir_unop_log2, ir->operands[0]->type,
+                           ir->operands[0]);
+
+   ir->operation = ir_unop_exp2;
+   ir->operands[0] = new(ir) ir_expression(ir_binop_mul, ir->operands[1]->type,
+                                          ir->operands[1], log2_x);
+   ir->operands[1] = NULL;
+   this->progress = true;
+}
+
 void
 lower_instructions_visitor::log_to_log2(ir_expression *ir)
 {
@@ -254,6 +275,11 @@ lower_instructions_visitor::visit_leave(ir_expression *ir)
         mod_to_fract(ir);
       break;
 
+   case ir_binop_pow:
+      if (lowering(POW_TO_EXP2))
+        pow_to_exp2(ir);
+      break;
+
    default:
       return visit_continue;
    }
index 80c20e09d9ae92ddb0dddc9f5347a3ef731cb36f..82495714f21e5407465079c4a64446759b44b483 100644 (file)
@@ -2197,6 +2197,7 @@ struct gl_shader_compiler_options
    GLboolean EmitNoCont;                  /**< Emit CONT opcode? */
    GLboolean EmitNoMainReturn;            /**< Emit CONT/RET opcodes? */
    GLboolean EmitNoNoise;                 /**< Emit NOISE opcodes? */
+   GLboolean EmitNoPow;                   /**< Emit POW opcodes? */
 
    /**
     * \name Forms of indirect addressing the driver cannot do.
index d9d86b6c29fccfc3925ea8e4013876e50c501bca..b274a961b28db5053f2563fcca437dada28e8231 100644 (file)
@@ -2849,8 +2849,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;