radeonsi/ac: move a bunch of load/store related things to common code.
[mesa.git] / src / amd / common / ac_llvm_util.c
index 7317db76baaa73bf2d2801d4e41fbe8ccc6bad74..43eeaac310c6abd67bdb8fd510739fd8f20f7d8a 100644 (file)
@@ -126,11 +126,11 @@ static const char *ac_get_llvm_processor_name(enum radeon_family family)
        }
 }
 
-LLVMTargetMachineRef ac_create_target_machine(enum radeon_family family)
+LLVMTargetMachineRef ac_create_target_machine(enum radeon_family family, bool supports_spill)
 {
        assert(family >= CHIP_TAHITI);
 
-       const char *triple = "amdgcn--";
+       const char *triple = supports_spill ? "amdgcn-mesa-mesa3d" : "amdgcn--";
        LLVMTargetRef target = ac_get_llvm_target(triple);
        LLVMTargetMachineRef tm = LLVMCreateTargetMachine(
                                     target,
@@ -160,10 +160,18 @@ ac_llvm_context_init(struct ac_llvm_context *ctx, LLVMContextRef context)
        ctx->i32 = LLVMIntTypeInContext(ctx->context, 32);
        ctx->f32 = LLVMFloatTypeInContext(ctx->context);
 
+       ctx->invariant_load_md_kind = LLVMGetMDKindIDInContext(ctx->context,
+                                                              "invariant.load", 14);
+
        ctx->fpmath_md_kind = LLVMGetMDKindIDInContext(ctx->context, "fpmath", 6);
 
        args[0] = LLVMConstReal(ctx->f32, 2.5);
        ctx->fpmath_md_2p5_ulp = LLVMMDNodeInContext(ctx->context, args, 1);
+
+       ctx->uniform_md_kind = LLVMGetMDKindIDInContext(ctx->context,
+                                                       "amdgpu.uniform", 14);
+
+       ctx->empty_md = LLVMMDNodeInContext(ctx->context, NULL, 0);
 }
 
 #if HAVE_LLVM < 0x0400
@@ -512,3 +520,131 @@ ac_dump_module(LLVMModuleRef module)
        fprintf(stderr, "%s", str);
        LLVMDisposeMessage(str);
 }
+
+LLVMValueRef
+ac_build_fs_interp(struct ac_llvm_context *ctx,
+                  LLVMValueRef llvm_chan,
+                  LLVMValueRef attr_number,
+                  LLVMValueRef params,
+                  LLVMValueRef i,
+                  LLVMValueRef j)
+{
+       LLVMValueRef args[5];
+       LLVMValueRef p1;
+       
+       if (HAVE_LLVM < 0x0400) {
+               LLVMValueRef ij[2];
+               ij[0] = LLVMBuildBitCast(ctx->builder, i, ctx->i32, "");
+               ij[1] = LLVMBuildBitCast(ctx->builder, j, ctx->i32, "");
+
+               args[0] = llvm_chan;
+               args[1] = attr_number;
+               args[2] = params;
+               args[3] = ac_build_gather_values(ctx, ij, 2);
+               return ac_emit_llvm_intrinsic(ctx, "llvm.SI.fs.interp",
+                                             ctx->f32, args, 4,
+                                             AC_FUNC_ATTR_READNONE);
+       }
+
+       args[0] = i;
+       args[1] = llvm_chan;
+       args[2] = attr_number;
+       args[3] = params;
+
+       p1 = ac_emit_llvm_intrinsic(ctx, "llvm.amdgcn.interp.p1",
+                                   ctx->f32, args, 4, AC_FUNC_ATTR_READNONE);
+
+       args[0] = p1;
+       args[1] = j;
+       args[2] = llvm_chan;
+       args[3] = attr_number;
+       args[4] = params;
+
+       return ac_emit_llvm_intrinsic(ctx, "llvm.amdgcn.interp.p2",
+                                     ctx->f32, args, 5, AC_FUNC_ATTR_READNONE);
+}
+
+LLVMValueRef
+ac_build_fs_interp_mov(struct ac_llvm_context *ctx,
+                      LLVMValueRef parameter,
+                      LLVMValueRef llvm_chan,
+                      LLVMValueRef attr_number,
+                      LLVMValueRef params)
+{
+       LLVMValueRef args[4];
+       if (HAVE_LLVM < 0x0400) {
+               args[0] = llvm_chan;
+               args[1] = attr_number;
+               args[2] = params;
+
+               return ac_emit_llvm_intrinsic(ctx,
+                                             "llvm.SI.fs.constant",
+                                             ctx->f32, args, 3,
+                                             AC_FUNC_ATTR_READNONE);
+       }
+
+       args[0] = parameter;
+       args[1] = llvm_chan;
+       args[2] = attr_number;
+       args[3] = params;
+
+       return ac_emit_llvm_intrinsic(ctx, "llvm.amdgcn.interp.mov",
+                                     ctx->f32, args, 4, AC_FUNC_ATTR_READNONE);
+}
+
+LLVMValueRef
+ac_build_gep0(struct ac_llvm_context *ctx,
+             LLVMValueRef base_ptr,
+             LLVMValueRef index)
+{
+       LLVMValueRef indices[2] = {
+               LLVMConstInt(ctx->i32, 0, 0),
+               index,
+       };
+       return LLVMBuildGEP(ctx->builder, base_ptr,
+                           indices, 2, "");
+}
+
+void
+ac_build_indexed_store(struct ac_llvm_context *ctx,
+                      LLVMValueRef base_ptr, LLVMValueRef index,
+                      LLVMValueRef value)
+{
+       LLVMBuildStore(ctx->builder, value,
+                      ac_build_gep0(ctx, base_ptr, index));
+}
+
+/**
+ * Build an LLVM bytecode indexed load using LLVMBuildGEP + LLVMBuildLoad.
+ * It's equivalent to doing a load from &base_ptr[index].
+ *
+ * \param base_ptr  Where the array starts.
+ * \param index     The element index into the array.
+ * \param uniform   Whether the base_ptr and index can be assumed to be
+ *                  dynamically uniform
+ */
+LLVMValueRef
+ac_build_indexed_load(struct ac_llvm_context *ctx,
+                     LLVMValueRef base_ptr, LLVMValueRef index,
+                     bool uniform)
+{
+       LLVMValueRef pointer;
+
+       pointer = ac_build_gep0(ctx, base_ptr, index);
+       if (uniform)
+               LLVMSetMetadata(pointer, ctx->uniform_md_kind, ctx->empty_md);
+       return LLVMBuildLoad(ctx->builder, pointer, "");
+}
+
+/**
+ * Do a load from &base_ptr[index], but also add a flag that it's loading
+ * a constant from a dynamically uniform index.
+ */
+LLVMValueRef
+ac_build_indexed_load_const(struct ac_llvm_context *ctx,
+                           LLVMValueRef base_ptr, LLVMValueRef index)
+{
+       LLVMValueRef result = ac_build_indexed_load(ctx, base_ptr, index, true);
+       LLVMSetMetadata(result, ctx->invariant_load_md_kind, ctx->empty_md);
+       return result;
+}