Intel® Implicit SPMD Program Compiler (Intel® ISPC)  1.13.0
builtins.c
Go to the documentation of this file.
1 /*
2  Copyright (c) 2010-2020, 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 #ifndef WASM
54 
55 #ifdef _MSC_VER
56 // We do want old school sprintf and don't want secure Microsoft extensions.
57 // And we also don't want warnings about it, so the define.
58 #define _CRT_SECURE_NO_WARNINGS
59 #else
60 // Some versions of glibc has "fortification" feature, which expands sprintf
61 // to __builtin___sprintf_chk(..., __builtin_object_size(...), ...).
62 // We don't want this kind of expansion, as we don't support these intrinsics.
63 #define _FORTIFY_SOURCE 0
64 #endif
65 
66 #ifndef _MSC_VER
67 // In unistd.h we need the definition of sysconf and _SC_NPROCESSORS_ONLN used as its arguments.
68 // We should include unistd.h, but it doesn't really work well for cross compilation, as
69 // requires us to carry around unistd.h, which is not available on Windows out of the box.
70 #include <unistd.h>
71 
72 // Just for the reference: these lines are eventually included from unistd.h
73 // #define _SC_NPROCESSORS_ONLN 58
74 // long sysconf(int);
75 #endif // !_MSC_VER
76 #endif // !WASM
77 #include <stdarg.h>
78 #include <stdint.h>
79 #include <stdio.h>
80 #include <stdlib.h>
81 #include <string.h>
82 
83 typedef int Bool;
84 
85 #define PRINT_BUF_SIZE 4096
86 
87 #define APPEND(str) \
88  do { \
89  int offset = bufp - &printString[0]; \
90  *bufp = '\0'; \
91  strncat(bufp, str, PRINT_BUF_SIZE - offset); \
92  bufp += strlen(str); \
93  if (bufp >= &printString[PRINT_BUF_SIZE]) \
94  goto done; \
95  } while (0) /* eat semicolon */
96 
97 #define PRINT_SCALAR(fmt, type) \
98  sprintf(tmpBuf, fmt, *((type *)ptr)); \
99  APPEND(tmpBuf); \
100  break
101 
102 #define PRINT_VECTOR(fmt, type) \
103  *bufp++ = '['; \
104  if (bufp == &printString[PRINT_BUF_SIZE]) \
105  break; \
106  for (int i = 0; i < width; ++i) { \
107  /* only print the value if the current lane is executing */ \
108  if (mask & (1ull << i)) \
109  sprintf(tmpBuf, fmt, ((type *)ptr)[i]); \
110  else \
111  sprintf(tmpBuf, "((" fmt "))", ((type *)ptr)[i]); \
112  APPEND(tmpBuf); \
113  *bufp++ = (i != width - 1 ? ',' : ']'); \
114  } \
115  break
116 
117 /** This function is called by PrintStmt to do the work of printing values
118  from ispc programs. Note that the function signature here must match
119  the parameters that PrintStmt::EmitCode() generates.
120 
121  @param format Print format string
122  @param types Encoded types of the values being printed.
123  (See lEncodeType()).
124  @param width Vector width of the compilation target
125  @param mask Current lane mask when the print statemnt is called
126  @param args Array of pointers to the values to be printed
127  */
128 void __do_print(const char *format, const char *types, int width, uint64_t mask, void **args) {
129  char printString[PRINT_BUF_SIZE + 1]; // +1 for trailing NUL
130  char *bufp = &printString[0];
131  char tmpBuf[256];
132 
133  int argCount = 0;
134  while (*format && bufp < &printString[PRINT_BUF_SIZE]) {
135  // Format strings are just single percent signs.
136  if (*format != '%') {
137  *bufp++ = *format;
138  } else {
139  if (*types) {
140  void *ptr = args[argCount++];
141  // Based on the encoding in the types string, cast the
142  // value appropriately and print it with a reasonable
143  // printf() formatting string.
144  switch (*types) {
145  case 'b': {
146  sprintf(tmpBuf, "%s", *((Bool *)ptr) ? "true" : "false");
147  APPEND(tmpBuf);
148  break;
149  }
150  case 'B': {
151  *bufp++ = '[';
152  if (bufp == &printString[PRINT_BUF_SIZE])
153  break;
154  for (int i = 0; i < width; ++i) {
155  if (mask & (1ull << i)) {
156  sprintf(tmpBuf, "%s", ((Bool *)ptr)[i] ? "true" : "false");
157  APPEND(tmpBuf);
158  } else
159  APPEND("_________");
160  *bufp++ = (i != width - 1) ? ',' : ']';
161  }
162  break;
163  }
164  case 'i':
165  PRINT_SCALAR("%d", int);
166  case 'I':
167  PRINT_VECTOR("%d", int);
168  case 'u':
169  PRINT_SCALAR("%u", unsigned int);
170  case 'U':
171  PRINT_VECTOR("%u", unsigned int);
172  case 'f':
173  PRINT_SCALAR("%f", float);
174  case 'F':
175  PRINT_VECTOR("%f", float);
176  case 'l':
177  PRINT_SCALAR("%lld", long long);
178  case 'L':
179  PRINT_VECTOR("%lld", long long);
180  case 'v':
181  PRINT_SCALAR("%llu", unsigned long long);
182  case 'V':
183  PRINT_VECTOR("%llu", unsigned long long);
184  case 'd':
185  PRINT_SCALAR("%f", double);
186  case 'D':
187  PRINT_VECTOR("%f", double);
188  case 'p':
189  PRINT_SCALAR("%p", void *);
190  case 'P':
191  PRINT_VECTOR("%p", void *);
192  default:
193  APPEND("UNKNOWN TYPE ");
194  *bufp++ = *types;
195  }
196  ++types;
197  }
198  }
199  ++format;
200  }
201 
202 done:
203  *bufp = '\0';
204  fputs(printString, stdout);
205  fflush(stdout);
206 }
207 
208 #ifdef WASM
209 int __num_cores() { return 1; }
210 #else // WASM
211 int __num_cores() {
212 #if defined(_MSC_VER) || defined(__MINGW32__)
213  // This is quite a hack. Including all of windows.h to get this definition
214  // pulls in a bunch of stuff that leads to undefined symbols at link time.
215  // So we don't #include <windows.h> but instead have the equivalent declarations
216  // here. Presumably this struct declaration won't be changing in the future
217  // anyway...
218  struct SYSTEM_INFO {
219  int pad0[2];
220  void *pad1[2];
221  int *pad2;
222  int dwNumberOfProcessors;
223  int pad3[3];
224  };
225 
226  struct SYSTEM_INFO sysInfo;
227  extern void __stdcall GetSystemInfo(struct SYSTEM_INFO *);
228  GetSystemInfo(&sysInfo);
229  return sysInfo.dwNumberOfProcessors;
230 #else
231  return sysconf(_SC_NPROCESSORS_ONLN);
232 #endif // !_MSC_VER
233 }
234 #endif // !WASM
int __num_cores()
Definition: builtins.c:211
#define PRINT_BUF_SIZE
Definition: builtins.c:85
int Bool
Definition: builtins.c:83
void __do_print(const char *format, const char *types, int width, uint64_t mask, void **args)
Definition: builtins.c:128
#define PRINT_SCALAR(fmt, type)
Definition: builtins.c:97
#define APPEND(str)
Definition: builtins.c:87
#define PRINT_VECTOR(fmt, type)
Definition: builtins.c:102