Intel SPMD Program Compiler  1.9.1
util.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 2010-2014, 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 util.cpp
35  @brief Various small utility routines.
36 */
37 
38 #include "util.h"
39 #include "module.h"
40 #ifdef ISPC_IS_WINDOWS
41 #include <shlwapi.h>
42 #ifdef __MINGW32__
43 #include <malloc.h> // for alloca()
44 #endif
45 #else
46 #include <alloca.h>
47 #include <unistd.h>
48 #endif
49 #include <stdio.h>
50 
51 #include <stdio.h>
52 #include <ctype.h>
53 #include <stdarg.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #ifdef ISPC_IS_WINDOWS
57 #include <io.h>
58 #include <direct.h>
59 #include <windows.h>
60 #else
61 #include <sys/ioctl.h>
62 #include <unistd.h>
63 #include <errno.h>
64 #endif // ISPC_IS_WINDOWS
65 #include <set>
66 #include <algorithm>
67 
68 #if ISPC_LLVM_VERSION == ISPC_LLVM_3_2
69  #include <llvm/DataLayout.h>
70 #else // LLVM 3.3+
71  #include <llvm/IR/DataLayout.h>
72 #endif
73 
74 /** Returns the width of the terminal where the compiler is running.
75  Finding this out may fail in a variety of reasonable situations (piping
76  compiler output to 'less', redirecting output to a file, running the
77  compiler under a debuffer; in this case, just return a reasonable
78  default.
79  */
80 int
82  if (g->disableLineWrap)
83  return 1<<30;
84 
85 #if defined(ISPC_IS_WINDOWS)
86  HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
87  if (h == INVALID_HANDLE_VALUE || h == NULL)
88  return 80;
89  CONSOLE_SCREEN_BUFFER_INFO bufferInfo = { {0} };
90  GetConsoleScreenBufferInfo(h, &bufferInfo);
91  return bufferInfo.dwSize.X;
92 #else
93  struct winsize w;
94  if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) < 0)
95  return 80;
96  return w.ws_col;
97 #endif // ISPC_IS_WINDOWS
98 }
99 
100 
101 static bool
103  static bool r = (getenv("TERM") != NULL &&
104  strcmp(getenv("TERM"), "dumb") != 0);
105 #ifndef ISPC_IS_WINDOWS
106  r &= isatty(2);
107 #endif // !ISPC_IS_WINDOWS
108  r |= g->forceColoredOutput;
109  return r;
110 }
111 
112 
113 static const char *
115  if (lHaveANSIColors())
116  return "\033[1m";
117  else
118  return "";
119 }
120 
121 
122 static const char *
124  if (lHaveANSIColors())
125  return "\033[31m";
126  else
127  return "";
128 }
129 
130 
131 static const char *
133  if (lHaveANSIColors())
134  return "\033[34m";
135  else
136  return "";
137 }
138 
139 
140 static const char *
142  if (lHaveANSIColors())
143  return "\033[0m";
144  else
145  return "";
146 }
147 
148 /** Given a pointer into a string, find the end of the current word and
149  return a pointer to its last character.
150 */
151 static const char *
152 lFindWordEnd(const char *buf) {
153  while (*buf != '\0' && !isspace(*buf))
154  ++buf;
155  return buf;
156 }
157 
158 /** When printing error messages, we sometimes want to include the source
159  file line for context. This function print the line(s) of the file
160  corresponding to the provided SourcePos and underlines the range of the
161  SourcePos with '^' symbols.
162 */
163 static void
165  if (p.first_line == 0)
166  return;
167 
168  FILE *f = fopen(p.name, "r");
169  if (!f)
170  return;
171 
172  int c, curLine = 1;
173  while ((c = fgetc(f)) != EOF) {
174  // Don't print more than three lines of context. (More than that,
175  // and we're probably doing the wrong thing...)
176  if (curLine >= std::max(p.first_line, p.last_line-2) &&
177  curLine <= p.last_line)
178  fputc(c, stderr);
179  if (c == '\n')
180  ++curLine;
181  if (curLine > p.last_line)
182  break;
183  }
184 
185  int i = 1;
186  for (; i < p.first_column; ++i)
187  fputc(' ', stderr);
188  fputc('^', stderr);
189  ++i;
190  for (; i < p.last_column; ++i)
191  fputc('^', stderr);
192  fputc('\n', stderr);
193  fputc('\n', stderr);
194 
195  fclose(f);
196 }
197 
198 
199 /** Counts the number of characters into the buf at which the numColons
200  colon character is found. Skips over ANSI escape sequences and doesn't
201  include their characters in the final count.
202  */
203 static int
204 lFindIndent(int numColons, const char *buf) {
205  int indent = 0;
206  while (*buf != '\0') {
207  if (*buf == '\033') {
208  while (*buf != '\0' && *buf != 'm')
209  ++buf;
210  if (*buf == 'm')
211  ++buf;
212  }
213  else {
214  if (*buf == ':') {
215  if (--numColons == 0)
216  break;
217  }
218  ++indent;
219  ++buf;
220  }
221  }
222  return indent + 2;
223 }
224 
225 
226 /** Print the given string to the given FILE, assuming the given output
227  column width. Break words as needed to avoid words spilling past the
228  last column. */
229 void
230 PrintWithWordBreaks(const char *buf, int indent, int columnWidth, FILE *out) {
231 #ifdef ISPC_IS_WINDOWS
232  fputs(buf, out);
233  fputs("\n", out);
234 #else
235  int column = 0;
236  int width = std::max(40, columnWidth - 2);
237 
238  // Collect everything into a string and print it all at once at the end
239  // -> try to avoid troubles with mangled error messages with
240  // multi-threaded builds.
241  std::string outStr;
242 
243  const char *msgPos = buf;
244  while (true) {
245  if (*msgPos == '\033') {
246  // handle ANSI color escape: copy it to the output buffer
247  // without charging for the characters it uses
248  do {
249  outStr.push_back(*msgPos++);
250  } while (*msgPos != '\0' && *msgPos != 'm');
251  continue;
252  }
253  else if (*msgPos == '\n') {
254  // Handle newlines cleanly
255  column = indent;
256  outStr.push_back('\n');
257  for (int i = 0; i < indent; ++i)
258  outStr.push_back(' ');
259  // Respect spaces after newlines
260  ++msgPos;
261  while (*msgPos == ' ') {
262  outStr.push_back(' ');
263  ++msgPos;
264  }
265  continue;
266  }
267 
268  while (*msgPos != '\0' && isspace(*msgPos))
269  ++msgPos;
270  if (*msgPos == '\0')
271  break;
272 
273  const char *wordEnd = lFindWordEnd(msgPos);
274  if (column > indent && column + wordEnd - msgPos > width) {
275  // This word would overflow, so start a new line
276  column = indent;
277  outStr.push_back('\n');
278  // Indent to the same column as the ":" at the start of the
279  // message.
280  for (int i = 0; i < indent; ++i)
281  outStr.push_back(' ');
282  }
283 
284  // Finally go and copy the word
285  while (msgPos != wordEnd) {
286  outStr.push_back(*msgPos++);
287  ++column;
288  }
289  outStr.push_back(' ');
290  ++column;
291  }
292  outStr.push_back('\n');
293  fputs(outStr.c_str(), out);
294 #endif
295 }
296 
297 
298 #ifdef ISPC_IS_WINDOWS
299 // we cover for the lack vasprintf and asprintf on windows (also covers mingw)
300 int
301 vasprintf(char **sptr, const char *fmt, va_list argv)
302 {
303  int wanted = vsnprintf(*sptr = NULL, 0, fmt, argv);
304  if((wanted < 0) || ((*sptr = (char*)malloc( 1 + wanted )) == NULL))
305  return -1;
306 
307  return vsprintf(*sptr, fmt, argv);
308 }
309 
310 
311 int
312 asprintf(char **sptr, const char *fmt, ...)
313 {
314  int retval;
315  va_list argv;
316  va_start(argv, fmt);
317  retval = vasprintf(sptr, fmt, argv);
318  va_end(argv);
319  return retval;
320 }
321 #endif
322 
323 
324 /** Helper function for Error(), Warning(), etc.
325 
326  @param type The type of message being printed (e.g. "Warning")
327  @param p Position in source file that is connected to the message
328  being printed
329  @param fmt printf()-style format string
330  @param args Arguments with values for format string % entries
331 */
332 static void
333 lPrint(const char *type, bool isError, SourcePos p, const char *fmt,
334  va_list args) {
335  char *errorBuf, *formattedBuf;
336  if (vasprintf(&errorBuf, fmt, args) == -1) {
337  fprintf(stderr, "vasprintf() unable to allocate memory!\n");
338  abort();
339  }
340 
341  int indent = 0;
342  if (p.first_line == 0) {
343  // We don't have a valid SourcePos, so create a message without it
344  if (asprintf(&formattedBuf, "%s%s%s%s%s: %s%s", lStartBold(),
345  isError ? lStartRed() : lStartBlue(), type,
346  lResetColor(), lStartBold(), errorBuf,
347  lResetColor()) == -1) {
348  fprintf(stderr, "asprintf() unable to allocate memory!\n");
349  exit(1);
350  }
351  indent = lFindIndent(1, formattedBuf);
352  }
353  else {
354  // Create an error message that includes the file and line number
355  if (asprintf(&formattedBuf, "%s%s:%d:%d: %s%s%s%s: %s%s",
357  isError ? lStartRed() : lStartBlue(), type,
358  lResetColor(), lStartBold(), errorBuf,
359  lResetColor()) == -1) {
360  fprintf(stderr, "asprintf() unable to allocate memory!\n");
361  exit(1);
362  }
363  indent = lFindIndent(3, formattedBuf);
364  }
365  // Don't indent too much with long filenames
366  indent = std::min(indent, 8);
367 
368  // Now that we've done all that work, see if we've already printed the
369  // exact same error message. If so, return, so we don't redundantly
370  // print it and annoy the user.
371  static std::set<std::string> printed;
372  if (printed.find(formattedBuf) != printed.end())
373  return;
374  printed.insert(formattedBuf);
375 
376  PrintWithWordBreaks(formattedBuf, indent, TerminalWidth(), stderr);
378 
379  free(errorBuf);
380  free(formattedBuf);
381 }
382 
383 
384 void
385 Error(SourcePos p, const char *fmt, ...) {
386  if (m != NULL) ++m->errorCount;
387  if (g->quiet)
388  return;
389 
390  va_list args;
391  va_start(args, fmt);
392  lPrint("Error", true, p, fmt, args);
393  va_end(args);
394 }
395 
396 
397 void
398 Debug(SourcePos p, const char *fmt, ...) {
399  if (!g->debugPrint || g->quiet)
400  return;
401 
402  va_list args;
403  va_start(args, fmt);
404  lPrint("Debug", false, p, fmt, args);
405  va_end(args);
406 }
407 
408 
409 void
410 Warning(SourcePos p, const char *fmt, ...) {
411  if (g->warningsAsErrors && m != NULL)
412  ++m->errorCount;
413 
414  if (g->disableWarnings || g->quiet)
415  return;
416 
417  va_list args;
418  va_start(args, fmt);
419  lPrint(g->warningsAsErrors ? "Error" : "Warning", g->warningsAsErrors,
420  p, fmt, args);
421  va_end(args);
422 }
423 
424 
425 void
426 PerformanceWarning(SourcePos p, const char *fmt, ...) {
427  if (!g->emitPerfWarnings || strcmp(p.name, "stdlib.ispc") == 0 ||
428  g->quiet)
429  return;
430 
431  va_list args;
432  va_start(args, fmt);
433  lPrint("Performance Warning", false, p, fmt, args);
434  va_end(args);
435 }
436 
437 
438 static void
440  static bool printed = false;
441  if (printed)
442  return;
443 
444  printed = true;
445  fprintf(stderr, "***\n"
446  "*** Please file a bug report at https://github.com/ispc/ispc/issues\n"
447  "*** (Including as much information as you can about how to "
448  "reproduce this error).\n"
449  "*** You have apparently encountered a bug in the compiler that we'd "
450  "like to fix!\n***\n");
451 }
452 
453 
454 void
455 FatalError(const char *file, int line, const char *message) {
456  fprintf(stderr, "%s(%d): FATAL ERROR: %s\n", file, line, message);
457  lPrintBugText();
458  abort();
459 }
460 
461 
462 void
463 DoAssert(const char *file, int line, const char *expr) {
464  fprintf(stderr, "%s:%u: Assertion failed: \"%s\".\n", file, line, expr);
465  lPrintBugText();
466  abort();
467 }
468 
469 
470 void
471 DoAssertPos(SourcePos pos, const char *file, int line, const char *expr) {
472  Error(pos, "Assertion failed (%s:%u): \"%s\".", file, line, expr);
473  lPrintBugText();
474  abort();
475 }
476 
477 
478 ///////////////////////////////////////////////////////////////////////////
479 
480 // http://en.wikipedia.org/wiki/Levenshtein_distance
481 int
482 StringEditDistance(const std::string &str1, const std::string &str2, int maxDist) {
483  // Small hack: don't return 0 if the strings are the same; if we've
484  // gotten here, there's been a parsing error, and suggesting the same
485  // string isn't going to actually help things.
486  if (str1 == str2)
487  return maxDist;
488 
489  int n1 = (int)str1.size(), n2 = (int)str2.size();
490  int nmax = std::max(n1, n2);
491 
492  int *current = (int *)alloca((nmax+1) * sizeof(int));
493  int *previous = (int *)alloca((nmax+1) * sizeof(int));
494 
495  for (int i = 0; i <= n2; ++i)
496  previous[i] = i;
497 
498  for (int y = 1; y <= n1; ++y) {
499  current[0] = y;
500  int rowBest = y;
501 
502  for (int x = 1; x <= n2; ++x) {
503  current[x] = std::min(previous[x-1] + (str1[y-1] == str2[x-1] ? 0 : 1),
504  std::min(current[x-1], previous[x])+1);
505  rowBest = std::min(rowBest, current[x]);
506  }
507 
508  if (maxDist != 0 && rowBest > maxDist)
509  return maxDist + 1;
510 
511  std::swap(current, previous);
512  }
513 
514  return previous[n2];
515 }
516 
517 
518 std::vector<std::string>
519 MatchStrings(const std::string &str, const std::vector<std::string> &options) {
520  if (str.size() == 0 || (str.size() == 1 && !isalpha(str[0])))
521  // don't even try...
522  return std::vector<std::string>();
523 
524  const int maxDelta = 2;
525  std::vector<std::string> matches[maxDelta+1];
526 
527  // For all of the options that are up to maxDelta edit distance, store
528  // them in the element of matches[] that corresponds to their edit
529  // distance.
530  for (int i = 0; i < (int)options.size(); ++i) {
531  int dist = StringEditDistance(str, options[i], maxDelta+1);
532  if (dist <= maxDelta)
533  matches[dist].push_back(options[i]);
534  }
535 
536  // And return the first one of them, if any, that has at least one
537  // match.
538  for (int i = 0; i <= maxDelta; ++i) {
539  if (matches[i].size())
540  return matches[i];
541  }
542  return std::vector<std::string>();
543 }
544 
545 
546 void
547 GetDirectoryAndFileName(const std::string &currentDirectory,
548  const std::string &relativeName,
549  std::string *directory, std::string *filename) {
550 #ifdef ISPC_IS_WINDOWS
551  char path[MAX_PATH];
552  const char *combPath = PathCombine(path, currentDirectory.c_str(),
553  relativeName.c_str());
554  Assert(combPath != NULL);
555  const char *filenamePtr = PathFindFileName(combPath);
556  *filename = filenamePtr;
557  *directory = std::string(combPath, filenamePtr - combPath);
558 #else
559  // We need a fully qualified path. First, see if the current file name
560  // is fully qualified itself--in that case, the current working
561  // directory isn't needed.
562  // @todo This probably needs to be smarter for Windows...
563  std::string fullPath;
564  if (relativeName[0] == '/')
565  fullPath = relativeName;
566  else {
567  fullPath = g->currentDirectory;
568  if (fullPath[fullPath.size()-1] != '/')
569  fullPath.push_back('/');
570  fullPath += relativeName;
571  }
572 
573  // now, we need to separate it into the base name and the directory
574  const char *fp = fullPath.c_str();
575  const char *basenameStart = strrchr(fp, '/');
576  Assert(basenameStart != NULL);
577  ++basenameStart;
578  Assert(basenameStart[0] != '\0');
579  *filename = basenameStart;
580  *directory = std::string(fp, basenameStart - fp);
581 #endif // ISPC_IS_WINDOWS
582 }
583 
584 static std::set<std::string> lGetStringArray(const std::string &str) {
585  std::set<std::string> result;
586 
587  Assert(str.find('-') != str.npos);
588 
589  size_t pos_prev = 0, pos;
590  do {
591  pos = str.find('-', pos_prev);
592  std::string substr = str.substr(pos_prev, pos-pos_prev);
593  result.insert(substr);
594  pos_prev = pos;
595  pos_prev++;
596  } while (pos != str.npos);
597 
598  return result;
599 }
600 
601 
602 bool
603 VerifyDataLayoutCompatibility(const std::string &module_dl,
604  const std::string &lib_dl) {
605  if (lib_dl.empty()) {
606  // This is the case for most of library pre-compiled .ll files.
607  return true;
608  }
609 
610  // Get "canonical" form. Instead of looking at "raw" DataLayout string, we
611  // look at the actual representation, as DataLayout class understands it.
612  // In the most cases there's no difference. But on x86 Windows (i386-pc-win32),
613  // clang generates a DataLayout string, which contains two definitions of f80,
614  // which contradic: f80:128:128 followed by f80:32:32. This is a bug, but
615  // correct thing to do is to interpret this exactly how LLVM would treat it,
616  // so we create a DataLayout class and take its string representation.
617 
618  llvm::DataLayout d1(module_dl);
619  llvm::DataLayout d2(lib_dl);
620 
621  std::string module_dl_canonic = d1.getStringRepresentation();
622  std::string lib_dl_canonic = d2.getStringRepresentation();
623 
624  // Break down DataLayout strings to separate type definitions.
625  std::set<std::string> module_dl_set = lGetStringArray(module_dl_canonic);
626  std::set<std::string> lib_dl_set = lGetStringArray(lib_dl_canonic);
627 
628  // For each element in library data layout, find matching module element.
629  // If no match is found, then we are in trouble and the library can't be used.
630  for (std::set<std::string>::iterator it = lib_dl_set.begin();
631  it != lib_dl_set.end(); ++it) {
632  // We use the simplest possible definition of "match", which is match exactly.
633  // Ideally it should be relaxed and for triples [p|i|v|f|a|s]<size>:<abi>:<pref>
634  // we should allow <pref> part (preferred alignment) to not match.
635  // But this seems to have no practical value at this point.
636  std::set<std::string>::iterator module_match =
637  std::find(module_dl_set.begin(), module_dl_set.end(), *it);
638  if (module_match == module_dl_set.end()) {
639  // No match for this piece of library DataLayout was found,
640  // return false.
641  return false;
642  }
643  // Remove matching piece from Module set.
644  module_dl_set.erase(module_match);
645  }
646 
647  // We allow extra types to be defined in the Module, but we should check
648  // that it's something that we expect. And we expect vectors and floats.
649  for (std::set<std::string>::iterator it = module_dl_set.begin();
650  it != module_dl_set.end(); ++it) {
651  if ((*it)[0] == 'v' || (*it)[0] == 'f') {
652  continue;
653  }
654  return false;
655  }
656 
657  return true;
658 }
659 
static const char * lStartBold()
Definition: util.cpp:114
static void lPrintBugText()
Definition: util.cpp:439
int last_column
Definition: ispc.h:142
bool disableWarnings
Definition: ispc.h:579
Module * m
Definition: ispc.cpp:89
int TerminalWidth()
Definition: util.cpp:81
int first_line
Definition: ispc.h:139
bool forceColoredOutput
Definition: ispc.h:597
bool emitPerfWarnings
Definition: ispc.h:590
bool warningsAsErrors
Definition: ispc.h:582
#define Assert(expr)
Definition: ispc.h:170
static const char * lStartRed()
Definition: util.cpp:123
bool disableLineWrap
Definition: ispc.h:586
std::vector< std::string > MatchStrings(const std::string &str, const std::vector< std::string > &options)
Definition: util.cpp:519
bool VerifyDataLayoutCompatibility(const std::string &module_dl, const std::string &lib_dl)
Definition: util.cpp:603
void FatalError(const char *file, int line, const char *message)
Definition: util.cpp:455
static const char * lResetColor()
Definition: util.cpp:141
Globals * g
Definition: ispc.cpp:88
void PerformanceWarning(SourcePos p, const char *fmt,...)
Definition: util.cpp:426
bool debugPrint
Definition: ispc.h:560
static void lPrintFileLineContext(SourcePos p)
Definition: util.cpp:164
void DoAssertPos(SourcePos pos, const char *file, int line, const char *expr)
Definition: util.cpp:471
char currentDirectory[1024]
Definition: ispc.h:636
void GetDirectoryAndFileName(const std::string &currentDirectory, const std::string &relativeName, std::string *directory, std::string *filename)
Definition: util.cpp:547
static const char * lStartBlue()
Definition: util.cpp:132
Representation of a range of positions in a source file.
Definition: ispc.h:134
static bool lHaveANSIColors()
Definition: util.cpp:102
const char * name
Definition: ispc.h:138
static const char * lFindWordEnd(const char *buf)
Definition: util.cpp:152
void Error(SourcePos p, const char *fmt,...)
Definition: util.cpp:385
int last_line
Definition: ispc.h:141
int first_column
Definition: ispc.h:140
int StringEditDistance(const std::string &str1, const std::string &str2, int maxDist)
Definition: util.cpp:482
static void lPrint(const char *type, bool isError, SourcePos p, const char *fmt, va_list args)
Definition: util.cpp:333
static int lFindIndent(int numColons, const char *buf)
Definition: util.cpp:204
void Debug(SourcePos p, const char *fmt,...)
Definition: util.cpp:398
void PrintWithWordBreaks(const char *buf, int indent, int columnWidth, FILE *out)
Definition: util.cpp:230
static std::set< std::string > lGetStringArray(const std::string &str)
Definition: util.cpp:584
bool quiet
Definition: ispc.h:593
Declaration of the Module class, which is the ispc-side representation of the results of compiling a ...
int errorCount
Definition: module.h:151
void Warning(SourcePos p, const char *fmt,...)
Definition: util.cpp:410
void DoAssert(const char *file, int line, const char *expr)
Definition: util.cpp:463