Intel® Implicit SPMD Program Compiler (Intel® ISPC)  1.13.0
module.cpp
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 module.cpp
35  @brief Impementation of the Module class, which collects the result of compiling
36  a source file and then generates output (object files, etc.)
37 */
38 
39 #include "module.h"
40 #include "builtins.h"
41 #include "ctx.h"
42 #include "expr.h"
43 #include "func.h"
44 #include "llvmutil.h"
45 #include "opt.h"
46 #include "stmt.h"
47 #include "sym.h"
48 #include "type.h"
49 #include "util.h"
50 
51 #include <algorithm>
52 #include <ctype.h>
53 #include <fcntl.h>
54 #include <set>
55 #include <sstream>
56 #include <stdarg.h>
57 #include <stdio.h>
58 #include <sys/stat.h>
59 #include <sys/types.h>
60 #ifdef ISPC_HOST_IS_WINDOWS
61 #include <io.h>
62 #include <windows.h>
63 #define strcasecmp stricmp
64 #endif
65 #include "llvm/IR/LegacyPassManager.h"
66 #include <clang/Basic/TargetInfo.h>
67 #include <clang/Frontend/CompilerInstance.h>
68 #include <clang/Frontend/TextDiagnosticPrinter.h>
69 #include <clang/Frontend/Utils.h>
70 #include <clang/Lex/PreprocessorOptions.h>
71 #include <llvm/Analysis/TargetTransformInfo.h>
72 #include <llvm/Bitcode/BitcodeWriter.h>
73 #include <llvm/IR/CFG.h>
74 #include <llvm/IR/DataLayout.h>
75 #include <llvm/IR/DerivedTypes.h>
76 #include <llvm/IR/IRPrintingPasses.h>
77 #include <llvm/IR/InstIterator.h>
78 #include <llvm/IR/Instructions.h>
79 #include <llvm/IR/Intrinsics.h>
80 #include <llvm/IR/LLVMContext.h>
81 #include <llvm/IR/Module.h>
82 #include <llvm/IR/Type.h>
83 #include <llvm/IR/Verifier.h>
84 #include <llvm/PassRegistry.h>
85 #include <llvm/Support/FileUtilities.h>
86 #include <llvm/Support/FormattedStream.h>
87 #include <llvm/Support/Host.h>
88 #include <llvm/Support/ToolOutputFile.h>
89 #include <llvm/Support/raw_ostream.h>
90 #include <llvm/Target/TargetMachine.h>
91 #include <llvm/Target/TargetOptions.h>
92 #include <llvm/Transforms/IPO.h>
93 #include <llvm/Transforms/Utils/ValueMapper.h>
94 
95 /*! list of files encountered by the parser. this allows emitting of
96  the module file's dependencies via the -MMM option */
97 std::set<std::string> registeredDependencies;
98 
99 /*! this is where the parser tells us that it has seen the given file
100  name in the CPP hash */
101 void RegisterDependency(const std::string &fileName) {
102  if (fileName[0] != '<' && fileName != "stdlib.ispc")
103  registeredDependencies.insert(fileName);
104 }
105 
106 static void lDeclareSizeAndPtrIntTypes(SymbolTable *symbolTable) {
108  ptrIntType = ptrIntType->GetAsUnboundVariabilityType();
109 
110  symbolTable->AddType("intptr_t", ptrIntType, SourcePos());
111  symbolTable->AddType("uintptr_t", ptrIntType->GetAsUnsignedType(), SourcePos());
112  symbolTable->AddType("ptrdiff_t", ptrIntType, SourcePos());
113 
114  const Type *sizeType =
116  sizeType = sizeType->GetAsUnboundVariabilityType();
117  symbolTable->AddType("size_t", sizeType, SourcePos());
118 }
119 
120 /** After compilation completes, there's often a lot of extra debugging
121  metadata left around that isn't needed any more--for example, for
122  static functions that weren't actually used, function information for
123  functions that were inlined, etc. This function takes a llvm::Module
124  and tries to strip out all of this extra stuff.
125  */
126 static void lStripUnusedDebugInfo(llvm::Module *module) { return; }
127 
128 ///////////////////////////////////////////////////////////////////////////
129 // Module
130 
131 Module::Module(const char *fn) {
132  // It's a hack to do this here, but it must be done after the target
133  // information has been set (so e.g. the vector width is known...) In
134  // particular, if we're compiling to multiple targets with different
135  // vector widths, this needs to be redone each time through.
136  InitLLVMUtil(g->ctx, *g->target);
137 
138  filename = fn;
139  errorCount = 0;
140  symbolTable = new SymbolTable;
141  ast = new AST;
142 
144 
145  module = new llvm::Module(!IsStdin(filename) ? filename : "<stdin>", *g->ctx);
146  module->setTargetTriple(g->target->GetTripleString());
147 
148  diBuilder = NULL;
149  diCompileUnit = NULL;
150 
151  // DataLayout information supposed to be managed in single place in Target class.
152  module->setDataLayout(g->target->getDataLayout()->getStringRepresentation());
153 
155  // To enable debug information on Windows, we have to let llvm know, that
156  // debug information should be emitted in CodeView format.
157  if (g->target_os == TargetOS::windows) {
158  module->addModuleFlag(llvm::Module::Warning, "CodeView", 1);
159  } else {
160  module->addModuleFlag(llvm::Module::Warning, "Dwarf Version", g->generateDWARFVersion);
161  }
162  diBuilder = new llvm::DIBuilder(*module);
163 
164  // Let the DIBuilder know that we're starting a new compilation
165  // unit.
166  if (IsStdin(filename)) {
167  // Unfortunately we can't yet call Error() since the global 'm'
168  // variable hasn't been initialized yet.
169  Error(SourcePos(), "Can't emit debugging information with no "
170  "source file on disk.\n");
171  ++errorCount;
172  delete diBuilder;
173  diBuilder = NULL;
174  } else {
175  std::string directory, name;
176  GetDirectoryAndFileName(g->currentDirectory, filename, &directory, &name);
177  char producerString[512];
178 #if defined(BUILD_VERSION) && defined(BUILD_DATE)
179  snprintf(producerString, sizeof(producerString), "ispc version %s (build %s on %s)", ISPC_VERSION,
180  BUILD_VERSION, BUILD_DATE);
181 #else
182  snprintf(producerString, sizeof(producerString), "ispc version %s (built on %s)", ISPC_VERSION, __DATE__);
183 #endif
184  auto srcFile = diBuilder->createFile(name, directory);
185  diCompileUnit =
186  diBuilder->createCompileUnit(llvm::dwarf::DW_LANG_C99, /* lang */
187  srcFile, /* filename */
188  producerString, /* producer */
189  g->opt.level > 0 /* is optimized */, "-g", /* command line args */
190  0 /* run time version */);
191  }
192  }
193 }
194 
195 extern FILE *yyin;
196 extern int yyparse();
197 typedef struct yy_buffer_state *YY_BUFFER_STATE;
199 extern YY_BUFFER_STATE yy_scan_string(const char *);
200 extern YY_BUFFER_STATE yy_create_buffer(FILE *, int);
201 extern void yy_delete_buffer(YY_BUFFER_STATE);
202 
204  extern void ParserInit();
205  ParserInit();
206 
207  // FIXME: it'd be nice to do this in the Module constructor, but this
208  // function ends up calling into routines that expect the global
209  // variable 'm' to be initialized and available (which it isn't until
210  // the Module constructor returns...)
212 
213  bool runPreprocessor = g->runCPP;
214 
215  if (runPreprocessor) {
216  if (!IsStdin(filename)) {
217  // Try to open the file first, since otherwise we crash in the
218  // preprocessor if the file doesn't exist.
219  FILE *f = fopen(filename, "r");
220  if (!f) {
221  perror(filename);
222  return 1;
223  }
224  fclose(f);
225  }
226 
227  std::string buffer;
228  llvm::raw_string_ostream os(buffer);
229  execPreprocessor(!IsStdin(filename) ? filename : "-", &os);
230  YY_BUFFER_STATE strbuf = yy_scan_string(os.str().c_str());
231  yyparse();
232  yy_delete_buffer(strbuf);
233  } else {
234  // No preprocessor, just open up the file if it's not stdin..
235  FILE *f = NULL;
236  if (IsStdin(filename)) {
237  f = stdin;
238  } else {
239  f = fopen(filename, "r");
240  if (f == NULL) {
241  perror(filename);
242  return 1;
243  }
244  }
245  yyin = f;
247  yyparse();
248  fclose(f);
249  }
250 
251  if (g->NoOmitFramePointer)
252  for (llvm::Function &f : *module)
253  f.addFnAttr("no-frame-pointer-elim", "true");
254  for (llvm::Function &f : *module)
256  ast->GenerateIR();
257 
258  if (diBuilder)
259  diBuilder->finalize();
260  if (errorCount == 0)
261  Optimize(module, g->opt.level);
262 
263  return errorCount;
264 }
265 
266 void Module::AddTypeDef(const std::string &name, const Type *type, SourcePos pos) {
267  // Typedefs are easy; just add the mapping between the given name and
268  // the given type.
269  symbolTable->AddType(name.c_str(), type, pos);
270 }
271 
272 void Module::AddGlobalVariable(const std::string &name, const Type *type, Expr *initExpr, bool isConst,
273  StorageClass storageClass, SourcePos pos) {
274  // These may be NULL due to errors in parsing; just gracefully return
275  // here if so.
276  if (name == "" || type == NULL) {
277  Assert(errorCount > 0);
278  return;
279  }
280 
281  if (symbolTable->LookupFunction(name.c_str())) {
282  Error(pos,
283  "Global variable \"%s\" shadows previously-declared "
284  "function.",
285  name.c_str());
286  return;
287  }
288 
289  if (storageClass == SC_EXTERN_C) {
290  Error(pos, "extern \"C\" qualifier can only be used for "
291  "functions.");
292  return;
293  }
294 
295  if (type->IsVoidType()) {
296  Error(pos, "\"void\" type global variable is illegal.");
297  return;
298  }
299 
300  type = ArrayType::SizeUnsizedArrays(type, initExpr);
301  if (type == NULL)
302  return;
303 
304  const ArrayType *at = CastType<ArrayType>(type);
305  if (at != NULL && at->TotalElementCount() == 0) {
306  Error(pos, "Illegal to declare a global variable with unsized "
307  "array dimensions that aren't set with an initializer "
308  "expression.");
309  return;
310  }
311 
312  llvm::Type *llvmType = type->LLVMStorageType(g->ctx);
313  if (llvmType == NULL)
314  return;
315 
316  // See if we have an initializer expression for the global. If so,
317  // make sure it's a compile-time constant!
318  llvm::Constant *llvmInitializer = NULL;
319  ConstExpr *constValue = NULL;
320  if (storageClass == SC_EXTERN) {
321  if (initExpr != NULL)
322  Error(pos,
323  "Initializer can't be provided with \"extern\" "
324  "global variable \"%s\".",
325  name.c_str());
326  } else {
327  if (initExpr != NULL) {
328  initExpr = TypeCheck(initExpr);
329  if (initExpr != NULL) {
330  // We need to make sure the initializer expression is
331  // the same type as the global. (But not if it's an
332  // ExprList; they don't have types per se / can't type
333  // convert themselves anyway.)
334  if (llvm::dyn_cast<ExprList>(initExpr) == NULL)
335  initExpr = TypeConvertExpr(initExpr, type, "initializer");
336 
337  if (initExpr != NULL) {
338  initExpr = Optimize(initExpr);
339  // Fingers crossed, now let's see if we've got a
340  // constant value..
341  std::pair<llvm::Constant *, bool> initPair = initExpr->GetStorageConstant(type);
342  llvmInitializer = initPair.first;
343 
344  // If compiling for multitarget, skip initialization for
345  // indentified scenarios unless it's static
346  if (llvmInitializer != NULL) {
347  if ((storageClass != SC_STATIC) && (initPair.second == true)) {
348  if (g->isMultiTargetCompilation == true) {
349  Error(initExpr->pos,
350  "Initializer for global variable \"%s\" "
351  "is not a constant for multi-target compilation.",
352  name.c_str());
353  return;
354  }
355  Warning(initExpr->pos,
356  "Initializer for global variable \"%s\" "
357  "is a constant for single-target compilation "
358  "but not for multi-target compilation.",
359  name.c_str());
360  }
361 
362  if (type->IsConstType())
363  // Try to get a ConstExpr associated with
364  // the symbol. This llvm::dyn_cast can
365  // validly fail, for example for types like
366  // StructTypes where a ConstExpr can't
367  // represent their values.
368  constValue = llvm::dyn_cast<ConstExpr>(initExpr);
369  } else
370  Error(initExpr->pos,
371  "Initializer for global variable \"%s\" "
372  "must be a constant.",
373  name.c_str());
374  }
375  }
376  }
377 
378  // If no initializer was provided or if we couldn't get a value
379  // above, initialize it with zeros..
380  if (llvmInitializer == NULL)
381  llvmInitializer = llvm::Constant::getNullValue(llvmType);
382  }
383 
384  Symbol *sym = symbolTable->LookupVariable(name.c_str());
385  llvm::GlobalVariable *oldGV = NULL;
386  if (sym != NULL) {
387  // We've already seen either a declaration or a definition of this
388  // global.
389 
390  // If the type doesn't match with the previous one, issue an error.
391  if (!Type::Equal(sym->type, type) ||
392  (sym->storageClass != SC_EXTERN && sym->storageClass != SC_EXTERN_C && sym->storageClass != storageClass)) {
393  Error(pos,
394  "Definition of variable \"%s\" conflicts with "
395  "definition at %s:%d.",
396  name.c_str(), sym->pos.name, sym->pos.first_line);
397  return;
398  }
399 
400  llvm::GlobalVariable *gv = llvm::dyn_cast<llvm::GlobalVariable>(sym->storagePtr);
401  Assert(gv != NULL);
402 
403  // And issue an error if this is a redefinition of a variable
404  if (gv->hasInitializer() && sym->storageClass != SC_EXTERN && sym->storageClass != SC_EXTERN_C) {
405  Error(pos,
406  "Redefinition of variable \"%s\" is illegal. "
407  "(Previous definition at %s:%d.)",
408  sym->name.c_str(), sym->pos.name, sym->pos.first_line);
409  return;
410  }
411 
412  // Now, we either have a redeclaration of a global, or a definition
413  // of a previously-declared global. First, save the pointer to the
414  // previous llvm::GlobalVariable
415  oldGV = gv;
416  } else {
417  sym = new Symbol(name, pos, type, storageClass);
418  symbolTable->AddVariable(sym);
419  }
420  sym->constValue = constValue;
421 
422  llvm::GlobalValue::LinkageTypes linkage =
423  (sym->storageClass == SC_STATIC) ? llvm::GlobalValue::InternalLinkage : llvm::GlobalValue::ExternalLinkage;
424 
425  // Note that the NULL llvmInitializer is what leads to "extern"
426  // declarations coming up extern and not defining storage (a bit
427  // subtle)...
428  sym->storagePtr = new llvm::GlobalVariable(*module, llvmType, isConst, linkage, llvmInitializer, sym->name.c_str());
429 
430  // Patch up any references to the previous GlobalVariable (e.g. from a
431  // declaration of a global that was later defined.)
432  if (oldGV != NULL) {
433  oldGV->replaceAllUsesWith(sym->storagePtr);
434  oldGV->removeFromParent();
435  sym->storagePtr->setName(sym->name.c_str());
436  }
437 
438  if (diBuilder) {
439  llvm::DIFile *file = pos.GetDIFile();
440  // llvm::MDFile *file = pos.GetDIFile();
441  llvm::GlobalVariable *sym_GV_storagePtr = llvm::dyn_cast<llvm::GlobalVariable>(sym->storagePtr);
442  Assert(sym_GV_storagePtr);
443  llvm::DIGlobalVariableExpression *var = diBuilder->createGlobalVariableExpression(
444  file, name, name, file, pos.first_line, sym->type->GetDIType(file), (sym->storageClass == SC_STATIC));
445  sym_GV_storagePtr->addDebugInfo(var);
446  /*#if ISPC_LLVM_VERSION <= ISPC_LLVM_3_6
447  Assert(var.Verify());
448  #else // LLVM 3.7+
449  // comming soon
450  #endif*/
451  }
452 }
453 
454 /** Given an arbitrary type, see if it or any of the leaf types contained
455  in it has a type that's illegal to have exported to C/C++
456  code.
457 
458  (Note that it's fine for the original struct or a contained struct to
459  be varying, so long as all of its members have bound 'uniform'
460  variability.)
461 
462  This functions returns true and issues an error if are any illegal
463  types are found and returns false otherwise.
464 */
465 static bool lRecursiveCheckValidParamType(const Type *t, bool vectorOk) {
466  const StructType *st = CastType<StructType>(t);
467  if (st != NULL) {
468  for (int i = 0; i < st->GetElementCount(); ++i)
469  if (!lRecursiveCheckValidParamType(st->GetElementType(i), vectorOk))
470  return false;
471  return true;
472  }
473 
474  // Vector types are also not supported, pending ispc properly
475  // supporting the platform ABI. (Pointers to vector types are ok,
476  // though.) (https://github.com/ispc/ispc/issues/363)...
477  if (vectorOk == false && CastType<VectorType>(t) != NULL)
478  return false;
479 
480  const SequentialType *seqt = CastType<SequentialType>(t);
481  if (seqt != NULL)
482  return lRecursiveCheckValidParamType(seqt->GetElementType(), vectorOk);
483 
484  const PointerType *pt = CastType<PointerType>(t);
485  if (pt != NULL) {
486  // Only allow exported uniform pointers
487  // Uniform pointers to varying data, however, are ok.
488  if (pt->IsVaryingType())
489  return false;
490  else
491  return lRecursiveCheckValidParamType(pt->GetBaseType(), true);
492  }
493 
494  if (t->IsVaryingType() && !vectorOk)
495  return false;
496  else
497  return true;
498 }
499 
500 /** Given a Symbol representing a function parameter, see if it or any
501  contained types are varying. If so, issue an error. (This function
502  should only be called for parameters to 'export'ed functions, where
503  varying parameters is illegal.
504  */
505 static void lCheckExportedParameterTypes(const Type *type, const std::string &name, SourcePos pos) {
506  if (lRecursiveCheckValidParamType(type, false) == false) {
507  if (CastType<PointerType>(type))
508  Error(pos,
509  "Varying pointer type parameter \"%s\" is illegal "
510  "in an exported function.",
511  name.c_str());
512  if (CastType<StructType>(type->GetBaseType()))
513  Error(pos,
514  "Struct parameter \"%s\" with vector typed "
515  "member(s) is illegal in an exported function.",
516  name.c_str());
517  else if (CastType<VectorType>(type))
518  Error(pos,
519  "Vector-typed parameter \"%s\" is illegal in an exported "
520  "function.",
521  name.c_str());
522  else
523  Error(pos, "Varying parameter \"%s\" is illegal in an exported function.", name.c_str());
524  }
525 }
526 
527 /** Given a function type, loop through the function parameters and see if
528  any are StructTypes. If so, issue an error; this is currently broken
529  (https://github.com/ispc/ispc/issues/3).
530  */
531 static void lCheckForStructParameters(const FunctionType *ftype, SourcePos pos) {
532  for (int i = 0; i < ftype->GetNumParameters(); ++i) {
533  const Type *type = ftype->GetParameterType(i);
534  if (CastType<StructType>(type) != NULL) {
535  Error(pos, "Passing structs to/from application functions by value "
536  "is currently not supported. Use a reference, a const reference, "
537  "a pointer, or a const pointer to the struct instead.");
538  return;
539  }
540  }
541 }
542 
543 /** We've got a declaration for a function to process. This function does
544  all the work of creating the corresponding llvm::Function instance,
545  adding the symbol for the function to the symbol table and doing
546  various sanity checks. This function returns true upon success and
547  false if any errors were encountered.
548  */
549 void Module::AddFunctionDeclaration(const std::string &name, const FunctionType *functionType,
550  StorageClass storageClass, bool isInline, bool isNoInline, SourcePos pos) {
551  Assert(functionType != NULL);
552 
553  // If a global variable with the same name has already been declared
554  // issue an error.
555  if (symbolTable->LookupVariable(name.c_str()) != NULL) {
556  Error(pos,
557  "Function \"%s\" shadows previously-declared global variable. "
558  "Ignoring this definition.",
559  name.c_str());
560  return;
561  }
562 
563  std::vector<Symbol *> overloadFuncs;
564  symbolTable->LookupFunction(name.c_str(), &overloadFuncs);
565  if (overloadFuncs.size() > 0) {
566  for (unsigned int i = 0; i < overloadFuncs.size(); ++i) {
567  Symbol *overloadFunc = overloadFuncs[i];
568 
569  const FunctionType *overloadType = CastType<FunctionType>(overloadFunc->type);
570  if (overloadType == NULL) {
571  Assert(m->errorCount == 0);
572  continue;
573  }
574 
575  // Check for a redeclaration of a function with the same name
576  // and type. This also hits when we have previously declared
577  // the function and are about to define it.
578  if (Type::Equal(overloadFunc->type, functionType))
579  return;
580 
581  if (functionType->isExported || overloadType->isExported)
582  Error(pos,
583  "Illegal to provide \"export\" qualifier for "
584  "functions with the same name but different types. "
585  "(Previous function declaration (%s:%d).)",
586  overloadFunc->pos.name, overloadFunc->pos.first_line);
587 
588  // If all of the parameter types match but the return type is
589  // different, return an error--overloading by return type isn't
590  // allowed.
591  const FunctionType *ofType = CastType<FunctionType>(overloadFunc->type);
592  Assert(ofType != NULL);
593  if (ofType->GetNumParameters() == functionType->GetNumParameters()) {
594  int i;
595  for (i = 0; i < functionType->GetNumParameters(); ++i) {
596  if (Type::Equal(ofType->GetParameterType(i), functionType->GetParameterType(i)) == false)
597  break;
598  }
599  if (i == functionType->GetNumParameters()) {
600  std::string thisRetType = functionType->GetReturnTypeString();
601  std::string otherRetType = ofType->GetReturnTypeString();
602  Error(pos,
603  "Illegal to overload function by return "
604  "type only. This function returns \"%s\" while "
605  "previous declaration at %s:%d returns \"%s\".",
606  thisRetType.c_str(), overloadFunc->pos.name, overloadFunc->pos.first_line,
607  otherRetType.c_str());
608  return;
609  }
610  }
611  }
612  }
613 
614  if (storageClass == SC_EXTERN_C) {
615  // Make sure the user hasn't supplied both an 'extern "C"' and a
616  // 'task' qualifier with the function
617  if (functionType->isTask) {
618  Error(pos,
619  "\"task\" qualifier is illegal with C-linkage extern "
620  "function \"%s\". Ignoring this function.",
621  name.c_str());
622  return;
623  }
624 
625  std::vector<Symbol *> funcs;
626  symbolTable->LookupFunction(name.c_str(), &funcs);
627  if (funcs.size() > 0) {
628  if (funcs.size() > 1) {
629  // Multiple functions with this name have already been declared;
630  // can't overload here
631  Error(pos,
632  "Can't overload extern \"C\" function \"%s\"; "
633  "%d functions with the same name have already been declared.",
634  name.c_str(), (int)funcs.size());
635  return;
636  }
637 
638  // One function with the same name has been declared; see if it
639  // has the same type as this one, in which case it's ok.
640  if (Type::Equal(funcs[0]->type, functionType))
641  return;
642  else {
643  Error(pos, "Can't overload extern \"C\" function \"%s\".", name.c_str());
644  return;
645  }
646  }
647  }
648 
649  // Get the LLVM FunctionType
650  bool disableMask = (storageClass == SC_EXTERN_C);
651  llvm::FunctionType *llvmFunctionType = functionType->LLVMFunctionType(g->ctx, disableMask);
652  if (llvmFunctionType == NULL)
653  return;
654 
655  // And create the llvm::Function
656  llvm::GlobalValue::LinkageTypes linkage = (storageClass == SC_STATIC || isInline)
657  ? llvm::GlobalValue::InternalLinkage
658  : llvm::GlobalValue::ExternalLinkage;
659 
660  std::string functionName = name;
661  if (storageClass != SC_EXTERN_C) {
662  functionName += functionType->Mangle();
663  // If we treat generic as smth, we should have appropriate mangling
665  functionName += g->target->GetISAString();
666  }
667  }
668  llvm::Function *function = llvm::Function::Create(llvmFunctionType, linkage, functionName.c_str(), module);
669 
670  if (g->target_os == TargetOS::windows) {
671  // Make export functions callable from DLLs.
672  if ((g->dllExport) && (storageClass != SC_STATIC)) {
673  function->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
674  }
675  }
676 
677  if (isNoInline && isInline) {
678  Error(pos, "Illegal to use \"noinline\" and \"inline\" qualifiers together on function \"%s\".", name.c_str());
679  return;
680  }
681  // Set function attributes: we never throw exceptions
682  function->setDoesNotThrow();
683  if (storageClass != SC_EXTERN_C && isInline) {
684  function->addFnAttr(llvm::Attribute::AlwaysInline);
685  }
686 
687  if (isNoInline) {
688  function->addFnAttr(llvm::Attribute::NoInline);
689  }
690 
691  if (functionType->isTask) {
692  // This also applies transitively to members I think?
693  function->addParamAttr(0, llvm::Attribute::NoAlias);
694  }
695 
696  g->target->markFuncWithTargetAttr(function);
697 
698  // Make sure that the return type isn't 'varying' or vector typed if
699  // the function is 'export'ed.
700  if (functionType->isExported && lRecursiveCheckValidParamType(functionType->GetReturnType(), false) == false)
701  Error(pos,
702  "Illegal to return a \"varying\" or vector type from "
703  "exported function \"%s\"",
704  name.c_str());
705 
706  if (functionType->isTask && functionType->GetReturnType()->IsVoidType() == false)
707  Error(pos, "Task-qualified functions must have void return type.");
708 
709  if (functionType->isExported || functionType->isExternC)
710  lCheckForStructParameters(functionType, pos);
711 
712  // Loop over all of the arguments; process default values if present
713  // and do other checks and parameter attribute setting.
714  bool seenDefaultArg = false;
715  int nArgs = functionType->GetNumParameters();
716  for (int i = 0; i < nArgs; ++i) {
717  const Type *argType = functionType->GetParameterType(i);
718  const std::string &argName = functionType->GetParameterName(i);
719  Expr *defaultValue = functionType->GetParameterDefault(i);
720  const SourcePos &argPos = functionType->GetParameterSourcePos(i);
721 
722  // If the function is exported, make sure that the parameter
723  // doesn't have any funky stuff going on in it.
724  // JCB nomosoa - Varying is now a-ok.
725  if (functionType->isExported) {
726  lCheckExportedParameterTypes(argType, argName, argPos);
727  }
728 
729  // ISPC assumes that no pointers alias. (It should be possible to
730  // specify when this is not the case, but this should be the
731  // default.) Set parameter attributes accordingly. (Only for
732  // uniform pointers, since varying pointers are int vectors...)
733  if (!functionType->isTask && ((CastType<PointerType>(argType) != NULL && argType->IsUniformType() &&
734  // Exclude SOA argument because it is a pair {struct *, int}
735  // instead of pointer
736  !CastType<PointerType>(argType)->IsSlice()) ||
737 
738  CastType<ReferenceType>(argType) != NULL)) {
739 
740  function->addParamAttr(i, llvm::Attribute::NoAlias);
741 #if 0
742  int align = 4 * RoundUpPow2(g->target->nativeVectorWidth);
743  function->addAttribute(i+1, llvm::Attribute::constructAlignmentFromInt(align));
744 #endif
745  }
746 
747  if (symbolTable->LookupFunction(argName.c_str()))
748  Warning(argPos,
749  "Function parameter \"%s\" shadows a function "
750  "declared in global scope.",
751  argName.c_str());
752 
753  if (defaultValue != NULL)
754  seenDefaultArg = true;
755  else if (seenDefaultArg) {
756  // Once one parameter has provided a default value, then all of
757  // the following ones must have them as well.
758  Error(argPos,
759  "Parameter \"%s\" is missing default: all "
760  "parameters after the first parameter with a default value "
761  "must have default values as well.",
762  argName.c_str());
763  }
764  }
765 
766  // If llvm gave us back a Function * with a different name than the one
767  // we asked for, then there's already a function with that same
768  // (mangled) name in the llvm::Module. In that case, erase the one we
769  // tried to add and just work with the one it already had.
770  if (function->getName() != functionName) {
771  function->eraseFromParent();
772  function = module->getFunction(functionName);
773  }
774 
775  // Finally, we know all is good and we can add the function to the
776  // symbol table
777  Symbol *funSym = new Symbol(name, pos, functionType, storageClass);
778  funSym->function = function;
779  bool ok = symbolTable->AddFunction(funSym);
780  Assert(ok);
781 }
782 
783 void Module::AddFunctionDefinition(const std::string &name, const FunctionType *type, Stmt *code) {
784  Symbol *sym = symbolTable->LookupFunction(name.c_str(), type);
785  if (sym == NULL || code == NULL) {
786  Assert(m->errorCount > 0);
787  return;
788  }
789 
790  sym->pos = code->pos;
791 
792  // FIXME: because we encode the parameter names in the function type,
793  // we need to override the function type here in case the function had
794  // earlier been declared with anonymous parameter names but is now
795  // defined with actual names. This is yet another reason we shouldn't
796  // include the names in FunctionType...
797  sym->type = type;
798 
799  ast->AddFunction(sym, code);
800 }
801 
802 void Module::AddExportedTypes(const std::vector<std::pair<const Type *, SourcePos>> &types) {
803  for (int i = 0; i < (int)types.size(); ++i) {
804  if (CastType<StructType>(types[i].first) == NULL && CastType<VectorType>(types[i].first) == NULL &&
805  CastType<EnumType>(types[i].first) == NULL)
806  Error(types[i].second,
807  "Only struct, vector, and enum types, "
808  "not \"%s\", are allowed in type export lists.",
809  types[i].first->GetString().c_str());
810  else
811  exportedTypes.push_back(types[i]);
812  }
813 }
814 
815 bool Module::writeOutput(OutputType outputType, OutputFlags flags, const char *outFileName, const char *includeFileName,
816  const char *sourceFileName, DispatchHeaderInfo *DHI) {
817  if (diBuilder && (outputType != Header) && (outputType != Deps))
819 
820  Assert(module);
821 
822  // In LLVM_3_4 after r195494 and r195504 revisions we should pass
823  // "Debug Info Version" constant to the module. LLVM will ignore
824  // our Debug Info metadata without it.
825  if (g->generateDebuggingSymbols == true) {
826  module->addModuleFlag(llvm::Module::Warning, "Debug Info Version", llvm::DEBUG_METADATA_VERSION);
827  }
828 
829  // SIC! (verifyModule() == TRUE) means "failed", see llvm-link code.
830  if ((outputType != Header) && (outputType != Deps) && (outputType != HostStub) && (outputType != DevStub) &&
831  llvm::verifyModule(*module)) {
832  FATAL("Resulting module verification failed!");
833  }
834 
835  if (outFileName) {
836  // First, issue a warning if the output file suffix and the type of
837  // file being created seem to mismatch. This can help catch missing
838  // command-line arguments specifying the output file type.
839  const char *suffix = strrchr(outFileName, '.');
840  if (suffix != NULL) {
841  ++suffix;
842  const char *fileType = NULL;
843  switch (outputType) {
844  case Asm:
845  if (strcasecmp(suffix, "s"))
846  fileType = "assembly";
847  break;
848  case Bitcode:
849  if (strcasecmp(suffix, "bc"))
850  fileType = "LLVM bitcode";
851  break;
852  case BitcodeText:
853  if (strcasecmp(suffix, "ll"))
854  fileType = "LLVM assembly";
855  break;
856  case Object:
857  if (strcasecmp(suffix, "o") && strcasecmp(suffix, "obj"))
858  fileType = "object";
859  break;
860  case CXX:
861  if (strcasecmp(suffix, "c") && strcasecmp(suffix, "cc") && strcasecmp(suffix, "c++") &&
862  strcasecmp(suffix, "cxx") && strcasecmp(suffix, "cpp"))
863  fileType = "c++";
864  break;
865  case Header:
866  if (strcasecmp(suffix, "h") && strcasecmp(suffix, "hh") && strcasecmp(suffix, "hpp"))
867  fileType = "header";
868  break;
869  case Deps:
870  break;
871  case DevStub:
872  if (strcasecmp(suffix, "c") && strcasecmp(suffix, "cc") && strcasecmp(suffix, "c++") &&
873  strcasecmp(suffix, "cxx") && strcasecmp(suffix, "cpp"))
874  fileType = "dev-side offload stub";
875  break;
876  case HostStub:
877  if (strcasecmp(suffix, "c") && strcasecmp(suffix, "cc") && strcasecmp(suffix, "c++") &&
878  strcasecmp(suffix, "cxx") && strcasecmp(suffix, "cpp"))
879  fileType = "host-side offload stub";
880  break;
881  default:
882  Assert(0 /* swtich case not handled */);
883  return 1;
884  }
885  if (fileType != NULL)
886  Warning(SourcePos(),
887  "Emitting %s file, but filename \"%s\" "
888  "has suffix \"%s\"?",
889  fileType, outFileName, suffix);
890  }
891  }
892  if (outputType == Header) {
893  if (DHI)
894  return writeDispatchHeader(DHI);
895  else
896  return writeHeader(outFileName);
897  } else if (outputType == Deps)
898  return writeDeps(outFileName, 0 != (flags & GenerateMakeRuleForDeps), includeFileName, sourceFileName);
899  else if (outputType == HostStub)
900  return writeHostStub(outFileName);
901  else if (outputType == DevStub)
902  return writeDevStub(outFileName);
903  else if ((outputType == Bitcode) || (outputType == BitcodeText))
904  return writeBitcode(module, outFileName, outputType);
905  else if (outputType == CXX) {
906  if (g->target->getISA() != Target::GENERIC) {
907  Error(SourcePos(), "Only \"generic-*\" targets can be used with "
908  "C++ emission.");
909  return false;
910  }
911  extern bool WriteCXXFile(llvm::Module * module, const char *fn, int vectorWidth, const char *includeName);
912  return WriteCXXFile(module, outFileName, g->target->getVectorWidth(), includeFileName);
913  } else
914  return writeObjectFileOrAssembly(outputType, outFileName);
915 }
916 
917 bool Module::writeBitcode(llvm::Module *module, const char *outFileName, OutputType outputType) {
918  // Get a file descriptor corresponding to where we want the output to
919  // go. If we open it, it'll be closed by the llvm::raw_fd_ostream
920  // destructor.
921  int fd;
922  if (!strcmp(outFileName, "-"))
923  fd = 1; // stdout
924  else {
925  int flags = O_CREAT | O_WRONLY | O_TRUNC;
926 #ifdef ISPC_HOST_IS_WINDOWS
927  flags |= O_BINARY;
928  fd = _open(outFileName, flags, 0644);
929 #else
930  fd = open(outFileName, flags, 0644);
931 #endif // ISPC_HOST_IS_WINDOWS
932  if (fd == -1) {
933  perror(outFileName);
934  return false;
935  }
936  }
937 
938  llvm::raw_fd_ostream fos(fd, (fd != 1), false);
939  if (outputType == Bitcode)
940 #if ISPC_LLVM_VERSION < ISPC_LLVM_7_0
941  llvm::WriteBitcodeToFile(module, fos);
942 #else
943  llvm::WriteBitcodeToFile(*module, fos);
944 #endif
945  else if (outputType == BitcodeText)
946  module->print(fos, nullptr);
947  return true;
948 }
949 
950 bool Module::writeObjectFileOrAssembly(OutputType outputType, const char *outFileName) {
951  llvm::TargetMachine *targetMachine = g->target->GetTargetMachine();
952  return writeObjectFileOrAssembly(targetMachine, module, outputType, outFileName);
953 }
954 
955 bool Module::writeObjectFileOrAssembly(llvm::TargetMachine *targetMachine, llvm::Module *module, OutputType outputType,
956  const char *outFileName) {
957  // Figure out if we're generating object file or assembly output, and
958  // set binary output for object files
959 #if ISPC_LLVM_VERSION <= ISPC_LLVM_9_0
960  llvm::TargetMachine::CodeGenFileType fileType =
961  (outputType == Object) ? llvm::TargetMachine::CGFT_ObjectFile : llvm::TargetMachine::CGFT_AssemblyFile;
962  bool binary = (fileType == llvm::TargetMachine::CGFT_ObjectFile);
963 #else // LLVM 10.0+
964  llvm::CodeGenFileType fileType = (outputType == Object) ? llvm::CGFT_ObjectFile : llvm::CGFT_AssemblyFile;
965  bool binary = (fileType == llvm::CGFT_ObjectFile);
966 #endif
967 
968  llvm::sys::fs::OpenFlags flags = binary ? llvm::sys::fs::F_None : llvm::sys::fs::F_Text;
969 
970  std::error_code error;
971 
972  std::unique_ptr<llvm::ToolOutputFile> of(new llvm::ToolOutputFile(outFileName, error, flags));
973 
974  if (error) {
975  Error(SourcePos(), "Cannot open output file \"%s\".\n", outFileName);
976  return false;
977  }
978 
979  llvm::legacy::PassManager pm;
980 
981  {
982  llvm::raw_fd_ostream &fos(of->os());
983 #if ISPC_LLVM_VERSION == ISPC_LLVM_6_0
984  if (targetMachine->addPassesToEmitFile(pm, fos, fileType)) {
985  FATAL("Failed to add passes to emit object file!");
986  }
987 #else // LLVM 7.0+
988  // Third parameter is for generation of .dwo file, which is separate DWARF
989  // file for ELF targets. We don't support it currently.
990  if (targetMachine->addPassesToEmitFile(pm, fos, nullptr, fileType)) {
991  FATAL("Failed to add passes to emit object file!");
992  }
993 #endif
994 
995  // Finally, run the passes to emit the object file/assembly
996  pm.run(*module);
997 
998  // Success; tell tool_output_file to keep the final output file.
999  of->keep();
1000  }
1001  return true;
1002 }
1003 
1004 /** Given a pointer to an element of a structure, see if it is a struct
1005  type or an array of a struct type. If so, return a pointer to the
1006  underlying struct type. */
1007 static const StructType *lGetElementStructType(const Type *t) {
1008  const StructType *st = CastType<StructType>(t);
1009  if (st != NULL)
1010  return st;
1011 
1012  const ArrayType *at = CastType<ArrayType>(t);
1013  if (at != NULL)
1014  return lGetElementStructType(at->GetElementType());
1015 
1016  return NULL;
1017 }
1018 
1019 static bool lContainsPtrToVarying(const StructType *st) {
1020  int numElts = st->GetElementCount();
1021 
1022  for (int j = 0; j < numElts; ++j) {
1023  const Type *t = st->GetElementType(j);
1024 
1025  if (t->IsVaryingType())
1026  return true;
1027  }
1028 
1029  return false;
1030 }
1031 
1032 /** Emits a declaration for the given struct to the given file. This
1033  function first makes sure that declarations for any structs that are
1034  (recursively) members of this struct are emitted first.
1035  */
1036 static void lEmitStructDecl(const StructType *st, std::vector<const StructType *> *emittedStructs, FILE *file,
1037  bool emitUnifs = true) {
1038 
1039  // if we're emitting this for a generic dispatch header file and it's
1040  // struct that only contains uniforms, don't bother if we're emitting uniforms
1041  if (!emitUnifs && !lContainsPtrToVarying(st)) {
1042  return;
1043  }
1044 
1045  // Has this struct type already been declared? (This happens if it's a
1046  // member of another struct for which we emitted a declaration
1047  // previously.)
1048  for (int i = 0; i < (int)emittedStructs->size(); ++i)
1049  if (Type::EqualIgnoringConst(st, (*emittedStructs)[i]))
1050  return;
1051 
1052  // Otherwise first make sure any contained structs have been declared.
1053  for (int i = 0; i < st->GetElementCount(); ++i) {
1054  const StructType *elementStructType = lGetElementStructType(st->GetElementType(i));
1055  if (elementStructType != NULL)
1056  lEmitStructDecl(elementStructType, emittedStructs, file, emitUnifs);
1057  }
1058 
1059  // And now it's safe to declare this one
1060  emittedStructs->push_back(st);
1061 
1062  fprintf(file, "#ifndef __ISPC_STRUCT_%s__\n", st->GetCStructName().c_str());
1063  fprintf(file, "#define __ISPC_STRUCT_%s__\n", st->GetCStructName().c_str());
1064 
1065  char sSOA[48];
1066  bool pack, needsAlign = false;
1067  llvm::Type *stype = st->LLVMType(g->ctx);
1068  const llvm::DataLayout *DL = g->target->getDataLayout();
1069 
1070  if (!(pack = llvm::dyn_cast<llvm::StructType>(stype)->isPacked()))
1071  for (int i = 0; !needsAlign && (i < st->GetElementCount()); ++i) {
1072  const Type *ftype = st->GetElementType(i)->GetAsNonConstType();
1073  needsAlign |= ftype->IsVaryingType() && (CastType<StructType>(ftype) == NULL);
1074  }
1075  if (st->GetSOAWidth() > 0)
1076  // This has to match the naming scheme in
1077  // StructType::GetCDeclaration().
1078  snprintf(sSOA, sizeof(sSOA), "_SOA%d", st->GetSOAWidth());
1079  else
1080  *sSOA = '\0';
1081  if (!needsAlign)
1082  fprintf(file, "%sstruct %s%s {\n", (pack) ? "packed " : "", st->GetCStructName().c_str(), sSOA);
1083  else {
1084  unsigned uABI = DL->getABITypeAlignment(stype);
1085  fprintf(file, "__ISPC_ALIGNED_STRUCT__(%u) %s%s {\n", uABI, st->GetCStructName().c_str(), sSOA);
1086  }
1087  for (int i = 0; i < st->GetElementCount(); ++i) {
1088  const Type *ftype = st->GetElementType(i)->GetAsNonConstType();
1089  std::string d = ftype->GetCDeclaration(st->GetElementName(i));
1090 
1091  fprintf(file, " ");
1092  if (needsAlign && ftype->IsVaryingType() && (CastType<StructType>(ftype) == NULL)) {
1093  unsigned uABI = DL->getABITypeAlignment(ftype->LLVMType(g->ctx));
1094  fprintf(file, "__ISPC_ALIGN__(%u) ", uABI);
1095  }
1096  // Don't expand arrays, pointers and structures:
1097  // their insides will be expanded automatically.
1098  if (!ftype->IsArrayType() && !ftype->IsPointerType() && ftype->IsVaryingType() &&
1099  (CastType<StructType>(ftype) == NULL)) {
1100  fprintf(file, "%s[%d];\n", d.c_str(), g->target->getVectorWidth());
1101  } else {
1102  fprintf(file, "%s;\n", d.c_str());
1103  }
1104  }
1105  fprintf(file, "};\n");
1106  fprintf(file, "#endif\n\n");
1107 }
1108 
1109 /** Given a set of structures that we want to print C declarations of in a
1110  header file, emit their declarations.
1111  */
1112 static void lEmitStructDecls(std::vector<const StructType *> &structTypes, FILE *file, bool emitUnifs = true) {
1113  std::vector<const StructType *> emittedStructs;
1114 
1115  fprintf(file, "\n#ifndef __ISPC_ALIGN__\n"
1116  "#if defined(__clang__) || !defined(_MSC_VER)\n"
1117  "// Clang, GCC, ICC\n"
1118  "#define __ISPC_ALIGN__(s) __attribute__((aligned(s)))\n"
1119  "#define __ISPC_ALIGNED_STRUCT__(s) struct __ISPC_ALIGN__(s)\n"
1120  "#else\n"
1121  "// Visual Studio\n"
1122  "#define __ISPC_ALIGN__(s) __declspec(align(s))\n"
1123  "#define __ISPC_ALIGNED_STRUCT__(s) __ISPC_ALIGN__(s) struct\n"
1124  "#endif\n"
1125  "#endif\n\n");
1126 
1127  for (unsigned int i = 0; i < structTypes.size(); ++i)
1128  lEmitStructDecl(structTypes[i], &emittedStructs, file, emitUnifs);
1129 }
1130 
1131 /** Emit C declarations of enumerator types to the generated header file.
1132  */
1133 static void lEmitEnumDecls(const std::vector<const EnumType *> &enumTypes, FILE *file) {
1134  if (enumTypes.size() == 0)
1135  return;
1136 
1137  fprintf(file, "///////////////////////////////////////////////////////////////////////////\n");
1138  fprintf(file, "// Enumerator types with external visibility from ispc code\n");
1139  fprintf(file, "///////////////////////////////////////////////////////////////////////////\n\n");
1140 
1141  for (unsigned int i = 0; i < enumTypes.size(); ++i) {
1142  fprintf(file, "#ifndef __ISPC_ENUM_%s__\n", enumTypes[i]->GetEnumName().c_str());
1143  fprintf(file, "#define __ISPC_ENUM_%s__\n", enumTypes[i]->GetEnumName().c_str());
1144  std::string declaration = enumTypes[i]->GetCDeclaration("");
1145  fprintf(file, "%s {\n", declaration.c_str());
1146 
1147  // Print the individual enumerators
1148  for (int j = 0; j < enumTypes[i]->GetEnumeratorCount(); ++j) {
1149  const Symbol *e = enumTypes[i]->GetEnumerator(j);
1150  Assert(e->constValue != NULL);
1151  unsigned int enumValue;
1152  int count = e->constValue->GetValues(&enumValue);
1153  Assert(count == 1);
1154 
1155  // Always print an initializer to set the value. We could be
1156  // 'clever' here and detect whether the implicit value given by
1157  // one plus the previous enumerator value (or zero, for the
1158  // first enumerator) is the same as the value stored with the
1159  // enumerator, though that doesn't seem worth the trouble...
1160  fprintf(file, " %s = %d%c\n", e->name.c_str(), enumValue,
1161  (j < enumTypes[i]->GetEnumeratorCount() - 1) ? ',' : ' ');
1162  }
1163  fprintf(file, "};\n");
1164  fprintf(file, "#endif\n\n");
1165  }
1166 }
1167 
1168 /** Print declarations of VectorTypes used in 'export'ed parts of the
1169  program in the header file.
1170  */
1171 static void lEmitVectorTypedefs(const std::vector<const VectorType *> &types, FILE *file) {
1172  if (types.size() == 0)
1173  return;
1174 
1175  fprintf(file, "///////////////////////////////////////////////////////////////////////////\n");
1176  fprintf(file, "// Vector types with external visibility from ispc code\n");
1177  fprintf(file, "///////////////////////////////////////////////////////////////////////////\n\n");
1178 
1179  for (unsigned int i = 0; i < types.size(); ++i) {
1180  std::string baseDecl;
1181  const VectorType *vt = types[i]->GetAsNonConstType();
1182  if (!vt->IsUniformType())
1183  // Varying stuff shouldn't be visibile to / used by the
1184  // application, so at least make it not simple to access it by
1185  // not declaring the type here...
1186  continue;
1187 
1188  int size = vt->GetElementCount();
1189 
1190  llvm::Type *ty = vt->LLVMType(g->ctx);
1191  int align = g->target->getDataLayout()->getABITypeAlignment(ty);
1192  baseDecl = vt->GetBaseType()->GetCDeclaration("");
1193  fprintf(file, "#ifndef __ISPC_VECTOR_%s%d__\n", baseDecl.c_str(), size);
1194  fprintf(file, "#define __ISPC_VECTOR_%s%d__\n", baseDecl.c_str(), size);
1195  fprintf(file, "#ifdef _MSC_VER\n__declspec( align(%d) ) ", align);
1196  fprintf(file, "struct %s%d { %s v[%d]; };\n", baseDecl.c_str(), size, baseDecl.c_str(), size);
1197  fprintf(file, "#else\n");
1198  fprintf(file, "struct %s%d { %s v[%d]; } __attribute__ ((aligned(%d)));\n", baseDecl.c_str(), size,
1199  baseDecl.c_str(), size, align);
1200  fprintf(file, "#endif\n");
1201  fprintf(file, "#endif\n\n");
1202  }
1203  fprintf(file, "\n");
1204 }
1205 
1206 /** Add the given type to the vector, if that type isn't already in there.
1207  */
1208 template <typename T> static void lAddTypeIfNew(const Type *type, std::vector<const T *> *exportedTypes) {
1209  type = type->GetAsNonConstType();
1210 
1211  // Linear search, so this ends up being n^2. It's unlikely this will
1212  // matter in practice, though.
1213  for (unsigned int i = 0; i < exportedTypes->size(); ++i)
1214  if (Type::Equal((*exportedTypes)[i], type))
1215  return;
1216 
1217  const T *castType = CastType<T>(type);
1218  Assert(castType != NULL);
1219  exportedTypes->push_back(castType);
1220 }
1221 
1222 /** Given an arbitrary type that appears in the app/ispc interface, add it
1223  to an appropriate vector if it is a struct, enum, or short vector type.
1224  Then, if it's a struct, recursively process its members to do the same.
1225  */
1226 static void lGetExportedTypes(const Type *type, std::vector<const StructType *> *exportedStructTypes,
1227  std::vector<const EnumType *> *exportedEnumTypes,
1228  std::vector<const VectorType *> *exportedVectorTypes) {
1229  const ArrayType *arrayType = CastType<ArrayType>(type);
1230  const StructType *structType = CastType<StructType>(type);
1231  const FunctionType *ftype = CastType<FunctionType>(type);
1232 
1233  if (CastType<ReferenceType>(type) != NULL)
1234  lGetExportedTypes(type->GetReferenceTarget(), exportedStructTypes, exportedEnumTypes, exportedVectorTypes);
1235  else if (CastType<PointerType>(type) != NULL)
1236  lGetExportedTypes(type->GetBaseType(), exportedStructTypes, exportedEnumTypes, exportedVectorTypes);
1237  else if (arrayType != NULL)
1238  lGetExportedTypes(arrayType->GetElementType(), exportedStructTypes, exportedEnumTypes, exportedVectorTypes);
1239  else if (structType != NULL) {
1240  lAddTypeIfNew(type, exportedStructTypes);
1241  for (int i = 0; i < structType->GetElementCount(); ++i)
1242  lGetExportedTypes(structType->GetElementType(i), exportedStructTypes, exportedEnumTypes,
1243  exportedVectorTypes);
1244  } else if (CastType<UndefinedStructType>(type) != NULL)
1245  // do nothing
1246  ;
1247  else if (CastType<EnumType>(type) != NULL)
1248  lAddTypeIfNew(type, exportedEnumTypes);
1249  else if (CastType<VectorType>(type) != NULL)
1250  lAddTypeIfNew(type, exportedVectorTypes);
1251  else if (ftype != NULL) {
1252  // Handle Return Types
1253  lGetExportedTypes(ftype->GetReturnType(), exportedStructTypes, exportedEnumTypes, exportedVectorTypes);
1254 
1255  // And now the parameter types...
1256  for (int j = 0; j < ftype->GetNumParameters(); ++j)
1257  lGetExportedTypes(ftype->GetParameterType(j), exportedStructTypes, exportedEnumTypes, exportedVectorTypes);
1258  } else
1259  Assert(CastType<AtomicType>(type) != NULL);
1260 }
1261 
1262 /** Given a set of functions, return the set of structure and vector types
1263  present in the parameters to them.
1264  */
1265 static void lGetExportedParamTypes(const std::vector<Symbol *> &funcs,
1266  std::vector<const StructType *> *exportedStructTypes,
1267  std::vector<const EnumType *> *exportedEnumTypes,
1268  std::vector<const VectorType *> *exportedVectorTypes) {
1269  for (unsigned int i = 0; i < funcs.size(); ++i) {
1270  const FunctionType *ftype = CastType<FunctionType>(funcs[i]->type);
1271  Assert(ftype != NULL);
1272 
1273  // Handle the return type
1274  lGetExportedTypes(ftype->GetReturnType(), exportedStructTypes, exportedEnumTypes, exportedVectorTypes);
1275 
1276  // And now the parameter types...
1277  for (int j = 0; j < ftype->GetNumParameters(); ++j) {
1278  lGetExportedTypes(ftype->GetParameterType(j), exportedStructTypes, exportedEnumTypes, exportedVectorTypes);
1279  }
1280  }
1281 }
1282 
1283 static void lPrintFunctionDeclarations(FILE *file, const std::vector<Symbol *> &funcs, bool useExternC = 1,
1284  bool rewriteForDispatch = false) {
1285  if (useExternC)
1286  fprintf(file, "#if defined(__cplusplus) && (! defined(__ISPC_NO_EXTERN_C) || !__ISPC_NO_EXTERN_C )\nextern "
1287  "\"C\" {\n#endif // __cplusplus\n");
1288  // fprintf(file, "#ifdef __cplusplus\nextern \"C\" {\n#endif // __cplusplus\n");
1289  for (unsigned int i = 0; i < funcs.size(); ++i) {
1290  const FunctionType *ftype = CastType<FunctionType>(funcs[i]->type);
1291  Assert(ftype);
1292  std::string decl;
1293  if (rewriteForDispatch) {
1294  decl = ftype->GetCDeclarationForDispatch(funcs[i]->name);
1295  } else {
1296  decl = ftype->GetCDeclaration(funcs[i]->name);
1297  }
1298  fprintf(file, " extern %s;\n", decl.c_str());
1299  }
1300  if (useExternC)
1301 
1302  fprintf(file, "#if defined(__cplusplus) && (! defined(__ISPC_NO_EXTERN_C) || !__ISPC_NO_EXTERN_C )\n} /* end "
1303  "extern C */\n#endif // __cplusplus\n");
1304  // fprintf(file, "#ifdef __cplusplus\n} /* end extern C */\n#endif // __cplusplus\n");
1305 }
1306 
1307 static bool lIsExported(const Symbol *sym) {
1308  const FunctionType *ft = CastType<FunctionType>(sym->type);
1309  Assert(ft);
1310  return ft->isExported;
1311 }
1312 
1313 static bool lIsExternC(const Symbol *sym) {
1314  const FunctionType *ft = CastType<FunctionType>(sym->type);
1315  Assert(ft);
1316  return ft->isExternC;
1317 }
1318 
1319 static void lUnescapeStringInPlace(std::string &str) {
1320  // There are many more escape sequences, but since this is a path,
1321  // we can get away with only supporting the basic ones (i.e. no
1322  // octal, hexadecimal or unicode values).
1323  for (std::string::iterator it = str.begin(); it != str.end(); ++it) {
1324  size_t pos = it - str.begin();
1325  std::string::iterator next = it + 1;
1326  if (*it == '\\' && next != str.end()) {
1327  switch (*next) {
1328 #define UNESCAPE_SEQ(c, esc) \
1329  case c: \
1330  *it = esc; \
1331  str.erase(next); \
1332  it = str.begin() + pos; \
1333  break
1334  UNESCAPE_SEQ('\'', '\'');
1335  UNESCAPE_SEQ('?', '?');
1336  UNESCAPE_SEQ('\\', '\\');
1337  UNESCAPE_SEQ('a', '\a');
1338  UNESCAPE_SEQ('b', '\b');
1339  UNESCAPE_SEQ('f', '\f');
1340  UNESCAPE_SEQ('n', '\n');
1341  UNESCAPE_SEQ('r', '\r');
1342  UNESCAPE_SEQ('t', '\t');
1343  UNESCAPE_SEQ('v', '\v');
1344 #undef UNESCAPE_SEQ
1345  }
1346  }
1347  }
1348 }
1349 
1350 bool Module::writeDeps(const char *fn, bool generateMakeRule, const char *tn, const char *sn) {
1351  if (fn && g->debugPrint) { // We may be passed nullptr for stdout output.
1352  printf("\nWriting dependencies to file %s\n", fn);
1353  }
1354  FILE *file = fn ? fopen(fn, "w") : stdout;
1355  if (!file) {
1356  perror("fopen");
1357  return false;
1358  }
1359 
1360  if (generateMakeRule) {
1361  fprintf(file, "%s:", tn);
1362  // Rules always emit source first.
1363  if (sn && !IsStdin(sn)) {
1364  fprintf(file, " %s", sn);
1365  }
1366  std::string unescaped;
1367 
1368  for (std::set<std::string>::const_iterator it = registeredDependencies.begin();
1369  it != registeredDependencies.end(); ++it) {
1370  unescaped = *it; // As this is preprocessor output, paths come escaped.
1371  lUnescapeStringInPlace(unescaped);
1372  if (sn && !IsStdin(sn) &&
1373  0 == strcmp(sn, unescaped.c_str())) // If source has been passed, it's already emitted.
1374  continue;
1375  fprintf(file, " \\\n");
1376  fprintf(file, " %s", unescaped.c_str());
1377  }
1378  fprintf(file, "\n");
1379  } else {
1380  for (std::set<std::string>::const_iterator it = registeredDependencies.begin();
1381  it != registeredDependencies.end(); ++it)
1382  fprintf(file, "%s\n", it->c_str());
1383  }
1384  fclose(file);
1385  return true;
1386 }
1387 
1388 std::string emitOffloadParamStruct(const std::string &paramStructName, const Symbol *sym, const FunctionType *fct) {
1389  std::stringstream out;
1390  out << "struct " << paramStructName << " {" << std::endl;
1391 
1392  for (int i = 0; i < fct->GetNumParameters(); i++) {
1393  const Type *orgParamType = fct->GetParameterType(i);
1394  if (orgParamType->IsPointerType() || orgParamType->IsArrayType()) {
1395  /* we're passing pointers separately -- no pointers in that struct... */
1396  continue;
1397  }
1398 
1399  // const reference parameters can be passed as copies.
1400  const Type *paramType;
1401  if (orgParamType->IsReferenceType()) {
1402  if (!orgParamType->IsConstType()) {
1403  Error(sym->pos, "When emitting offload-stubs, \"export\"ed functions cannot have non-const "
1404  "reference-type parameters.\n");
1405  }
1406  const ReferenceType *refType = static_cast<const ReferenceType *>(orgParamType);
1407  paramType = refType->GetReferenceTarget()->GetAsNonConstType();
1408  } else {
1409  paramType = orgParamType->GetAsNonConstType();
1410  }
1411  std::string paramName = fct->GetParameterName(i);
1412  std::string paramTypeName = paramType->GetString();
1413 
1414  std::string tmpArgDecl = paramType->GetCDeclaration(paramName);
1415  out << " " << tmpArgDecl << ";" << std::endl;
1416  }
1417 
1418  out << "};" << std::endl;
1419  return out.str();
1420 }
1421 
1422 bool Module::writeDevStub(const char *fn) {
1423  FILE *file = fopen(fn, "w");
1424  if (!file) {
1425  perror("fopen");
1426  return false;
1427  }
1428  fprintf(file, "//\n// %s\n// (device stubs automatically generated by the ispc compiler.)\n", fn);
1429  fprintf(file, "// DO NOT EDIT THIS FILE.\n//\n\n");
1430  fprintf(file, "#include \"ispc/dev/offload.h\"\n\n");
1431 
1432  fprintf(file, "#include <stdint.h>\n\n");
1433 
1434  // Collect single linear arrays of the *exported* functions (we'll
1435  // treat those as "__kernel"s in IVL -- "extern" functions will only
1436  // be used for dev-dev function calls; only "export" functions will
1437  // get exported to the host
1438  std::vector<Symbol *> exportedFuncs;
1439  m->symbolTable->GetMatchingFunctions(lIsExported, &exportedFuncs);
1440 
1441  // Get all of the struct, vector, and enumerant types used as function
1442  // parameters. These vectors may have repeats.
1443  std::vector<const StructType *> exportedStructTypes;
1444  std::vector<const EnumType *> exportedEnumTypes;
1445  std::vector<const VectorType *> exportedVectorTypes;
1446  lGetExportedParamTypes(exportedFuncs, &exportedStructTypes, &exportedEnumTypes, &exportedVectorTypes);
1447 
1448  // And print them
1449  lEmitVectorTypedefs(exportedVectorTypes, file);
1450  lEmitEnumDecls(exportedEnumTypes, file);
1451  lEmitStructDecls(exportedStructTypes, file);
1452 
1453  fprintf(file, "#ifdef __cplusplus\n");
1454  fprintf(file, "namespace ispc {\n");
1455  fprintf(file, "#endif // __cplusplus\n");
1456 
1457  fprintf(file, "\n");
1458  fprintf(file, "///////////////////////////////////////////////////////////////////////////\n");
1459  fprintf(file, "// Functions exported from ispc code\n");
1460  fprintf(file, "// (so the dev stub knows what to call)\n");
1461  fprintf(file, "///////////////////////////////////////////////////////////////////////////\n");
1462  lPrintFunctionDeclarations(file, exportedFuncs, true);
1463 
1464  fprintf(file, "#ifdef __cplusplus\n");
1465  fprintf(file, "}/* end namespace */\n");
1466  fprintf(file, "#endif // __cplusplus\n");
1467 
1468  fprintf(file, "\n");
1469  fprintf(file, "///////////////////////////////////////////////////////////////////////////\n");
1470  fprintf(file, "// actual dev stubs\n");
1471  fprintf(file, "///////////////////////////////////////////////////////////////////////////\n");
1472 
1473  fprintf(file, "// note(iw): due to some linking issues offload stubs *only* work under C++\n");
1474  fprintf(file, "extern \"C\" {\n\n");
1475  for (unsigned int i = 0; i < exportedFuncs.size(); ++i) {
1476  const Symbol *sym = exportedFuncs[i];
1477  Assert(sym);
1478  const FunctionType *fct = CastType<FunctionType>(sym->type);
1479  Assert(fct);
1480 
1481  if (!fct->GetReturnType()->IsVoidType()) {
1482  // Error(sym->pos,"When emitting offload-stubs, \"export\"ed functions cannot have non-void return
1483  // types.\n");
1484  Warning(sym->pos,
1485  "When emitting offload-stubs, ignoring \"export\"ed function with non-void return types.\n");
1486  continue;
1487  }
1488 
1489  // -------------------------------------------------------
1490  // first, emit a struct that holds the parameters
1491  // -------------------------------------------------------
1492  std::string paramStructName = std::string("__ispc_dev_stub_") + sym->name;
1493  std::string paramStruct = emitOffloadParamStruct(paramStructName, sym, fct);
1494  fprintf(file, "%s\n", paramStruct.c_str());
1495  // -------------------------------------------------------
1496  // then, emit a fct stub that unpacks the parameters and pointers
1497  // -------------------------------------------------------
1498  fprintf(file,
1499  "void __ispc_dev_stub_%s(\n"
1500  " uint32_t in_BufferCount,\n"
1501  " void** in_ppBufferPointers,\n"
1502  " uint64_t* in_pBufferLengths,\n"
1503  " void* in_pMiscData,\n"
1504  " uint16_t in_MiscDataLength,\n"
1505  " void* in_pReturnValue,\n"
1506  " uint16_t in_ReturnValueLength)\n",
1507  sym->name.c_str());
1508  fprintf(file, "{\n");
1509  fprintf(file, " struct %s args;\n memcpy(&args,in_pMiscData,sizeof(args));\n", paramStructName.c_str());
1510  std::stringstream funcall;
1511 
1512  funcall << "ispc::" << sym->name << "(";
1513  for (int i = 0; i < fct->GetNumParameters(); i++) {
1514  // get param type and make it non-const, so we can write while unpacking
1515  // const Type *paramType = fct->GetParameterType(i)->GetAsNonConstType();
1516  const Type *paramType; // = fct->GetParameterType(i)->GetAsNonConstType();
1517  const Type *orgParamType = fct->GetParameterType(i);
1518  if (orgParamType->IsReferenceType()) {
1519  if (!orgParamType->IsConstType()) {
1520  Error(sym->pos, "When emitting offload-stubs, \"export\"ed functions cannot have non-const "
1521  "reference-type parameters.\n");
1522  }
1523  const ReferenceType *refType = static_cast<const ReferenceType *>(orgParamType);
1524  paramType = refType->GetReferenceTarget()->GetAsNonConstType();
1525  } else {
1526  paramType = orgParamType->GetAsNonConstType();
1527  }
1528 
1529  std::string paramName = fct->GetParameterName(i);
1530  std::string paramTypeName = paramType->GetString();
1531 
1532  if (i)
1533  funcall << ", ";
1534  std::string tmpArgName = std::string("_") + paramName;
1535  if (paramType->IsPointerType() || paramType->IsArrayType()) {
1536  std::string tmpArgDecl = paramType->GetCDeclaration(tmpArgName);
1537  fprintf(file, " %s;\n", tmpArgDecl.c_str());
1538  fprintf(file, " (void *&)%s = ispc_dev_translate_pointer(*in_ppBufferPointers++);\n",
1539  tmpArgName.c_str());
1540  funcall << tmpArgName;
1541  } else {
1542  funcall << "args." << paramName;
1543  }
1544  }
1545  funcall << ");";
1546  fprintf(file, " %s\n", funcall.str().c_str());
1547  fprintf(file, "}\n\n");
1548  }
1549 
1550  // end extern "C"
1551  fprintf(file, "}/* end extern C */\n");
1552 
1553  fclose(file);
1554  return true;
1555 }
1556 
1557 bool Module::writeHostStub(const char *fn) {
1558  FILE *file = fopen(fn, "w");
1559  if (!file) {
1560  perror("fopen");
1561  return false;
1562  }
1563  fprintf(file, "//\n// %s\n// (device stubs automatically generated by the ispc compiler.)\n", fn);
1564  fprintf(file, "// DO NOT EDIT THIS FILE.\n//\n\n");
1565  fprintf(file, "#include \"ispc/host/offload.h\"\n\n");
1566  fprintf(
1567  file,
1568  "// note(iw): Host stubs do not get extern C linkage -- dev-side already uses that for the same symbols.\n\n");
1569  // fprintf(file,"#ifdef __cplusplus\nextern \"C\" {\n#endif // __cplusplus\n");
1570 
1571  fprintf(file, "#ifdef __cplusplus\nnamespace ispc {\n#endif // __cplusplus\n\n");
1572 
1573  // Collect single linear arrays of the *exported* functions (we'll
1574  // treat those as "__kernel"s in IVL -- "extern" functions will only
1575  // be used for dev-dev function calls; only "export" functions will
1576  // get exported to the host
1577  std::vector<Symbol *> exportedFuncs;
1578  m->symbolTable->GetMatchingFunctions(lIsExported, &exportedFuncs);
1579 
1580  // Get all of the struct, vector, and enumerant types used as function
1581  // parameters. These vectors may have repeats.
1582  std::vector<const StructType *> exportedStructTypes;
1583  std::vector<const EnumType *> exportedEnumTypes;
1584  std::vector<const VectorType *> exportedVectorTypes;
1585  lGetExportedParamTypes(exportedFuncs, &exportedStructTypes, &exportedEnumTypes, &exportedVectorTypes);
1586 
1587  // And print them
1588  lEmitVectorTypedefs(exportedVectorTypes, file);
1589  lEmitEnumDecls(exportedEnumTypes, file);
1590  lEmitStructDecls(exportedStructTypes, file);
1591 
1592  fprintf(file, "\n");
1593  fprintf(file, "///////////////////////////////////////////////////////////////////////////\n");
1594  fprintf(file, "// host-side stubs for dev-side ISPC fucntion(s)\n");
1595  fprintf(file, "///////////////////////////////////////////////////////////////////////////\n");
1596  for (unsigned int i = 0; i < exportedFuncs.size(); ++i) {
1597  const Symbol *sym = exportedFuncs[i];
1598  Assert(sym);
1599  const FunctionType *fct = CastType<FunctionType>(sym->type);
1600  Assert(fct);
1601 
1602  if (!fct->GetReturnType()->IsVoidType()) {
1603  Warning(sym->pos,
1604  "When emitting offload-stubs, ignoring \"export\"ed function with non-void return types.\n");
1605  continue;
1606  }
1607 
1608  // -------------------------------------------------------
1609  // first, emit a struct that holds the parameters
1610  // -------------------------------------------------------
1611  std::string paramStructName = std::string("__ispc_dev_stub_") + sym->name;
1612  std::string paramStruct = emitOffloadParamStruct(paramStructName, sym, fct);
1613  fprintf(file, "%s\n", paramStruct.c_str());
1614  // -------------------------------------------------------
1615  // then, emit a fct stub that unpacks the parameters and pointers
1616  // -------------------------------------------------------
1617 
1618  std::string decl = fct->GetCDeclaration(sym->name);
1619  fprintf(file, "extern %s {\n", decl.c_str());
1620  int numPointers = 0;
1621  fprintf(file, " %s __args;\n", paramStructName.c_str());
1622 
1623  // ------------------------------------------------------------------
1624  // write args, and save pointers for later
1625  // ------------------------------------------------------------------
1626  std::stringstream pointerArgs;
1627  for (int i = 0; i < fct->GetNumParameters(); i++) {
1628  const Type *orgParamType = fct->GetParameterType(i);
1629  std::string paramName = fct->GetParameterName(i);
1630  if (orgParamType->IsPointerType() || orgParamType->IsArrayType()) {
1631  /* we're passing pointers separately -- no pointers in that struct... */
1632  if (numPointers)
1633  pointerArgs << ",";
1634  pointerArgs << "(void*)" << paramName;
1635  numPointers++;
1636  continue;
1637  }
1638 
1639  fprintf(file, " __args.%s = %s;\n", paramName.c_str(), paramName.c_str());
1640  }
1641  // ------------------------------------------------------------------
1642  // writer pointer list
1643  // ------------------------------------------------------------------
1644  if (numPointers == 0)
1645  pointerArgs << "NULL";
1646  fprintf(file, " void *ptr_args[] = { %s };\n", pointerArgs.str().c_str());
1647 
1648  // ------------------------------------------------------------------
1649  // ... and call the kernel with those args
1650  // ------------------------------------------------------------------
1651  fprintf(file, " static ispc_kernel_handle_t kernel_handle = NULL;\n");
1652  fprintf(file, " if (!kernel_handle) kernel_handle = ispc_host_get_kernel_handle(\"__ispc_dev_stub_%s\");\n",
1653  sym->name.c_str());
1654  fprintf(file, " assert(kernel_handle);\n");
1655  fprintf(file,
1656  " ispc_host_call_kernel(kernel_handle,\n"
1657  " &__args, sizeof(__args),\n"
1658  " ptr_args,%i);\n",
1659  numPointers);
1660  fprintf(file, "}\n\n");
1661  }
1662 
1663  // end extern "C"
1664  fprintf(file, "#ifdef __cplusplus\n");
1665  fprintf(file, "}/* namespace */\n");
1666  fprintf(file, "#endif // __cplusplus\n");
1667  // fprintf(file, "#ifdef __cplusplus\n");
1668  // fprintf(file, "}/* end extern C */\n");
1669  // fprintf(file, "#endif // __cplusplus\n");
1670 
1671  fclose(file);
1672  return true;
1673 }
1674 
1675 bool Module::writeHeader(const char *fn) {
1676  FILE *f = fopen(fn, "w");
1677  if (!f) {
1678  perror("fopen");
1679  return false;
1680  }
1681  fprintf(f, "//\n// %s\n// (Header automatically generated by the ispc compiler.)\n", fn);
1682  fprintf(f, "// DO NOT EDIT THIS FILE.\n//\n\n");
1683 
1684  // Create a nice guard string from the filename, turning any
1685  // non-number/letter characters into underbars
1686  std::string guard = "ISPC_";
1687  const char *p = fn;
1688  while (*p) {
1689  if (isdigit(*p))
1690  guard += *p;
1691  else if (isalpha(*p))
1692  guard += toupper(*p);
1693  else
1694  guard += "_";
1695  ++p;
1696  }
1697 
1698  if (g->noPragmaOnce)
1699  fprintf(f, "#ifndef %s\n#define %s\n\n", guard.c_str(), guard.c_str());
1700  else
1701  fprintf(f, "#pragma once\n");
1702 
1703  fprintf(f, "#include <stdint.h>\n\n");
1704 
1705  if (g->emitInstrumentation) {
1706  fprintf(f, "#define ISPC_INSTRUMENTATION 1\n");
1707  fprintf(f, "#if defined(__cplusplus) && (! defined(__ISPC_NO_EXTERN_C) || !__ISPC_NO_EXTERN_C )\nextern \"C\" "
1708  "{\n#endif // __cplusplus\n");
1709  fprintf(f, " void ISPCInstrument(const char *fn, const char *note, int line, uint64_t mask);\n");
1710  fprintf(f, "#if defined(__cplusplus) && (! defined(__ISPC_NO_EXTERN_C) || !__ISPC_NO_EXTERN_C )\n} /* end "
1711  "extern C */\n#endif // __cplusplus\n");
1712  }
1713 
1714  // end namespace
1715  fprintf(f, "\n");
1716  fprintf(f, "\n#ifdef __cplusplus\nnamespace ispc { /* namespace */\n#endif // __cplusplus\n");
1717 
1718  // Collect single linear arrays of the exported and extern "C"
1719  // functions
1720  std::vector<Symbol *> exportedFuncs, externCFuncs;
1721  m->symbolTable->GetMatchingFunctions(lIsExported, &exportedFuncs);
1722  m->symbolTable->GetMatchingFunctions(lIsExternC, &externCFuncs);
1723 
1724  // Get all of the struct, vector, and enumerant types used as function
1725  // parameters. These vectors may have repeats.
1726  std::vector<const StructType *> exportedStructTypes;
1727  std::vector<const EnumType *> exportedEnumTypes;
1728  std::vector<const VectorType *> exportedVectorTypes;
1729  lGetExportedParamTypes(exportedFuncs, &exportedStructTypes, &exportedEnumTypes, &exportedVectorTypes);
1730  lGetExportedParamTypes(externCFuncs, &exportedStructTypes, &exportedEnumTypes, &exportedVectorTypes);
1731 
1732  // Go through the explicitly exported types
1733  for (int i = 0; i < (int)exportedTypes.size(); ++i) {
1734  if (const StructType *st = CastType<StructType>(exportedTypes[i].first))
1735  exportedStructTypes.push_back(st->GetAsUniformType());
1736  else if (const EnumType *et = CastType<EnumType>(exportedTypes[i].first))
1737  exportedEnumTypes.push_back(et->GetAsUniformType());
1738  else if (const VectorType *vt = CastType<VectorType>(exportedTypes[i].first))
1739  exportedVectorTypes.push_back(vt->GetAsUniformType());
1740  else
1741  FATAL("Unexpected type in export list");
1742  }
1743 
1744  // And print them
1745  lEmitVectorTypedefs(exportedVectorTypes, f);
1746  lEmitEnumDecls(exportedEnumTypes, f);
1747  lEmitStructDecls(exportedStructTypes, f);
1748 
1749  // emit function declarations for exported stuff...
1750  if (exportedFuncs.size() > 0) {
1751  fprintf(f, "\n");
1752  fprintf(f, "///////////////////////////////////////////////////////////////////////////\n");
1753  fprintf(f, "// Functions exported from ispc code\n");
1754  fprintf(f, "///////////////////////////////////////////////////////////////////////////\n");
1755  lPrintFunctionDeclarations(f, exportedFuncs);
1756  }
1757 #if 0
1758  if (externCFuncs.size() > 0) {
1759  fprintf(f, "\n");
1760  fprintf(f, "///////////////////////////////////////////////////////////////////////////\n");
1761  fprintf(f, "// External C functions used by ispc code\n");
1762  fprintf(f, "///////////////////////////////////////////////////////////////////////////\n");
1763  lPrintFunctionDeclarations(f, externCFuncs);
1764  }
1765 #endif
1766 
1767  // end namespace
1768  fprintf(f, "\n");
1769  fprintf(f, "\n#ifdef __cplusplus\n} /* namespace */\n#endif // __cplusplus\n");
1770 
1771  // end guard
1772  if (g->noPragmaOnce)
1773  fprintf(f, "\n#endif // %s\n", guard.c_str());
1774 
1775  fclose(f);
1776  return true;
1777 }
1778 
1784  bool Emit4;
1785  bool Emit8;
1786  bool Emit16;
1787  FILE *file;
1788  const char *fn;
1789 };
1790 
1792  FILE *f = DHI->file;
1793 
1794  if (DHI->EmitFrontMatter) {
1795  fprintf(f, "//\n// %s\n// (Header automatically generated by the ispc compiler.)\n", DHI->fn);
1796  fprintf(f, "// DO NOT EDIT THIS FILE.\n//\n\n");
1797  }
1798  // Create a nice guard string from the filename, turning any
1799  // non-number/letter characters into underbars
1800  std::string guard = "ISPC_";
1801  const char *p = DHI->fn;
1802  while (*p) {
1803  if (isdigit(*p))
1804  guard += *p;
1805  else if (isalpha(*p))
1806  guard += toupper(*p);
1807  else
1808  guard += "_";
1809  ++p;
1810  }
1811  if (DHI->EmitFrontMatter) {
1812  if (g->noPragmaOnce)
1813  fprintf(f, "#ifndef %s\n#define %s\n\n", guard.c_str(), guard.c_str());
1814  else
1815  fprintf(f, "#pragma once\n");
1816 
1817  fprintf(f, "#include <stdint.h>\n\n");
1818 
1819  if (g->emitInstrumentation) {
1820  fprintf(f, "#define ISPC_INSTRUMENTATION 1\n");
1821  fprintf(f, "#if defined(__cplusplus) && (! defined(__ISPC_NO_EXTERN_C) || !__ISPC_NO_EXTERN_C )\nextern "
1822  "\"C\" {\n#endif // __cplusplus\n");
1823  fprintf(f, " void ISPCInstrument(const char *fn, const char *note, int line, uint64_t mask);\n");
1824  fprintf(f, "#if defined(__cplusplus) && (! defined(__ISPC_NO_EXTERN_C) || !__ISPC_NO_EXTERN_C )\n} /* end "
1825  "extern C */\n#endif // __cplusplus\n");
1826  }
1827 
1828  // end namespace
1829  fprintf(f, "\n");
1830  fprintf(f, "\n#ifdef __cplusplus\nnamespace ispc { /* namespace */\n#endif // __cplusplus\n\n");
1831  DHI->EmitFrontMatter = false;
1832  }
1833 
1834  // Collect single linear arrays of the exported and extern "C"
1835  // functions
1836  std::vector<Symbol *> exportedFuncs, externCFuncs;
1837  m->symbolTable->GetMatchingFunctions(lIsExported, &exportedFuncs);
1838  m->symbolTable->GetMatchingFunctions(lIsExternC, &externCFuncs);
1839 
1840  int programCount = g->target->getVectorWidth();
1841 
1842  if ((DHI->Emit4 && (programCount == 4)) || (DHI->Emit8 && (programCount == 8)) ||
1843  (DHI->Emit16 && (programCount == 16))) {
1844  // Get all of the struct, vector, and enumerant types used as function
1845  // parameters. These vectors may have repeats.
1846  std::vector<const StructType *> exportedStructTypes;
1847  std::vector<const EnumType *> exportedEnumTypes;
1848  std::vector<const VectorType *> exportedVectorTypes;
1849  lGetExportedParamTypes(exportedFuncs, &exportedStructTypes, &exportedEnumTypes, &exportedVectorTypes);
1850  lGetExportedParamTypes(externCFuncs, &exportedStructTypes, &exportedEnumTypes, &exportedVectorTypes);
1851 
1852  // Go through the explicitly exported types
1853  for (int i = 0; i < (int)exportedTypes.size(); ++i) {
1854  if (const StructType *st = CastType<StructType>(exportedTypes[i].first))
1855  exportedStructTypes.push_back(st->GetAsUniformType());
1856  else if (const EnumType *et = CastType<EnumType>(exportedTypes[i].first))
1857  exportedEnumTypes.push_back(et->GetAsUniformType());
1858  else if (const VectorType *vt = CastType<VectorType>(exportedTypes[i].first))
1859  exportedVectorTypes.push_back(vt->GetAsUniformType());
1860  else
1861  FATAL("Unexpected type in export list");
1862  }
1863 
1864  // And print them
1865  if (DHI->EmitUnifs) {
1866  lEmitVectorTypedefs(exportedVectorTypes, f);
1867  lEmitEnumDecls(exportedEnumTypes, f);
1868  }
1869  lEmitStructDecls(exportedStructTypes, f, DHI->EmitUnifs);
1870 
1871  // Update flags
1872  DHI->EmitUnifs = false;
1873  if (programCount == 4) {
1874  DHI->Emit4 = false;
1875  } else if (programCount == 8) {
1876  DHI->Emit8 = false;
1877  } else if (programCount == 16) {
1878  DHI->Emit16 = false;
1879  }
1880  }
1881  if (DHI->EmitFuncs) {
1882  // emit function declarations for exported stuff...
1883  if (exportedFuncs.size() > 0) {
1884  fprintf(f, "\n");
1885  fprintf(f, "///////////////////////////////////////////////////////////////////////////\n");
1886  fprintf(f, "// Functions exported from ispc code\n");
1887  fprintf(f, "///////////////////////////////////////////////////////////////////////////\n");
1888  lPrintFunctionDeclarations(f, exportedFuncs, 1, true);
1889  fprintf(f, "\n");
1890  }
1891  DHI->EmitFuncs = false;
1892  }
1893 
1894  if (DHI->EmitBackMatter) {
1895  // end namespace
1896  fprintf(f, "\n");
1897  fprintf(f, "\n#ifdef __cplusplus\n} /* namespace */\n#endif // __cplusplus\n");
1898 
1899  // end guard
1900  if (g->noPragmaOnce)
1901  fprintf(f, "\n#endif // %s\n", guard.c_str());
1902  DHI->EmitBackMatter = false;
1903  }
1904  return true;
1905 }
1906 
1907 void Module::execPreprocessor(const char *infilename, llvm::raw_string_ostream *ostream) const {
1908  clang::CompilerInstance inst;
1909 
1910  llvm::raw_fd_ostream stderrRaw(2, false);
1911 
1912  clang::DiagnosticOptions *diagOptions = new clang::DiagnosticOptions();
1913  clang::TextDiagnosticPrinter *diagPrinter = new clang::TextDiagnosticPrinter(stderrRaw, diagOptions);
1914 
1915  llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagIDs(new clang::DiagnosticIDs);
1916  clang::DiagnosticsEngine *diagEngine = new clang::DiagnosticsEngine(diagIDs, diagOptions, diagPrinter);
1917 
1918  inst.setDiagnostics(diagEngine);
1919 
1920  inst.createFileManager();
1921 
1922  const std::shared_ptr<clang::TargetOptions> &options = std::make_shared<clang::TargetOptions>(inst.getTargetOpts());
1923 
1924  llvm::Triple triple(module->getTargetTriple());
1925  if (triple.getTriple().empty()) {
1926  triple.setTriple(llvm::sys::getDefaultTargetTriple());
1927  }
1928 
1929  options->Triple = triple.getTriple();
1930 
1931  clang::TargetInfo *target = clang::TargetInfo::CreateTargetInfo(inst.getDiagnostics(), options);
1932  inst.setTarget(target);
1933  inst.createSourceManager(inst.getFileManager());
1934 
1935 #if ISPC_LLVM_VERSION <= ISPC_LLVM_9_0
1936  clang::FrontendInputFile inputFile(infilename, clang::InputKind::Unknown);
1937 #else // LLVM 10.0+
1938  clang::FrontendInputFile inputFile(infilename, clang::InputKind());
1939 #endif
1940 
1941  inst.InitializeSourceManager(inputFile);
1942 
1943  // Don't remove comments in the preprocessor, so that we can accurately
1944  // track the source file position by handling them ourselves.
1945  inst.getPreprocessorOutputOpts().ShowComments = 1;
1946 
1947  inst.getPreprocessorOutputOpts().ShowCPP = 1;
1948  clang::HeaderSearchOptions &headerOpts = inst.getHeaderSearchOpts();
1949  headerOpts.UseBuiltinIncludes = 0;
1950  headerOpts.UseStandardSystemIncludes = 0;
1951  headerOpts.UseStandardCXXIncludes = 0;
1952 #ifndef ISPC_NO_DUMPS
1953  if (g->debugPrint)
1954  headerOpts.Verbose = 1;
1955 #endif
1956  for (int i = 0; i < (int)g->includePath.size(); ++i) {
1957  headerOpts.AddPath(g->includePath[i], clang::frontend::Angled, false /* not a framework */,
1958  true /* ignore sys root */);
1959  }
1960 
1961  clang::PreprocessorOptions &opts = inst.getPreprocessorOpts();
1962 
1963  // Add defs for ISPC and PI
1964  opts.addMacroDef("ISPC");
1965  opts.addMacroDef("PI=3.1415926535");
1966 
1967  // Add defs for ISPC_UINT_IS_DEFINED.
1968  // This lets the user know uint* is part of language.
1969  opts.addMacroDef("ISPC_UINT_IS_DEFINED");
1970 
1971  // Add #define for current compilation target
1972  char targetMacro[128];
1973  snprintf(targetMacro, sizeof(targetMacro), "ISPC_TARGET_%s", g->target->GetISAString());
1974  char *p = targetMacro;
1975  while (*p) {
1976  *p = toupper(*p);
1977  if (*p == '-')
1978  *p = '_';
1979  ++p;
1980  }
1981 
1982  // Add 'TARGET_WIDTH' macro to expose vector width to user.
1983  std::string TARGET_WIDTH = "TARGET_WIDTH=" + std::to_string(g->target->getVectorWidth());
1984  opts.addMacroDef(TARGET_WIDTH);
1985 
1986  // Add 'TARGET_ELEMENT_WIDTH' macro to expose element width to user.
1987  std::string TARGET_ELEMENT_WIDTH = "TARGET_ELEMENT_WIDTH=" + std::to_string(g->target->getDataTypeWidth() / 8);
1988  opts.addMacroDef(TARGET_ELEMENT_WIDTH);
1989 
1990  opts.addMacroDef(targetMacro);
1991 
1992  if (g->target->is32Bit())
1993  opts.addMacroDef("ISPC_POINTER_SIZE=32");
1994  else
1995  opts.addMacroDef("ISPC_POINTER_SIZE=64");
1996 
1997  if (g->target->hasHalf())
1998  opts.addMacroDef("ISPC_TARGET_HAS_HALF");
1999  if (g->target->hasRand())
2000  opts.addMacroDef("ISPC_TARGET_HAS_RAND");
2001  if (g->target->hasTranscendentals())
2002  opts.addMacroDef("ISPC_TARGET_HAS_TRANSCENDENTALS");
2003  if (g->opt.forceAlignedMemory)
2004  opts.addMacroDef("ISPC_FORCE_ALIGNED_MEMORY");
2005 
2006  constexpr int buf_size = 25;
2007  char ispc_major[buf_size], ispc_minor[buf_size];
2008  snprintf(ispc_major, buf_size, "ISPC_MAJOR_VERSION=%d", ISPC_VERSION_MAJOR);
2009  snprintf(ispc_minor, buf_size, "ISPC_MINOR_VERSION=%d", ISPC_VERSION_MINOR);
2010  opts.addMacroDef(ispc_major);
2011  opts.addMacroDef(ispc_minor);
2012 
2013  if (g->includeStdlib) {
2014  if (g->opt.disableAsserts)
2015  opts.addMacroDef("assert(x)=");
2016  else
2017  opts.addMacroDef("assert(x)=__assert(#x, x)");
2018  }
2019 
2020  for (unsigned int i = 0; i < g->cppArgs.size(); ++i) {
2021  // Sanity check--should really begin with -D
2022  if (g->cppArgs[i].substr(0, 2) == "-D") {
2023  opts.addMacroDef(g->cppArgs[i].substr(2));
2024  }
2025  }
2026 
2027  inst.getLangOpts().LineComment = 1;
2028 
2029  inst.createPreprocessor(clang::TU_Complete);
2030 
2031  diagPrinter->BeginSourceFile(inst.getLangOpts(), &inst.getPreprocessor());
2032  clang::DoPrintPreprocessedInput(inst.getPreprocessor(), ostream, inst.getPreprocessorOutputOpts());
2033  diagPrinter->EndSourceFile();
2034 }
2035 
2036 // Given an output filename of the form "foo.obj", and an ISA name like
2037 // "avx", return a string with the ISA name inserted before the original
2038 // filename's suffix, like "foo_avx.obj".
2039 static std::string lGetTargetFileName(const char *outFileName, const char *isaString) {
2040  int bufferSize = strlen(outFileName) + 16;
2041  char *targetOutFileName = new char[bufferSize];
2042  if (strrchr(outFileName, '.') != NULL) {
2043  // Copy everything up to the last '.'
2044  int count = strrchr(outFileName, '.') - outFileName;
2045  strncpy(targetOutFileName, outFileName, count);
2046  targetOutFileName[count] = '\0';
2047 
2048  // Add the ISA name
2049  strncat(targetOutFileName, "_", bufferSize - strlen(targetOutFileName) - 1);
2050  strncat(targetOutFileName, isaString, bufferSize - strlen(targetOutFileName) - 1);
2051 
2052  // And finish with the original file suffix
2053  strncat(targetOutFileName, strrchr(outFileName, '.'), bufferSize - strlen(targetOutFileName) - 1);
2054  } else {
2055  // Can't find a '.' in the filename, so just append the ISA suffix
2056  // to what we weregiven
2057  strncpy(targetOutFileName, outFileName, bufferSize - 1);
2058  targetOutFileName[bufferSize - 1] = '\0';
2059  strncat(targetOutFileName, "_", bufferSize - strlen(targetOutFileName) - 1);
2060  strncat(targetOutFileName, isaString, bufferSize - strlen(targetOutFileName) - 1);
2061  }
2062  return targetOutFileName;
2063 }
2064 
2065 static bool lSymbolIsExported(const Symbol *s) { return s->exportedFunction != NULL; }
2066 
2067 // Small structure to hold pointers to the various different versions of a
2068 // llvm::Function that were compiled for different compilation target ISAs.
2071  for (int i = 0; i < Target::NUM_ISAS; ++i) {
2072  func[i] = NULL;
2073  FTs[i] = NULL;
2074  }
2075  }
2076  // The func array is indexed with the Target::ISA enumerant. Some
2077  // values may be NULL, indicating that the original function wasn't
2078  // compiled to the corresponding target ISA.
2079  llvm::Function *func[Target::NUM_ISAS];
2081 };
2082 
2083 // Given the symbol table for a module, return a map from function names to
2084 // FunctionTargetVariants for each function that was defined with the
2085 // 'export' qualifier in ispc.
2086 static void lGetExportedFunctions(SymbolTable *symbolTable, std::map<std::string, FunctionTargetVariants> &functions) {
2087  std::vector<Symbol *> syms;
2088  symbolTable->GetMatchingFunctions(lSymbolIsExported, &syms);
2089  for (unsigned int i = 0; i < syms.size(); ++i) {
2090  FunctionTargetVariants &ftv = functions[syms[i]->name];
2091  ftv.func[g->target->getISA()] = syms[i]->exportedFunction;
2092  ftv.FTs[g->target->getISA()] = CastType<FunctionType>(syms[i]->type);
2093  }
2094 }
2095 
2096 static llvm::FunctionType *lGetVaryingDispatchType(FunctionTargetVariants &funcs) {
2097  llvm::Type *ptrToInt8Ty = llvm::Type::getInt8PtrTy(*g->ctx);
2098  llvm::FunctionType *resultFuncTy = NULL;
2099 
2100  for (int i = 0; i < Target::NUM_ISAS; ++i) {
2101  if (funcs.func[i] == NULL) {
2102  continue;
2103  } else {
2104  bool foundVarying = false;
2105  const FunctionType *ft = funcs.FTs[i];
2106  resultFuncTy = funcs.func[i]->getFunctionType();
2107 
2108  int numArgs = ft->GetNumParameters();
2109  llvm::SmallVector<llvm::Type *, 8> ftype;
2110  for (int j = 0; j < numArgs; ++j) {
2111  ftype.push_back(resultFuncTy->getParamType(j));
2112  }
2113 
2114  for (int j = 0; j < numArgs; ++j) {
2115  const Type *arg = ft->GetParameterType(j);
2116 
2117  if (arg->IsPointerType()) {
2118  const Type *baseType = CastType<PointerType>(arg)->GetBaseType();
2119  // For each varying type pointed to, swap the LLVM pointer type
2120  // with i8 * (as close as we can get to void *)
2121  if (baseType->IsVaryingType()) {
2122  ftype[j] = ptrToInt8Ty;
2123  foundVarying = true;
2124  }
2125  }
2126  }
2127  if (foundVarying) {
2128  resultFuncTy = llvm::FunctionType::get(resultFuncTy->getReturnType(), ftype, false);
2129  }
2130  }
2131  }
2132 
2133  // We should've found at least one variant here
2134  // or else something fishy is going on.
2135  Assert(resultFuncTy);
2136 
2137  return resultFuncTy;
2138 }
2139 
2140 /** Create the dispatch function for an exported ispc function.
2141  This function checks to see which vector ISAs the system the
2142  code is running on supports and calls out to the best available
2143  variant that was generated at compile time.
2144 
2145  @param module Module in which to create the dispatch function.
2146  @param setISAFunc Pointer to the __set_system_isa() function defined
2147  in builtins-dispatch.ll (which is linked into the
2148  given module before we get here.)
2149  @param systemBestISAPtr Pointer to the module-local __system_best_isa
2150  variable, which holds a value of the Target::ISA
2151  enumerant giving the most capable ISA that the
2152  system supports.
2153  @param name Name of the function for which we're generating a
2154  dispatch function
2155  @param funcs Target-specific variants of the exported function.
2156 */
2157 static void lCreateDispatchFunction(llvm::Module *module, llvm::Function *setISAFunc, llvm::Value *systemBestISAPtr,
2158  const std::string &name, FunctionTargetVariants &funcs) {
2159  // The llvm::Function pointers in funcs are pointers to functions in
2160  // different llvm::Modules, so we can't call them directly. Therefore,
2161  // we'll start by generating an 'extern' declaration of each one that
2162  // we have in the current module so that we can then call out to that.
2163  llvm::Function *targetFuncs[Target::NUM_ISAS];
2164 
2165  // New helper function checks to see if we need to rewrite the
2166  // type for the dispatch function in case of pointers to varyings
2167  llvm::FunctionType *ftype = lGetVaryingDispatchType(funcs);
2168 
2169  // Now we insert type-punned declarations for dispatched functions.
2170  // This is needed when compiling modules for a set of architectures
2171  // with different vector lengths. Due to restrictions, the return
2172  // type is the same across all architectures, however in different
2173  // modules it may have dissimilar names. The loop below works this
2174  // around.
2175  for (int i = 0; i < Target::NUM_ISAS; ++i) {
2176  if (funcs.func[i])
2177  targetFuncs[i] =
2178  llvm::Function::Create(ftype, llvm::GlobalValue::ExternalLinkage, funcs.func[i]->getName(), module);
2179  else
2180  targetFuncs[i] = NULL;
2181  }
2182 
2183  bool voidReturn = ftype->getReturnType()->isVoidTy();
2184 
2185  // Now we can emit the definition of the dispatch function..
2186  llvm::Function *dispatchFunc =
2187  llvm::Function::Create(ftype, llvm::GlobalValue::ExternalLinkage, name.c_str(), module);
2188  llvm::BasicBlock *bblock = llvm::BasicBlock::Create(*g->ctx, "entry", dispatchFunc);
2189 
2190  // Start by calling out to the function that determines the system's
2191  // ISA and sets __system_best_isa, if it hasn't been set yet.
2192  llvm::CallInst::Create(setISAFunc, "", bblock);
2193 
2194  // Now we can load the system's ISA enumerant
2195  llvm::Value *systemISA = new llvm::LoadInst(systemBestISAPtr, "system_isa", bblock);
2196 
2197  // Now emit code that works backwards though the available variants of
2198  // the function. We'll call out to the first one we find that will run
2199  // successfully on the system the code is running on. In working
2200  // through the candidate ISAs here backward, we're taking advantage of
2201  // the expectation that they are ordered in the Target::ISA enumerant
2202  // from least to most capable.
2203  for (int i = Target::NUM_ISAS - 1; i >= 0; --i) {
2204  if (targetFuncs[i] == NULL)
2205  continue;
2206 
2207  // Emit code to see if the system can run the current candidate
2208  // variant successfully--"is the system's ISA enumerant value >=
2209  // the enumerant value of the current candidate?"
2210 
2211  llvm::Value *ok = llvm::CmpInst::Create(llvm::Instruction::ICmp, llvm::CmpInst::ICMP_SGE, systemISA,
2212  LLVMInt32(i), "isa_ok", bblock);
2213  llvm::BasicBlock *callBBlock = llvm::BasicBlock::Create(*g->ctx, "do_call", dispatchFunc);
2214  llvm::BasicBlock *nextBBlock = llvm::BasicBlock::Create(*g->ctx, "next_try", dispatchFunc);
2215  llvm::BranchInst::Create(callBBlock, nextBBlock, ok, bblock);
2216 
2217  // Emit the code to make the call call in callBBlock.
2218  // Just pass through all of the args from the dispatch function to
2219  // the target-specific function.
2220  std::vector<llvm::Value *> args;
2221  llvm::Function::arg_iterator argIter = dispatchFunc->arg_begin();
2222  llvm::Function::arg_iterator targsIter = targetFuncs[i]->arg_begin();
2223  for (; argIter != dispatchFunc->arg_end(); ++argIter, ++targsIter) {
2224  // Check to see if we rewrote any types in the dispatch function.
2225  // If so, create bitcasts for the appropriate pointer types.
2226  if (argIter->getType() == targsIter->getType()) {
2227  args.push_back(&*argIter);
2228  } else {
2229  llvm::CastInst *argCast = llvm::CastInst::CreatePointerCast(&*argIter, targsIter->getType(),
2230  "dpatch_arg_bitcast", callBBlock);
2231  args.push_back(argCast);
2232  }
2233  }
2234  if (voidReturn) {
2235  llvm::CallInst::Create(targetFuncs[i], args, "", callBBlock);
2236  llvm::ReturnInst::Create(*g->ctx, callBBlock);
2237  } else {
2238  llvm::Value *retValue = llvm::CallInst::Create(targetFuncs[i], args, "ret_value", callBBlock);
2239  llvm::ReturnInst::Create(*g->ctx, retValue, callBBlock);
2240  }
2241 
2242  // Otherwise we'll go on to the next candidate and see about that
2243  // one...
2244  bblock = nextBBlock;
2245  }
2246 
2247  // We couldn't find a match that the current system was capable of
2248  // running. We'll call abort(); this is a bit of a blunt hammer--it
2249  // might be preferable to call a user-supplied callback--ISPCError(...)
2250  // or some such, but we don't want to start imposing too much of a
2251  // runtime library requirement either...
2252  llvm::Function *abortFunc = module->getFunction("abort");
2253  Assert(abortFunc);
2254  llvm::CallInst::Create(abortFunc, "", bblock);
2255 
2256  // Return an undef value from the function here; we won't get to this
2257  // point at runtime, but LLVM needs all of the basic blocks to be
2258  // terminated...
2259  if (voidReturn)
2260  llvm::ReturnInst::Create(*g->ctx, bblock);
2261  else {
2262  llvm::Value *undefRet = llvm::UndefValue::get(ftype->getReturnType());
2263  llvm::ReturnInst::Create(*g->ctx, undefRet, bblock);
2264  }
2265 }
2266 
2267 // Initialize a dispatch module
2268 static llvm::Module *lInitDispatchModule() {
2269  llvm::Module *module = new llvm::Module("dispatch_module", *g->ctx);
2270 
2271  module->setTargetTriple(g->target->GetTripleString());
2272 
2273  // DataLayout information supposed to be managed in single place in Target class.
2274  module->setDataLayout(g->target->getDataLayout()->getStringRepresentation());
2275 
2276  // First, link in the definitions from the builtins-dispatch.ll file.
2277  const BitcodeLib *dispatch = g->target_registry->getDispatchLib();
2278  Assert(dispatch);
2279  AddBitcodeToModule(dispatch, module);
2280 
2281  return module;
2282 }
2283 
2284 // Complete the creation of a dispatch module.
2285 // Given a map that holds the mapping from each of the 'export'ed functions
2286 // in the ispc program to the target-specific variants of the function,
2287 // create a llvm::Module that has a dispatch function for each exported
2288 // function that checks the system's capabilities and picks the most
2289 // appropriate compiled variant of the function.
2290 static void lEmitDispatchModule(llvm::Module *module, std::map<std::string, FunctionTargetVariants> &functions) {
2291  // Get pointers to things we need below
2292  llvm::Function *setFunc = module->getFunction("__set_system_isa");
2293  Assert(setFunc != NULL);
2294  llvm::Value *systemBestISAPtr = module->getGlobalVariable("__system_best_isa", true);
2295  Assert(systemBestISAPtr != NULL);
2296 
2297  // For each exported function, create the dispatch function
2298  std::map<std::string, FunctionTargetVariants>::iterator iter;
2299  for (iter = functions.begin(); iter != functions.end(); ++iter)
2300  lCreateDispatchFunction(module, setFunc, systemBestISAPtr, iter->first, iter->second);
2301 
2302  // Do some rudimentary cleanup of the final result and make sure that
2303  // the module is all ok.
2304  llvm::legacy::PassManager optPM;
2305  optPM.add(llvm::createGlobalDCEPass());
2306  optPM.add(llvm::createVerifierPass());
2307  optPM.run(*module);
2308 }
2309 
2310 // Determines if two types are compatible
2311 static bool lCompatibleTypes(llvm::Type *Ty1, llvm::Type *Ty2) {
2312  while (Ty1->getTypeID() == Ty2->getTypeID())
2313  switch (Ty1->getTypeID()) {
2314  case llvm::ArrayType::ArrayTyID:
2315  if (Ty1->getArrayNumElements() != Ty2->getArrayNumElements())
2316  return false;
2317  Ty1 = Ty1->getArrayElementType();
2318  Ty2 = Ty2->getArrayElementType();
2319  break;
2320 
2321  case llvm::ArrayType::PointerTyID:
2322  Ty1 = Ty1->getPointerElementType();
2323  Ty2 = Ty2->getPointerElementType();
2324  break;
2325 
2326  case llvm::ArrayType::StructTyID: {
2327  llvm::StructType *STy1 = llvm::dyn_cast<llvm::StructType>(Ty1);
2328  llvm::StructType *STy2 = llvm::dyn_cast<llvm::StructType>(Ty2);
2329  return STy1 && STy2 && STy1->isLayoutIdentical(STy2);
2330  }
2331  default:
2332  // Pointers for compatible simple types are assumed equal
2333  return Ty1 == Ty2;
2334  }
2335  return false;
2336 }
2337 
2338 // Grab all of the global value definitions from the module and change them
2339 // to be declarations; we'll emit a single definition of each global in the
2340 // final module used with the dispatch functions, so that we don't have
2341 // multiple definitions of them, one in each of the target-specific output
2342 // files.
2343 static void lExtractOrCheckGlobals(llvm::Module *msrc, llvm::Module *mdst, bool check) {
2344  llvm::Module::global_iterator iter;
2345  llvm::ValueToValueMapTy VMap;
2346 
2347  for (iter = msrc->global_begin(); iter != msrc->global_end(); ++iter) {
2348  llvm::GlobalVariable *gv = &*iter;
2349  // Is it a global definition?
2350  if (gv->getLinkage() == llvm::GlobalValue::ExternalLinkage && gv->hasInitializer()) {
2351  llvm::Type *type = gv->getType()->getElementType();
2352  Symbol *sym = m->symbolTable->LookupVariable(gv->getName().str().c_str());
2353  Assert(sym != NULL);
2354 
2355  // Check presence and compatibility for the current global
2356  if (check) {
2357  llvm::GlobalVariable *exist = mdst->getGlobalVariable(gv->getName());
2358  Assert(exist != NULL);
2359 
2360  // It is possible that the types may not match: for
2361  // example, this happens with varying globals if we
2362  // compile to different vector widths
2363  if (!lCompatibleTypes(exist->getType(), gv->getType())) {
2364  Warning(sym->pos,
2365  "Mismatch in size/layout of global "
2366  "variable \"%s\" with different targets. "
2367  "Globals must not include \"varying\" types or arrays "
2368  "with size based on programCount when compiling to "
2369  "targets with differing vector widths.",
2370  gv->getName().str().c_str());
2371  }
2372  }
2373  // Alternatively, create it anew and make it match the original
2374  else {
2375  llvm::GlobalVariable *newGlobal =
2376  new llvm::GlobalVariable(*mdst, type, gv->isConstant(), llvm::GlobalValue::ExternalLinkage,
2377  (llvm::Constant *)nullptr, gv->getName());
2378  VMap[&*iter] = newGlobal;
2379 
2380  newGlobal->setInitializer(llvm::MapValue(iter->getInitializer(), VMap));
2381  newGlobal->copyAttributesFrom(gv);
2382  }
2383  // Turn this into an 'extern' declaration by clearing its
2384  // initializer.
2385  gv->setInitializer(NULL);
2386  }
2387  }
2388 }
2389 
2390 int Module::CompileAndOutput(const char *srcFile, Arch arch, const char *cpu, std::vector<ISPCTarget> targets,
2391  OutputFlags outputFlags, OutputType outputType, const char *outFileName,
2392  const char *headerFileName, const char *includeFileName, const char *depsFileName,
2393  const char *depsTargetName, const char *hostStubFileName, const char *devStubFileName) {
2394  if (targets.size() == 0 || targets.size() == 1) {
2395  // We're only compiling to a single target
2396  // TODO something wrong here
2397  ISPCTarget target = ISPCTarget::none;
2398  if (targets.size() == 1) {
2399  target = targets[0];
2400  }
2401  g->target = new Target(arch, cpu, target, 0 != (outputFlags & GeneratePIC), g->printTarget);
2402  if (!g->target->isValid())
2403  return 1;
2404 
2405  m = new Module(srcFile);
2406  if (m->CompileFile() == 0) {
2407  if (outputType == CXX) {
2408  if (target == ISPCTarget::none || !ISPCTargetIsGeneric(target)) {
2409  Error(SourcePos(), "When generating C++ output, one of the \"generic-*\" "
2410  "targets must be used.");
2411  return 1;
2412  }
2413  } else if (outputType == Asm || outputType == Object) {
2414  if (ISPCTargetIsGeneric(target)) {
2415  Error(SourcePos(),
2416  "When using a \"generic-*\" compilation target, "
2417  "%s output can not be used.",
2418  (outputType == Asm) ? "assembly" : "object file");
2419  return 1;
2420  }
2421  }
2422 
2423  if (outFileName != NULL)
2424  if (!m->writeOutput(outputType, outputFlags, outFileName, includeFileName))
2425  return 1;
2426  if (headerFileName != NULL)
2427  if (!m->writeOutput(Module::Header, outputFlags, headerFileName))
2428  return 1;
2429  if (depsFileName != NULL || (outputFlags & Module::OutputDepsToStdout)) {
2430  std::string targetName;
2431  if (depsTargetName)
2432  targetName = depsTargetName;
2433  else if (outFileName)
2434  targetName = outFileName;
2435  else if (!IsStdin(srcFile)) {
2436  targetName = srcFile;
2437  size_t dot = targetName.find_last_of('.');
2438  if (dot != std::string::npos)
2439  targetName.erase(dot, std::string::npos);
2440  targetName.append(".o");
2441  } else
2442  targetName = "a.out";
2443  if (!m->writeOutput(Module::Deps, outputFlags, depsFileName, targetName.c_str(), srcFile))
2444  return 1;
2445  }
2446  if (hostStubFileName != NULL)
2447  if (!m->writeOutput(Module::HostStub, outputFlags, hostStubFileName))
2448  return 1;
2449  if (devStubFileName != NULL)
2450  if (!m->writeOutput(Module::DevStub, outputFlags, devStubFileName))
2451  return 1;
2452  } else
2453  ++m->errorCount;
2454 
2455  int errorCount = m->errorCount;
2456  delete m;
2457  m = NULL;
2458 
2459  delete g->target;
2460  g->target = NULL;
2461 
2462  return errorCount > 0;
2463  } else {
2464  if (outputType == CXX) {
2465  Error(SourcePos(), "Illegal to specify more than one target when "
2466  "compiling C++ output.");
2467  return 1;
2468  }
2469  if (IsStdin(srcFile)) {
2470  Error(SourcePos(), "Compiling programs from standard input isn't "
2471  "supported when compiling for multiple targets. Please use "
2472  "an intermediate temporary file.");
2473  return 1;
2474  }
2475  if (cpu != NULL) {
2476  Error(SourcePos(), "Illegal to specify cpu type when compiling "
2477  "for multiple targets.");
2478  return 1;
2479  }
2480 
2481  // The user supplied multiple targets
2482  Assert(targets.size() > 1);
2483 
2484  if (outFileName != NULL && strcmp(outFileName, "-") == 0) {
2485  Error(SourcePos(), "Multi-target compilation can't generate output "
2486  "to stdout. Please provide an output filename.\n");
2487  return 1;
2488  }
2489 
2490  // Make sure that the function names for 'export'ed functions have
2491  // the target ISA appended to them.
2492  g->mangleFunctionsWithTarget = true;
2493 
2494  llvm::TargetMachine *targetMachines[Target::NUM_ISAS];
2495  for (int i = 0; i < Target::NUM_ISAS; ++i)
2496  targetMachines[i] = NULL;
2497 
2498  llvm::Module *dispatchModule = NULL;
2499 
2500  std::map<std::string, FunctionTargetVariants> exportedFunctions;
2501  int errorCount = 0;
2502 
2503  // Handle creating a "generic" header file for multiple targets
2504  // that use exported varyings
2505  DispatchHeaderInfo DHI;
2506  if (headerFileName != NULL) {
2507  DHI.file = fopen(headerFileName, "w");
2508  if (!DHI.file) {
2509  perror("fopen");
2510  return false;
2511  }
2512  DHI.fn = headerFileName;
2513  DHI.EmitUnifs = true;
2514  DHI.EmitFuncs = true;
2515  DHI.EmitFrontMatter = true;
2516  DHI.Emit4 = true;
2517  DHI.Emit8 = true;
2518  DHI.Emit16 = true;
2519  // This is toggled later.
2520  DHI.EmitBackMatter = false;
2521  }
2522 
2523  for (unsigned int i = 0; i < targets.size(); ++i) {
2524  g->target = new Target(arch, cpu, targets[i], 0 != (outputFlags & GeneratePIC), g->printTarget);
2525  if (!g->target->isValid())
2526  return 1;
2527 
2528  // Issue an error if we've already compiled to a variant of
2529  // this target ISA. (It doesn't make sense to compile to both
2530  // avx and avx-x2, for example.)
2531  if (targetMachines[g->target->getISA()] != NULL) {
2532  Error(SourcePos(),
2533  "Can't compile to multiple variants of %s "
2534  "target!\n",
2535  g->target->GetISAString());
2536  return 1;
2537  }
2538  targetMachines[g->target->getISA()] = g->target->GetTargetMachine();
2539 
2540  m = new Module(srcFile);
2541  if (m->CompileFile() == 0) {
2542  // Create the dispatch module, unless already created;
2543  // in the latter case, just do the checking
2544  bool check = (dispatchModule != NULL);
2545  if (!check)
2546  dispatchModule = lInitDispatchModule();
2547  lExtractOrCheckGlobals(m->module, dispatchModule, check);
2548 
2549  // Grab pointers to the exported functions from the module we
2550  // just compiled, for use in generating the dispatch function
2551  // later.
2552  lGetExportedFunctions(m->symbolTable, exportedFunctions);
2553 
2554  if (outFileName != NULL) {
2555  std::string targetOutFileName;
2556  const char *isaName = g->target->GetISAString();
2557  targetOutFileName = lGetTargetFileName(outFileName, isaName);
2558  if (!m->writeOutput(outputType, outputFlags, targetOutFileName.c_str())) {
2559  return 1;
2560  }
2561  }
2562  } else {
2563  ++m->errorCount;
2564  }
2565 
2566  errorCount += m->errorCount;
2567  if (errorCount != 0) {
2568  return 1;
2569  }
2570 
2571  // Only write the generate header file, if desired, the first
2572  // time through the loop here.
2573  if (headerFileName != NULL) {
2574  if (i == targets.size() - 1) {
2575  // only print backmatter on the last target.
2576  DHI.EmitBackMatter = true;
2577  }
2578 
2579  const char *isaName;
2580  isaName = g->target->GetISAString();
2581  std::string targetHeaderFileName = lGetTargetFileName(headerFileName, isaName);
2582  // write out a header w/o target name for the first target only
2583  if (!m->writeOutput(Module::Header, outputFlags, headerFileName, "", nullptr, &DHI)) {
2584  return 1;
2585  }
2586  if (!m->writeOutput(Module::Header, outputFlags, targetHeaderFileName.c_str())) {
2587  return 1;
2588  }
2589  if (i == targets.size() - 1) {
2590  fclose(DHI.file);
2591  }
2592  }
2593 
2594  delete g->target;
2595  g->target = NULL;
2596 
2597  // Important: Don't delete the llvm::Module *m here; we need to
2598  // keep it around so the llvm::Functions *s stay valid for when
2599  // we generate the dispatch module's functions...
2600  }
2601 
2602  // Find the first non-NULL target machine from the targets we
2603  // compiled to above. We'll use this as the target machine for
2604  // compiling the dispatch module--this is safe in that it is the
2605  // least-common-denominator of all of the targets we compiled to.
2606  llvm::TargetMachine *firstTargetMachine = NULL;
2607  int i = 0;
2608  const char *firstISA = "";
2609  ISPCTarget firstTarget = ISPCTarget::none;
2610  while (i < Target::NUM_ISAS && firstTargetMachine == NULL) {
2611  firstISA = Target::ISAToTargetString((Target::ISA)i);
2612  firstTarget = ParseISPCTarget(firstISA);
2613  firstTargetMachine = targetMachines[i++];
2614  }
2615  Assert(strcmp(firstISA, "") != 0);
2616  Assert(firstTarget != ISPCTarget::none);
2617  Assert(firstTargetMachine != NULL);
2618 
2619  g->target = new Target(arch, cpu, firstTarget, 0 != (outputFlags & GeneratePIC), false);
2620  if (!g->target->isValid()) {
2621  return 1;
2622  }
2623 
2624  if (dispatchModule == NULL) {
2625  Error(SourcePos(), "Failed to create dispatch module.\n");
2626  return 1;
2627  }
2628 
2629  lEmitDispatchModule(dispatchModule, exportedFunctions);
2630 
2631  if (outFileName != NULL) {
2632  if ((outputType == Bitcode) || (outputType == BitcodeText))
2633  writeBitcode(dispatchModule, outFileName, outputType);
2634  else
2635  writeObjectFileOrAssembly(firstTargetMachine, dispatchModule, outputType, outFileName);
2636  }
2637 
2638  if (depsFileName != NULL || (outputFlags & Module::OutputDepsToStdout)) {
2639  std::string targetName;
2640  if (depsTargetName)
2641  targetName = depsTargetName;
2642  else if (outFileName)
2643  targetName = outFileName;
2644  else if (!IsStdin(srcFile)) {
2645  targetName = srcFile;
2646  size_t dot = targetName.find_last_of('.');
2647  if (dot != std::string::npos)
2648  targetName.erase(dot, std::string::npos);
2649  targetName.append(".o");
2650  } else
2651  targetName = "a.out";
2652  if (!m->writeOutput(Module::Deps, outputFlags, depsFileName, targetName.c_str(), srcFile))
2653  return 1;
2654  }
2655 
2656  delete g->target;
2657  g->target = NULL;
2658  return errorCount > 0;
2659  }
2660 }
int yyparse()
llvm::Value * storagePtr
Definition: sym.h:70
static const AtomicType * VaryingInt32
Definition: type.h:325
bool writeOutput(OutputType ot, OutputFlags flags, const char *filename, const char *includeFileName=NULL, const char *sourceFileName=NULL, DispatchHeaderInfo *DHI=0)
Definition: module.cpp:815
bool IsReferenceType() const
Definition: type.cpp:165
TargetOS target_os
Definition: ispc.h:515
bool IsUniformType() const
Definition: type.h:134
llvm::Function * function
Definition: sym.h:74
bool isMultiTargetCompilation
Definition: ispc.h:636
void DefineStdlib(SymbolTable *symbolTable, llvm::LLVMContext *ctx, llvm::Module *module, bool includeStdlibISPC)
Definition: builtins.cpp:920
ISPCTarget
Definition: target_enums.h:55
Definition: ast.h:138
Opt opt
Definition: ispc.h:509
llvm::DIFile * GetDIFile() const
Definition: ispc.cpp:1507
void AddTypeDef(const std::string &name, const Type *type, SourcePos pos)
Definition: module.cpp:266
const Type * GetReturnType() const
Definition: type.h:864
virtual const Type * GetAsUnsignedType() const
Definition: type.cpp:2569
std::vector< std::pair< const Type *, SourcePos > > exportedTypes
Definition: module.h:162
bool writeDevStub(const char *filename)
Definition: module.cpp:1422
static void lEmitEnumDecls(const std::vector< const EnumType *> &enumTypes, FILE *file)
Definition: module.cpp:1133
Declaration of the FunctionEmitContext class
#define ISPC_VERSION_MINOR
Definition: ispc_version.h:41
TargetLibRegistry * target_registry
Definition: ispc.h:506
bool AddFunction(Symbol *symbol)
Definition: sym.cpp:126
static const AtomicType * VaryingUInt64
Definition: type.h:331
static void lCheckForStructParameters(const FunctionType *ftype, SourcePos pos)
Definition: module.cpp:531
YY_BUFFER_STATE yy_create_buffer(FILE *, int)
bool IsVaryingType() const
Definition: type.h:137
static llvm::Module * lInitDispatchModule()
Definition: module.cpp:2268
static void lCreateDispatchFunction(llvm::Module *module, llvm::Function *setISAFunc, llvm::Value *systemBestISAPtr, const std::string &name, FunctionTargetVariants &funcs)
Definition: module.cpp:2157
#define UNESCAPE_SEQ(c, esc)
static void lExtractOrCheckGlobals(llvm::Module *msrc, llvm::Module *mdst, bool check)
Definition: module.cpp:2343
static bool lSymbolIsExported(const Symbol *s)
Definition: module.cpp:2065
Interface class for statements in the ispc language.
Definition: stmt.h:48
std::string emitOffloadParamStruct(const std::string &paramStructName, const Symbol *sym, const FunctionType *fct)
Definition: module.cpp:1388
int first_line
Definition: ispc.h:127
Structure that defines a compilation target.
Definition: ispc.h:149
int GetSOAWidth() const
Definition: type.h:145
Target * target
Definition: ispc.h:512
ASTNode * TypeCheck(ASTNode *root)
Definition: ast.cpp:242
bool AddVariable(Symbol *symbol)
Definition: sym.cpp:85
virtual std::pair< llvm::Constant *, bool > GetStorageConstant(const Type *type) const
Definition: expr.cpp:84
static void lEmitVectorTypedefs(const std::vector< const VectorType *> &types, FILE *file)
Definition: module.cpp:1171
const std::string & GetParameterName(int i) const
Definition: type.cpp:2556
Expression representing a compile-time constant value.
Definition: expr.h:374
llvm::Function * func[Target::NUM_ISAS]
Definition: module.cpp:2079
Abstract base class for types that represent sequences.
Definition: type.h:498
std::vector< std::string > includePath
Definition: ispc.h:623
std::string GetCDeclaration(const std::string &fname) const
Definition: type.cpp:2364
static void lCheckExportedParameterTypes(const Type *type, const std::string &name, SourcePos pos)
Definition: module.cpp:505
const Type * GetElementType() const
Definition: type.cpp:1185
void AddFunctionDeclaration(const std::string &name, const FunctionType *ftype, StorageClass sc, bool isInline, bool isNoInline, SourcePos pos)
Definition: module.cpp:549
bool NoOmitFramePointer
Definition: ispc.h:542
std::string Mangle() const
Definition: type.cpp:2350
Symbol table that holds all known symbols during parsing and compilation.
Definition: sym.h:116
std::string GetTripleString() const
Definition: ispc.cpp:1124
void yy_switch_to_buffer(YY_BUFFER_STATE)
Expr * TypeConvertExpr(Expr *expr, const Type *toType, const char *errorMsgBase)
Definition: expr.cpp:548
Declarations related to optimization passes.
void InitLLVMUtil(llvm::LLVMContext *ctx, Target &target)
Definition: llvmutil.cpp:97
static void lGetExportedTypes(const Type *type, std::vector< const StructType *> *exportedStructTypes, std::vector< const EnumType *> *exportedEnumTypes, std::vector< const VectorType *> *exportedVectorTypes)
Definition: module.cpp:1226
bool forceAlignedMemory
Definition: ispc.h:426
const FunctionType * FTs[Target::NUM_ISAS]
Definition: module.cpp:2080
int getDataTypeWidth() const
Definition: ispc.h:243
Declarations of functions related to builtins and the standard library.
const char * fn
Definition: module.cpp:1788
bool hasHalf() const
Definition: ispc.h:253
int GetNumParameters() const
Definition: type.h:874
Module * m
Definition: ispc.cpp:73
std::string name
Definition: sym.h:69
Symbol * LookupVariable(const char *name)
Definition: sym.cpp:112
OutputType
Definition: module.h:86
Type implementation for pointers to other types.
Definition: type.h:419
static bool lIsExternC(const Symbol *sym)
Definition: module.cpp:1313
int TotalElementCount() const
Definition: type.cpp:1266
bool writeHeader(const char *filename)
Definition: module.cpp:1675
const Type * GetBaseType() const
Definition: type.cpp:1363
ConstExpr * constValue
Definition: sym.h:85
static const StructType * lGetElementStructType(const Type *t)
Definition: module.cpp:1007
bool writeObjectFileOrAssembly(OutputType outputType, const char *filename)
Definition: module.cpp:950
virtual llvm::Type * LLVMType(llvm::LLVMContext *ctx) const =0
header file with declarations for symbol and symbol table classes.
bool writeHostStub(const char *filename)
Definition: module.cpp:1557
Type representing a reference to another (non-reference) type.
Definition: type.h:782
static llvm::FunctionType * lGetVaryingDispatchType(FunctionTargetVariants &funcs)
Definition: module.cpp:2096
virtual const Type * GetReferenceTarget() const
Definition: type.cpp:2564
bool includeStdlib
Definition: ispc.h:528
virtual llvm::DIType * GetDIType(llvm::DIScope *scope) const =0
int level
Definition: ispc.h:392
static bool lIsExported(const Symbol *sym)
Definition: module.cpp:1307
llvm::Module * module
Definition: module.h:151
void execPreprocessor(const char *infilename, llvm::raw_string_ostream *ostream) const
Definition: module.cpp:1907
Expr * GetParameterDefault(int i) const
Definition: type.cpp:2546
File with declarations for classes related to statements in the language.
struct yy_buffer_state * YY_BUFFER_STATE
Definition: module.cpp:197
llvm::Type * LLVMType(llvm::LLVMContext *ctx) const
Definition: type.cpp:1809
std::set< std::string > registeredDependencies
Definition: module.cpp:97
const SourcePos & GetParameterSourcePos(int i) const
Definition: type.cpp:2551
bool debugPrint
Definition: ispc.h:536
void RegisterDependency(const std::string &fileName)
Definition: module.cpp:101
static bool lContainsPtrToVarying(const StructType *st)
Definition: module.cpp:1019
const bool isExternC
Definition: type.h:890
void AddExportedTypes(const std::vector< std::pair< const Type *, SourcePos >> &types)
Definition: module.cpp:802
bool AddType(const char *name, const Type *type, SourcePos pos)
Definition: sym.cpp:165
bool LookupFunction(const char *name, std::vector< Symbol *> *matches=NULL)
Definition: sym.cpp:139
bool printTarget
Definition: ispc.h:539
static void lPrintFunctionDeclarations(FILE *file, const std::vector< Symbol *> &funcs, bool useExternC=1, bool rewriteForDispatch=false)
Definition: module.cpp:1283
const Type * GetReferenceTarget() const
Definition: type.cpp:2087
static void lGetExportedParamTypes(const std::vector< Symbol *> &funcs, std::vector< const StructType *> *exportedStructTypes, std::vector< const EnumType *> *exportedEnumTypes, std::vector< const VectorType *> *exportedVectorTypes)
Definition: module.cpp:1265
bool runCPP
Definition: ispc.h:532
static void lDeclareSizeAndPtrIntTypes(SymbolTable *symbolTable)
Definition: module.cpp:106
Representation of a structure holding a number of members.
Definition: type.h:650
int GetValues(bool *, bool forceVarying=false) const
Definition: expr.cpp:5535
char currentDirectory[1024]
Definition: ispc.h:615
void GetDirectoryAndFileName(const std::string &currentDirectory, const std::string &relativeName, std::string *directory, std::string *filename)
Definition: util.cpp:516
bool mangleFunctionsWithTarget
Definition: ispc.h:600
Header file with declarations for various LLVM utility stuff.
const std::string & GetElementName(int i) const
Definition: type.h:696
int CompileFile()
Definition: module.cpp:203
ISPCTarget ParseISPCTarget(std::string target)
bool emitInstrumentation
Definition: ispc.h:582
SourcePos pos
Definition: sym.h:68
uint32_t RoundUpPow2(uint32_t v)
Definition: util.h:50
Module(const char *filename)
Definition: module.cpp:131
static void lGetExportedFunctions(SymbolTable *symbolTable, std::map< std::string, FunctionTargetVariants > &functions)
Definition: module.cpp:2086
StorageClass storageClass
Definition: sym.h:94
bool hasRand() const
Definition: ispc.h:255
Representation of a range of positions in a source file.
Definition: ispc.h:123
bool generateDebuggingSymbols
Definition: ispc.h:588
llvm::ConstantInt * LLVMInt32(int32_t ival)
Definition: llvmutil.cpp:233
Type implementation for enumerated types.
Definition: type.h:347
virtual const Type * GetAsNonConstType() const =0
virtual std::string GetString() const =0
bool hasTranscendentals() const
Definition: ispc.h:261
StorageClass
Definition: ispc.h:114
bool force32BitAddressing
Definition: ispc.h:412
int GetElementCount() const
Definition: type.h:699
bool dllExport
Definition: ispc.h:630
const char * name
Definition: ispc.h:126
void markFuncWithTargetAttr(llvm::Function *func)
Definition: ispc.cpp:1410
static void lEmitStructDecl(const StructType *st, std::vector< const StructType *> *emittedStructs, FILE *file, bool emitUnifs=true)
Definition: module.cpp:1036
SourcePos pos
Definition: ast.h:76
bool IsVoidType() const
Definition: type.cpp:167
static const AtomicType * VaryingInt64
Definition: type.h:330
void Error(SourcePos p, const char *fmt,...)
Definition: util.cpp:351
#define ISPC_VERSION_MAJOR
Definition: ispc_version.h:40
int getVectorWidth() const
Definition: ispc.h:245
bool IsPointerType() const
Definition: type.cpp:161
static void lAddTypeIfNew(const Type *type, std::vector< const T *> *exportedTypes)
Definition: module.cpp:1208
#define FATAL(message)
Definition: util.h:116
A (short) vector of atomic types.
Definition: type.h:600
llvm::Type * LLVMType(llvm::LLVMContext *ctx) const
Definition: type.cpp:1460
const Type * GetElementType(const std::string &name) const
Definition: type.cpp:1881
const llvm::DataLayout * getDataLayout() const
Definition: ispc.h:224
static void lEmitStructDecls(std::vector< const StructType *> &structTypes, FILE *file, bool emitUnifs=true)
Definition: module.cpp:1112
const std::string GetCStructName() const
Definition: type.cpp:1630
YY_BUFFER_STATE yy_scan_string(const char *)
Representation of a function in a source file.
static void lEmitDispatchModule(llvm::Module *module, std::map< std::string, FunctionTargetVariants > &functions)
Definition: module.cpp:2290
std::string GetCDeclarationForDispatch(const std::string &fname) const
Definition: type.cpp:2392
#define Assert(expr)
Definition: util.h:128
virtual const Type * GetElementType() const =0
static bool Equal(const Type *a, const Type *b)
Definition: type.cpp:2853
ISA
Definition: ispc.h:157
const bool isTask
Definition: type.h:882
static std::string lGetTargetFileName(const char *outFileName, const char *isaString)
Definition: module.cpp:2039
void AddFunctionDefinition(const std::string &name, const FunctionType *ftype, Stmt *code)
Definition: module.cpp:783
OutputFlags
Definition: module.h:100
ISA getISA() const
Definition: ispc.h:231
const Type * GetParameterType(int i) const
Definition: type.cpp:2541
const char * GetISAString() const
Definition: ispc.cpp:1287
static void lUnescapeStringInPlace(std::string &str)
Definition: module.cpp:1319
Type representing a function (return type + argument types)
Definition: type.h:829
Representation of a program symbol.
Definition: sym.h:62
void AddFunction(Symbol *sym, Stmt *code)
Definition: ast.cpp:55
void GenerateIR()
Definition: ast.cpp:61
virtual bool IsConstType() const =0
Interface class that defines the type abstraction.
Definition: type.h:90
Globals * g
Definition: ispc.cpp:72
int generateDWARFVersion
Definition: ispc.h:596
Expr abstract base class and expression implementations.
void AddBitcodeToModule(const BitcodeLib *lib, llvm::Module *module, SymbolTable *symbolTable, bool warn)
Definition: builtins.cpp:746
llvm::DICompileUnit * diCompileUnit
Definition: module.h:156
static bool lRecursiveCheckValidParamType(const Type *t, bool vectorOk)
Definition: module.cpp:465
void GetMatchingFunctions(Predicate pred, std::vector< Symbol *> *matches) const
Definition: sym.h:277
static bool lCompatibleTypes(llvm::Type *Ty1, llvm::Type *Ty2)
Definition: module.cpp:2311
static bool writeBitcode(llvm::Module *module, const char *outFileName, OutputType outputType)
Definition: module.cpp:917
Expr is the abstract base class that defines the interface that all expression types must implement...
Definition: expr.h:47
static void lStripUnusedDebugInfo(llvm::Module *module)
Definition: module.cpp:126
virtual std::string GetCDeclaration(const std::string &name) const =0
const BitcodeLib * getDispatchLib() const
bool noPragmaOnce
Definition: ispc.h:584
ASTNode * Optimize(ASTNode *root)
Definition: ast.cpp:234
bool writeDeps(const char *filename, bool generateMakeRule, const char *targetName=NULL, const char *srcFilename=NULL)
Definition: module.cpp:1350
bool isValid() const
Definition: ispc.h:227
FILE * yyin
static const Type * SizeUnsizedArrays(const Type *type, Expr *initExpr)
Definition: type.cpp:1288
virtual const Type * GetBaseType() const =0
#define ISPC_VERSION
Definition: ispc_version.h:42
static int CompileAndOutput(const char *srcFile, Arch arch, const char *cpu, std::vector< ISPCTarget > targets, OutputFlags outputFlags, OutputType outputType, const char *outFileName, const char *headerFileName, const char *includeFileName, const char *depsFileName, const char *depsTargetName, const char *hostStubFileName, const char *devStubFileName)
Definition: module.cpp:2390
std::vector< std::string > cppArgs
Definition: ispc.h:619
void AddGlobalVariable(const std::string &name, const Type *type, Expr *initExpr, bool isConst, StorageClass storageClass, SourcePos pos)
Definition: module.cpp:272
const bool isExported
Definition: type.h:886
bool is32Bit() const
Definition: ispc.h:235
int GetElementCount() const
Definition: type.cpp:1416
Declaration of the Module class, which is the ispc-side representation of the results of compiling a ...
const VectorType * GetAsNonConstType() const
Definition: type.cpp:1391
int errorCount
Definition: module.h:144
virtual const Type * GetAsUnboundVariabilityType() const =0
llvm::LLVMContext * ctx
Definition: ispc.h:611
const char * filename
Definition: module.h:159
void yy_delete_buffer(YY_BUFFER_STATE)
const Type * type
Definition: sym.h:82
llvm::DIBuilder * diBuilder
Definition: module.h:154
void Warning(SourcePos p, const char *fmt,...)
Definition: util.cpp:378
Arch
Definition: target_enums.h:50
static bool EqualIgnoringConst(const Type *a, const Type *b)
Definition: type.cpp:2855
bool disableAsserts
Definition: ispc.h:416
static const AtomicType * VaryingUInt32
Definition: type.h:328
static const char * ISAToTargetString(Target::ISA isa)
Definition: ispc.cpp:1292
const std::string GetReturnTypeString() const
Definition: type.cpp:2452
virtual llvm::Type * LLVMStorageType(llvm::LLVMContext *ctx) const
Definition: type.cpp:125
llvm::TargetMachine * GetTargetMachine() const
Definition: ispc.h:191
SymbolTable * symbolTable
Definition: module.h:148
llvm::Function * exportedFunction
Definition: sym.h:77
bool IsStdin(const char *filepath)
Definition: util.cpp:621
bool IsArrayType() const
Definition: type.cpp:163
File with declarations for classes related to type representation.
AST * ast
Definition: module.h:160
llvm::FunctionType * LLVMFunctionType(llvm::LLVMContext *ctx, bool disableMask=false) const
Definition: type.cpp:2476
bool ISPCTargetIsGeneric(ISPCTarget target)
bool WriteCXXFile(llvm::Module *module, const char *fn, int vectorWidth, const char *includeName)
Definition: cbackend.cpp:5237
bool writeDispatchHeader(DispatchHeaderInfo *DHI)
Definition: module.cpp:1791
One-dimensional array type.
Definition: type.h:521