]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - ir.c
Fix unary negation (-)
[xonotic/gmqcc.git] / ir.c
diff --git a/ir.c b/ir.c
index 00d81c25dbb5ae3334b560f1e01476c1afd8cc31..73cbc9af06abec83170abbf9e3b98c9bb867f28a 100644 (file)
--- a/ir.c
+++ b/ir.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012, 2013, 2014
+ * Copyright (C) 2012, 2013, 2014, 2015
  *     Wolfgang Bumiller
  *     Dale Weiler
  *
@@ -1124,6 +1124,7 @@ ir_value* ir_value_var(const char *name, int storetype, int vtype)
 /*  helper function */
 static ir_value* ir_builder_imm_float(ir_builder *self, float value, bool add_to_list) {
     ir_value *v = ir_value_var("#IMMEDIATE", store_global, TYPE_FLOAT);
+    v->flags |= IR_FLAG_ERASABLE;
     v->hasvalue = true;
     v->cvq = CV_CONST;
     v->constval.vfloat = value;
@@ -1916,6 +1917,9 @@ ir_value* ir_block_create_unary(ir_block *self, lex_ctx_t ctx,
                                 ir_value *operand)
 {
     int ot = TYPE_FLOAT;
+    ir_value *minus_1 = NULL;
+    if (opcode == VINSTR_NEG_F || opcode == VINSTR_NEG_V)
+        minus_1 = ir_builder_imm_float(self->owner->owner, -1.0f, false);
     switch (opcode) {
         case INSTR_NOT_F:
         case INSTR_NOT_V:
@@ -1925,15 +1929,11 @@ ir_value* ir_block_create_unary(ir_block *self, lex_ctx_t ctx,
         case INSTR_NOT_I:   */
             ot = TYPE_FLOAT;
             break;
-
-        /*
-         * Negation for virtual instructions is emulated with 0-value. Thankfully
-         * the operand for 0 already exists so we just source it from here.
-         */
+        /* Negation is implemented as -1 * <operand> */
         case VINSTR_NEG_F:
-            return ir_block_create_general_instr(self, ctx, label, INSTR_SUB_F, NULL, operand, ot);
+            return ir_block_create_general_instr(self, ctx, label, INSTR_MUL_F, minus_1, operand, TYPE_FLOAT);
         case VINSTR_NEG_V:
-            return ir_block_create_general_instr(self, ctx, label, INSTR_SUB_V, NULL, operand, TYPE_VECTOR);
+            return ir_block_create_general_instr(self, ctx, label, INSTR_MUL_FV, minus_1, operand, TYPE_VECTOR);
 
         default:
             ot = operand->vtype;
@@ -3580,7 +3580,7 @@ static bool gen_global_function_code(ir_builder *ir, ir_value *global)
      * If there is no definition and the thing is eraseable, we can ignore
      * outputting the function to begin with.
      */
-    if (global->flags & IR_FLAG_ERASEABLE && irfun->code_function_def < 0) {
+    if (global->flags & IR_FLAG_ERASABLE && irfun->code_function_def < 0) {
         return true;
     }
 
@@ -3692,7 +3692,7 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool isloc
          * if we're eraseable and the function isn't referenced ignore outputting
          * the function.
          */
-        if (global->flags & IR_FLAG_ERASEABLE && vec_size(global->reads) == 0) {
+        if (global->flags & IR_FLAG_ERASABLE && vec_size(global->reads) == 0) {
             return true;
         }
 
@@ -3771,6 +3771,8 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool isloc
     {
         ir_value_code_setaddr(global, vec_size(self->code->globals));
         if (global->hasvalue) {
+            if (global->cvq == CV_CONST && !vec_size(global->reads))
+                return true;
             iptr = (int32_t*)&global->constval.ivec[0];
             vec_push(self->code->globals, *iptr);
         } else {
@@ -3786,7 +3788,10 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool isloc
     {
         ir_value_code_setaddr(global, vec_size(self->code->globals));
         if (global->hasvalue) {
-            uint32_t load = code_genstring(self->code, global->constval.vstring);
+            uint32_t load;
+            if (global->cvq == CV_CONST && !vec_size(global->reads))
+                return true;
+            load = code_genstring(self->code, global->constval.vstring);
             vec_push(self->code->globals, load);
         } else {
             vec_push(self->code->globals, 0);