llvmpipe: Generate instrinsics for integer comparisons.
authorJosé Fonseca <jfonseca@vmware.com>
Thu, 20 Aug 2009 19:17:55 +0000 (20:17 +0100)
committerJosé Fonseca <jfonseca@vmware.com>
Sat, 29 Aug 2009 08:21:37 +0000 (09:21 +0100)
It is a little messy, given the available instrucions form SIMD
integer comparisons is rather limited.

src/gallium/drivers/llvmpipe/lp_bld_logic.c

index 95d7f8c5ba41afc509239949a27423f08b8bd0e4..5b8efb05778a8249564537fa12efe011e4f7f146 100644 (file)
@@ -107,6 +107,77 @@ lp_build_cmp(struct lp_build_context *bld,
          res = LLVMBuildBitCast(bld->builder, res, int_vec_type, "");
          return res;
       }
+      else {
+         static const struct {
+            unsigned swap:1;
+            unsigned eq:1;
+            unsigned gt:1;
+            unsigned not:1;
+         } table[] = {
+            {0, 0, 0, 1}, /* PIPE_FUNC_NEVER */
+            {1, 0, 1, 0}, /* PIPE_FUNC_LESS */
+            {0, 1, 0, 0}, /* PIPE_FUNC_EQUAL */
+            {0, 0, 1, 1}, /* PIPE_FUNC_LEQUAL */
+            {0, 0, 1, 0}, /* PIPE_FUNC_GREATER */
+            {0, 1, 0, 1}, /* PIPE_FUNC_NOTEQUAL */
+            {1, 0, 1, 1}, /* PIPE_FUNC_GEQUAL */
+            {0, 0, 0, 0}  /* PIPE_FUNC_ALWAYS */
+         };
+         const char *pcmpeq;
+         const char *pcmpgt;
+         LLVMValueRef args[2];
+         LLVMValueRef res;
+
+         switch (type.width) {
+         case 8:
+            pcmpeq = "llvm.x86.sse2.pcmpeq.b";
+            pcmpgt = "llvm.x86.sse2.pcmpgt.b";
+            break;
+         case 16:
+            pcmpeq = "llvm.x86.sse2.pcmpeq.w";
+            pcmpgt = "llvm.x86.sse2.pcmpgt.w";
+            break;
+         case 32:
+            pcmpeq = "llvm.x86.sse2.pcmpeq.d";
+            pcmpgt = "llvm.x86.sse2.pcmpgt.d";
+            break;
+         default:
+            assert(0);
+            return bld->undef;
+         }
+
+         /* There are no signed byte and unsigned word/dword comparison
+          * instructions. So flip the sign bit so that the results match.
+          */
+         if(table[func].gt &&
+            ((type.width == 8 && type.sign) ||
+             (type.width != 8 && !type.sign))) {
+            LLVMValueRef msb = lp_build_int_const_uni(type, (unsigned long long)1 << (type.width - 1));
+            a = LLVMBuildXor(bld->builder, a, msb, "");
+            b = LLVMBuildXor(bld->builder, b, msb, "");
+         }
+
+         if(table[func].swap) {
+            args[0] = b;
+            args[1] = a;
+         }
+         else {
+            args[0] = a;
+            args[1] = b;
+         }
+
+         if(table[func].eq)
+            res = lp_build_intrinsic(bld->builder, pcmpeq, vec_type, args, 2);
+         else if (table[func].gt)
+            res = lp_build_intrinsic(bld->builder, pcmpgt, vec_type, args, 2);
+         else
+            res = LLVMConstNull(vec_type);
+
+         if(table[func].not)
+            res = LLVMBuildNot(bld->builder, res, "");
+
+         return res;
+      }
    }
 #endif