#include "si_pipe.h"
#include "sid.h"
+#include "compiler/nir/nir.h"
static const char *scratch_rsrc_dword0_symbol =
"SCRATCH_RSRC_DWORD0";
ubyte vertex_stream[4];
};
+/**
+ * Used to collect types and other info about arguments of the LLVM function
+ * before the function is created.
+ */
+struct si_function_info {
+ LLVMTypeRef types[100];
+ LLVMValueRef *assign[100];
+ unsigned num_sgpr_params;
+ unsigned num_params;
+};
+
+enum si_arg_regfile {
+ ARG_SGPR,
+ ARG_VGPR
+};
+
static void si_init_shader_ctx(struct si_shader_context *ctx,
struct si_screen *sscreen,
LLVMTargetMachineRef tm);
struct lp_build_tgsi_context *bld_base,
struct lp_build_emit_data *emit_data);
-static void si_dump_shader_key(unsigned processor, struct si_shader *shader,
+static void si_dump_shader_key(unsigned processor, const struct si_shader *shader,
FILE *f);
static unsigned llvm_get_type_size(LLVMTypeRef type);
shader->selector->type == PIPE_SHADER_GEOMETRY;
}
+static void si_init_function_info(struct si_function_info *fninfo)
+{
+ fninfo->num_params = 0;
+ fninfo->num_sgpr_params = 0;
+}
+
+static unsigned add_arg_assign(struct si_function_info *fninfo,
+ enum si_arg_regfile regfile, LLVMTypeRef type,
+ LLVMValueRef *assign)
+{
+ assert(regfile != ARG_SGPR || fninfo->num_sgpr_params == fninfo->num_params);
+
+ unsigned idx = fninfo->num_params++;
+ assert(idx < ARRAY_SIZE(fninfo->types));
+
+ if (regfile == ARG_SGPR)
+ fninfo->num_sgpr_params = fninfo->num_params;
+
+ fninfo->types[idx] = type;
+ fninfo->assign[idx] = assign;
+ return idx;
+}
+
+static unsigned add_arg(struct si_function_info *fninfo,
+ enum si_arg_regfile regfile, LLVMTypeRef type)
+{
+ return add_arg_assign(fninfo, regfile, type, NULL);
+}
+
+static void add_arg_checked(struct si_function_info *fninfo,
+ enum si_arg_regfile regfile, LLVMTypeRef type,
+ unsigned idx)
+{
+ MAYBE_UNUSED unsigned actual = add_arg(fninfo, regfile, type);
+ assert(actual == idx);
+}
+
/**
- * Returns a unique index for a semantic name and index. The index must be
- * less than 64, so that a 64-bit bitmask of used inputs or outputs can be
- * calculated.
+ * Returns a unique index for a per-patch semantic name and index. The index
+ * must be less than 32, so that a 32-bit bitmask of used inputs or outputs
+ * can be calculated.
*/
-unsigned si_shader_io_get_unique_index(unsigned semantic_name, unsigned index)
+unsigned si_shader_io_get_unique_index_patch(unsigned semantic_name, unsigned index)
{
switch (semantic_name) {
- case TGSI_SEMANTIC_POSITION:
- return 0;
- case TGSI_SEMANTIC_PSIZE:
- return 1;
- case TGSI_SEMANTIC_CLIPDIST:
- assert(index <= 1);
- return 2 + index;
- case TGSI_SEMANTIC_GENERIC:
- if (index <= 63-4)
- return 4 + index;
-
- assert(!"invalid generic index");
- return 0;
-
- /* patch indices are completely separate and thus start from 0 */
case TGSI_SEMANTIC_TESSOUTER:
return 0;
case TGSI_SEMANTIC_TESSINNER:
return 1;
case TGSI_SEMANTIC_PATCH:
+ assert(index < 30);
return 2 + index;
default:
}
}
-unsigned si_shader_io_get_unique_index2(unsigned name, unsigned index)
+/**
+ * Returns a unique index for a semantic name and index. The index must be
+ * less than 64, so that a 64-bit bitmask of used inputs or outputs can be
+ * calculated.
+ */
+unsigned si_shader_io_get_unique_index(unsigned semantic_name, unsigned index)
{
- switch (name) {
- case TGSI_SEMANTIC_FOG:
+ switch (semantic_name) {
+ case TGSI_SEMANTIC_POSITION:
+ return 0;
+ case TGSI_SEMANTIC_GENERIC:
+ /* Since some shader stages use the the highest used IO index
+ * to determine the size to allocate for inputs/outputs
+ * (in LDS, tess and GS rings). GENERIC should be placed right
+ * after POSITION to make that size as small as possible.
+ */
+ if (index < SI_MAX_IO_GENERIC)
+ return 1 + index;
+
+ assert(!"invalid generic index");
return 0;
+ case TGSI_SEMANTIC_PSIZE:
+ return SI_MAX_IO_GENERIC + 1;
+ case TGSI_SEMANTIC_CLIPDIST:
+ assert(index <= 1);
+ return SI_MAX_IO_GENERIC + 2 + index;
+ case TGSI_SEMANTIC_FOG:
+ return SI_MAX_IO_GENERIC + 4;
case TGSI_SEMANTIC_LAYER:
- return 1;
+ return SI_MAX_IO_GENERIC + 5;
case TGSI_SEMANTIC_VIEWPORT_INDEX:
- return 2;
+ return SI_MAX_IO_GENERIC + 6;
case TGSI_SEMANTIC_PRIMID:
- return 3;
+ return SI_MAX_IO_GENERIC + 7;
case TGSI_SEMANTIC_COLOR: /* these alias */
case TGSI_SEMANTIC_BCOLOR:
- return 4 + index;
+ assert(index < 2);
+ return SI_MAX_IO_GENERIC + 8 + index;
case TGSI_SEMANTIC_TEXCOORD:
- return 6 + index;
+ assert(index < 8);
+ assert(SI_MAX_IO_GENERIC + 10 + index < 64);
+ return SI_MAX_IO_GENERIC + 10 + index;
default:
assert(!"invalid semantic name");
return 0;
}
}
+/**
+ * Helper function that builds an LLVM IR PHI node and immediately adds
+ * incoming edges.
+ */
+static LLVMValueRef
+build_phi(struct ac_llvm_context *ctx, LLVMTypeRef type,
+ unsigned count_incoming, LLVMValueRef *values,
+ LLVMBasicBlockRef *blocks)
+{
+ LLVMValueRef phi = LLVMBuildPhi(ctx->builder, type, "");
+ LLVMAddIncoming(phi, values, blocks, count_incoming);
+ return phi;
+}
+
/**
* Get the value of a shader input parameter and extract a bitfield.
*/
static LLVMValueRef get_instance_index_for_fetch(
struct si_shader_context *ctx,
- unsigned param_start_instance, unsigned divisor)
+ unsigned param_start_instance, LLVMValueRef divisor)
{
struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMValueRef result = LLVMGetParam(ctx->main_fn,
- ctx->param_instance_id);
+ LLVMValueRef result = ctx->abi.instance_id;
/* The division must be done before START_INSTANCE is added. */
- if (divisor > 1)
- result = LLVMBuildUDiv(gallivm->builder, result,
- LLVMConstInt(ctx->i32, divisor, 0), "");
+ if (divisor != ctx->i32_1)
+ result = LLVMBuildUDiv(gallivm->builder, result, divisor, "");
return LLVMBuildAdd(gallivm->builder, result,
LLVMGetParam(ctx->main_fn, param_start_instance), "");
return LLVMBuildFPTrunc(builder, value, ctx->f32, "");
}
-static void declare_input_vs(
+void si_llvm_load_input_vs(
struct si_shader_context *ctx,
unsigned input_index,
- const struct tgsi_full_declaration *decl,
LLVMValueRef out[4])
{
struct gallivm_state *gallivm = &ctx->gallivm;
}
}
-static LLVMValueRef get_primitive_id(struct lp_build_tgsi_context *bld_base,
- unsigned swizzle)
+static void declare_input_vs(
+ struct si_shader_context *ctx,
+ unsigned input_index,
+ const struct tgsi_full_declaration *decl,
+ LLVMValueRef out[4])
{
- struct si_shader_context *ctx = si_shader_context(bld_base);
+ si_llvm_load_input_vs(ctx, input_index, out);
+}
+static LLVMValueRef get_primitive_id(struct si_shader_context *ctx,
+ unsigned swizzle)
+{
if (swizzle > 0)
return ctx->i32_0;
* Like get_indirect_index, but restricts the return value to a (possibly
* undefined) value inside [0..num).
*/
-static LLVMValueRef get_bounded_indirect_index(struct si_shader_context *ctx,
- const struct tgsi_ind_register *ind,
- int rel_index, unsigned num)
+LLVMValueRef si_get_bounded_indirect_index(struct si_shader_context *ctx,
+ const struct tgsi_ind_register *ind,
+ int rel_index, unsigned num)
{
LLVMValueRef result = get_indirect_index(ctx, ind, rel_index);
LLVMBuildMul(gallivm->builder, ind_index,
LLVMConstInt(ctx->i32, 4, 0), ""), "");
- param = si_shader_io_get_unique_index(name[first], index[first]);
+ param = reg.Register.Dimension ?
+ si_shader_io_get_unique_index(name[first], index[first]) :
+ si_shader_io_get_unique_index_patch(name[first], index[first]);
} else {
- param = si_shader_io_get_unique_index(name[reg.Register.Index],
- index[reg.Register.Index]);
+ param = reg.Register.Dimension ?
+ si_shader_io_get_unique_index(name[reg.Register.Index],
+ index[reg.Register.Index]) :
+ si_shader_io_get_unique_index_patch(name[reg.Register.Index],
+ index[reg.Register.Index]);
}
/* Add the base address of the element. */
param_index = ctx->i32_0;
}
- param_index_base = si_shader_io_get_unique_index(name[param_base],
- index[param_base]);
+ param_index_base = reg.Register.Dimension ?
+ si_shader_io_get_unique_index(name[param_base], index[param_base]) :
+ si_shader_io_get_unique_index_patch(name[param_base], index[param_base]);
param_index = LLVMBuildAdd(gallivm->builder, param_index,
LLVMConstInt(ctx->i32, param_index_base, 0),
static LLVMValueRef buffer_load(struct lp_build_tgsi_context *bld_base,
enum tgsi_opcode_type type, unsigned swizzle,
LLVMValueRef buffer, LLVMValueRef offset,
- LLVMValueRef base, bool readonly_memory)
+ LLVMValueRef base, bool can_speculate)
{
struct si_shader_context *ctx = si_shader_context(bld_base);
struct gallivm_state *gallivm = &ctx->gallivm;
if (swizzle == ~0) {
value = ac_build_buffer_load(&ctx->ac, buffer, 4, NULL, base, offset,
- 0, 1, 0, readonly_memory);
+ 0, 1, 0, can_speculate, false);
return LLVMBuildBitCast(gallivm->builder, value, vec_type, "");
}
if (!tgsi_type_is_64bit(type)) {
value = ac_build_buffer_load(&ctx->ac, buffer, 4, NULL, base, offset,
- 0, 1, 0, readonly_memory);
+ 0, 1, 0, can_speculate, false);
value = LLVMBuildBitCast(gallivm->builder, value, vec_type, "");
return LLVMBuildExtractElement(gallivm->builder, value,
}
value = ac_build_buffer_load(&ctx->ac, buffer, 1, NULL, base, offset,
- swizzle * 4, 1, 0, readonly_memory);
+ swizzle * 4, 1, 0, can_speculate, false);
value2 = ac_build_buffer_load(&ctx->ac, buffer, 1, NULL, base, offset,
- swizzle * 4 + 4, 1, 0, readonly_memory);
+ swizzle * 4 + 4, 1, 0, can_speculate, false);
return si_llvm_emit_fetch_64bit(bld_base, type, value, value2);
}
LLVMValueRef value;
if (swizzle != ~0 && semantic_name == TGSI_SEMANTIC_PRIMID)
- return get_primitive_id(bld_base, swizzle);
+ return get_primitive_id(ctx, swizzle);
if (!reg->Register.Dimension)
return NULL;
soffset = LLVMConstInt(ctx->i32, (param * 4 + swizzle) * 256, 0);
value = ac_build_buffer_load(&ctx->ac, ctx->esgs_ring, 1, ctx->i32_0,
- vtx_offset, soffset, 0, 1, 0, true);
+ vtx_offset, soffset, 0, 1, 0, true, false);
if (tgsi_type_is_64bit(type)) {
LLVMValueRef value2;
soffset = LLVMConstInt(ctx->i32, (param * 4 + swizzle + 1) * 256, 0);
value2 = ac_build_buffer_load(&ctx->ac, ctx->esgs_ring, 1,
ctx->i32_0, vtx_offset, soffset,
- 0, 1, 0, true);
+ 0, 1, 0, true, false);
return si_llvm_emit_fetch_64bit(bld_base, type,
value, value2);
}
}
}
+static LLVMValueRef si_build_fs_interp(struct si_shader_context *ctx,
+ unsigned attr_index, unsigned chan,
+ LLVMValueRef prim_mask,
+ LLVMValueRef i, LLVMValueRef j)
+{
+ if (i || j) {
+ return ac_build_fs_interp(&ctx->ac,
+ LLVMConstInt(ctx->i32, chan, 0),
+ LLVMConstInt(ctx->i32, attr_index, 0),
+ prim_mask, i, j);
+ }
+ return ac_build_fs_interp_mov(&ctx->ac,
+ LLVMConstInt(ctx->i32, 2, 0), /* P0 */
+ LLVMConstInt(ctx->i32, chan, 0),
+ LLVMConstInt(ctx->i32, attr_index, 0),
+ prim_mask);
+}
+
/**
* Interpolate a fragment shader input.
*
LLVMValueRef result[4])
{
struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMValueRef attr_number;
- LLVMValueRef i, j;
-
+ LLVMValueRef i = NULL, j = NULL;
unsigned chan;
/* fs.constant returns the param from the middle vertex, so it's not
*/
bool interp = interp_param != NULL;
- attr_number = LLVMConstInt(ctx->i32, input_index, 0);
-
if (interp) {
interp_param = LLVMBuildBitCast(gallivm->builder, interp_param,
LLVMVectorType(ctx->f32, 2), "");
if (semantic_name == TGSI_SEMANTIC_COLOR &&
ctx->shader->key.part.ps.prolog.color_two_side) {
LLVMValueRef is_face_positive;
- LLVMValueRef back_attr_number;
/* If BCOLOR0 is used, BCOLOR1 is at offset "num_inputs + 1",
* otherwise it's at offset "num_inputs".
if (semantic_index == 1 && colors_read_mask & 0xf)
back_attr_offset += 1;
- back_attr_number = LLVMConstInt(ctx->i32, back_attr_offset, 0);
-
is_face_positive = LLVMBuildICmp(gallivm->builder, LLVMIntNE,
face, ctx->i32_0, "");
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) {
- LLVMValueRef llvm_chan = LLVMConstInt(ctx->i32, chan, 0);
LLVMValueRef front, back;
- if (interp) {
- front = ac_build_fs_interp(&ctx->ac, llvm_chan,
- attr_number, prim_mask,
- i, j);
- back = ac_build_fs_interp(&ctx->ac, llvm_chan,
- back_attr_number, prim_mask,
- i, j);
- } else {
- front = ac_build_fs_interp_mov(&ctx->ac,
- LLVMConstInt(ctx->i32, 2, 0), /* P0 */
- llvm_chan, attr_number, prim_mask);
- back = ac_build_fs_interp_mov(&ctx->ac,
- LLVMConstInt(ctx->i32, 2, 0), /* P0 */
- llvm_chan, back_attr_number, prim_mask);
- }
+ front = si_build_fs_interp(ctx,
+ input_index, chan,
+ prim_mask, i, j);
+ back = si_build_fs_interp(ctx,
+ back_attr_offset, chan,
+ prim_mask, i, j);
result[chan] = LLVMBuildSelect(gallivm->builder,
is_face_positive,
"");
}
} else if (semantic_name == TGSI_SEMANTIC_FOG) {
- if (interp) {
- result[0] = ac_build_fs_interp(&ctx->ac, ctx->i32_0,
- attr_number, prim_mask, i, j);
- } else {
- result[0] = ac_build_fs_interp_mov(&ctx->ac, ctx->i32_0,
- LLVMConstInt(ctx->i32, 2, 0), /* P0 */
- attr_number, prim_mask);
- }
+ result[0] = si_build_fs_interp(ctx, input_index,
+ 0, prim_mask, i, j);
result[1] =
result[2] = LLVMConstReal(ctx->f32, 0.0f);
result[3] = LLVMConstReal(ctx->f32, 1.0f);
} else {
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) {
- LLVMValueRef llvm_chan = LLVMConstInt(ctx->i32, chan, 0);
-
- if (interp) {
- result[chan] = ac_build_fs_interp(&ctx->ac,
- llvm_chan, attr_number, prim_mask, i, j);
- } else {
- result[chan] = ac_build_fs_interp_mov(&ctx->ac,
- LLVMConstInt(ctx->i32, 2, 0), /* P0 */
- llvm_chan, attr_number, prim_mask);
- }
+ result[chan] = si_build_fs_interp(ctx,
+ input_index, chan,
+ prim_mask, i, j);
}
}
}
-static void declare_input_fs(
+void si_llvm_load_input_fs(
struct si_shader_context *ctx,
unsigned input_index,
- const struct tgsi_full_declaration *decl,
LLVMValueRef out[4])
{
struct lp_build_context *base = &ctx->bld_base.base;
struct si_shader *shader = ctx->shader;
+ struct tgsi_shader_info *info = &shader->selector->info;
LLVMValueRef main_fn = ctx->main_fn;
LLVMValueRef interp_param = NULL;
int interp_param_idx;
+ enum tgsi_semantic semantic_name = info->input_semantic_name[input_index];
+ unsigned semantic_index = info->input_semantic_index[input_index];
+ enum tgsi_interpolate_mode interp_mode = info->input_interpolate[input_index];
+ enum tgsi_interpolate_loc interp_loc = info->input_interpolate_loc[input_index];
/* Get colors from input VGPRs (set by the prolog). */
- if (decl->Semantic.Name == TGSI_SEMANTIC_COLOR) {
- unsigned i = decl->Semantic.Index;
+ if (semantic_name == TGSI_SEMANTIC_COLOR) {
unsigned colors_read = shader->selector->info.colors_read;
- unsigned mask = colors_read >> (i * 4);
+ unsigned mask = colors_read >> (semantic_index * 4);
unsigned offset = SI_PARAM_POS_FIXED_PT + 1 +
- (i ? util_bitcount(colors_read & 0xf) : 0);
+ (semantic_index ? util_bitcount(colors_read & 0xf) : 0);
out[0] = mask & 0x1 ? LLVMGetParam(main_fn, offset++) : base->undef;
out[1] = mask & 0x2 ? LLVMGetParam(main_fn, offset++) : base->undef;
return;
}
- interp_param_idx = lookup_interp_param_index(decl->Interp.Interpolate,
- decl->Interp.Location);
+ interp_param_idx = lookup_interp_param_index(interp_mode, interp_loc);
if (interp_param_idx == -1)
return;
else if (interp_param_idx) {
interp_param = LLVMGetParam(ctx->main_fn, interp_param_idx);
}
- if (decl->Semantic.Name == TGSI_SEMANTIC_COLOR &&
- decl->Interp.Interpolate == TGSI_INTERPOLATE_COLOR &&
- ctx->shader->key.part.ps.prolog.flatshade_colors)
- interp_param = NULL; /* load the constant color */
-
- interp_fs_input(ctx, input_index, decl->Semantic.Name,
- decl->Semantic.Index, shader->selector->info.num_inputs,
+ interp_fs_input(ctx, input_index, semantic_name,
+ semantic_index, 0, /* this param is unused */
shader->selector->info.colors_read, interp_param,
LLVMGetParam(main_fn, SI_PARAM_PRIM_MASK),
LLVMGetParam(main_fn, SI_PARAM_FRONT_FACE),
&out[0]);
}
+static void declare_input_fs(
+ struct si_shader_context *ctx,
+ unsigned input_index,
+ const struct tgsi_full_declaration *decl,
+ LLVMValueRef out[4])
+{
+ si_llvm_load_input_fs(ctx, input_index, out);
+}
+
static LLVMValueRef get_sample_id(struct si_shader_context *ctx)
{
return unpack_param(ctx, SI_PARAM_ANCILLARY, 8, 4);
LLVMValueRef resource,
LLVMValueRef offset)
{
- LLVMBuilderRef builder = ctx->gallivm.builder;
- LLVMValueRef args[2] = {resource, offset};
-
- return lp_build_intrinsic(builder, "llvm.SI.load.const.v4i32", ctx->f32, args, 2,
- LP_FUNC_ATTR_READNONE |
- LP_FUNC_ATTR_LEGACY);
+ return ac_build_buffer_load(&ctx->ac, resource, 1, NULL, offset, NULL,
+ 0, 0, 0, true, true);
}
static LLVMValueRef load_sample_position(struct si_shader_context *ctx, LLVMValueRef sample_id)
switch (decl->Semantic.Name) {
case TGSI_SEMANTIC_INSTANCEID:
- value = LLVMGetParam(ctx->main_fn,
- ctx->param_instance_id);
+ value = ctx->abi.instance_id;
break;
case TGSI_SEMANTIC_VERTEXID:
value = LLVMBuildAdd(gallivm->builder,
- LLVMGetParam(ctx->main_fn,
- ctx->param_vertex_id),
- LLVMGetParam(ctx->main_fn,
- ctx->param_base_vertex), "");
+ ctx->abi.vertex_id,
+ ctx->abi.base_vertex, "");
break;
case TGSI_SEMANTIC_VERTEXID_NOBASE:
indexed = LLVMBuildTrunc(gallivm->builder, indexed, ctx->i1, "");
value = LLVMBuildSelect(gallivm->builder, indexed,
- LLVMGetParam(ctx->main_fn, ctx->param_base_vertex),
- ctx->i32_0, "");
+ ctx->abi.base_vertex, ctx->i32_0, "");
break;
}
case TGSI_SEMANTIC_BASEINSTANCE:
- value = LLVMGetParam(ctx->main_fn, ctx->param_start_instance);
+ value = ctx->abi.start_instance;
break;
case TGSI_SEMANTIC_DRAWID:
- value = LLVMGetParam(ctx->main_fn, ctx->param_draw_id);
+ value = ctx->abi.draw_id;
break;
case TGSI_SEMANTIC_INVOCATIONID:
case TGSI_SEMANTIC_TESSOUTER:
{
LLVMValueRef buffer, base, addr;
- int param = si_shader_io_get_unique_index(decl->Semantic.Name, 0);
+ int param = si_shader_io_get_unique_index_patch(decl->Semantic.Name, 0);
buffer = desc_from_addr_base64k(ctx, ctx->param_tcs_offchip_addr_base64k);
}
case TGSI_SEMANTIC_PRIMID:
- value = get_primitive_id(&ctx->bld_base, 0);
+ value = get_primitive_id(ctx, 0);
break;
case TGSI_SEMANTIC_GRID_SIZE:
static LLVMValueRef load_const_buffer_desc(struct si_shader_context *ctx, int i)
{
LLVMValueRef list_ptr = LLVMGetParam(ctx->main_fn,
- ctx->param_const_buffers);
+ ctx->param_const_and_shader_buffers);
return ac_build_indexed_load_const(&ctx->ac, list_ptr,
- LLVMConstInt(ctx->i32, i, 0));
+ LLVMConstInt(ctx->i32, si_get_constbuf_slot(i), 0));
+}
+
+static LLVMValueRef load_ubo(struct ac_shader_abi *abi, LLVMValueRef index)
+{
+ struct si_shader_context *ctx = si_shader_context_from_abi(abi);
+ LLVMValueRef ptr = LLVMGetParam(ctx->main_fn, ctx->param_const_and_shader_buffers);
+
+ index = si_llvm_bound_index(ctx, index, ctx->num_const_buffers);
+ index = LLVMBuildAdd(ctx->gallivm.builder, index,
+ LLVMConstInt(ctx->i32, SI_NUM_SHADER_BUFFERS, 0), "");
+
+ return ac_build_indexed_load_const(&ctx->ac, ptr, index);
}
static LLVMValueRef fetch_constant(
idx = reg->Register.Index * 4 + swizzle;
if (reg->Register.Dimension && reg->Dimension.Indirect) {
- LLVMValueRef ptr = LLVMGetParam(ctx->main_fn, ctx->param_const_buffers);
+ LLVMValueRef ptr = LLVMGetParam(ctx->main_fn, ctx->param_const_and_shader_buffers);
LLVMValueRef index;
- index = get_bounded_indirect_index(ctx, ®->DimIndirect,
- reg->Dimension.Index,
- SI_NUM_CONST_BUFFERS);
+ index = si_get_bounded_indirect_index(ctx, ®->DimIndirect,
+ reg->Dimension.Index,
+ ctx->num_const_buffers);
+ index = LLVMBuildAdd(ctx->gallivm.builder, index,
+ LLVMConstInt(ctx->i32, SI_NUM_SHADER_BUFFERS, 0), "");
bufp = ac_build_indexed_load_const(&ctx->ac, ptr, index);
} else
bufp = load_const_buffer_desc(ctx, buf);
lp_build_endif(&if_ctx);
}
+static void si_export_param(struct si_shader_context *ctx, unsigned index,
+ LLVMValueRef *values)
+{
+ struct ac_export_args args;
-/* Generate export instructions for hardware VS shader stage */
-static void si_llvm_export_vs(struct lp_build_tgsi_context *bld_base,
- struct si_shader_output_values *outputs,
- unsigned noutput)
+ si_llvm_init_export_args(&ctx->bld_base, values,
+ V_008DFC_SQ_EXP_PARAM + index, &args);
+ ac_build_export(&ctx->ac, &args);
+}
+
+static void si_build_param_exports(struct si_shader_context *ctx,
+ struct si_shader_output_values *outputs,
+ unsigned noutput)
{
- struct si_shader_context *ctx = si_shader_context(bld_base);
struct si_shader *shader = ctx->shader;
- struct lp_build_context *base = &bld_base->base;
- struct ac_export_args args, pos_args[4] = {};
- LLVMValueRef psize_value = NULL, edgeflag_value = NULL, layer_value = NULL, viewport_index_value = NULL;
- unsigned semantic_name, semantic_index;
- unsigned target;
unsigned param_count = 0;
- unsigned pos_idx;
- int i;
-
- for (i = 0; i < noutput; i++) {
- semantic_name = outputs[i].semantic_name;
- semantic_index = outputs[i].semantic_index;
- bool export_param = true;
- switch (semantic_name) {
- case TGSI_SEMANTIC_POSITION: /* ignore these */
- case TGSI_SEMANTIC_PSIZE:
- case TGSI_SEMANTIC_CLIPVERTEX:
- case TGSI_SEMANTIC_EDGEFLAG:
- break;
- case TGSI_SEMANTIC_GENERIC:
- case TGSI_SEMANTIC_CLIPDIST:
- if (shader->key.opt.hw_vs.kill_outputs &
- (1ull << si_shader_io_get_unique_index(semantic_name, semantic_index)))
- export_param = false;
- break;
- default:
- if (shader->key.opt.hw_vs.kill_outputs2 &
- (1u << si_shader_io_get_unique_index2(semantic_name, semantic_index)))
- export_param = false;
- break;
- }
+ for (unsigned i = 0; i < noutput; i++) {
+ unsigned semantic_name = outputs[i].semantic_name;
+ unsigned semantic_index = outputs[i].semantic_index;
if (outputs[i].vertex_stream[0] != 0 &&
outputs[i].vertex_stream[1] != 0 &&
outputs[i].vertex_stream[2] != 0 &&
outputs[i].vertex_stream[3] != 0)
- export_param = false;
-
-handle_semantic:
- /* Select the correct target */
- switch(semantic_name) {
- case TGSI_SEMANTIC_PSIZE:
- psize_value = outputs[i].values[0];
- continue;
- case TGSI_SEMANTIC_EDGEFLAG:
- edgeflag_value = outputs[i].values[0];
continue;
+
+ switch (semantic_name) {
case TGSI_SEMANTIC_LAYER:
- layer_value = outputs[i].values[0];
- semantic_name = TGSI_SEMANTIC_GENERIC;
- goto handle_semantic;
case TGSI_SEMANTIC_VIEWPORT_INDEX:
- viewport_index_value = outputs[i].values[0];
- semantic_name = TGSI_SEMANTIC_GENERIC;
- goto handle_semantic;
- case TGSI_SEMANTIC_POSITION:
- target = V_008DFC_SQ_EXP_POS;
- break;
case TGSI_SEMANTIC_CLIPDIST:
- if (shader->key.opt.hw_vs.clip_disable) {
- semantic_name = TGSI_SEMANTIC_GENERIC;
- goto handle_semantic;
- }
- target = V_008DFC_SQ_EXP_POS + 2 + semantic_index;
- break;
- case TGSI_SEMANTIC_CLIPVERTEX:
- if (shader->key.opt.hw_vs.clip_disable)
- continue;
- si_llvm_emit_clipvertex(bld_base, pos_args, outputs[i].values);
- continue;
case TGSI_SEMANTIC_COLOR:
case TGSI_SEMANTIC_BCOLOR:
case TGSI_SEMANTIC_PRIMID:
case TGSI_SEMANTIC_FOG:
case TGSI_SEMANTIC_TEXCOORD:
case TGSI_SEMANTIC_GENERIC:
- if (!export_param)
- continue;
- target = V_008DFC_SQ_EXP_PARAM + param_count;
- assert(i < ARRAY_SIZE(shader->info.vs_output_param_offset));
- shader->info.vs_output_param_offset[i] = param_count;
- param_count++;
break;
default:
- target = 0;
- fprintf(stderr,
- "Warning: SI unhandled vs output type:%d\n",
- semantic_name);
+ continue;
}
- si_llvm_init_export_args(bld_base, outputs[i].values, target, &args);
+ if ((semantic_name != TGSI_SEMANTIC_GENERIC ||
+ semantic_index < SI_MAX_IO_GENERIC) &&
+ shader->key.opt.kill_outputs &
+ (1ull << si_shader_io_get_unique_index(semantic_name, semantic_index)))
+ continue;
- if (target >= V_008DFC_SQ_EXP_POS &&
- target <= (V_008DFC_SQ_EXP_POS + 3)) {
- memcpy(&pos_args[target - V_008DFC_SQ_EXP_POS],
- &args, sizeof(args));
- } else {
- ac_build_export(&ctx->ac, &args);
- }
+ si_export_param(ctx, param_count, outputs[i].values);
- if (semantic_name == TGSI_SEMANTIC_CLIPDIST) {
- semantic_name = TGSI_SEMANTIC_GENERIC;
- goto handle_semantic;
- }
+ assert(i < ARRAY_SIZE(shader->info.vs_output_param_offset));
+ shader->info.vs_output_param_offset[i] = param_count++;
}
shader->info.nr_param_exports = param_count;
+}
+
+/* Generate export instructions for hardware VS shader stage */
+static void si_llvm_export_vs(struct lp_build_tgsi_context *bld_base,
+ struct si_shader_output_values *outputs,
+ unsigned noutput)
+{
+ struct si_shader_context *ctx = si_shader_context(bld_base);
+ struct si_shader *shader = ctx->shader;
+ struct lp_build_context *base = &bld_base->base;
+ struct ac_export_args pos_args[4] = {};
+ LLVMValueRef psize_value = NULL, edgeflag_value = NULL, layer_value = NULL, viewport_index_value = NULL;
+ unsigned pos_idx;
+ int i;
+
+ /* Build position exports. */
+ for (i = 0; i < noutput; i++) {
+ switch (outputs[i].semantic_name) {
+ case TGSI_SEMANTIC_POSITION:
+ si_llvm_init_export_args(bld_base, outputs[i].values,
+ V_008DFC_SQ_EXP_POS, &pos_args[0]);
+ break;
+ case TGSI_SEMANTIC_PSIZE:
+ psize_value = outputs[i].values[0];
+ break;
+ case TGSI_SEMANTIC_LAYER:
+ layer_value = outputs[i].values[0];
+ break;
+ case TGSI_SEMANTIC_VIEWPORT_INDEX:
+ viewport_index_value = outputs[i].values[0];
+ break;
+ case TGSI_SEMANTIC_EDGEFLAG:
+ edgeflag_value = outputs[i].values[0];
+ break;
+ case TGSI_SEMANTIC_CLIPDIST:
+ if (!shader->key.opt.clip_disable) {
+ unsigned index = 2 + outputs[i].semantic_index;
+ si_llvm_init_export_args(bld_base, outputs[i].values,
+ V_008DFC_SQ_EXP_POS + index,
+ &pos_args[index]);
+ }
+ break;
+ case TGSI_SEMANTIC_CLIPVERTEX:
+ if (!shader->key.opt.clip_disable) {
+ si_llvm_emit_clipvertex(bld_base, pos_args,
+ outputs[i].values);
+ }
+ break;
+ }
+ }
/* We need to add the position output manually if it's missing. */
if (!pos_args[0].out[0]) {
ac_build_export(&ctx->ac, &pos_args[i]);
}
+
+ /* Build parameter exports. */
+ si_build_param_exports(ctx, outputs, noutput);
}
/**
lds_base = get_tcs_in_current_patch_offset(ctx);
lds_base = LLVMBuildAdd(gallivm->builder, lds_base, lds_vertex_offset, "");
- inputs = ctx->shader->key.mono.ff_tcs_inputs_to_copy;
+ inputs = ctx->shader->key.mono.u.ff_tcs_inputs_to_copy;
while (inputs) {
unsigned i = u_bit_scan64(&inputs);
/* Load tess_inner and tess_outer from LDS.
* Any invocation can write them, so we can't get them from a temporary.
*/
- tess_inner_index = si_shader_io_get_unique_index(TGSI_SEMANTIC_TESSINNER, 0);
- tess_outer_index = si_shader_io_get_unique_index(TGSI_SEMANTIC_TESSOUTER, 0);
+ tess_inner_index = si_shader_io_get_unique_index_patch(TGSI_SEMANTIC_TESSINNER, 0);
+ tess_outer_index = si_shader_io_get_unique_index_patch(TGSI_SEMANTIC_TESSOUTER, 0);
lds_base = tcs_out_current_patch_data_offset;
lds_inner = LLVMBuildAdd(gallivm->builder, lds_base,
buf = desc_from_addr_base64k(ctx, ctx->param_tcs_offchip_addr_base64k);
base = LLVMGetParam(ctx->main_fn, ctx->param_tcs_offchip_offset);
- param_outer = si_shader_io_get_unique_index(
+ param_outer = si_shader_io_get_unique_index_patch(
TGSI_SEMANTIC_TESSOUTER, 0);
tf_outer_offset = get_tcs_tes_buffer_address(ctx, rel_patch_id, NULL,
LLVMConstInt(ctx->i32, param_outer, 0));
outer_comps, tf_outer_offset,
base, 0, 1, 0, true, false);
if (inner_comps) {
- param_inner = si_shader_io_get_unique_index(
+ param_inner = si_shader_io_get_unique_index_patch(
TGSI_SEMANTIC_TESSINNER, 0);
tf_inner_offset = get_tcs_tes_buffer_address(ctx, rel_patch_id, NULL,
LLVMConstInt(ctx->i32, param_inner, 0));
static void si_llvm_emit_tcs_epilogue(struct lp_build_tgsi_context *bld_base)
{
struct si_shader_context *ctx = si_shader_context(bld_base);
+ LLVMBuilderRef builder = ctx->gallivm.builder;
LLVMValueRef rel_patch_id, invocation_id, tf_lds_offset;
si_copy_tcs_inputs(bld_base);
invocation_id = unpack_param(ctx, ctx->param_tcs_rel_ids, 8, 5);
tf_lds_offset = get_tcs_out_current_patch_data_offset(ctx);
+ if (ctx->screen->b.chip_class >= GFX9) {
+ LLVMBasicBlockRef blocks[2] = {
+ LLVMGetInsertBlock(builder),
+ ctx->merged_wrap_if_state.entry_block
+ };
+ LLVMValueRef values[2];
+
+ lp_build_endif(&ctx->merged_wrap_if_state);
+
+ values[0] = rel_patch_id;
+ values[1] = LLVMGetUndef(ctx->i32);
+ rel_patch_id = build_phi(&ctx->ac, ctx->i32, 2, values, blocks);
+
+ values[0] = tf_lds_offset;
+ values[1] = LLVMGetUndef(ctx->i32);
+ tf_lds_offset = build_phi(&ctx->ac, ctx->i32, 2, values, blocks);
+
+ values[0] = invocation_id;
+ values[1] = ctx->i32_1; /* cause the epilog to skip threads */
+ invocation_id = build_phi(&ctx->ac, ctx->i32, 2, values, blocks);
+ }
+
/* Return epilog parameters from this function. */
- LLVMBuilderRef builder = ctx->gallivm.builder;
LLVMValueRef ret = ctx->return_value;
unsigned vgpr;
invocation_id = bitcast(bld_base, TGSI_TYPE_FLOAT, invocation_id);
tf_lds_offset = bitcast(bld_base, TGSI_TYPE_FLOAT, tf_lds_offset);
+ /* Leave a hole corresponding to the two input VGPRs. This ensures that
+ * the invocation_id output does not alias the param_tcs_rel_ids input,
+ * which saves a V_MOV on gfx9.
+ */
+ vgpr += 2;
+
ret = LLVMBuildInsertValue(builder, ret, rel_patch_id, vgpr++, "");
ret = LLVMBuildInsertValue(builder, ret, invocation_id, vgpr++, "");
ret = LLVMBuildInsertValue(builder, ret, tf_lds_offset, vgpr++, "");
unsigned desc_param = ctx->param_tcs_factor_addr_base64k + 2;
ret = si_insert_input_ptr_as_2xi32(ctx, ret, desc_param,
- 8 + GFX9_SGPR_TCS_CONST_BUFFERS);
+ 8 + GFX9_SGPR_TCS_CONST_AND_SHADER_BUFFERS);
ret = si_insert_input_ptr_as_2xi32(ctx, ret, desc_param + 1,
- 8 + GFX9_SGPR_TCS_SAMPLERS);
- ret = si_insert_input_ptr_as_2xi32(ctx, ret, desc_param + 2,
- 8 + GFX9_SGPR_TCS_IMAGES);
- ret = si_insert_input_ptr_as_2xi32(ctx, ret, desc_param + 3,
- 8 + GFX9_SGPR_TCS_SHADER_BUFFERS);
+ 8 + GFX9_SGPR_TCS_SAMPLERS_AND_IMAGES);
unsigned vgpr = 8 + GFX9_TCS_NUM_USER_SGPR;
ret = si_insert_input_ret_float(ctx, ret,
unsigned desc_param = ctx->param_vs_state_bits + 1;
ret = si_insert_input_ptr_as_2xi32(ctx, ret, desc_param,
- 8 + GFX9_SGPR_GS_CONST_BUFFERS);
+ 8 + GFX9_SGPR_GS_CONST_AND_SHADER_BUFFERS);
ret = si_insert_input_ptr_as_2xi32(ctx, ret, desc_param + 1,
- 8 + GFX9_SGPR_GS_SAMPLERS);
- ret = si_insert_input_ptr_as_2xi32(ctx, ret, desc_param + 2,
- 8 + GFX9_SGPR_GS_IMAGES);
- ret = si_insert_input_ptr_as_2xi32(ctx, ret, desc_param + 3,
- 8 + GFX9_SGPR_GS_SHADER_BUFFERS);
+ 8 + GFX9_SGPR_GS_SAMPLERS_AND_IMAGES);
unsigned vgpr = 8 + GFX9_GS_NUM_USER_SGPR;
for (unsigned i = 0; i < 5; i++) {
if (ctx->screen->b.chip_class >= GFX9 && info->num_outputs) {
unsigned itemsize_dw = es->selector->esgs_itemsize / 4;
- lds_base = LLVMBuildMul(gallivm->builder, ac_get_thread_id(&ctx->ac),
+ LLVMValueRef vertex_idx = ac_get_thread_id(&ctx->ac);
+ LLVMValueRef wave_idx = unpack_param(ctx, ctx->param_merged_wave_info, 24, 4);
+ vertex_idx = LLVMBuildOr(gallivm->builder, vertex_idx,
+ LLVMBuildMul(gallivm->builder, wave_idx,
+ LLVMConstInt(ctx->i32, 64, false), ""), "");
+ lds_base = LLVMBuildMul(gallivm->builder, vertex_idx,
LLVMConstInt(ctx->i32, itemsize_dw, 0), "");
}
ac_build_sendmsg(&ctx->ac, AC_SENDMSG_GS_OP_NOP | AC_SENDMSG_GS_DONE,
si_get_gs_wave_id(ctx));
+
+ if (ctx->screen->b.chip_class >= GFX9)
+ lp_build_endif(&ctx->merged_wrap_if_state);
}
-static void si_llvm_emit_vs_epilogue(struct lp_build_tgsi_context *bld_base)
+static void si_llvm_emit_vs_epilogue(struct ac_shader_abi *abi,
+ unsigned max_outputs,
+ LLVMValueRef *addrs)
{
- struct si_shader_context *ctx = si_shader_context(bld_base);
+ struct si_shader_context *ctx = si_shader_context_from_abi(abi);
struct gallivm_state *gallivm = &ctx->gallivm;
struct tgsi_shader_info *info = &ctx->shader->selector->info;
struct si_shader_output_values *outputs = NULL;
int i,j;
assert(!ctx->shader->is_gs_copy_shader);
+ assert(info->num_outputs <= max_outputs);
outputs = MALLOC((info->num_outputs + 1) * sizeof(outputs[0]));
}
for (j = 0; j < 4; j++) {
- addr = ctx->outputs[i][j];
+ addr = addrs[4 * i + j];
val = LLVMBuildLoad(gallivm->builder, addr, "");
val = ac_build_clamp(&ctx->ac, val);
LLVMBuildStore(gallivm->builder, val, addr);
for (j = 0; j < 4; j++) {
outputs[i].values[j] =
LLVMBuildLoad(gallivm->builder,
- ctx->outputs[i][j],
+ addrs[4 * i + j],
"");
outputs[i].vertex_stream[j] =
(info->output_streams[i] >> (2 * j)) & 3;
si_llvm_emit_streamout(ctx, outputs, i, 0);
/* Export PrimitiveID. */
- if (ctx->shader->key.mono.vs_export_prim_id) {
+ if (ctx->shader->key.mono.u.vs_export_prim_id) {
outputs[i].semantic_name = TGSI_SEMANTIC_PRIMID;
outputs[i].semantic_index = 0;
- outputs[i].values[0] = bitcast(bld_base, TGSI_TYPE_FLOAT,
- get_primitive_id(bld_base, 0));
+ outputs[i].values[0] = LLVMBuildBitCast(gallivm->builder,
+ get_primitive_id(ctx, 0), ctx->f32, "");
for (j = 1; j < 4; j++)
outputs[i].values[j] = LLVMConstReal(ctx->f32, 0);
i++;
}
- si_llvm_export_vs(bld_base, outputs, i);
+ si_llvm_export_vs(&ctx->bld_base, outputs, i);
FREE(outputs);
}
+static void si_tgsi_emit_epilogue(struct lp_build_tgsi_context *bld_base)
+{
+ struct si_shader_context *ctx = si_shader_context(bld_base);
+
+ ctx->abi.emit_outputs(&ctx->abi, RADEON_LLVM_MAX_OUTPUTS,
+ &ctx->outputs[0][0]);
+}
+
struct si_ps_exports {
unsigned num;
struct ac_export_args args[10];
* vN+0 = Depth
* vN+1 = Stencil
* vN+2 = SampleMask
- * vN+3 = SampleMaskIn (used for OpenGL smoothing)
- *
- * The alpha-ref SGPR is returned via its original location.
- */
-static void si_llvm_return_fs_outputs(struct lp_build_tgsi_context *bld_base)
-{
- struct si_shader_context *ctx = si_shader_context(bld_base);
- struct si_shader *shader = ctx->shader;
- struct tgsi_shader_info *info = &shader->selector->info;
- LLVMBuilderRef builder = ctx->gallivm.builder;
- unsigned i, j, first_vgpr, vgpr;
-
- LLVMValueRef color[8][4] = {};
- LLVMValueRef depth = NULL, stencil = NULL, samplemask = NULL;
- LLVMValueRef ret;
-
- /* Read the output values. */
- for (i = 0; i < info->num_outputs; i++) {
- unsigned semantic_name = info->output_semantic_name[i];
- unsigned semantic_index = info->output_semantic_index[i];
-
- switch (semantic_name) {
- case TGSI_SEMANTIC_COLOR:
- assert(semantic_index < 8);
- for (j = 0; j < 4; j++) {
- LLVMValueRef ptr = ctx->outputs[i][j];
- LLVMValueRef result = LLVMBuildLoad(builder, ptr, "");
- color[semantic_index][j] = result;
- }
- break;
- case TGSI_SEMANTIC_POSITION:
- depth = LLVMBuildLoad(builder,
- ctx->outputs[i][2], "");
- break;
- case TGSI_SEMANTIC_STENCIL:
- stencil = LLVMBuildLoad(builder,
- ctx->outputs[i][1], "");
- break;
- case TGSI_SEMANTIC_SAMPLEMASK:
- samplemask = LLVMBuildLoad(builder,
- ctx->outputs[i][0], "");
- break;
- default:
- fprintf(stderr, "Warning: SI unhandled fs output type:%d\n",
- semantic_name);
- }
- }
-
- /* Fill the return structure. */
- ret = ctx->return_value;
-
- /* Set SGPRs. */
- ret = LLVMBuildInsertValue(builder, ret,
- bitcast(bld_base, TGSI_TYPE_SIGNED,
- LLVMGetParam(ctx->main_fn,
- SI_PARAM_ALPHA_REF)),
- SI_SGPR_ALPHA_REF, "");
-
- /* Set VGPRs */
- first_vgpr = vgpr = SI_SGPR_ALPHA_REF + 1;
- for (i = 0; i < ARRAY_SIZE(color); i++) {
- if (!color[i][0])
- continue;
-
- for (j = 0; j < 4; j++)
- ret = LLVMBuildInsertValue(builder, ret, color[i][j], vgpr++, "");
- }
- if (depth)
- ret = LLVMBuildInsertValue(builder, ret, depth, vgpr++, "");
- if (stencil)
- ret = LLVMBuildInsertValue(builder, ret, stencil, vgpr++, "");
- if (samplemask)
- ret = LLVMBuildInsertValue(builder, ret, samplemask, vgpr++, "");
-
- /* Add the input sample mask for smoothing at the end. */
- if (vgpr < first_vgpr + PS_EPILOG_SAMPLEMASK_MIN_LOC)
- vgpr = first_vgpr + PS_EPILOG_SAMPLEMASK_MIN_LOC;
- ret = LLVMBuildInsertValue(builder, ret,
- LLVMGetParam(ctx->main_fn,
- SI_PARAM_SAMPLE_COVERAGE), vgpr++, "");
-
- ctx->return_value = ret;
-}
-
-/**
- * Given a v8i32 resource descriptor for a buffer, extract the size of the
- * buffer in number of elements and return it as an i32.
- */
-static LLVMValueRef get_buffer_size(
- struct lp_build_tgsi_context *bld_base,
- LLVMValueRef descriptor)
-{
- struct si_shader_context *ctx = si_shader_context(bld_base);
- struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMBuilderRef builder = gallivm->builder;
- LLVMValueRef size =
- LLVMBuildExtractElement(builder, descriptor,
- LLVMConstInt(ctx->i32, 2, 0), "");
-
- if (ctx->screen->b.chip_class == VI) {
- /* On VI, the descriptor contains the size in bytes,
- * but TXQ must return the size in elements.
- * The stride is always non-zero for resources using TXQ.
- */
- LLVMValueRef stride =
- LLVMBuildExtractElement(builder, descriptor,
- ctx->i32_1, "");
- stride = LLVMBuildLShr(builder, stride,
- LLVMConstInt(ctx->i32, 16, 0), "");
- stride = LLVMBuildAnd(builder, stride,
- LLVMConstInt(ctx->i32, 0x3FFF, 0), "");
-
- size = LLVMBuildUDiv(builder, size, stride, "");
- }
-
- return size;
-}
-
-static void build_tex_intrinsic(const struct lp_build_tgsi_action *action,
- struct lp_build_tgsi_context *bld_base,
- struct lp_build_emit_data *emit_data);
-
-/* Prevent optimizations (at least of memory accesses) across the current
- * point in the program by emitting empty inline assembly that is marked as
- * having side effects.
- *
- * Optionally, a value can be passed through the inline assembly to prevent
- * LLVM from hoisting calls to ReadNone functions.
- */
-static void emit_optimization_barrier(struct si_shader_context *ctx,
- LLVMValueRef *pvgpr)
-{
- static int counter = 0;
-
- LLVMBuilderRef builder = ctx->gallivm.builder;
- char code[16];
-
- snprintf(code, sizeof(code), "; %d", p_atomic_inc_return(&counter));
-
- if (!pvgpr) {
- LLVMTypeRef ftype = LLVMFunctionType(ctx->voidt, NULL, 0, false);
- LLVMValueRef inlineasm = LLVMConstInlineAsm(ftype, code, "", true, false);
- LLVMBuildCall(builder, inlineasm, NULL, 0, "");
- } else {
- LLVMTypeRef ftype = LLVMFunctionType(ctx->i32, &ctx->i32, 1, false);
- LLVMValueRef inlineasm = LLVMConstInlineAsm(ftype, code, "=v,0", true, false);
- LLVMValueRef vgpr = *pvgpr;
- LLVMTypeRef vgpr_type = LLVMTypeOf(vgpr);
- unsigned vgpr_size = llvm_get_type_size(vgpr_type);
- LLVMValueRef vgpr0;
-
- assert(vgpr_size % 4 == 0);
-
- vgpr = LLVMBuildBitCast(builder, vgpr, LLVMVectorType(ctx->i32, vgpr_size / 4), "");
- vgpr0 = LLVMBuildExtractElement(builder, vgpr, ctx->i32_0, "");
- vgpr0 = LLVMBuildCall(builder, inlineasm, &vgpr0, 1, "");
- vgpr = LLVMBuildInsertElement(builder, vgpr, vgpr0, ctx->i32_0, "");
- vgpr = LLVMBuildBitCast(builder, vgpr, vgpr_type, "");
-
- *pvgpr = vgpr;
- }
-}
-
-/* Combine these with & instead of |. */
-#define NOOP_WAITCNT 0xf7f
-#define LGKM_CNT 0x07f
-#define VM_CNT 0xf70
-
-static void emit_waitcnt(struct si_shader_context *ctx, unsigned simm16)
-{
- struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMBuilderRef builder = gallivm->builder;
- LLVMValueRef args[1] = {
- LLVMConstInt(ctx->i32, simm16, 0)
- };
- lp_build_intrinsic(builder, "llvm.amdgcn.s.waitcnt",
- ctx->voidt, args, 1, 0);
-}
-
-static void membar_emit(
- const struct lp_build_tgsi_action *action,
- struct lp_build_tgsi_context *bld_base,
- struct lp_build_emit_data *emit_data)
-{
- struct si_shader_context *ctx = si_shader_context(bld_base);
- LLVMValueRef src0 = lp_build_emit_fetch(bld_base, emit_data->inst, 0, 0);
- unsigned flags = LLVMConstIntGetZExtValue(src0);
- unsigned waitcnt = NOOP_WAITCNT;
-
- if (flags & TGSI_MEMBAR_THREAD_GROUP)
- waitcnt &= VM_CNT & LGKM_CNT;
-
- if (flags & (TGSI_MEMBAR_ATOMIC_BUFFER |
- TGSI_MEMBAR_SHADER_BUFFER |
- TGSI_MEMBAR_SHADER_IMAGE))
- waitcnt &= VM_CNT;
-
- if (flags & TGSI_MEMBAR_SHARED)
- waitcnt &= LGKM_CNT;
-
- if (waitcnt != NOOP_WAITCNT)
- emit_waitcnt(ctx, waitcnt);
-}
-
-static void clock_emit(
- const struct lp_build_tgsi_action *action,
- struct lp_build_tgsi_context *bld_base,
- struct lp_build_emit_data *emit_data)
-{
- struct si_shader_context *ctx = si_shader_context(bld_base);
- struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMValueRef tmp;
-
- tmp = lp_build_intrinsic(gallivm->builder, "llvm.readcyclecounter",
- ctx->i64, NULL, 0, 0);
- tmp = LLVMBuildBitCast(gallivm->builder, tmp, ctx->v2i32, "");
-
- emit_data->output[0] =
- LLVMBuildExtractElement(gallivm->builder, tmp, ctx->i32_0, "");
- emit_data->output[1] =
- LLVMBuildExtractElement(gallivm->builder, tmp, ctx->i32_1, "");
-}
-
-static LLVMValueRef
-shader_buffer_fetch_rsrc(struct si_shader_context *ctx,
- const struct tgsi_full_src_register *reg)
-{
- LLVMValueRef index;
- LLVMValueRef rsrc_ptr = LLVMGetParam(ctx->main_fn,
- ctx->param_shader_buffers);
-
- if (!reg->Register.Indirect)
- index = LLVMConstInt(ctx->i32, reg->Register.Index, 0);
- else
- index = get_bounded_indirect_index(ctx, ®->Indirect,
- reg->Register.Index,
- SI_NUM_SHADER_BUFFERS);
-
- return ac_build_indexed_load_const(&ctx->ac, rsrc_ptr, index);
-}
-
-static bool tgsi_is_array_sampler(unsigned target)
-{
- return target == TGSI_TEXTURE_1D_ARRAY ||
- target == TGSI_TEXTURE_SHADOW1D_ARRAY ||
- target == TGSI_TEXTURE_2D_ARRAY ||
- target == TGSI_TEXTURE_SHADOW2D_ARRAY ||
- target == TGSI_TEXTURE_CUBE_ARRAY ||
- target == TGSI_TEXTURE_SHADOWCUBE_ARRAY ||
- target == TGSI_TEXTURE_2D_ARRAY_MSAA;
-}
-
-static bool tgsi_is_array_image(unsigned target)
-{
- return target == TGSI_TEXTURE_3D ||
- target == TGSI_TEXTURE_CUBE ||
- target == TGSI_TEXTURE_1D_ARRAY ||
- target == TGSI_TEXTURE_2D_ARRAY ||
- target == TGSI_TEXTURE_CUBE_ARRAY ||
- target == TGSI_TEXTURE_2D_ARRAY_MSAA;
-}
-
-/**
- * Given a 256-bit resource descriptor, force the DCC enable bit to off.
- *
- * At least on Tonga, executing image stores on images with DCC enabled and
- * non-trivial can eventually lead to lockups. This can occur when an
- * application binds an image as read-only but then uses a shader that writes
- * to it. The OpenGL spec allows almost arbitrarily bad behavior (including
- * program termination) in this case, but it doesn't cost much to be a bit
- * nicer: disabling DCC in the shader still leads to undefined results but
- * avoids the lockup.
- */
-static LLVMValueRef force_dcc_off(struct si_shader_context *ctx,
- LLVMValueRef rsrc)
-{
- if (ctx->screen->b.chip_class <= CIK) {
- return rsrc;
- } else {
- LLVMBuilderRef builder = ctx->gallivm.builder;
- LLVMValueRef i32_6 = LLVMConstInt(ctx->i32, 6, 0);
- LLVMValueRef i32_C = LLVMConstInt(ctx->i32, C_008F28_COMPRESSION_EN, 0);
- LLVMValueRef tmp;
-
- tmp = LLVMBuildExtractElement(builder, rsrc, i32_6, "");
- tmp = LLVMBuildAnd(builder, tmp, i32_C, "");
- return LLVMBuildInsertElement(builder, rsrc, tmp, i32_6, "");
- }
-}
-
-static LLVMTypeRef const_array(LLVMTypeRef elem_type, int num_elements)
-{
- return LLVMPointerType(LLVMArrayType(elem_type, num_elements),
- CONST_ADDR_SPACE);
-}
-
-static LLVMValueRef load_image_desc(struct si_shader_context *ctx,
- LLVMValueRef list, LLVMValueRef index,
- unsigned target)
-{
- LLVMBuilderRef builder = ctx->gallivm.builder;
-
- if (target == TGSI_TEXTURE_BUFFER) {
- index = LLVMBuildMul(builder, index,
- LLVMConstInt(ctx->i32, 2, 0), "");
- index = LLVMBuildAdd(builder, index,
- ctx->i32_1, "");
- list = LLVMBuildPointerCast(builder, list,
- const_array(ctx->v4i32, 0), "");
- }
-
- return ac_build_indexed_load_const(&ctx->ac, list, index);
-}
-
-/**
- * Load the resource descriptor for \p image.
- */
-static void
-image_fetch_rsrc(
- struct lp_build_tgsi_context *bld_base,
- const struct tgsi_full_src_register *image,
- bool is_store, unsigned target,
- LLVMValueRef *rsrc)
-{
- struct si_shader_context *ctx = si_shader_context(bld_base);
- LLVMValueRef rsrc_ptr = LLVMGetParam(ctx->main_fn,
- ctx->param_images);
- LLVMValueRef index;
- bool dcc_off = is_store;
-
- assert(image->Register.File == TGSI_FILE_IMAGE);
-
- if (!image->Register.Indirect) {
- const struct tgsi_shader_info *info = bld_base->info;
- unsigned images_writemask = info->images_store |
- info->images_atomic;
-
- index = LLVMConstInt(ctx->i32, image->Register.Index, 0);
-
- if (images_writemask & (1 << image->Register.Index))
- dcc_off = true;
- } else {
- /* From the GL_ARB_shader_image_load_store extension spec:
- *
- * If a shader performs an image load, store, or atomic
- * operation using an image variable declared as an array,
- * and if the index used to select an individual element is
- * negative or greater than or equal to the size of the
- * array, the results of the operation are undefined but may
- * not lead to termination.
- */
- index = get_bounded_indirect_index(ctx, &image->Indirect,
- image->Register.Index,
- SI_NUM_IMAGES);
- }
-
- *rsrc = load_image_desc(ctx, rsrc_ptr, index, target);
- if (dcc_off && target != TGSI_TEXTURE_BUFFER)
- *rsrc = force_dcc_off(ctx, *rsrc);
-}
-
-static LLVMValueRef image_fetch_coords(
- struct lp_build_tgsi_context *bld_base,
- const struct tgsi_full_instruction *inst,
- unsigned src, LLVMValueRef desc)
-{
- struct si_shader_context *ctx = si_shader_context(bld_base);
- struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMBuilderRef builder = gallivm->builder;
- unsigned target = inst->Memory.Texture;
- unsigned num_coords = tgsi_util_get_texture_coord_dim(target);
- LLVMValueRef coords[4];
- LLVMValueRef tmp;
- int chan;
-
- for (chan = 0; chan < num_coords; ++chan) {
- tmp = lp_build_emit_fetch(bld_base, inst, src, chan);
- tmp = LLVMBuildBitCast(builder, tmp, ctx->i32, "");
- coords[chan] = tmp;
- }
-
- if (ctx->screen->b.chip_class >= GFX9) {
- /* 1D textures are allocated and used as 2D on GFX9. */
- if (target == TGSI_TEXTURE_1D) {
- coords[1] = ctx->i32_0;
- num_coords++;
- } else if (target == TGSI_TEXTURE_1D_ARRAY) {
- coords[2] = coords[1];
- coords[1] = ctx->i32_0;
- num_coords++;
- } else if (target == TGSI_TEXTURE_2D) {
- /* The hw can't bind a slice of a 3D image as a 2D
- * image, because it ignores BASE_ARRAY if the target
- * is 3D. The workaround is to read BASE_ARRAY and set
- * it as the 3rd address operand for all 2D images.
- */
- LLVMValueRef first_layer, const5, mask;
-
- const5 = LLVMConstInt(ctx->i32, 5, 0);
- mask = LLVMConstInt(ctx->i32, S_008F24_BASE_ARRAY(~0), 0);
- first_layer = LLVMBuildExtractElement(builder, desc, const5, "");
- first_layer = LLVMBuildAnd(builder, first_layer, mask, "");
-
- coords[2] = first_layer;
- num_coords++;
- }
- }
-
- if (num_coords == 1)
- return coords[0];
-
- if (num_coords == 3) {
- /* LLVM has difficulties lowering 3-element vectors. */
- coords[3] = bld_base->uint_bld.undef;
- num_coords = 4;
- }
-
- return lp_build_gather_values(gallivm, coords, num_coords);
-}
-
-/**
- * Append the extra mode bits that are used by image load and store.
- */
-static void image_append_args(
- struct si_shader_context *ctx,
- struct lp_build_emit_data * emit_data,
- unsigned target,
- bool atomic,
- bool force_glc)
-{
- const struct tgsi_full_instruction *inst = emit_data->inst;
- LLVMValueRef i1false = LLVMConstInt(ctx->i1, 0, 0);
- LLVMValueRef i1true = LLVMConstInt(ctx->i1, 1, 0);
- LLVMValueRef r128 = i1false;
- LLVMValueRef da = tgsi_is_array_image(target) ? i1true : i1false;
- LLVMValueRef glc =
- force_glc ||
- inst->Memory.Qualifier & (TGSI_MEMORY_COHERENT | TGSI_MEMORY_VOLATILE) ?
- i1true : i1false;
- LLVMValueRef slc = i1false;
- LLVMValueRef lwe = i1false;
-
- if (atomic || (HAVE_LLVM <= 0x0309)) {
- emit_data->args[emit_data->arg_count++] = r128;
- emit_data->args[emit_data->arg_count++] = da;
- if (!atomic) {
- emit_data->args[emit_data->arg_count++] = glc;
- }
- emit_data->args[emit_data->arg_count++] = slc;
- return;
- }
-
- /* HAVE_LLVM >= 0x0400 */
- emit_data->args[emit_data->arg_count++] = glc;
- emit_data->args[emit_data->arg_count++] = slc;
- emit_data->args[emit_data->arg_count++] = lwe;
- emit_data->args[emit_data->arg_count++] = da;
-}
-
-/**
- * Append the resource and indexing arguments for buffer intrinsics.
- *
- * \param rsrc the v4i32 buffer resource
- * \param index index into the buffer (stride-based)
- * \param offset byte offset into the buffer
- */
-static void buffer_append_args(
- struct si_shader_context *ctx,
- struct lp_build_emit_data *emit_data,
- LLVMValueRef rsrc,
- LLVMValueRef index,
- LLVMValueRef offset,
- bool atomic,
- bool force_glc)
-{
- const struct tgsi_full_instruction *inst = emit_data->inst;
- LLVMValueRef i1false = LLVMConstInt(ctx->i1, 0, 0);
- LLVMValueRef i1true = LLVMConstInt(ctx->i1, 1, 0);
-
- emit_data->args[emit_data->arg_count++] = rsrc;
- emit_data->args[emit_data->arg_count++] = index; /* vindex */
- emit_data->args[emit_data->arg_count++] = offset; /* voffset */
- if (!atomic) {
- emit_data->args[emit_data->arg_count++] =
- force_glc ||
- inst->Memory.Qualifier & (TGSI_MEMORY_COHERENT | TGSI_MEMORY_VOLATILE) ?
- i1true : i1false; /* glc */
- }
- emit_data->args[emit_data->arg_count++] = i1false; /* slc */
-}
-
-static void load_fetch_args(
- struct lp_build_tgsi_context * bld_base,
- struct lp_build_emit_data * emit_data)
-{
- struct si_shader_context *ctx = si_shader_context(bld_base);
- struct gallivm_state *gallivm = &ctx->gallivm;
- const struct tgsi_full_instruction * inst = emit_data->inst;
- unsigned target = inst->Memory.Texture;
- LLVMValueRef rsrc;
-
- emit_data->dst_type = ctx->v4f32;
-
- if (inst->Src[0].Register.File == TGSI_FILE_BUFFER) {
- LLVMBuilderRef builder = gallivm->builder;
- LLVMValueRef offset;
- LLVMValueRef tmp;
-
- rsrc = shader_buffer_fetch_rsrc(ctx, &inst->Src[0]);
-
- tmp = lp_build_emit_fetch(bld_base, inst, 1, 0);
- offset = LLVMBuildBitCast(builder, tmp, ctx->i32, "");
-
- buffer_append_args(ctx, emit_data, rsrc, ctx->i32_0,
- offset, false, false);
- } else if (inst->Src[0].Register.File == TGSI_FILE_IMAGE) {
- LLVMValueRef coords;
-
- image_fetch_rsrc(bld_base, &inst->Src[0], false, target, &rsrc);
- coords = image_fetch_coords(bld_base, inst, 1, rsrc);
-
- if (target == TGSI_TEXTURE_BUFFER) {
- buffer_append_args(ctx, emit_data, rsrc, coords,
- ctx->i32_0, false, false);
- } else {
- emit_data->args[0] = coords;
- emit_data->args[1] = rsrc;
- emit_data->args[2] = LLVMConstInt(ctx->i32, 15, 0); /* dmask */
- emit_data->arg_count = 3;
-
- image_append_args(ctx, emit_data, target, false, false);
- }
- }
-}
-
-static unsigned get_load_intr_attribs(bool readonly_memory)
-{
- /* READNONE means writes can't affect it, while READONLY means that
- * writes can affect it. */
- return readonly_memory && HAVE_LLVM >= 0x0400 ?
- LP_FUNC_ATTR_READNONE :
- LP_FUNC_ATTR_READONLY;
-}
-
-static unsigned get_store_intr_attribs(bool writeonly_memory)
-{
- return writeonly_memory && HAVE_LLVM >= 0x0400 ?
- LP_FUNC_ATTR_INACCESSIBLE_MEM_ONLY :
- LP_FUNC_ATTR_WRITEONLY;
-}
-
-static void load_emit_buffer(struct si_shader_context *ctx,
- struct lp_build_emit_data *emit_data,
- bool readonly_memory)
-{
- const struct tgsi_full_instruction *inst = emit_data->inst;
- struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMBuilderRef builder = gallivm->builder;
- uint writemask = inst->Dst[0].Register.WriteMask;
- uint count = util_last_bit(writemask);
- const char *intrinsic_name;
- LLVMTypeRef dst_type;
-
- switch (count) {
- case 1:
- intrinsic_name = "llvm.amdgcn.buffer.load.f32";
- dst_type = ctx->f32;
- break;
- case 2:
- intrinsic_name = "llvm.amdgcn.buffer.load.v2f32";
- dst_type = LLVMVectorType(ctx->f32, 2);
- break;
- default: // 3 & 4
- intrinsic_name = "llvm.amdgcn.buffer.load.v4f32";
- dst_type = ctx->v4f32;
- count = 4;
- }
-
- emit_data->output[emit_data->chan] = lp_build_intrinsic(
- builder, intrinsic_name, dst_type,
- emit_data->args, emit_data->arg_count,
- get_load_intr_attribs(readonly_memory));
-}
-
-static LLVMValueRef get_memory_ptr(struct si_shader_context *ctx,
- const struct tgsi_full_instruction *inst,
- LLVMTypeRef type, int arg)
-{
- struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMBuilderRef builder = gallivm->builder;
- LLVMValueRef offset, ptr;
- int addr_space;
-
- offset = lp_build_emit_fetch(&ctx->bld_base, inst, arg, 0);
- offset = LLVMBuildBitCast(builder, offset, ctx->i32, "");
-
- ptr = ctx->shared_memory;
- ptr = LLVMBuildGEP(builder, ptr, &offset, 1, "");
- addr_space = LLVMGetPointerAddressSpace(LLVMTypeOf(ptr));
- ptr = LLVMBuildBitCast(builder, ptr, LLVMPointerType(type, addr_space), "");
-
- return ptr;
-}
-
-static void load_emit_memory(
- struct si_shader_context *ctx,
- struct lp_build_emit_data *emit_data)
-{
- const struct tgsi_full_instruction *inst = emit_data->inst;
- struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMBuilderRef builder = gallivm->builder;
- unsigned writemask = inst->Dst[0].Register.WriteMask;
- LLVMValueRef channels[4], ptr, derived_ptr, index;
- int chan;
-
- ptr = get_memory_ptr(ctx, inst, ctx->f32, 1);
-
- for (chan = 0; chan < 4; ++chan) {
- if (!(writemask & (1 << chan))) {
- channels[chan] = LLVMGetUndef(ctx->f32);
- continue;
- }
-
- index = LLVMConstInt(ctx->i32, chan, 0);
- derived_ptr = LLVMBuildGEP(builder, ptr, &index, 1, "");
- channels[chan] = LLVMBuildLoad(builder, derived_ptr, "");
- }
- emit_data->output[emit_data->chan] = lp_build_gather_values(gallivm, channels, 4);
-}
-
-/**
- * Return true if the memory accessed by a LOAD or STORE instruction is
- * read-only or write-only, respectively.
- *
- * \param shader_buffers_reverse_access_mask
- * For LOAD, set this to (store | atomic) slot usage in the shader.
- * For STORE, set this to (load | atomic) slot usage in the shader.
- * \param images_reverse_access_mask Same as above, but for images.
- */
-static bool is_oneway_access_only(const struct tgsi_full_instruction *inst,
- const struct tgsi_shader_info *info,
- unsigned shader_buffers_reverse_access_mask,
- unsigned images_reverse_access_mask)
-{
- /* RESTRICT means NOALIAS.
- * If there are no writes, we can assume the accessed memory is read-only.
- * If there are no reads, we can assume the accessed memory is write-only.
- */
- if (inst->Memory.Qualifier & TGSI_MEMORY_RESTRICT) {
- unsigned reverse_access_mask;
-
- if (inst->Src[0].Register.File == TGSI_FILE_BUFFER) {
- reverse_access_mask = shader_buffers_reverse_access_mask;
- } else if (inst->Memory.Texture == TGSI_TEXTURE_BUFFER) {
- reverse_access_mask = info->images_buffers &
- images_reverse_access_mask;
- } else {
- reverse_access_mask = ~info->images_buffers &
- images_reverse_access_mask;
- }
-
- if (inst->Src[0].Register.Indirect) {
- if (!reverse_access_mask)
- return true;
- } else {
- if (!(reverse_access_mask &
- (1u << inst->Src[0].Register.Index)))
- return true;
- }
- }
-
- /* If there are no buffer writes (for both shader buffers & image
- * buffers), it implies that buffer memory is read-only.
- * If there are no buffer reads (for both shader buffers & image
- * buffers), it implies that buffer memory is write-only.
- *
- * Same for the case when there are no writes/reads for non-buffer
- * images.
- */
- if (inst->Src[0].Register.File == TGSI_FILE_BUFFER ||
- (inst->Src[0].Register.File == TGSI_FILE_IMAGE &&
- inst->Memory.Texture == TGSI_TEXTURE_BUFFER)) {
- if (!shader_buffers_reverse_access_mask &&
- !(info->images_buffers & images_reverse_access_mask))
- return true;
- } else {
- if (!(~info->images_buffers & images_reverse_access_mask))
- return true;
- }
- return false;
-}
-
-static void load_emit(
- const struct lp_build_tgsi_action *action,
- struct lp_build_tgsi_context *bld_base,
- struct lp_build_emit_data *emit_data)
-{
- struct si_shader_context *ctx = si_shader_context(bld_base);
- struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMBuilderRef builder = gallivm->builder;
- const struct tgsi_full_instruction * inst = emit_data->inst;
- const struct tgsi_shader_info *info = &ctx->shader->selector->info;
- char intrinsic_name[64];
- bool readonly_memory = false;
-
- if (inst->Src[0].Register.File == TGSI_FILE_MEMORY) {
- load_emit_memory(ctx, emit_data);
- return;
- }
-
- if (inst->Memory.Qualifier & TGSI_MEMORY_VOLATILE)
- emit_waitcnt(ctx, VM_CNT);
-
- readonly_memory = !(inst->Memory.Qualifier & TGSI_MEMORY_VOLATILE) &&
- is_oneway_access_only(inst, info,
- info->shader_buffers_store |
- info->shader_buffers_atomic,
- info->images_store |
- info->images_atomic);
-
- if (inst->Src[0].Register.File == TGSI_FILE_BUFFER) {
- load_emit_buffer(ctx, emit_data, readonly_memory);
- return;
- }
-
- if (inst->Memory.Texture == TGSI_TEXTURE_BUFFER) {
- emit_data->output[emit_data->chan] =
- lp_build_intrinsic(
- builder, "llvm.amdgcn.buffer.load.format.v4f32", emit_data->dst_type,
- emit_data->args, emit_data->arg_count,
- get_load_intr_attribs(readonly_memory));
- } else {
- ac_get_image_intr_name("llvm.amdgcn.image.load",
- emit_data->dst_type, /* vdata */
- LLVMTypeOf(emit_data->args[0]), /* coords */
- LLVMTypeOf(emit_data->args[1]), /* rsrc */
- intrinsic_name, sizeof(intrinsic_name));
-
- emit_data->output[emit_data->chan] =
- lp_build_intrinsic(
- builder, intrinsic_name, emit_data->dst_type,
- emit_data->args, emit_data->arg_count,
- get_load_intr_attribs(readonly_memory));
- }
-}
-
-static void store_fetch_args(
- struct lp_build_tgsi_context * bld_base,
- struct lp_build_emit_data * emit_data)
-{
- struct si_shader_context *ctx = si_shader_context(bld_base);
- struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMBuilderRef builder = gallivm->builder;
- const struct tgsi_full_instruction * inst = emit_data->inst;
- struct tgsi_full_src_register memory;
- LLVMValueRef chans[4];
- LLVMValueRef data;
- LLVMValueRef rsrc;
- unsigned chan;
-
- emit_data->dst_type = LLVMVoidTypeInContext(gallivm->context);
-
- for (chan = 0; chan < 4; ++chan) {
- chans[chan] = lp_build_emit_fetch(bld_base, inst, 1, chan);
- }
- data = lp_build_gather_values(gallivm, chans, 4);
-
- emit_data->args[emit_data->arg_count++] = data;
-
- memory = tgsi_full_src_register_from_dst(&inst->Dst[0]);
-
- if (inst->Dst[0].Register.File == TGSI_FILE_BUFFER) {
- LLVMValueRef offset;
- LLVMValueRef tmp;
-
- rsrc = shader_buffer_fetch_rsrc(ctx, &memory);
-
- tmp = lp_build_emit_fetch(bld_base, inst, 0, 0);
- offset = LLVMBuildBitCast(builder, tmp, ctx->i32, "");
-
- buffer_append_args(ctx, emit_data, rsrc, ctx->i32_0,
- offset, false, false);
- } else if (inst->Dst[0].Register.File == TGSI_FILE_IMAGE) {
- unsigned target = inst->Memory.Texture;
- LLVMValueRef coords;
-
- /* 8bit/16bit TC L1 write corruption bug on SI.
- * All store opcodes not aligned to a dword are affected.
- *
- * The only way to get unaligned stores in radeonsi is through
- * shader images.
- */
- bool force_glc = ctx->screen->b.chip_class == SI;
-
- image_fetch_rsrc(bld_base, &memory, true, target, &rsrc);
- coords = image_fetch_coords(bld_base, inst, 0, rsrc);
-
- if (target == TGSI_TEXTURE_BUFFER) {
- buffer_append_args(ctx, emit_data, rsrc, coords,
- ctx->i32_0, false, force_glc);
- } else {
- emit_data->args[1] = coords;
- emit_data->args[2] = rsrc;
- emit_data->args[3] = LLVMConstInt(ctx->i32, 15, 0); /* dmask */
- emit_data->arg_count = 4;
-
- image_append_args(ctx, emit_data, target, false, force_glc);
- }
- }
-}
-
-static void store_emit_buffer(
- struct si_shader_context *ctx,
- struct lp_build_emit_data *emit_data,
- bool writeonly_memory)
-{
- const struct tgsi_full_instruction *inst = emit_data->inst;
- struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMBuilderRef builder = gallivm->builder;
- LLVMValueRef base_data = emit_data->args[0];
- LLVMValueRef base_offset = emit_data->args[3];
- unsigned writemask = inst->Dst[0].Register.WriteMask;
-
- while (writemask) {
- int start, count;
- const char *intrinsic_name;
- LLVMValueRef data;
- LLVMValueRef offset;
- LLVMValueRef tmp;
-
- u_bit_scan_consecutive_range(&writemask, &start, &count);
-
- /* Due to an LLVM limitation, split 3-element writes
- * into a 2-element and a 1-element write. */
- if (count == 3) {
- writemask |= 1 << (start + 2);
- count = 2;
- }
-
- if (count == 4) {
- data = base_data;
- intrinsic_name = "llvm.amdgcn.buffer.store.v4f32";
- } else if (count == 2) {
- LLVMTypeRef v2f32 = LLVMVectorType(ctx->f32, 2);
-
- tmp = LLVMBuildExtractElement(
- builder, base_data,
- LLVMConstInt(ctx->i32, start, 0), "");
- data = LLVMBuildInsertElement(
- builder, LLVMGetUndef(v2f32), tmp,
- ctx->i32_0, "");
-
- tmp = LLVMBuildExtractElement(
- builder, base_data,
- LLVMConstInt(ctx->i32, start + 1, 0), "");
- data = LLVMBuildInsertElement(
- builder, data, tmp, ctx->i32_1, "");
-
- intrinsic_name = "llvm.amdgcn.buffer.store.v2f32";
- } else {
- assert(count == 1);
- data = LLVMBuildExtractElement(
- builder, base_data,
- LLVMConstInt(ctx->i32, start, 0), "");
- intrinsic_name = "llvm.amdgcn.buffer.store.f32";
- }
-
- offset = base_offset;
- if (start != 0) {
- offset = LLVMBuildAdd(
- builder, offset,
- LLVMConstInt(ctx->i32, start * 4, 0), "");
- }
-
- emit_data->args[0] = data;
- emit_data->args[3] = offset;
-
- lp_build_intrinsic(
- builder, intrinsic_name, emit_data->dst_type,
- emit_data->args, emit_data->arg_count,
- get_store_intr_attribs(writeonly_memory));
- }
-}
-
-static void store_emit_memory(
- struct si_shader_context *ctx,
- struct lp_build_emit_data *emit_data)
-{
- const struct tgsi_full_instruction *inst = emit_data->inst;
- struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMBuilderRef builder = gallivm->builder;
- unsigned writemask = inst->Dst[0].Register.WriteMask;
- LLVMValueRef ptr, derived_ptr, data, index;
- int chan;
-
- ptr = get_memory_ptr(ctx, inst, ctx->f32, 0);
-
- for (chan = 0; chan < 4; ++chan) {
- if (!(writemask & (1 << chan))) {
- continue;
- }
- data = lp_build_emit_fetch(&ctx->bld_base, inst, 1, chan);
- index = LLVMConstInt(ctx->i32, chan, 0);
- derived_ptr = LLVMBuildGEP(builder, ptr, &index, 1, "");
- LLVMBuildStore(builder, data, derived_ptr);
- }
-}
-
-static void store_emit(
- const struct lp_build_tgsi_action *action,
- struct lp_build_tgsi_context *bld_base,
- struct lp_build_emit_data *emit_data)
-{
- struct si_shader_context *ctx = si_shader_context(bld_base);
- struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMBuilderRef builder = gallivm->builder;
- const struct tgsi_full_instruction * inst = emit_data->inst;
- const struct tgsi_shader_info *info = &ctx->shader->selector->info;
- unsigned target = inst->Memory.Texture;
- char intrinsic_name[64];
- bool writeonly_memory = false;
-
- if (inst->Dst[0].Register.File == TGSI_FILE_MEMORY) {
- store_emit_memory(ctx, emit_data);
- return;
- }
-
- if (inst->Memory.Qualifier & TGSI_MEMORY_VOLATILE)
- emit_waitcnt(ctx, VM_CNT);
-
- writeonly_memory = is_oneway_access_only(inst, info,
- info->shader_buffers_load |
- info->shader_buffers_atomic,
- info->images_load |
- info->images_atomic);
-
- if (inst->Dst[0].Register.File == TGSI_FILE_BUFFER) {
- store_emit_buffer(ctx, emit_data, writeonly_memory);
- return;
- }
-
- if (target == TGSI_TEXTURE_BUFFER) {
- emit_data->output[emit_data->chan] = lp_build_intrinsic(
- builder, "llvm.amdgcn.buffer.store.format.v4f32",
- emit_data->dst_type, emit_data->args,
- emit_data->arg_count,
- get_store_intr_attribs(writeonly_memory));
- } else {
- ac_get_image_intr_name("llvm.amdgcn.image.store",
- LLVMTypeOf(emit_data->args[0]), /* vdata */
- LLVMTypeOf(emit_data->args[1]), /* coords */
- LLVMTypeOf(emit_data->args[2]), /* rsrc */
- intrinsic_name, sizeof(intrinsic_name));
-
- emit_data->output[emit_data->chan] =
- lp_build_intrinsic(
- builder, intrinsic_name, emit_data->dst_type,
- emit_data->args, emit_data->arg_count,
- get_store_intr_attribs(writeonly_memory));
- }
-}
-
-static void atomic_fetch_args(
- struct lp_build_tgsi_context * bld_base,
- struct lp_build_emit_data * emit_data)
-{
- struct si_shader_context *ctx = si_shader_context(bld_base);
- struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMBuilderRef builder = gallivm->builder;
- const struct tgsi_full_instruction * inst = emit_data->inst;
- LLVMValueRef data1, data2;
- LLVMValueRef rsrc;
- LLVMValueRef tmp;
-
- emit_data->dst_type = ctx->f32;
-
- tmp = lp_build_emit_fetch(bld_base, inst, 2, 0);
- data1 = LLVMBuildBitCast(builder, tmp, ctx->i32, "");
-
- if (inst->Instruction.Opcode == TGSI_OPCODE_ATOMCAS) {
- tmp = lp_build_emit_fetch(bld_base, inst, 3, 0);
- data2 = LLVMBuildBitCast(builder, tmp, ctx->i32, "");
- }
-
- /* llvm.amdgcn.image/buffer.atomic.cmpswap reflect the hardware order
- * of arguments, which is reversed relative to TGSI (and GLSL)
- */
- if (inst->Instruction.Opcode == TGSI_OPCODE_ATOMCAS)
- emit_data->args[emit_data->arg_count++] = data2;
- emit_data->args[emit_data->arg_count++] = data1;
-
- if (inst->Src[0].Register.File == TGSI_FILE_BUFFER) {
- LLVMValueRef offset;
-
- rsrc = shader_buffer_fetch_rsrc(ctx, &inst->Src[0]);
-
- tmp = lp_build_emit_fetch(bld_base, inst, 1, 0);
- offset = LLVMBuildBitCast(builder, tmp, ctx->i32, "");
-
- buffer_append_args(ctx, emit_data, rsrc, ctx->i32_0,
- offset, true, false);
- } else if (inst->Src[0].Register.File == TGSI_FILE_IMAGE) {
- unsigned target = inst->Memory.Texture;
- LLVMValueRef coords;
-
- image_fetch_rsrc(bld_base, &inst->Src[0], true, target, &rsrc);
- coords = image_fetch_coords(bld_base, inst, 1, rsrc);
-
- if (target == TGSI_TEXTURE_BUFFER) {
- buffer_append_args(ctx, emit_data, rsrc, coords,
- ctx->i32_0, true, false);
- } else {
- emit_data->args[emit_data->arg_count++] = coords;
- emit_data->args[emit_data->arg_count++] = rsrc;
-
- image_append_args(ctx, emit_data, target, true, false);
- }
- }
-}
-
-static void atomic_emit_memory(struct si_shader_context *ctx,
- struct lp_build_emit_data *emit_data) {
- struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMBuilderRef builder = gallivm->builder;
- const struct tgsi_full_instruction * inst = emit_data->inst;
- LLVMValueRef ptr, result, arg;
-
- ptr = get_memory_ptr(ctx, inst, ctx->i32, 1);
-
- arg = lp_build_emit_fetch(&ctx->bld_base, inst, 2, 0);
- arg = LLVMBuildBitCast(builder, arg, ctx->i32, "");
-
- if (inst->Instruction.Opcode == TGSI_OPCODE_ATOMCAS) {
- LLVMValueRef new_data;
- new_data = lp_build_emit_fetch(&ctx->bld_base,
- inst, 3, 0);
-
- new_data = LLVMBuildBitCast(builder, new_data, ctx->i32, "");
-
- result = LLVMBuildAtomicCmpXchg(builder, ptr, arg, new_data,
- LLVMAtomicOrderingSequentiallyConsistent,
- LLVMAtomicOrderingSequentiallyConsistent,
- false);
-
- result = LLVMBuildExtractValue(builder, result, 0, "");
- } else {
- LLVMAtomicRMWBinOp op;
-
- switch(inst->Instruction.Opcode) {
- case TGSI_OPCODE_ATOMUADD:
- op = LLVMAtomicRMWBinOpAdd;
- break;
- case TGSI_OPCODE_ATOMXCHG:
- op = LLVMAtomicRMWBinOpXchg;
- break;
- case TGSI_OPCODE_ATOMAND:
- op = LLVMAtomicRMWBinOpAnd;
- break;
- case TGSI_OPCODE_ATOMOR:
- op = LLVMAtomicRMWBinOpOr;
- break;
- case TGSI_OPCODE_ATOMXOR:
- op = LLVMAtomicRMWBinOpXor;
- break;
- case TGSI_OPCODE_ATOMUMIN:
- op = LLVMAtomicRMWBinOpUMin;
- break;
- case TGSI_OPCODE_ATOMUMAX:
- op = LLVMAtomicRMWBinOpUMax;
- break;
- case TGSI_OPCODE_ATOMIMIN:
- op = LLVMAtomicRMWBinOpMin;
- break;
- case TGSI_OPCODE_ATOMIMAX:
- op = LLVMAtomicRMWBinOpMax;
- break;
- default:
- unreachable("unknown atomic opcode");
- }
-
- result = LLVMBuildAtomicRMW(builder, op, ptr, arg,
- LLVMAtomicOrderingSequentiallyConsistent,
- false);
- }
- emit_data->output[emit_data->chan] = LLVMBuildBitCast(builder, result, emit_data->dst_type, "");
-}
-
-static void atomic_emit(
- const struct lp_build_tgsi_action *action,
- struct lp_build_tgsi_context *bld_base,
- struct lp_build_emit_data *emit_data)
-{
- struct si_shader_context *ctx = si_shader_context(bld_base);
- struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMBuilderRef builder = gallivm->builder;
- const struct tgsi_full_instruction * inst = emit_data->inst;
- char intrinsic_name[40];
- LLVMValueRef tmp;
-
- if (inst->Src[0].Register.File == TGSI_FILE_MEMORY) {
- atomic_emit_memory(ctx, emit_data);
- return;
- }
-
- if (inst->Src[0].Register.File == TGSI_FILE_BUFFER ||
- inst->Memory.Texture == TGSI_TEXTURE_BUFFER) {
- snprintf(intrinsic_name, sizeof(intrinsic_name),
- "llvm.amdgcn.buffer.atomic.%s", action->intr_name);
- } else {
- LLVMValueRef coords;
- char coords_type[8];
-
- if (inst->Instruction.Opcode == TGSI_OPCODE_ATOMCAS)
- coords = emit_data->args[2];
- else
- coords = emit_data->args[1];
-
- ac_build_type_name_for_intr(LLVMTypeOf(coords), coords_type, sizeof(coords_type));
- snprintf(intrinsic_name, sizeof(intrinsic_name),
- "llvm.amdgcn.image.atomic.%s.%s",
- action->intr_name, coords_type);
- }
-
- tmp = lp_build_intrinsic(
- builder, intrinsic_name, ctx->i32,
- emit_data->args, emit_data->arg_count, 0);
- emit_data->output[emit_data->chan] =
- LLVMBuildBitCast(builder, tmp, ctx->f32, "");
-}
-
-static void set_tex_fetch_args(struct si_shader_context *ctx,
- struct lp_build_emit_data *emit_data,
- unsigned target,
- LLVMValueRef res_ptr, LLVMValueRef samp_ptr,
- LLVMValueRef *param, unsigned count,
- unsigned dmask)
-{
- struct gallivm_state *gallivm = &ctx->gallivm;
- struct ac_image_args args = {};
-
- /* Pad to power of two vector */
- while (count < util_next_power_of_two(count))
- param[count++] = LLVMGetUndef(ctx->i32);
-
- if (count > 1)
- args.addr = lp_build_gather_values(gallivm, param, count);
- else
- args.addr = param[0];
-
- args.resource = res_ptr;
- args.sampler = samp_ptr;
- args.dmask = dmask;
- args.unorm = target == TGSI_TEXTURE_RECT ||
- target == TGSI_TEXTURE_SHADOWRECT;
- args.da = tgsi_is_array_sampler(target);
-
- /* Ugly, but we seem to have no other choice right now. */
- STATIC_ASSERT(sizeof(args) <= sizeof(emit_data->args));
- memcpy(emit_data->args, &args, sizeof(args));
-}
-
-static LLVMValueRef fix_resinfo(struct si_shader_context *ctx,
- unsigned target, LLVMValueRef out)
-{
- LLVMBuilderRef builder = ctx->gallivm.builder;
-
- /* 1D textures are allocated and used as 2D on GFX9. */
- if (ctx->screen->b.chip_class >= GFX9 &&
- (target == TGSI_TEXTURE_1D_ARRAY ||
- target == TGSI_TEXTURE_SHADOW1D_ARRAY)) {
- LLVMValueRef layers =
- LLVMBuildExtractElement(builder, out,
- LLVMConstInt(ctx->i32, 2, 0), "");
- out = LLVMBuildInsertElement(builder, out, layers,
- ctx->i32_1, "");
- }
-
- /* Divide the number of layers by 6 to get the number of cubes. */
- if (target == TGSI_TEXTURE_CUBE_ARRAY ||
- target == TGSI_TEXTURE_SHADOWCUBE_ARRAY) {
- LLVMValueRef imm2 = LLVMConstInt(ctx->i32, 2, 0);
-
- LLVMValueRef z = LLVMBuildExtractElement(builder, out, imm2, "");
- z = LLVMBuildSDiv(builder, z, LLVMConstInt(ctx->i32, 6, 0), "");
-
- out = LLVMBuildInsertElement(builder, out, z, imm2, "");
- }
- return out;
-}
-
-static void resq_fetch_args(
- struct lp_build_tgsi_context * bld_base,
- struct lp_build_emit_data * emit_data)
-{
- struct si_shader_context *ctx = si_shader_context(bld_base);
- const struct tgsi_full_instruction *inst = emit_data->inst;
- const struct tgsi_full_src_register *reg = &inst->Src[0];
-
- emit_data->dst_type = ctx->v4i32;
-
- if (reg->Register.File == TGSI_FILE_BUFFER) {
- emit_data->args[0] = shader_buffer_fetch_rsrc(ctx, reg);
- emit_data->arg_count = 1;
- } else if (inst->Memory.Texture == TGSI_TEXTURE_BUFFER) {
- image_fetch_rsrc(bld_base, reg, false, inst->Memory.Texture,
- &emit_data->args[0]);
- emit_data->arg_count = 1;
- } else {
- LLVMValueRef res_ptr;
- unsigned image_target;
-
- if (inst->Memory.Texture == TGSI_TEXTURE_3D)
- image_target = TGSI_TEXTURE_2D_ARRAY;
- else
- image_target = inst->Memory.Texture;
-
- image_fetch_rsrc(bld_base, reg, false, inst->Memory.Texture,
- &res_ptr);
- set_tex_fetch_args(ctx, emit_data, image_target,
- res_ptr, NULL, &ctx->i32_0, 1,
- 0xf);
- }
-}
-
-static void resq_emit(
- const struct lp_build_tgsi_action *action,
- struct lp_build_tgsi_context *bld_base,
- struct lp_build_emit_data *emit_data)
-{
- struct si_shader_context *ctx = si_shader_context(bld_base);
- struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMBuilderRef builder = gallivm->builder;
- const struct tgsi_full_instruction *inst = emit_data->inst;
- LLVMValueRef out;
-
- if (inst->Src[0].Register.File == TGSI_FILE_BUFFER) {
- out = LLVMBuildExtractElement(builder, emit_data->args[0],
- LLVMConstInt(ctx->i32, 2, 0), "");
- } else if (inst->Memory.Texture == TGSI_TEXTURE_BUFFER) {
- out = get_buffer_size(bld_base, emit_data->args[0]);
- } else {
- struct ac_image_args args;
-
- memcpy(&args, emit_data->args, sizeof(args)); /* ugly */
- args.opcode = ac_image_get_resinfo;
- out = ac_build_image_opcode(&ctx->ac, &args);
-
- out = fix_resinfo(ctx, inst->Memory.Texture, out);
- }
-
- emit_data->output[emit_data->chan] = out;
-}
-
-static const struct lp_build_tgsi_action tex_action;
-
-enum desc_type {
- DESC_IMAGE,
- DESC_BUFFER,
- DESC_FMASK,
- DESC_SAMPLER,
-};
-
-/**
- * Load an image view, fmask view. or sampler state descriptor.
- */
-static LLVMValueRef load_sampler_desc(struct si_shader_context *ctx,
- LLVMValueRef list, LLVMValueRef index,
- enum desc_type type)
-{
- struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMBuilderRef builder = gallivm->builder;
-
- switch (type) {
- case DESC_IMAGE:
- /* The image is at [0:7]. */
- index = LLVMBuildMul(builder, index, LLVMConstInt(ctx->i32, 2, 0), "");
- break;
- case DESC_BUFFER:
- /* The buffer is in [4:7]. */
- index = LLVMBuildMul(builder, index, LLVMConstInt(ctx->i32, 4, 0), "");
- index = LLVMBuildAdd(builder, index, ctx->i32_1, "");
- list = LLVMBuildPointerCast(builder, list,
- const_array(ctx->v4i32, 0), "");
- break;
- case DESC_FMASK:
- /* The FMASK is at [8:15]. */
- index = LLVMBuildMul(builder, index, LLVMConstInt(ctx->i32, 2, 0), "");
- index = LLVMBuildAdd(builder, index, ctx->i32_1, "");
- break;
- case DESC_SAMPLER:
- /* The sampler state is at [12:15]. */
- index = LLVMBuildMul(builder, index, LLVMConstInt(ctx->i32, 4, 0), "");
- index = LLVMBuildAdd(builder, index, LLVMConstInt(ctx->i32, 3, 0), "");
- list = LLVMBuildPointerCast(builder, list,
- const_array(ctx->v4i32, 0), "");
- break;
- }
-
- return ac_build_indexed_load_const(&ctx->ac, list, index);
-}
-
-/* Disable anisotropic filtering if BASE_LEVEL == LAST_LEVEL.
- *
- * SI-CI:
- * If BASE_LEVEL == LAST_LEVEL, the shader must disable anisotropic
- * filtering manually. The driver sets img7 to a mask clearing
- * MAX_ANISO_RATIO if BASE_LEVEL == LAST_LEVEL. The shader must do:
- * s_and_b32 samp0, samp0, img7
- *
- * VI:
- * The ANISO_OVERRIDE sampler field enables this fix in TA.
- */
-static LLVMValueRef sici_fix_sampler_aniso(struct si_shader_context *ctx,
- LLVMValueRef res, LLVMValueRef samp)
-{
- LLVMBuilderRef builder = ctx->gallivm.builder;
- LLVMValueRef img7, samp0;
-
- if (ctx->screen->b.chip_class >= VI)
- return samp;
-
- img7 = LLVMBuildExtractElement(builder, res,
- LLVMConstInt(ctx->i32, 7, 0), "");
- samp0 = LLVMBuildExtractElement(builder, samp,
- ctx->i32_0, "");
- samp0 = LLVMBuildAnd(builder, samp0, img7, "");
- return LLVMBuildInsertElement(builder, samp, samp0,
- ctx->i32_0, "");
-}
-
-static void tex_fetch_ptrs(
- struct lp_build_tgsi_context *bld_base,
- struct lp_build_emit_data *emit_data,
- LLVMValueRef *res_ptr, LLVMValueRef *samp_ptr, LLVMValueRef *fmask_ptr)
-{
- struct si_shader_context *ctx = si_shader_context(bld_base);
- LLVMValueRef list = LLVMGetParam(ctx->main_fn, ctx->param_samplers);
- const struct tgsi_full_instruction *inst = emit_data->inst;
- const struct tgsi_full_src_register *reg;
- unsigned target = inst->Texture.Texture;
- unsigned sampler_src;
- LLVMValueRef index;
-
- sampler_src = emit_data->inst->Instruction.NumSrcRegs - 1;
- reg = &emit_data->inst->Src[sampler_src];
-
- if (reg->Register.Indirect) {
- index = get_bounded_indirect_index(ctx,
- ®->Indirect,
- reg->Register.Index,
- SI_NUM_SAMPLERS);
- } else {
- index = LLVMConstInt(ctx->i32, reg->Register.Index, 0);
- }
-
- if (target == TGSI_TEXTURE_BUFFER)
- *res_ptr = load_sampler_desc(ctx, list, index, DESC_BUFFER);
- else
- *res_ptr = load_sampler_desc(ctx, list, index, DESC_IMAGE);
-
- if (samp_ptr)
- *samp_ptr = NULL;
- if (fmask_ptr)
- *fmask_ptr = NULL;
-
- if (target == TGSI_TEXTURE_2D_MSAA ||
- target == TGSI_TEXTURE_2D_ARRAY_MSAA) {
- if (fmask_ptr)
- *fmask_ptr = load_sampler_desc(ctx, list, index,
- DESC_FMASK);
- } else if (target != TGSI_TEXTURE_BUFFER) {
- if (samp_ptr) {
- *samp_ptr = load_sampler_desc(ctx, list, index,
- DESC_SAMPLER);
- *samp_ptr = sici_fix_sampler_aniso(ctx, *res_ptr, *samp_ptr);
- }
- }
-}
-
-static void txq_fetch_args(
- struct lp_build_tgsi_context *bld_base,
- struct lp_build_emit_data *emit_data)
-{
- struct si_shader_context *ctx = si_shader_context(bld_base);
- const struct tgsi_full_instruction *inst = emit_data->inst;
- unsigned target = inst->Texture.Texture;
- LLVMValueRef res_ptr;
- LLVMValueRef address;
-
- tex_fetch_ptrs(bld_base, emit_data, &res_ptr, NULL, NULL);
-
- if (target == TGSI_TEXTURE_BUFFER) {
- /* Read the size from the buffer descriptor directly. */
- emit_data->args[0] = get_buffer_size(bld_base, res_ptr);
- return;
- }
-
- /* Textures - set the mip level. */
- address = lp_build_emit_fetch(bld_base, inst, 0, TGSI_CHAN_X);
-
- set_tex_fetch_args(ctx, emit_data, target, res_ptr,
- NULL, &address, 1, 0xf);
-}
-
-static void txq_emit(const struct lp_build_tgsi_action *action,
- struct lp_build_tgsi_context *bld_base,
- struct lp_build_emit_data *emit_data)
-{
- struct si_shader_context *ctx = si_shader_context(bld_base);
- struct ac_image_args args;
- unsigned target = emit_data->inst->Texture.Texture;
-
- if (target == TGSI_TEXTURE_BUFFER) {
- /* Just return the buffer size. */
- emit_data->output[emit_data->chan] = emit_data->args[0];
- return;
- }
-
- memcpy(&args, emit_data->args, sizeof(args)); /* ugly */
-
- args.opcode = ac_image_get_resinfo;
- LLVMValueRef result = ac_build_image_opcode(&ctx->ac, &args);
-
- emit_data->output[emit_data->chan] = fix_resinfo(ctx, target, result);
-}
-
-static void tex_fetch_args(
- struct lp_build_tgsi_context *bld_base,
- struct lp_build_emit_data *emit_data)
-{
- struct si_shader_context *ctx = si_shader_context(bld_base);
- struct gallivm_state *gallivm = &ctx->gallivm;
- const struct tgsi_full_instruction *inst = emit_data->inst;
- unsigned opcode = inst->Instruction.Opcode;
- unsigned target = inst->Texture.Texture;
- LLVMValueRef coords[5], derivs[6];
- LLVMValueRef address[16];
- unsigned num_coords = tgsi_util_get_texture_coord_dim(target);
- int ref_pos = tgsi_util_get_shadow_ref_src_index(target);
- unsigned count = 0;
- unsigned chan;
- unsigned num_deriv_channels = 0;
- bool has_offset = inst->Texture.NumOffsets > 0;
- LLVMValueRef res_ptr, samp_ptr, fmask_ptr = NULL;
- unsigned dmask = 0xf;
-
- tex_fetch_ptrs(bld_base, emit_data, &res_ptr, &samp_ptr, &fmask_ptr);
-
- if (target == TGSI_TEXTURE_BUFFER) {
- emit_data->dst_type = ctx->v4f32;
- emit_data->args[0] = res_ptr;
- emit_data->args[1] = ctx->i32_0;
- emit_data->args[2] = lp_build_emit_fetch(bld_base, emit_data->inst, 0, TGSI_CHAN_X);
- emit_data->arg_count = 3;
- return;
- }
-
- /* Fetch and project texture coordinates */
- coords[3] = lp_build_emit_fetch(bld_base, emit_data->inst, 0, TGSI_CHAN_W);
- for (chan = 0; chan < 3; chan++ ) {
- coords[chan] = lp_build_emit_fetch(bld_base,
- emit_data->inst, 0,
- chan);
- if (opcode == TGSI_OPCODE_TXP)
- coords[chan] = lp_build_emit_llvm_binary(bld_base,
- TGSI_OPCODE_DIV,
- coords[chan],
- coords[3]);
- }
-
- if (opcode == TGSI_OPCODE_TXP)
- coords[3] = bld_base->base.one;
-
- /* Pack offsets. */
- if (has_offset &&
- opcode != TGSI_OPCODE_TXF &&
- opcode != TGSI_OPCODE_TXF_LZ) {
- /* The offsets are six-bit signed integers packed like this:
- * X=[5:0], Y=[13:8], and Z=[21:16].
- */
- LLVMValueRef offset[3], pack;
-
- assert(inst->Texture.NumOffsets == 1);
-
- for (chan = 0; chan < 3; chan++) {
- offset[chan] = lp_build_emit_fetch_texoffset(bld_base,
- emit_data->inst, 0, chan);
- offset[chan] = LLVMBuildAnd(gallivm->builder, offset[chan],
- LLVMConstInt(ctx->i32, 0x3f, 0), "");
- if (chan)
- offset[chan] = LLVMBuildShl(gallivm->builder, offset[chan],
- LLVMConstInt(ctx->i32, chan*8, 0), "");
- }
-
- pack = LLVMBuildOr(gallivm->builder, offset[0], offset[1], "");
- pack = LLVMBuildOr(gallivm->builder, pack, offset[2], "");
- address[count++] = pack;
- }
-
- /* Pack LOD bias value */
- if (opcode == TGSI_OPCODE_TXB)
- address[count++] = coords[3];
- if (opcode == TGSI_OPCODE_TXB2)
- address[count++] = lp_build_emit_fetch(bld_base, inst, 1, TGSI_CHAN_X);
-
- /* Pack depth comparison value */
- if (tgsi_is_shadow_target(target) && opcode != TGSI_OPCODE_LODQ) {
- LLVMValueRef z;
-
- if (target == TGSI_TEXTURE_SHADOWCUBE_ARRAY) {
- z = lp_build_emit_fetch(bld_base, inst, 1, TGSI_CHAN_X);
- } else {
- assert(ref_pos >= 0);
- z = coords[ref_pos];
- }
-
- /* TC-compatible HTILE promotes Z16 and Z24 to Z32_FLOAT,
- * so the depth comparison value isn't clamped for Z16 and
- * Z24 anymore. Do it manually here.
- *
- * It's unnecessary if the original texture format was
- * Z32_FLOAT, but we don't know that here.
- */
- if (ctx->screen->b.chip_class == VI)
- z = ac_build_clamp(&ctx->ac, z);
-
- address[count++] = z;
- }
-
- /* Pack user derivatives */
- if (opcode == TGSI_OPCODE_TXD) {
- int param, num_src_deriv_channels, num_dst_deriv_channels;
-
- switch (target) {
- case TGSI_TEXTURE_3D:
- num_src_deriv_channels = 3;
- num_dst_deriv_channels = 3;
- num_deriv_channels = 3;
- break;
- case TGSI_TEXTURE_2D:
- case TGSI_TEXTURE_SHADOW2D:
- case TGSI_TEXTURE_RECT:
- case TGSI_TEXTURE_SHADOWRECT:
- case TGSI_TEXTURE_2D_ARRAY:
- case TGSI_TEXTURE_SHADOW2D_ARRAY:
- num_src_deriv_channels = 2;
- num_dst_deriv_channels = 2;
- num_deriv_channels = 2;
- break;
- case TGSI_TEXTURE_CUBE:
- case TGSI_TEXTURE_SHADOWCUBE:
- case TGSI_TEXTURE_CUBE_ARRAY:
- case TGSI_TEXTURE_SHADOWCUBE_ARRAY:
- /* Cube derivatives will be converted to 2D. */
- num_src_deriv_channels = 3;
- num_dst_deriv_channels = 3;
- num_deriv_channels = 2;
- break;
- case TGSI_TEXTURE_1D:
- case TGSI_TEXTURE_SHADOW1D:
- case TGSI_TEXTURE_1D_ARRAY:
- case TGSI_TEXTURE_SHADOW1D_ARRAY:
- num_src_deriv_channels = 1;
-
- /* 1D textures are allocated and used as 2D on GFX9. */
- if (ctx->screen->b.chip_class >= GFX9) {
- num_dst_deriv_channels = 2;
- num_deriv_channels = 2;
- } else {
- num_dst_deriv_channels = 1;
- num_deriv_channels = 1;
- }
- break;
- default:
- unreachable("invalid target");
- }
-
- for (param = 0; param < 2; param++) {
- for (chan = 0; chan < num_src_deriv_channels; chan++)
- derivs[param * num_dst_deriv_channels + chan] =
- lp_build_emit_fetch(bld_base, inst, param+1, chan);
-
- /* Fill in the rest with zeros. */
- for (chan = num_src_deriv_channels;
- chan < num_dst_deriv_channels; chan++)
- derivs[param * num_dst_deriv_channels + chan] =
- bld_base->base.zero;
- }
- }
-
- if (target == TGSI_TEXTURE_CUBE ||
- target == TGSI_TEXTURE_CUBE_ARRAY ||
- target == TGSI_TEXTURE_SHADOWCUBE ||
- target == TGSI_TEXTURE_SHADOWCUBE_ARRAY)
- 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)
- address[count++] = coords[2];
-
- /* 1D textures are allocated and used as 2D on GFX9. */
- if (ctx->screen->b.chip_class >= GFX9) {
- LLVMValueRef filler;
-
- /* Use 0.5, so that we don't sample the border color. */
- if (opcode == TGSI_OPCODE_TXF)
- filler = ctx->i32_0;
- else
- filler = LLVMConstReal(ctx->f32, 0.5);
-
- if (target == TGSI_TEXTURE_1D ||
- target == TGSI_TEXTURE_SHADOW1D) {
- address[count++] = filler;
- } else if (target == TGSI_TEXTURE_1D_ARRAY ||
- target == TGSI_TEXTURE_SHADOW1D_ARRAY) {
- address[count] = address[count - 1];
- address[count - 1] = filler;
- count++;
- }
- }
-
- /* Pack LOD or sample index */
- if (opcode == TGSI_OPCODE_TXL || opcode == TGSI_OPCODE_TXF)
- address[count++] = coords[3];
- else if (opcode == TGSI_OPCODE_TXL2)
- address[count++] = lp_build_emit_fetch(bld_base, inst, 1, TGSI_CHAN_X);
-
- if (count > 16) {
- assert(!"Cannot handle more than 16 texture address parameters");
- count = 16;
- }
-
- for (chan = 0; chan < count; chan++ ) {
- address[chan] = LLVMBuildBitCast(gallivm->builder,
- address[chan], ctx->i32, "");
- }
-
- /* Adjust the sample index according to FMASK.
- *
- * For uncompressed MSAA surfaces, FMASK should return 0x76543210,
- * which is the identity mapping. Each nibble says which physical sample
- * should be fetched to get that sample.
- *
- * For example, 0x11111100 means there are only 2 samples stored and
- * the second sample covers 3/4 of the pixel. When reading samples 0
- * and 1, return physical sample 0 (determined by the first two 0s
- * in FMASK), otherwise return physical sample 1.
- *
- * The sample index should be adjusted as follows:
- * sample_index = (fmask >> (sample_index * 4)) & 0xF;
- */
- if (target == TGSI_TEXTURE_2D_MSAA ||
- target == TGSI_TEXTURE_2D_ARRAY_MSAA) {
- struct lp_build_emit_data txf_emit_data = *emit_data;
- LLVMValueRef txf_address[4];
- /* We only need .xy for non-arrays, and .xyz for arrays. */
- unsigned txf_count = target == TGSI_TEXTURE_2D_MSAA ? 2 : 3;
- struct tgsi_full_instruction inst = {};
-
- memcpy(txf_address, address, sizeof(txf_address));
-
- /* Read FMASK using TXF_LZ. */
- inst.Instruction.Opcode = TGSI_OPCODE_TXF_LZ;
- inst.Texture.Texture = target;
- txf_emit_data.inst = &inst;
- txf_emit_data.chan = 0;
- set_tex_fetch_args(ctx, &txf_emit_data,
- target, fmask_ptr, NULL,
- txf_address, txf_count, 0xf);
- build_tex_intrinsic(&tex_action, bld_base, &txf_emit_data);
-
- /* Initialize some constants. */
- LLVMValueRef four = LLVMConstInt(ctx->i32, 4, 0);
- LLVMValueRef F = LLVMConstInt(ctx->i32, 0xF, 0);
-
- /* Apply the formula. */
- LLVMValueRef fmask =
- LLVMBuildExtractElement(gallivm->builder,
- txf_emit_data.output[0],
- ctx->i32_0, "");
-
- unsigned sample_chan = txf_count; /* the sample index is last */
-
- LLVMValueRef sample_index4 =
- LLVMBuildMul(gallivm->builder, address[sample_chan], four, "");
-
- LLVMValueRef shifted_fmask =
- LLVMBuildLShr(gallivm->builder, fmask, sample_index4, "");
+ * vN+3 = SampleMaskIn (used for OpenGL smoothing)
+ *
+ * The alpha-ref SGPR is returned via its original location.
+ */
+static void si_llvm_return_fs_outputs(struct ac_shader_abi *abi,
+ unsigned max_outputs,
+ LLVMValueRef *addrs)
+{
+ struct si_shader_context *ctx = si_shader_context_from_abi(abi);
+ struct si_shader *shader = ctx->shader;
+ struct tgsi_shader_info *info = &shader->selector->info;
+ LLVMBuilderRef builder = ctx->gallivm.builder;
+ unsigned i, j, first_vgpr, vgpr;
- LLVMValueRef final_sample =
- LLVMBuildAnd(gallivm->builder, shifted_fmask, F, "");
+ LLVMValueRef color[8][4] = {};
+ LLVMValueRef depth = NULL, stencil = NULL, samplemask = NULL;
+ LLVMValueRef ret;
- /* Don't rewrite the sample index if WORD1.DATA_FORMAT of the FMASK
- * resource descriptor is 0 (invalid),
- */
- LLVMValueRef fmask_desc =
- LLVMBuildBitCast(gallivm->builder, fmask_ptr,
- ctx->v8i32, "");
+ if (ctx->postponed_kill)
+ ac_build_kill(&ctx->ac, LLVMBuildLoad(builder, ctx->postponed_kill, ""));
- LLVMValueRef fmask_word1 =
- LLVMBuildExtractElement(gallivm->builder, fmask_desc,
- ctx->i32_1, "");
+ /* Read the output values. */
+ for (i = 0; i < info->num_outputs; i++) {
+ unsigned semantic_name = info->output_semantic_name[i];
+ unsigned semantic_index = info->output_semantic_index[i];
- LLVMValueRef word1_is_nonzero =
- LLVMBuildICmp(gallivm->builder, LLVMIntNE,
- fmask_word1, ctx->i32_0, "");
-
- /* Replace the MSAA sample index. */
- address[sample_chan] =
- LLVMBuildSelect(gallivm->builder, word1_is_nonzero,
- final_sample, address[sample_chan], "");
- }
-
- if (opcode == TGSI_OPCODE_TXF ||
- opcode == TGSI_OPCODE_TXF_LZ) {
- /* add tex offsets */
- if (inst->Texture.NumOffsets) {
- struct lp_build_context *uint_bld = &bld_base->uint_bld;
- const struct tgsi_texture_offset *off = inst->TexOffsets;
-
- assert(inst->Texture.NumOffsets == 1);
-
- switch (target) {
- case TGSI_TEXTURE_3D:
- address[2] = lp_build_add(uint_bld, address[2],
- ctx->imms[off->Index * TGSI_NUM_CHANNELS + off->SwizzleZ]);
- /* fall through */
- case TGSI_TEXTURE_2D:
- case TGSI_TEXTURE_SHADOW2D:
- case TGSI_TEXTURE_RECT:
- case TGSI_TEXTURE_SHADOWRECT:
- case TGSI_TEXTURE_2D_ARRAY:
- case TGSI_TEXTURE_SHADOW2D_ARRAY:
- address[1] =
- lp_build_add(uint_bld, address[1],
- ctx->imms[off->Index * TGSI_NUM_CHANNELS + off->SwizzleY]);
- /* fall through */
- case TGSI_TEXTURE_1D:
- case TGSI_TEXTURE_SHADOW1D:
- case TGSI_TEXTURE_1D_ARRAY:
- case TGSI_TEXTURE_SHADOW1D_ARRAY:
- address[0] =
- lp_build_add(uint_bld, address[0],
- ctx->imms[off->Index * TGSI_NUM_CHANNELS + off->SwizzleX]);
- break;
- /* texture offsets do not apply to other texture targets */
+ switch (semantic_name) {
+ case TGSI_SEMANTIC_COLOR:
+ assert(semantic_index < 8);
+ for (j = 0; j < 4; j++) {
+ LLVMValueRef ptr = addrs[4 * i + j];
+ LLVMValueRef result = LLVMBuildLoad(builder, ptr, "");
+ color[semantic_index][j] = result;
}
+ break;
+ case TGSI_SEMANTIC_POSITION:
+ depth = LLVMBuildLoad(builder,
+ addrs[4 * i + 2], "");
+ break;
+ case TGSI_SEMANTIC_STENCIL:
+ stencil = LLVMBuildLoad(builder,
+ addrs[4 * i + 1], "");
+ break;
+ case TGSI_SEMANTIC_SAMPLEMASK:
+ samplemask = LLVMBuildLoad(builder,
+ addrs[4 * i + 0], "");
+ break;
+ default:
+ fprintf(stderr, "Warning: SI unhandled fs output type:%d\n",
+ semantic_name);
}
}
- if (opcode == TGSI_OPCODE_TG4) {
- unsigned gather_comp = 0;
-
- /* DMASK was repurposed for GATHER4. 4 components are always
- * returned and DMASK works like a swizzle - it selects
- * the component to fetch. The only valid DMASK values are
- * 1=red, 2=green, 4=blue, 8=alpha. (e.g. 1 returns
- * (red,red,red,red) etc.) The ISA document doesn't mention
- * this.
- */
-
- /* Get the component index from src1.x for Gather4. */
- if (!tgsi_is_shadow_target(target)) {
- LLVMValueRef comp_imm;
- struct tgsi_src_register src1 = inst->Src[1].Register;
+ /* Fill the return structure. */
+ ret = ctx->return_value;
- assert(src1.File == TGSI_FILE_IMMEDIATE);
+ /* Set SGPRs. */
+ ret = LLVMBuildInsertValue(builder, ret,
+ LLVMBuildBitCast(ctx->ac.builder,
+ LLVMGetParam(ctx->main_fn,
+ SI_PARAM_ALPHA_REF),
+ ctx->i32, ""),
+ SI_SGPR_ALPHA_REF, "");
- comp_imm = ctx->imms[src1.Index * TGSI_NUM_CHANNELS + src1.SwizzleX];
- gather_comp = LLVMConstIntGetZExtValue(comp_imm);
- gather_comp = CLAMP(gather_comp, 0, 3);
- }
+ /* Set VGPRs */
+ first_vgpr = vgpr = SI_SGPR_ALPHA_REF + 1;
+ for (i = 0; i < ARRAY_SIZE(color); i++) {
+ if (!color[i][0])
+ continue;
- dmask = 1 << gather_comp;
+ for (j = 0; j < 4; j++)
+ ret = LLVMBuildInsertValue(builder, ret, color[i][j], vgpr++, "");
}
+ if (depth)
+ ret = LLVMBuildInsertValue(builder, ret, depth, vgpr++, "");
+ if (stencil)
+ ret = LLVMBuildInsertValue(builder, ret, stencil, vgpr++, "");
+ if (samplemask)
+ ret = LLVMBuildInsertValue(builder, ret, samplemask, vgpr++, "");
+
+ /* Add the input sample mask for smoothing at the end. */
+ if (vgpr < first_vgpr + PS_EPILOG_SAMPLEMASK_MIN_LOC)
+ vgpr = first_vgpr + PS_EPILOG_SAMPLEMASK_MIN_LOC;
+ ret = LLVMBuildInsertValue(builder, ret,
+ LLVMGetParam(ctx->main_fn,
+ SI_PARAM_SAMPLE_COVERAGE), vgpr++, "");
- set_tex_fetch_args(ctx, emit_data, target, res_ptr,
- samp_ptr, address, count, dmask);
+ ctx->return_value = ret;
}
-/* Gather4 should follow the same rules as bilinear filtering, but the hardware
- * incorrectly forces nearest filtering if the texture format is integer.
- * The only effect it has on Gather4, which always returns 4 texels for
- * bilinear filtering, is that the final coordinates are off by 0.5 of
- * the texel size.
+/* Prevent optimizations (at least of memory accesses) across the current
+ * point in the program by emitting empty inline assembly that is marked as
+ * having side effects.
*
- * The workaround is to subtract 0.5 from the unnormalized coordinates,
- * or (0.5 / size) from the normalized coordinates.
+ * Optionally, a value can be passed through the inline assembly to prevent
+ * LLVM from hoisting calls to ReadNone functions.
*/
-static void si_lower_gather4_integer(struct si_shader_context *ctx,
- struct ac_image_args *args,
- unsigned target)
+static void emit_optimization_barrier(struct si_shader_context *ctx,
+ LLVMValueRef *pvgpr)
{
+ static int counter = 0;
+
LLVMBuilderRef builder = ctx->gallivm.builder;
- LLVMValueRef coord = args->addr;
- LLVMValueRef half_texel[2];
- /* Texture coordinates start after:
- * {offset, bias, z-compare, derivatives}
- * Only the offset and z-compare can occur here.
- */
- unsigned coord_vgpr_index = (int)args->offset + (int)args->compare;
- int c;
+ char code[16];
+
+ snprintf(code, sizeof(code), "; %d", p_atomic_inc_return(&counter));
- if (target == TGSI_TEXTURE_RECT ||
- target == TGSI_TEXTURE_SHADOWRECT) {
- half_texel[0] = half_texel[1] = LLVMConstReal(ctx->f32, -0.5);
+ if (!pvgpr) {
+ LLVMTypeRef ftype = LLVMFunctionType(ctx->voidt, NULL, 0, false);
+ LLVMValueRef inlineasm = LLVMConstInlineAsm(ftype, code, "", true, false);
+ LLVMBuildCall(builder, inlineasm, NULL, 0, "");
} else {
- struct tgsi_full_instruction txq_inst = {};
- struct lp_build_emit_data txq_emit_data = {};
-
- /* Query the texture size. */
- txq_inst.Texture.Texture = target;
- txq_emit_data.inst = &txq_inst;
- txq_emit_data.dst_type = ctx->v4i32;
- set_tex_fetch_args(ctx, &txq_emit_data, target,
- args->resource, NULL, &ctx->i32_0,
- 1, 0xf);
- txq_emit(NULL, &ctx->bld_base, &txq_emit_data);
-
- /* Compute -0.5 / size. */
- for (c = 0; c < 2; c++) {
- half_texel[c] =
- LLVMBuildExtractElement(builder, txq_emit_data.output[0],
- LLVMConstInt(ctx->i32, c, 0), "");
- half_texel[c] = LLVMBuildUIToFP(builder, half_texel[c], ctx->f32, "");
- half_texel[c] =
- lp_build_emit_llvm_unary(&ctx->bld_base,
- TGSI_OPCODE_RCP, half_texel[c]);
- half_texel[c] = LLVMBuildFMul(builder, half_texel[c],
- LLVMConstReal(ctx->f32, -0.5), "");
- }
- }
+ LLVMTypeRef ftype = LLVMFunctionType(ctx->i32, &ctx->i32, 1, false);
+ LLVMValueRef inlineasm = LLVMConstInlineAsm(ftype, code, "=v,0", true, false);
+ LLVMValueRef vgpr = *pvgpr;
+ LLVMTypeRef vgpr_type = LLVMTypeOf(vgpr);
+ unsigned vgpr_size = llvm_get_type_size(vgpr_type);
+ LLVMValueRef vgpr0;
+
+ assert(vgpr_size % 4 == 0);
- for (c = 0; c < 2; c++) {
- LLVMValueRef tmp;
- LLVMValueRef index = LLVMConstInt(ctx->i32, coord_vgpr_index + c, 0);
+ vgpr = LLVMBuildBitCast(builder, vgpr, LLVMVectorType(ctx->i32, vgpr_size / 4), "");
+ vgpr0 = LLVMBuildExtractElement(builder, vgpr, ctx->i32_0, "");
+ vgpr0 = LLVMBuildCall(builder, inlineasm, &vgpr0, 1, "");
+ vgpr = LLVMBuildInsertElement(builder, vgpr, vgpr0, ctx->i32_0, "");
+ vgpr = LLVMBuildBitCast(builder, vgpr, vgpr_type, "");
- tmp = LLVMBuildExtractElement(builder, coord, index, "");
- tmp = LLVMBuildBitCast(builder, tmp, ctx->f32, "");
- tmp = LLVMBuildFAdd(builder, tmp, half_texel[c], "");
- tmp = LLVMBuildBitCast(builder, tmp, ctx->i32, "");
- coord = LLVMBuildInsertElement(builder, coord, tmp, index, "");
+ *pvgpr = vgpr;
}
+}
- args->addr = coord;
+void si_emit_waitcnt(struct si_shader_context *ctx, unsigned simm16)
+{
+ struct gallivm_state *gallivm = &ctx->gallivm;
+ LLVMBuilderRef builder = gallivm->builder;
+ LLVMValueRef args[1] = {
+ LLVMConstInt(ctx->i32, simm16, 0)
+ };
+ lp_build_intrinsic(builder, "llvm.amdgcn.s.waitcnt",
+ ctx->voidt, args, 1, 0);
}
-static void build_tex_intrinsic(const struct lp_build_tgsi_action *action,
- struct lp_build_tgsi_context *bld_base,
- struct lp_build_emit_data *emit_data)
+static void membar_emit(
+ const struct lp_build_tgsi_action *action,
+ struct lp_build_tgsi_context *bld_base,
+ struct lp_build_emit_data *emit_data)
{
struct si_shader_context *ctx = si_shader_context(bld_base);
- const struct tgsi_full_instruction *inst = emit_data->inst;
- struct ac_image_args args;
- unsigned opcode = inst->Instruction.Opcode;
- unsigned target = inst->Texture.Texture;
-
- if (target == TGSI_TEXTURE_BUFFER) {
- emit_data->output[emit_data->chan] =
- ac_build_buffer_load_format(&ctx->ac,
- emit_data->args[0],
- emit_data->args[2],
- emit_data->args[1],
- true);
- return;
- }
-
- memcpy(&args, emit_data->args, sizeof(args)); /* ugly */
-
- args.opcode = ac_image_sample;
- args.compare = tgsi_is_shadow_target(target);
- args.offset = inst->Texture.NumOffsets > 0;
-
- switch (opcode) {
- case TGSI_OPCODE_TXF:
- case TGSI_OPCODE_TXF_LZ:
- args.opcode = opcode == TGSI_OPCODE_TXF_LZ ||
- target == TGSI_TEXTURE_2D_MSAA ||
- target == TGSI_TEXTURE_2D_ARRAY_MSAA ?
- ac_image_load : ac_image_load_mip;
- args.compare = false;
- args.offset = false;
- break;
- case TGSI_OPCODE_LODQ:
- args.opcode = ac_image_get_lod;
- args.compare = false;
- args.offset = false;
- break;
- case TGSI_OPCODE_TEX:
- case TGSI_OPCODE_TEX2:
- case TGSI_OPCODE_TXP:
- if (ctx->type != PIPE_SHADER_FRAGMENT)
- args.level_zero = true;
- break;
- case TGSI_OPCODE_TEX_LZ:
- args.level_zero = true;
- break;
- case TGSI_OPCODE_TXB:
- case TGSI_OPCODE_TXB2:
- assert(ctx->type == PIPE_SHADER_FRAGMENT);
- args.bias = true;
- break;
- case TGSI_OPCODE_TXL:
- case TGSI_OPCODE_TXL2:
- args.lod = true;
- break;
- case TGSI_OPCODE_TXD:
- args.deriv = true;
- break;
- case TGSI_OPCODE_TG4:
- args.opcode = ac_image_gather4;
- args.level_zero = true;
- break;
- default:
- assert(0);
- return;
- }
+ LLVMValueRef src0 = lp_build_emit_fetch(bld_base, emit_data->inst, 0, 0);
+ unsigned flags = LLVMConstIntGetZExtValue(src0);
+ unsigned waitcnt = NOOP_WAITCNT;
- /* The hardware needs special lowering for Gather4 with integer formats. */
- if (ctx->screen->b.chip_class <= VI &&
- opcode == TGSI_OPCODE_TG4) {
- struct tgsi_shader_info *info = &ctx->shader->selector->info;
- /* This will also work with non-constant indexing because of how
- * glsl_to_tgsi works and we intent to preserve that behavior.
- */
- const unsigned src_idx = 2;
- unsigned sampler = inst->Src[src_idx].Register.Index;
+ if (flags & TGSI_MEMBAR_THREAD_GROUP)
+ waitcnt &= VM_CNT & LGKM_CNT;
- assert(inst->Src[src_idx].Register.File == TGSI_FILE_SAMPLER);
+ if (flags & (TGSI_MEMBAR_ATOMIC_BUFFER |
+ TGSI_MEMBAR_SHADER_BUFFER |
+ TGSI_MEMBAR_SHADER_IMAGE))
+ waitcnt &= VM_CNT;
- if (info->sampler_type[sampler] == TGSI_RETURN_TYPE_SINT ||
- info->sampler_type[sampler] == TGSI_RETURN_TYPE_UINT)
- si_lower_gather4_integer(ctx, &args, target);
- }
+ if (flags & TGSI_MEMBAR_SHARED)
+ waitcnt &= LGKM_CNT;
- emit_data->output[emit_data->chan] =
- ac_build_image_opcode(&ctx->ac, &args);
+ if (waitcnt != NOOP_WAITCNT)
+ si_emit_waitcnt(ctx, waitcnt);
}
-static void si_llvm_emit_txqs(
- const struct lp_build_tgsi_action *action,
- struct lp_build_tgsi_context *bld_base,
- struct lp_build_emit_data *emit_data)
+static void clock_emit(
+ const struct lp_build_tgsi_action *action,
+ struct lp_build_tgsi_context *bld_base,
+ struct lp_build_emit_data *emit_data)
{
struct si_shader_context *ctx = si_shader_context(bld_base);
struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMBuilderRef builder = gallivm->builder;
- LLVMValueRef res, samples;
- LLVMValueRef res_ptr, samp_ptr, fmask_ptr = NULL;
-
- tex_fetch_ptrs(bld_base, emit_data, &res_ptr, &samp_ptr, &fmask_ptr);
+ LLVMValueRef tmp;
+ tmp = lp_build_intrinsic(gallivm->builder, "llvm.readcyclecounter",
+ ctx->i64, NULL, 0, 0);
+ tmp = LLVMBuildBitCast(gallivm->builder, tmp, ctx->v2i32, "");
- /* Read the samples from the descriptor directly. */
- res = LLVMBuildBitCast(builder, res_ptr, ctx->v8i32, "");
- samples = LLVMBuildExtractElement(
- builder, res,
- LLVMConstInt(ctx->i32, 3, 0), "");
- samples = LLVMBuildLShr(builder, samples,
- LLVMConstInt(ctx->i32, 16, 0), "");
- samples = LLVMBuildAnd(builder, samples,
- LLVMConstInt(ctx->i32, 0xf, 0), "");
- samples = LLVMBuildShl(builder, ctx->i32_1,
- samples, "");
+ emit_data->output[0] =
+ LLVMBuildExtractElement(gallivm->builder, tmp, ctx->i32_0, "");
+ emit_data->output[1] =
+ LLVMBuildExtractElement(gallivm->builder, tmp, ctx->i32_1, "");
+}
- emit_data->output[emit_data->chan] = samples;
+LLVMTypeRef si_const_array(LLVMTypeRef elem_type, int num_elements)
+{
+ return LLVMPointerType(LLVMArrayType(elem_type, num_elements),
+ CONST_ADDR_SPACE);
}
static void si_llvm_emit_ddxy(
struct si_shader_context *ctx = si_shader_context(bld_base);
struct si_shader *shader = ctx->shader;
struct gallivm_state *gallivm = &ctx->gallivm;
+ const struct tgsi_shader_info *info = &shader->selector->info;
LLVMValueRef interp_param;
const struct tgsi_full_instruction *inst = emit_data->inst;
- int input_index = inst->Src[0].Register.Index;
+ const struct tgsi_full_src_register *input = &inst->Src[0];
+ int input_base, input_array_size;
int chan;
int i;
- LLVMValueRef attr_number;
- LLVMValueRef params = LLVMGetParam(ctx->main_fn, SI_PARAM_PRIM_MASK);
+ LLVMValueRef prim_mask = LLVMGetParam(ctx->main_fn, SI_PARAM_PRIM_MASK);
+ LLVMValueRef array_idx;
int interp_param_idx;
- unsigned interp = shader->selector->info.input_interpolate[input_index];
+ unsigned interp;
unsigned location;
- assert(inst->Src[0].Register.File == TGSI_FILE_INPUT);
+ assert(input->Register.File == TGSI_FILE_INPUT);
+
+ if (input->Register.Indirect) {
+ unsigned array_id = input->Indirect.ArrayID;
+
+ if (array_id) {
+ input_base = info->input_array_first[array_id];
+ input_array_size = info->input_array_last[array_id] - input_base + 1;
+ } else {
+ input_base = inst->Src[0].Register.Index;
+ input_array_size = info->num_inputs - input_base;
+ }
+
+ array_idx = get_indirect_index(ctx, &input->Indirect,
+ input->Register.Index - input_base);
+ } else {
+ input_base = inst->Src[0].Register.Index;
+ input_array_size = 1;
+ array_idx = ctx->i32_0;
+ }
+
+ interp = shader->selector->info.input_interpolate[input_base];
if (inst->Instruction.Opcode == TGSI_OPCODE_INTERP_OFFSET ||
inst->Instruction.Opcode == TGSI_OPCODE_INTERP_SAMPLE)
else
interp_param = NULL;
- attr_number = LLVMConstInt(ctx->i32, input_index, 0);
-
if (inst->Instruction.Opcode == TGSI_OPCODE_INTERP_OFFSET ||
inst->Instruction.Opcode == TGSI_OPCODE_INTERP_SAMPLE) {
LLVMValueRef ij_out[2];
interp_param = lp_build_gather_values(gallivm, ij_out, 2);
}
+ if (interp_param) {
+ interp_param = LLVMBuildBitCast(gallivm->builder,
+ interp_param, LLVMVectorType(ctx->f32, 2), "");
+ }
+
for (chan = 0; chan < 4; chan++) {
- LLVMValueRef llvm_chan;
- unsigned schan;
-
- schan = tgsi_util_get_full_src_register_swizzle(&inst->Src[0], chan);
- llvm_chan = LLVMConstInt(ctx->i32, schan, 0);
-
- if (interp_param) {
- interp_param = LLVMBuildBitCast(gallivm->builder,
- interp_param, LLVMVectorType(ctx->f32, 2), "");
- LLVMValueRef i = LLVMBuildExtractElement(
- gallivm->builder, interp_param, ctx->i32_0, "");
- LLVMValueRef j = LLVMBuildExtractElement(
- gallivm->builder, interp_param, ctx->i32_1, "");
- emit_data->output[chan] = ac_build_fs_interp(&ctx->ac,
- llvm_chan, attr_number, params,
- i, j);
- } else {
- emit_data->output[chan] = ac_build_fs_interp_mov(&ctx->ac,
- LLVMConstInt(ctx->i32, 2, 0), /* P0 */
- llvm_chan, attr_number, params);
+ LLVMValueRef gather = LLVMGetUndef(LLVMVectorType(ctx->f32, input_array_size));
+ unsigned schan = tgsi_util_get_full_src_register_swizzle(&inst->Src[0], chan);
+
+ for (unsigned idx = 0; idx < input_array_size; ++idx) {
+ LLVMValueRef v, i = NULL, j = NULL;
+
+ if (interp_param) {
+ interp_param = LLVMBuildBitCast(gallivm->builder,
+ interp_param, LLVMVectorType(ctx->f32, 2), "");
+ i = LLVMBuildExtractElement(
+ gallivm->builder, interp_param, ctx->i32_0, "");
+ j = LLVMBuildExtractElement(
+ gallivm->builder, interp_param, ctx->i32_1, "");
+ }
+ v = si_build_fs_interp(ctx, input_base + idx, schan,
+ prim_mask, i, j);
+
+ gather = LLVMBuildInsertElement(gallivm->builder,
+ gather, v, LLVMConstInt(ctx->i32, idx, false), "");
}
+
+ emit_data->output[chan] = LLVMBuildExtractElement(
+ gallivm->builder, gather, array_idx, "");
}
}
*/
if (ctx->screen->b.chip_class == SI &&
ctx->type == PIPE_SHADER_TESS_CTRL) {
- emit_waitcnt(ctx, LGKM_CNT & VM_CNT);
+ si_emit_waitcnt(ctx, LGKM_CNT & VM_CNT);
return;
}
ctx->voidt, NULL, 0, LP_FUNC_ATTR_CONVERGENT);
}
-static const struct lp_build_tgsi_action tex_action = {
- .fetch_args = tex_fetch_args,
- .emit = build_tex_intrinsic,
-};
-
static const struct lp_build_tgsi_action interp_action = {
.fetch_args = interp_fetch_args,
.emit = build_interp_intrinsic,
static void si_create_function(struct si_shader_context *ctx,
const char *name,
LLVMTypeRef *returns, unsigned num_returns,
- LLVMTypeRef *params, unsigned num_params,
- int last_sgpr, unsigned max_workgroup_size)
+ struct si_function_info *fninfo,
+ unsigned max_workgroup_size)
{
int i;
si_llvm_create_func(ctx, name, returns, num_returns,
- params, num_params);
- si_llvm_shader_type(ctx->main_fn, ctx->type);
+ fninfo->types, fninfo->num_params);
ctx->return_value = LLVMGetUndef(ctx->return_type);
- for (i = 0; i <= last_sgpr; ++i) {
+ for (i = 0; i < fninfo->num_sgpr_params; ++i) {
LLVMValueRef P = LLVMGetParam(ctx->main_fn, i);
/* The combination of:
lp_add_function_attr(ctx->main_fn, i + 1, LP_FUNC_ATTR_INREG);
}
+ for (i = 0; i < fninfo->num_params; ++i) {
+ if (fninfo->assign[i])
+ *fninfo->assign[i] = LLVMGetParam(ctx->main_fn, i);
+ }
+
if (max_workgroup_size) {
si_llvm_add_attribute(ctx->main_fn, "amdgpu-max-work-group-size",
max_workgroup_size);
static void declare_streamout_params(struct si_shader_context *ctx,
struct pipe_stream_output_info *so,
- LLVMTypeRef *params, LLVMTypeRef i32,
- unsigned *num_params)
+ struct si_function_info *fninfo)
{
int i;
/* Streamout SGPRs. */
if (so->num_outputs) {
if (ctx->type != PIPE_SHADER_TESS_EVAL)
- params[ctx->param_streamout_config = (*num_params)++] = i32;
+ ctx->param_streamout_config = add_arg(fninfo, ARG_SGPR, ctx->ac.i32);
else
- ctx->param_streamout_config = *num_params - 1;
+ ctx->param_streamout_config = fninfo->num_params - 1;
- params[ctx->param_streamout_write_index = (*num_params)++] = i32;
+ ctx->param_streamout_write_index = add_arg(fninfo, ARG_SGPR, ctx->ac.i32);
}
/* A streamout buffer offset is loaded if the stride is non-zero. */
for (i = 0; i < 4; i++) {
if (!so->stride[i])
continue;
- params[ctx->param_streamout_offset[i] = (*num_params)++] = i32;
+ ctx->param_streamout_offset[i] = add_arg(fninfo, ARG_SGPR, ctx->ac.i32);
}
}
"lds");
}
-static unsigned si_get_max_workgroup_size(struct si_shader *shader)
+static unsigned si_get_max_workgroup_size(const struct si_shader *shader)
{
switch (shader->selector->type) {
case PIPE_SHADER_TESS_CTRL:
}
static void declare_per_stage_desc_pointers(struct si_shader_context *ctx,
- LLVMTypeRef *params,
- unsigned *num_params,
+ struct si_function_info *fninfo,
bool assign_params)
{
- params[(*num_params)++] = const_array(ctx->v4i32, SI_NUM_CONST_BUFFERS);
- params[(*num_params)++] = const_array(ctx->v8i32, SI_NUM_SAMPLERS);
- params[(*num_params)++] = const_array(ctx->v8i32, SI_NUM_IMAGES);
- params[(*num_params)++] = const_array(ctx->v4i32, SI_NUM_SHADER_BUFFERS);
+ unsigned const_and_shader_buffers =
+ add_arg(fninfo, ARG_SGPR,
+ si_const_array(ctx->v4i32,
+ SI_NUM_SHADER_BUFFERS + SI_NUM_CONST_BUFFERS));
+ unsigned samplers_and_images =
+ add_arg(fninfo, ARG_SGPR,
+ si_const_array(ctx->v8i32,
+ SI_NUM_IMAGES + SI_NUM_SAMPLERS * 2));
if (assign_params) {
- ctx->param_const_buffers = *num_params - 4;
- ctx->param_samplers = *num_params - 3;
- ctx->param_images = *num_params - 2;
- ctx->param_shader_buffers = *num_params - 1;
+ ctx->param_const_and_shader_buffers = const_and_shader_buffers;
+ ctx->param_samplers_and_images = samplers_and_images;
}
}
static void declare_default_desc_pointers(struct si_shader_context *ctx,
- LLVMTypeRef *params,
- unsigned *num_params)
+ struct si_function_info *fninfo)
{
- params[ctx->param_rw_buffers = (*num_params)++] =
- const_array(ctx->v4i32, SI_NUM_RW_BUFFERS);
- declare_per_stage_desc_pointers(ctx, params, num_params, true);
+ ctx->param_rw_buffers = add_arg(fninfo, ARG_SGPR,
+ si_const_array(ctx->v4i32, SI_NUM_RW_BUFFERS));
+ declare_per_stage_desc_pointers(ctx, fninfo, true);
}
static void declare_vs_specific_input_sgprs(struct si_shader_context *ctx,
- LLVMTypeRef *params,
- unsigned *num_params)
+ struct si_function_info *fninfo)
{
- params[ctx->param_vertex_buffers = (*num_params)++] =
- const_array(ctx->v4i32, SI_NUM_VERTEX_BUFFERS);
- params[ctx->param_base_vertex = (*num_params)++] = ctx->i32;
- params[ctx->param_start_instance = (*num_params)++] = ctx->i32;
- params[ctx->param_draw_id = (*num_params)++] = ctx->i32;
- params[ctx->param_vs_state_bits = (*num_params)++] = ctx->i32;
+ ctx->param_vertex_buffers = add_arg(fninfo, ARG_SGPR,
+ si_const_array(ctx->v4i32, SI_NUM_VERTEX_BUFFERS));
+ add_arg_assign(fninfo, ARG_SGPR, ctx->i32, &ctx->abi.base_vertex);
+ add_arg_assign(fninfo, ARG_SGPR, ctx->i32, &ctx->abi.start_instance);
+ add_arg_assign(fninfo, ARG_SGPR, ctx->i32, &ctx->abi.draw_id);
+ ctx->param_vs_state_bits = add_arg(fninfo, ARG_SGPR, ctx->i32);
}
static void declare_vs_input_vgprs(struct si_shader_context *ctx,
- LLVMTypeRef *params, unsigned *num_params,
+ struct si_function_info *fninfo,
unsigned *num_prolog_vgprs)
{
struct si_shader *shader = ctx->shader;
- params[ctx->param_vertex_id = (*num_params)++] = ctx->i32;
+ add_arg_assign(fninfo, ARG_VGPR, ctx->i32, &ctx->abi.vertex_id);
if (shader->key.as_ls) {
- params[ctx->param_rel_auto_id = (*num_params)++] = ctx->i32;
- params[ctx->param_instance_id = (*num_params)++] = ctx->i32;
+ ctx->param_rel_auto_id = add_arg(fninfo, ARG_VGPR, ctx->i32);
+ add_arg_assign(fninfo, ARG_VGPR, ctx->i32, &ctx->abi.instance_id);
} else {
- params[ctx->param_instance_id = (*num_params)++] = ctx->i32;
- params[ctx->param_vs_prim_id = (*num_params)++] = ctx->i32;
+ add_arg_assign(fninfo, ARG_VGPR, ctx->i32, &ctx->abi.instance_id);
+ ctx->param_vs_prim_id = add_arg(fninfo, ARG_VGPR, ctx->i32);
}
- params[(*num_params)++] = ctx->i32; /* unused */
+ add_arg(fninfo, ARG_VGPR, ctx->i32); /* unused */
if (!shader->is_gs_copy_shader) {
/* Vertex load indices. */
- ctx->param_vertex_index0 = (*num_params);
+ ctx->param_vertex_index0 = fninfo->num_params;
for (unsigned i = 0; i < shader->selector->info.num_inputs; i++)
- params[(*num_params)++] = ctx->i32;
+ add_arg(fninfo, ARG_VGPR, ctx->i32);
*num_prolog_vgprs += shader->selector->info.num_inputs;
}
}
static void declare_tes_input_vgprs(struct si_shader_context *ctx,
- LLVMTypeRef *params, unsigned *num_params)
+ struct si_function_info *fninfo)
{
- params[ctx->param_tes_u = (*num_params)++] = ctx->f32;
- params[ctx->param_tes_v = (*num_params)++] = ctx->f32;
- params[ctx->param_tes_rel_patch_id = (*num_params)++] = ctx->i32;
- params[ctx->param_tes_patch_id = (*num_params)++] = ctx->i32;
+ ctx->param_tes_u = add_arg(fninfo, ARG_VGPR, ctx->f32);
+ ctx->param_tes_v = add_arg(fninfo, ARG_VGPR, ctx->f32);
+ ctx->param_tes_rel_patch_id = add_arg(fninfo, ARG_VGPR, ctx->i32);
+ ctx->param_tes_patch_id = add_arg(fninfo, ARG_VGPR, ctx->i32);
}
enum {
struct lp_build_tgsi_context *bld_base = &ctx->bld_base;
struct gallivm_state *gallivm = &ctx->gallivm;
struct si_shader *shader = ctx->shader;
- LLVMTypeRef params[100]; /* just make it large enough */
+ struct si_function_info fninfo;
LLVMTypeRef returns[16+32*4];
- unsigned i, last_sgpr, num_params = 0, num_return_sgprs;
+ unsigned i, num_return_sgprs;
unsigned num_returns = 0;
unsigned num_prolog_vgprs = 0;
unsigned type = ctx->type;
+ si_init_function_info(&fninfo);
+
/* Set MERGED shaders. */
if (ctx->screen->b.chip_class >= GFX9) {
if (shader->key.as_ls || type == PIPE_SHADER_TESS_CTRL)
switch (type) {
case PIPE_SHADER_VERTEX:
- declare_default_desc_pointers(ctx, params, &num_params);
- declare_vs_specific_input_sgprs(ctx, params, &num_params);
+ declare_default_desc_pointers(ctx, &fninfo);
+ declare_vs_specific_input_sgprs(ctx, &fninfo);
if (shader->key.as_es) {
- params[ctx->param_es2gs_offset = num_params++] = ctx->i32;
+ ctx->param_es2gs_offset = add_arg(&fninfo, ARG_SGPR, ctx->i32);
} else if (shader->key.as_ls) {
/* no extra parameters */
} else {
- if (shader->is_gs_copy_shader)
- num_params = ctx->param_rw_buffers + 1;
+ if (shader->is_gs_copy_shader) {
+ fninfo.num_params = ctx->param_rw_buffers + 1;
+ fninfo.num_sgpr_params = fninfo.num_params;
+ }
/* The locations of the other parameters are assigned dynamically. */
declare_streamout_params(ctx, &shader->selector->so,
- params, ctx->i32, &num_params);
+ &fninfo);
}
- last_sgpr = num_params-1;
-
/* VGPRs */
- declare_vs_input_vgprs(ctx, params, &num_params,
- &num_prolog_vgprs);
+ declare_vs_input_vgprs(ctx, &fninfo, &num_prolog_vgprs);
break;
case PIPE_SHADER_TESS_CTRL: /* SI-CI-VI */
- declare_default_desc_pointers(ctx, params, &num_params);
- params[ctx->param_tcs_offchip_layout = num_params++] = ctx->i32;
- params[ctx->param_tcs_out_lds_offsets = num_params++] = ctx->i32;
- params[ctx->param_tcs_out_lds_layout = num_params++] = ctx->i32;
- params[ctx->param_vs_state_bits = num_params++] = ctx->i32;
- params[ctx->param_tcs_offchip_addr_base64k = num_params++] = ctx->i32;
- params[ctx->param_tcs_factor_addr_base64k = num_params++] = ctx->i32;
- params[ctx->param_tcs_offchip_offset = num_params++] = ctx->i32;
- params[ctx->param_tcs_factor_offset = num_params++] = ctx->i32;
- last_sgpr = num_params - 1;
+ declare_default_desc_pointers(ctx, &fninfo);
+ ctx->param_tcs_offchip_layout = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_out_lds_offsets = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_out_lds_layout = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_vs_state_bits = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_offchip_addr_base64k = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_factor_addr_base64k = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_offchip_offset = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_factor_offset = add_arg(&fninfo, ARG_SGPR, ctx->i32);
/* VGPRs */
- params[ctx->param_tcs_patch_id = num_params++] = ctx->i32;
- params[ctx->param_tcs_rel_ids = num_params++] = ctx->i32;
+ ctx->param_tcs_patch_id = add_arg(&fninfo, ARG_VGPR, ctx->i32);
+ ctx->param_tcs_rel_ids = add_arg(&fninfo, ARG_VGPR, ctx->i32);
/* param_tcs_offchip_offset and param_tcs_factor_offset are
* placed after the user SGPRs.
*/
for (i = 0; i < GFX6_TCS_NUM_USER_SGPR + 2; i++)
returns[num_returns++] = ctx->i32; /* SGPRs */
- for (i = 0; i < 3; i++)
+ for (i = 0; i < 5; i++)
returns[num_returns++] = ctx->f32; /* VGPRs */
break;
case SI_SHADER_MERGED_VERTEX_TESSCTRL:
/* Merged stages have 8 system SGPRs at the beginning. */
- params[ctx->param_rw_buffers = num_params++] = /* SPI_SHADER_USER_DATA_ADDR_LO_HS */
- const_array(ctx->v4i32, SI_NUM_RW_BUFFERS);
- params[ctx->param_tcs_offchip_offset = num_params++] = ctx->i32;
- params[ctx->param_merged_wave_info = num_params++] = ctx->i32;
- params[ctx->param_tcs_factor_offset = num_params++] = ctx->i32;
- params[ctx->param_merged_scratch_offset = num_params++] = ctx->i32;
- params[num_params++] = ctx->i32; /* unused */
- params[num_params++] = ctx->i32; /* unused */
-
- params[num_params++] = ctx->i32; /* unused */
- params[num_params++] = ctx->i32; /* unused */
- declare_per_stage_desc_pointers(ctx, params, &num_params,
+ ctx->param_rw_buffers = /* SPI_SHADER_USER_DATA_ADDR_LO_HS */
+ add_arg(&fninfo, ARG_SGPR, si_const_array(ctx->v4i32, SI_NUM_RW_BUFFERS));
+ ctx->param_tcs_offchip_offset = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_merged_wave_info = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_factor_offset = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_merged_scratch_offset = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ add_arg(&fninfo, ARG_SGPR, ctx->i32); /* unused */
+ add_arg(&fninfo, ARG_SGPR, ctx->i32); /* unused */
+
+ add_arg(&fninfo, ARG_SGPR, ctx->i32); /* unused */
+ add_arg(&fninfo, ARG_SGPR, ctx->i32); /* unused */
+ declare_per_stage_desc_pointers(ctx, &fninfo,
ctx->type == PIPE_SHADER_VERTEX);
- declare_vs_specific_input_sgprs(ctx, params, &num_params);
+ declare_vs_specific_input_sgprs(ctx, &fninfo);
- params[ctx->param_tcs_offchip_layout = num_params++] = ctx->i32;
- params[ctx->param_tcs_out_lds_offsets = num_params++] = ctx->i32;
- params[ctx->param_tcs_out_lds_layout = num_params++] = ctx->i32;
- params[ctx->param_tcs_offchip_addr_base64k = num_params++] = ctx->i32;
- params[ctx->param_tcs_factor_addr_base64k = num_params++] = ctx->i32;
- params[num_params++] = ctx->i32; /* unused */
+ ctx->param_tcs_offchip_layout = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_out_lds_offsets = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_out_lds_layout = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_offchip_addr_base64k = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_factor_addr_base64k = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ add_arg(&fninfo, ARG_SGPR, ctx->i32); /* unused */
- declare_per_stage_desc_pointers(ctx, params, &num_params,
+ declare_per_stage_desc_pointers(ctx, &fninfo,
ctx->type == PIPE_SHADER_TESS_CTRL);
- last_sgpr = num_params - 1;
/* VGPRs (first TCS, then VS) */
- params[ctx->param_tcs_patch_id = num_params++] = ctx->i32;
- params[ctx->param_tcs_rel_ids = num_params++] = ctx->i32;
+ ctx->param_tcs_patch_id = add_arg(&fninfo, ARG_VGPR, ctx->i32);
+ ctx->param_tcs_rel_ids = add_arg(&fninfo, ARG_VGPR, ctx->i32);
if (ctx->type == PIPE_SHADER_VERTEX) {
- declare_vs_input_vgprs(ctx, params, &num_params,
+ declare_vs_input_vgprs(ctx, &fninfo,
&num_prolog_vgprs);
/* LS return values are inputs to the TCS main shader part. */
*/
for (i = 0; i <= 8 + GFX9_SGPR_TCS_FACTOR_ADDR_BASE64K; i++)
returns[num_returns++] = ctx->i32; /* SGPRs */
- for (i = 0; i < 3; i++)
+ for (i = 0; i < 5; i++)
returns[num_returns++] = ctx->f32; /* VGPRs */
}
break;
case SI_SHADER_MERGED_VERTEX_OR_TESSEVAL_GEOMETRY:
/* Merged stages have 8 system SGPRs at the beginning. */
- params[ctx->param_rw_buffers = num_params++] = /* SPI_SHADER_USER_DATA_ADDR_LO_GS */
- const_array(ctx->v4i32, SI_NUM_RW_BUFFERS);
- params[ctx->param_gs2vs_offset = num_params++] = ctx->i32;
- params[ctx->param_merged_wave_info = num_params++] = ctx->i32;
- params[ctx->param_tcs_offchip_offset = num_params++] = ctx->i32;
- params[ctx->param_merged_scratch_offset = num_params++] = ctx->i32;
- params[num_params++] = ctx->i32; /* unused (SPI_SHADER_PGM_LO/HI_GS << 8) */
- params[num_params++] = ctx->i32; /* unused (SPI_SHADER_PGM_LO/HI_GS >> 24) */
-
- params[num_params++] = ctx->i32; /* unused */
- params[num_params++] = ctx->i32; /* unused */
- declare_per_stage_desc_pointers(ctx, params, &num_params,
+ ctx->param_rw_buffers = /* SPI_SHADER_USER_DATA_ADDR_LO_GS */
+ add_arg(&fninfo, ARG_SGPR, si_const_array(ctx->v4i32, SI_NUM_RW_BUFFERS));
+ ctx->param_gs2vs_offset = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_merged_wave_info = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_offchip_offset = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_merged_scratch_offset = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ add_arg(&fninfo, ARG_SGPR, ctx->i32); /* unused (SPI_SHADER_PGM_LO/HI_GS << 8) */
+ add_arg(&fninfo, ARG_SGPR, ctx->i32); /* unused (SPI_SHADER_PGM_LO/HI_GS >> 24) */
+
+ add_arg(&fninfo, ARG_SGPR, ctx->i32); /* unused */
+ add_arg(&fninfo, ARG_SGPR, ctx->i32); /* unused */
+ declare_per_stage_desc_pointers(ctx, &fninfo,
(ctx->type == PIPE_SHADER_VERTEX ||
ctx->type == PIPE_SHADER_TESS_EVAL));
if (ctx->type == PIPE_SHADER_VERTEX) {
- declare_vs_specific_input_sgprs(ctx, params, &num_params);
+ declare_vs_specific_input_sgprs(ctx, &fninfo);
} else {
/* TESS_EVAL (and also GEOMETRY):
* Declare as many input SGPRs as the VS has. */
- params[ctx->param_tcs_offchip_layout = num_params++] = ctx->i32;
- params[ctx->param_tcs_offchip_addr_base64k = num_params++] = ctx->i32;
- params[num_params++] = ctx->i32; /* unused */
- params[num_params++] = ctx->i32; /* unused */
- params[num_params++] = ctx->i32; /* unused */
- params[ctx->param_vs_state_bits = num_params++] = ctx->i32; /* unused */
+ ctx->param_tcs_offchip_layout = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_offchip_addr_base64k = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ add_arg(&fninfo, ARG_SGPR, ctx->i32); /* unused */
+ add_arg(&fninfo, ARG_SGPR, ctx->i32); /* unused */
+ add_arg(&fninfo, ARG_SGPR, ctx->i32); /* unused */
+ ctx->param_vs_state_bits = add_arg(&fninfo, ARG_SGPR, ctx->i32); /* unused */
}
- declare_per_stage_desc_pointers(ctx, params, &num_params,
+ declare_per_stage_desc_pointers(ctx, &fninfo,
ctx->type == PIPE_SHADER_GEOMETRY);
- last_sgpr = num_params - 1;
/* VGPRs (first GS, then VS/TES) */
- params[ctx->param_gs_vtx01_offset = num_params++] = ctx->i32;
- params[ctx->param_gs_vtx23_offset = num_params++] = ctx->i32;
- params[ctx->param_gs_prim_id = num_params++] = ctx->i32;
- params[ctx->param_gs_instance_id = num_params++] = ctx->i32;
- params[ctx->param_gs_vtx45_offset = num_params++] = ctx->i32;
+ ctx->param_gs_vtx01_offset = add_arg(&fninfo, ARG_VGPR, ctx->i32);
+ ctx->param_gs_vtx23_offset = add_arg(&fninfo, ARG_VGPR, ctx->i32);
+ ctx->param_gs_prim_id = add_arg(&fninfo, ARG_VGPR, ctx->i32);
+ ctx->param_gs_instance_id = add_arg(&fninfo, ARG_VGPR, ctx->i32);
+ ctx->param_gs_vtx45_offset = add_arg(&fninfo, ARG_VGPR, ctx->i32);
if (ctx->type == PIPE_SHADER_VERTEX) {
- declare_vs_input_vgprs(ctx, params, &num_params,
+ declare_vs_input_vgprs(ctx, &fninfo,
&num_prolog_vgprs);
} else if (ctx->type == PIPE_SHADER_TESS_EVAL) {
- declare_tes_input_vgprs(ctx, params, &num_params);
+ declare_tes_input_vgprs(ctx, &fninfo);
}
if (ctx->type == PIPE_SHADER_VERTEX ||
break;
case PIPE_SHADER_TESS_EVAL:
- declare_default_desc_pointers(ctx, params, &num_params);
- params[ctx->param_tcs_offchip_layout = num_params++] = ctx->i32;
- params[ctx->param_tcs_offchip_addr_base64k = num_params++] = ctx->i32;
+ declare_default_desc_pointers(ctx, &fninfo);
+ ctx->param_tcs_offchip_layout = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_offchip_addr_base64k = add_arg(&fninfo, ARG_SGPR, ctx->i32);
if (shader->key.as_es) {
- params[ctx->param_tcs_offchip_offset = num_params++] = ctx->i32;
- params[num_params++] = ctx->i32;
- params[ctx->param_es2gs_offset = num_params++] = ctx->i32;
+ ctx->param_tcs_offchip_offset = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_es2gs_offset = add_arg(&fninfo, ARG_SGPR, ctx->i32);
} else {
- params[num_params++] = ctx->i32;
+ add_arg(&fninfo, ARG_SGPR, ctx->i32);
declare_streamout_params(ctx, &shader->selector->so,
- params, ctx->i32, &num_params);
- params[ctx->param_tcs_offchip_offset = num_params++] = ctx->i32;
+ &fninfo);
+ ctx->param_tcs_offchip_offset = add_arg(&fninfo, ARG_SGPR, ctx->i32);
}
- last_sgpr = num_params - 1;
/* VGPRs */
- declare_tes_input_vgprs(ctx, params, &num_params);
+ declare_tes_input_vgprs(ctx, &fninfo);
break;
case PIPE_SHADER_GEOMETRY:
- declare_default_desc_pointers(ctx, params, &num_params);
- params[ctx->param_gs2vs_offset = num_params++] = ctx->i32;
- params[ctx->param_gs_wave_id = num_params++] = ctx->i32;
- last_sgpr = num_params - 1;
+ declare_default_desc_pointers(ctx, &fninfo);
+ ctx->param_gs2vs_offset = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_gs_wave_id = add_arg(&fninfo, ARG_SGPR, ctx->i32);
/* VGPRs */
- params[ctx->param_gs_vtx0_offset = num_params++] = ctx->i32;
- params[ctx->param_gs_vtx1_offset = num_params++] = ctx->i32;
- params[ctx->param_gs_prim_id = num_params++] = ctx->i32;
- params[ctx->param_gs_vtx2_offset = num_params++] = ctx->i32;
- params[ctx->param_gs_vtx3_offset = num_params++] = ctx->i32;
- params[ctx->param_gs_vtx4_offset = num_params++] = ctx->i32;
- params[ctx->param_gs_vtx5_offset = num_params++] = ctx->i32;
- params[ctx->param_gs_instance_id = num_params++] = ctx->i32;
+ ctx->param_gs_vtx0_offset = add_arg(&fninfo, ARG_VGPR, ctx->i32);
+ ctx->param_gs_vtx1_offset = add_arg(&fninfo, ARG_VGPR, ctx->i32);
+ ctx->param_gs_prim_id = add_arg(&fninfo, ARG_VGPR, ctx->i32);
+ ctx->param_gs_vtx2_offset = add_arg(&fninfo, ARG_VGPR, ctx->i32);
+ ctx->param_gs_vtx3_offset = add_arg(&fninfo, ARG_VGPR, ctx->i32);
+ ctx->param_gs_vtx4_offset = add_arg(&fninfo, ARG_VGPR, ctx->i32);
+ ctx->param_gs_vtx5_offset = add_arg(&fninfo, ARG_VGPR, ctx->i32);
+ ctx->param_gs_instance_id = add_arg(&fninfo, ARG_VGPR, ctx->i32);
break;
case PIPE_SHADER_FRAGMENT:
- declare_default_desc_pointers(ctx, params, &num_params);
- params[SI_PARAM_ALPHA_REF] = ctx->f32;
- params[SI_PARAM_PRIM_MASK] = ctx->i32;
- last_sgpr = SI_PARAM_PRIM_MASK;
- params[SI_PARAM_PERSP_SAMPLE] = ctx->v2i32;
- params[SI_PARAM_PERSP_CENTER] = ctx->v2i32;
- params[SI_PARAM_PERSP_CENTROID] = ctx->v2i32;
- params[SI_PARAM_PERSP_PULL_MODEL] = v3i32;
- params[SI_PARAM_LINEAR_SAMPLE] = ctx->v2i32;
- params[SI_PARAM_LINEAR_CENTER] = ctx->v2i32;
- params[SI_PARAM_LINEAR_CENTROID] = ctx->v2i32;
- params[SI_PARAM_LINE_STIPPLE_TEX] = ctx->f32;
- params[SI_PARAM_POS_X_FLOAT] = ctx->f32;
- params[SI_PARAM_POS_Y_FLOAT] = ctx->f32;
- params[SI_PARAM_POS_Z_FLOAT] = ctx->f32;
- params[SI_PARAM_POS_W_FLOAT] = ctx->f32;
- params[SI_PARAM_FRONT_FACE] = ctx->i32;
+ declare_default_desc_pointers(ctx, &fninfo);
+ add_arg_checked(&fninfo, ARG_SGPR, ctx->f32, SI_PARAM_ALPHA_REF);
+ add_arg_checked(&fninfo, ARG_SGPR, ctx->i32, SI_PARAM_PRIM_MASK);
+
+ add_arg_checked(&fninfo, ARG_VGPR, ctx->v2i32, SI_PARAM_PERSP_SAMPLE);
+ add_arg_checked(&fninfo, ARG_VGPR, ctx->v2i32, SI_PARAM_PERSP_CENTER);
+ add_arg_checked(&fninfo, ARG_VGPR, ctx->v2i32, SI_PARAM_PERSP_CENTROID);
+ add_arg_checked(&fninfo, ARG_VGPR, v3i32, SI_PARAM_PERSP_PULL_MODEL);
+ add_arg_checked(&fninfo, ARG_VGPR, ctx->v2i32, SI_PARAM_LINEAR_SAMPLE);
+ add_arg_checked(&fninfo, ARG_VGPR, ctx->v2i32, SI_PARAM_LINEAR_CENTER);
+ add_arg_checked(&fninfo, ARG_VGPR, ctx->v2i32, SI_PARAM_LINEAR_CENTROID);
+ add_arg_checked(&fninfo, ARG_VGPR, ctx->f32, SI_PARAM_LINE_STIPPLE_TEX);
+ add_arg_checked(&fninfo, ARG_VGPR, ctx->f32, SI_PARAM_POS_X_FLOAT);
+ add_arg_checked(&fninfo, ARG_VGPR, ctx->f32, SI_PARAM_POS_Y_FLOAT);
+ add_arg_checked(&fninfo, ARG_VGPR, ctx->f32, SI_PARAM_POS_Z_FLOAT);
+ add_arg_checked(&fninfo, ARG_VGPR, ctx->f32, SI_PARAM_POS_W_FLOAT);
+ add_arg_checked(&fninfo, ARG_VGPR, ctx->i32, SI_PARAM_FRONT_FACE);
shader->info.face_vgpr_index = 20;
- params[SI_PARAM_ANCILLARY] = ctx->i32;
- params[SI_PARAM_SAMPLE_COVERAGE] = ctx->f32;
- params[SI_PARAM_POS_FIXED_PT] = ctx->i32;
- num_params = SI_PARAM_POS_FIXED_PT+1;
+ add_arg_checked(&fninfo, ARG_VGPR, ctx->i32, SI_PARAM_ANCILLARY);
+ add_arg_checked(&fninfo, ARG_VGPR, ctx->f32, SI_PARAM_SAMPLE_COVERAGE);
+ add_arg_checked(&fninfo, ARG_VGPR, ctx->i32, SI_PARAM_POS_FIXED_PT);
/* Color inputs from the prolog. */
if (shader->selector->info.colors_read) {
unsigned num_color_elements =
util_bitcount(shader->selector->info.colors_read);
- assert(num_params + num_color_elements <= ARRAY_SIZE(params));
+ assert(fninfo.num_params + num_color_elements <= ARRAY_SIZE(fninfo.types));
for (i = 0; i < num_color_elements; i++)
- params[num_params++] = ctx->f32;
+ add_arg(&fninfo, ARG_VGPR, ctx->f32);
num_prolog_vgprs += num_color_elements;
}
break;
case PIPE_SHADER_COMPUTE:
- declare_default_desc_pointers(ctx, params, &num_params);
+ declare_default_desc_pointers(ctx, &fninfo);
if (shader->selector->info.uses_grid_size)
- params[ctx->param_grid_size = num_params++] = v3i32;
+ ctx->param_grid_size = add_arg(&fninfo, ARG_SGPR, v3i32);
if (shader->selector->info.uses_block_size)
- params[ctx->param_block_size = num_params++] = v3i32;
+ ctx->param_block_size = add_arg(&fninfo, ARG_SGPR, v3i32);
for (i = 0; i < 3; i++) {
ctx->param_block_id[i] = -1;
if (shader->selector->info.uses_block_id[i])
- params[ctx->param_block_id[i] = num_params++] = ctx->i32;
+ ctx->param_block_id[i] = add_arg(&fninfo, ARG_SGPR, ctx->i32);
}
- last_sgpr = num_params - 1;
- params[ctx->param_thread_id = num_params++] = v3i32;
+ ctx->param_thread_id = add_arg(&fninfo, ARG_VGPR, v3i32);
break;
default:
assert(0 && "unimplemented shader");
return;
}
- assert(num_params <= ARRAY_SIZE(params));
-
- si_create_function(ctx, "main", returns, num_returns, params,
- num_params, last_sgpr,
+ si_create_function(ctx, "main", returns, num_returns, &fninfo,
si_get_max_workgroup_size(shader));
/* Reserve register locations for VGPR inputs the PS prolog may need. */
shader->info.num_input_sgprs = 0;
shader->info.num_input_vgprs = 0;
- for (i = 0; i <= last_sgpr; ++i)
- shader->info.num_input_sgprs += llvm_get_type_size(params[i]) / 4;
+ for (i = 0; i < fninfo.num_sgpr_params; ++i)
+ shader->info.num_input_sgprs += llvm_get_type_size(fninfo.types[i]) / 4;
- for (; i < num_params; ++i)
- shader->info.num_input_vgprs += llvm_get_type_size(params[i]) / 4;
+ for (; i < fninfo.num_params; ++i)
+ shader->info.num_input_vgprs += llvm_get_type_size(fninfo.types[i]) / 4;
assert(shader->info.num_input_vgprs >= num_prolog_vgprs);
shader->info.num_input_vgprs -= num_prolog_vgprs;
case R_00B028_SPI_SHADER_PGM_RSRC1_PS:
case R_00B128_SPI_SHADER_PGM_RSRC1_VS:
case R_00B228_SPI_SHADER_PGM_RSRC1_GS:
+ case R_00B428_SPI_SHADER_PGM_RSRC1_HS:
case R_00B848_COMPUTE_PGM_RSRC1:
conf->num_sgprs = MAX2(conf->num_sgprs, (G_00B028_SGPRS(value) + 1) * 8);
conf->num_vgprs = MAX2(conf->num_vgprs, (G_00B028_VGPRS(value) + 1) * 4);
conf->spi_ps_input_addr = conf->spi_ps_input_ena;
}
-void si_shader_apply_scratch_relocs(struct si_context *sctx,
- struct si_shader *shader,
- struct si_shader_config *config,
- uint64_t scratch_va)
+void si_shader_apply_scratch_relocs(struct si_shader *shader,
+ uint64_t scratch_va)
{
unsigned i;
uint32_t scratch_rsrc_dword0 = scratch_va;
}
}
-static unsigned si_get_shader_binary_size(struct si_shader *shader)
+static unsigned si_get_shader_binary_size(const struct si_shader *shader)
{
unsigned size = shader->binary.code_size;
!mainb->rodata_size);
assert(!epilog || !epilog->rodata_size);
- /* GFX9 can fetch at most 128 bytes past the end of the shader.
- * Prevent VM faults.
- */
- if (sscreen->b.chip_class >= GFX9)
- bo_size += 128;
-
r600_resource_reference(&shader->bo, NULL);
shader->bo = (struct r600_resource*)
pipe_buffer_create(&sscreen->b.b, 0,
PIPE_TRANSFER_READ_WRITE |
PIPE_TRANSFER_UNSYNCHRONIZED);
+ /* Don't use util_memcpy_cpu_to_le32. LLVM binaries are
+ * endian-independent. */
if (prolog) {
- util_memcpy_cpu_to_le32(ptr, prolog->code, prolog->code_size);
+ memcpy(ptr, prolog->code, prolog->code_size);
ptr += prolog->code_size;
}
if (previous_stage) {
- util_memcpy_cpu_to_le32(ptr, previous_stage->code,
- previous_stage->code_size);
+ memcpy(ptr, previous_stage->code, previous_stage->code_size);
ptr += previous_stage->code_size;
}
if (prolog2) {
- util_memcpy_cpu_to_le32(ptr, prolog2->code, prolog2->code_size);
+ memcpy(ptr, prolog2->code, prolog2->code_size);
ptr += prolog2->code_size;
}
- util_memcpy_cpu_to_le32(ptr, mainb->code, mainb->code_size);
+ memcpy(ptr, mainb->code, mainb->code_size);
ptr += mainb->code_size;
if (epilog)
- util_memcpy_cpu_to_le32(ptr, epilog->code, epilog->code_size);
+ memcpy(ptr, epilog->code, epilog->code_size);
else if (mainb->rodata_size > 0)
- util_memcpy_cpu_to_le32(ptr, mainb->rodata, mainb->rodata_size);
+ memcpy(ptr, mainb->rodata, mainb->rodata_size);
sscreen->b.ws->buffer_unmap(shader->bo->buf);
return 0;
}
static void si_shader_dump_stats(struct si_screen *sscreen,
- struct si_shader *shader,
+ const struct si_shader *shader,
struct pipe_debug_callback *debug,
unsigned processor,
FILE *file,
bool check_debug_option)
{
- struct si_shader_config *conf = &shader->config;
+ const struct si_shader_config *conf = &shader->config;
unsigned num_inputs = shader->selector ? shader->selector->info.num_inputs : 0;
unsigned code_size = si_get_shader_binary_size(shader);
unsigned lds_increment = sscreen->b.chip_class >= CIK ? 512 : 256;
conf->spilled_vgprs, conf->private_mem_vgprs);
}
-const char *si_get_shader_name(struct si_shader *shader, unsigned processor)
+const char *si_get_shader_name(const struct si_shader *shader, unsigned processor)
{
switch (processor) {
case PIPE_SHADER_VERTEX:
}
}
-void si_shader_dump(struct si_screen *sscreen, struct si_shader *shader,
+void si_shader_dump(struct si_screen *sscreen, const struct si_shader *shader,
struct pipe_debug_callback *debug, unsigned processor,
FILE *file, bool check_debug_option)
{
si_dump_shader_key(processor, shader, file);
if (!check_debug_option && shader->binary.llvm_ir_string) {
+ if (shader->previous_stage &&
+ shader->previous_stage->binary.llvm_ir_string) {
+ fprintf(file, "\n%s - previous stage - LLVM IR:\n\n",
+ si_get_shader_name(shader, processor));
+ fprintf(file, "%s\n", shader->previous_stage->binary.llvm_ir_string);
+ }
+
fprintf(file, "\n%s - main shader part - LLVM IR:\n\n",
si_get_shader_name(shader, processor));
fprintf(file, "%s\n", shader->binary.llvm_ir_string);
check_debug_option);
}
-int si_compile_llvm(struct si_screen *sscreen,
- struct ac_shader_binary *binary,
- struct si_shader_config *conf,
- LLVMTargetMachineRef tm,
- LLVMModuleRef mod,
- struct pipe_debug_callback *debug,
- unsigned processor,
- const char *name)
+static int si_compile_llvm(struct si_screen *sscreen,
+ struct ac_shader_binary *binary,
+ struct si_shader_config *conf,
+ LLVMTargetMachineRef tm,
+ LLVMModuleRef mod,
+ struct pipe_debug_callback *debug,
+ unsigned processor,
+ const char *name)
{
int r = 0;
unsigned count = p_atomic_inc_return(&sscreen->b.num_compilations);
preload_ring_buffers(&ctx);
LLVMValueRef voffset =
- lp_build_mul_imm(uint, LLVMGetParam(ctx.main_fn,
- ctx.param_vertex_id), 4);
+ lp_build_mul_imm(uint, ctx.abi.vertex_id, 4);
/* Fetch the vertex stream ID.*/
LLVMValueRef stream_id;
ac_build_buffer_load(&ctx.ac,
ctx.gsvs_ring[0], 1,
ctx.i32_0, voffset,
- soffset, 0, 1, 1, true);
+ soffset, 0, 1, 1,
+ true, false);
}
}
LLVMBuildRetVoid(gallivm->builder);
- /* Dump LLVM IR before any optimization passes */
- if (sscreen->b.debug_flags & DBG_PREOPT_IR &&
- r600_can_dump_shader(&sscreen->b, PIPE_SHADER_GEOMETRY))
- ac_dump_module(ctx.gallivm.module);
-
- si_llvm_finalize_module(&ctx,
- r600_extra_shader_checks(&sscreen->b, PIPE_SHADER_GEOMETRY));
+ ctx.type = PIPE_SHADER_GEOMETRY; /* override for shader dumping */
+ si_llvm_optimize_module(&ctx);
r = si_compile_llvm(sscreen, &ctx.shader->binary,
&ctx.shader->config, ctx.tm,
return shader;
}
-static void si_dump_shader_key_vs(struct si_shader_key *key,
- struct si_vs_prolog_bits *prolog,
+static void si_dump_shader_key_vs(const struct si_shader_key *key,
+ const struct si_vs_prolog_bits *prolog,
const char *prefix, FILE *f)
{
- fprintf(f, " %s.instance_divisors = {", prefix);
- for (int i = 0; i < ARRAY_SIZE(prolog->instance_divisors); i++) {
- fprintf(f, !i ? "%u" : ", %u",
- prolog->instance_divisors[i]);
- }
- fprintf(f, "}\n");
+ fprintf(f, " %s.instance_divisor_is_one = %u\n",
+ prefix, prolog->instance_divisor_is_one);
+ fprintf(f, " %s.instance_divisor_is_fetched = %u\n",
+ prefix, prolog->instance_divisor_is_fetched);
fprintf(f, " mono.vs.fix_fetch = {");
for (int i = 0; i < SI_MAX_ATTRIBS; i++)
fprintf(f, "}\n");
}
-static void si_dump_shader_key(unsigned processor, struct si_shader *shader,
+static void si_dump_shader_key(unsigned processor, const struct si_shader *shader,
FILE *f)
{
- struct si_shader_key *key = &shader->key;
+ const struct si_shader_key *key = &shader->key;
fprintf(f, "SHADER KEY\n");
"part.vs.prolog", f);
fprintf(f, " as_es = %u\n", key->as_es);
fprintf(f, " as_ls = %u\n", key->as_ls);
- fprintf(f, " mono.vs_export_prim_id = %u\n",
- key->mono.vs_export_prim_id);
+ fprintf(f, " mono.u.vs_export_prim_id = %u\n",
+ key->mono.u.vs_export_prim_id);
break;
case PIPE_SHADER_TESS_CTRL:
"part.tcs.ls_prolog", f);
}
fprintf(f, " part.tcs.epilog.prim_mode = %u\n", key->part.tcs.epilog.prim_mode);
- fprintf(f, " mono.ff_tcs_inputs_to_copy = 0x%"PRIx64"\n", key->mono.ff_tcs_inputs_to_copy);
+ fprintf(f, " mono.u.ff_tcs_inputs_to_copy = 0x%"PRIx64"\n", key->mono.u.ff_tcs_inputs_to_copy);
break;
case PIPE_SHADER_TESS_EVAL:
fprintf(f, " as_es = %u\n", key->as_es);
- fprintf(f, " mono.vs_export_prim_id = %u\n",
- key->mono.vs_export_prim_id);
+ fprintf(f, " mono.u.vs_export_prim_id = %u\n",
+ key->mono.u.vs_export_prim_id);
break;
case PIPE_SHADER_GEOMETRY:
processor == PIPE_SHADER_TESS_EVAL ||
processor == PIPE_SHADER_VERTEX) &&
!key->as_es && !key->as_ls) {
- fprintf(f, " opt.hw_vs.kill_outputs = 0x%"PRIx64"\n", key->opt.hw_vs.kill_outputs);
- fprintf(f, " opt.hw_vs.kill_outputs2 = 0x%x\n", key->opt.hw_vs.kill_outputs2);
- fprintf(f, " opt.hw_vs.clip_disable = %u\n", key->opt.hw_vs.clip_disable);
+ fprintf(f, " opt.kill_outputs = 0x%"PRIx64"\n", key->opt.kill_outputs);
+ fprintf(f, " opt.clip_disable = %u\n", key->opt.clip_disable);
}
}
LLVMTargetMachineRef tm)
{
struct lp_build_tgsi_context *bld_base;
- struct lp_build_tgsi_action tmpl = {};
si_llvm_context_init(ctx, sscreen, tm);
bld_base->op_actions[TGSI_OPCODE_INTERP_SAMPLE] = interp_action;
bld_base->op_actions[TGSI_OPCODE_INTERP_OFFSET] = interp_action;
- bld_base->op_actions[TGSI_OPCODE_TEX] = tex_action;
- bld_base->op_actions[TGSI_OPCODE_TEX_LZ] = tex_action;
- bld_base->op_actions[TGSI_OPCODE_TEX2] = tex_action;
- bld_base->op_actions[TGSI_OPCODE_TXB] = tex_action;
- bld_base->op_actions[TGSI_OPCODE_TXB2] = tex_action;
- bld_base->op_actions[TGSI_OPCODE_TXD] = tex_action;
- bld_base->op_actions[TGSI_OPCODE_TXF] = tex_action;
- bld_base->op_actions[TGSI_OPCODE_TXF_LZ] = tex_action;
- bld_base->op_actions[TGSI_OPCODE_TXL] = tex_action;
- bld_base->op_actions[TGSI_OPCODE_TXL2] = tex_action;
- bld_base->op_actions[TGSI_OPCODE_TXP] = tex_action;
- bld_base->op_actions[TGSI_OPCODE_TXQ].fetch_args = txq_fetch_args;
- bld_base->op_actions[TGSI_OPCODE_TXQ].emit = txq_emit;
- bld_base->op_actions[TGSI_OPCODE_TG4] = tex_action;
- bld_base->op_actions[TGSI_OPCODE_LODQ] = tex_action;
- bld_base->op_actions[TGSI_OPCODE_TXQS].emit = si_llvm_emit_txqs;
-
- bld_base->op_actions[TGSI_OPCODE_LOAD].fetch_args = load_fetch_args;
- bld_base->op_actions[TGSI_OPCODE_LOAD].emit = load_emit;
- bld_base->op_actions[TGSI_OPCODE_STORE].fetch_args = store_fetch_args;
- bld_base->op_actions[TGSI_OPCODE_STORE].emit = store_emit;
- bld_base->op_actions[TGSI_OPCODE_RESQ].fetch_args = resq_fetch_args;
- bld_base->op_actions[TGSI_OPCODE_RESQ].emit = resq_emit;
-
- tmpl.fetch_args = atomic_fetch_args;
- tmpl.emit = atomic_emit;
- bld_base->op_actions[TGSI_OPCODE_ATOMUADD] = tmpl;
- bld_base->op_actions[TGSI_OPCODE_ATOMUADD].intr_name = "add";
- bld_base->op_actions[TGSI_OPCODE_ATOMXCHG] = tmpl;
- bld_base->op_actions[TGSI_OPCODE_ATOMXCHG].intr_name = "swap";
- bld_base->op_actions[TGSI_OPCODE_ATOMCAS] = tmpl;
- bld_base->op_actions[TGSI_OPCODE_ATOMCAS].intr_name = "cmpswap";
- bld_base->op_actions[TGSI_OPCODE_ATOMAND] = tmpl;
- bld_base->op_actions[TGSI_OPCODE_ATOMAND].intr_name = "and";
- bld_base->op_actions[TGSI_OPCODE_ATOMOR] = tmpl;
- bld_base->op_actions[TGSI_OPCODE_ATOMOR].intr_name = "or";
- bld_base->op_actions[TGSI_OPCODE_ATOMXOR] = tmpl;
- bld_base->op_actions[TGSI_OPCODE_ATOMXOR].intr_name = "xor";
- bld_base->op_actions[TGSI_OPCODE_ATOMUMIN] = tmpl;
- bld_base->op_actions[TGSI_OPCODE_ATOMUMIN].intr_name = "umin";
- bld_base->op_actions[TGSI_OPCODE_ATOMUMAX] = tmpl;
- bld_base->op_actions[TGSI_OPCODE_ATOMUMAX].intr_name = "umax";
- bld_base->op_actions[TGSI_OPCODE_ATOMIMIN] = tmpl;
- bld_base->op_actions[TGSI_OPCODE_ATOMIMIN].intr_name = "smin";
- bld_base->op_actions[TGSI_OPCODE_ATOMIMAX] = tmpl;
- bld_base->op_actions[TGSI_OPCODE_ATOMIMAX].intr_name = "smax";
-
bld_base->op_actions[TGSI_OPCODE_MEMBAR].emit = membar_emit;
bld_base->op_actions[TGSI_OPCODE_CLOCK].emit = clock_emit;
bld_base->op_actions[TGSI_OPCODE_BARRIER].emit = si_llvm_emit_barrier;
}
-static void si_eliminate_const_vs_outputs(struct si_shader_context *ctx)
+static void si_optimize_vs_outputs(struct si_shader_context *ctx)
{
struct si_shader *shader = ctx->shader;
struct tgsi_shader_info *info = &shader->selector->info;
struct si_shader_selector *sel = shader->selector;
struct lp_build_tgsi_context *bld_base = &ctx->bld_base;
+ // TODO clean all this up!
switch (ctx->type) {
case PIPE_SHADER_VERTEX:
ctx->load_input = declare_input_vs;
bld_base->emit_epilogue = si_llvm_emit_ls_epilogue;
else if (shader->key.as_es)
bld_base->emit_epilogue = si_llvm_emit_es_epilogue;
- else
- bld_base->emit_epilogue = si_llvm_emit_vs_epilogue;
+ else {
+ ctx->abi.emit_outputs = si_llvm_emit_vs_epilogue;
+ bld_base->emit_epilogue = si_tgsi_emit_epilogue;
+ }
break;
case PIPE_SHADER_TESS_CTRL:
bld_base->emit_fetch_funcs[TGSI_FILE_INPUT] = fetch_input_tcs;
bld_base->emit_fetch_funcs[TGSI_FILE_INPUT] = fetch_input_tes;
if (shader->key.as_es)
bld_base->emit_epilogue = si_llvm_emit_es_epilogue;
- else
- bld_base->emit_epilogue = si_llvm_emit_vs_epilogue;
+ else {
+ ctx->abi.emit_outputs = si_llvm_emit_vs_epilogue;
+ bld_base->emit_epilogue = si_tgsi_emit_epilogue;
+ }
break;
case PIPE_SHADER_GEOMETRY:
bld_base->emit_fetch_funcs[TGSI_FILE_INPUT] = fetch_input_gs;
break;
case PIPE_SHADER_FRAGMENT:
ctx->load_input = declare_input_fs;
- bld_base->emit_epilogue = si_llvm_return_fs_outputs;
+ ctx->abi.emit_outputs = si_llvm_return_fs_outputs;
+ bld_base->emit_epilogue = si_tgsi_emit_epilogue;
break;
case PIPE_SHADER_COMPUTE:
ctx->declare_memory_region = declare_compute_memory;
return false;
}
+ ctx->abi.load_ubo = load_ubo;
+
create_function(ctx);
preload_ring_buffers(ctx);
/* For GFX9 merged shaders:
- * - Set EXEC. If the prolog is present, set EXEC there instead.
+ * - Set EXEC for the first shader. If the prolog is present, set
+ * EXEC there instead.
* - Add a barrier before the second shader.
+ * - In the second shader, reset EXEC to ~0 and wrap the main part in
+ * an if-statement. This is required for correctness in geometry
+ * shaders, to ensure that empty GS waves do not send GS_EMIT and
+ * GS_CUT messages.
*
- * The same thing for monolithic shaders is done in
- * si_build_wrapper_function.
+ * For monolithic merged shaders, the first shader is wrapped in an
+ * if-block together with its prolog in si_build_wrapper_function.
*/
- if (ctx->screen->b.chip_class >= GFX9 && !is_monolithic) {
- if (sel->info.num_instructions > 1 && /* not empty shader */
+ if (ctx->screen->b.chip_class >= GFX9) {
+ if (!is_monolithic &&
+ sel->info.num_instructions > 1 && /* not empty shader */
(shader->key.as_es || shader->key.as_ls) &&
(ctx->type == PIPE_SHADER_TESS_EVAL ||
(ctx->type == PIPE_SHADER_VERTEX &&
ctx->param_merged_wave_info, 0);
} else if (ctx->type == PIPE_SHADER_TESS_CTRL ||
ctx->type == PIPE_SHADER_GEOMETRY) {
- si_init_exec_from_input(ctx,
- ctx->param_merged_wave_info, 8);
+ if (!is_monolithic)
+ si_init_exec_full_mask(ctx);
+
+ /* The barrier must execute for all shaders in a
+ * threadgroup.
+ */
si_llvm_emit_barrier(NULL, bld_base, NULL);
+
+ LLVMValueRef num_threads = unpack_param(ctx, ctx->param_merged_wave_info, 8, 8);
+ LLVMValueRef ena =
+ LLVMBuildICmp(ctx->ac.builder, LLVMIntULT,
+ ac_get_thread_id(&ctx->ac), num_threads, "");
+ lp_build_if(&ctx->merged_wrap_if_state, &ctx->gallivm, ena);
}
}
}
}
- if (!lp_build_tgsi_llvm(bld_base, sel->tokens)) {
- fprintf(stderr, "Failed to translate shader from TGSI to LLVM\n");
- return false;
+ if (ctx->type == PIPE_SHADER_FRAGMENT && sel->info.uses_kill &&
+ ctx->screen->b.debug_flags & DBG_FS_CORRECT_DERIVS_AFTER_KILL) {
+ /* This is initialized to 0.0 = not kill. */
+ ctx->postponed_kill = lp_build_alloca(&ctx->gallivm, ctx->f32, "");
+ }
+
+ if (sel->tokens) {
+ if (!lp_build_tgsi_llvm(bld_base, sel->tokens)) {
+ fprintf(stderr, "Failed to translate shader from TGSI to LLVM\n");
+ return false;
+ }
+ } else {
+ if (!si_nir_build_llvm(ctx, sel->nir)) {
+ fprintf(stderr, "Failed to translate shader from NIR to LLVM\n");
+ return false;
+ }
}
si_llvm_build_ret(ctx, ctx->return_value);
key->vs_prolog.num_merged_next_stage_vgprs = 5;
}
- /* Set the instanceID flag. */
- for (unsigned i = 0; i < info->num_inputs; i++)
- if (key->vs_prolog.states.instance_divisors[i])
- shader_out->info.uses_instanceid = true;
+ /* Enable loading the InstanceID VGPR. */
+ uint16_t input_mask = u_bit_consecutive(0, info->num_inputs);
+
+ if ((key->vs_prolog.states.instance_divisor_is_one |
+ key->vs_prolog.states.instance_divisor_is_fetched) & input_mask)
+ shader_out->info.uses_instanceid = true;
}
/**
{
unsigned num_sgprs, num_vgprs;
struct gallivm_state *gallivm = &ctx->gallivm;
+ struct si_function_info fninfo;
LLVMBuilderRef builder = gallivm->builder;
- LLVMTypeRef params[48]; /* 40 SGPRs (maximum) + some VGPRs */
LLVMTypeRef returns[48];
LLVMValueRef func, ret;
+ si_init_function_info(&fninfo);
+
if (ctx->screen->b.chip_class >= GFX9) {
num_sgprs = 8 + GFX9_GS_NUM_USER_SGPR;
num_vgprs = 5; /* ES inputs are not needed by GS */
}
for (unsigned i = 0; i < num_sgprs; ++i) {
- params[i] = ctx->i32;
+ add_arg(&fninfo, ARG_SGPR, ctx->i32);
returns[i] = ctx->i32;
}
for (unsigned i = 0; i < num_vgprs; ++i) {
- params[num_sgprs + i] = ctx->i32;
+ add_arg(&fninfo, ARG_VGPR, ctx->i32);
returns[num_sgprs + i] = ctx->f32;
}
/* Create the function. */
si_create_function(ctx, "gs_prolog", returns, num_sgprs + num_vgprs,
- params, num_sgprs + num_vgprs, num_sgprs - 1, 0);
+ &fninfo, 0);
func = ctx->main_fn;
/* Set the full EXEC mask for the prolog, because we are only fiddling
{
struct gallivm_state *gallivm = &ctx->gallivm;
LLVMBuilderRef builder = ctx->gallivm.builder;
- /* PS epilog has one arg per color component */
- LLVMTypeRef param_types[48];
- LLVMValueRef initial[48], out[48];
+ /* PS epilog has one arg per color component; gfx9 merged shader
+ * prologs need to forward 32 user SGPRs.
+ */
+ struct si_function_info fninfo;
+ LLVMValueRef initial[64], out[64];
LLVMTypeRef function_type;
- unsigned num_params;
+ unsigned num_first_params;
unsigned num_out, initial_num_out;
MAYBE_UNUSED unsigned num_out_sgpr; /* used in debug checks */
MAYBE_UNUSED unsigned initial_num_out_sgpr; /* used in debug checks */
unsigned num_sgprs, num_vgprs;
- unsigned last_sgpr_param;
unsigned gprs;
struct lp_build_if_state if_state;
+ si_init_function_info(&fninfo);
+
for (unsigned i = 0; i < num_parts; ++i) {
lp_add_function_attr(parts[i], -1, LP_FUNC_ATTR_ALWAYSINLINE);
LLVMSetLinkage(parts[i], LLVMPrivateLinkage);
num_vgprs = 0;
function_type = LLVMGetElementType(LLVMTypeOf(parts[0]));
- num_params = LLVMCountParamTypes(function_type);
+ num_first_params = LLVMCountParamTypes(function_type);
- for (unsigned i = 0; i < num_params; ++i) {
+ for (unsigned i = 0; i < num_first_params; ++i) {
LLVMValueRef param = LLVMGetParam(parts[0], i);
if (ac_is_sgpr_param(param)) {
num_vgprs += llvm_get_type_size(LLVMTypeOf(param)) / 4;
}
}
- assert(num_vgprs + num_sgprs <= ARRAY_SIZE(param_types));
- num_params = 0;
- last_sgpr_param = 0;
gprs = 0;
while (gprs < num_sgprs + num_vgprs) {
- LLVMValueRef param = LLVMGetParam(parts[main_part], num_params);
- unsigned size;
+ LLVMValueRef param = LLVMGetParam(parts[main_part], fninfo.num_params);
+ LLVMTypeRef type = LLVMTypeOf(param);
+ unsigned size = llvm_get_type_size(type) / 4;
- param_types[num_params] = LLVMTypeOf(param);
- if (gprs < num_sgprs)
- last_sgpr_param = num_params;
- size = llvm_get_type_size(param_types[num_params]) / 4;
- num_params++;
+ add_arg(&fninfo, gprs < num_sgprs ? ARG_SGPR : ARG_VGPR, type);
assert(ac_is_sgpr_param(param) == (gprs < num_sgprs));
assert(gprs + size <= num_sgprs + num_vgprs &&
gprs += size;
}
- si_create_function(ctx, "wrapper", NULL, 0, param_types, num_params,
- last_sgpr_param,
+ si_create_function(ctx, "wrapper", NULL, 0, &fninfo,
si_get_max_workgroup_size(ctx->shader));
if (is_merged_shader(ctx->shader))
num_out = 0;
num_out_sgpr = 0;
- for (unsigned i = 0; i < num_params; ++i) {
+ for (unsigned i = 0; i < fninfo.num_params; ++i) {
LLVMValueRef param = LLVMGetParam(ctx->main_fn, i);
LLVMTypeRef param_type = LLVMTypeOf(param);
- LLVMTypeRef out_type = i <= last_sgpr_param ? ctx->i32 : ctx->f32;
+ LLVMTypeRef out_type = i < fninfo.num_sgpr_params ? ctx->i32 : ctx->f32;
unsigned size = llvm_get_type_size(param_type) / 4;
if (size == 1) {
builder, param, LLVMConstInt(ctx->i32, j, 0), "");
}
- if (i <= last_sgpr_param)
+ if (i < fninfo.num_sgpr_params)
num_out_sgpr = num_out;
}
LLVMValueRef ret;
LLVMTypeRef ret_type;
unsigned out_idx = 0;
-
- num_params = LLVMCountParams(parts[part]);
- assert(num_params <= ARRAY_SIZE(param_types));
+ unsigned num_params = LLVMCountParams(parts[part]);
/* Merged shaders are executed conditionally depending
* on the number of enabled threads passed in the input SGPRs. */
- if (is_merged_shader(ctx->shader) &&
- (part == 0 || part == next_shader_first_part)) {
+ if (is_merged_shader(ctx->shader) && part == 0) {
LLVMValueRef ena, count = initial[3];
- /* The thread count for the 2nd shader is at bit-offset 8. */
- if (part == next_shader_first_part) {
- count = LLVMBuildLShr(builder, count,
- LLVMConstInt(ctx->i32, 8, 0), "");
- }
count = LLVMBuildAnd(builder, count,
LLVMConstInt(ctx->i32, 0x7f, 0), "");
ena = LLVMBuildICmp(builder, LLVMIntULT,
ret = LLVMBuildCall(builder, parts[part], in, num_params, "");
if (is_merged_shader(ctx->shader) &&
- (part + 1 == next_shader_first_part ||
- part + 1 == num_parts)) {
+ part + 1 == next_shader_first_part) {
lp_build_endif(&if_state);
- if (part + 1 == next_shader_first_part) {
- /* A barrier is required between 2 merged shaders. */
- si_llvm_emit_barrier(NULL, &ctx->bld_base, NULL);
-
- /* The second half of the merged shader should use
- * the inputs from the toplevel (wrapper) function,
- * not the return value from the last call.
- *
- * That's because the last call was executed condi-
- * tionally, so we can't consume it in the main
- * block.
- */
- memcpy(out, initial, sizeof(initial));
- num_out = initial_num_out;
- num_out_sgpr = initial_num_out_sgpr;
- }
+ /* The second half of the merged shader should use
+ * the inputs from the toplevel (wrapper) function,
+ * not the return value from the last call.
+ *
+ * That's because the last call was executed condi-
+ * tionally, so we can't consume it in the main
+ * block.
+ */
+ memcpy(out, initial, sizeof(initial));
+ num_out = initial_num_out;
+ num_out_sgpr = initial_num_out_sgpr;
continue;
}
LLVMValueRef val =
LLVMBuildExtractValue(builder, ret, i, "");
+ assert(num_out < ARRAY_SIZE(out));
out[num_out++] = val;
if (LLVMTypeOf(val) == ctx->i32) {
* conversion fails. */
if (r600_can_dump_shader(&sscreen->b, sel->info.processor) &&
!(sscreen->b.debug_flags & DBG_NO_TGSI)) {
- tgsi_dump(sel->tokens, 0);
+ if (sel->tokens)
+ tgsi_dump(sel->tokens, 0);
+ else
+ nir_print_shader(sel->nir, stderr);
si_dump_streamout(&sel->so);
}
need_prolog ? 1 : 0, 0);
}
- /* Dump LLVM IR before any optimization passes */
- if (sscreen->b.debug_flags & DBG_PREOPT_IR &&
- r600_can_dump_shader(&sscreen->b, ctx.type))
- LLVMDumpModule(ctx.gallivm.module);
-
- si_llvm_finalize_module(&ctx,
- r600_extra_shader_checks(&sscreen->b, ctx.type));
+ si_llvm_optimize_module(&ctx);
/* Post-optimization transformations and analysis. */
- si_eliminate_const_vs_outputs(&ctx);
+ si_optimize_vs_outputs(&ctx);
if ((debug && debug->debug_message) ||
r600_can_dump_shader(&sscreen->b, ctx.type))
build(&ctx, key);
/* Compile. */
- si_llvm_finalize_module(&ctx,
- r600_extra_shader_checks(&sscreen->b, PIPE_SHADER_FRAGMENT));
+ si_llvm_optimize_module(&ctx);
if (si_compile_llvm(sscreen, &result->binary, &result->config, tm,
gallivm->module, debug, ctx.type, name)) {
return result;
}
+static LLVMValueRef si_prolog_get_rw_buffers(struct si_shader_context *ctx)
+{
+ struct gallivm_state *gallivm = &ctx->gallivm;
+ LLVMValueRef ptr[2], list;
+
+ /* Get the pointer to rw buffers. */
+ ptr[0] = LLVMGetParam(ctx->main_fn, SI_SGPR_RW_BUFFERS);
+ ptr[1] = LLVMGetParam(ctx->main_fn, SI_SGPR_RW_BUFFERS_HI);
+ list = lp_build_gather_values(gallivm, ptr, 2);
+ list = LLVMBuildBitCast(gallivm->builder, list, ctx->i64, "");
+ list = LLVMBuildIntToPtr(gallivm->builder, list,
+ si_const_array(ctx->v4i32, SI_NUM_RW_BUFFERS), "");
+ return list;
+}
+
/**
* Build the vertex shader prolog function.
*
union si_shader_part_key *key)
{
struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMTypeRef *params, *returns;
+ struct si_function_info fninfo;
+ LLVMTypeRef *returns;
LLVMValueRef ret, func;
- int last_sgpr, num_params, num_returns, i;
+ int num_returns, i;
unsigned first_vs_vgpr = key->vs_prolog.num_input_sgprs +
key->vs_prolog.num_merged_next_stage_vgprs;
unsigned num_input_vgprs = key->vs_prolog.num_merged_next_stage_vgprs + 4;
num_input_vgprs;
unsigned user_sgpr_base = key->vs_prolog.num_merged_next_stage_vgprs ? 8 : 0;
- ctx->param_vertex_id = first_vs_vgpr;
- ctx->param_instance_id = first_vs_vgpr + (key->vs_prolog.as_ls ? 2 : 1);
+ si_init_function_info(&fninfo);
/* 4 preloaded VGPRs + vertex load indices as prolog outputs */
- params = alloca(num_all_input_regs * sizeof(LLVMTypeRef));
returns = alloca((num_all_input_regs + key->vs_prolog.last_input + 1) *
sizeof(LLVMTypeRef));
- num_params = 0;
num_returns = 0;
/* Declare input and output SGPRs. */
- num_params = 0;
for (i = 0; i < key->vs_prolog.num_input_sgprs; i++) {
- params[num_params++] = ctx->i32;
+ add_arg(&fninfo, ARG_SGPR, ctx->i32);
returns[num_returns++] = ctx->i32;
}
- last_sgpr = num_params - 1;
/* Preloaded VGPRs (outputs must be floats) */
for (i = 0; i < num_input_vgprs; i++) {
- params[num_params++] = ctx->i32;
+ add_arg(&fninfo, ARG_VGPR, ctx->i32);
returns[num_returns++] = ctx->f32;
}
+ fninfo.assign[first_vs_vgpr] = &ctx->abi.vertex_id;
+ fninfo.assign[first_vs_vgpr + (key->vs_prolog.as_ls ? 2 : 1)] = &ctx->abi.instance_id;
+
/* Vertex load indices. */
for (i = 0; i <= key->vs_prolog.last_input; i++)
returns[num_returns++] = ctx->f32;
/* Create the function. */
- si_create_function(ctx, "vs_prolog", returns, num_returns, params,
- num_params, last_sgpr, 0);
+ si_create_function(ctx, "vs_prolog", returns, num_returns, &fninfo, 0);
func = ctx->main_fn;
if (key->vs_prolog.num_merged_next_stage_vgprs &&
LLVMValueRef p = LLVMGetParam(func, i);
ret = LLVMBuildInsertValue(gallivm->builder, ret, p, i, "");
}
- for (; i < num_params; i++) {
+ for (; i < fninfo.num_params; i++) {
LLVMValueRef p = LLVMGetParam(func, i);
p = LLVMBuildBitCast(gallivm->builder, p, ctx->f32, "");
ret = LLVMBuildInsertValue(gallivm->builder, ret, p, i, "");
}
/* Compute vertex load indices from instance divisors. */
+ LLVMValueRef instance_divisor_constbuf = NULL;
+
+ if (key->vs_prolog.states.instance_divisor_is_fetched) {
+ LLVMValueRef list = si_prolog_get_rw_buffers(ctx);
+ LLVMValueRef buf_index =
+ LLVMConstInt(ctx->i32, SI_VS_CONST_INSTANCE_DIVISORS, 0);
+ instance_divisor_constbuf =
+ ac_build_indexed_load_const(&ctx->ac, list, buf_index);
+ }
+
for (i = 0; i <= key->vs_prolog.last_input; i++) {
- unsigned divisor = key->vs_prolog.states.instance_divisors[i];
+ bool divisor_is_one =
+ key->vs_prolog.states.instance_divisor_is_one & (1u << i);
+ bool divisor_is_fetched =
+ key->vs_prolog.states.instance_divisor_is_fetched & (1u << i);
LLVMValueRef index;
- if (divisor) {
+ if (divisor_is_one || divisor_is_fetched) {
+ LLVMValueRef divisor = ctx->i32_1;
+
+ if (divisor_is_fetched) {
+ divisor = buffer_load_const(ctx, instance_divisor_constbuf,
+ LLVMConstInt(ctx->i32, i * 4, 0));
+ divisor = LLVMBuildBitCast(gallivm->builder, divisor,
+ ctx->i32, "");
+ }
+
/* InstanceID / Divisor + StartInstance */
index = get_instance_index_for_fetch(ctx,
user_sgpr_base +
} else {
/* VertexID + BaseVertex */
index = LLVMBuildAdd(gallivm->builder,
- LLVMGetParam(func, ctx->param_vertex_id),
+ ctx->abi.vertex_id,
LLVMGetParam(func, user_sgpr_base +
SI_SGPR_BASE_VERTEX), "");
}
index = LLVMBuildBitCast(gallivm->builder, index, ctx->f32, "");
ret = LLVMBuildInsertValue(gallivm->builder, ret, index,
- num_params++, "");
+ fninfo.num_params + i, "");
}
si_llvm_build_ret(ctx, ret);
{
struct gallivm_state *gallivm = &ctx->gallivm;
struct lp_build_tgsi_context *bld_base = &ctx->bld_base;
- LLVMTypeRef params[32];
+ struct si_function_info fninfo;
LLVMValueRef func;
- int last_sgpr, num_params = 0;
+
+ si_init_function_info(&fninfo);
if (ctx->screen->b.chip_class >= GFX9) {
- params[num_params++] = ctx->i64;
- params[ctx->param_tcs_offchip_offset = num_params++] = ctx->i32;
- params[num_params++] = ctx->i32; /* wave info */
- params[ctx->param_tcs_factor_offset = num_params++] = ctx->i32;
- params[num_params++] = ctx->i32;
- params[num_params++] = ctx->i32;
- params[num_params++] = ctx->i32;
- params[num_params++] = ctx->i64;
- params[num_params++] = ctx->i64;
- params[num_params++] = ctx->i64;
- params[num_params++] = ctx->i64;
- params[num_params++] = ctx->i64;
- params[num_params++] = ctx->i64;
- params[num_params++] = ctx->i32;
- params[num_params++] = ctx->i32;
- params[num_params++] = ctx->i32;
- params[num_params++] = ctx->i32;
- params[ctx->param_tcs_offchip_layout = num_params++] = ctx->i32;
- params[num_params++] = ctx->i32;
- params[num_params++] = ctx->i32;
- params[ctx->param_tcs_offchip_addr_base64k = num_params++] = ctx->i32;
- params[ctx->param_tcs_factor_addr_base64k = num_params++] = ctx->i32;
+ add_arg(&fninfo, ARG_SGPR, ctx->i64);
+ ctx->param_tcs_offchip_offset = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ add_arg(&fninfo, ARG_SGPR, ctx->i32); /* wave info */
+ ctx->param_tcs_factor_offset = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ add_arg(&fninfo, ARG_SGPR, ctx->i64);
+ add_arg(&fninfo, ARG_SGPR, ctx->i64);
+ add_arg(&fninfo, ARG_SGPR, ctx->i64);
+ add_arg(&fninfo, ARG_SGPR, ctx->i64);
+ add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_offchip_layout = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_offchip_addr_base64k = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_factor_addr_base64k = add_arg(&fninfo, ARG_SGPR, ctx->i32);
} else {
- params[num_params++] = ctx->i64;
- params[num_params++] = ctx->i64;
- params[num_params++] = ctx->i64;
- params[num_params++] = ctx->i64;
- params[num_params++] = ctx->i64;
- params[ctx->param_tcs_offchip_layout = num_params++] = ctx->i32;
- params[num_params++] = ctx->i32;
- params[num_params++] = ctx->i32;
- params[num_params++] = ctx->i32;
- params[ctx->param_tcs_offchip_addr_base64k = num_params++] = ctx->i32;
- params[ctx->param_tcs_factor_addr_base64k = num_params++] = ctx->i32;
- params[ctx->param_tcs_offchip_offset = num_params++] = ctx->i32;
- params[ctx->param_tcs_factor_offset = num_params++] = ctx->i32;
- }
- last_sgpr = num_params - 1;
-
- params[num_params++] = ctx->i32; /* patch index within the wave (REL_PATCH_ID) */
- params[num_params++] = ctx->i32; /* invocation ID within the patch */
- params[num_params++] = ctx->i32; /* LDS offset where tess factors should be loaded from */
+ add_arg(&fninfo, ARG_SGPR, ctx->i64);
+ add_arg(&fninfo, ARG_SGPR, ctx->i64);
+ add_arg(&fninfo, ARG_SGPR, ctx->i64);
+ ctx->param_tcs_offchip_layout = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_offchip_addr_base64k = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_factor_addr_base64k = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_offchip_offset = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ ctx->param_tcs_factor_offset = add_arg(&fninfo, ARG_SGPR, ctx->i32);
+ }
+
+ add_arg(&fninfo, ARG_VGPR, ctx->i32); /* VGPR gap */
+ add_arg(&fninfo, ARG_VGPR, ctx->i32); /* VGPR gap */
+ unsigned tess_factors_idx =
+ add_arg(&fninfo, ARG_VGPR, ctx->i32); /* patch index within the wave (REL_PATCH_ID) */
+ add_arg(&fninfo, ARG_VGPR, ctx->i32); /* invocation ID within the patch */
+ add_arg(&fninfo, ARG_VGPR, ctx->i32); /* LDS offset where tess factors should be loaded from */
/* Create the function. */
- si_create_function(ctx, "tcs_epilog", NULL, 0, params, num_params, last_sgpr,
+ si_create_function(ctx, "tcs_epilog", NULL, 0, &fninfo,
ctx->screen->b.chip_class >= CIK ? 128 : 64);
declare_lds_as_pointer(ctx);
func = ctx->main_fn;
si_write_tess_factors(bld_base,
- LLVMGetParam(func, last_sgpr + 1),
- LLVMGetParam(func, last_sgpr + 2),
- LLVMGetParam(func, last_sgpr + 3));
+ LLVMGetParam(func, tess_factors_idx),
+ LLVMGetParam(func, tess_factors_idx + 1),
+ LLVMGetParam(func, tess_factors_idx + 2));
LLVMBuildRetVoid(gallivm->builder);
}
union si_shader_part_key *key)
{
struct gallivm_state *gallivm = &ctx->gallivm;
- LLVMTypeRef *params;
+ struct si_function_info fninfo;
LLVMValueRef ret, func;
- int last_sgpr, num_params, num_returns, i, num_color_channels;
+ int num_returns, i, num_color_channels;
assert(si_need_ps_prolog(key));
- /* Number of inputs + 8 color elements. */
- params = alloca((key->ps_prolog.num_input_sgprs +
- key->ps_prolog.num_input_vgprs + 8) *
- sizeof(LLVMTypeRef));
+ si_init_function_info(&fninfo);
/* Declare inputs. */
- num_params = 0;
for (i = 0; i < key->ps_prolog.num_input_sgprs; i++)
- params[num_params++] = ctx->i32;
- last_sgpr = num_params - 1;
+ add_arg(&fninfo, ARG_SGPR, ctx->i32);
for (i = 0; i < key->ps_prolog.num_input_vgprs; i++)
- params[num_params++] = ctx->f32;
+ add_arg(&fninfo, ARG_VGPR, ctx->f32);
/* Declare outputs (same as inputs + add colors if needed) */
- num_returns = num_params;
+ num_returns = fninfo.num_params;
num_color_channels = util_bitcount(key->ps_prolog.colors_read);
for (i = 0; i < num_color_channels; i++)
- params[num_returns++] = ctx->f32;
+ fninfo.types[num_returns++] = ctx->f32;
/* Create the function. */
- si_create_function(ctx, "ps_prolog", params, num_returns, params,
- num_params, last_sgpr, 0);
+ si_create_function(ctx, "ps_prolog", fninfo.types, num_returns,
+ &fninfo, 0);
func = ctx->main_fn;
/* Copy inputs to outputs. This should be no-op, as the registers match,
* but it will prevent the compiler from overwriting them unintentionally.
*/
ret = ctx->return_value;
- for (i = 0; i < num_params; i++) {
+ for (i = 0; i < fninfo.num_params; i++) {
LLVMValueRef p = LLVMGetParam(func, i);
ret = LLVMBuildInsertValue(gallivm->builder, ret, p, i, "");
}
/* POS_FIXED_PT is always last. */
unsigned pos = key->ps_prolog.num_input_sgprs +
key->ps_prolog.num_input_vgprs - 1;
- LLVMValueRef ptr[2], list;
-
- /* Get the pointer to rw buffers. */
- ptr[0] = LLVMGetParam(func, SI_SGPR_RW_BUFFERS);
- ptr[1] = LLVMGetParam(func, SI_SGPR_RW_BUFFERS_HI);
- list = lp_build_gather_values(gallivm, ptr, 2);
- list = LLVMBuildBitCast(gallivm->builder, list, ctx->i64, "");
- list = LLVMBuildIntToPtr(gallivm->builder, list,
- const_array(ctx->v4i32, SI_NUM_RW_BUFFERS), "");
+ LLVMValueRef list = si_prolog_get_rw_buffers(ctx);
si_llvm_emit_polygon_stipple(ctx, list, pos);
}
}
/* Interpolate colors. */
+ unsigned color_out_idx = 0;
for (i = 0; i < 2; i++) {
unsigned writemask = (key->ps_prolog.colors_read >> (i * 4)) & 0xf;
unsigned face_vgpr = key->ps_prolog.num_input_sgprs +
while (writemask) {
unsigned chan = u_bit_scan(&writemask);
ret = LLVMBuildInsertValue(gallivm->builder, ret, color[chan],
- num_params++, "");
+ fninfo.num_params + color_out_idx++, "");
}
}
{
struct gallivm_state *gallivm = &ctx->gallivm;
struct lp_build_tgsi_context *bld_base = &ctx->bld_base;
- LLVMTypeRef params[16+8*4+3];
+ struct si_function_info fninfo;
LLVMValueRef depth = NULL, stencil = NULL, samplemask = NULL;
- int last_sgpr, num_params = 0, i;
+ int i;
struct si_ps_exports exp = {};
+ si_init_function_info(&fninfo);
+
/* Declare input SGPRs. */
- params[ctx->param_rw_buffers = num_params++] = ctx->i64;
- params[ctx->param_const_buffers = num_params++] = ctx->i64;
- params[ctx->param_samplers = num_params++] = ctx->i64;
- params[ctx->param_images = num_params++] = ctx->i64;
- params[ctx->param_shader_buffers = num_params++] = ctx->i64;
- assert(num_params == SI_PARAM_ALPHA_REF);
- params[SI_PARAM_ALPHA_REF] = ctx->f32;
- last_sgpr = SI_PARAM_ALPHA_REF;
+ ctx->param_rw_buffers = add_arg(&fninfo, ARG_SGPR, ctx->i64);
+ ctx->param_const_and_shader_buffers = add_arg(&fninfo, ARG_SGPR, ctx->i64);
+ ctx->param_samplers_and_images = add_arg(&fninfo, ARG_SGPR, ctx->i64);
+ add_arg_checked(&fninfo, ARG_SGPR, ctx->f32, SI_PARAM_ALPHA_REF);
/* Declare input VGPRs. */
- num_params = (last_sgpr + 1) +
+ unsigned required_num_params =
+ fninfo.num_sgpr_params +
util_bitcount(key->ps_epilog.colors_written) * 4 +
key->ps_epilog.writes_z +
key->ps_epilog.writes_stencil +
key->ps_epilog.writes_samplemask;
- num_params = MAX2(num_params,
- last_sgpr + 1 + PS_EPILOG_SAMPLEMASK_MIN_LOC + 1);
-
- assert(num_params <= ARRAY_SIZE(params));
+ required_num_params = MAX2(required_num_params,
+ fninfo.num_sgpr_params + PS_EPILOG_SAMPLEMASK_MIN_LOC + 1);
- for (i = last_sgpr + 1; i < num_params; i++)
- params[i] = ctx->f32;
+ while (fninfo.num_params < required_num_params)
+ add_arg(&fninfo, ARG_VGPR, ctx->f32);
/* Create the function. */
- si_create_function(ctx, "ps_epilog", NULL, 0, params, num_params,
- last_sgpr, 0);
+ si_create_function(ctx, "ps_epilog", NULL, 0, &fninfo, 0);
/* Disable elimination of unused inputs. */
si_llvm_add_attribute(ctx->main_fn,
"InitialPSInputAddr", 0xffffff);
/* Process colors. */
- unsigned vgpr = last_sgpr + 1;
+ unsigned vgpr = fninfo.num_sgpr_params;
unsigned colors_written = key->ps_epilog.colors_written;
int last_color_export = -1;
if (colors_written == 0x1 && key->ps_epilog.states.last_cbuf > 0) {
/* Just set this if any of the colorbuffers are enabled. */
if (spi_format &
- ((1llu << (4 * (key->ps_epilog.states.last_cbuf + 1))) - 1))
+ ((1ull << (4 * (key->ps_epilog.states.last_cbuf + 1))) - 1))
last_color_export = 0;
} else {
for (i = 0; i < 8; i++)
color[i] = LLVMGetParam(ctx->main_fn, vgpr++);
si_export_mrt_color(bld_base, color, mrt,
- num_params - 1,
+ fninfo.num_params - 1,
mrt == last_color_export, &exp);
}
if (r)
return r;
} else {
- /* The shader consists of 2-3 parts:
+ /* The shader consists of several parts:
*
* - the middle part is the user shader, it has 1 variant only
* and it was compiled during the creation of the shader
* - the epilog part is inserted at the end
*
* The prolog and epilog have many (but simple) variants.
+ *
+ * Starting with gfx9, geometry and tessellation control
+ * shaders also contain the prolog and user shader parts of
+ * the previous shader stage.
*/
+ if (!mainp)
+ return -1;
+
/* Copy the compiled TGSI shader data over. */
shader->is_binary_shared = true;
shader->binary = mainp->binary;