• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <inttypes.h>
30 
31 #include "util/u_debug.h"
32 #include "util/u_memory.h"
33 #include "util/u_string.h"
34 #include "lp_bld_const.h"
35 #include "lp_bld_init.h"
36 #include "lp_bld_const.h"
37 #include "lp_bld_printf.h"
38 #include "lp_bld_type.h"
39 
40 
41 /**
42  * Generates LLVM IR to call debug_printf.
43  */
44 static LLVMValueRef
lp_build_print_args(struct gallivm_state * gallivm,int argcount,LLVMValueRef * args)45 lp_build_print_args(struct gallivm_state* gallivm,
46                     int argcount,
47                     LLVMValueRef* args)
48 {
49    LLVMBuilderRef builder = gallivm->builder;
50    LLVMContextRef context = gallivm->context;
51    int i;
52 
53    assert(args);
54    assert(argcount > 0);
55    assert(LLVMTypeOf(args[0]) == LLVMPointerType(LLVMInt8TypeInContext(context), 0));
56 
57    /* Cast any float arguments to doubles as printf expects */
58    for (i = 1; i < argcount; i++) {
59       LLVMTypeRef type = LLVMTypeOf(args[i]);
60 
61       if (LLVMGetTypeKind(type) == LLVMFloatTypeKind)
62          args[i] = LLVMBuildFPExt(builder, args[i], LLVMDoubleTypeInContext(context), "");
63    }
64 
65    if (!gallivm->debug_printf_hook) {
66       LLVMTypeRef printf_type = LLVMFunctionType(LLVMInt32TypeInContext(context), NULL, 0, 1);
67       gallivm->debug_printf_hook = LLVMAddFunction(gallivm->module, "debug_printf", printf_type);
68    }
69    return LLVMBuildCall(builder, gallivm->debug_printf_hook, args, argcount, "");
70 }
71 
72 
73 /**
74  * Print a LLVM value of any type
75  */
76 LLVMValueRef
lp_build_print_value(struct gallivm_state * gallivm,const char * msg,LLVMValueRef value)77 lp_build_print_value(struct gallivm_state *gallivm,
78                      const char *msg,
79                      LLVMValueRef value)
80 {
81    LLVMBuilderRef builder = gallivm->builder;
82    LLVMTypeKind type_kind;
83    LLVMTypeRef type_ref;
84    LLVMValueRef params[2 + LP_MAX_VECTOR_LENGTH];
85    char type_fmt[6] = " %x";
86    char format[2 + 5 * LP_MAX_VECTOR_LENGTH + 2] = "%s";
87    unsigned length;
88    unsigned i;
89 
90    type_ref = LLVMTypeOf(value);
91    type_kind = LLVMGetTypeKind(type_ref);
92 
93    if (type_kind == LLVMVectorTypeKind) {
94       length = LLVMGetVectorSize(type_ref);
95 
96       type_ref = LLVMGetElementType(type_ref);
97       type_kind = LLVMGetTypeKind(type_ref);
98    } else {
99       length = 1;
100    }
101 
102    if (type_kind == LLVMFloatTypeKind || type_kind == LLVMDoubleTypeKind) {
103       type_fmt[2] = '.';
104       type_fmt[3] = '9';
105       type_fmt[4] = 'g';
106       type_fmt[5] = '\0';
107    } else if (type_kind == LLVMIntegerTypeKind) {
108       if (LLVMGetIntTypeWidth(type_ref) == 64) {
109          snprintf(type_fmt + 2, 3, "%s", PRId64);
110       } else if (LLVMGetIntTypeWidth(type_ref) == 8) {
111          type_fmt[2] = 'u';
112       } else {
113          type_fmt[2] = 'i';
114       }
115    } else if (type_kind == LLVMPointerTypeKind) {
116       type_fmt[2] = 'p';
117    } else {
118       /* Unsupported type */
119       assert(0);
120    }
121 
122    /* Create format string and arguments */
123    assert(strlen(format) + strlen(type_fmt) * length + 2 <= sizeof format);
124 
125    params[1] = lp_build_const_string(gallivm, msg);
126    if (length == 1) {
127       strncat(format, type_fmt, sizeof(format) - strlen(format) - 1);
128       params[2] = value;
129    } else {
130       for (i = 0; i < length; ++i) {
131          LLVMValueRef param;
132          strncat(format, type_fmt, sizeof(format) - strlen(format) - 1);
133          param = LLVMBuildExtractElement(builder, value, lp_build_const_int32(gallivm, i), "");
134          if (type_kind == LLVMIntegerTypeKind &&
135              LLVMGetIntTypeWidth(type_ref) < sizeof(int) * 8) {
136             LLVMTypeRef int_type = LLVMIntTypeInContext(gallivm->context, sizeof(int) * 8);
137             if (LLVMGetIntTypeWidth(type_ref) == 8) {
138                param = LLVMBuildZExt(builder, param, int_type, "");
139             } else {
140                param = LLVMBuildSExt(builder, param, int_type, "");
141             }
142          }
143          params[2 + i] = param;
144       }
145    }
146 
147    strncat(format, "\n", sizeof(format) - strlen(format) - 1);
148 
149    params[0] = lp_build_const_string(gallivm, format);
150    return lp_build_print_args(gallivm, 2 + length, params);
151 }
152 
153 
154 static unsigned
lp_get_printf_arg_count(const char * fmt)155 lp_get_printf_arg_count(const char *fmt)
156 {
157    unsigned count = 0;
158    const char *p = fmt;
159    int c;
160 
161    while ((c = *p++)) {
162       if (c != '%')
163          continue;
164       switch (*p) {
165          case '\0':
166        continue;
167          case '%':
168        p++;
169        continue;
170     case '.':
171        if (p[1] == '*' && p[2] == 's') {
172           count += 2;
173           p += 3;
174                continue;
175        }
176        /* fallthrough */
177     default:
178        count ++;
179       }
180    }
181    return count;
182 }
183 
184 
185 /**
186  * Generate LLVM IR for a c style printf
187  */
188 LLVMValueRef
lp_build_printf(struct gallivm_state * gallivm,const char * fmt,...)189 lp_build_printf(struct gallivm_state *gallivm,
190                 const char *fmt, ...)
191 {
192    LLVMValueRef params[50];
193    va_list arglist;
194    unsigned argcount, i;
195 
196    argcount = lp_get_printf_arg_count(fmt);
197    assert(ARRAY_SIZE(params) >= argcount + 1);
198 
199    va_start(arglist, fmt);
200    for (i = 1; i <= argcount; i++) {
201       params[i] = va_arg(arglist, LLVMValueRef);
202    }
203    va_end(arglist);
204 
205    params[0] = lp_build_const_string(gallivm, fmt);
206    return lp_build_print_args(gallivm, argcount + 1, params);
207 }
208