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