1 /************************************************************************** 2 * 3 * Copyright 2010 VMware, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28 #include <stdio.h> 29 30 #include "util/u_debug.h" 31 #include "util/u_memory.h" 32 #include "util/u_string.h" 33 #include "lp_bld_const.h" 34 #include "lp_bld_init.h" 35 #include "lp_bld_const.h" 36 #include "lp_bld_printf.h" 37 #include "lp_bld_type.h" 38 39 40 /** 41 * Generates LLVM IR to call debug_printf. 42 */ 43 static LLVMValueRef 44 lp_build_print_args(struct gallivm_state* gallivm, 45 int argcount, 46 LLVMValueRef* args) 47 { 48 LLVMBuilderRef builder = gallivm->builder; 49 LLVMContextRef context = gallivm->context; 50 LLVMValueRef func_printf; 51 LLVMTypeRef printf_type; 52 int i; 53 54 assert(args); 55 assert(argcount > 0); 56 assert(LLVMTypeOf(args[0]) == LLVMPointerType(LLVMInt8TypeInContext(context), 0)); 57 58 /* Cast any float arguments to doubles as printf expects */ 59 for (i = 1; i < argcount; i++) { 60 LLVMTypeRef type = LLVMTypeOf(args[i]); 61 62 if (LLVMGetTypeKind(type) == LLVMFloatTypeKind) 63 args[i] = LLVMBuildFPExt(builder, args[i], LLVMDoubleTypeInContext(context), ""); 64 } 65 66 printf_type = LLVMFunctionType(LLVMInt32TypeInContext(context), NULL, 0, 1); 67 func_printf = lp_build_const_int_pointer(gallivm, func_to_pointer((func_pointer)debug_printf)); 68 func_printf = LLVMBuildBitCast(builder, func_printf, LLVMPointerType(printf_type, 0), "debug_printf"); 69 70 return LLVMBuildCall(builder, func_printf, args, argcount, ""); 71 } 72 73 74 /** 75 * Print a LLVM value of any type 76 */ 77 LLVMValueRef 78 lp_build_print_value(struct gallivm_state *gallivm, 79 const char *msg, 80 LLVMValueRef value) 81 { 82 LLVMBuilderRef builder = gallivm->builder; 83 LLVMTypeKind type_kind; 84 LLVMTypeRef type_ref; 85 LLVMValueRef params[2 + LP_MAX_VECTOR_LENGTH]; 86 char type_fmt[6] = " %x"; 87 char format[2 + 5 * LP_MAX_VECTOR_LENGTH + 2] = "%s"; 88 unsigned length; 89 unsigned i; 90 91 type_ref = LLVMTypeOf(value); 92 type_kind = LLVMGetTypeKind(type_ref); 93 94 if (type_kind == LLVMVectorTypeKind) { 95 length = LLVMGetVectorSize(type_ref); 96 97 type_ref = LLVMGetElementType(type_ref); 98 type_kind = LLVMGetTypeKind(type_ref); 99 } else { 100 length = 1; 101 } 102 103 if (type_kind == LLVMFloatTypeKind || type_kind == LLVMDoubleTypeKind) { 104 type_fmt[2] = '.'; 105 type_fmt[3] = '9'; 106 type_fmt[4] = 'g'; 107 type_fmt[5] = '\0'; 108 } else if (type_kind == LLVMIntegerTypeKind) { 109 if (LLVMGetIntTypeWidth(type_ref) == 8) { 110 type_fmt[2] = 'u'; 111 } else { 112 type_fmt[2] = 'i'; 113 } 114 } else { 115 /* Unsupported type */ 116 assert(0); 117 } 118 119 /* Create format string and arguments */ 120 assert(strlen(format) + strlen(type_fmt) * length + 2 <= sizeof format); 121 122 params[1] = lp_build_const_string(gallivm, msg); 123 if (length == 1) { 124 util_strncat(format, type_fmt, sizeof(format) - strlen(format) - 1); 125 params[2] = value; 126 } else { 127 for (i = 0; i < length; ++i) { 128 util_strncat(format, type_fmt, sizeof(format) - strlen(format) - 1); 129 params[2 + i] = LLVMBuildExtractElement(builder, value, lp_build_const_int32(gallivm, i), ""); 130 } 131 } 132 133 util_strncat(format, "\n", sizeof(format) - strlen(format) - 1); 134 135 params[0] = lp_build_const_string(gallivm, format); 136 return lp_build_print_args(gallivm, 2 + length, params); 137 } 138 139 140 static int 141 lp_get_printf_arg_count(const char *fmt) 142 { 143 int count =0; 144 const char *p = fmt; 145 int c; 146 147 while ((c = *p++)) { 148 if (c != '%') 149 continue; 150 switch (*p) { 151 case '\0': 152 continue; 153 case '%': 154 p++; 155 continue; 156 case '.': 157 if (p[1] == '*' && p[2] == 's') { 158 count += 2; 159 p += 3; 160 continue; 161 } 162 /* fallthrough */ 163 default: 164 count ++; 165 } 166 } 167 return count; 168 } 169 170 171 /** 172 * Generate LLVM IR for a c style printf 173 */ 174 LLVMValueRef 175 lp_build_printf(struct gallivm_state *gallivm, 176 const char *fmt, ...) 177 { 178 LLVMValueRef params[50]; 179 va_list arglist; 180 int argcount; 181 int i; 182 183 argcount = lp_get_printf_arg_count(fmt); 184 assert(Elements(params) >= argcount + 1); 185 186 va_start(arglist, fmt); 187 for (i = 1; i <= argcount; i++) { 188 params[i] = va_arg(arglist, LLVMValueRef); 189 } 190 va_end(arglist); 191 192 params[0] = lp_build_const_string(gallivm, fmt); 193 return lp_build_print_args(gallivm, argcount + 1, params); 194 } 195