Intel SPMD Program Compiler  1.12.0
builtins.c
Go to the documentation of this file.
1 /*
2  Copyright (c) 2010-2019, 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 // In unistd.h we need the definition of sysconf and _SC_NPROCESSORS_ONLN used as its arguments.
66 // We should include unistd.h, but it doesn't really work well for cross compilation, as
67 // requires us to carry around unistd.h, which is not available on Windows out of the box.
68 #include <unistd.h>
69 
70 // Just for the reference: these lines are eventually included from unistd.h
71 // #define _SC_NPROCESSORS_ONLN 58
72 // long sysconf(int);
73 #endif // !_MSC_VER
74 
75 #include <stdarg.h>
76 #include <stdint.h>
77 #include <stdio.h>
78 #include <stdlib.h>
79 #include <string.h>
80 
81 typedef int Bool;
82 
83 #define PRINT_BUF_SIZE 4096
84 
85 #define APPEND(str) \
86  do { \
87  int offset = bufp - &printString[0]; \
88  *bufp = '\0'; \
89  strncat(bufp, str, PRINT_BUF_SIZE - offset); \
90  bufp += strlen(str); \
91  if (bufp >= &printString[PRINT_BUF_SIZE]) \
92  goto done; \
93  } while (0) /* eat semicolon */
94 
95 #define PRINT_SCALAR(fmt, type) \
96  sprintf(tmpBuf, fmt, *((type *)ptr)); \
97  APPEND(tmpBuf); \
98  break
99 
100 #define PRINT_VECTOR(fmt, type) \
101  *bufp++ = '['; \
102  if (bufp == &printString[PRINT_BUF_SIZE]) \
103  break; \
104  for (int i = 0; i < width; ++i) { \
105  /* only print the value if the current lane is executing */ \
106  if (mask & (1ull << i)) \
107  sprintf(tmpBuf, fmt, ((type *)ptr)[i]); \
108  else \
109  sprintf(tmpBuf, "((" fmt "))", ((type *)ptr)[i]); \
110  APPEND(tmpBuf); \
111  *bufp++ = (i != width - 1 ? ',' : ']'); \
112  } \
113  break
114 
115 /** This function is called by PrintStmt to do the work of printing values
116  from ispc programs. Note that the function signature here must match
117  the parameters that PrintStmt::EmitCode() generates.
118 
119  @param format Print format string
120  @param types Encoded types of the values being printed.
121  (See lEncodeType()).
122  @param width Vector width of the compilation target
123  @param mask Current lane mask when the print statemnt is called
124  @param args Array of pointers to the values to be printed
125  */
126 void __do_print(const char *format, const char *types, int width, uint64_t mask, void **args) {
127  char printString[PRINT_BUF_SIZE + 1]; // +1 for trailing NUL
128  char *bufp = &printString[0];
129  char tmpBuf[256];
130 
131  int argCount = 0;
132  while (*format && bufp < &printString[PRINT_BUF_SIZE]) {
133  // Format strings are just single percent signs.
134  if (*format != '%') {
135  *bufp++ = *format;
136  } else {
137  if (*types) {
138  void *ptr = args[argCount++];
139  // Based on the encoding in the types string, cast the
140  // value appropriately and print it with a reasonable
141  // printf() formatting string.
142  switch (*types) {
143  case 'b': {
144  sprintf(tmpBuf, "%s", *((Bool *)ptr) ? "true" : "false");
145  APPEND(tmpBuf);
146  break;
147  }
148  case 'B': {
149  *bufp++ = '[';
150  if (bufp == &printString[PRINT_BUF_SIZE])
151  break;
152  for (int i = 0; i < width; ++i) {
153  if (mask & (1ull << i)) {
154  sprintf(tmpBuf, "%s", ((Bool *)ptr)[i] ? "true" : "false");
155  APPEND(tmpBuf);
156  } else
157  APPEND("_________");
158  *bufp++ = (i != width - 1) ? ',' : ']';
159  }
160  break;
161  }
162  case 'i':
163  PRINT_SCALAR("%d", int);
164  case 'I':
165  PRINT_VECTOR("%d", int);
166  case 'u':
167  PRINT_SCALAR("%u", unsigned int);
168  case 'U':
169  PRINT_VECTOR("%u", unsigned int);
170  case 'f':
171  PRINT_SCALAR("%f", float);
172  case 'F':
173  PRINT_VECTOR("%f", float);
174  case 'l':
175  PRINT_SCALAR("%lld", long long);
176  case 'L':
177  PRINT_VECTOR("%lld", long long);
178  case 'v':
179  PRINT_SCALAR("%llu", unsigned long long);
180  case 'V':
181  PRINT_VECTOR("%llu", unsigned long long);
182  case 'd':
183  PRINT_SCALAR("%f", double);
184  case 'D':
185  PRINT_VECTOR("%f", double);
186  case 'p':
187  PRINT_SCALAR("%p", void *);
188  case 'P':
189  PRINT_VECTOR("%p", void *);
190  default:
191  APPEND("UNKNOWN TYPE ");
192  *bufp++ = *types;
193  }
194  ++types;
195  }
196  }
197  ++format;
198  }
199 
200 done:
201  *bufp = '\0';
202  fputs(printString, stdout);
203  fflush(stdout);
204 }
205 
206 #ifdef ISPC_NVPTX_ENABLED
207 /* this is print for PTX target only */
208 int __puts_nvptx(const char *);
209 void __do_print_nvptx(const char *format, const char *types, int width, uint64_t mask, void **args) {
210 #if 0
211  char printString[PRINT_BUF_SIZE+1]; // +1 for trailing NUL
212  char *bufp = &printString[0];
213  char tmpBuf[256];
214 
215  int argCount = 0;
216  while (*format && bufp < &printString[PRINT_BUF_SIZE]) {
217  // Format strings are just single percent signs.
218  if (*format != '%') {
219  *bufp++ = *format;
220  }
221  else {
222  if (*types) {
223  void *ptr = args[argCount++];
224  // Based on the encoding in the types string, cast the
225  // value appropriately and print it with a reasonable
226  // printf() formatting string.
227  switch (*types) {
228  case 'b': {
229  sprintf(tmpBuf, "%s", *((Bool *)ptr) ? "true" : "false");
230  APPEND(tmpBuf);
231  break;
232  }
233  case 'B': {
234  *bufp++ = '[';
235  if (bufp == &printString[PRINT_BUF_SIZE])
236  break;
237  for (int i = 0; i < width; ++i) {
238  if (mask & (1ull << i)) {
239  sprintf(tmpBuf, "%s", ((Bool *)ptr)[i] ? "true" : "false");
240  APPEND(tmpBuf);
241  }
242  else
243  APPEND("_________");
244  *bufp++ = (i != width-1) ? ',' : ']';
245  }
246  break;
247  }
248  case 'i': PRINT_SCALAR("%d", int);
249  case 'I': PRINT_VECTOR("%d", int);
250  case 'u': PRINT_SCALAR("%u", unsigned int);
251  case 'U': PRINT_VECTOR("%u", unsigned int);
252  case 'f': PRINT_SCALAR("%f", float);
253  case 'F': PRINT_VECTOR("%f", float);
254  case 'l': PRINT_SCALAR("%lld", long long);
255  case 'L': PRINT_VECTOR("%lld", long long);
256  case 'v': PRINT_SCALAR("%llu", unsigned long long);
257  case 'V': PRINT_VECTOR("%llu", unsigned long long);
258  case 'd': PRINT_SCALAR("%f", double);
259  case 'D': PRINT_VECTOR("%f", double);
260  case 'p': PRINT_SCALAR("%p", void *);
261  case 'P': PRINT_VECTOR("%p", void *);
262  default:
263  APPEND("UNKNOWN TYPE ");
264  *bufp++ = *types;
265  }
266  ++types;
267  }
268  }
269  ++format;
270  }
271 
272  done:
273  *bufp = '\n'; bufp++;
274  *bufp = '\0';
275  __puts_nvptx(printString);
276 #else
277  __puts_nvptx("---nvptx printing is not support---\n");
278 #endif
279 }
280 #endif
281 
282 int __num_cores() {
283 #if defined(_MSC_VER) || defined(__MINGW32__)
284  // This is quite a hack. Including all of windows.h to get this definition
285  // pulls in a bunch of stuff that leads to undefined symbols at link time.
286  // So we don't #include <windows.h> but instead have the equivalent declarations
287  // here. Presumably this struct declaration won't be changing in the future
288  // anyway...
289  struct SYSTEM_INFO {
290  int pad0[2];
291  void *pad1[2];
292  int *pad2;
293  int dwNumberOfProcessors;
294  int pad3[3];
295  };
296 
297  struct SYSTEM_INFO sysInfo;
298  extern void __stdcall GetSystemInfo(struct SYSTEM_INFO *);
299  GetSystemInfo(&sysInfo);
300  return sysInfo.dwNumberOfProcessors;
301 #else
302  return sysconf(_SC_NPROCESSORS_ONLN);
303 #endif // !_MSC_VER
304 }
int __num_cores()
Definition: builtins.c:282
#define PRINT_BUF_SIZE
Definition: builtins.c:83
int Bool
Definition: builtins.c:81
void __do_print(const char *format, const char *types, int width, uint64_t mask, void **args)
Definition: builtins.c:126
#define PRINT_SCALAR(fmt, type)
Definition: builtins.c:95
#define APPEND(str)
Definition: builtins.c:85
#define PRINT_VECTOR(fmt, type)
Definition: builtins.c:100