#include "util/u_memory.h"
#include "util/u_string.h"
#include "tgsi/tgsi_build.h"
+#include "tgsi/tgsi_strings.h"
#include "tgsi/tgsi_util.h"
#include "tgsi/tgsi_dump.h"
+#include "ac_binary.h"
#include "ac_exp_param.h"
#include "ac_shader_util.h"
+#include "ac_rtld.h"
#include "ac_llvm_util.h"
#include "si_shader_internal.h"
#include "si_pipe.h"
#include "compiler/nir/nir.h"
-static const char *scratch_rsrc_dword0_symbol =
+static const char scratch_rsrc_dword0_symbol[] =
"SCRATCH_RSRC_DWORD0";
-static const char *scratch_rsrc_dword1_symbol =
+static const char scratch_rsrc_dword1_symbol[] =
"SCRATCH_RSRC_DWORD1";
struct si_shader_output_values
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,
struct ac_llvm_compiler *compiler);
union si_shader_part_key *key);
static void si_build_ps_epilog_function(struct si_shader_context *ctx,
union si_shader_part_key *key);
+static void si_fix_resource_usage(struct si_screen *sscreen,
+ struct si_shader *shader);
/* Ideally pass the sample mask input to the PS epilog as v14, which
* is its usual location, so that the shader doesn't have to add v_mov.
static bool is_merged_shader(struct si_shader_context *ctx)
{
- if (ctx->screen->info.chip_class <= VI)
+ if (ctx->screen->info.chip_class <= GFX8)
return false;
return ctx->shader->key.as_ls ||
ctx->type == PIPE_SHADER_GEOMETRY;
}
-static void si_init_function_info(struct si_function_info *fninfo)
+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,
+unsigned add_arg_assign(struct si_function_info *fninfo,
enum si_arg_regfile regfile, LLVMTypeRef type,
LLVMValueRef *assign)
{
}
}
-/* Bitcast <4 x float> to <2 x double>, extract the component, and convert
- * to float. */
-static LLVMValueRef extract_double_to_float(struct si_shader_context *ctx,
- LLVMValueRef vec4,
- unsigned double_index)
-{
- LLVMBuilderRef builder = ctx->ac.builder;
- LLVMTypeRef f64 = LLVMDoubleTypeInContext(ctx->ac.context);
- LLVMValueRef dvec2 = LLVMBuildBitCast(builder, vec4,
- LLVMVectorType(f64, 2), "");
- LLVMValueRef index = LLVMConstInt(ctx->i32, double_index, 0);
- LLVMValueRef value = LLVMBuildExtractElement(builder, dvec2, index, "");
- return LLVMBuildFPTrunc(builder, value, ctx->f32, "");
-}
-
static LLVMValueRef unpack_sint16(struct si_shader_context *ctx,
LLVMValueRef i32, unsigned index)
{
return;
}
- unsigned chan;
- unsigned fix_fetch;
- unsigned num_fetches;
- unsigned fetch_stride;
- unsigned num_channels;
-
+ union si_vs_fix_fetch fix_fetch;
LLVMValueRef t_list_ptr;
LLVMValueRef t_offset;
LLVMValueRef t_list;
LLVMValueRef vertex_index;
- LLVMValueRef input[3];
+ LLVMValueRef tmp;
/* Load the T list */
t_list_ptr = LLVMGetParam(ctx->main_fn, ctx->param_vertex_buffers);
ctx->param_vertex_index0 +
input_index);
- fix_fetch = ctx->shader->key.mono.vs_fix_fetch[input_index];
+ /* Use the open-coded implementation for all loads of doubles and
+ * of dword-sized data that needs fixups. We need to insert conversion
+ * code anyway, and the amd/common code does it for us.
+ *
+ * Note: On LLVM <= 8, we can only open-code formats with
+ * channel size >= 4 bytes.
+ */
+ bool opencode = ctx->shader->key.mono.vs_fetch_opencode & (1 << input_index);
+ fix_fetch.bits = ctx->shader->key.mono.vs_fix_fetch[input_index].bits;
+ if (opencode ||
+ (fix_fetch.u.log_size == 3 && fix_fetch.u.format == AC_FETCH_FORMAT_FLOAT) ||
+ (fix_fetch.u.log_size == 2)) {
+ tmp = ac_build_opencoded_load_format(
+ &ctx->ac, fix_fetch.u.log_size, fix_fetch.u.num_channels_m1 + 1,
+ fix_fetch.u.format, fix_fetch.u.reverse, !opencode,
+ t_list, vertex_index, ctx->ac.i32_0, ctx->ac.i32_0,
+ false, false, true);
+ for (unsigned i = 0; i < 4; ++i)
+ out[i] = LLVMBuildExtractElement(ctx->ac.builder, tmp, LLVMConstInt(ctx->i32, i, false), "");
+ return;
+ }
/* Do multiple loads for special formats. */
- switch (fix_fetch) {
- case SI_FIX_FETCH_RGB_64_FLOAT:
- num_fetches = 3; /* 3 2-dword loads */
- fetch_stride = 8;
- num_channels = 2;
- break;
- case SI_FIX_FETCH_RGBA_64_FLOAT:
- num_fetches = 2; /* 2 4-dword loads */
- fetch_stride = 16;
- num_channels = 4;
- break;
- case SI_FIX_FETCH_RGB_8:
- case SI_FIX_FETCH_RGB_8_INT:
- num_fetches = 3;
- fetch_stride = 1;
- num_channels = 1;
- break;
- case SI_FIX_FETCH_RGB_16:
- case SI_FIX_FETCH_RGB_16_INT:
- num_fetches = 3;
- fetch_stride = 2;
- num_channels = 1;
- break;
- default:
+ unsigned required_channels = util_last_bit(info->input_usage_mask[input_index]);
+ LLVMValueRef fetches[4];
+ unsigned num_fetches;
+ unsigned fetch_stride;
+ unsigned channels_per_fetch;
+
+ if (fix_fetch.u.log_size <= 1 && fix_fetch.u.num_channels_m1 == 2) {
+ num_fetches = MIN2(required_channels, 3);
+ fetch_stride = 1 << fix_fetch.u.log_size;
+ channels_per_fetch = 1;
+ } else {
num_fetches = 1;
fetch_stride = 0;
- num_channels = util_last_bit(info->input_usage_mask[input_index]);
+ channels_per_fetch = required_channels;
}
- for (unsigned i = 0; i < num_fetches; i++) {
+ for (unsigned i = 0; i < num_fetches; ++i) {
LLVMValueRef voffset = LLVMConstInt(ctx->i32, fetch_stride * i, 0);
-
- input[i] = ac_build_buffer_load_format(&ctx->ac, t_list,
- vertex_index, voffset,
- num_channels, false, true);
- input[i] = ac_build_expand_to_vec4(&ctx->ac, input[i], num_channels);
+ fetches[i] = ac_build_buffer_load_format(&ctx->ac, t_list, vertex_index, voffset,
+ channels_per_fetch, false, true);
}
- /* Break up the vec4 into individual components */
- for (chan = 0; chan < 4; chan++) {
- LLVMValueRef llvm_chan = LLVMConstInt(ctx->i32, chan, 0);
- out[chan] = LLVMBuildExtractElement(ctx->ac.builder,
- input[0], llvm_chan, "");
+ if (num_fetches == 1 && channels_per_fetch > 1) {
+ LLVMValueRef fetch = fetches[0];
+ for (unsigned i = 0; i < channels_per_fetch; ++i) {
+ tmp = LLVMConstInt(ctx->i32, i, false);
+ fetches[i] = LLVMBuildExtractElement(
+ ctx->ac.builder, fetch, tmp, "");
+ }
+ num_fetches = channels_per_fetch;
+ channels_per_fetch = 1;
}
- switch (fix_fetch) {
- case SI_FIX_FETCH_A2_SNORM:
- case SI_FIX_FETCH_A2_SSCALED:
- case SI_FIX_FETCH_A2_SINT: {
- /* The hardware returns an unsigned value; convert it to a
- * signed one.
+ for (unsigned i = num_fetches; i < 4; ++i)
+ fetches[i] = LLVMGetUndef(ctx->f32);
+
+ if (fix_fetch.u.log_size <= 1 && fix_fetch.u.num_channels_m1 == 2 &&
+ required_channels == 4) {
+ if (fix_fetch.u.format == AC_FETCH_FORMAT_UINT || fix_fetch.u.format == AC_FETCH_FORMAT_SINT)
+ fetches[3] = ctx->ac.i32_1;
+ else
+ fetches[3] = ctx->ac.f32_1;
+ } else if (fix_fetch.u.log_size == 3 &&
+ (fix_fetch.u.format == AC_FETCH_FORMAT_SNORM ||
+ fix_fetch.u.format == AC_FETCH_FORMAT_SSCALED ||
+ fix_fetch.u.format == AC_FETCH_FORMAT_SINT) &&
+ required_channels == 4) {
+ /* For 2_10_10_10, the hardware returns an unsigned value;
+ * convert it to a signed one.
*/
- LLVMValueRef tmp = out[3];
+ LLVMValueRef tmp = fetches[3];
LLVMValueRef c30 = LLVMConstInt(ctx->i32, 30, 0);
/* First, recover the sign-extended signed integer value. */
- if (fix_fetch == SI_FIX_FETCH_A2_SSCALED)
+ if (fix_fetch.u.format == AC_FETCH_FORMAT_SSCALED)
tmp = LLVMBuildFPToUI(ctx->ac.builder, tmp, ctx->i32, "");
else
tmp = ac_to_integer(&ctx->ac, tmp);
* exponent.
*/
tmp = LLVMBuildShl(ctx->ac.builder, tmp,
- fix_fetch == SI_FIX_FETCH_A2_SNORM ?
+ fix_fetch.u.format == AC_FETCH_FORMAT_SNORM ?
LLVMConstInt(ctx->i32, 7, 0) : c30, "");
tmp = LLVMBuildAShr(ctx->ac.builder, tmp, c30, "");
/* Convert back to the right type. */
- if (fix_fetch == SI_FIX_FETCH_A2_SNORM) {
+ if (fix_fetch.u.format == AC_FETCH_FORMAT_SNORM) {
LLVMValueRef clamp;
LLVMValueRef neg_one = LLVMConstReal(ctx->f32, -1.0);
tmp = LLVMBuildSIToFP(ctx->ac.builder, tmp, ctx->f32, "");
clamp = LLVMBuildFCmp(ctx->ac.builder, LLVMRealULT, tmp, neg_one, "");
tmp = LLVMBuildSelect(ctx->ac.builder, clamp, neg_one, tmp, "");
- } else if (fix_fetch == SI_FIX_FETCH_A2_SSCALED) {
+ } else if (fix_fetch.u.format == AC_FETCH_FORMAT_SSCALED) {
tmp = LLVMBuildSIToFP(ctx->ac.builder, tmp, ctx->f32, "");
}
- out[3] = tmp;
- break;
+ fetches[3] = tmp;
}
- case SI_FIX_FETCH_RGBA_32_UNORM:
- case SI_FIX_FETCH_RGBX_32_UNORM:
- for (chan = 0; chan < 4; chan++) {
- out[chan] = ac_to_integer(&ctx->ac, out[chan]);
- out[chan] = LLVMBuildUIToFP(ctx->ac.builder,
- out[chan], ctx->f32, "");
- out[chan] = LLVMBuildFMul(ctx->ac.builder, out[chan],
- LLVMConstReal(ctx->f32, 1.0 / UINT_MAX), "");
- }
- /* RGBX UINT returns 1 in alpha, which would be rounded to 0 by normalizing. */
- if (fix_fetch == SI_FIX_FETCH_RGBX_32_UNORM)
- out[3] = LLVMConstReal(ctx->f32, 1);
- break;
- case SI_FIX_FETCH_RGBA_32_SNORM:
- case SI_FIX_FETCH_RGBX_32_SNORM:
- case SI_FIX_FETCH_RGBA_32_FIXED:
- case SI_FIX_FETCH_RGBX_32_FIXED: {
- double scale;
- if (fix_fetch >= SI_FIX_FETCH_RGBA_32_FIXED)
- scale = 1.0 / 0x10000;
- else
- scale = 1.0 / INT_MAX;
- for (chan = 0; chan < 4; chan++) {
- out[chan] = ac_to_integer(&ctx->ac, out[chan]);
- out[chan] = LLVMBuildSIToFP(ctx->ac.builder,
- out[chan], ctx->f32, "");
- out[chan] = LLVMBuildFMul(ctx->ac.builder, out[chan],
- LLVMConstReal(ctx->f32, scale), "");
- }
- /* RGBX SINT returns 1 in alpha, which would be rounded to 0 by normalizing. */
- if (fix_fetch == SI_FIX_FETCH_RGBX_32_SNORM ||
- fix_fetch == SI_FIX_FETCH_RGBX_32_FIXED)
- out[3] = LLVMConstReal(ctx->f32, 1);
- break;
- }
- case SI_FIX_FETCH_RGBA_32_USCALED:
- for (chan = 0; chan < 4; chan++) {
- out[chan] = ac_to_integer(&ctx->ac, out[chan]);
- out[chan] = LLVMBuildUIToFP(ctx->ac.builder,
- out[chan], ctx->f32, "");
- }
- break;
- case SI_FIX_FETCH_RGBA_32_SSCALED:
- for (chan = 0; chan < 4; chan++) {
- out[chan] = ac_to_integer(&ctx->ac, out[chan]);
- out[chan] = LLVMBuildSIToFP(ctx->ac.builder,
- out[chan], ctx->f32, "");
- }
- break;
- case SI_FIX_FETCH_RG_64_FLOAT:
- for (chan = 0; chan < 2; chan++)
- out[chan] = extract_double_to_float(ctx, input[0], chan);
-
- out[2] = LLVMConstReal(ctx->f32, 0);
- out[3] = LLVMConstReal(ctx->f32, 1);
- break;
- case SI_FIX_FETCH_RGB_64_FLOAT:
- for (chan = 0; chan < 3; chan++)
- out[chan] = extract_double_to_float(ctx, input[chan], 0);
-
- out[3] = LLVMConstReal(ctx->f32, 1);
- break;
- case SI_FIX_FETCH_RGBA_64_FLOAT:
- for (chan = 0; chan < 4; chan++) {
- out[chan] = extract_double_to_float(ctx, input[chan / 2],
- chan % 2);
- }
- break;
- case SI_FIX_FETCH_RGB_8:
- case SI_FIX_FETCH_RGB_8_INT:
- case SI_FIX_FETCH_RGB_16:
- case SI_FIX_FETCH_RGB_16_INT:
- for (chan = 0; chan < 3; chan++) {
- out[chan] = LLVMBuildExtractElement(ctx->ac.builder,
- input[chan],
- ctx->i32_0, "");
- }
- if (fix_fetch == SI_FIX_FETCH_RGB_8 ||
- fix_fetch == SI_FIX_FETCH_RGB_16) {
- out[3] = LLVMConstReal(ctx->f32, 1);
- } else {
- out[3] = ac_to_float(&ctx->ac, ctx->i32_1);
- }
- break;
- }
+ for (unsigned i = 0; i < 4; ++i)
+ out[i] = ac_to_float(&ctx->ac, fetches[i]);
}
static void declare_input_vs(
}
/**
- * Load from LDS.
+ * Load from LSHS LDS storage.
*
* \param type output value type
* \param swizzle offset (typically 0..3); it can be ~0, which loads a vec4
* \param dw_addr address in dwords
*/
-static LLVMValueRef lds_load(struct lp_build_tgsi_context *bld_base,
+static LLVMValueRef lshs_lds_load(struct lp_build_tgsi_context *bld_base,
LLVMTypeRef type, unsigned swizzle,
LLVMValueRef dw_addr)
{
LLVMValueRef values[TGSI_NUM_CHANNELS];
for (unsigned chan = 0; chan < TGSI_NUM_CHANNELS; chan++)
- values[chan] = lds_load(bld_base, type, chan, dw_addr);
+ values[chan] = lshs_lds_load(bld_base, type, chan, dw_addr);
return ac_build_gather_values(&ctx->ac, values,
TGSI_NUM_CHANNELS);
if (llvm_type_is_64bit(ctx, type)) {
LLVMValueRef lo, hi;
- lo = lds_load(bld_base, ctx->i32, swizzle, dw_addr);
- hi = lds_load(bld_base, ctx->i32, swizzle + 1, dw_addr);
+ lo = lshs_lds_load(bld_base, ctx->i32, swizzle, dw_addr);
+ hi = lshs_lds_load(bld_base, ctx->i32, swizzle + 1, dw_addr);
return si_llvm_emit_fetch_64bit(bld_base, type, lo, hi);
}
}
/**
- * Store to LDS.
+ * Store to LSHS LDS storage.
*
* \param swizzle offset (typically 0..3)
* \param dw_addr address in dwords
* \param value value to store
*/
-static void lds_store(struct si_shader_context *ctx,
+static void lshs_lds_store(struct si_shader_context *ctx,
unsigned dw_offset_imm, LLVMValueRef dw_addr,
LLVMValueRef value)
{
dw_addr = get_tcs_in_current_patch_offset(ctx);
dw_addr = get_dw_address(ctx, NULL, reg, stride, dw_addr);
- return lds_load(bld_base, tgsi2llvmtype(bld_base, type), swizzle, dw_addr);
+ return lshs_lds_load(bld_base, tgsi2llvmtype(bld_base, type), swizzle, dw_addr);
}
static LLVMValueRef si_nir_load_tcs_varyings(struct ac_shader_abi *abi,
offset *= 2;
offset += component;
- value[i + component] = lds_load(bld_base, type, offset, dw_addr);
+ value[i + component] = lshs_lds_load(bld_base, type, offset, dw_addr);
}
return ac_build_varying_gather_values(&ctx->ac, value, num_components, component);
dw_addr = get_dw_address(ctx, NULL, reg, NULL, dw_addr);
}
- return lds_load(bld_base, tgsi2llvmtype(bld_base, type), swizzle, dw_addr);
+ return lshs_lds_load(bld_base, tgsi2llvmtype(bld_base, type), swizzle, dw_addr);
}
static LLVMValueRef fetch_input_tes(
LLVMValueRef value[4];
for (unsigned i = 0; i < num_components; i++) {
unsigned offset = i;
- if (llvm_type_is_64bit(ctx, type))
+ if (llvm_type_is_64bit(ctx, type)) {
offset *= 2;
+ if (offset == 4) {
+ addr = get_tcs_tes_buffer_address_from_generic_indices(ctx,
+ vertex_index,
+ param_index,
+ driver_location + 1,
+ info->input_semantic_name,
+ info->input_semantic_index,
+ is_patch);
+ }
+
+ offset = offset % 4;
+ }
offset += component;
value[i + component] = buffer_load(&ctx->bld_base, type, offset,
/* Skip LDS stores if there is no LDS read of this output. */
if (!skip_lds_store)
- lds_store(ctx, chan_index, dw_addr, value);
+ lshs_lds_store(ctx, chan_index, dw_addr, value);
value = ac_to_integer(&ctx->ac, value);
values[chan_index] = value;
if (reg->Register.WriteMask != 0xF && !is_tess_factor) {
ac_build_buffer_store_dword(&ctx->ac, buffer, value, 1,
buf_addr, base,
- 4 * chan_index, 1, 0, true, false);
+ 4 * chan_index, 1, 0, false);
}
/* Write tess factors into VGPRs for the epilog. */
LLVMValueRef value = ac_build_gather_values(&ctx->ac,
values, 4);
ac_build_buffer_store_dword(&ctx->ac, buffer, value, 4, buf_addr,
- base, 0, 1, 0, true, false);
+ base, 0, 1, 0, false);
}
}
unsigned driver_location = var->data.driver_location;
LLVMValueRef dw_addr, stride;
LLVMValueRef buffer, base, addr;
- LLVMValueRef values[4];
+ LLVMValueRef values[8];
bool skip_lds_store;
bool is_tess_factor = false, is_tess_inner = false;
info->output_semantic_index,
is_patch);
- for (unsigned chan = 0; chan < 4; chan++) {
+ for (unsigned chan = 0; chan < 8; chan++) {
if (!(writemask & (1 << chan)))
continue;
LLVMValueRef value = ac_llvm_extract_elem(&ctx->ac, src, chan - component);
+ unsigned buffer_store_offset = chan % 4;
+ if (chan == 4) {
+ addr = get_tcs_tes_buffer_address_from_generic_indices(ctx,
+ vertex_index,
+ param_index,
+ driver_location + 1,
+ info->output_semantic_name,
+ info->output_semantic_index,
+ is_patch);
+ }
+
/* Skip LDS stores if there is no LDS read of this output. */
if (!skip_lds_store)
- lds_store(ctx, chan, dw_addr, value);
+ lshs_lds_store(ctx, chan, dw_addr, value);
value = ac_to_integer(&ctx->ac, value);
values[chan] = value;
if (writemask != 0xF && !is_tess_factor) {
ac_build_buffer_store_dword(&ctx->ac, buffer, value, 1,
addr, base,
- 4 * chan, 1, 0, true, false);
+ 4 * buffer_store_offset,
+ 1, 0, false);
}
/* Write tess factors into VGPRs for the epilog. */
LLVMValueRef value = ac_build_gather_values(&ctx->ac,
values, 4);
ac_build_buffer_store_dword(&ctx->ac, buffer, value, 4, addr,
- base, 0, 1, 0, true, false);
+ base, 0, 1, 0, false);
}
}
return NULL;
}
+ unsigned offset = param * 4 + swizzle;
vtx_offset = LLVMBuildAdd(ctx->ac.builder, vtx_offset,
- LLVMConstInt(ctx->i32, param * 4, 0), "");
- return lds_load(bld_base, type, swizzle, vtx_offset);
+ LLVMConstInt(ctx->i32, offset, false), "");
+
+ LLVMValueRef ptr = ac_build_gep0(&ctx->ac, ctx->esgs_ring, vtx_offset);
+ LLVMValueRef value = LLVMBuildLoad(ctx->ac.builder, ptr, "");
+ if (llvm_type_is_64bit(ctx, type)) {
+ ptr = LLVMBuildGEP(ctx->ac.builder, ptr,
+ &ctx->ac.i32_1, 1, "");
+ LLVMValueRef values[2] = {
+ value,
+ LLVMBuildLoad(ctx->ac.builder, ptr, "")
+ };
+ value = ac_build_gather_values(&ctx->ac, values, 2);
+ }
+ return LLVMBuildBitCast(ctx->ac.builder, value, type, "");
}
/* GFX6: input load from the ESGS ring in memory. */
break;
case TGSI_SEMANTIC_HELPER_INVOCATION:
- value = ac_build_intrinsic(&ctx->ac,
- "llvm.amdgcn.ps.live",
- ctx->i1, NULL, 0,
- AC_FUNC_ATTR_READNONE);
- value = LLVMBuildNot(ctx->ac.builder, value, "");
- value = LLVMBuildSExt(ctx->ac.builder, value, ctx->i32, "");
+ value = ac_build_load_helper_invocation(&ctx->ac);
break;
case TGSI_SEMANTIC_SUBGROUP_SIZE:
LLVMArrayType(ctx->i8, lds_size),
"compute_lds",
AC_ADDR_SPACE_LDS);
- LLVMSetAlignment(var, 4);
+ LLVMSetAlignment(var, 64 * 1024);
ctx->ac.lds = LLVMBuildBitCast(ctx->ac.builder, var, i8p, "");
}
vdata = out[0];
break;
case 2: /* as v2i32 */
- case 3: /* as v4i32 (aligned to 4) */
+ case 3: /* as v3i32 */
+ if (ac_has_vec3_support(ctx->screen->info.chip_class, false)) {
+ vdata = ac_build_gather_values(&ctx->ac, out, num_comps);
+ break;
+ }
+ /* as v4i32 (aligned to 4) */
out[3] = LLVMGetUndef(ctx->i32);
/* fall through */
case 4: /* as v4i32 */
vdata, num_comps,
so_write_offsets[buf_idx],
ctx->i32_0,
- stream_out->dst_offset * 4, 1, 1, true, false);
+ stream_out->dst_offset * 4, 1, 1, false);
}
/**
shader->info.nr_param_exports = param_count;
}
+/**
+ * Vertex color clamping.
+ *
+ * This uses a state constant loaded in a user data SGPR and
+ * an IF statement is added that clamps all colors if the constant
+ * is true.
+ */
+static void si_vertex_color_clamping(struct si_shader_context *ctx,
+ struct si_shader_output_values *outputs,
+ unsigned noutput)
+{
+ LLVMValueRef addr[SI_MAX_VS_OUTPUTS][4];
+ bool has_colors = false;
+
+ /* Store original colors to alloca variables. */
+ for (unsigned i = 0; i < noutput; i++) {
+ if (outputs[i].semantic_name != TGSI_SEMANTIC_COLOR &&
+ outputs[i].semantic_name != TGSI_SEMANTIC_BCOLOR)
+ continue;
+
+ for (unsigned j = 0; j < 4; j++) {
+ addr[i][j] = ac_build_alloca_undef(&ctx->ac, ctx->f32, "");
+ LLVMBuildStore(ctx->ac.builder, outputs[i].values[j], addr[i][j]);
+ }
+ has_colors = true;
+ }
+
+ if (!has_colors)
+ return;
+
+ /* The state is in the first bit of the user SGPR. */
+ LLVMValueRef cond = LLVMGetParam(ctx->main_fn, ctx->param_vs_state_bits);
+ cond = LLVMBuildTrunc(ctx->ac.builder, cond, ctx->i1, "");
+
+ struct lp_build_if_state if_ctx;
+ lp_build_if(&if_ctx, &ctx->gallivm, cond);
+
+ /* Store clamped colors to alloca variables within the conditional block. */
+ for (unsigned i = 0; i < noutput; i++) {
+ if (outputs[i].semantic_name != TGSI_SEMANTIC_COLOR &&
+ outputs[i].semantic_name != TGSI_SEMANTIC_BCOLOR)
+ continue;
+
+ for (unsigned j = 0; j < 4; j++) {
+ LLVMBuildStore(ctx->ac.builder,
+ ac_build_clamp(&ctx->ac, outputs[i].values[j]),
+ addr[i][j]);
+ }
+ }
+ lp_build_endif(&if_ctx);
+
+ /* Load clamped colors */
+ for (unsigned i = 0; i < noutput; i++) {
+ if (outputs[i].semantic_name != TGSI_SEMANTIC_COLOR &&
+ outputs[i].semantic_name != TGSI_SEMANTIC_BCOLOR)
+ continue;
+
+ for (unsigned j = 0; j < 4; j++) {
+ outputs[i].values[j] =
+ LLVMBuildLoad(ctx->ac.builder, addr[i][j], "");
+ }
+ }
+}
+
/* Generate export instructions for hardware VS shader stage */
static void si_llvm_export_vs(struct si_shader_context *ctx,
struct si_shader_output_values *outputs,
unsigned pos_idx;
int i;
+ si_vertex_color_clamping(ctx, outputs, noutput);
+
/* Build position exports. */
for (i = 0; i < noutput; i++) {
switch (outputs[i].semantic_name) {
invocation_id,
LLVMConstInt(ctx->i32, i, 0));
- LLVMValueRef value = lds_load(bld_base, ctx->ac.i32, ~0,
- lds_ptr);
+ LLVMValueRef value = lshs_lds_load(bld_base, ctx->ac.i32, ~0, lds_ptr);
ac_build_buffer_store_dword(&ctx->ac, buffer, value, 4, buffer_addr,
- buffer_offset, 0, 1, 0, true, false);
+ buffer_offset, 0, 1, 0, false);
}
}
for (i = 0; i < outer_comps; i++) {
outer[i] = out[i] =
- lds_load(bld_base, ctx->ac.i32, i, lds_outer);
+ lshs_lds_load(bld_base, ctx->ac.i32, i, lds_outer);
}
for (i = 0; i < inner_comps; i++) {
inner[i] = out[outer_comps+i] =
- lds_load(bld_base, ctx->ac.i32, i, lds_inner);
+ lshs_lds_load(bld_base, ctx->ac.i32, i, lds_inner);
}
}
/* Store the dynamic HS control word. */
offset = 0;
- if (ctx->screen->info.chip_class <= VI) {
+ if (ctx->screen->info.chip_class <= GFX8) {
ac_build_buffer_store_dword(&ctx->ac, buffer,
LLVMConstInt(ctx->i32, 0x80000000, 0),
1, ctx->i32_0, tf_base,
- offset, 1, 0, true, false);
+ offset, 1, 0, false);
offset += 4;
}
/* Store the tessellation factors. */
ac_build_buffer_store_dword(&ctx->ac, buffer, vec0,
MIN2(stride, 4), byteoffset, tf_base,
- offset, 1, 0, true, false);
+ offset, 1, 0, false);
offset += 16;
if (vec1)
ac_build_buffer_store_dword(&ctx->ac, buffer, vec1,
stride - 4, byteoffset, tf_base,
- offset, 1, 0, true, false);
+ offset, 1, 0, false);
/* Store the tess factors into the offchip buffer if TES reads them. */
if (shader->key.part.tcs.epilog.tes_reads_tess_factors) {
tf_outer_offset = get_tcs_tes_buffer_address(ctx, rel_patch_id, NULL,
LLVMConstInt(ctx->i32, param_outer, 0));
- outer_vec = ac_build_gather_values(&ctx->ac, outer,
- util_next_power_of_two(outer_comps));
+ unsigned outer_vec_size =
+ ac_has_vec3_support(ctx->screen->info.chip_class, false) ?
+ outer_comps : util_next_power_of_two(outer_comps);
+ outer_vec = ac_build_gather_values(&ctx->ac, outer, outer_vec_size);
ac_build_buffer_store_dword(&ctx->ac, buf, outer_vec,
outer_comps, tf_outer_offset,
- base, 0, 1, 0, true, false);
+ base, 0, 1, 0, false);
if (inner_comps) {
param_inner = si_shader_io_get_unique_index_patch(
TGSI_SEMANTIC_TESSINNER, 0);
ac_build_gather_values(&ctx->ac, inner, inner_comps);
ac_build_buffer_store_dword(&ctx->ac, buf, inner_vec,
inner_comps, tf_inner_offset,
- base, 0, 1, 0, true, false);
+ base, 0, 1, 0, false);
}
}
unsigned param, unsigned return_index)
{
LLVMBuilderRef builder = ctx->ac.builder;
- LLVMValueRef ptr, lo, hi;
-
- ptr = LLVMGetParam(ctx->main_fn, param);
+ LLVMValueRef ptr = LLVMGetParam(ctx->main_fn, param);
ptr = LLVMBuildPtrToInt(builder, ptr, ctx->i32, "");
return LLVMBuildInsertValue(builder, ret, ptr, return_index, "");
}
if (!(info->output_usagemask[i] & (1 << chan)))
continue;
- lds_store(ctx, chan, dw_addr,
+ lshs_lds_store(ctx, chan, dw_addr,
LLVMBuildLoad(ctx->ac.builder, addrs[4 * i + chan], ""));
}
}
/* GFX9 has the ESGS ring in LDS. */
if (ctx->screen->info.chip_class >= GFX9) {
- lds_store(ctx, param * 4 + chan, lds_base, out_val);
+ LLVMValueRef idx = LLVMConstInt(ctx->i32, param * 4 + chan, false);
+ idx = LLVMBuildAdd(ctx->ac.builder, lds_base, idx, "");
+ ac_build_indexed_store(&ctx->ac, ctx->esgs_ring, idx, out_val);
continue;
}
ctx->esgs_ring,
out_val, 1, NULL, soffset,
(4 * param + chan) * 4,
- 1, 1, true, true);
+ 1, 1, true);
}
}
outputs = MALLOC((info->num_outputs + 1) * sizeof(outputs[0]));
- /* Vertex color clamping.
- *
- * This uses a state constant loaded in a user data SGPR and
- * an IF statement is added that clamps all colors if the constant
- * is true.
- */
- struct lp_build_if_state if_ctx;
- LLVMValueRef cond = NULL;
- LLVMValueRef addr, val;
-
- for (i = 0; i < info->num_outputs; i++) {
- if (info->output_semantic_name[i] != TGSI_SEMANTIC_COLOR &&
- info->output_semantic_name[i] != TGSI_SEMANTIC_BCOLOR)
- continue;
-
- /* We've found a color. */
- if (!cond) {
- /* The state is in the first bit of the user SGPR. */
- cond = LLVMGetParam(ctx->main_fn,
- ctx->param_vs_state_bits);
- cond = LLVMBuildTrunc(ctx->ac.builder, cond,
- ctx->i1, "");
- lp_build_if(&if_ctx, &ctx->gallivm, cond);
- }
-
- for (j = 0; j < 4; j++) {
- addr = addrs[4 * i + j];
- val = LLVMBuildLoad(ctx->ac.builder, addr, "");
- val = ac_build_clamp(&ctx->ac, val);
- LLVMBuildStore(ctx->ac.builder, val, addr);
- }
- }
-
- if (cond)
- lp_build_endif(&if_ctx);
-
for (i = 0; i < info->num_outputs; i++) {
outputs[i].semantic_name = info->output_semantic_name[i];
outputs[i].semantic_index = info->output_semantic_index[i];
FREE(outputs);
}
+static void si_llvm_emit_prim_discard_cs_epilogue(struct ac_shader_abi *abi,
+ unsigned max_outputs,
+ LLVMValueRef *addrs)
+{
+ struct si_shader_context *ctx = si_shader_context_from_abi(abi);
+ struct tgsi_shader_info *info = &ctx->shader->selector->info;
+ LLVMValueRef pos[4] = {};
+
+ assert(info->num_outputs <= max_outputs);
+
+ for (unsigned i = 0; i < info->num_outputs; i++) {
+ if (info->output_semantic_name[i] != TGSI_SEMANTIC_POSITION)
+ continue;
+
+ for (unsigned chan = 0; chan < 4; chan++)
+ pos[chan] = LLVMBuildLoad(ctx->ac.builder, addrs[4 * i + chan], "");
+ break;
+ }
+ assert(pos[0] != NULL);
+
+ /* Return the position output. */
+ LLVMValueRef ret = ctx->return_value;
+ for (unsigned chan = 0; chan < 4; chan++)
+ ret = LLVMBuildInsertValue(ctx->ac.builder, ret, pos[chan], chan, "");
+ ctx->return_value = ret;
+}
+
static void si_tgsi_emit_epilogue(struct lp_build_tgsi_context *bld_base)
{
struct si_shader_context *ctx = si_shader_context(bld_base);
addrs[4 * i + 0], "");
break;
default:
- fprintf(stderr, "Warning: SI unhandled fs output type:%d\n",
+ fprintf(stderr, "Warning: GFX6 unhandled fs output type:%d\n",
semantic_name);
}
}
emit_data->output[emit_data->chan] = val;
}
-/*
- * this takes an I,J coordinate pair,
- * and works out the X and Y derivatives.
- * it returns DDX(I), DDX(J), DDY(I), DDY(J).
- */
-static LLVMValueRef si_llvm_emit_ddxy_interp(
- struct lp_build_tgsi_context *bld_base,
- LLVMValueRef interp_ij)
-{
- struct si_shader_context *ctx = si_shader_context(bld_base);
- LLVMValueRef result[4], a;
- unsigned i;
-
- for (i = 0; i < 2; i++) {
- a = LLVMBuildExtractElement(ctx->ac.builder, interp_ij,
- LLVMConstInt(ctx->i32, i, 0), "");
- result[i] = ac_build_ddxy(&ctx->ac, AC_TID_MASK_TOP_LEFT, 1,
- ac_to_integer(&ctx->ac, a)); /* DDX */
- result[2+i] = ac_build_ddxy(&ctx->ac, AC_TID_MASK_TOP_LEFT, 2,
- ac_to_integer(&ctx->ac, a)); /* DDY */
- }
-
- return ac_build_gather_values(&ctx->ac, result, 4);
-}
-
static void build_interp_intrinsic(const struct lp_build_tgsi_action *action,
struct lp_build_tgsi_context *bld_base,
struct lp_build_emit_data *emit_data)
if (inst->Instruction.Opcode == TGSI_OPCODE_INTERP_OFFSET ||
inst->Instruction.Opcode == TGSI_OPCODE_INTERP_SAMPLE) {
LLVMValueRef ij_out[2];
- LLVMValueRef ddxy_out = si_llvm_emit_ddxy_interp(bld_base, interp_param);
+ LLVMValueRef ddxy_out = ac_build_ddxy_interp(&ctx->ac, interp_param);
/*
* take the I then J parameters, and the DDX/Y for it, and
ctx->gsvs_ring[stream],
out_val, 1,
voffset, soffset, 0,
- 1, 1, true, true);
+ 1, 1, true);
}
}
{
struct si_shader_context *ctx = si_shader_context(bld_base);
- /* SI only (thanks to a hw bug workaround):
+ /* GFX6 only (thanks to a hw bug workaround):
* The real barrier instruction isn’t needed, because an entire patch
* always fits into a single wave.
*/
- if (ctx->screen->info.chip_class == SI &&
+ if (ctx->screen->info.chip_class == GFX6 &&
ctx->type == PIPE_SHADER_TESS_CTRL) {
ac_build_waitcnt(&ctx->ac, LGKM_CNT & VM_CNT);
return;
ac_build_s_barrier(&ctx->ac);
}
-static void si_create_function(struct si_shader_context *ctx,
- const char *name,
- LLVMTypeRef *returns, unsigned num_returns,
- struct si_function_info *fninfo,
- unsigned max_workgroup_size)
+void si_create_function(struct si_shader_context *ctx,
+ const char *name,
+ LLVMTypeRef *returns, unsigned num_returns,
+ struct si_function_info *fninfo,
+ unsigned max_workgroup_size)
{
int i;
ctx->screen->info.address32_hi);
}
- if (max_workgroup_size) {
- ac_llvm_add_target_dep_function_attr(ctx->main_fn,
- "amdgpu-max-work-group-size",
- max_workgroup_size);
- }
+ ac_llvm_set_workgroup_size(ctx->main_fn, max_workgroup_size);
+
LLVMAddTargetDependentFunctionAttr(ctx->main_fn,
"no-signed-zeros-fp-math",
"true");
case PIPE_SHADER_TESS_CTRL:
/* Return this so that LLVM doesn't remove s_barrier
* instructions on chips where we use s_barrier. */
- return shader->selector->screen->info.chip_class >= CIK ? 128 : 64;
+ return shader->selector->screen->info.chip_class >= GFX7 ? 128 : 64;
case PIPE_SHADER_GEOMETRY:
return shader->selector->screen->info.chip_class >= GFX9 ? 128 : 64;
}
}
+static void declare_vs_blit_inputs(struct si_shader_context *ctx,
+ struct si_function_info *fninfo,
+ unsigned vs_blit_property)
+{
+ ctx->param_vs_blit_inputs = fninfo->num_params;
+ add_arg(fninfo, ARG_SGPR, ctx->i32); /* i16 x1, y1 */
+ add_arg(fninfo, ARG_SGPR, ctx->i32); /* i16 x2, y2 */
+ add_arg(fninfo, ARG_SGPR, ctx->f32); /* depth */
+
+ if (vs_blit_property == SI_VS_BLIT_SGPRS_POS_COLOR) {
+ add_arg(fninfo, ARG_SGPR, ctx->f32); /* color0 */
+ add_arg(fninfo, ARG_SGPR, ctx->f32); /* color1 */
+ add_arg(fninfo, ARG_SGPR, ctx->f32); /* color2 */
+ add_arg(fninfo, ARG_SGPR, ctx->f32); /* color3 */
+ } else if (vs_blit_property == SI_VS_BLIT_SGPRS_POS_TEXCOORD) {
+ add_arg(fninfo, ARG_SGPR, ctx->f32); /* texcoord.x1 */
+ add_arg(fninfo, ARG_SGPR, ctx->f32); /* texcoord.y1 */
+ add_arg(fninfo, ARG_SGPR, ctx->f32); /* texcoord.x2 */
+ add_arg(fninfo, ARG_SGPR, ctx->f32); /* texcoord.y2 */
+ add_arg(fninfo, ARG_SGPR, ctx->f32); /* texcoord.z */
+ add_arg(fninfo, ARG_SGPR, ctx->f32); /* texcoord.w */
+ }
+}
+
static void declare_tes_input_vgprs(struct si_shader_context *ctx,
struct si_function_info *fninfo)
{
declare_global_desc_pointers(ctx, &fninfo);
if (vs_blit_property) {
- ctx->param_vs_blit_inputs = fninfo.num_params;
- add_arg(&fninfo, ARG_SGPR, ctx->i32); /* i16 x1, y1 */
- add_arg(&fninfo, ARG_SGPR, ctx->i32); /* i16 x2, y2 */
- add_arg(&fninfo, ARG_SGPR, ctx->f32); /* depth */
-
- if (vs_blit_property == SI_VS_BLIT_SGPRS_POS_COLOR) {
- add_arg(&fninfo, ARG_SGPR, ctx->f32); /* color0 */
- add_arg(&fninfo, ARG_SGPR, ctx->f32); /* color1 */
- add_arg(&fninfo, ARG_SGPR, ctx->f32); /* color2 */
- add_arg(&fninfo, ARG_SGPR, ctx->f32); /* color3 */
- } else if (vs_blit_property == SI_VS_BLIT_SGPRS_POS_TEXCOORD) {
- add_arg(&fninfo, ARG_SGPR, ctx->f32); /* texcoord.x1 */
- add_arg(&fninfo, ARG_SGPR, ctx->f32); /* texcoord.y1 */
- add_arg(&fninfo, ARG_SGPR, ctx->f32); /* texcoord.x2 */
- add_arg(&fninfo, ARG_SGPR, ctx->f32); /* texcoord.y2 */
- add_arg(&fninfo, ARG_SGPR, ctx->f32); /* texcoord.z */
- add_arg(&fninfo, ARG_SGPR, ctx->f32); /* texcoord.w */
- }
+ declare_vs_blit_inputs(ctx, &fninfo, vs_blit_property);
/* VGPRs */
declare_vs_input_vgprs(ctx, &fninfo, &num_prolog_vgprs);
/* VGPRs */
declare_vs_input_vgprs(ctx, &fninfo, &num_prolog_vgprs);
+
+ /* Return values */
+ if (shader->key.opt.vs_as_prim_discard_cs) {
+ for (i = 0; i < 4; i++)
+ returns[num_returns++] = ctx->f32; /* VGPRs */
+ }
break;
- case PIPE_SHADER_TESS_CTRL: /* SI-CI-VI */
+ case PIPE_SHADER_TESS_CTRL: /* GFX6-GFX8 */
declare_global_desc_pointers(ctx, &fninfo);
declare_per_stage_desc_pointers(ctx, &fninfo, true);
ctx->param_tcs_offchip_layout = add_arg(&fninfo, ARG_SGPR, ctx->i32);
assert(shader->info.num_input_vgprs >= num_prolog_vgprs);
shader->info.num_input_vgprs -= num_prolog_vgprs;
- if (shader->key.as_ls ||
- ctx->type == PIPE_SHADER_TESS_CTRL ||
- /* GFX9 has the ESGS ring buffer in LDS. */
- type == SI_SHADER_MERGED_VERTEX_OR_TESSEVAL_GEOMETRY)
- ac_declare_lds_as_pointer(&ctx->ac);
+ if (shader->key.as_ls || ctx->type == PIPE_SHADER_TESS_CTRL) {
+ if (USE_LDS_SYMBOLS && HAVE_LLVM >= 0x0900) {
+ /* The LSHS size is not known until draw time, so we append it
+ * at the end of whatever LDS use there may be in the rest of
+ * the shader (currently none, unless LLVM decides to do its
+ * own LDS-based lowering).
+ */
+ ctx->ac.lds = LLVMAddGlobalInAddressSpace(
+ ctx->ac.module, LLVMArrayType(ctx->i32, 0),
+ "__lds_end", AC_ADDR_SPACE_LDS);
+ LLVMSetAlignment(ctx->ac.lds, 256);
+ } else {
+ ac_declare_lds_as_pointer(&ctx->ac);
+ }
+ }
}
/**
LLVMValueRef buf_ptr = LLVMGetParam(ctx->main_fn,
ctx->param_rw_buffers);
- if (ctx->screen->info.chip_class <= VI &&
- (ctx->shader->key.as_es || ctx->type == PIPE_SHADER_GEOMETRY)) {
- unsigned ring =
- ctx->type == PIPE_SHADER_GEOMETRY ? SI_GS_RING_ESGS
- : SI_ES_RING_ESGS;
- LLVMValueRef offset = LLVMConstInt(ctx->i32, ring, 0);
+ if (ctx->shader->key.as_es || ctx->type == PIPE_SHADER_GEOMETRY) {
+ if (ctx->screen->info.chip_class <= GFX8) {
+ unsigned ring =
+ ctx->type == PIPE_SHADER_GEOMETRY ? SI_GS_RING_ESGS
+ : SI_ES_RING_ESGS;
+ LLVMValueRef offset = LLVMConstInt(ctx->i32, ring, 0);
- ctx->esgs_ring =
- ac_build_load_to_sgpr(&ctx->ac, buf_ptr, offset);
+ ctx->esgs_ring =
+ ac_build_load_to_sgpr(&ctx->ac, buf_ptr, offset);
+ } else {
+ if (USE_LDS_SYMBOLS && HAVE_LLVM >= 0x0900) {
+ /* Declare the ESGS ring as an explicit LDS symbol.
+ * For monolithic shaders, we declare the ring only once.
+ *
+ * We declare it with 64KB alignment as a hint that the
+ * pointer value will always be 0.
+ */
+ ctx->esgs_ring = LLVMAddGlobalInAddressSpace(
+ ctx->ac.module, LLVMArrayType(ctx->i32, 0),
+ "esgs_ring",
+ AC_ADDR_SPACE_LDS);
+ LLVMSetAlignment(ctx->esgs_ring, 64 * 1024);
+ } else {
+ ac_declare_lds_as_pointer(&ctx->ac);
+ ctx->esgs_ring = ctx->ac.lds;
+ }
+ }
}
if (ctx->shader->is_gs_copy_shader) {
stride = 4 * num_components * sel->gs_max_out_vertices;
- /* Limit on the stride field for <= CIK. */
+ /* Limit on the stride field for <= GFX7. */
assert(stride < (1 << 14));
num_records = 64;
ac_build_kill_if_false(&ctx->ac, bit);
}
-void si_shader_binary_read_config(struct ac_shader_binary *binary,
- struct si_shader_config *conf,
- unsigned symbol_offset)
-{
- unsigned i;
- const unsigned char *config =
- ac_shader_binary_config_start(binary, symbol_offset);
- bool really_needs_scratch = false;
+/* For the UMR disassembler. */
+#define DEBUGGER_END_OF_CODE_MARKER 0xbf9f0000 /* invalid instruction */
+#define DEBUGGER_NUM_MARKERS 5
- /* LLVM adds SGPR spills to the scratch size.
- * Find out if we really need the scratch buffer.
- */
- for (i = 0; i < binary->reloc_count; i++) {
- const struct ac_shader_reloc *reloc = &binary->relocs[i];
+static bool si_shader_binary_open(struct si_screen *screen,
+ struct si_shader *shader,
+ struct ac_rtld_binary *rtld)
+{
+ const struct si_shader_selector *sel = shader->selector;
+ const char *part_elfs[5];
+ size_t part_sizes[5];
+ unsigned num_parts = 0;
- if (!strcmp(scratch_rsrc_dword0_symbol, reloc->name) ||
- !strcmp(scratch_rsrc_dword1_symbol, reloc->name)) {
- really_needs_scratch = true;
- break;
- }
+#define add_part(shader_or_part) \
+ if (shader_or_part) { \
+ part_elfs[num_parts] = (shader_or_part)->binary.elf_buffer; \
+ part_sizes[num_parts] = (shader_or_part)->binary.elf_size; \
+ num_parts++; \
}
- /* XXX: We may be able to emit some of these values directly rather than
- * extracting fields to be emitted later.
- */
+ add_part(shader->prolog);
+ add_part(shader->previous_stage);
+ add_part(shader->prolog2);
+ add_part(shader);
+ add_part(shader->epilog);
- for (i = 0; i < binary->config_size_per_symbol; i+= 8) {
- unsigned reg = util_le32_to_cpu(*(uint32_t*)(config + i));
- unsigned value = util_le32_to_cpu(*(uint32_t*)(config + i + 4));
- switch (reg) {
- 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->float_mode = G_00B028_FLOAT_MODE(value);
- conf->rsrc1 = value;
- break;
- case R_00B02C_SPI_SHADER_PGM_RSRC2_PS:
- conf->lds_size = MAX2(conf->lds_size, G_00B02C_EXTRA_LDS_SIZE(value));
- break;
- case R_00B84C_COMPUTE_PGM_RSRC2:
- conf->lds_size = MAX2(conf->lds_size, G_00B84C_LDS_SIZE(value));
- conf->rsrc2 = value;
- break;
- case R_0286CC_SPI_PS_INPUT_ENA:
- conf->spi_ps_input_ena = value;
- break;
- case R_0286D0_SPI_PS_INPUT_ADDR:
- conf->spi_ps_input_addr = value;
- break;
- case R_0286E8_SPI_TMPRING_SIZE:
- case R_00B860_COMPUTE_TMPRING_SIZE:
- /* WAVESIZE is in units of 256 dwords. */
- if (really_needs_scratch)
- conf->scratch_bytes_per_wave =
- G_00B860_WAVESIZE(value) * 256 * 4;
- break;
- case 0x4: /* SPILLED_SGPRS */
- conf->spilled_sgprs = value;
- break;
- case 0x8: /* SPILLED_VGPRS */
- conf->spilled_vgprs = value;
- break;
- default:
- {
- static bool printed;
+#undef add_part
- if (!printed) {
- fprintf(stderr, "Warning: LLVM emitted unknown "
- "config register: 0x%x\n", reg);
- printed = true;
- }
- }
- break;
- }
+ struct ac_rtld_symbol lds_symbols[1];
+ unsigned num_lds_symbols = 0;
+
+ if (sel && screen->info.chip_class >= GFX9 &&
+ sel->type == PIPE_SHADER_GEOMETRY && !shader->is_gs_copy_shader) {
+ /* We add this symbol even on LLVM <= 8 to ensure that
+ * shader->config.lds_size is set correctly below.
+ */
+ struct ac_rtld_symbol *sym = &lds_symbols[num_lds_symbols++];
+ sym->name = "esgs_ring";
+ sym->size = shader->gs_info.esgs_ring_size;
+ sym->align = 64 * 1024;
}
- if (!conf->spi_ps_input_addr)
- conf->spi_ps_input_addr = conf->spi_ps_input_ena;
+ bool ok = ac_rtld_open(rtld, (struct ac_rtld_open_info){
+ .info = &screen->info,
+ .options = {
+ .halt_at_entry = screen->options.halt_shaders,
+ },
+ .num_parts = num_parts,
+ .elf_ptrs = part_elfs,
+ .elf_sizes = part_sizes,
+ .num_shared_lds_symbols = num_lds_symbols,
+ .shared_lds_symbols = lds_symbols });
+
+ if (rtld->lds_size > 0) {
+ unsigned alloc_granularity = screen->info.chip_class >= GFX7 ? 512 : 256;
+ shader->config.lds_size =
+ align(rtld->lds_size, alloc_granularity) / alloc_granularity;
+ }
+
+ return ok;
}
-void si_shader_apply_scratch_relocs(struct si_shader *shader,
- uint64_t scratch_va)
+static unsigned si_get_shader_binary_size(struct si_screen *screen, struct si_shader *shader)
{
- unsigned i;
- uint32_t scratch_rsrc_dword0 = scratch_va;
- uint32_t scratch_rsrc_dword1 =
- S_008F04_BASE_ADDRESS_HI(scratch_va >> 32);
-
- /* Enable scratch coalescing. */
- scratch_rsrc_dword1 |= S_008F04_SWIZZLE_ENABLE(1);
-
- for (i = 0 ; i < shader->binary.reloc_count; i++) {
- const struct ac_shader_reloc *reloc =
- &shader->binary.relocs[i];
- if (!strcmp(scratch_rsrc_dword0_symbol, reloc->name)) {
- util_memcpy_cpu_to_le32(shader->binary.code + reloc->offset,
- &scratch_rsrc_dword0, 4);
- } else if (!strcmp(scratch_rsrc_dword1_symbol, reloc->name)) {
- util_memcpy_cpu_to_le32(shader->binary.code + reloc->offset,
- &scratch_rsrc_dword1, 4);
+ struct ac_rtld_binary rtld;
+ si_shader_binary_open(screen, shader, &rtld);
+ return rtld.rx_size;
+}
+
+
+static bool si_get_external_symbol(void *data, const char *name, uint64_t *value)
+{
+ uint64_t *scratch_va = data;
+
+ if (!strcmp(scratch_rsrc_dword0_symbol, name)) {
+ *value = (uint32_t)*scratch_va;
+ return true;
+ }
+ if (!strcmp(scratch_rsrc_dword1_symbol, name)) {
+ /* Enable scratch coalescing. */
+ *value = S_008F04_BASE_ADDRESS_HI(*scratch_va >> 32) |
+ S_008F04_SWIZZLE_ENABLE(1);
+ if (HAVE_LLVM < 0x0800) {
+ /* Old LLVM created an R_ABS32_HI relocation for
+ * this symbol. */
+ *value <<= 32;
}
+ return true;
}
+
+ return false;
}
-/* For the UMR disassembler. */
-#define DEBUGGER_END_OF_CODE_MARKER 0xbf9f0000 /* invalid instruction */
-#define DEBUGGER_NUM_MARKERS 5
+bool si_shader_binary_upload(struct si_screen *sscreen, struct si_shader *shader,
+ uint64_t scratch_va)
+{
+ struct ac_rtld_binary binary;
+ if (!si_shader_binary_open(sscreen, shader, &binary))
+ return false;
-static unsigned si_get_shader_binary_size(const struct si_shader *shader)
-{
- unsigned size = shader->binary.code_size;
-
- if (shader->prolog)
- size += shader->prolog->binary.code_size;
- if (shader->previous_stage)
- size += shader->previous_stage->binary.code_size;
- if (shader->prolog2)
- size += shader->prolog2->binary.code_size;
- if (shader->epilog)
- size += shader->epilog->binary.code_size;
- return size + DEBUGGER_NUM_MARKERS * 4;
-}
-
-int si_shader_binary_upload(struct si_screen *sscreen, struct si_shader *shader)
-{
- const struct ac_shader_binary *prolog =
- shader->prolog ? &shader->prolog->binary : NULL;
- const struct ac_shader_binary *previous_stage =
- shader->previous_stage ? &shader->previous_stage->binary : NULL;
- const struct ac_shader_binary *prolog2 =
- shader->prolog2 ? &shader->prolog2->binary : NULL;
- const struct ac_shader_binary *epilog =
- shader->epilog ? &shader->epilog->binary : NULL;
- const struct ac_shader_binary *mainb = &shader->binary;
- unsigned bo_size = si_get_shader_binary_size(shader) +
- (!epilog ? mainb->rodata_size : 0);
- unsigned char *ptr;
-
- assert(!prolog || !prolog->rodata_size);
- assert(!previous_stage || !previous_stage->rodata_size);
- assert(!prolog2 || !prolog2->rodata_size);
- assert((!prolog && !previous_stage && !prolog2 && !epilog) ||
- !mainb->rodata_size);
- assert(!epilog || !epilog->rodata_size);
-
- r600_resource_reference(&shader->bo, NULL);
+ si_resource_reference(&shader->bo, NULL);
shader->bo = si_aligned_buffer_create(&sscreen->b,
sscreen->cpdma_prefetch_writes_memory ?
0 : SI_RESOURCE_FLAG_READ_ONLY,
PIPE_USAGE_IMMUTABLE,
- align(bo_size, SI_CPDMA_ALIGNMENT),
+ align(binary.rx_size, SI_CPDMA_ALIGNMENT),
256);
if (!shader->bo)
- return -ENOMEM;
+ return false;
/* Upload. */
- ptr = sscreen->ws->buffer_map(shader->bo->buf, NULL,
+ struct ac_rtld_upload_info u = {};
+ u.binary = &binary;
+ u.get_external_symbol = si_get_external_symbol;
+ u.cb_data = &scratch_va;
+ u.rx_va = shader->bo->gpu_address;
+ u.rx_ptr = sscreen->ws->buffer_map(shader->bo->buf, NULL,
PIPE_TRANSFER_READ_WRITE |
PIPE_TRANSFER_UNSYNCHRONIZED |
RADEON_TRANSFER_TEMPORARY);
+ if (!u.rx_ptr)
+ return false;
- /* Don't use util_memcpy_cpu_to_le32. LLVM binaries are
- * endian-independent. */
- if (prolog) {
- memcpy(ptr, prolog->code, prolog->code_size);
- ptr += prolog->code_size;
- }
- if (previous_stage) {
- memcpy(ptr, previous_stage->code, previous_stage->code_size);
- ptr += previous_stage->code_size;
- }
- if (prolog2) {
- memcpy(ptr, prolog2->code, prolog2->code_size);
- ptr += prolog2->code_size;
- }
-
- memcpy(ptr, mainb->code, mainb->code_size);
- ptr += mainb->code_size;
-
- if (epilog) {
- memcpy(ptr, epilog->code, epilog->code_size);
- ptr += epilog->code_size;
- } else if (mainb->rodata_size > 0) {
- memcpy(ptr, mainb->rodata, mainb->rodata_size);
- ptr += mainb->rodata_size;
- }
-
- /* Add end-of-code markers for the UMR disassembler. */
- uint32_t *ptr32 = (uint32_t*)ptr;
- for (unsigned i = 0; i < DEBUGGER_NUM_MARKERS; i++)
- ptr32[i] = DEBUGGER_END_OF_CODE_MARKER;
+ bool ok = ac_rtld_upload(&u);
sscreen->ws->buffer_unmap(shader->bo->buf);
- return 0;
+ ac_rtld_close(&binary);
+
+ return ok;
}
-static void si_shader_dump_disassembly(const struct ac_shader_binary *binary,
+static void si_shader_dump_disassembly(struct si_screen *screen,
+ const struct si_shader_binary *binary,
struct pipe_debug_callback *debug,
const char *name, FILE *file)
{
- char *line, *p;
- unsigned i, count;
+ struct ac_rtld_binary rtld_binary;
- if (binary->disasm_string) {
- fprintf(file, "Shader %s disassembly:\n", name);
- fprintf(file, "%s", binary->disasm_string);
+ if (!ac_rtld_open(&rtld_binary, (struct ac_rtld_open_info){
+ .info = &screen->info,
+ .num_parts = 1,
+ .elf_ptrs = &binary->elf_buffer,
+ .elf_sizes = &binary->elf_size }))
+ return;
- if (debug && debug->debug_message) {
- /* Very long debug messages are cut off, so send the
- * disassembly one line at a time. This causes more
- * overhead, but on the plus side it simplifies
- * parsing of resulting logs.
- */
- pipe_debug_message(debug, SHADER_INFO,
- "Shader Disassembly Begin");
+ const char *disasm;
+ size_t nbytes;
- line = binary->disasm_string;
- while (*line) {
- p = util_strchrnul(line, '\n');
- count = p - line;
+ if (!ac_rtld_get_section_by_name(&rtld_binary, ".AMDGPU.disasm", &disasm, &nbytes))
+ goto out;
- if (count) {
- pipe_debug_message(debug, SHADER_INFO,
- "%.*s", count, line);
- }
+ if (nbytes > INT_MAX)
+ goto out;
- if (!*p)
- break;
- line = p + 1;
+ if (debug && debug->debug_message) {
+ /* Very long debug messages are cut off, so send the
+ * disassembly one line at a time. This causes more
+ * overhead, but on the plus side it simplifies
+ * parsing of resulting logs.
+ */
+ pipe_debug_message(debug, SHADER_INFO,
+ "Shader Disassembly Begin");
+
+ uint64_t line = 0;
+ while (line < nbytes) {
+ int count = nbytes - line;
+ const char *nl = memchr(disasm + line, '\n', nbytes - line);
+ if (nl)
+ count = nl - (disasm + line);
+
+ if (count) {
+ pipe_debug_message(debug, SHADER_INFO,
+ "%.*s", count, disasm + line);
}
- pipe_debug_message(debug, SHADER_INFO,
- "Shader Disassembly End");
- }
- } else {
- fprintf(file, "Shader %s binary:\n", name);
- for (i = 0; i < binary->code_size; i += 4) {
- fprintf(file, "@0x%x: %02x%02x%02x%02x\n", i,
- binary->code[i + 3], binary->code[i + 2],
- binary->code[i + 1], binary->code[i]);
+ line += count + 1;
}
+
+ pipe_debug_message(debug, SHADER_INFO,
+ "Shader Disassembly End");
}
+
+ if (file) {
+ fprintf(file, "Shader %s disassembly:\n", name);
+ fprintf(file, "%*s", (int)nbytes, disasm);
+ }
+
+out:
+ ac_rtld_close(&rtld_binary);
}
static void si_calculate_max_simd_waves(struct si_shader *shader)
{
struct si_screen *sscreen = shader->selector->screen;
- struct si_shader_config *conf = &shader->config;
+ struct ac_shader_config *conf = &shader->config;
unsigned num_inputs = shader->selector->info.num_inputs;
- unsigned lds_increment = sscreen->info.chip_class >= CIK ? 512 : 256;
+ unsigned lds_increment = sscreen->info.chip_class >= GFX7 ? 512 : 256;
unsigned lds_per_wave = 0;
unsigned max_simd_waves;
/* Compute the per-SIMD wave counts. */
if (conf->num_sgprs) {
- if (sscreen->info.chip_class >= VI)
- max_simd_waves = MIN2(max_simd_waves, 800 / conf->num_sgprs);
- else
- max_simd_waves = MIN2(max_simd_waves, 512 / conf->num_sgprs);
+ max_simd_waves =
+ MIN2(max_simd_waves,
+ ac_get_num_physical_sgprs(sscreen->info.chip_class) / conf->num_sgprs);
}
if (conf->num_vgprs)
if (lds_per_wave)
max_simd_waves = MIN2(max_simd_waves, 16384 / lds_per_wave);
- conf->max_simd_waves = max_simd_waves;
+ shader->info.max_simd_waves = max_simd_waves;
}
-void si_shader_dump_stats_for_shader_db(const struct si_shader *shader,
+void si_shader_dump_stats_for_shader_db(struct si_screen *screen,
+ struct si_shader *shader,
struct pipe_debug_callback *debug)
{
- const struct si_shader_config *conf = &shader->config;
+ const struct ac_shader_config *conf = &shader->config;
+
+ if (screen->options.debug_disassembly)
+ si_shader_dump_disassembly(screen, &shader->binary, debug, "main", NULL);
pipe_debug_message(debug, SHADER_INFO,
"Shader Stats: SGPRS: %d VGPRS: %d Code Size: %d "
"LDS: %d Scratch: %d Max Waves: %d Spilled SGPRs: %d "
"Spilled VGPRs: %d PrivMem VGPRs: %d",
conf->num_sgprs, conf->num_vgprs,
- si_get_shader_binary_size(shader),
+ si_get_shader_binary_size(screen, shader),
conf->lds_size, conf->scratch_bytes_per_wave,
- conf->max_simd_waves, conf->spilled_sgprs,
- conf->spilled_vgprs, conf->private_mem_vgprs);
+ shader->info.max_simd_waves, conf->spilled_sgprs,
+ conf->spilled_vgprs, shader->info.private_mem_vgprs);
}
static void si_shader_dump_stats(struct si_screen *sscreen,
- const struct si_shader *shader,
+ struct si_shader *shader,
unsigned processor,
FILE *file,
bool check_debug_option)
{
- const struct si_shader_config *conf = &shader->config;
+ const struct ac_shader_config *conf = &shader->config;
if (!check_debug_option ||
si_can_dump_shader(sscreen, processor)) {
"********************\n\n\n",
conf->num_sgprs, conf->num_vgprs,
conf->spilled_sgprs, conf->spilled_vgprs,
- conf->private_mem_vgprs,
- si_get_shader_binary_size(shader),
+ shader->info.private_mem_vgprs,
+ si_get_shader_binary_size(sscreen, shader),
conf->lds_size, conf->scratch_bytes_per_wave,
- conf->max_simd_waves);
+ shader->info.max_simd_waves);
}
}
return "Vertex Shader as ES";
else if (shader->key.as_ls)
return "Vertex Shader as LS";
+ else if (shader->key.opt.vs_as_prim_discard_cs)
+ return "Vertex Shader as Primitive Discard CS";
else
return "Vertex Shader as VS";
case PIPE_SHADER_TESS_CTRL:
}
}
-void si_shader_dump(struct si_screen *sscreen, const struct si_shader *shader,
+void si_shader_dump(struct si_screen *sscreen, struct si_shader *shader,
struct pipe_debug_callback *debug, unsigned processor,
FILE *file, bool check_debug_option)
{
fprintf(file, "\n%s:\n", si_get_shader_name(shader, processor));
if (shader->prolog)
- si_shader_dump_disassembly(&shader->prolog->binary,
+ si_shader_dump_disassembly(sscreen, &shader->prolog->binary,
debug, "prolog", file);
if (shader->previous_stage)
- si_shader_dump_disassembly(&shader->previous_stage->binary,
+ si_shader_dump_disassembly(sscreen, &shader->previous_stage->binary,
debug, "previous stage", file);
if (shader->prolog2)
- si_shader_dump_disassembly(&shader->prolog2->binary,
+ si_shader_dump_disassembly(sscreen, &shader->prolog2->binary,
debug, "prolog2", file);
- si_shader_dump_disassembly(&shader->binary, debug, "main", file);
+ si_shader_dump_disassembly(sscreen, &shader->binary, debug, "main", file);
if (shader->epilog)
- si_shader_dump_disassembly(&shader->epilog->binary,
+ si_shader_dump_disassembly(sscreen, &shader->epilog->binary,
debug, "epilog", file);
fprintf(file, "\n");
}
}
static int si_compile_llvm(struct si_screen *sscreen,
- struct ac_shader_binary *binary,
- struct si_shader_config *conf,
+ struct si_shader_binary *binary,
+ struct ac_shader_config *conf,
struct ac_llvm_compiler *compiler,
LLVMModuleRef mod,
struct pipe_debug_callback *debug,
const char *name,
bool less_optimized)
{
- int r = 0;
unsigned count = p_atomic_inc_return(&sscreen->num_compilations);
if (si_can_dump_shader(sscreen, processor)) {
}
if (!si_replace_shader(count, binary)) {
- r = si_llvm_compile(mod, binary, compiler, debug,
- less_optimized);
+ unsigned r = si_llvm_compile(mod, binary, compiler, debug,
+ less_optimized);
if (r)
return r;
}
- si_shader_binary_read_config(binary, conf, 0);
+ struct ac_rtld_binary rtld;
+ if (!ac_rtld_open(&rtld, (struct ac_rtld_open_info){
+ .info = &sscreen->info,
+ .num_parts = 1,
+ .elf_ptrs = &binary->elf_buffer,
+ .elf_sizes = &binary->elf_size }))
+ return -1;
+
+ bool ok = ac_rtld_read_config(&rtld, conf);
+ ac_rtld_close(&rtld);
+ if (!ok)
+ return -1;
/* Enable 64-bit and 16-bit denormals, because there is no performance
* cost.
* - Floating-point output modifiers would be ignored by the hw.
* - Some opcodes don't support denormals, such as v_mad_f32. We would
* have to stop using those.
- * - SI & CI would be very slow.
+ * - GFX6 & GFX7 would be very slow.
*/
conf->float_mode |= V_00B028_FP_64_DENORMS;
- FREE(binary->config);
- FREE(binary->global_symbol_offsets);
- binary->config = NULL;
- binary->global_symbol_offsets = NULL;
-
- /* Some shaders can't have rodata because their binaries can be
- * concatenated.
- */
- if (binary->rodata_size &&
- (processor == PIPE_SHADER_VERTEX ||
- processor == PIPE_SHADER_TESS_CTRL ||
- processor == PIPE_SHADER_TESS_EVAL ||
- processor == PIPE_SHADER_FRAGMENT)) {
- fprintf(stderr, "radeonsi: The shader can't have rodata.");
- return -EINVAL;
- }
-
- return r;
+ return 0;
}
static void si_llvm_build_ret(struct si_shader_context *ctx, LLVMValueRef ret)
LLVMBuilderRef builder;
struct si_shader_output_values outputs[SI_MAX_VS_OUTPUTS];
struct tgsi_shader_info *gsinfo = &gs_selector->info;
- int i, r;
+ int i;
shader = CALLOC_STRUCT(si_shader);
stream);
}
- if (stream == 0) {
- /* Vertex color clamping.
- *
- * This uses a state constant loaded in a user data SGPR and
- * an IF statement is added that clamps all colors if the constant
- * is true.
- */
- struct lp_build_if_state if_ctx;
- LLVMValueRef v[2], cond = NULL;
- LLVMBasicBlockRef blocks[2];
-
- for (unsigned i = 0; i < gsinfo->num_outputs; i++) {
- if (gsinfo->output_semantic_name[i] != TGSI_SEMANTIC_COLOR &&
- gsinfo->output_semantic_name[i] != TGSI_SEMANTIC_BCOLOR)
- continue;
-
- /* We've found a color. */
- if (!cond) {
- /* The state is in the first bit of the user SGPR. */
- cond = LLVMGetParam(ctx.main_fn,
- ctx.param_vs_state_bits);
- cond = LLVMBuildTrunc(ctx.ac.builder, cond,
- ctx.i1, "");
- lp_build_if(&if_ctx, &ctx.gallivm, cond);
- /* Remember blocks for Phi. */
- blocks[0] = if_ctx.true_block;
- blocks[1] = if_ctx.entry_block;
- }
-
- for (unsigned j = 0; j < 4; j++) {
- /* Insert clamp into the true block. */
- v[0] = ac_build_clamp(&ctx.ac, outputs[i].values[j]);
- v[1] = outputs[i].values[j];
-
- /* Insert Phi into the endif block. */
- LLVMPositionBuilderAtEnd(ctx.ac.builder, if_ctx.merge_block);
- outputs[i].values[j] = ac_build_phi(&ctx.ac, ctx.f32, 2, v, blocks);
- LLVMPositionBuilderAtEnd(ctx.ac.builder, if_ctx.true_block);
- }
- }
- if (cond)
- lp_build_endif(&if_ctx);
-
+ if (stream == 0)
si_llvm_export_vs(&ctx, outputs, gsinfo->num_outputs);
- }
LLVMBuildBr(builder, end_bb);
}
ctx.type = PIPE_SHADER_GEOMETRY; /* override for shader dumping */
si_llvm_optimize_module(&ctx);
- r = si_compile_llvm(sscreen, &ctx.shader->binary,
+ bool ok = false;
+ if (si_compile_llvm(sscreen, &ctx.shader->binary,
&ctx.shader->config, ctx.compiler,
ctx.ac.module,
debug, PIPE_SHADER_GEOMETRY,
- "GS Copy Shader", false);
- if (!r) {
+ "GS Copy Shader", false) == 0) {
if (si_can_dump_shader(sscreen, PIPE_SHADER_GEOMETRY))
fprintf(stderr, "GS Copy Shader:\n");
si_shader_dump(sscreen, ctx.shader, debug,
PIPE_SHADER_GEOMETRY, stderr, true);
- r = si_shader_binary_upload(sscreen, ctx.shader);
+
+ if (!ctx.shader->config.scratch_bytes_per_wave)
+ ok = si_shader_binary_upload(sscreen, ctx.shader, 0);
+ else
+ ok = true;
}
si_llvm_dispose(&ctx);
- if (r != 0) {
+ if (!ok) {
FREE(shader);
shader = NULL;
+ } else {
+ si_fix_resource_usage(sscreen, shader);
}
return shader;
}
prefix, prolog->instance_divisor_is_one);
fprintf(f, " %s.instance_divisor_is_fetched = %u\n",
prefix, prolog->instance_divisor_is_fetched);
+ fprintf(f, " %s.unpack_instance_id_from_vertex_id = %u\n",
+ prefix, prolog->unpack_instance_id_from_vertex_id);
fprintf(f, " %s.ls_vgpr_fix = %u\n",
prefix, prolog->ls_vgpr_fix);
+ fprintf(f, " mono.vs.fetch_opencode = %x\n", key->mono.vs_fetch_opencode);
fprintf(f, " mono.vs.fix_fetch = {");
- for (int i = 0; i < SI_MAX_ATTRIBS; i++)
- fprintf(f, !i ? "%u" : ", %u", key->mono.vs_fix_fetch[i]);
+ for (int i = 0; i < SI_MAX_ATTRIBS; i++) {
+ union si_vs_fix_fetch fix = key->mono.vs_fix_fetch[i];
+ if (i)
+ fprintf(f, ", ");
+ if (!fix.bits)
+ fprintf(f, "0");
+ else
+ fprintf(f, "%u.%u.%u.%u", fix.u.reverse, fix.u.log_size,
+ fix.u.num_channels_m1, fix.u.format);
+ }
fprintf(f, "}\n");
}
fprintf(f, " as_ls = %u\n", key->as_ls);
fprintf(f, " mono.u.vs_export_prim_id = %u\n",
key->mono.u.vs_export_prim_id);
+ fprintf(f, " opt.vs_as_prim_discard_cs = %u\n",
+ key->opt.vs_as_prim_discard_cs);
+ fprintf(f, " opt.cs_prim_type = %s\n",
+ tgsi_primitive_names[key->opt.cs_prim_type]);
+ fprintf(f, " opt.cs_indexed = %u\n",
+ key->opt.cs_indexed);
+ fprintf(f, " opt.cs_instancing = %u\n",
+ key->opt.cs_instancing);
+ fprintf(f, " opt.cs_primitive_restart = %u\n",
+ key->opt.cs_primitive_restart);
+ fprintf(f, " opt.cs_provoking_vertex_first = %u\n",
+ key->opt.cs_provoking_vertex_first);
+ fprintf(f, " opt.cs_need_correct_orientation = %u\n",
+ key->opt.cs_need_correct_orientation);
+ fprintf(f, " opt.cs_cull_front = %u\n",
+ key->opt.cs_cull_front);
+ fprintf(f, " opt.cs_cull_back = %u\n",
+ key->opt.cs_cull_back);
+ fprintf(f, " opt.cs_cull_z = %u\n",
+ key->opt.cs_cull_z);
+ fprintf(f, " opt.cs_halfz_clip_space = %u\n",
+ key->opt.cs_halfz_clip_space);
break;
case PIPE_SHADER_TESS_CTRL:
ctx->abi.emit_outputs = si_llvm_emit_ls_epilogue;
else if (shader->key.as_es)
ctx->abi.emit_outputs = si_llvm_emit_es_epilogue;
+ else if (shader->key.opt.vs_as_prim_discard_cs)
+ ctx->abi.emit_outputs = si_llvm_emit_prim_discard_cs_epilogue;
else
ctx->abi.emit_outputs = si_llvm_emit_vs_epilogue;
bld_base->emit_epilogue = si_tgsi_emit_epilogue;
gprs += size;
}
- si_create_function(ctx, "wrapper", NULL, 0, &fninfo,
+ /* Prepare the return type. */
+ unsigned num_returns = 0;
+ LLVMTypeRef returns[32], last_func_type, return_type;
+
+ last_func_type = LLVMGetElementType(LLVMTypeOf(parts[num_parts - 1]));
+ return_type = LLVMGetReturnType(last_func_type);
+
+ switch (LLVMGetTypeKind(return_type)) {
+ case LLVMStructTypeKind:
+ num_returns = LLVMCountStructElementTypes(return_type);
+ assert(num_returns <= ARRAY_SIZE(returns));
+ LLVMGetStructElementTypes(return_type, returns);
+ break;
+ case LLVMVoidTypeKind:
+ break;
+ default:
+ unreachable("unexpected type");
+ }
+
+ si_create_function(ctx, "wrapper", returns, num_returns, &fninfo,
si_get_max_workgroup_size(ctx->shader));
if (is_merged_shader(ctx))
initial_num_out_sgpr = num_out_sgpr;
/* Now chain the parts. */
+ LLVMValueRef ret;
for (unsigned part = 0; part < num_parts; ++part) {
LLVMValueRef in[48];
- LLVMValueRef ret;
LLVMTypeRef ret_type;
unsigned out_idx = 0;
unsigned num_params = LLVMCountParams(parts[part]);
}
}
- LLVMBuildRetVoid(builder);
+ /* Return the value from the last part. */
+ if (LLVMGetTypeKind(LLVMTypeOf(ret)) == LLVMVoidTypeKind)
+ LLVMBuildRetVoid(builder);
+ else
+ LLVMBuildRet(builder, ret);
}
static bool si_should_optimize_less(struct ac_llvm_compiler *compiler,
/* Assume a slow CPU. */
assert(!sel->screen->info.has_dedicated_vram &&
- sel->screen->info.chip_class <= VI);
+ sel->screen->info.chip_class <= GFX8);
/* For a crazy dEQP test containing 2597 memory opcodes, mostly
* buffer stores. */
si_build_wrapper_function(&ctx, parts + !need_prolog,
1 + need_prolog, need_prolog, 0);
+
+ if (ctx.shader->key.opt.vs_as_prim_discard_cs)
+ si_build_prim_discard_compute_shader(&ctx);
} else if (shader->is_monolithic && ctx.type == PIPE_SHADER_TESS_CTRL) {
if (sscreen->info.chip_class >= GFX9) {
struct si_shader_selector *ls = shader->key.part.tcs.ls;
if ((debug && debug->debug_message) ||
si_can_dump_shader(sscreen, ctx.type)) {
- ctx.shader->config.private_mem_vgprs =
+ ctx.shader->info.private_mem_vgprs =
ac_count_scratch_private_memory(ctx.main_fn);
}
if (sel->type == PIPE_SHADER_COMPUTE) {
unsigned wave_size = 64;
unsigned max_vgprs = 256;
- unsigned max_sgprs = sscreen->info.chip_class >= VI ? 800 : 512;
+ unsigned max_sgprs = sscreen->info.chip_class >= GFX8 ? 800 : 512;
unsigned max_sgprs_per_wave = 128;
unsigned max_block_threads = si_get_max_workgroup_size(shader);
unsigned min_waves_per_cu = DIV_ROUND_UP(max_block_threads, wave_size);
}
si_calculate_max_simd_waves(shader);
- si_shader_dump_stats_for_shader_db(shader, debug);
+ si_shader_dump_stats_for_shader_db(sscreen, shader, debug);
return 0;
}
}
}
- ctx->abi.vertex_id = input_vgprs[first_vs_vgpr];
- ctx->abi.instance_id = input_vgprs[first_vs_vgpr + (key->vs_prolog.as_ls ? 2 : 1)];
+ unsigned vertex_id_vgpr = first_vs_vgpr;
+ unsigned instance_id_vgpr = first_vs_vgpr + (key->vs_prolog.as_ls ? 2 : 1);
+
+ ctx->abi.vertex_id = input_vgprs[vertex_id_vgpr];
+ ctx->abi.instance_id = input_vgprs[instance_id_vgpr];
+
+ /* InstanceID = VertexID >> 16;
+ * VertexID = VertexID & 0xffff;
+ */
+ if (key->vs_prolog.states.unpack_instance_id_from_vertex_id) {
+ ctx->abi.instance_id = LLVMBuildLShr(ctx->ac.builder, ctx->abi.vertex_id,
+ LLVMConstInt(ctx->i32, 16, 0), "");
+ ctx->abi.vertex_id = LLVMBuildAnd(ctx->ac.builder, ctx->abi.vertex_id,
+ LLVMConstInt(ctx->i32, 0xffff, 0), "");
+ }
/* Copy inputs to outputs. This should be no-op, as the registers match,
* but it will prevent the compiler from overwriting them unintentionally.
}
for (i = 0; i < num_input_vgprs; i++) {
LLVMValueRef p = input_vgprs[i];
+
+ if (i == vertex_id_vgpr)
+ p = ctx->abi.vertex_id;
+ else if (i == instance_id_vgpr)
+ p = ctx->abi.instance_id;
+
p = ac_to_float(&ctx->ac, p);
ret = LLVMBuildInsertValue(ctx->ac.builder, ret, p,
key->vs_prolog.num_input_sgprs + i, "");
/* Create the function. */
si_create_function(ctx, "tcs_epilog", NULL, 0, &fninfo,
- ctx->screen->info.chip_class >= CIK ? 128 : 64);
+ ctx->screen->info.chip_class >= GFX7 ? 128 : 64);
ac_declare_lds_as_pointer(&ctx->ac);
func = ctx->main_fn;
* It applies to workgroup sizes of more than one wavefront.
*/
if (sscreen->info.family == CHIP_BONAIRE ||
- sscreen->info.family == CHIP_KABINI ||
- sscreen->info.family == CHIP_MULLINS)
+ sscreen->info.family == CHIP_KABINI)
*lds_size = MAX2(*lds_size, 8);
}
}
}
-int si_shader_create(struct si_screen *sscreen, struct ac_llvm_compiler *compiler,
+bool si_shader_create(struct si_screen *sscreen, struct ac_llvm_compiler *compiler,
struct si_shader *shader,
struct pipe_debug_callback *debug)
{
*/
r = si_compile_tgsi_shader(sscreen, compiler, shader, debug);
if (r)
- return r;
+ return false;
} else {
/* The shader consists of several parts:
*
*/
if (!mainp)
- return -1;
+ return false;
/* Copy the compiled TGSI shader data over. */
shader->is_binary_shared = true;
switch (sel->type) {
case PIPE_SHADER_VERTEX:
if (!si_shader_select_vs_parts(sscreen, compiler, shader, debug))
- return -1;
+ return false;
break;
case PIPE_SHADER_TESS_CTRL:
if (!si_shader_select_tcs_parts(sscreen, compiler, shader, debug))
- return -1;
+ return false;
break;
case PIPE_SHADER_TESS_EVAL:
break;
case PIPE_SHADER_GEOMETRY:
if (!si_shader_select_gs_parts(sscreen, compiler, shader, debug))
- return -1;
+ return false;
break;
case PIPE_SHADER_FRAGMENT:
if (!si_shader_select_ps_parts(sscreen, compiler, shader, debug))
- return -1;
+ return false;
/* Make sure we have at least as many VGPRs as there
* are allocated inputs.
shader->config.spilled_vgprs =
MAX2(shader->config.spilled_vgprs,
shader->previous_stage->config.spilled_vgprs);
- shader->config.private_mem_vgprs =
- MAX2(shader->config.private_mem_vgprs,
- shader->previous_stage->config.private_mem_vgprs);
+ shader->info.private_mem_vgprs =
+ MAX2(shader->info.private_mem_vgprs,
+ shader->previous_stage->info.private_mem_vgprs);
shader->config.scratch_bytes_per_wave =
MAX2(shader->config.scratch_bytes_per_wave,
shader->previous_stage->config.scratch_bytes_per_wave);
si_calculate_max_simd_waves(shader);
}
+ if (sscreen->info.chip_class >= GFX9 && sel->type == PIPE_SHADER_GEOMETRY)
+ gfx9_get_gs_info(shader->previous_stage_sel, sel, &shader->gs_info);
+
si_fix_resource_usage(sscreen, shader);
si_shader_dump(sscreen, shader, debug, sel->info.processor,
stderr, true);
/* Upload. */
- r = si_shader_binary_upload(sscreen, shader);
- if (r) {
+ if (!si_shader_binary_upload(sscreen, shader, 0)) {
fprintf(stderr, "LLVM failed to upload shader\n");
- return r;
+ return false;
}
- return 0;
+ return true;
}
void si_shader_destroy(struct si_shader *shader)
{
if (shader->scratch_bo)
- r600_resource_reference(&shader->scratch_bo, NULL);
+ si_resource_reference(&shader->scratch_bo, NULL);
- r600_resource_reference(&shader->bo, NULL);
+ si_resource_reference(&shader->bo, NULL);
if (!shader->is_binary_shared)
- ac_shader_binary_clean(&shader->binary);
+ si_shader_binary_clean(&shader->binary);
free(shader->shader_log);
}