util: use standard name for snprintf()
[mesa.git] / src / gallium / auxiliary / gallivm / lp_bld_printf.c
index 0d8d8065cb994f21d9c025366add30dcd51f08ed..a4233a24e3317cc98f0c1cb3afe60cdc73258826 100644 (file)
@@ -26,6 +26,7 @@
  **************************************************************************/
 
 #include <stdio.h>
+#include <inttypes.h>
 
 #include "util/u_debug.h"
 #include "util/u_memory.h"
 #include "lp_bld_init.h"
 #include "lp_bld_const.h"
 #include "lp_bld_printf.h"
+#include "lp_bld_type.h"
 
 
-static int
-lp_get_printf_arg_count(const char *fmt)
-{
-   int count =0;
-   const char *p = fmt;
-   int c;
-
-   while ((c = *p++)) {
-      if (c != '%')
-         continue;
-      switch (*p) {
-         case '\0':
-           continue;
-         case '%':
-           p++;
-           continue;
-        case '.':
-           if (p[1] == '*' && p[2] == 's') {
-              count += 2;
-              p += 3;
-               continue;
-           }
-           /* fallthrough */
-        default:
-           count ++;
-      }
-   }
-   return count;
-}
-
-LLVMValueRef 
-lp_build_const_string_variable(LLVMModuleRef module,
-                               LLVMContextRef context,
-                               const char *str, int len)
-{
-   LLVMValueRef string = LLVMAddGlobal(module, LLVMArrayType(LLVMInt8TypeInContext(context), len + 1), "");
-   LLVMSetGlobalConstant(string, TRUE);
-   LLVMSetLinkage(string, LLVMInternalLinkage);
-   LLVMSetInitializer(string, LLVMConstStringInContext(context, str, len + 1, TRUE));
-   return string;
-}
-
 /**
- * lp_build_printf.
- *
- * Build printf call in LLVM IR. The output goes to stdout.
- * The additional variable arguments need to have type
- * LLVMValueRef.
+ * Generates LLVM IR to call debug_printf.
  */
-LLVMValueRef
-lp_build_printf(struct gallivm_state *gallivm, const char *fmt, ...)
+static LLVMValueRef
+lp_build_print_args(struct gallivm_state* gallivm,
+                    int argcount,
+                    LLVMValueRef* args)
 {
-   va_list arglist;
-   int i = 0;
-   int argcount = lp_get_printf_arg_count(fmt);
    LLVMBuilderRef builder = gallivm->builder;
    LLVMContextRef context = gallivm->context;
-   LLVMModuleRef module = gallivm->module;
-   LLVMValueRef params[50];
-   LLVMValueRef fmtarg = lp_build_const_string_variable(module, context,
-                                                        fmt, strlen(fmt) + 1);
-   LLVMValueRef int0 = lp_build_const_int32(gallivm, 0);
-   LLVMValueRef index[2];
-   LLVMValueRef func_printf = LLVMGetNamedFunction(module, "printf");
+   LLVMValueRef func_printf;
+   LLVMTypeRef printf_type;
+   int i;
 
-   assert(Elements(params) >= argcount + 1);
+   assert(args);
+   assert(argcount > 0);
+   assert(LLVMTypeOf(args[0]) == LLVMPointerType(LLVMInt8TypeInContext(context), 0));
 
-   index[0] = index[1] = int0;
+   /* Cast any float arguments to doubles as printf expects */
+   for (i = 1; i < argcount; i++) {
+      LLVMTypeRef type = LLVMTypeOf(args[i]);
 
-   if (!func_printf) {
-      LLVMTypeRef printf_type = LLVMFunctionType(LLVMIntTypeInContext(context, 32), NULL, 0, 1);
-      func_printf = LLVMAddFunction(module, "printf", printf_type);
-   }
-
-   params[0] = LLVMBuildGEP(builder, fmtarg, index, 2, "");
-
-   va_start(arglist, fmt);
-   for (i = 1; i <= argcount; i++) {
-      LLVMValueRef val = va_arg(arglist, LLVMValueRef);
-      LLVMTypeRef type = LLVMTypeOf(val);
-      /* printf wants doubles, so lets convert so that
-       * we can actually print them */
       if (LLVMGetTypeKind(type) == LLVMFloatTypeKind)
-         val = LLVMBuildFPExt(builder, val, LLVMDoubleTypeInContext(context), "");
-      params[i] = val;
+         args[i] = LLVMBuildFPExt(builder, args[i], LLVMDoubleTypeInContext(context), "");
    }
-   va_end(arglist);
 
-   return LLVMBuildCall(builder, func_printf, params, argcount + 1, "");
-}
+   printf_type = LLVMFunctionType(LLVMInt32TypeInContext(context), NULL, 0, 1);
+   func_printf = lp_build_const_int_pointer(gallivm, func_to_pointer((func_pointer)debug_printf));
+   func_printf = LLVMBuildBitCast(builder, func_printf, LLVMPointerType(printf_type, 0), "debug_printf");
 
+   return LLVMBuildCall(builder, func_printf, args, argcount, "");
+}
 
 
 /**
- * Print a float[4] vector.
+ * Print a LLVM value of any type
  */
 LLVMValueRef
-lp_build_print_vec4(struct gallivm_state *gallivm,
-                    const char *msg, LLVMValueRef vec)
+lp_build_print_value(struct gallivm_state *gallivm,
+                     const char *msg,
+                     LLVMValueRef value)
 {
    LLVMBuilderRef builder = gallivm->builder;
-   char format[1000];
-   LLVMValueRef x, y, z, w;
+   LLVMTypeKind type_kind;
+   LLVMTypeRef type_ref;
+   LLVMValueRef params[2 + LP_MAX_VECTOR_LENGTH];
+   char type_fmt[6] = " %x";
+   char format[2 + 5 * LP_MAX_VECTOR_LENGTH + 2] = "%s";
+   unsigned length;
+   unsigned i;
+
+   type_ref = LLVMTypeOf(value);
+   type_kind = LLVMGetTypeKind(type_ref);
+
+   if (type_kind == LLVMVectorTypeKind) {
+      length = LLVMGetVectorSize(type_ref);
+
+      type_ref = LLVMGetElementType(type_ref);
+      type_kind = LLVMGetTypeKind(type_ref);
+   } else {
+      length = 1;
+   }
+
+   if (type_kind == LLVMFloatTypeKind || type_kind == LLVMDoubleTypeKind) {
+      type_fmt[2] = '.';
+      type_fmt[3] = '9';
+      type_fmt[4] = 'g';
+      type_fmt[5] = '\0';
+   } else if (type_kind == LLVMIntegerTypeKind) {
+      if (LLVMGetIntTypeWidth(type_ref) == 64) {
+         snprintf(type_fmt + 2, 3, "%s", PRId64);
+      } else if (LLVMGetIntTypeWidth(type_ref) == 8) {
+         type_fmt[2] = 'u';
+      } else {
+         type_fmt[2] = 'i';
+      }
+   } else if (type_kind == LLVMPointerTypeKind) {
+      type_fmt[2] = 'p';
+   } else {
+      /* Unsupported type */
+      assert(0);
+   }
 
-   x = LLVMBuildExtractElement(builder, vec, lp_build_const_int32(gallivm, 0), "");
-   y = LLVMBuildExtractElement(builder, vec, lp_build_const_int32(gallivm, 1), "");
-   z = LLVMBuildExtractElement(builder, vec, lp_build_const_int32(gallivm, 2), "");
-   w = LLVMBuildExtractElement(builder, vec, lp_build_const_int32(gallivm, 3), "");
+   /* Create format string and arguments */
+   assert(strlen(format) + strlen(type_fmt) * length + 2 <= sizeof format);
+
+   params[1] = lp_build_const_string(gallivm, msg);
+   if (length == 1) {
+      strncat(format, type_fmt, sizeof(format) - strlen(format) - 1);
+      params[2] = value;
+   } else {
+      for (i = 0; i < length; ++i) {
+         LLVMValueRef param;
+         strncat(format, type_fmt, sizeof(format) - strlen(format) - 1);
+         param = LLVMBuildExtractElement(builder, value, lp_build_const_int32(gallivm, i), "");
+         if (type_kind == LLVMIntegerTypeKind &&
+             LLVMGetIntTypeWidth(type_ref) < sizeof(int) * 8) {
+            LLVMTypeRef int_type = LLVMIntTypeInContext(gallivm->context, sizeof(int) * 8);
+            if (LLVMGetIntTypeWidth(type_ref) == 8) {
+               param = LLVMBuildZExt(builder, param, int_type, "");
+            } else {
+               param = LLVMBuildSExt(builder, param, int_type, "");
+            }
+         }
+         params[2 + i] = param;
+      }
+   }
 
-   util_snprintf(format, sizeof(format), "%s %%f %%f %%f %%f\n", msg);
-   return lp_build_printf(gallivm, format, x, y, z, w);
+   strncat(format, "\n", sizeof(format) - strlen(format) - 1);
+
+   params[0] = lp_build_const_string(gallivm, format);
+   return lp_build_print_args(gallivm, 2 + length, params);
 }
 
 
-/**
- * Print a intt[4] vector.
- */
-LLVMValueRef
-lp_build_print_ivec4(struct gallivm_state *gallivm,
-                    const char *msg, LLVMValueRef vec)
+static unsigned
+lp_get_printf_arg_count(const char *fmt)
 {
-   LLVMBuilderRef builder = gallivm->builder;
-   char format[1000];
-   LLVMValueRef x, y, z, w;
-
-   x = LLVMBuildExtractElement(builder, vec, lp_build_const_int32(gallivm, 0), "");
-   y = LLVMBuildExtractElement(builder, vec, lp_build_const_int32(gallivm, 1), "");
-   z = LLVMBuildExtractElement(builder, vec, lp_build_const_int32(gallivm, 2), "");
-   w = LLVMBuildExtractElement(builder, vec, lp_build_const_int32(gallivm, 3), "");
+   unsigned count = 0;
+   const char *p = fmt;
+   int c;
 
-   util_snprintf(format, sizeof(format), "%s %%i %%i %%i %%i\n", msg);
-   return lp_build_printf(gallivm, format, x, y, z, w);
+   while ((c = *p++)) {
+      if (c != '%')
+         continue;
+      switch (*p) {
+         case '\0':
+       continue;
+         case '%':
+       p++;
+       continue;
+    case '.':
+       if (p[1] == '*' && p[2] == 's') {
+          count += 2;
+          p += 3;
+               continue;
+       }
+       /* fallthrough */
+    default:
+       count ++;
+      }
+   }
+   return count;
 }
 
 
 /**
- * Print a uint8[16] vector.
+ * Generate LLVM IR for a c style printf
  */
 LLVMValueRef
-lp_build_print_uvec16(struct gallivm_state *gallivm,
-                    const char *msg, LLVMValueRef vec)
+lp_build_printf(struct gallivm_state *gallivm,
+                const char *fmt, ...)
 {
-   LLVMBuilderRef builder = gallivm->builder;
-   char format[1000];
-   LLVMValueRef args[16];
+   LLVMValueRef params[50];
+   va_list arglist;
+   unsigned argcount, i;
 
-   for(int i = 0; i < 16; ++i)
-      args[i] = LLVMBuildExtractElement(builder, vec, lp_build_const_int32(gallivm, i), "");
+   argcount = lp_get_printf_arg_count(fmt);
+   assert(ARRAY_SIZE(params) >= argcount + 1);
 
-   util_snprintf(format, sizeof(format), "%s %%u %%u %%u %%u %%u %%u %%u %%u %%u %%u %%u %%u %%u %%u %%u %%u\n", msg);
+   va_start(arglist, fmt);
+   for (i = 1; i <= argcount; i++) {
+      params[i] = va_arg(arglist, LLVMValueRef);
+   }
+   va_end(arglist);
 
-   return lp_build_printf(
-            gallivm, format,
-            args[ 0], args[ 1], args[ 2], args[ 3],
-            args[ 4], args[ 5], args[ 6], args[ 7],
-            args[ 8], args[ 9], args[10], args[11],
-            args[12], args[13], args[14], args[15]);
+   params[0] = lp_build_const_string(gallivm, fmt);
+   return lp_build_print_args(gallivm, argcount + 1, params);
 }