+#include "lp_bld_type.h"
+
+
+/**
+ * Generates LLVM IR to call debug_printf.
+ */
+static LLVMValueRef
+lp_build_print_args(struct gallivm_state* gallivm,
+ int argcount,
+ LLVMValueRef* args)
+{
+ LLVMBuilderRef builder = gallivm->builder;
+ LLVMContextRef context = gallivm->context;
+ LLVMValueRef func_printf;
+ LLVMTypeRef printf_type;
+ int i;
+
+ assert(args);
+ assert(argcount > 0);
+ assert(LLVMTypeOf(args[0]) == LLVMPointerType(LLVMInt8TypeInContext(context), 0));
+
+ /* Cast any float arguments to doubles as printf expects */
+ for (i = 1; i < argcount; i++) {
+ LLVMTypeRef type = LLVMTypeOf(args[i]);
+
+ if (LLVMGetTypeKind(type) == LLVMFloatTypeKind)
+ args[i] = LLVMBuildFPExt(builder, args[i], LLVMDoubleTypeInContext(context), "");
+ }
+
+ 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 LLVM value of any type
+ */
+LLVMValueRef
+lp_build_print_value(struct gallivm_state *gallivm,
+ const char *msg,
+ LLVMValueRef value)
+{
+ LLVMBuilderRef builder = gallivm->builder;
+ 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) {
+ unsigned flen = strlen(PRId64);
+ assert(flen <= 3);
+ strncpy(type_fmt + 2, PRId64, flen);
+ } 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);
+ }
+
+ /* 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) {
+ util_strncat(format, type_fmt, sizeof(format) - strlen(format) - 1);
+ params[2] = value;
+ } else {
+ for (i = 0; i < length; ++i) {
+ LLVMValueRef param;
+ util_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_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);
+}