+LLVMValueRef
+build_intrinsic(LLVMBuilderRef builder,
+ const char *name,
+ LLVMTypeRef ret_type,
+ LLVMValueRef *args,
+ unsigned num_args,
+ LLVMAttribute attr)
+{
+ LLVMModuleRef module = LLVMGetGlobalParent(LLVMGetBasicBlockParent(LLVMGetInsertBlock(builder)));
+ LLVMValueRef function;
+
+ function = LLVMGetNamedFunction(module, name);
+ if(!function) {
+ LLVMTypeRef arg_types[LP_MAX_FUNC_ARGS];
+ unsigned i;
+
+ assert(num_args <= LP_MAX_FUNC_ARGS);
+
+ for(i = 0; i < num_args; ++i) {
+ assert(args[i]);
+ arg_types[i] = LLVMTypeOf(args[i]);
+ }
+
+ function = lp_declare_intrinsic(module, name, ret_type, arg_types, num_args);
+
+ if (attr)
+ LLVMAddFunctionAttr(function, attr);
+ }
+
+ return LLVMBuildCall(builder, function, args, num_args, "");
+}
+
+static void build_tgsi_intrinsic(
+ const struct lp_build_tgsi_action * action,
+ struct lp_build_tgsi_context * bld_base,
+ struct lp_build_emit_data * emit_data,
+ LLVMAttribute attr)
+{
+ struct lp_build_context * base = &bld_base->base;
+ emit_data->output[emit_data->chan] = build_intrinsic(
+ base->gallivm->builder, action->intr_name,
+ emit_data->dst_type, emit_data->args,
+ emit_data->arg_count, attr);
+}
+
+void
+build_tgsi_intrinsic_nomem(
+ const struct lp_build_tgsi_action * action,
+ struct lp_build_tgsi_context * bld_base,
+ struct lp_build_emit_data * emit_data)
+{
+ build_tgsi_intrinsic(action, bld_base, emit_data, LLVMReadNoneAttribute);
+}
+
+static void emit_bfi(const struct lp_build_tgsi_action * action,
+ struct lp_build_tgsi_context * bld_base,
+ struct lp_build_emit_data * emit_data)
+{
+ struct gallivm_state *gallivm = bld_base->base.gallivm;
+ LLVMBuilderRef builder = gallivm->builder;
+ LLVMValueRef bfi_args[3];
+
+ // Calculate the bitmask: (((1 << src3) - 1) << src2
+ bfi_args[0] = LLVMBuildShl(builder,
+ LLVMBuildSub(builder,
+ LLVMBuildShl(builder,
+ bld_base->int_bld.one,
+ emit_data->args[3], ""),
+ bld_base->int_bld.one, ""),
+ emit_data->args[2], "");
+
+ bfi_args[1] = LLVMBuildShl(builder, emit_data->args[1],
+ emit_data->args[2], "");
+
+ bfi_args[2] = emit_data->args[0];
+
+ /* Calculate:
+ * (arg0 & arg1) | (~arg0 & arg2) = arg2 ^ (arg0 & (arg1 ^ arg2)
+ * Use the right-hand side, which the LLVM backend can convert to V_BFI.
+ */
+ emit_data->output[emit_data->chan] =
+ LLVMBuildXor(builder, bfi_args[2],
+ LLVMBuildAnd(builder, bfi_args[0],
+ LLVMBuildXor(builder, bfi_args[1], bfi_args[2],
+ ""), ""), "");
+}
+
+/* this is ffs in C */
+static void emit_lsb(const struct lp_build_tgsi_action * action,
+ struct lp_build_tgsi_context * bld_base,
+ struct lp_build_emit_data * emit_data)
+{
+ struct gallivm_state *gallivm = bld_base->base.gallivm;
+ LLVMValueRef args[2] = {
+ emit_data->args[0],
+
+ /* The value of 1 means that ffs(x=0) = undef, so LLVM won't
+ * add special code to check for x=0. The reason is that
+ * the LLVM behavior for x=0 is different from what we
+ * need here.
+ *
+ * The hardware already implements the correct behavior.
+ */
+ lp_build_const_int32(gallivm, 1)
+ };
+
+ emit_data->output[emit_data->chan] =
+ build_intrinsic(gallivm->builder, "llvm.cttz.i32",
+ emit_data->dst_type, args, Elements(args),
+ LLVMReadNoneAttribute);
+}
+
+/* Find the last bit set. */
+static void emit_umsb(const struct lp_build_tgsi_action * action,
+ struct lp_build_tgsi_context * bld_base,
+ struct lp_build_emit_data * emit_data)
+{
+ struct gallivm_state *gallivm = bld_base->base.gallivm;
+ LLVMBuilderRef builder = gallivm->builder;
+ LLVMValueRef args[2] = {
+ emit_data->args[0],
+ /* Don't generate code for handling zero: */
+ lp_build_const_int32(gallivm, 1)
+ };
+
+ LLVMValueRef msb =
+ build_intrinsic(builder, "llvm.ctlz.i32",
+ emit_data->dst_type, args, Elements(args),
+ LLVMReadNoneAttribute);
+
+ /* The HW returns the last bit index from MSB, but TGSI wants
+ * the index from LSB. Invert it by doing "31 - msb". */
+ msb = LLVMBuildSub(builder, lp_build_const_int32(gallivm, 31),
+ msb, "");
+
+ /* Check for zero: */
+ emit_data->output[emit_data->chan] =
+ LLVMBuildSelect(builder,
+ LLVMBuildICmp(builder, LLVMIntEQ, args[0],
+ bld_base->uint_bld.zero, ""),
+ lp_build_const_int32(gallivm, -1), msb, "");
+}
+
+/* Find the last bit opposite of the sign bit. */
+static void emit_imsb(const struct lp_build_tgsi_action * action,
+ struct lp_build_tgsi_context * bld_base,
+ struct lp_build_emit_data * emit_data)
+{
+ struct gallivm_state *gallivm = bld_base->base.gallivm;
+ LLVMBuilderRef builder = gallivm->builder;
+ LLVMValueRef arg = emit_data->args[0];
+
+ LLVMValueRef msb =
+ build_intrinsic(builder, "llvm.AMDGPU.flbit.i32",
+ emit_data->dst_type, &arg, 1,
+ LLVMReadNoneAttribute);
+
+ /* The HW returns the last bit index from MSB, but TGSI wants
+ * the index from LSB. Invert it by doing "31 - msb". */
+ msb = LLVMBuildSub(builder, lp_build_const_int32(gallivm, 31),
+ msb, "");
+
+ /* If arg == 0 || arg == -1 (0xffffffff), return -1. */
+ LLVMValueRef all_ones = lp_build_const_int32(gallivm, -1);
+
+ LLVMValueRef cond =
+ LLVMBuildOr(builder,
+ LLVMBuildICmp(builder, LLVMIntEQ, arg,
+ bld_base->uint_bld.zero, ""),
+ LLVMBuildICmp(builder, LLVMIntEQ, arg,
+ all_ones, ""), "");
+
+ emit_data->output[emit_data->chan] =
+ LLVMBuildSelect(builder, cond, all_ones, msb, "");
+}
+