ac: replace SI.export with amdgcn.exp.*
[mesa.git] / src / amd / common / ac_llvm_build.c
index afcbf3199951f08ba3e9982c1819229c15b7a1c4..bd1b63d40fae25571e7b97206db04ad3e595fa14 100644 (file)
@@ -82,7 +82,9 @@ ac_emit_llvm_intrinsic(struct ac_llvm_context *ctx, const char *name,
                       LLVMTypeRef return_type, LLVMValueRef *params,
                       unsigned param_count, unsigned attrib_mask)
 {
-       LLVMValueRef function;
+       LLVMValueRef function, call;
+       bool set_callsite_attrs = HAVE_LLVM >= 0x0400 &&
+                                 !(attrib_mask & AC_FUNC_ATTR_LEGACY);
 
        function = LLVMGetNamedFunction(ctx->module, name);
        if (!function) {
@@ -102,13 +104,51 @@ ac_emit_llvm_intrinsic(struct ac_llvm_context *ctx, const char *name,
                LLVMSetFunctionCallConv(function, LLVMCCallConv);
                LLVMSetLinkage(function, LLVMExternalLinkage);
 
-               attrib_mask |= AC_FUNC_ATTR_NOUNWIND;
-               while (attrib_mask) {
-                       enum ac_func_attr attr = 1u << u_bit_scan(&attrib_mask);
-                       ac_add_function_attr(function, -1, attr);
+               if (!set_callsite_attrs)
+                       ac_add_func_attributes(ctx->context, function, attrib_mask);
+       }
+
+       call = LLVMBuildCall(ctx->builder, function, params, param_count, "");
+       if (set_callsite_attrs)
+               ac_add_func_attributes(ctx->context, call, attrib_mask);
+       return call;
+}
+
+/**
+ * Given the i32 or vNi32 \p type, generate the textual name (e.g. for use with
+ * intrinsic names).
+ */
+void ac_build_type_name_for_intr(LLVMTypeRef type, char *buf, unsigned bufsize)
+{
+       LLVMTypeRef elem_type = type;
+
+       assert(bufsize >= 8);
+
+       if (LLVMGetTypeKind(type) == LLVMVectorTypeKind) {
+               int ret = snprintf(buf, bufsize, "v%u",
+                                       LLVMGetVectorSize(type));
+               if (ret < 0) {
+                       char *type_name = LLVMPrintTypeToString(type);
+                       fprintf(stderr, "Error building type name for: %s\n",
+                               type_name);
+                       return;
                }
+               elem_type = LLVMGetElementType(type);
+               buf += ret;
+               bufsize -= ret;
+       }
+       switch (LLVMGetTypeKind(elem_type)) {
+       default: break;
+       case LLVMIntegerTypeKind:
+               snprintf(buf, bufsize, "i%d", LLVMGetIntTypeWidth(elem_type));
+               break;
+       case LLVMFloatTypeKind:
+               snprintf(buf, bufsize, "f32");
+               break;
+       case LLVMDoubleTypeKind:
+               snprintf(buf, bufsize, "f64");
+               break;
        }
-       return LLVMBuildCall(ctx->builder, function, params, param_count, "");
 }
 
 LLVMValueRef
@@ -119,10 +159,9 @@ ac_build_gather_values_extended(struct ac_llvm_context *ctx,
                                bool load)
 {
        LLVMBuilderRef builder = ctx->builder;
-       LLVMValueRef vec;
+       LLVMValueRef vec = NULL;
        unsigned i;
 
-
        if (value_count == 1) {
                if (load)
                        return LLVMBuildLoad(builder, values[0], "");
@@ -531,7 +570,8 @@ ac_build_tbuffer_store(struct ac_llvm_context *ctx,
        snprintf(name, sizeof(name), "llvm.SI.tbuffer.store.%s", types[func]);
 
        ac_emit_llvm_intrinsic(ctx, name, ctx->voidt,
-                              args, ARRAY_SIZE(args), 0);
+                              args, ARRAY_SIZE(args),
+                              AC_FUNC_ATTR_LEGACY);
 }
 
 void
@@ -750,3 +790,145 @@ ac_emit_ddxy(struct ac_llvm_context *ctx,
        result = LLVMBuildFSub(ctx->builder, trbl, tl, "");
        return result;
 }
+
+void
+ac_emit_sendmsg(struct ac_llvm_context *ctx,
+               uint32_t msg,
+               LLVMValueRef wave_id)
+{
+       LLVMValueRef args[2];
+       const char *intr_name = (HAVE_LLVM < 0x0400) ? "llvm.SI.sendmsg" : "llvm.amdgcn.s.sendmsg";
+       args[0] = LLVMConstInt(ctx->i32, msg, false);
+       args[1] = wave_id;
+       ac_emit_llvm_intrinsic(ctx, intr_name, ctx->voidt,
+                              args, 2, 0);
+}
+
+LLVMValueRef
+ac_emit_imsb(struct ac_llvm_context *ctx,
+            LLVMValueRef arg,
+            LLVMTypeRef dst_type)
+{
+       const char *intr_name = (HAVE_LLVM < 0x0400) ? "llvm.AMDGPU.flbit.i32" :
+                                                      "llvm.amdgcn.sffbh.i32";
+       LLVMValueRef msb = ac_emit_llvm_intrinsic(ctx, intr_name,
+                                                 dst_type, &arg, 1,
+                                                 AC_FUNC_ATTR_READNONE);
+
+       /* The HW returns the last bit index from MSB, but NIR/TGSI wants
+        * the index from LSB. Invert it by doing "31 - msb". */
+       msb = LLVMBuildSub(ctx->builder, LLVMConstInt(ctx->i32, 31, false),
+                          msb, "");
+
+       LLVMValueRef all_ones = LLVMConstInt(ctx->i32, -1, true);
+       LLVMValueRef cond = LLVMBuildOr(ctx->builder,
+                                       LLVMBuildICmp(ctx->builder, LLVMIntEQ,
+                                                     arg, LLVMConstInt(ctx->i32, 0, 0), ""),
+                                       LLVMBuildICmp(ctx->builder, LLVMIntEQ,
+                                                     arg, all_ones, ""), "");
+
+       return LLVMBuildSelect(ctx->builder, cond, all_ones, msb, "");
+}
+
+LLVMValueRef
+ac_emit_umsb(struct ac_llvm_context *ctx,
+            LLVMValueRef arg,
+            LLVMTypeRef dst_type)
+{
+       LLVMValueRef args[2] = {
+               arg,
+               LLVMConstInt(ctx->i1, 1, 0),
+       };
+       LLVMValueRef msb = ac_emit_llvm_intrinsic(ctx, "llvm.ctlz.i32",
+                                                 dst_type, args, ARRAY_SIZE(args),
+                                                 AC_FUNC_ATTR_READNONE);
+
+       /* The HW returns the last bit index from MSB, but TGSI/NIR wants
+        * the index from LSB. Invert it by doing "31 - msb". */
+       msb = LLVMBuildSub(ctx->builder, LLVMConstInt(ctx->i32, 31, false),
+                          msb, "");
+
+       /* check for zero */
+       return LLVMBuildSelect(ctx->builder,
+                              LLVMBuildICmp(ctx->builder, LLVMIntEQ, arg,
+                                            LLVMConstInt(ctx->i32, 0, 0), ""),
+                              LLVMConstInt(ctx->i32, -1, true), msb, "");
+}
+
+LLVMValueRef ac_emit_clamp(struct ac_llvm_context *ctx, LLVMValueRef value)
+{
+       if (HAVE_LLVM >= 0x0500) {
+               LLVMValueRef max[2] = {
+                       value,
+                       LLVMConstReal(ctx->f32, 0),
+               };
+               LLVMValueRef min[2] = {
+                       LLVMConstReal(ctx->f32, 1),
+               };
+
+               min[1] = ac_emit_llvm_intrinsic(ctx, "llvm.maxnum.f32",
+                                               ctx->f32, max, 2,
+                                               AC_FUNC_ATTR_READNONE);
+               return ac_emit_llvm_intrinsic(ctx, "llvm.minnum.f32",
+                                             ctx->f32, min, 2,
+                                             AC_FUNC_ATTR_READNONE);
+       }
+
+       const char *intr = HAVE_LLVM >= 0x0308 ? "llvm.AMDGPU.clamp." :
+                                                "llvm.AMDIL.clamp.";
+       LLVMValueRef args[3] = {
+               value,
+               LLVMConstReal(ctx->f32, 0),
+               LLVMConstReal(ctx->f32, 1),
+       };
+
+       return ac_emit_llvm_intrinsic(ctx, intr, ctx->f32, args, 3,
+                                     AC_FUNC_ATTR_READNONE |
+                                     AC_FUNC_ATTR_LEGACY);
+}
+
+void ac_emit_export(struct ac_llvm_context *ctx, struct ac_export_args *a)
+{
+       LLVMValueRef args[9];
+
+       if (HAVE_LLVM >= 0x0500) {
+               args[0] = LLVMConstInt(ctx->i32, a->target, 0);
+               args[1] = LLVMConstInt(ctx->i32, a->enabled_channels, 0);
+
+               if (a->compr) {
+                       LLVMTypeRef i16 = LLVMInt16TypeInContext(ctx->context);
+                       LLVMTypeRef v2i16 = LLVMVectorType(i16, 2);
+
+                       args[2] = LLVMBuildBitCast(ctx->builder, a->out[0],
+                                                  v2i16, "");
+                       args[3] = LLVMBuildBitCast(ctx->builder, a->out[1],
+                                                  v2i16, "");
+                       args[4] = LLVMConstInt(ctx->i1, a->done, 0);
+                       args[5] = LLVMConstInt(ctx->i1, a->valid_mask, 0);
+
+                       ac_emit_llvm_intrinsic(ctx, "llvm.amdgcn.exp.compr.v2i16",
+                                              ctx->voidt, args, 6, 0);
+               } else {
+                       args[2] = a->out[0];
+                       args[3] = a->out[1];
+                       args[4] = a->out[2];
+                       args[5] = a->out[3];
+                       args[6] = LLVMConstInt(ctx->i1, a->done, 0);
+                       args[7] = LLVMConstInt(ctx->i1, a->valid_mask, 0);
+
+                       ac_emit_llvm_intrinsic(ctx, "llvm.amdgcn.exp.f32",
+                                              ctx->voidt, args, 8, 0);
+               }
+               return;
+       }
+
+       args[0] = LLVMConstInt(ctx->i32, a->enabled_channels, 0);
+       args[1] = LLVMConstInt(ctx->i32, a->valid_mask, 0);
+       args[2] = LLVMConstInt(ctx->i32, a->done, 0);
+       args[3] = LLVMConstInt(ctx->i32, a->target, 0);
+       args[4] = LLVMConstInt(ctx->i32, a->compr, 0);
+       memcpy(args + 5, a->out, sizeof(a->out[0]) * 4);
+
+       ac_emit_llvm_intrinsic(ctx, "llvm.SI.export", ctx->voidt, args, 9,
+                              AC_FUNC_ATTR_LEGACY);
+}