[Mesa-dev] [PATCH 06/10] amd/common: unify cube map coordinate handling between radeonsi and radv

Nicolai Hähnle nhaehnle at gmail.com
Tue Jan 10 15:12:18 UTC 2017


From: Nicolai Hähnle <nicolai.haehnle at amd.com>

Code is taken from a combination of radv (for the more basic functions,
to avoid gallivm dependencies) and radeonsi (for the new and improved
derivative calculations).
---
 src/amd/common/ac_llvm_util.c                      | 362 +++++++++++++++++++++
 src/amd/common/ac_llvm_util.h                      |  57 ++++
 src/amd/common/ac_nir_to_llvm.c                    | 204 +-----------
 src/gallium/drivers/radeonsi/si_shader.c           |   6 +-
 src/gallium/drivers/radeonsi/si_shader_internal.h  |   2 +
 .../drivers/radeonsi/si_shader_tgsi_setup.c        |   4 +
 6 files changed, 438 insertions(+), 197 deletions(-)

diff --git a/src/amd/common/ac_llvm_util.c b/src/amd/common/ac_llvm_util.c
index a8408dd..6dd6cfa 100644
--- a/src/amd/common/ac_llvm_util.c
+++ b/src/amd/common/ac_llvm_util.c
@@ -25,20 +25,23 @@
 /* based on pieces from si_pipe.c and radeon_llvm_emit.c */
 #include "ac_llvm_util.h"
 
 #include <llvm-c/Core.h>
 
 #include "c11/threads.h"
 
 #include <assert.h>
 #include <stdio.h>
 
+#include "util/bitscan.h"
+#include "util/macros.h"
+
 static void ac_init_llvm_target()
 {
 #if HAVE_LLVM < 0x0307
 	LLVMInitializeR600TargetInfo();
 	LLVMInitializeR600Target();
 	LLVMInitializeR600TargetMC();
 	LLVMInitializeR600AsmPrinter();
 #else
 	LLVMInitializeAMDGPUTargetInfo();
 	LLVMInitializeAMDGPUTarget();
@@ -133,10 +136,369 @@ LLVMTargetMachineRef ac_create_target_machine(enum radeon_family family)
 	                             target,
 	                             triple,
 	                             ac_get_llvm_processor_name(family),
 	                             "+DumpCode,+vgpr-spilling",
 	                             LLVMCodeGenLevelDefault,
 	                             LLVMRelocDefault,
 	                             LLVMCodeModelDefault);
 
 	return tm;
 }
+
+/* Initialize module-independent parts of the context.
+ *
+ * The caller is responsible for initializing ctx::module and ctx::builder.
+ */
+void
+ac_llvm_context_init(struct ac_llvm_context *ctx, LLVMContextRef context)
+{
+	LLVMValueRef args[1];
+
+	ctx->context = context;
+	ctx->module = NULL;
+	ctx->builder = NULL;
+
+	ctx->i32 = LLVMIntTypeInContext(ctx->context, 32);
+	ctx->f32 = LLVMFloatTypeInContext(ctx->context);
+
+	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);
+}
+
+#if HAVE_LLVM < 0x0400
+static LLVMAttribute ac_attr_to_llvm_attr(enum ac_func_attr attr)
+{
+   switch (attr) {
+   case AC_FUNC_ATTR_ALWAYSINLINE: return LLVMAlwaysInlineAttribute;
+   case AC_FUNC_ATTR_BYVAL: return LLVMByValAttribute;
+   case AC_FUNC_ATTR_INREG: return LLVMInRegAttribute;
+   case AC_FUNC_ATTR_NOALIAS: return LLVMNoAliasAttribute;
+   case AC_FUNC_ATTR_NOUNWIND: return LLVMNoUnwindAttribute;
+   case AC_FUNC_ATTR_READNONE: return LLVMReadNoneAttribute;
+   case AC_FUNC_ATTR_READONLY: return LLVMReadOnlyAttribute;
+   default:
+	   fprintf(stderr, "Unhandled function attribute: %x\n", attr);
+	   return 0;
+   }
+}
+
+#else
+
+static const char *attr_to_str(enum ac_func_attr attr)
+{
+   switch (attr) {
+   case AC_FUNC_ATTR_ALWAYSINLINE: return "alwaysinline";
+   case AC_FUNC_ATTR_BYVAL: return "byval";
+   case AC_FUNC_ATTR_INREG: return "inreg";
+   case AC_FUNC_ATTR_NOALIAS: return "noalias";
+   case AC_FUNC_ATTR_NOUNWIND: return "nounwind";
+   case AC_FUNC_ATTR_READNONE: return "readnone";
+   case AC_FUNC_ATTR_READONLY: return "readonly";
+   default:
+	   fprintf(stderr, "Unhandled function attribute: %x\n", attr);
+	   return 0;
+   }
+}
+
+#endif
+
+void
+ac_add_function_attr(LLVMValueRef function,
+                     int attr_idx,
+                     enum ac_func_attr attr)
+{
+
+#if HAVE_LLVM < 0x0400
+   LLVMAttribute llvm_attr = ac_attr_to_llvm_attr(attr);
+   if (attr_idx == -1) {
+      LLVMAddFunctionAttr(function, llvm_attr);
+   } else {
+      LLVMAddAttribute(LLVMGetParam(function, attr_idx - 1), llvm_attr);
+   }
+#else
+   LLVMContextRef context = LLVMGetModuleContext(LLVMGetGlobalParent(function));
+   const char *attr_name = attr_to_str(attr);
+   unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name,
+                                                      strlen(attr_name));
+   LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(context, kind_id, 0);
+   LLVMAddAttributeAtIndex(function, attr_idx, llvm_attr);
+#endif
+}
+
+LLVMValueRef
+ac_emit_llvm_intrinsic(struct ac_llvm_context *ctx, const char *name,
+		       LLVMTypeRef return_type, LLVMValueRef *params,
+		       unsigned param_count, unsigned attrib_mask)
+{
+	LLVMValueRef function;
+
+	function = LLVMGetNamedFunction(ctx->module, name);
+	if (!function) {
+		LLVMTypeRef param_types[32], function_type;
+		unsigned i;
+
+		assert(param_count <= 32);
+
+		for (i = 0; i < param_count; ++i) {
+			assert(params[i]);
+			param_types[i] = LLVMTypeOf(params[i]);
+		}
+		function_type =
+		    LLVMFunctionType(return_type, param_types, param_count, 0);
+		function = LLVMAddFunction(ctx->module, name, function_type);
+
+		LLVMSetFunctionCallConv(function, LLVMCCallConv);
+		LLVMSetLinkage(function, LLVMExternalLinkage);
+
+		attrib_mask |= AC_FUNC_ATTR_NOUNWIND;
+		while (attrib_mask) {
+			enum ac_func_attr attr = 1u << u_bit_scan(&attrib_mask);
+			ac_add_function_attr(function, -1, attr);
+		}
+	}
+	return LLVMBuildCall(ctx->builder, function, params, param_count, "");
+}
+
+LLVMValueRef
+ac_build_gather_values_extended(struct ac_llvm_context *ctx,
+				LLVMValueRef *values,
+				unsigned value_count,
+				unsigned value_stride,
+				bool load)
+{
+	LLVMBuilderRef builder = ctx->builder;
+	LLVMValueRef vec;
+	unsigned i;
+
+
+	if (value_count == 1) {
+		if (load)
+			return LLVMBuildLoad(builder, values[0], "");
+		return values[0];
+	} else if (!value_count)
+		unreachable("value_count is 0");
+
+	for (i = 0; i < value_count; i++) {
+		LLVMValueRef value = values[i * value_stride];
+		if (load)
+			value = LLVMBuildLoad(builder, value, "");
+
+		if (!i)
+			vec = LLVMGetUndef( LLVMVectorType(LLVMTypeOf(value), value_count));
+		LLVMValueRef index = LLVMConstInt(ctx->i32, i, false);
+		vec = LLVMBuildInsertElement(builder, vec, value, index, "");
+	}
+	return vec;
+}
+
+LLVMValueRef
+ac_build_gather_values(struct ac_llvm_context *ctx,
+		       LLVMValueRef *values,
+		       unsigned value_count)
+{
+	return ac_build_gather_values_extended(ctx, values, value_count, 1, false);
+}
+
+LLVMValueRef
+ac_emit_fdiv(struct ac_llvm_context *ctx,
+	     LLVMValueRef num,
+	     LLVMValueRef den)
+{
+	LLVMValueRef ret = LLVMBuildFDiv(ctx->builder, num, den, "");
+
+	if (!LLVMIsConstant(ret))
+		LLVMSetMetadata(ret, ctx->fpmath_md_kind, ctx->fpmath_md_2p5_ulp);
+	return ret;
+}
+
+/* Coordinates for cube map selection. sc, tc, and ma are as in Table 8.27
+ * of the OpenGL 4.5 (Compatibility Profile) specification, except ma is
+ * already multiplied by two. id is the cube face number.
+ */
+struct cube_selection_coords {
+	LLVMValueRef stc[2];
+	LLVMValueRef ma;
+	LLVMValueRef id;
+};
+
+static void
+build_cube_intrinsic(struct ac_llvm_context *ctx,
+		     LLVMValueRef in[3],
+		     struct cube_selection_coords *out)
+{
+	LLVMBuilderRef builder = ctx->builder;
+
+	if (HAVE_LLVM >= 0x0309) {
+		LLVMTypeRef f32 = ctx->f32;
+
+		out->stc[1] = ac_emit_llvm_intrinsic(ctx, "llvm.amdgcn.cubetc",
+					f32, in, 3, AC_FUNC_ATTR_READNONE);
+		out->stc[0] = ac_emit_llvm_intrinsic(ctx, "llvm.amdgcn.cubesc",
+					f32, in, 3, AC_FUNC_ATTR_READNONE);
+		out->ma = ac_emit_llvm_intrinsic(ctx, "llvm.amdgcn.cubema",
+					f32, in, 3, AC_FUNC_ATTR_READNONE);
+		out->id = ac_emit_llvm_intrinsic(ctx, "llvm.amdgcn.cubeid",
+					f32, in, 3, AC_FUNC_ATTR_READNONE);
+	} else {
+		LLVMValueRef c[4] = {
+			in[0],
+			in[1],
+			in[2],
+			LLVMGetUndef(LLVMTypeOf(in[0]))
+		};
+		LLVMValueRef vec = ac_build_gather_values(ctx, c, 4);
+
+		LLVMValueRef tmp =
+			ac_emit_llvm_intrinsic(ctx, "llvm.AMDGPU.cube",
+					  LLVMTypeOf(vec), &vec, 1,
+					  AC_FUNC_ATTR_READNONE);
+
+		out->stc[1] = LLVMBuildExtractElement(builder, tmp,
+				LLVMConstInt(ctx->i32, 0, 0), "");
+		out->stc[0] = LLVMBuildExtractElement(builder, tmp,
+				LLVMConstInt(ctx->i32, 1, 0), "");
+		out->ma = LLVMBuildExtractElement(builder, tmp,
+				LLVMConstInt(ctx->i32, 2, 0), "");
+		out->id = LLVMBuildExtractElement(builder, tmp,
+				LLVMConstInt(ctx->i32, 3, 0), "");
+	}
+}
+
+/**
+ * Build a manual selection sequence for cube face sc/tc coordinates and
+ * major axis vector (multiplied by 2 for consistency) for the given
+ * vec3 \p coords, for the face implied by \p selcoords.
+ *
+ * For the major axis, we always adjust the sign to be in the direction of
+ * selcoords.ma; i.e., a positive out_ma means that coords is pointed towards
+ * the selcoords major axis.
+ */
+static void build_cube_select(LLVMBuilderRef builder,
+			      const struct cube_selection_coords *selcoords,
+			      const LLVMValueRef *coords,
+			      LLVMValueRef *out_st,
+			      LLVMValueRef *out_ma)
+{
+	LLVMTypeRef f32 = LLVMTypeOf(coords[0]);
+	LLVMValueRef is_ma_positive;
+	LLVMValueRef sgn_ma;
+	LLVMValueRef is_ma_z, is_not_ma_z;
+	LLVMValueRef is_ma_y;
+	LLVMValueRef is_ma_x;
+	LLVMValueRef sgn;
+	LLVMValueRef tmp;
+
+	is_ma_positive = LLVMBuildFCmp(builder, LLVMRealUGE,
+		selcoords->ma, LLVMConstReal(f32, 0.0), "");
+	sgn_ma = LLVMBuildSelect(builder, is_ma_positive,
+		LLVMConstReal(f32, 1.0), LLVMConstReal(f32, -1.0), "");
+
+	is_ma_z = LLVMBuildFCmp(builder, LLVMRealUGE, selcoords->id, LLVMConstReal(f32, 4.0), "");
+	is_not_ma_z = LLVMBuildNot(builder, is_ma_z, "");
+	is_ma_y = LLVMBuildAnd(builder, is_not_ma_z,
+		LLVMBuildFCmp(builder, LLVMRealUGE, selcoords->id, LLVMConstReal(f32, 2.0), ""), "");
+	is_ma_x = LLVMBuildAnd(builder, is_not_ma_z, LLVMBuildNot(builder, is_ma_y, ""), "");
+
+	/* Select sc */
+	tmp = LLVMBuildSelect(builder, is_ma_z, coords[2], coords[0], "");
+	sgn = LLVMBuildSelect(builder, is_ma_y, LLVMConstReal(f32, 1.0),
+		LLVMBuildSelect(builder, is_ma_x, sgn_ma,
+			LLVMBuildFNeg(builder, sgn_ma, ""), ""), "");
+	out_st[0] = LLVMBuildFMul(builder, tmp, sgn, "");
+
+	/* Select tc */
+	tmp = LLVMBuildSelect(builder, is_ma_y, coords[2], coords[1], "");
+	sgn = LLVMBuildSelect(builder, is_ma_y, LLVMBuildFNeg(builder, sgn_ma, ""),
+		LLVMConstReal(f32, -1.0), "");
+	out_st[1] = LLVMBuildFMul(builder, tmp, sgn, "");
+
+	/* Select ma */
+	tmp = LLVMBuildSelect(builder, is_ma_z, coords[2],
+		LLVMBuildSelect(builder, is_ma_y, coords[1], coords[0], ""), "");
+	sgn = LLVMBuildSelect(builder, is_ma_positive,
+		LLVMConstReal(f32, 2.0), LLVMConstReal(f32, -2.0), "");
+	*out_ma = LLVMBuildFMul(builder, tmp, sgn, "");
+}
+
+void
+ac_prepare_cube_coords(struct ac_llvm_context *ctx,
+		       bool is_deriv, bool is_array,
+		       LLVMValueRef *coords_arg,
+		       LLVMValueRef *derivs_arg)
+{
+
+	LLVMBuilderRef builder = ctx->builder;
+	struct cube_selection_coords selcoords;
+	LLVMValueRef coords[4];
+	LLVMValueRef invma;
+
+	build_cube_intrinsic(ctx, coords_arg, &selcoords);
+
+	invma = ac_emit_llvm_intrinsic(ctx, "llvm.fabs.f32",
+			ctx->f32, &selcoords.ma, 1, AC_FUNC_ATTR_READNONE);
+	invma = ac_emit_fdiv(ctx, LLVMConstReal(ctx->f32, 1.0), invma);
+
+	for (int i = 0; i < 2; ++i) {
+		coords[i] =
+			LLVMBuildFAdd(builder,
+				LLVMBuildFMul(builder, selcoords.stc[i], invma, ""),
+				LLVMConstReal(ctx->f32, 0.5), "");
+	}
+
+	coords[2] = selcoords.id;
+
+	if (is_deriv && derivs_arg) {
+		LLVMValueRef derivs[4];
+		int axis;
+
+		/* Convert cube derivatives to 2D derivatives. */
+		for (axis = 0; axis < 2; axis++) {
+			LLVMValueRef deriv_st[2];
+			LLVMValueRef deriv_ma;
+
+			/* Transform the derivative alongside the texture
+			 * coordinate. Mathematically, the correct formula is
+			 * as follows. Assume we're projecting onto the +Z face
+			 * and denote by dx/dh the derivative of the (original)
+			 * X texture coordinate with respect to horizontal
+			 * window coordinates. The projection onto the +Z face
+			 * plane is:
+			 *
+			 *   f(x,z) = x/z
+			 *
+			 * Then df/dh = df/dx * dx/dh + df/dz * dz/dh
+			 *            = 1/z * dx/dh - x/z * 1/z * dz/dh.
+			 *
+			 * This motivatives the implementation below.
+			 *
+			 * Whether this actually gives the expected results for
+			 * apps that might feed in derivatives obtained via
+			 * finite differences is anyone's guess. The OpenGL spec
+			 * seems awfully quiet about how textureGrad for cube
+			 * maps should be handled.
+			 */
+			build_cube_select(builder, &selcoords, &derivs_arg[axis * 3],
+					  deriv_st, &deriv_ma);
+
+			deriv_ma = LLVMBuildFMul(builder, deriv_ma, invma, "");
+
+			for (int i = 0; i < 2; ++i)
+				derivs[axis * 2 + i] =
+					LLVMBuildFSub(builder,
+						LLVMBuildFMul(builder, deriv_st[i], invma, ""),
+						LLVMBuildFMul(builder, deriv_ma, coords[i], ""), "");
+		}
+
+		memcpy(derivs_arg, derivs, sizeof(derivs));
+	}
+
+	if (is_array) {
+		/* for cube arrays coord.z = coord.w(array_index) * 8 + face */
+		/* coords_arg.w component - array_index for cube arrays */
+		LLVMValueRef tmp = LLVMBuildFMul(ctx->builder, coords_arg[3], LLVMConstReal(ctx->f32, 8.0), "");
+		coords[2] = LLVMBuildFAdd(ctx->builder, tmp, coords[2], "");
+	}
+
+	memcpy(coords_arg, coords, sizeof(coords));
+}
diff --git a/src/amd/common/ac_llvm_util.h b/src/amd/common/ac_llvm_util.h
index d9ea9bd..802c266 100644
--- a/src/amd/common/ac_llvm_util.h
+++ b/src/amd/common/ac_llvm_util.h
@@ -26,18 +26,75 @@
 
 #include <stdbool.h>
 #include <llvm-c/TargetMachine.h>
 
 #include "amd_family.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+enum ac_func_attr {
+	AC_FUNC_ATTR_ALWAYSINLINE = (1 << 0),
+	AC_FUNC_ATTR_BYVAL        = (1 << 1),
+	AC_FUNC_ATTR_INREG        = (1 << 2),
+	AC_FUNC_ATTR_NOALIAS      = (1 << 3),
+	AC_FUNC_ATTR_NOUNWIND     = (1 << 4),
+	AC_FUNC_ATTR_READNONE     = (1 << 5),
+	AC_FUNC_ATTR_READONLY     = (1 << 6),
+	AC_FUNC_ATTR_LAST         = (1 << 7)
+};
+
+struct ac_llvm_context {
+	LLVMContextRef context;
+	LLVMModuleRef module;
+	LLVMBuilderRef builder;
+
+	LLVMTypeRef i32;
+	LLVMTypeRef f32;
+
+	unsigned fpmath_md_kind;
+	LLVMValueRef fpmath_md_2p5_ulp;
+};
+
 LLVMTargetMachineRef ac_create_target_machine(enum radeon_family family);
 
 void ac_add_attr_dereferenceable(LLVMValueRef val, uint64_t bytes);
 bool ac_is_sgpr_param(LLVMValueRef param);
 
+void
+ac_llvm_context_init(struct ac_llvm_context *ctx, LLVMContextRef context);
+
+void
+ac_add_function_attr(LLVMValueRef function,
+                     int attr_idx,
+                     enum ac_func_attr attr);
+LLVMValueRef
+ac_emit_llvm_intrinsic(struct ac_llvm_context *ctx, const char *name,
+		       LLVMTypeRef return_type, LLVMValueRef *params,
+		       unsigned param_count, unsigned attrib_mask);
+
+LLVMValueRef
+ac_build_gather_values_extended(struct ac_llvm_context *ctx,
+				LLVMValueRef *values,
+				unsigned value_count,
+				unsigned value_stride,
+				bool load);
+LLVMValueRef
+ac_build_gather_values(struct ac_llvm_context *ctx,
+		       LLVMValueRef *values,
+		       unsigned value_count);
+
+LLVMValueRef
+ac_emit_fdiv(struct ac_llvm_context *ctx,
+	     LLVMValueRef num,
+	     LLVMValueRef den);
+
+void
+ac_prepare_cube_coords(struct ac_llvm_context *ctx,
+		       bool is_deriv, bool is_array,
+		       LLVMValueRef *coords_arg,
+		       LLVMValueRef *derivs_arg);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/amd/common/ac_nir_to_llvm.c b/src/amd/common/ac_nir_to_llvm.c
index f214fcd..0fd8559 100644
--- a/src/amd/common/ac_nir_to_llvm.c
+++ b/src/amd/common/ac_nir_to_llvm.c
@@ -44,20 +44,21 @@ enum radeon_llvm_calling_convention {
 #define RADEON_LLVM_MAX_OUTPUTS (VARYING_SLOT_VAR31 + 1)
 
 enum desc_type {
 	DESC_IMAGE,
 	DESC_FMASK,
 	DESC_SAMPLER,
 	DESC_BUFFER,
 };
 
 struct nir_to_llvm_context {
+	struct ac_llvm_context ac;
 	const struct ac_nir_compiler_options *options;
 	struct ac_shader_variant_info *shader_info;
 
 	LLVMContextRef context;
 	LLVMModuleRef module;
 	LLVMBuilderRef builder;
 	LLVMValueRef main_function;
 
 	struct hash_table *defs;
 	struct hash_table *phis;
@@ -134,91 +135,20 @@ struct nir_to_llvm_context {
 	bool has_ds_bpermute;
 };
 
 struct ac_tex_info {
 	LLVMValueRef args[12];
 	int arg_count;
 	LLVMTypeRef dst_type;
 	bool has_offset;
 };
 
-enum ac_func_attr {
-	AC_FUNC_ATTR_ALWAYSINLINE = (1 << 0),
-	AC_FUNC_ATTR_BYVAL        = (1 << 1),
-	AC_FUNC_ATTR_INREG        = (1 << 2),
-	AC_FUNC_ATTR_NOALIAS      = (1 << 3),
-	AC_FUNC_ATTR_NOUNWIND     = (1 << 4),
-	AC_FUNC_ATTR_READNONE     = (1 << 5),
-	AC_FUNC_ATTR_READONLY     = (1 << 6),
-	AC_FUNC_ATTR_LAST         = (1 << 7)
-};
-
-#if HAVE_LLVM < 0x0400
-static LLVMAttribute ac_attr_to_llvm_attr(enum ac_func_attr attr)
-{
-   switch (attr) {
-   case AC_FUNC_ATTR_ALWAYSINLINE: return LLVMAlwaysInlineAttribute;
-   case AC_FUNC_ATTR_BYVAL: return LLVMByValAttribute;
-   case AC_FUNC_ATTR_INREG: return LLVMInRegAttribute;
-   case AC_FUNC_ATTR_NOALIAS: return LLVMNoAliasAttribute;
-   case AC_FUNC_ATTR_NOUNWIND: return LLVMNoUnwindAttribute;
-   case AC_FUNC_ATTR_READNONE: return LLVMReadNoneAttribute;
-   case AC_FUNC_ATTR_READONLY: return LLVMReadOnlyAttribute;
-   default:
-	   fprintf(stderr, "Unhandled function attribute: %x\n", attr);
-	   return 0;
-   }
-}
-
-#else
-
-static const char *attr_to_str(enum ac_func_attr attr)
-{
-   switch (attr) {
-   case AC_FUNC_ATTR_ALWAYSINLINE: return "alwaysinline";
-   case AC_FUNC_ATTR_BYVAL: return "byval";
-   case AC_FUNC_ATTR_INREG: return "inreg";
-   case AC_FUNC_ATTR_NOALIAS: return "noalias";
-   case AC_FUNC_ATTR_NOUNWIND: return "nounwind";
-   case AC_FUNC_ATTR_READNONE: return "readnone";
-   case AC_FUNC_ATTR_READONLY: return "readonly";
-   default:
-	   fprintf(stderr, "Unhandled function attribute: %x\n", attr);
-	   return 0;
-   }
-}
-
-#endif
-
-static void
-ac_add_function_attr(LLVMValueRef function,
-                     int attr_idx,
-                     enum ac_func_attr attr)
-{
-
-#if HAVE_LLVM < 0x0400
-   LLVMAttribute llvm_attr = ac_attr_to_llvm_attr(attr);
-   if (attr_idx == -1) {
-      LLVMAddFunctionAttr(function, llvm_attr);
-   } else {
-      LLVMAddAttribute(LLVMGetParam(function, attr_idx - 1), llvm_attr);
-   }
-#else
-   LLVMContextRef context = LLVMGetModuleContext(LLVMGetGlobalParent(function));
-   const char *attr_name = attr_to_str(attr);
-   unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name,
-                                                      strlen(attr_name));
-   LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(context, kind_id, 0);
-   LLVMAddAttributeAtIndex(function, attr_idx, llvm_attr);
-#endif
-}
-
 static LLVMValueRef
 emit_llvm_intrinsic(struct nir_to_llvm_context *ctx, const char *name,
                     LLVMTypeRef return_type, LLVMValueRef *params,
                     unsigned param_count, unsigned attr_mask);
 static LLVMValueRef get_sampler_desc(struct nir_to_llvm_context *ctx,
 				     nir_deref_var *deref,
 				     enum desc_type desc_type);
 static unsigned radeon_llvm_reg_index_soa(unsigned index, unsigned chan)
 {
 	return (index * 4) + chan;
@@ -3297,144 +3227,20 @@ static void tex_fetch_ptrs(struct nir_to_llvm_context *ctx,
 		else
 			*samp_ptr = get_sampler_desc(ctx, instr->texture, DESC_SAMPLER);
 		if (instr->sampler_dim < GLSL_SAMPLER_DIM_RECT)
 			*samp_ptr = sici_fix_sampler_aniso(ctx, *res_ptr, *samp_ptr);
 	}
 	if (fmask_ptr && !instr->sampler && (instr->op == nir_texop_txf_ms ||
 					     instr->op == nir_texop_samples_identical))
 		*fmask_ptr = get_sampler_desc(ctx, instr->texture, DESC_FMASK);
 }
 
-static LLVMValueRef build_cube_intrinsic(struct nir_to_llvm_context *ctx,
-					 LLVMValueRef *in)
-{
-
-	LLVMValueRef v, cube_vec;
-
-	if (1) {
-		LLVMTypeRef f32 = LLVMTypeOf(in[0]);
-		LLVMValueRef out[4];
-
-		out[0] = emit_llvm_intrinsic(ctx, "llvm.amdgcn.cubetc",
-					     f32, in, 3, AC_FUNC_ATTR_READNONE);
-		out[1] = emit_llvm_intrinsic(ctx, "llvm.amdgcn.cubesc",
-					     f32, in, 3, AC_FUNC_ATTR_READNONE);
-		out[2] = emit_llvm_intrinsic(ctx, "llvm.amdgcn.cubema",
-					     f32, in, 3, AC_FUNC_ATTR_READNONE);
-		out[3] = emit_llvm_intrinsic(ctx, "llvm.amdgcn.cubeid",
-					     f32, in, 3, AC_FUNC_ATTR_READNONE);
-
-		return build_gather_values(ctx, out, 4);
-	} else {
-		LLVMValueRef c[4];
-		c[0] = in[0];
-		c[1] = in[1];
-		c[2] = in[2];
-		c[3] = LLVMGetUndef(LLVMTypeOf(in[0]));
-		cube_vec = build_gather_values(ctx, c, 4);
-		v = emit_llvm_intrinsic(ctx, "llvm.AMDGPU.cube", LLVMTypeOf(cube_vec),
-					&cube_vec, 1, AC_FUNC_ATTR_READNONE);
-	}
-	return v;
-}
-
-static void cube_to_2d_coords(struct nir_to_llvm_context *ctx,
-			      LLVMValueRef *in, LLVMValueRef *out)
-{
-	LLVMValueRef coords[4];
-	LLVMValueRef mad_args[3];
-	LLVMValueRef v;
-	LLVMValueRef tmp;
-	int i;
-
-	v = build_cube_intrinsic(ctx, in);
-	for (i = 0; i < 4; i++)
-		coords[i] = LLVMBuildExtractElement(ctx->builder, v,
-						    LLVMConstInt(ctx->i32, i, false), "");
-
-	coords[2] = emit_llvm_intrinsic(ctx, "llvm.fabs.f32", ctx->f32,
-					&coords[2], 1, AC_FUNC_ATTR_READNONE);
-	coords[2] = emit_fdiv(ctx, ctx->f32one, coords[2]);
-
-	mad_args[1] = coords[2];
-	mad_args[2] = LLVMConstReal(ctx->f32, 1.5);
-	mad_args[0] = coords[0];
-
-	/* emit MAD */
-	tmp = LLVMBuildFMul(ctx->builder, mad_args[0], mad_args[1], "");
-	coords[0] = LLVMBuildFAdd(ctx->builder, tmp, mad_args[2], "");
-
-	mad_args[0] = coords[1];
-
-	/* emit MAD */
-	tmp = LLVMBuildFMul(ctx->builder, mad_args[0], mad_args[1], "");
-	coords[1] = LLVMBuildFAdd(ctx->builder, tmp, mad_args[2], "");
-
-	/* apply xyz = yxw swizzle to cooords */
-	out[0] = coords[1];
-	out[1] = coords[0];
-	out[2] = coords[3];
-}
-
-static void emit_prepare_cube_coords(struct nir_to_llvm_context *ctx,
-				     LLVMValueRef *coords_arg, int num_coords,
-				     bool is_deriv,
-				     bool is_array, LLVMValueRef *derivs_arg)
-{
-	LLVMValueRef coords[4];
-	int i;
-	cube_to_2d_coords(ctx, coords_arg, coords);
-
-	if (is_deriv && derivs_arg) {
-		LLVMValueRef derivs[4];
-		int axis;
-
-		/* Convert cube derivatives to 2D derivatives. */
-		for (axis = 0; axis < 2; axis++) {
-			LLVMValueRef shifted_cube_coords[4], shifted_coords[4];
-
-			/* Shift the cube coordinates by the derivatives to get
-			 * the cube coordinates of the "neighboring pixel".
-			 */
-			for (i = 0; i < 3; i++)
-				shifted_cube_coords[i] =
-					LLVMBuildFAdd(ctx->builder, coords_arg[i],
-						      derivs_arg[axis*3+i], "");
-			shifted_cube_coords[3] = LLVMGetUndef(ctx->f32);
-
-			/* Project the shifted cube coordinates onto the face. */
-			cube_to_2d_coords(ctx, shifted_cube_coords,
-					  shifted_coords);
-
-			/* Subtract both sets of 2D coordinates to get 2D derivatives.
-			 * This won't work if the shifted coordinates ended up
-			 * in a different face.
-			 */
-			for (i = 0; i < 2; i++)
-				derivs[axis * 2 + i] =
-					LLVMBuildFSub(ctx->builder, shifted_coords[i],
-						      coords[i], "");
-		}
-
-		memcpy(derivs_arg, derivs, sizeof(derivs));
-	}
-
-	if (is_array) {
-		/* for cube arrays coord.z = coord.w(array_index) * 8 + face */
-		/* coords_arg.w component - array_index for cube arrays */
-		LLVMValueRef tmp = LLVMBuildFMul(ctx->builder, coords_arg[3], LLVMConstReal(ctx->f32, 8.0), "");
-		coords[2] = LLVMBuildFAdd(ctx->builder, tmp, coords[2], "");
-	}
-
-	memcpy(coords_arg, coords, sizeof(coords));
-}
-
 static void visit_tex(struct nir_to_llvm_context *ctx, nir_tex_instr *instr)
 {
 	LLVMValueRef result = NULL;
 	struct ac_tex_info tinfo = { 0 };
 	unsigned dmask = 0xf;
 	LLVMValueRef address[16];
 	LLVMValueRef coords[5];
 	LLVMValueRef coord = NULL, lod = NULL, comparator = NULL;
 	LLVMValueRef bias = NULL, offsets = NULL;
 	LLVMValueRef res_ptr, samp_ptr, fmask_ptr = NULL, sample_index = NULL;
@@ -3562,21 +3368,23 @@ static void visit_tex(struct nir_to_llvm_context *ctx, nir_tex_instr *instr)
 			derivs[i * 2] = to_float(ctx, llvm_extract_elem(ctx, ddx, i));
 			derivs[i * 2 + 1] = to_float(ctx, llvm_extract_elem(ctx, ddy, i));
 		}
 	}
 
 	if (instr->sampler_dim == GLSL_SAMPLER_DIM_CUBE && coord) {
 		for (chan = 0; chan < instr->coord_components; chan++)
 			coords[chan] = to_float(ctx, coords[chan]);
 		if (instr->coord_components == 3)
 			coords[3] = LLVMGetUndef(ctx->f32);
-		emit_prepare_cube_coords(ctx, coords, instr->coord_components, instr->op == nir_texop_txd, instr->is_array, derivs);
+		ac_prepare_cube_coords(&ctx->ac,
+			instr->op == nir_texop_txd, instr->is_array,
+			coords, derivs);
 		if (num_deriv_comp)
 			num_deriv_comp--;
 	}
 
 	if (ddx || ddy) {
 		for (unsigned i = 0; i < num_deriv_comp * 2; i++)
 			address[count++] = derivs[i];
 	}
 
 	/* Pack texture coordinates */
@@ -4672,28 +4480,32 @@ LLVMModuleRef ac_translate_nir_to_llvm(LLVMTargetMachineRef tm,
                                        const struct ac_nir_compiler_options *options)
 {
 	struct nir_to_llvm_context ctx = {0};
 	struct nir_function *func;
 	unsigned i;
 	ctx.options = options;
 	ctx.shader_info = shader_info;
 	ctx.context = LLVMContextCreate();
 	ctx.module = LLVMModuleCreateWithNameInContext("shader", ctx.context);
 
+	ac_llvm_context_init(&ctx.ac, ctx.context);
+	ctx.ac.module = ctx.module;
+
 	ctx.has_ds_bpermute = ctx.options->chip_class >= VI;
 
 	memset(shader_info, 0, sizeof(*shader_info));
 
 	LLVMSetTarget(ctx.module, "amdgcn--");
 	setup_types(&ctx);
 
 	ctx.builder = LLVMCreateBuilderInContext(ctx.context);
+	ctx.ac.builder = ctx.builder;
 	ctx.stage = nir->stage;
 
 	for (i = 0; i < AC_UD_MAX_SETS; i++)
 		shader_info->user_sgprs_locs.descriptor_sets[i].sgpr_idx = -1;
 	for (i = 0; i < AC_UD_MAX_UD; i++)
 		shader_info->user_sgprs_locs.shader_data[i].sgpr_idx = -1;
 
 	create_function(&ctx);
 
 	if (nir->stage == MESA_SHADER_COMPUTE) {
diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c
index 8dec55c..f760dd2 100644
--- a/src/gallium/drivers/radeonsi/si_shader.c
+++ b/src/gallium/drivers/radeonsi/si_shader.c
@@ -4599,21 +4599,25 @@ static void tex_fetch_args(
 		for (param = 0; param < 2; param++)
 			for (chan = 0; chan < num_src_deriv_channels; chan++)
 				derivs[param * num_src_deriv_channels + chan] =
 					lp_build_emit_fetch(bld_base, inst, param+1, chan);
 	}
 
 	if (target == TGSI_TEXTURE_CUBE ||
 	    target == TGSI_TEXTURE_CUBE_ARRAY ||
 	    target == TGSI_TEXTURE_SHADOWCUBE ||
 	    target == TGSI_TEXTURE_SHADOWCUBE_ARRAY)
-		si_prepare_cube_coords(bld_base, emit_data, coords, derivs);
+		ac_prepare_cube_coords(&ctx->ac,
+				       opcode == TGSI_OPCODE_TXD,
+				       target == TGSI_TEXTURE_CUBE_ARRAY ||
+				       target == TGSI_TEXTURE_SHADOWCUBE_ARRAY,
+				       coords, derivs);
 
 	if (opcode == TGSI_OPCODE_TXD)
 		for (int i = 0; i < num_deriv_channels * 2; i++)
 			address[count++] = derivs[i];
 
 	/* Pack texture coordinates */
 	address[count++] = coords[0];
 	if (num_coords > 1)
 		address[count++] = coords[1];
 	if (num_coords > 2)
diff --git a/src/gallium/drivers/radeonsi/si_shader_internal.h b/src/gallium/drivers/radeonsi/si_shader_internal.h
index 8d6a40b..6b3ac17 100644
--- a/src/gallium/drivers/radeonsi/si_shader_internal.h
+++ b/src/gallium/drivers/radeonsi/si_shader_internal.h
@@ -21,40 +21,42 @@
  * USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
 #ifndef SI_SHADER_PRIVATE_H
 #define SI_SHADER_PRIVATE_H
 
 #include "si_shader.h"
 #include "gallivm/lp_bld_init.h"
 #include "gallivm/lp_bld_tgsi.h"
 #include "tgsi/tgsi_parse.h"
+#include "ac_llvm_util.h"
 
 #include <llvm-c/Core.h>
 #include <llvm-c/TargetMachine.h>
 
 struct pipe_debug_callback;
 struct radeon_shader_binary;
 
 #define RADEON_LLVM_MAX_INPUT_SLOTS 32
 #define RADEON_LLVM_MAX_INPUTS 32 * 4
 #define RADEON_LLVM_MAX_OUTPUTS 32 * 4
 
 #define RADEON_LLVM_INITIAL_CF_DEPTH 4
 
 #define RADEON_LLVM_MAX_SYSTEM_VALUES 4
 
 struct si_llvm_flow;
 
 struct si_shader_context {
 	struct lp_build_tgsi_soa_context soa;
 	struct gallivm_state gallivm;
+	struct ac_llvm_context ac;
 	struct si_shader *shader;
 	struct si_screen *screen;
 
 	unsigned type; /* PIPE_SHADER_* specifies the type of shader. */
 
 	/* Whether the prolog will be compiled separately. */
 	bool separate_prolog;
 
 	/** This function is responsible for initilizing the inputs array and will be
 	  * called once for each input declared in the TGSI shader.
diff --git a/src/gallium/drivers/radeonsi/si_shader_tgsi_setup.c b/src/gallium/drivers/radeonsi/si_shader_tgsi_setup.c
index 2f38949..4a919dd 100644
--- a/src/gallium/drivers/radeonsi/si_shader_tgsi_setup.c
+++ b/src/gallium/drivers/radeonsi/si_shader_tgsi_setup.c
@@ -1245,20 +1245,24 @@ void si_llvm_context_init(struct si_shader_context *ctx,
 
 	ctx->gallivm.context = LLVMContextCreate();
 	ctx->gallivm.module = LLVMModuleCreateWithNameInContext("tgsi",
 						ctx->gallivm.context);
 	LLVMSetTarget(ctx->gallivm.module, "amdgcn--");
 
 	bool unsafe_fpmath = (sscreen->b.debug_flags & DBG_UNSAFE_MATH) != 0;
 	ctx->gallivm.builder = lp_create_builder(ctx->gallivm.context,
 						 unsafe_fpmath);
 
+	ac_llvm_context_init(&ctx->ac, ctx->gallivm.context);
+	ctx->ac.module = ctx->gallivm.module;
+	ctx->ac.builder = ctx->gallivm.builder;
+
 	struct lp_build_tgsi_context *bld_base = &ctx->soa.bld_base;
 
 	bld_base->info = info;
 
 	if (info && info->array_max[TGSI_FILE_TEMPORARY] > 0) {
 		int size = info->array_max[TGSI_FILE_TEMPORARY];
 
 		ctx->temp_arrays = CALLOC(size, sizeof(ctx->temp_arrays[0]));
 		ctx->temp_array_allocas = CALLOC(size, sizeof(ctx->temp_array_allocas[0]));
 
-- 
2.7.4



More information about the mesa-dev mailing list