freedreno/ir3: array rework
[mesa.git] / src / gallium / auxiliary / gallivm / lp_bld_gather.c
index d60472e06567385f324a70a73f4d0616f8af7488..d02602041ce13c9722e9be2b7721d879ffe0fc57 100644 (file)
@@ -31,6 +31,8 @@
 #include "lp_bld_const.h"
 #include "lp_bld_format.h"
 #include "lp_bld_gather.h"
+#include "lp_bld_init.h"
+#include "lp_bld_intr.h"
 
 
 /**
@@ -39,7 +41,7 @@
  * @sa lp_build_gather()
  */
 LLVMValueRef
-lp_build_gather_elem_ptr(LLVMBuilderRef builder,
+lp_build_gather_elem_ptr(struct gallivm_state *gallivm,
                          unsigned length,
                          LLVMValueRef base_ptr,
                          LLVMValueRef offsets,
@@ -48,17 +50,17 @@ lp_build_gather_elem_ptr(LLVMBuilderRef builder,
    LLVMValueRef offset;
    LLVMValueRef ptr;
 
-   assert(LLVMTypeOf(base_ptr) == LLVMPointerType(LLVMInt8Type(), 0));
+   assert(LLVMTypeOf(base_ptr) == LLVMPointerType(LLVMInt8TypeInContext(gallivm->context), 0));
 
    if (length == 1) {
       assert(i == 0);
       offset = offsets;
    } else {
-      LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
-      offset = LLVMBuildExtractElement(builder, offsets, index, "");
+      LLVMValueRef index = lp_build_const_int32(gallivm, i);
+      offset = LLVMBuildExtractElement(gallivm->builder, offsets, index, "");
    }
 
-   ptr = LLVMBuildGEP(builder, base_ptr, &offset, 1, "");
+   ptr = LLVMBuildGEP(gallivm->builder, base_ptr, &offset, 1, "");
 
    return ptr;
 }
@@ -70,31 +72,61 @@ lp_build_gather_elem_ptr(LLVMBuilderRef builder,
  * @sa lp_build_gather()
  */
 LLVMValueRef
-lp_build_gather_elem(LLVMBuilderRef builder,
+lp_build_gather_elem(struct gallivm_state *gallivm,
                      unsigned length,
                      unsigned src_width,
                      unsigned dst_width,
+                     boolean aligned,
                      LLVMValueRef base_ptr,
                      LLVMValueRef offsets,
-                     unsigned i)
+                     unsigned i,
+                     boolean vector_justify)
 {
-   LLVMTypeRef src_type = LLVMIntType(src_width);
+   LLVMTypeRef src_type = LLVMIntTypeInContext(gallivm->context, src_width);
    LLVMTypeRef src_ptr_type = LLVMPointerType(src_type, 0);
-   LLVMTypeRef dst_elem_type = LLVMIntType(dst_width);
+   LLVMTypeRef dst_elem_type = LLVMIntTypeInContext(gallivm->context, dst_width);
    LLVMValueRef ptr;
    LLVMValueRef res;
 
-   assert(LLVMTypeOf(base_ptr) == LLVMPointerType(LLVMInt8Type(), 0));
-
-   ptr = lp_build_gather_elem_ptr(builder, length, base_ptr, offsets, i);
-   ptr = LLVMBuildBitCast(builder, ptr, src_ptr_type, "");
-   res = LLVMBuildLoad(builder, ptr, "");
+   assert(LLVMTypeOf(base_ptr) == LLVMPointerType(LLVMInt8TypeInContext(gallivm->context), 0));
+
+   ptr = lp_build_gather_elem_ptr(gallivm, length, base_ptr, offsets, i);
+   ptr = LLVMBuildBitCast(gallivm->builder, ptr, src_ptr_type, "");
+   res = LLVMBuildLoad(gallivm->builder, ptr, "");
+
+   /* XXX
+    * On some archs we probably really want to avoid having to deal
+    * with alignments lower than 4 bytes (if fetch size is a power of
+    * two >= 32). On x86 it doesn't matter, however.
+    * We should be able to guarantee full alignment for any kind of texture
+    * fetch (except ARB_texture_buffer_range, oops), but not vertex fetch
+    * (there's PIPE_CAP_VERTEX_BUFFER_OFFSET_4BYTE_ALIGNED_ONLY and friends
+    * but I don't think that's quite what we wanted).
+    * For ARB_texture_buffer_range, PIPE_CAP_TEXTURE_BUFFER_OFFSET_ALIGNMENT
+    * looks like a good fit, but it seems this cap bit (and OpenGL) aren't
+    * enforcing what we want (which is what d3d10 does, the offset needs to
+    * be aligned to element size, but GL has bytes regardless of element
+    * size which would only leave us with minimum alignment restriction of 16
+    * which doesn't make much sense if the type isn't 4x32bit). Due to
+    * translation of offsets to first_elem in sampler_views it actually seems
+    * gallium could not do anything else except 16 no matter what...
+    */
+  if (!aligned) {
+      lp_set_load_alignment(res, 1);
+   }
 
    assert(src_width <= dst_width);
-   if (src_width > dst_width)
-      res = LLVMBuildTrunc(builder, res, dst_elem_type, "");
-   if (src_width < dst_width)
-      res = LLVMBuildZExt(builder, res, dst_elem_type, "");
+   if (src_width > dst_width) {
+      res = LLVMBuildTrunc(gallivm->builder, res, dst_elem_type, "");
+   } else if (src_width < dst_width) {
+      res = LLVMBuildZExt(gallivm->builder, res, dst_elem_type, "");
+      if (vector_justify) {
+#ifdef PIPE_ARCH_BIG_ENDIAN
+         res = LLVMBuildShl(gallivm->builder, res,
+                            LLVMConstInt(dst_elem_type, dst_width - src_width, 0), "");
+#endif
+      }
+   }
 
    return res;
 }
@@ -105,44 +137,73 @@ lp_build_gather_elem(LLVMBuilderRef builder,
  * Use for fetching texels from a texture.
  * For SSE, typical values are length=4, src_width=32, dst_width=32.
  *
+ * When src_width < dst_width, the return value can be justified in
+ * one of two ways:
+ * "integer justification" is used when the caller treats the destination
+ * as a packed integer bitmask, as described by the channels' "shift" and
+ * "width" fields;
+ * "vector justification" is used when the caller casts the destination
+ * to a vector and needs channel X to be in vector element 0.
+ *
  * @param length length of the offsets
  * @param src_width src element width in bits
  * @param dst_width result element width in bits (src will be expanded to fit)
+ * @param aligned whether the data is guaranteed to be aligned (to src_width)
  * @param base_ptr base pointer, should be a i8 pointer type.
  * @param offsets vector with offsets
+ * @param vector_justify select vector rather than integer justification
  */
 LLVMValueRef
-lp_build_gather(LLVMBuilderRef builder,
+lp_build_gather(struct gallivm_state *gallivm,
                 unsigned length,
                 unsigned src_width,
                 unsigned dst_width,
+                boolean aligned,
                 LLVMValueRef base_ptr,
-                LLVMValueRef offsets)
+                LLVMValueRef offsets,
+                boolean vector_justify)
 {
    LLVMValueRef res;
 
    if (length == 1) {
       /* Scalar */
-      return lp_build_gather_elem(builder, length,
-                                  src_width, dst_width,
-                                  base_ptr, offsets, 0);
+      return lp_build_gather_elem(gallivm, length,
+                                  src_width, dst_width, aligned,
+                                  base_ptr, offsets, 0, vector_justify);
    } else {
       /* Vector */
 
-      LLVMTypeRef dst_elem_type = LLVMIntType(dst_width);
+      LLVMTypeRef dst_elem_type = LLVMIntTypeInContext(gallivm->context, dst_width);
       LLVMTypeRef dst_vec_type = LLVMVectorType(dst_elem_type, length);
       unsigned i;
 
       res = LLVMGetUndef(dst_vec_type);
       for (i = 0; i < length; ++i) {
-         LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
+         LLVMValueRef index = lp_build_const_int32(gallivm, i);
          LLVMValueRef elem;
-         elem = lp_build_gather_elem(builder, length,
-                                     src_width, dst_width,
-                                     base_ptr, offsets, i);
-         res = LLVMBuildInsertElement(builder, res, elem, index, "");
+         elem = lp_build_gather_elem(gallivm, length,
+                                     src_width, dst_width, aligned,
+                                     base_ptr, offsets, i, vector_justify);
+         res = LLVMBuildInsertElement(gallivm->builder, res, elem, index, "");
       }
    }
 
    return res;
 }
+
+LLVMValueRef
+lp_build_gather_values(struct gallivm_state * gallivm,
+                       LLVMValueRef * values,
+                       unsigned value_count)
+{
+   LLVMTypeRef vec_type = LLVMVectorType(LLVMTypeOf(values[0]), value_count);
+   LLVMBuilderRef builder = gallivm->builder;
+   LLVMValueRef vec = LLVMGetUndef(vec_type);
+   unsigned i;
+
+   for (i = 0; i < value_count; i++) {
+      LLVMValueRef index = lp_build_const_int32(gallivm, i);
+      vec = LLVMBuildInsertElement(builder, vec, values[i], index, "");
+   }
+   return vec;
+}