radeonsi: store shader disassemblies in memory for future users
[mesa.git] / src / gallium / drivers / radeonsi / si_shader.c
index 81f7bdb3472c1e09fbc449506968d7da49342319..465eecd0346aed995451ee1b5e562c01280d325e 100644 (file)
@@ -31,6 +31,7 @@
 #include "gallivm/lp_bld_intr.h"
 #include "gallivm/lp_bld_logic.h"
 #include "gallivm/lp_bld_arit.h"
+#include "gallivm/lp_bld_bitarit.h"
 #include "gallivm/lp_bld_flow.h"
 #include "radeon/r600_cs.h"
 #include "radeon/radeon_llvm.h"
@@ -87,8 +88,8 @@ struct si_shader_context
        LLVMValueRef samplers[SI_NUM_SAMPLER_STATES];
        LLVMValueRef so_buffers[4];
        LLVMValueRef esgs_ring;
-       LLVMValueRef gsvs_ring;
-       LLVMValueRef gs_next_vertex;
+       LLVMValueRef gsvs_ring[4];
+       LLVMValueRef gs_next_vertex[4];
 };
 
 static struct si_shader_context * si_shader_context(
@@ -456,7 +457,7 @@ static void declare_input_vs(
        args[0] = t_list;
        args[1] = attribute_offset;
        args[2] = buffer_index;
-       input = build_intrinsic(gallivm->builder,
+       input = lp_build_intrinsic(gallivm->builder,
                "llvm.SI.vs.load.input", vec4_type, args, 3,
                LLVMReadNoneAttribute | LLVMNoUnwindAttribute);
 
@@ -829,7 +830,7 @@ static LLVMValueRef fetch_input_gs(
        args[8] = uint->zero; /* TFE */
 
        return LLVMBuildBitCast(gallivm->builder,
-                               build_intrinsic(gallivm->builder,
+                               lp_build_intrinsic(gallivm->builder,
                                                "llvm.SI.buffer.load.dword.i32.i32",
                                                i32, args, 9,
                                                LLVMReadOnlyAttribute | LLVMNoUnwindAttribute),
@@ -973,12 +974,12 @@ static void declare_input_fs(
 
                        args[0] = llvm_chan;
                        args[1] = attr_number;
-                       front = build_intrinsic(gallivm->builder, intr_name,
+                       front = lp_build_intrinsic(gallivm->builder, intr_name,
                                                input_type, args, args[3] ? 4 : 3,
                                                LLVMReadNoneAttribute | LLVMNoUnwindAttribute);
 
                        args[1] = back_attr_number;
-                       back = build_intrinsic(gallivm->builder, intr_name,
+                       back = lp_build_intrinsic(gallivm->builder, intr_name,
                                               input_type, args, args[3] ? 4 : 3,
                                               LLVMReadNoneAttribute | LLVMNoUnwindAttribute);
 
@@ -999,7 +1000,7 @@ static void declare_input_fs(
                args[2] = params;
                args[3] = interp_param;
                radeon_bld->inputs[radeon_llvm_reg_index_soa(input_index, 0)] =
-                       build_intrinsic(gallivm->builder, intr_name,
+                       lp_build_intrinsic(gallivm->builder, intr_name,
                                        input_type, args, args[3] ? 4 : 3,
                                        LLVMReadNoneAttribute | LLVMNoUnwindAttribute);
                radeon_bld->inputs[radeon_llvm_reg_index_soa(input_index, 1)] =
@@ -1017,7 +1018,7 @@ static void declare_input_fs(
                        args[2] = params;
                        args[3] = interp_param;
                        radeon_bld->inputs[soa_index] =
-                               build_intrinsic(gallivm->builder, intr_name,
+                               lp_build_intrinsic(gallivm->builder, intr_name,
                                                input_type, args, args[3] ? 4 : 3,
                                                LLVMReadNoneAttribute | LLVMNoUnwindAttribute);
                }
@@ -1038,7 +1039,7 @@ static LLVMValueRef buffer_load_const(LLVMBuilderRef builder, LLVMValueRef resou
 {
        LLVMValueRef args[2] = {resource, offset};
 
-       return build_intrinsic(builder, "llvm.SI.load.const", return_type, args, 2,
+       return lp_build_intrinsic(builder, "llvm.SI.load.const", return_type, args, 2,
                               LLVMReadNoneAttribute | LLVMNoUnwindAttribute);
 }
 
@@ -1289,7 +1290,7 @@ static void si_llvm_init_export_args(struct lp_build_tgsi_context *bld_base,
                        args[0] = values[2 * chan];
                        args[1] = values[2 * chan + 1];
                        args[chan + 5] =
-                               build_intrinsic(base->gallivm->builder,
+                               lp_build_intrinsic(base->gallivm->builder,
                                                "llvm.SI.packf16",
                                                LLVMInt32TypeInContext(base->gallivm->context),
                                                args, 2,
@@ -1371,12 +1372,12 @@ static void si_alpha_test(struct lp_build_tgsi_context *bld_base,
                                        lp_build_const_float(gallivm, 1.0f),
                                        lp_build_const_float(gallivm, -1.0f));
 
-               build_intrinsic(gallivm->builder,
+               lp_build_intrinsic(gallivm->builder,
                                "llvm.AMDGPU.kill",
                                LLVMVoidTypeInContext(gallivm->context),
                                &arg, 1, 0);
        } else {
-               build_intrinsic(gallivm->builder,
+               lp_build_intrinsic(gallivm->builder,
                                "llvm.AMDGPU.kilp",
                                LLVMVoidTypeInContext(gallivm->context),
                                NULL, 0, 0);
@@ -1397,7 +1398,7 @@ static void si_scale_alpha_by_sample_mask(struct lp_build_tgsi_context *bld_base
                                SI_PARAM_SAMPLE_COVERAGE);
        coverage = bitcast(bld_base, TGSI_TYPE_SIGNED, coverage);
 
-       coverage = build_intrinsic(gallivm->builder, "llvm.ctpop.i32",
+       coverage = lp_build_intrinsic(gallivm->builder, "llvm.ctpop.i32",
                                   bld_base->int_bld.elem_type,
                                   &coverage, 1, LLVMReadNoneAttribute);
 
@@ -1527,7 +1528,7 @@ static void build_tbuffer_store(struct si_shader_context *shader,
 
        lp_build_intrinsic(gallivm->builder, name,
                           LLVMVoidTypeInContext(gallivm->context),
-                          args, Elements(args));
+                          args, Elements(args), 0);
 }
 
 static void build_tbuffer_store_dwords(struct si_shader_context *shader,
@@ -1569,13 +1570,16 @@ static void si_llvm_emit_streamout(struct si_shader_context *shader,
        LLVMValueRef so_vtx_count =
                unpack_param(shader, shader->param_streamout_config, 16, 7);
 
-       LLVMValueRef tid = build_intrinsic(builder, "llvm.SI.tid", i32,
+       LLVMValueRef tid = lp_build_intrinsic(builder, "llvm.SI.tid", i32,
                                           NULL, 0, LLVMReadNoneAttribute);
 
        /* can_emit = tid < so_vtx_count; */
        LLVMValueRef can_emit =
                LLVMBuildICmp(builder, LLVMIntULT, tid, so_vtx_count, "");
 
+       LLVMValueRef stream_id =
+               unpack_param(shader, shader->param_streamout_config, 24, 2);
+
        /* Emit the streamout code conditionally. This actually avoids
         * out-of-bounds buffer access. The hw tells us via the SGPR
         * (so_vtx_count) which threads are allowed to emit streamout data. */
@@ -1615,7 +1619,9 @@ static void si_llvm_emit_streamout(struct si_shader_context *shader,
                        unsigned reg = so->output[i].register_index;
                        unsigned start = so->output[i].start_component;
                        unsigned num_comps = so->output[i].num_components;
+                       unsigned stream = so->output[i].stream;
                        LLVMValueRef out[4];
+                       struct lp_build_if_state if_ctx_stream;
 
                        assert(num_comps && num_comps <= 4);
                        if (!num_comps || num_comps > 4)
@@ -1649,11 +1655,18 @@ static void si_llvm_emit_streamout(struct si_shader_context *shader,
                                break;
                        }
 
+                       LLVMValueRef can_emit_stream =
+                               LLVMBuildICmp(builder, LLVMIntEQ,
+                                             stream_id,
+                                             lp_build_const_int32(gallivm, stream), "");
+
+                       lp_build_if(&if_ctx_stream, gallivm, can_emit_stream);
                        build_tbuffer_store_dwords(shader, shader->so_buffers[buf_idx],
                                                   vdata, num_comps,
                                                   so_write_offset[buf_idx],
                                                   LLVMConstInt(i32, 0, 0),
                                                   so->output[i].dst_offset*4);
+                       lp_build_endif(&if_ctx_stream);
                }
        }
        lp_build_endif(&if_ctx);
@@ -1744,7 +1757,7 @@ handle_semantic:
                        lp_build_intrinsic(base->gallivm->builder,
                                           "llvm.SI.export",
                                           LLVMVoidTypeInContext(base->gallivm->context),
-                                          args, 9);
+                                          args, 9, 0);
                }
 
                if (semantic_name == TGSI_SEMANTIC_CLIPDIST) {
@@ -1832,7 +1845,7 @@ handle_semantic:
                lp_build_intrinsic(base->gallivm->builder,
                                   "llvm.SI.export",
                                   LLVMVoidTypeInContext(base->gallivm->context),
-                                  pos_args[i], 9);
+                                  pos_args[i], 9, 0);
        }
 }
 
@@ -2018,7 +2031,7 @@ static void si_llvm_emit_gs_epilogue(struct lp_build_tgsi_context *bld_base)
 
        args[0] = lp_build_const_int32(gallivm, SENDMSG_GS_OP_NOP | SENDMSG_GS_DONE);
        args[1] = LLVMGetParam(si_shader_ctx->radeon_bld.main_fn, SI_PARAM_GS_WAVE_ID);
-       build_intrinsic(gallivm->builder, "llvm.SI.sendmsg",
+       lp_build_intrinsic(gallivm->builder, "llvm.SI.sendmsg",
                        LLVMVoidTypeInContext(gallivm->context), args, 2,
                        LLVMNoUnwindAttribute);
 }
@@ -2109,7 +2122,7 @@ static void si_llvm_emit_fs_epilogue(struct lp_build_tgsi_context * bld_base)
                                lp_build_intrinsic(base->gallivm->builder,
                                                   "llvm.SI.export",
                                                   LLVMVoidTypeInContext(base->gallivm->context),
-                                                  last_args, 9);
+                                                  last_args, 9, 0);
                        }
 
                        /* This instruction will be emitted at the end of the shader. */
@@ -2126,14 +2139,14 @@ static void si_llvm_emit_fs_epilogue(struct lp_build_tgsi_context * bld_base)
                                        lp_build_intrinsic(base->gallivm->builder,
                                                           "llvm.SI.export",
                                                           LLVMVoidTypeInContext(base->gallivm->context),
-                                                          args, 9);
+                                                          args, 9, 0);
                                }
                        }
                } else {
                        lp_build_intrinsic(base->gallivm->builder,
                                           "llvm.SI.export",
                                           LLVMVoidTypeInContext(base->gallivm->context),
-                                          args, 9);
+                                          args, 9, 0);
                }
        }
 
@@ -2195,7 +2208,7 @@ static void si_llvm_emit_fs_epilogue(struct lp_build_tgsi_context * bld_base)
                        lp_build_intrinsic(base->gallivm->builder,
                                           "llvm.SI.export",
                                           LLVMVoidTypeInContext(base->gallivm->context),
-                                          args, 9);
+                                          args, 9, 0);
                else
                        memcpy(last_args, args, sizeof(args));
        }
@@ -2226,7 +2239,7 @@ static void si_llvm_emit_fs_epilogue(struct lp_build_tgsi_context * bld_base)
        lp_build_intrinsic(base->gallivm->builder,
                           "llvm.SI.export",
                           LLVMVoidTypeInContext(base->gallivm->context),
-                          last_args, 9);
+                          last_args, 9, 0);
 }
 
 static void build_tex_intrinsic(const struct lp_build_tgsi_action * action,
@@ -2255,7 +2268,7 @@ static void tex_fetch_args(
        const struct tgsi_full_instruction * inst = emit_data->inst;
        unsigned opcode = inst->Instruction.Opcode;
        unsigned target = inst->Texture.Texture;
-       LLVMValueRef coords[5];
+       LLVMValueRef coords[5], derivs[6];
        LLVMValueRef address[16];
        int ref_pos;
        unsigned num_coords = tgsi_util_get_texture_coord_dim(target, &ref_pos);
@@ -2263,6 +2276,7 @@ static void tex_fetch_args(
        unsigned chan;
        unsigned sampler_src;
        unsigned sampler_index;
+       unsigned num_deriv_channels = 0;
        bool has_offset = HAVE_LLVM >= 0x0305 ? inst->Texture.NumOffsets > 0 : false;
        LLVMValueRef res_ptr, samp_ptr;
 
@@ -2361,18 +2375,13 @@ static void tex_fetch_args(
                }
        }
 
-       if (target == TGSI_TEXTURE_CUBE ||
-           target == TGSI_TEXTURE_CUBE_ARRAY ||
-           target == TGSI_TEXTURE_SHADOWCUBE ||
-           target == TGSI_TEXTURE_SHADOWCUBE_ARRAY)
-               radeon_llvm_emit_prepare_cube_coords(bld_base, emit_data, coords);
-
        /* Pack user derivatives */
        if (opcode == TGSI_OPCODE_TXD) {
-               int num_deriv_channels, param;
+               int param, num_src_deriv_channels;
 
                switch (target) {
                case TGSI_TEXTURE_3D:
+                       num_src_deriv_channels = 3;
                        num_deriv_channels = 3;
                        break;
                case TGSI_TEXTURE_2D:
@@ -2381,27 +2390,44 @@ static void tex_fetch_args(
                case TGSI_TEXTURE_SHADOWRECT:
                case TGSI_TEXTURE_2D_ARRAY:
                case TGSI_TEXTURE_SHADOW2D_ARRAY:
+                       num_src_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_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;
                        num_deriv_channels = 1;
                        break;
                default:
                        assert(0); /* no other targets are valid here */
                }
 
-               for (param = 1; param <= 2; param++)
-                       for (chan = 0; chan < num_deriv_channels; chan++)
-                               address[count++] = lp_build_emit_fetch(bld_base, inst, param, chan);
+               for (param = 0; param < 2; param++)
+                       for (chan = 0; chan < num_src_deriv_channels; chan++)
+                               derivs[param * num_src_deriv_channels + chan] =
+                                       lp_build_emit_fetch(bld_base, inst, param+1, chan);
        }
 
+       if (target == TGSI_TEXTURE_CUBE ||
+           target == TGSI_TEXTURE_CUBE_ARRAY ||
+           target == TGSI_TEXTURE_SHADOWCUBE ||
+           target == TGSI_TEXTURE_SHADOWCUBE_ARRAY)
+               radeon_llvm_emit_prepare_cube_coords(bld_base, emit_data, 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)
@@ -2652,7 +2678,7 @@ static void build_tex_intrinsic(const struct lp_build_tgsi_action * action,
                                emit_data->inst->Texture.NumOffsets > 0 : false;
 
        if (target == TGSI_TEXTURE_BUFFER) {
-               emit_data->output[emit_data->chan] = build_intrinsic(
+               emit_data->output[emit_data->chan] = lp_build_intrinsic(
                        base->gallivm->builder,
                        "llvm.SI.vs.load.input", emit_data->dst_type,
                        emit_data->args, emit_data->arg_count,
@@ -2701,7 +2727,7 @@ static void build_tex_intrinsic(const struct lp_build_tgsi_action * action,
                        is_shadow ? ".c" : "", infix, has_offset ? ".o" : "",
                        LLVMGetVectorSize(LLVMTypeOf(emit_data->args[0])));
 
-               emit_data->output[emit_data->chan] = build_intrinsic(
+               emit_data->output[emit_data->chan] = lp_build_intrinsic(
                        base->gallivm->builder, intr_name, emit_data->dst_type,
                        emit_data->args, emit_data->arg_count,
                        LLVMReadNoneAttribute | LLVMNoUnwindAttribute);
@@ -2748,7 +2774,7 @@ static void build_tex_intrinsic(const struct lp_build_tgsi_action * action,
                sprintf(intr_name, "%s.v%ui32", name,
                        LLVMGetVectorSize(LLVMTypeOf(emit_data->args[0])));
 
-               emit_data->output[emit_data->chan] = build_intrinsic(
+               emit_data->output[emit_data->chan] = lp_build_intrinsic(
                        base->gallivm->builder, intr_name, emit_data->dst_type,
                        emit_data->args, emit_data->arg_count,
                        LLVMReadNoneAttribute | LLVMNoUnwindAttribute);
@@ -2841,6 +2867,35 @@ static void build_txq_intrinsic(const struct lp_build_tgsi_action * action,
        }
 }
 
+/*
+ * SI implements derivatives using the local data store (LDS)
+ * All writes to the LDS happen in all executing threads at
+ * the same time. TID is the Thread ID for the current
+ * thread and is a value between 0 and 63, representing
+ * the thread's position in the wavefront.
+ *
+ * For the pixel shader threads are grouped into quads of four pixels.
+ * The TIDs of the pixels of a quad are:
+ *
+ *  +------+------+
+ *  |4n + 0|4n + 1|
+ *  +------+------+
+ *  |4n + 2|4n + 3|
+ *  +------+------+
+ *
+ * So, masking the TID with 0xfffffffc yields the TID of the top left pixel
+ * of the quad, masking with 0xfffffffd yields the TID of the top pixel of
+ * the current pixel's column, and masking with 0xfffffffe yields the TID
+ * of the left pixel of the current pixel's row.
+ *
+ * Adding 1 yields the TID of the pixel to the right of the left pixel, and
+ * adding 2 yields the TID of the pixel below the top pixel.
+ */
+/* masks for thread ID. */
+#define TID_MASK_TOP_LEFT 0xfffffffc
+#define TID_MASK_TOP      0xfffffffd
+#define TID_MASK_LEFT     0xfffffffe
+
 static void si_llvm_emit_ddxy(
        const struct lp_build_tgsi_action * action,
        struct lp_build_tgsi_context * bld_base,
@@ -2857,24 +2912,33 @@ static void si_llvm_emit_ddxy(
        LLVMTypeRef i32;
        unsigned swizzle[4];
        unsigned c;
+       int idx;
+       unsigned mask;
 
        i32 = LLVMInt32TypeInContext(gallivm->context);
 
        indices[0] = bld_base->uint_bld.zero;
-       indices[1] = build_intrinsic(gallivm->builder, "llvm.SI.tid", i32,
+       indices[1] = lp_build_intrinsic(gallivm->builder, "llvm.SI.tid", i32,
                                     NULL, 0, LLVMReadNoneAttribute);
        store_ptr = LLVMBuildGEP(gallivm->builder, si_shader_ctx->lds,
                                 indices, 2, "");
 
+       if (opcode == TGSI_OPCODE_DDX_FINE)
+               mask = TID_MASK_LEFT;
+       else if (opcode == TGSI_OPCODE_DDY_FINE)
+               mask = TID_MASK_TOP;
+       else
+               mask = TID_MASK_TOP_LEFT;
+
        indices[1] = LLVMBuildAnd(gallivm->builder, indices[1],
-                                 lp_build_const_int32(gallivm, 0xfffffffc), "");
+                                 lp_build_const_int32(gallivm, mask), "");
        load_ptr0 = LLVMBuildGEP(gallivm->builder, si_shader_ctx->lds,
                                 indices, 2, "");
 
+       /* for DDX we want to next X pixel, DDY next Y pixel. */
+       idx = (opcode == TGSI_OPCODE_DDX || opcode == TGSI_OPCODE_DDX_FINE) ? 1 : 2;
        indices[1] = LLVMBuildAdd(gallivm->builder, indices[1],
-                                 lp_build_const_int32(gallivm,
-                                                      opcode == TGSI_OPCODE_DDX ? 1 : 2),
-                                 "");
+                                 lp_build_const_int32(gallivm, idx), "");
        load_ptr1 = LLVMBuildGEP(gallivm->builder, si_shader_ctx->lds,
                                 indices, 2, "");
 
@@ -2909,6 +2973,247 @@ static void si_llvm_emit_ddxy(
        emit_data->output[0] = lp_build_gather_values(gallivm, result, 4);
 }
 
+/*
+ * 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 *si_shader_ctx = si_shader_context(bld_base);
+       struct gallivm_state *gallivm = bld_base->base.gallivm;
+       struct lp_build_context *base = &bld_base->base;
+       LLVMValueRef indices[2];
+       LLVMValueRef store_ptr, load_ptr_x, load_ptr_y, load_ptr_ddx, load_ptr_ddy, temp, temp2;
+       LLVMValueRef tl, tr, bl, result[4];
+       LLVMTypeRef i32;
+       unsigned c;
+
+       i32 = LLVMInt32TypeInContext(gallivm->context);
+
+       indices[0] = bld_base->uint_bld.zero;
+       indices[1] = lp_build_intrinsic(gallivm->builder, "llvm.SI.tid", i32,
+                                       NULL, 0, LLVMReadNoneAttribute);
+       store_ptr = LLVMBuildGEP(gallivm->builder, si_shader_ctx->lds,
+                                indices, 2, "");
+
+       temp = LLVMBuildAnd(gallivm->builder, indices[1],
+                           lp_build_const_int32(gallivm, TID_MASK_LEFT), "");
+
+       temp2 = LLVMBuildAnd(gallivm->builder, indices[1],
+                            lp_build_const_int32(gallivm, TID_MASK_TOP), "");
+
+       indices[1] = temp;
+       load_ptr_x = LLVMBuildGEP(gallivm->builder, si_shader_ctx->lds,
+                                 indices, 2, "");
+
+       indices[1] = temp2;
+       load_ptr_y = LLVMBuildGEP(gallivm->builder, si_shader_ctx->lds,
+                                 indices, 2, "");
+
+       indices[1] = LLVMBuildAdd(gallivm->builder, temp,
+                                 lp_build_const_int32(gallivm, 1), "");
+       load_ptr_ddx = LLVMBuildGEP(gallivm->builder, si_shader_ctx->lds,
+                                  indices, 2, "");
+
+       indices[1] = LLVMBuildAdd(gallivm->builder, temp2,
+                                 lp_build_const_int32(gallivm, 2), "");
+       load_ptr_ddy = LLVMBuildGEP(gallivm->builder, si_shader_ctx->lds,
+                                  indices, 2, "");
+
+       for (c = 0; c < 2; ++c) {
+               LLVMValueRef store_val;
+               LLVMValueRef c_ll = lp_build_const_int32(gallivm, c);
+
+               store_val = LLVMBuildExtractElement(gallivm->builder,
+                                                   interp_ij, c_ll, "");
+               LLVMBuildStore(gallivm->builder,
+                              store_val,
+                              store_ptr);
+
+               tl = LLVMBuildLoad(gallivm->builder, load_ptr_x, "");
+               tl = LLVMBuildBitCast(gallivm->builder, tl, base->elem_type, "");
+
+               tr = LLVMBuildLoad(gallivm->builder, load_ptr_ddx, "");
+               tr = LLVMBuildBitCast(gallivm->builder, tr, base->elem_type, "");
+
+               result[c] = LLVMBuildFSub(gallivm->builder, tr, tl, "");
+
+               tl = LLVMBuildLoad(gallivm->builder, load_ptr_y, "");
+               tl = LLVMBuildBitCast(gallivm->builder, tl, base->elem_type, "");
+
+               bl = LLVMBuildLoad(gallivm->builder, load_ptr_ddy, "");
+               bl = LLVMBuildBitCast(gallivm->builder, bl, base->elem_type, "");
+
+               result[c + 2] = LLVMBuildFSub(gallivm->builder, bl, tl, "");
+       }
+
+       return lp_build_gather_values(gallivm, result, 4);
+}
+
+static void interp_fetch_args(
+       struct lp_build_tgsi_context *bld_base,
+       struct lp_build_emit_data *emit_data)
+{
+       struct si_shader_context *si_shader_ctx = si_shader_context(bld_base);
+       struct gallivm_state *gallivm = bld_base->base.gallivm;
+       const struct tgsi_full_instruction *inst = emit_data->inst;
+
+       if (inst->Instruction.Opcode == TGSI_OPCODE_INTERP_OFFSET) {
+               /* offset is in second src, first two channels */
+               emit_data->args[0] = lp_build_emit_fetch(bld_base,
+                                                        emit_data->inst, 1,
+                                                        0);
+               emit_data->args[1] = lp_build_emit_fetch(bld_base,
+                                                        emit_data->inst, 1,
+                                                        1);
+               emit_data->arg_count = 2;
+       } else if (inst->Instruction.Opcode == TGSI_OPCODE_INTERP_SAMPLE) {
+               LLVMValueRef sample_position;
+               LLVMValueRef sample_id;
+               LLVMValueRef halfval = lp_build_const_float(gallivm, 0.5f);
+
+               /* fetch sample ID, then fetch its sample position,
+                * and place into first two channels.
+                */
+               sample_id = lp_build_emit_fetch(bld_base,
+                                               emit_data->inst, 1, 0);
+               sample_id = LLVMBuildBitCast(gallivm->builder, sample_id,
+                                            LLVMInt32TypeInContext(gallivm->context),
+                                            "");
+               sample_position = load_sample_position(&si_shader_ctx->radeon_bld, sample_id);
+
+               emit_data->args[0] = LLVMBuildExtractElement(gallivm->builder,
+                                                            sample_position,
+                                                            lp_build_const_int32(gallivm, 0), "");
+
+               emit_data->args[0] = LLVMBuildFSub(gallivm->builder, emit_data->args[0], halfval, "");
+               emit_data->args[1] = LLVMBuildExtractElement(gallivm->builder,
+                                                            sample_position,
+                                                            lp_build_const_int32(gallivm, 1), "");
+               emit_data->args[1] = LLVMBuildFSub(gallivm->builder, emit_data->args[1], halfval, "");
+               emit_data->arg_count = 2;
+       }
+}
+
+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)
+{
+       struct si_shader_context *si_shader_ctx = si_shader_context(bld_base);
+       struct si_shader *shader = si_shader_ctx->shader;
+       struct gallivm_state *gallivm = bld_base->base.gallivm;
+       LLVMValueRef interp_param;
+       const struct tgsi_full_instruction *inst = emit_data->inst;
+       const char *intr_name;
+       int input_index;
+       int chan;
+       int i;
+       LLVMValueRef attr_number;
+       LLVMTypeRef input_type = LLVMFloatTypeInContext(gallivm->context);
+       LLVMValueRef params = LLVMGetParam(si_shader_ctx->radeon_bld.main_fn, SI_PARAM_PRIM_MASK);
+       int interp_param_idx;
+       unsigned location;
+
+       assert(inst->Src[0].Register.File == TGSI_FILE_INPUT);
+       input_index = inst->Src[0].Register.Index;
+
+       if (inst->Instruction.Opcode == TGSI_OPCODE_INTERP_OFFSET ||
+           inst->Instruction.Opcode == TGSI_OPCODE_INTERP_SAMPLE)
+               location = TGSI_INTERPOLATE_LOC_CENTER;
+       else
+               location = TGSI_INTERPOLATE_LOC_CENTROID;
+
+       interp_param_idx = lookup_interp_param_index(shader->ps_input_interpolate[input_index],
+                                                    location);
+       if (interp_param_idx == -1)
+               return;
+       else if (interp_param_idx)
+               interp_param = LLVMGetParam(si_shader_ctx->radeon_bld.main_fn, interp_param_idx);
+       else
+               interp_param = NULL;
+
+       attr_number = lp_build_const_int32(gallivm,
+                                          shader->ps_input_param_offset[input_index]);
+
+       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);
+
+               /*
+                * take the I then J parameters, and the DDX/Y for it, and
+                * calculate the IJ inputs for the interpolator.
+                * temp1 = ddx * offset/sample.x + I;
+                * interp_param.I = ddy * offset/sample.y + temp1;
+                * temp1 = ddx * offset/sample.x + J;
+                * interp_param.J = ddy * offset/sample.y + temp1;
+                */
+               for (i = 0; i < 2; i++) {
+                       LLVMValueRef ix_ll = lp_build_const_int32(gallivm, i);
+                       LLVMValueRef iy_ll = lp_build_const_int32(gallivm, i + 2);
+                       LLVMValueRef ddx_el = LLVMBuildExtractElement(gallivm->builder,
+                                                                     ddxy_out, ix_ll, "");
+                       LLVMValueRef ddy_el = LLVMBuildExtractElement(gallivm->builder,
+                                                                     ddxy_out, iy_ll, "");
+                       LLVMValueRef interp_el = LLVMBuildExtractElement(gallivm->builder,
+                                                                        interp_param, ix_ll, "");
+                       LLVMValueRef temp1, temp2;
+
+                       interp_el = LLVMBuildBitCast(gallivm->builder, interp_el,
+                                                    LLVMFloatTypeInContext(gallivm->context), "");
+
+                       temp1 = LLVMBuildFMul(gallivm->builder, ddx_el, emit_data->args[0], "");
+
+                       temp1 = LLVMBuildFAdd(gallivm->builder, temp1, interp_el, "");
+
+                       temp2 = LLVMBuildFMul(gallivm->builder, ddy_el, emit_data->args[1], "");
+
+                       temp2 = LLVMBuildFAdd(gallivm->builder, temp2, temp1, "");
+
+                       ij_out[i] = LLVMBuildBitCast(gallivm->builder,
+                                                    temp2,
+                                                    LLVMIntTypeInContext(gallivm->context, 32), "");
+               }
+               interp_param = lp_build_gather_values(bld_base->base.gallivm, ij_out, 2);
+       }
+
+       intr_name = interp_param ? "llvm.SI.fs.interp" : "llvm.SI.fs.constant";
+       for (chan = 0; chan < 2; chan++) {
+               LLVMValueRef args[4];
+               LLVMValueRef llvm_chan;
+               unsigned schan;
+
+               schan = tgsi_util_get_full_src_register_swizzle(&inst->Src[0], chan);
+               llvm_chan = lp_build_const_int32(gallivm, schan);
+
+               args[0] = llvm_chan;
+               args[1] = attr_number;
+               args[2] = params;
+               args[3] = interp_param;
+
+               emit_data->output[chan] =
+                       lp_build_intrinsic(gallivm->builder, intr_name,
+                                          input_type, args, args[3] ? 4 : 3,
+                                          LLVMReadNoneAttribute | LLVMNoUnwindAttribute);
+       }
+}
+
+static unsigned si_llvm_get_stream(struct lp_build_tgsi_context *bld_base,
+                                      struct lp_build_emit_data *emit_data)
+{
+       LLVMValueRef (*imms)[4] = lp_soa_context(bld_base)->immediates;
+       struct tgsi_src_register src0 = emit_data->inst->Src[0].Register;
+       unsigned stream;
+
+       assert(src0.File == TGSI_FILE_IMMEDIATE);
+
+       stream = LLVMConstIntGetZExtValue(imms[src0.Index][src0.SwizzleX]) & 0x3;
+       return stream;
+}
+
 /* Emit one vertex from the geometry shader */
 static void si_llvm_emit_vertex(
        const struct lp_build_tgsi_action *action,
@@ -2928,9 +3233,14 @@ static void si_llvm_emit_vertex(
        LLVMValueRef args[2];
        unsigned chan;
        int i;
+       unsigned stream;
+
+       stream = si_llvm_get_stream(bld_base, emit_data);
 
        /* Write vertex attribute values to GSVS ring */
-       gs_next_vertex = LLVMBuildLoad(gallivm->builder, si_shader_ctx->gs_next_vertex, "");
+       gs_next_vertex = LLVMBuildLoad(gallivm->builder,
+                                      si_shader_ctx->gs_next_vertex[stream],
+                                      "");
 
        /* If this thread has already emitted the declared maximum number of
         * vertices, kill it: excessive vertex emissions are not supposed to
@@ -2943,8 +3253,9 @@ static void si_llvm_emit_vertex(
        kill = lp_build_select(&bld_base->base, can_emit,
                               lp_build_const_float(gallivm, 1.0f),
                               lp_build_const_float(gallivm, -1.0f));
-       build_intrinsic(gallivm->builder, "llvm.AMDGPU.kill",
-                       LLVMVoidTypeInContext(gallivm->context), &kill, 1, 0);
+
+       lp_build_intrinsic(gallivm->builder, "llvm.AMDGPU.kill",
+                          LLVMVoidTypeInContext(gallivm->context), &kill, 1, 0);
 
        for (i = 0; i < info->num_outputs; i++) {
                LLVMValueRef *out_ptr =
@@ -2962,7 +3273,7 @@ static void si_llvm_emit_vertex(
                        out_val = LLVMBuildBitCast(gallivm->builder, out_val, i32, "");
 
                        build_tbuffer_store(si_shader_ctx,
-                                           si_shader_ctx->gsvs_ring,
+                                           si_shader_ctx->gsvs_ring[stream],
                                            out_val, 1,
                                            voffset, soffset, 0,
                                            V_008F0C_BUF_DATA_FORMAT_32,
@@ -2972,12 +3283,13 @@ static void si_llvm_emit_vertex(
        }
        gs_next_vertex = lp_build_add(uint, gs_next_vertex,
                                      lp_build_const_int32(gallivm, 1));
-       LLVMBuildStore(gallivm->builder, gs_next_vertex, si_shader_ctx->gs_next_vertex);
+
+       LLVMBuildStore(gallivm->builder, gs_next_vertex, si_shader_ctx->gs_next_vertex[stream]);
 
        /* Signal vertex emission */
-       args[0] = lp_build_const_int32(gallivm, SENDMSG_GS_OP_EMIT | SENDMSG_GS);
+       args[0] = lp_build_const_int32(gallivm, SENDMSG_GS_OP_EMIT | SENDMSG_GS | (stream << 8));
        args[1] = LLVMGetParam(si_shader_ctx->radeon_bld.main_fn, SI_PARAM_GS_WAVE_ID);
-       build_intrinsic(gallivm->builder, "llvm.SI.sendmsg",
+       lp_build_intrinsic(gallivm->builder, "llvm.SI.sendmsg",
                        LLVMVoidTypeInContext(gallivm->context), args, 2,
                        LLVMNoUnwindAttribute);
 }
@@ -2991,11 +3303,13 @@ static void si_llvm_emit_primitive(
        struct si_shader_context *si_shader_ctx = si_shader_context(bld_base);
        struct gallivm_state *gallivm = bld_base->base.gallivm;
        LLVMValueRef args[2];
+       unsigned stream;
 
        /* Signal primitive cut */
-       args[0] = lp_build_const_int32(gallivm, SENDMSG_GS_OP_CUT | SENDMSG_GS);
+       stream = si_llvm_get_stream(bld_base, emit_data);
+       args[0] = lp_build_const_int32(gallivm, SENDMSG_GS_OP_CUT | SENDMSG_GS | (stream << 8));
        args[1] = LLVMGetParam(si_shader_ctx->radeon_bld.main_fn, SI_PARAM_GS_WAVE_ID);
-       build_intrinsic(gallivm->builder, "llvm.SI.sendmsg",
+       lp_build_intrinsic(gallivm->builder, "llvm.SI.sendmsg",
                        LLVMVoidTypeInContext(gallivm->context), args, 2,
                        LLVMNoUnwindAttribute);
 }
@@ -3006,7 +3320,7 @@ static void si_llvm_emit_barrier(const struct lp_build_tgsi_action *action,
 {
        struct gallivm_state *gallivm = bld_base->base.gallivm;
 
-       build_intrinsic(gallivm->builder, "llvm.AMDGPU.barrier.local",
+       lp_build_intrinsic(gallivm->builder, "llvm.AMDGPU.barrier.local",
                        LLVMVoidTypeInContext(gallivm->context), NULL, 0,
                        LLVMNoUnwindAttribute);
 }
@@ -3022,6 +3336,11 @@ static const struct lp_build_tgsi_action txq_action = {
        .intr_name = "llvm.SI.resinfo"
 };
 
+static const struct lp_build_tgsi_action interp_action = {
+       .fetch_args = interp_fetch_args,
+       .emit = build_interp_intrinsic,
+};
+
 static void create_meta_data(struct si_shader_context *si_shader_ctx)
 {
        struct gallivm_state *gallivm = si_shader_ctx->radeon_bld.soa.bld_base.base.gallivm;
@@ -3216,7 +3535,11 @@ static void create_function(struct si_shader_context *si_shader_ctx)
 
        if (bld_base->info &&
            (bld_base->info->opcode_count[TGSI_OPCODE_DDX] > 0 ||
-            bld_base->info->opcode_count[TGSI_OPCODE_DDY] > 0))
+            bld_base->info->opcode_count[TGSI_OPCODE_DDY] > 0 ||
+            bld_base->info->opcode_count[TGSI_OPCODE_DDX_FINE] > 0 ||
+            bld_base->info->opcode_count[TGSI_OPCODE_DDY_FINE] > 0 ||
+            bld_base->info->opcode_count[TGSI_OPCODE_INTERP_OFFSET] > 0 ||
+            bld_base->info->opcode_count[TGSI_OPCODE_INTERP_SAMPLE] > 0))
                si_shader_ctx->lds =
                        LLVMAddGlobalInAddressSpace(gallivm->module,
                                                    LLVMArrayType(i32, 64),
@@ -3363,13 +3686,21 @@ static void preload_ring_buffers(struct si_shader_context *si_shader_ctx)
                        build_indexed_load_const(si_shader_ctx, buf_ptr, offset);
        }
 
-       if (si_shader_ctx->type == TGSI_PROCESSOR_GEOMETRY ||
-           si_shader_ctx->shader->is_gs_copy_shader) {
+       if (si_shader_ctx->shader->is_gs_copy_shader) {
                LLVMValueRef offset = lp_build_const_int32(gallivm, SI_RING_GSVS);
 
-               si_shader_ctx->gsvs_ring =
+               si_shader_ctx->gsvs_ring[0] =
                        build_indexed_load_const(si_shader_ctx, buf_ptr, offset);
        }
+       if (si_shader_ctx->type == TGSI_PROCESSOR_GEOMETRY) {
+               int i;
+               for (i = 0; i < 4; i++) {
+                       LLVMValueRef offset = lp_build_const_int32(gallivm, SI_RING_GSVS + i);
+
+                       si_shader_ctx->gsvs_ring[i] =
+                               build_indexed_load_const(si_shader_ctx, buf_ptr, offset);
+               }
+       }
 }
 
 void si_shader_binary_read_config(const struct si_screen *sscreen,
@@ -3480,7 +3811,10 @@ int si_shader_binary_read(struct si_screen *sscreen, struct si_shader *shader)
        si_shader_binary_upload(sscreen, shader);
 
        if (dump) {
-               if (!binary->disassembled) {
+               if (binary->disasm_string) {
+                       fprintf(stderr, "\nShader Disassembly:\n\n");
+                       fprintf(stderr, "%s\n", binary->disasm_string);
+               } else {
                        fprintf(stderr, "SI CODE:\n");
                        for (i = 0; i < binary->code_size; i+=4 ) {
                                fprintf(stderr, "@0x%x: %02x%02x%02x%02x\n", i, binary->code[i + 3],
@@ -3518,7 +3852,8 @@ int si_compile_llvm(struct si_screen *sscreen, struct si_shader *shader,
        if (shader->scratch_bytes_per_wave == 0) {
                FREE(shader->binary.code);
                FREE(shader->binary.relocs);
-               memset(&shader->binary, 0, sizeof(shader->binary));
+               memset(&shader->binary, 0,
+                      offsetof(struct radeon_shader_binary, disasm_string));
        }
        return r;
 }
@@ -3550,7 +3885,7 @@ static int si_generate_gs_copy_shader(struct si_screen *sscreen,
        preload_streamout_buffers(si_shader_ctx);
        preload_ring_buffers(si_shader_ctx);
 
-       args[0] = si_shader_ctx->gsvs_ring;
+       args[0] = si_shader_ctx->gsvs_ring[0];
        args[1] = lp_build_mul_imm(uint,
                                   LLVMGetParam(si_shader_ctx->radeon_bld.main_fn,
                                                si_shader_ctx->param_vertex_id),
@@ -3576,7 +3911,7 @@ static int si_generate_gs_copy_shader(struct si_screen *sscreen,
 
                        outputs[i].values[chan] =
                                LLVMBuildBitCast(gallivm->builder,
-                                                build_intrinsic(gallivm->builder,
+                                                lp_build_intrinsic(gallivm->builder,
                                                                 "llvm.SI.buffer.load.dword.i32.i32",
                                                                 LLVMInt32TypeInContext(gallivm->context),
                                                                 args, 9,
@@ -3694,6 +4029,10 @@ int si_shader_create(struct si_screen *sscreen, LLVMTargetMachineRef tm,
        bld_base->info = poly_stipple ? &stipple_shader_info : &sel->info;
        bld_base->emit_fetch_funcs[TGSI_FILE_CONSTANT] = fetch_constant;
 
+       bld_base->op_actions[TGSI_OPCODE_INTERP_CENTROID] = interp_action;
+       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_TEX2] = tex_action;
        bld_base->op_actions[TGSI_OPCODE_TXB] = tex_action;
@@ -3709,6 +4048,8 @@ int si_shader_create(struct si_screen *sscreen, LLVMTargetMachineRef tm,
 
        bld_base->op_actions[TGSI_OPCODE_DDX].emit = si_llvm_emit_ddxy;
        bld_base->op_actions[TGSI_OPCODE_DDY].emit = si_llvm_emit_ddxy;
+       bld_base->op_actions[TGSI_OPCODE_DDX_FINE].emit = si_llvm_emit_ddxy;
+       bld_base->op_actions[TGSI_OPCODE_DDY_FINE].emit = si_llvm_emit_ddxy;
 
        bld_base->op_actions[TGSI_OPCODE_EMIT].emit = si_llvm_emit_vertex;
        bld_base->op_actions[TGSI_OPCODE_ENDPRIM].emit = si_llvm_emit_primitive;
@@ -3782,9 +4123,12 @@ int si_shader_create(struct si_screen *sscreen, LLVMTargetMachineRef tm,
        preload_ring_buffers(&si_shader_ctx);
 
        if (si_shader_ctx.type == TGSI_PROCESSOR_GEOMETRY) {
-               si_shader_ctx.gs_next_vertex =
-                       lp_build_alloca(bld_base->base.gallivm,
-                                       bld_base->uint_bld.elem_type, "");
+               int i;
+               for (i = 0; i < 4; i++) {
+                       si_shader_ctx.gs_next_vertex[i] =
+                               lp_build_alloca(bld_base->base.gallivm,
+                                               bld_base->uint_bld.elem_type, "");
+               }
        }
 
        if (!lp_build_tgsi_llvm(bld_base, tokens)) {
@@ -3836,4 +4180,5 @@ void si_shader_destroy(struct pipe_context *ctx, struct si_shader *shader)
 
        FREE(shader->binary.code);
        FREE(shader->binary.relocs);
+       FREE(shader->binary.disasm_string);
 }