glsl: Reinstate constant-folding for division by zero
authorChad Versace <chad.versace@intel.com>
Mon, 14 Feb 2011 21:22:39 +0000 (13:22 -0800)
committerChad Versace <chad.versace@intel.com>
Tue, 15 Feb 2011 23:46:12 +0000 (15:46 -0800)
Fixes regression: https://bugs.freedesktop.org/show_bug.cgi?id=34160

Commit e7c1f058d18f62aa4871aec623f994d7b68cb8c1 disabled constant-folding
when division-by-zero occured. This was a mistake, because the spec does
allow division by zero. (From section 5.9 of the GLSL 1.20 spec: Dividing
by zero does not cause an exception but does result in an unspecified
value.)

For floating-point division, the original pre-e7c1f05 behavior is
reinstated.

For integer division, constant-fold 1/0 to 0.

src/glsl/ir_constant_expression.cpp

index 7e00db66eec1a7699f3a04d0bc3033158d836174..2a3084896569eaecb9ee734ad6698d53cc15661b 100644 (file)
@@ -310,13 +310,9 @@ ir_expression::constant_expression_value()
       break;
 
    case ir_unop_rsq:
-      /* FINISHME: Emit warning when division-by-zero is detected. */
       assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
       for (unsigned c = 0; c < op[0]->type->components(); c++) {
-        float s = sqrtf(op[0]->value.f[c]);
-        if (s == 0)
-           return NULL;
-        data.f[c] = 1.0F / s;
+        data.f[c] = 1.0F / sqrtf(op[0]->value.f[c]);
       }
       break;
 
@@ -519,18 +515,20 @@ ir_expression::constant_expression_value()
 
         switch (op[0]->type->base_type) {
         case GLSL_TYPE_UINT:
-           if (op[1]->value.u[c1] == 0)
-              return NULL;
-           data.u[c] = op[0]->value.u[c0] / op[1]->value.u[c1];
+           if (op[1]->value.u[c1] == 0) {
+              data.u[c] = 0;
+           } else {
+              data.u[c] = op[0]->value.u[c0] / op[1]->value.u[c1];
+           }
            break;
         case GLSL_TYPE_INT:
-           if (op[1]->value.i[c1] == 0)
-              return NULL;
-           data.i[c] = op[0]->value.i[c0] / op[1]->value.i[c1];
+           if (op[1]->value.i[c1] == 0) {
+              data.i[c] = 0;
+           } else {
+              data.i[c] = op[0]->value.i[c0] / op[1]->value.i[c1];
+           }
            break;
         case GLSL_TYPE_FLOAT:
-           if (op[1]->value.f[c1] == 0)
-              return NULL;
            data.f[c] = op[0]->value.f[c0] / op[1]->value.f[c1];
            break;
         default:
@@ -548,18 +546,20 @@ ir_expression::constant_expression_value()
 
         switch (op[0]->type->base_type) {
         case GLSL_TYPE_UINT:
-           if (op[1]->value.u[c1] == 0)
-              return NULL;
-           data.u[c] = op[0]->value.u[c0] % op[1]->value.u[c1];
+           if (op[1]->value.u[c1] == 0) {
+              data.u[c] = 0;
+           } else {
+              data.u[c] = op[0]->value.u[c0] % op[1]->value.u[c1];
+           }
            break;
         case GLSL_TYPE_INT:
-           if (op[1]->value.i[c1] == 0)
-              return NULL;
-           data.i[c] = op[0]->value.i[c0] % op[1]->value.i[c1];
+           if (op[1]->value.i[c1] == 0) {
+              data.i[c] = 0;
+           } else {
+              data.i[c] = op[0]->value.i[c0] % op[1]->value.i[c1];
+           }
            break;
         case GLSL_TYPE_FLOAT:
-           if (op[1]->value.f[c1] == 0)
-              return NULL;
            /* We don't use fmod because it rounds toward zero; GLSL specifies
             * the use of floor.
             */