OSDN Git Service

ac: add helpers for fast integer division by a constant
authorMarek Olšák <marek.olsak@amd.com>
Sun, 23 Sep 2018 01:17:52 +0000 (21:17 -0400)
committerMarek Olšák <marek.olsak@amd.com>
Tue, 16 Oct 2018 21:23:25 +0000 (17:23 -0400)
src/amd/common/ac_llvm_build.c
src/amd/common/ac_llvm_build.h

index d0bcfe2..2d78ca1 100644 (file)
@@ -594,6 +594,67 @@ ac_build_fdiv(struct ac_llvm_context *ctx,
        return ret;
 }
 
+/* See fast_idiv_by_const.h. */
+/* Set: increment = util_fast_udiv_info::increment ? multiplier : 0; */
+LLVMValueRef ac_build_fast_udiv(struct ac_llvm_context *ctx,
+                               LLVMValueRef num,
+                               LLVMValueRef multiplier,
+                               LLVMValueRef pre_shift,
+                               LLVMValueRef post_shift,
+                               LLVMValueRef increment)
+{
+       LLVMBuilderRef builder = ctx->builder;
+
+       num = LLVMBuildLShr(builder, num, pre_shift, "");
+       num = LLVMBuildMul(builder,
+                          LLVMBuildZExt(builder, num, ctx->i64, ""),
+                          LLVMBuildZExt(builder, multiplier, ctx->i64, ""), "");
+       num = LLVMBuildAdd(builder, num,
+                          LLVMBuildZExt(builder, increment, ctx->i64, ""), "");
+       num = LLVMBuildLShr(builder, num, LLVMConstInt(ctx->i64, 32, 0), "");
+       num = LLVMBuildTrunc(builder, num, ctx->i32, "");
+       return LLVMBuildLShr(builder, num, post_shift, "");
+}
+
+/* See fast_idiv_by_const.h. */
+/* If num != UINT_MAX, this more efficient version can be used. */
+/* Set: increment = util_fast_udiv_info::increment; */
+LLVMValueRef ac_build_fast_udiv_nuw(struct ac_llvm_context *ctx,
+                                   LLVMValueRef num,
+                                   LLVMValueRef multiplier,
+                                   LLVMValueRef pre_shift,
+                                   LLVMValueRef post_shift,
+                                   LLVMValueRef increment)
+{
+       LLVMBuilderRef builder = ctx->builder;
+
+       num = LLVMBuildLShr(builder, num, pre_shift, "");
+       num = LLVMBuildNUWAdd(builder, num, increment, "");
+       num = LLVMBuildMul(builder,
+                          LLVMBuildZExt(builder, num, ctx->i64, ""),
+                          LLVMBuildZExt(builder, multiplier, ctx->i64, ""), "");
+       num = LLVMBuildLShr(builder, num, LLVMConstInt(ctx->i64, 32, 0), "");
+       num = LLVMBuildTrunc(builder, num, ctx->i32, "");
+       return LLVMBuildLShr(builder, num, post_shift, "");
+}
+
+/* See fast_idiv_by_const.h. */
+/* Both operands must fit in 31 bits and the divisor must not be 1. */
+LLVMValueRef ac_build_fast_udiv_u31_d_not_one(struct ac_llvm_context *ctx,
+                                             LLVMValueRef num,
+                                             LLVMValueRef multiplier,
+                                             LLVMValueRef post_shift)
+{
+       LLVMBuilderRef builder = ctx->builder;
+
+       num = LLVMBuildMul(builder,
+                          LLVMBuildZExt(builder, num, ctx->i64, ""),
+                          LLVMBuildZExt(builder, multiplier, ctx->i64, ""), "");
+       num = LLVMBuildLShr(builder, num, LLVMConstInt(ctx->i64, 32, 0), "");
+       num = LLVMBuildTrunc(builder, num, ctx->i32, "");
+       return LLVMBuildLShr(builder, num, post_shift, "");
+}
+
 /* Coordinates for cube map selection. sc, tc, and ma are as in Table 8.27
  * of the OpenGL 4.5 (Compatibility Profile) specification, except ma is
  * already multiplied by two. id is the cube face number.
index 5c3e221..f68efbc 100644 (file)
@@ -182,6 +182,23 @@ ac_build_fdiv(struct ac_llvm_context *ctx,
              LLVMValueRef num,
              LLVMValueRef den);
 
+LLVMValueRef ac_build_fast_udiv(struct ac_llvm_context *ctx,
+                               LLVMValueRef num,
+                               LLVMValueRef multiplier,
+                               LLVMValueRef pre_shift,
+                               LLVMValueRef post_shift,
+                               LLVMValueRef increment);
+LLVMValueRef ac_build_fast_udiv_nuw(struct ac_llvm_context *ctx,
+                                   LLVMValueRef num,
+                                   LLVMValueRef multiplier,
+                                   LLVMValueRef pre_shift,
+                                   LLVMValueRef post_shift,
+                                   LLVMValueRef increment);
+LLVMValueRef ac_build_fast_udiv_u31_d_not_one(struct ac_llvm_context *ctx,
+                                             LLVMValueRef num,
+                                             LLVMValueRef multiplier,
+                                             LLVMValueRef post_shift);
+
 void
 ac_prepare_cube_coords(struct ac_llvm_context *ctx,
                       bool is_deriv, bool is_array, bool is_lod,