vtn: Fix Modf.
authorKenneth Graunke <kenneth@whitecape.org>
Wed, 27 Jan 2016 22:20:47 +0000 (14:20 -0800)
committerKenneth Graunke <kenneth@whitecape.org>
Wed, 27 Jan 2016 22:21:08 +0000 (14:21 -0800)
We were botching this for negative numbers - floor of a negative rounds
the wrong way.  Additionally, both results are supposed to retain the
sign of the original.

To fix this, just take the abs of both values, then put the sign back.
There's probably a better way to do this, but this works for now.

src/glsl/nir/spirv/vtn_glsl450.c

index 515a743fe485a9f111ddd4cac0c9dc4243f1c950..b98ef052cbf8db49623ae4cccec7efadc8bd6883 100644 (file)
@@ -418,16 +418,20 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSLstd450 entrypoint,
    case GLSLstd450InverseSqrt: op = nir_op_frsq;       break;
 
    case GLSLstd450Modf: {
-      val->ssa->def = nir_ffract(nb, src[0]);
+      nir_ssa_def *sign = nir_fsign(nb, src[0]);
+      nir_ssa_def *abs = nir_fabs(nb, src[0]);
+      val->ssa->def = nir_fmul(nb, sign, nir_ffract(nb, abs));
       nir_store_deref_var(nb, vtn_nir_deref(b, w[6]),
-                          nir_ffloor(nb, src[0]), 0xf);
+                          nir_fmul(nb, sign, nir_ffloor(nb, abs)), 0xf);
       return;
    }
 
    case GLSLstd450ModfStruct: {
+      nir_ssa_def *sign = nir_fsign(nb, src[0]);
+      nir_ssa_def *abs = nir_fabs(nb, src[0]);
       assert(glsl_type_is_struct(val->ssa->type));
-      val->ssa->elems[0]->def = nir_ffract(nb, src[0]);
-      val->ssa->elems[1]->def = nir_ffloor(nb, src[0]);
+      val->ssa->elems[0]->def = nir_fmul(nb, sign, nir_ffract(nb, abs));
+      val->ssa->elems[1]->def = nir_fmul(nb, sign, nir_ffloor(nb, abs));
       return;
    }