ac/llvm: add support for texturing with clamped LOD
[mesa.git] / src / amd / llvm / ac_llvm_build.c
index a66272873f00da297223674bb54ab63fca35c4d8..ebcb91bd4b3374c02d1bb60e19773d15c4822cdd 100644 (file)
@@ -65,8 +65,6 @@ ac_llvm_context_init(struct ac_llvm_context *ctx,
                     enum ac_float_mode float_mode, unsigned wave_size,
                     unsigned ballot_mask_bits)
 {
-       LLVMValueRef args[1];
-
        ctx->context = LLVMContextCreate();
 
        ctx->chip_class = chip_class;
@@ -85,6 +83,7 @@ ac_llvm_context_init(struct ac_llvm_context *ctx,
        ctx->i16 = LLVMIntTypeInContext(ctx->context, 16);
        ctx->i32 = LLVMIntTypeInContext(ctx->context, 32);
        ctx->i64 = LLVMIntTypeInContext(ctx->context, 64);
+       ctx->i128 = LLVMIntTypeInContext(ctx->context, 128);
        ctx->intptr = ctx->i32;
        ctx->f16 = LLVMHalfTypeInContext(ctx->context);
        ctx->f32 = LLVMFloatTypeInContext(ctx->context);
@@ -108,6 +107,8 @@ ac_llvm_context_init(struct ac_llvm_context *ctx,
        ctx->i32_1 = LLVMConstInt(ctx->i32, 1, false);
        ctx->i64_0 = LLVMConstInt(ctx->i64, 0, false);
        ctx->i64_1 = LLVMConstInt(ctx->i64, 1, false);
+       ctx->i128_0 = LLVMConstInt(ctx->i128, 0, false);
+       ctx->i128_1 = LLVMConstInt(ctx->i128, 1, false);
        ctx->f16_0 = LLVMConstReal(ctx->f16, 0.0);
        ctx->f16_1 = LLVMConstReal(ctx->f16, 1.0);
        ctx->f32_0 = LLVMConstReal(ctx->f32, 0.0);
@@ -124,11 +125,6 @@ ac_llvm_context_init(struct ac_llvm_context *ctx,
        ctx->invariant_load_md_kind = LLVMGetMDKindIDInContext(ctx->context,
                                                               "invariant.load", 14);
 
-       ctx->fpmath_md_kind = LLVMGetMDKindIDInContext(ctx->context, "fpmath", 6);
-
-       args[0] = LLVMConstReal(ctx->f32, 2.5);
-       ctx->fpmath_md_2p5_ulp = LLVMMDNodeInContext(ctx->context, args, 1);
-
        ctx->uniform_md_kind = LLVMGetMDKindIDInContext(ctx->context,
                                                        "amdgpu.uniform", 14);
 
@@ -148,7 +144,7 @@ int
 ac_get_llvm_num_components(LLVMValueRef value)
 {
        LLVMTypeRef type = LLVMTypeOf(value);
-       unsigned num_components = LLVMGetTypeKind(type) == LLVMVectorTypeKind
+       unsigned num_components = LLVMGetTypeKind(type) == LLVMFixedVectorTypeKind
                                      ? LLVMGetVectorSize(type)
                                      : 1;
        return num_components;
@@ -159,7 +155,7 @@ ac_llvm_extract_elem(struct ac_llvm_context *ac,
                     LLVMValueRef value,
                     int index)
 {
-       if (LLVMGetTypeKind(LLVMTypeOf(value)) != LLVMVectorTypeKind) {
+       if (LLVMGetTypeKind(LLVMTypeOf(value)) != LLVMFixedVectorTypeKind) {
                assert(index == 0);
                return value;
        }
@@ -171,7 +167,7 @@ ac_llvm_extract_elem(struct ac_llvm_context *ac,
 int
 ac_get_elem_bits(struct ac_llvm_context *ctx, LLVMTypeRef type)
 {
-       if (LLVMGetTypeKind(type) == LLVMVectorTypeKind)
+       if (LLVMGetTypeKind(type) == LLVMFixedVectorTypeKind)
                type = LLVMGetElementType(type);
 
        if (LLVMGetTypeKind(type) == LLVMIntegerTypeKind)
@@ -210,7 +206,7 @@ ac_get_type_size(LLVMTypeRef type)
                if (LLVMGetPointerAddressSpace(type) == AC_ADDR_SPACE_CONST_32BIT)
                        return 4;
                return 8;
-       case LLVMVectorTypeKind:
+       case LLVMFixedVectorTypeKind:
                return LLVMGetVectorSize(type) *
                       ac_get_type_size(LLVMGetElementType(type));
        case LLVMArrayTypeKind:
@@ -239,7 +235,7 @@ static LLVMTypeRef to_integer_type_scalar(struct ac_llvm_context *ctx, LLVMTypeR
 LLVMTypeRef
 ac_to_integer_type(struct ac_llvm_context *ctx, LLVMTypeRef t)
 {
-       if (LLVMGetTypeKind(t) == LLVMVectorTypeKind) {
+       if (LLVMGetTypeKind(t) == LLVMFixedVectorTypeKind) {
                LLVMTypeRef elem_type = LLVMGetElementType(t);
                return LLVMVectorType(to_integer_type_scalar(ctx, elem_type),
                                      LLVMGetVectorSize(t));
@@ -294,7 +290,7 @@ static LLVMTypeRef to_float_type_scalar(struct ac_llvm_context *ctx, LLVMTypeRef
 LLVMTypeRef
 ac_to_float_type(struct ac_llvm_context *ctx, LLVMTypeRef t)
 {
-       if (LLVMGetTypeKind(t) == LLVMVectorTypeKind) {
+       if (LLVMGetTypeKind(t) == LLVMFixedVectorTypeKind) {
                LLVMTypeRef elem_type = LLVMGetElementType(t);
                return LLVMVectorType(to_float_type_scalar(ctx, elem_type),
                                      LLVMGetVectorSize(t));
@@ -356,7 +352,7 @@ void ac_build_type_name_for_intr(LLVMTypeRef type, char *buf, unsigned bufsize)
 
        assert(bufsize >= 8);
 
-       if (LLVMGetTypeKind(type) == LLVMVectorTypeKind) {
+       if (LLVMGetTypeKind(type) == LLVMFixedVectorTypeKind) {
                int ret = snprintf(buf, bufsize, "v%u",
                                        LLVMGetVectorSize(type));
                if (ret < 0) {
@@ -631,7 +627,7 @@ ac_build_expand(struct ac_llvm_context *ctx,
        LLVMTypeRef elemtype;
        LLVMValueRef chan[dst_channels];
 
-       if (LLVMGetTypeKind(LLVMTypeOf(value)) == LLVMVectorTypeKind) {
+       if (LLVMGetTypeKind(LLVMTypeOf(value)) == LLVMFixedVectorTypeKind) {
                unsigned vec_size = LLVMGetVectorSize(LLVMTypeOf(value));
 
                if (src_channels == dst_channels && vec_size == dst_channels)
@@ -704,20 +700,20 @@ ac_build_fdiv(struct ac_llvm_context *ctx,
              LLVMValueRef num,
              LLVMValueRef den)
 {
-       /* If we do (num / den), LLVM >= 7.0 does:
-        *    return num * v_rcp_f32(den * (fabs(den) > 0x1.0p+96f ? 0x1.0p-32f : 1.0f));
-        *
-        * If we do (num * (1 / den)), LLVM does:
-        *    return num * v_rcp_f32(den);
-        */
-       LLVMValueRef one = LLVMConstReal(LLVMTypeOf(num), 1.0);
-       LLVMValueRef rcp = LLVMBuildFDiv(ctx->builder, one, den, "");
-       LLVMValueRef ret = LLVMBuildFMul(ctx->builder, num, rcp, "");
+       unsigned type_size = ac_get_type_size(LLVMTypeOf(den));
+       const char *name;
 
-       /* Use v_rcp_f32 instead of precise division. */
-       if (!LLVMIsConstant(ret))
-               LLVMSetMetadata(ret, ctx->fpmath_md_kind, ctx->fpmath_md_2p5_ulp);
-       return ret;
+       if (type_size == 2)
+               name = "llvm.amdgcn.rcp.f16";
+       else if (type_size == 4)
+               name = "llvm.amdgcn.rcp.f32";
+       else
+               name = "llvm.amdgcn.rcp.f64";
+
+        LLVMValueRef rcp = ac_build_intrinsic(ctx, name, LLVMTypeOf(den),
+                                              &den, 1, AC_FUNC_ATTR_READNONE);
+
+       return LLVMBuildFMul(ctx->builder, num, rcp, "");
 }
 
 /* See fast_idiv_by_const.h. */
@@ -2377,6 +2373,9 @@ LLVMValueRef ac_build_image_opcode(struct ac_llvm_context *ctx,
               (a->lod ? 1 : 0) +
               (a->level_zero ? 1 : 0) +
               (a->derivs[0] ? 1 : 0) <= 1);
+       assert((a->min_lod ? 1 : 0) +
+              (a->lod ? 1 : 0) +
+              (a->level_zero ? 1 : 0) <= 1);
 
        if (a->opcode == ac_image_get_lod) {
                switch (dim) {
@@ -2432,6 +2431,9 @@ LLVMValueRef ac_build_image_opcode(struct ac_llvm_context *ctx,
                args[num_args++] = LLVMBuildBitCast(ctx->builder, a->coords[i], coord_type, "");
        if (a->lod)
                args[num_args++] = LLVMBuildBitCast(ctx->builder, a->lod, coord_type, "");
+       if (a->min_lod)
+               args[num_args++] = LLVMBuildBitCast(ctx->builder, a->min_lod, coord_type, "");
+
        overload[num_overloads++] = sample ? ".f32" : ".i32";
 
        args[num_args++] = a->resource;
@@ -2485,7 +2487,7 @@ LLVMValueRef ac_build_image_opcode(struct ac_llvm_context *ctx,
        char intr_name[96];
        snprintf(intr_name, sizeof(intr_name),
                 "llvm.amdgcn.image.%s%s" /* base name */
-                "%s%s%s" /* sample/gather modifiers */
+                "%s%s%s%s" /* sample/gather modifiers */
                 ".%s.%s%s%s%s", /* dimension and type overloads */
                 name, atomic_subop,
                 a->compare ? ".c" : "",
@@ -2493,6 +2495,7 @@ LLVMValueRef ac_build_image_opcode(struct ac_llvm_context *ctx,
                 lod_suffix ? ".l" :
                 a->derivs[0] ? ".d" :
                 a->level_zero ? ".lz" : "",
+                a->min_lod ? ".cl" : "",
                 a->offset ? ".o" : "",
                 dimname,
                 atomic ? "i32" : "v4f32",
@@ -2720,27 +2723,48 @@ LLVMValueRef ac_build_fmed3(struct ac_llvm_context *ctx, LLVMValueRef src0,
                            LLVMValueRef src1, LLVMValueRef src2,
                            unsigned bitsize)
 {
-       LLVMTypeRef type;
-       char *intr;
+       LLVMValueRef result;
 
-       if (bitsize == 16) {
-               intr = "llvm.amdgcn.fmed3.f16";
-               type = ctx->f16;
-       } else if (bitsize == 32) {
-               intr = "llvm.amdgcn.fmed3.f32";
-               type = ctx->f32;
+       if (bitsize == 64 || (bitsize == 16 && ctx->chip_class <= GFX8)) {
+               /* Lower 64-bit fmed because LLVM doesn't expose an intrinsic,
+                * or lower 16-bit fmed because it's only supported on GFX9+.
+                */
+               LLVMValueRef min1, min2, max1;
+
+               min1 = ac_build_fmin(ctx, src0, src1);
+               max1 = ac_build_fmax(ctx, src0, src1);
+               min2 = ac_build_fmin(ctx, max1, src2);
+
+               result = ac_build_fmax(ctx, min2, min1);
        } else {
-               intr = "llvm.amdgcn.fmed3.f64";
-               type = ctx->f64;
+               LLVMTypeRef type;
+               char *intr;
+
+               if (bitsize == 16) {
+                       intr = "llvm.amdgcn.fmed3.f16";
+                       type = ctx->f16;
+               } else {
+                       assert(bitsize == 32);
+                       intr = "llvm.amdgcn.fmed3.f32";
+                       type = ctx->f32;
+               }
+
+               LLVMValueRef params[] = {
+                       src0,
+                       src1,
+                       src2,
+               };
+
+               result = ac_build_intrinsic(ctx, intr, type, params, 3,
+                                           AC_FUNC_ATTR_READNONE);
        }
 
-       LLVMValueRef params[] = {
-               src0,
-               src1,
-               src2,
-       };
-       return ac_build_intrinsic(ctx, intr, type, params, 3,
-                                 AC_FUNC_ATTR_READNONE);
+       if (ctx->chip_class < GFX9 && bitsize == 32) {
+               /* Only pre-GFX9 chips do not flush denorms. */
+               result = ac_build_canonicalize(ctx, result, bitsize);
+       }
+
+       return result;
 }
 
 LLVMValueRef ac_build_fract(struct ac_llvm_context *ctx, LLVMValueRef src0,
@@ -2817,6 +2841,12 @@ LLVMValueRef ac_build_bit_count(struct ac_llvm_context *ctx, LLVMValueRef src0)
        bitsize = ac_get_elem_bits(ctx, LLVMTypeOf(src0));
 
        switch (bitsize) {
+       case 128:
+               result = ac_build_intrinsic(ctx, "llvm.ctpop.i128", ctx->i128,
+                                           (LLVMValueRef []) { src0 }, 1,
+                                           AC_FUNC_ATTR_READNONE);
+               result = LLVMBuildTrunc(ctx->builder, result, ctx->i32, "");
+               break;
        case 64:
                result = ac_build_intrinsic(ctx, "llvm.ctpop.i64", ctx->i64,
                                            (LLVMValueRef []) { src0 }, 1,
@@ -3058,6 +3088,7 @@ void ac_optimize_vs_outputs(struct ac_llvm_context *ctx,
                            LLVMValueRef main_fn,
                            uint8_t *vs_output_param_offset,
                            uint32_t num_outputs,
+                           uint32_t skip_output_mask,
                            uint8_t *num_param_exports)
 {
        LLVMBasicBlockRef bb;
@@ -3124,12 +3155,13 @@ void ac_optimize_vs_outputs(struct ac_llvm_context *ctx,
                        }
 
                        /* Eliminate constant and duplicated PARAM exports. */
-                       if (ac_eliminate_const_output(vs_output_param_offset,
-                                                     num_outputs, &exp) ||
-                           ac_eliminate_duplicated_output(ctx,
-                                                          vs_output_param_offset,
-                                                          num_outputs, &exports,
-                                                          &exp)) {
+                       if (!((1u << target) & skip_output_mask) &&
+                            (ac_eliminate_const_output(vs_output_param_offset,
+                                                      num_outputs, &exp) ||
+                            ac_eliminate_duplicated_output(ctx,
+                                                           vs_output_param_offset,
+                                                           num_outputs, &exports,
+                                                           &exp))) {
                                removed_any = true;
                        } else {
                                exports.exp[exports.num++] = exp;
@@ -3581,12 +3613,14 @@ void ac_apply_fmask_to_sample(struct ac_llvm_context *ac, LLVMValueRef fmask,
 }
 
 static LLVMValueRef
-_ac_build_readlane(struct ac_llvm_context *ctx, LLVMValueRef src, LLVMValueRef lane)
+_ac_build_readlane(struct ac_llvm_context *ctx, LLVMValueRef src,
+                 LLVMValueRef lane, bool with_opt_barrier)
 {
        LLVMTypeRef type = LLVMTypeOf(src);
        LLVMValueRef result;
 
-       ac_build_optimization_barrier(ctx, &src);
+       if (with_opt_barrier)
+               ac_build_optimization_barrier(ctx, &src);
 
        src = LLVMBuildZExt(ctx->builder, src, ctx->i32, "");
        if (lane)
@@ -3602,15 +3636,10 @@ _ac_build_readlane(struct ac_llvm_context *ctx, LLVMValueRef src, LLVMValueRef l
        return LLVMBuildTrunc(ctx->builder, result, type, "");
 }
 
-/**
- * Builds the "llvm.amdgcn.readlane" or "llvm.amdgcn.readfirstlane" intrinsic.
- * @param ctx
- * @param src
- * @param lane - id of the lane or NULL for the first active lane
- * @return value of the lane
- */
-LLVMValueRef
-ac_build_readlane(struct ac_llvm_context *ctx, LLVMValueRef src, LLVMValueRef lane)
+static LLVMValueRef
+ac_build_readlane_common(struct ac_llvm_context *ctx,
+                        LLVMValueRef src, LLVMValueRef lane,
+                        bool with_opt_barrier)
 {
        LLVMTypeRef src_type = LLVMTypeOf(src);
        src = ac_to_integer(ctx, src);
@@ -3624,14 +3653,19 @@ ac_build_readlane(struct ac_llvm_context *ctx, LLVMValueRef src, LLVMValueRef la
                        LLVMBuildBitCast(ctx->builder, src, vec_type, "");
                ret = LLVMGetUndef(vec_type);
                for (unsigned i = 0; i < bits / 32; i++) {
+                       LLVMValueRef ret_comp;
+
                        src = LLVMBuildExtractElement(ctx->builder, src_vector,
                                                LLVMConstInt(ctx->i32, i, 0), "");
-                       LLVMValueRef ret_comp = _ac_build_readlane(ctx, src, lane);
+
+                       ret_comp = _ac_build_readlane(ctx, src, lane,
+                                                     with_opt_barrier);
+
                        ret = LLVMBuildInsertElement(ctx->builder, ret, ret_comp,
                                                LLVMConstInt(ctx->i32, i, 0), "");
                }
        } else {
-               ret = _ac_build_readlane(ctx, src, lane);
+               ret = _ac_build_readlane(ctx, src, lane, with_opt_barrier);
        }
 
        if (LLVMGetTypeKind(src_type) == LLVMPointerTypeKind)
@@ -3639,6 +3673,30 @@ ac_build_readlane(struct ac_llvm_context *ctx, LLVMValueRef src, LLVMValueRef la
        return LLVMBuildBitCast(ctx->builder, ret, src_type, "");
 }
 
+/**
+ * Builds the "llvm.amdgcn.readlane" or "llvm.amdgcn.readfirstlane" intrinsic.
+ *
+ * The optimization barrier is not needed if the value is the same in all lanes
+ * or if this is called in the outermost block.
+ *
+ * @param ctx
+ * @param src
+ * @param lane - id of the lane or NULL for the first active lane
+ * @return value of the lane
+ */
+LLVMValueRef ac_build_readlane_no_opt_barrier(struct ac_llvm_context *ctx,
+                                             LLVMValueRef src, LLVMValueRef lane)
+{
+       return ac_build_readlane_common(ctx, src, lane, false);
+}
+
+
+LLVMValueRef
+ac_build_readlane(struct ac_llvm_context *ctx, LLVMValueRef src, LLVMValueRef lane)
+{
+       return ac_build_readlane_common(ctx, src, lane, true);
+}
+
 LLVMValueRef
 ac_build_writelane(struct ac_llvm_context *ctx, LLVMValueRef src, LLVMValueRef value, LLVMValueRef lane)
 {
@@ -4335,12 +4393,15 @@ ac_build_reduce(struct ac_llvm_context *ctx, LLVMValueRef src, nir_op op, unsign
        if (cluster_size == 32) return ac_build_wwm(ctx, result);
 
        if (ctx->chip_class >= GFX8) {
-               if (ctx->chip_class >= GFX10)
-                       swap = ac_build_readlane(ctx, result, LLVMConstInt(ctx->i32, 31, false));
-               else
-                       swap = ac_build_dpp(ctx, identity, result, dpp_row_bcast31, 0xc, 0xf, false);
-               result = ac_build_alu_op(ctx, result, swap, op);
-               result = ac_build_readlane(ctx, result, LLVMConstInt(ctx->i32, 63, 0));
+               if (ctx->wave_size == 64) {
+                       if (ctx->chip_class >= GFX10)
+                               swap = ac_build_readlane(ctx, result, LLVMConstInt(ctx->i32, 31, false));
+                       else
+                               swap = ac_build_dpp(ctx, identity, result, dpp_row_bcast31, 0xc, 0xf, false);
+                       result = ac_build_alu_op(ctx, result, swap, op);
+                       result = ac_build_readlane(ctx, result, LLVMConstInt(ctx->i32, 63, 0));
+               }
+
                return ac_build_wwm(ctx, result);
        } else {
                swap = ac_build_readlane(ctx, result, ctx->i32_0);
@@ -4651,6 +4712,24 @@ ac_build_load_helper_invocation(struct ac_llvm_context *ctx)
        return LLVMBuildSExt(ctx->builder, result, ctx->i32, "");
 }
 
+LLVMValueRef
+ac_build_is_helper_invocation(struct ac_llvm_context *ctx)
+{
+       if (!ctx->postponed_kill)
+               return ac_build_load_helper_invocation(ctx);
+
+       /* !(exact && postponed) */
+       LLVMValueRef exact = ac_build_intrinsic(ctx, "llvm.amdgcn.ps.live",
+                                               ctx->i1, NULL, 0,
+                                               AC_FUNC_ATTR_READNONE);
+
+       LLVMValueRef postponed = LLVMBuildLoad(ctx->builder, ctx->postponed_kill, "");
+       LLVMValueRef result = LLVMBuildAnd(ctx->builder, exact, postponed, "");
+
+       return LLVMBuildSelect(ctx->builder, result, ctx->i32_0,
+                              LLVMConstInt(ctx->i32, 0xFFFFFFFF, false), "");
+}
+
 LLVMValueRef ac_build_call(struct ac_llvm_context *ctx, LLVMValueRef func,
                           LLVMValueRef *args, unsigned num_args)
 {
@@ -4738,6 +4817,18 @@ void ac_build_sendmsg_gs_alloc_req(struct ac_llvm_context *ctx, LLVMValueRef wav
 {
        LLVMBuilderRef builder = ctx->builder;
        LLVMValueRef tmp;
+       bool export_dummy_prim = false;
+
+       /* HW workaround for a GPU hang with 100% culling.
+        * We always have to export at least 1 primitive.
+        * Export a degenerate triangle using vertex 0 for all 3 vertices.
+        */
+       if (prim_cnt == ctx->i32_0 && ctx->chip_class == GFX10) {
+               assert(vtx_cnt == ctx->i32_0);
+               prim_cnt = ctx->i32_1;
+               vtx_cnt = ctx->i32_1;
+               export_dummy_prim = true;
+       }
 
        ac_build_ifcc(ctx, LLVMBuildICmp(builder, LLVMIntEQ, wave_id, ctx->i32_0, ""), 5020);
 
@@ -4745,6 +4836,24 @@ void ac_build_sendmsg_gs_alloc_req(struct ac_llvm_context *ctx, LLVMValueRef wav
        tmp = LLVMBuildOr(builder, tmp, vtx_cnt, "");
        ac_build_sendmsg(ctx, AC_SENDMSG_GS_ALLOC_REQ, tmp);
 
+       if (export_dummy_prim) {
+               struct ac_ngg_prim prim = {};
+               /* The vertex indices are 0,0,0. */
+               prim.passthrough = ctx->i32_0;
+
+               struct ac_export_args pos = {};
+               pos.out[0] = pos.out[1] = pos.out[2] = pos.out[3] = ctx->f32_0;
+               pos.target = V_008DFC_SQ_EXP_POS;
+               pos.enabled_channels = 0xf;
+               pos.done = true;
+
+               ac_build_ifcc(ctx, LLVMBuildICmp(builder, LLVMIntEQ, ac_get_thread_id(ctx),
+                                                ctx->i32_0, ""), 5021);
+               ac_build_export_prim(ctx, &prim);
+               ac_build_export(ctx, &pos);
+               ac_build_endif(ctx, 5021);
+       }
+
        ac_build_endif(ctx, 5020);
 }
 
@@ -4877,6 +4986,115 @@ ac_build_main(const struct ac_shader_args *args,
        }
 
        ctx->main_function = main_function;
+
+       if (LLVM_VERSION_MAJOR >= 11) {
+               /* Enable denormals for FP16 and FP64: */
+               LLVMAddTargetDependentFunctionAttr(main_function, "denormal-fp-math",
+                                                  "ieee,ieee");
+               /* Disable denormals for FP32: */
+               LLVMAddTargetDependentFunctionAttr(main_function, "denormal-fp-math-f32",
+                                                  "preserve-sign,preserve-sign");
+       }
        return main_function;
 }
 
+void ac_build_s_endpgm(struct ac_llvm_context *ctx)
+{
+       LLVMTypeRef calltype = LLVMFunctionType(ctx->voidt, NULL, 0, false);
+       LLVMValueRef code = LLVMConstInlineAsm(calltype, "s_endpgm", "", true, false);
+       LLVMBuildCall(ctx->builder, code, NULL, 0, "");
+}
+
+LLVMValueRef ac_prefix_bitcount(struct ac_llvm_context *ctx,
+                               LLVMValueRef mask, LLVMValueRef index)
+{
+       LLVMBuilderRef builder = ctx->builder;
+       LLVMTypeRef type = LLVMTypeOf(mask);
+
+       LLVMValueRef bit = LLVMBuildShl(builder, LLVMConstInt(type, 1, 0),
+                                       LLVMBuildZExt(builder, index, type, ""), "");
+       LLVMValueRef prefix_bits = LLVMBuildSub(builder, bit, LLVMConstInt(type, 1, 0), "");
+       LLVMValueRef prefix_mask = LLVMBuildAnd(builder, mask, prefix_bits, "");
+       return ac_build_bit_count(ctx, prefix_mask);
+}
+
+/* Compute the prefix sum of the "mask" bit array with 128 elements (bits). */
+LLVMValueRef ac_prefix_bitcount_2x64(struct ac_llvm_context *ctx,
+                                    LLVMValueRef mask[2], LLVMValueRef index)
+{
+       LLVMBuilderRef builder = ctx->builder;
+#if 0
+       /* Reference version using i128. */
+       LLVMValueRef input_mask =
+               LLVMBuildBitCast(builder, ac_build_gather_values(ctx, mask, 2), ctx->i128, "");
+
+       return ac_prefix_bitcount(ctx, input_mask, index);
+#else
+       /* Optimized version using 2 64-bit masks. */
+       LLVMValueRef is_hi, is_0, c64, c128, all_bits;
+       LLVMValueRef prefix_mask[2], shift[2], mask_bcnt0, prefix_bcnt[2];
+
+       /* Compute the 128-bit prefix mask. */
+       c64 = LLVMConstInt(ctx->i32, 64, 0);
+       c128 = LLVMConstInt(ctx->i32, 128, 0);
+       all_bits = LLVMConstInt(ctx->i64, UINT64_MAX, 0);
+       /* The first index that can have non-zero high bits in the prefix mask is 65. */
+       is_hi = LLVMBuildICmp(builder, LLVMIntUGT, index, c64, "");
+       is_0 = LLVMBuildICmp(builder, LLVMIntEQ, index, ctx->i32_0, "");
+       mask_bcnt0 = ac_build_bit_count(ctx, mask[0]);
+
+       for (unsigned i = 0; i < 2; i++) {
+               shift[i] = LLVMBuildSub(builder, i ? c128 : c64, index, "");
+               /* For i==0, index==0, the right shift by 64 doesn't give the desired result,
+                * so we handle it by the is_0 select.
+                * For i==1, index==64, same story, so we handle it by the last is_hi select.
+                * For i==0, index==64, we shift by 0, which is what we want.
+                */
+               prefix_mask[i] = LLVMBuildLShr(builder, all_bits,
+                                       LLVMBuildZExt(builder, shift[i], ctx->i64, ""), "");
+               prefix_mask[i] = LLVMBuildAnd(builder, mask[i], prefix_mask[i], "");
+               prefix_bcnt[i] = ac_build_bit_count(ctx, prefix_mask[i]);
+       }
+
+       prefix_bcnt[0] = LLVMBuildSelect(builder, is_0, ctx->i32_0, prefix_bcnt[0], "");
+       prefix_bcnt[0] = LLVMBuildSelect(builder, is_hi, mask_bcnt0, prefix_bcnt[0], "");
+       prefix_bcnt[1] = LLVMBuildSelect(builder, is_hi, prefix_bcnt[1], ctx->i32_0, "");
+
+       return LLVMBuildAdd(builder, prefix_bcnt[0], prefix_bcnt[1], "");
+#endif
+}
+
+/**
+ * Convert triangle strip indices to triangle indices. This is used to decompose
+ * triangle strips into triangles.
+ */
+void ac_build_triangle_strip_indices_to_triangle(struct ac_llvm_context *ctx,
+                                                LLVMValueRef is_odd,
+                                                LLVMValueRef flatshade_first,
+                                                LLVMValueRef index[3])
+{
+       LLVMBuilderRef builder = ctx->builder;
+       LLVMValueRef out[3];
+
+       /* We need to change the vertex order for odd triangles to get correct
+        * front/back facing by swapping 2 vertex indices, but we also have to
+        * keep the provoking vertex in the same place.
+        *
+        * If the first vertex is provoking, swap index 1 and 2.
+        * If the last vertex is provoking, swap index 0 and 1.
+        */
+       out[0] = LLVMBuildSelect(builder, flatshade_first,
+                                index[0],
+                                LLVMBuildSelect(builder, is_odd,
+                                                index[1], index[0], ""), "");
+       out[1] = LLVMBuildSelect(builder, flatshade_first,
+                                LLVMBuildSelect(builder, is_odd,
+                                                index[2], index[1], ""),
+                                LLVMBuildSelect(builder, is_odd,
+                                                index[0], index[1], ""), "");
+       out[2] = LLVMBuildSelect(builder, flatshade_first,
+                                LLVMBuildSelect(builder, is_odd,
+                                                index[1], index[2], ""),
+                                index[2], "");
+       memcpy(index, out, sizeof(out));
+}