]> git.rm.cloudns.org Git - xonotic/gmqcc.git/commitdiff
Fix lshift/rshift for runtime and const-fold consistency.
authorDale Weiler <killfieldengine@gmail.com>
Tue, 7 Jan 2014 17:58:53 +0000 (12:58 -0500)
committerDale Weiler <killfieldengine@gmail.com>
Tue, 7 Jan 2014 17:58:53 +0000 (12:58 -0500)
fold.c
intrin.c

diff --git a/fold.c b/fold.c
index dd78beb46044f6b02a9d17233f8ada9197b66f74..173d613abda50068ee7410df74c305e2e76ada38 100644 (file)
--- a/fold.c
+++ b/fold.c
@@ -550,13 +550,13 @@ static GMQCC_INLINE ast_expression *fold_op_xor(fold_t *fold, ast_value *a, ast_
 
 static GMQCC_INLINE ast_expression *fold_op_lshift(fold_t *fold, ast_value *a, ast_value *b) {
     if (fold_can_2(a, b) && isfloats(a, b))
-        return fold_constgen_float(fold, (qcfloat_t)((qcuint_t)(fold_immvalue_float(a)) << (qcuint_t)(fold_immvalue_float(b))));
+        return fold_constgen_float(fold, (qcfloat_t)(((qcuint_t)floorf(fold_immvalue_float(a) * powf(2, fold_immvalue_float(b)))) & 0xFFFFFF));
     return NULL;
 }
 
 static GMQCC_INLINE ast_expression *fold_op_rshift(fold_t *fold, ast_value *a, ast_value *b) {
     if (fold_can_2(a, b) && isfloats(a, b))
-        return fold_constgen_float(fold, (qcfloat_t)((qcuint_t)(fold_immvalue_float(a)) >> (qcuint_t)(fold_immvalue_float(b))));
+        return fold_constgen_float(fold, (qcfloat_t)(((qcuint_t)floorf(fold_immvalue_float(a) / powf(2, fold_immvalue_float(b)))) & 0xFFFFFF));
     return NULL;
 }
 
index 339d0c3f2da3df94ce587056e4622a33f73f5ec1..8c78ba744a17dde3e6b213d9badf5c899e23954c 100644 (file)
--- a/intrin.c
+++ b/intrin.c
@@ -1940,28 +1940,41 @@ static ast_expression *intrin_logb(intrin_t *intrin) {
 }
 
 static ast_expression *intrin_shift_variant(intrin_t *intrin, const char *name, size_t instr) {
-    ast_value    *value    = NULL;
-    ast_call     *callpow  = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "pow", name));
-    ast_value    *a        = ast_value_new(intrin_ctx(intrin), "a", TYPE_FLOAT);
-    ast_value    *b        = ast_value_new(intrin_ctx(intrin), "b", TYPE_FLOAT);
-    ast_block    *body     = ast_block_new(intrin_ctx(intrin));
-    ast_function *func     = intrin_value(intrin, &value, name, TYPE_FLOAT);
+    /*
+     * float [shift] (float a, float b) {
+     *   return floor(a [instr] pow(2, b));
+     */
+    ast_value    *value     = NULL;
+    ast_call     *callpow   = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "pow", name));
+    ast_call     *callfloor = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "floor", name));
+    ast_value    *a         = ast_value_new(intrin_ctx(intrin), "a", TYPE_FLOAT);
+    ast_value    *b         = ast_value_new(intrin_ctx(intrin), "b", TYPE_FLOAT);
+    ast_block    *body      = ast_block_new(intrin_ctx(intrin));
+    ast_function *func      = intrin_value(intrin, &value, name, TYPE_FLOAT);
 
     vec_push(value->expression.params, a);
     vec_push(value->expression.params, b);
 
+    /* <callpow> = pow(2, b) */
     vec_push(callpow->params, (ast_expression*)intrin->fold->imm_float[3]);
     vec_push(callpow->params, (ast_expression*)b);
 
+    /* <callfloor> = floor(a [instr] <callpow>) */
+    vec_push(
+        callfloor->params,
+        (ast_expression*)ast_binary_new(
+            intrin_ctx(intrin),
+            instr,
+            (ast_expression*)a,
+            (ast_expression*)callpow
+        )
+    );
+
+    /* return <callfloor> */
     vec_push(body->exprs,
         (ast_expression*)ast_return_new(
             intrin_ctx(intrin),
-            (ast_expression*)ast_binary_new(
-                intrin_ctx(intrin),
-                instr,
-                (ast_expression*)a,
-                (ast_expression*)callpow
-            )
+            (ast_expression*)callfloor
         )
     );