summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/glsl/ir_optimization.h5
-rw-r--r--src/glsl/lower_instructions.cpp26
-rw-r--r--src/mesa/main/mtypes.h1
-rw-r--r--src/mesa/program/ir_to_mesa.cpp5
4 files changed, 33 insertions, 4 deletions
diff --git a/src/glsl/ir_optimization.h b/src/glsl/ir_optimization.h
index 1048ff982e..f264265f4b 100644
--- a/src/glsl/ir_optimization.h
+++ b/src/glsl/ir_optimization.h
@@ -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);
diff --git a/src/glsl/lower_instructions.cpp b/src/glsl/lower_instructions.cpp
index 0d9374d73b..a5f61f213d 100644
--- a/src/glsl/lower_instructions.cpp
+++ b/src/glsl/lower_instructions.cpp
@@ -33,6 +33,7 @@
* - SUB_TO_ADD_NEG
* - DIV_TO_MUL_RCP
* - EXP_TO_EXP2
+ * - POW_TO_EXP2
* - LOG_TO_LOG2
* - MOD_TO_FRACT
*
@@ -61,6 +62,11 @@
* 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 *);
};
@@ -181,6 +188,20 @@ lower_instructions_visitor::exp_to_exp2(ir_expression *ir)
}
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)
{
ir->operation = ir_binop_mul;
@@ -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;
}
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 80c20e09d9..82495714f2 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -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.
diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp
index d9d86b6c29..b274a961b2 100644
--- a/src/mesa/program/ir_to_mesa.cpp
+++ b/src/mesa/program/ir_to_mesa.cpp
@@ -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;