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