Intel SPMD Program Compiler  1.11.0
builtins.c
Go to the documentation of this file.
1 /*
2  Copyright (c) 2010-2013, Intel Corporation
3  All rights reserved.
4 
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are
7  met:
8 
9  * Redistributions of source code must retain the above copyright
10  notice, this list of conditions and the following disclaimer.
11 
12  * Redistributions in binary form must reproduce the above copyright
13  notice, this list of conditions and the following disclaimer in the
14  documentation and/or other materials provided with the distribution.
15 
16  * Neither the name of Intel Corporation nor the names of its
17  contributors may be used to endorse or promote products derived from
18  this software without specific prior written permission.
19 
20 
21  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
25  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 
34 /** @file builtins-c.c
35  @brief Standard library function implementations written in C.
36 
37  This file provides C implementations of various functions that can be
38  called from ispc programs; in other words, this file is *not* linked
39  into the ispc compiler executable, but rather provides functions that
40  can be compiled into ispc programs.
41 
42  When the ispc compiler is built, this file is compiled with clang to
43  generate LLVM bitcode. This bitcode is later linked in to the program
44  being compiled by the DefineStdlib() function. The first way to access
45  definitions from this file is by asking for them name from the
46  llvm::Module's' symbol table (e.g. as the PrintStmt implementation does
47  with __do_print() below. Alternatively, if a function defined in this
48  file has a signature that can be mapped back to ispc types by the
49  lLLVMTypeToIspcType() function, then its declaration will be made
50  available to ispc programs at compile time automatically.
51  */
52 
53 #ifdef _MSC_VER
54 // We do want old school sprintf and don't want secure Microsoft extensions.
55 // And we also don't want warnings about it, so the define.
56 #define _CRT_SECURE_NO_WARNINGS
57 #else
58 // Some versions of glibc has "fortification" feature, which expands sprintf
59 // to __builtin___sprintf_chk(..., __builtin_object_size(...), ...).
60 // We don't want this kind of expansion, as we don't support these intrinsics.
61 #define _FORTIFY_SOURCE 0
62 #endif
63 
64 #ifndef _MSC_VER
65 #include <unistd.h>
66 #endif // !_MSC_VER
67 
68 #include <stdarg.h>
69 #include <stdint.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 
74 typedef int Bool;
75 
76 #define PRINT_BUF_SIZE 4096
77 
78 #define APPEND(str) \
79  do { \
80  int offset = bufp - &printString[0]; \
81  *bufp = '\0'; \
82  strncat(bufp, str, PRINT_BUF_SIZE - offset); \
83  bufp += strlen(str); \
84  if (bufp >= &printString[PRINT_BUF_SIZE]) \
85  goto done; \
86  } while (0) /* eat semicolon */
87 
88 #define PRINT_SCALAR(fmt, type) \
89  sprintf(tmpBuf, fmt, *((type *)ptr)); \
90  APPEND(tmpBuf); \
91  break
92 
93 #define PRINT_VECTOR(fmt, type) \
94  *bufp++ = '['; \
95  if (bufp == &printString[PRINT_BUF_SIZE]) \
96  break; \
97  for (int i = 0; i < width; ++i) { \
98  /* only print the value if the current lane is executing */ \
99  if (mask & (1ull << i)) \
100  sprintf(tmpBuf, fmt, ((type *)ptr)[i]); \
101  else \
102  sprintf(tmpBuf, "((" fmt "))", ((type *)ptr)[i]); \
103  APPEND(tmpBuf); \
104  *bufp++ = (i != width - 1 ? ',' : ']'); \
105  } \
106  break
107 
108 /** This function is called by PrintStmt to do the work of printing values
109  from ispc programs. Note that the function signature here must match
110  the parameters that PrintStmt::EmitCode() generates.
111 
112  @param format Print format string
113  @param types Encoded types of the values being printed.
114  (See lEncodeType()).
115  @param width Vector width of the compilation target
116  @param mask Current lane mask when the print statemnt is called
117  @param args Array of pointers to the values to be printed
118  */
119 void __do_print(const char *format, const char *types, int width, uint64_t mask, void **args) {
120  char printString[PRINT_BUF_SIZE + 1]; // +1 for trailing NUL
121  char *bufp = &printString[0];
122  char tmpBuf[256];
123 
124  int argCount = 0;
125  while (*format && bufp < &printString[PRINT_BUF_SIZE]) {
126  // Format strings are just single percent signs.
127  if (*format != '%') {
128  *bufp++ = *format;
129  } else {
130  if (*types) {
131  void *ptr = args[argCount++];
132  // Based on the encoding in the types string, cast the
133  // value appropriately and print it with a reasonable
134  // printf() formatting string.
135  switch (*types) {
136  case 'b': {
137  sprintf(tmpBuf, "%s", *((Bool *)ptr) ? "true" : "false");
138  APPEND(tmpBuf);
139  break;
140  }
141  case 'B': {
142  *bufp++ = '[';
143  if (bufp == &printString[PRINT_BUF_SIZE])
144  break;
145  for (int i = 0; i < width; ++i) {
146  if (mask & (1ull << i)) {
147  sprintf(tmpBuf, "%s", ((Bool *)ptr)[i] ? "true" : "false");
148  APPEND(tmpBuf);
149  } else
150  APPEND("_________");
151  *bufp++ = (i != width - 1) ? ',' : ']';
152  }
153  break;
154  }
155  case 'i':
156  PRINT_SCALAR("%d", int);
157  case 'I':
158  PRINT_VECTOR("%d", int);
159  case 'u':
160  PRINT_SCALAR("%u", unsigned int);
161  case 'U':
162  PRINT_VECTOR("%u", unsigned int);
163  case 'f':
164  PRINT_SCALAR("%f", float);
165  case 'F':
166  PRINT_VECTOR("%f", float);
167  case 'l':
168  PRINT_SCALAR("%lld", long long);
169  case 'L':
170  PRINT_VECTOR("%lld", long long);
171  case 'v':
172  PRINT_SCALAR("%llu", unsigned long long);
173  case 'V':
174  PRINT_VECTOR("%llu", unsigned long long);
175  case 'd':
176  PRINT_SCALAR("%f", double);
177  case 'D':
178  PRINT_VECTOR("%f", double);
179  case 'p':
180  PRINT_SCALAR("%p", void *);
181  case 'P':
182  PRINT_VECTOR("%p", void *);
183  default:
184  APPEND("UNKNOWN TYPE ");
185  *bufp++ = *types;
186  }
187  ++types;
188  }
189  }
190  ++format;
191  }
192 
193 done:
194  *bufp = '\0';
195  fputs(printString, stdout);
196  fflush(stdout);
197 }
198 
199 /* this is print for PTX target only */
200 int __puts_nvptx(const char *);
201 void __do_print_nvptx(const char *format, const char *types, int width, uint64_t mask, void **args) {
202 #if 0
203  char printString[PRINT_BUF_SIZE+1]; // +1 for trailing NUL
204  char *bufp = &printString[0];
205  char tmpBuf[256];
206 
207  int argCount = 0;
208  while (*format && bufp < &printString[PRINT_BUF_SIZE]) {
209  // Format strings are just single percent signs.
210  if (*format != '%') {
211  *bufp++ = *format;
212  }
213  else {
214  if (*types) {
215  void *ptr = args[argCount++];
216  // Based on the encoding in the types string, cast the
217  // value appropriately and print it with a reasonable
218  // printf() formatting string.
219  switch (*types) {
220  case 'b': {
221  sprintf(tmpBuf, "%s", *((Bool *)ptr) ? "true" : "false");
222  APPEND(tmpBuf);
223  break;
224  }
225  case 'B': {
226  *bufp++ = '[';
227  if (bufp == &printString[PRINT_BUF_SIZE])
228  break;
229  for (int i = 0; i < width; ++i) {
230  if (mask & (1ull << i)) {
231  sprintf(tmpBuf, "%s", ((Bool *)ptr)[i] ? "true" : "false");
232  APPEND(tmpBuf);
233  }
234  else
235  APPEND("_________");
236  *bufp++ = (i != width-1) ? ',' : ']';
237  }
238  break;
239  }
240  case 'i': PRINT_SCALAR("%d", int);
241  case 'I': PRINT_VECTOR("%d", int);
242  case 'u': PRINT_SCALAR("%u", unsigned int);
243  case 'U': PRINT_VECTOR("%u", unsigned int);
244  case 'f': PRINT_SCALAR("%f", float);
245  case 'F': PRINT_VECTOR("%f", float);
246  case 'l': PRINT_SCALAR("%lld", long long);
247  case 'L': PRINT_VECTOR("%lld", long long);
248  case 'v': PRINT_SCALAR("%llu", unsigned long long);
249  case 'V': PRINT_VECTOR("%llu", unsigned long long);
250  case 'd': PRINT_SCALAR("%f", double);
251  case 'D': PRINT_VECTOR("%f", double);
252  case 'p': PRINT_SCALAR("%p", void *);
253  case 'P': PRINT_VECTOR("%p", void *);
254  default:
255  APPEND("UNKNOWN TYPE ");
256  *bufp++ = *types;
257  }
258  ++types;
259  }
260  }
261  ++format;
262  }
263 
264  done:
265  *bufp = '\n'; bufp++;
266  *bufp = '\0';
267  __puts_nvptx(printString);
268 #else
269  __puts_nvptx("---nvptx printing is not support---\n");
270 #endif
271 }
272 
273 int __num_cores() {
274 #if defined(_MSC_VER) || defined(__MINGW32__)
275  // This is quite a hack. Including all of windows.h to get this definition
276  // pulls in a bunch of stuff that leads to undefined symbols at link time.
277  // So we don't #include <windows.h> but instead have the equivalent declarations
278  // here. Presumably this struct declaration won't be changing in the future
279  // anyway...
280  struct SYSTEM_INFO {
281  int pad0[2];
282  void *pad1[2];
283  int *pad2;
284  int dwNumberOfProcessors;
285  int pad3[3];
286  };
287 
288  struct SYSTEM_INFO sysInfo;
289  extern void __stdcall GetSystemInfo(struct SYSTEM_INFO *);
290  GetSystemInfo(&sysInfo);
291  return sysInfo.dwNumberOfProcessors;
292 #else
293  return sysconf(_SC_NPROCESSORS_ONLN);
294 #endif // !_MSC_VER
295 }
int __puts_nvptx(const char *)
int __num_cores()
Definition: builtins.c:273
void __do_print_nvptx(const char *format, const char *types, int width, uint64_t mask, void **args)
Definition: builtins.c:201
#define PRINT_BUF_SIZE
Definition: builtins.c:76
int Bool
Definition: builtins.c:74
void __do_print(const char *format, const char *types, int width, uint64_t mask, void **args)
Definition: builtins.c:119
#define PRINT_SCALAR(fmt, type)
Definition: builtins.c:88
#define APPEND(str)
Definition: builtins.c:78
#define PRINT_VECTOR(fmt, type)
Definition: builtins.c:93