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