34 '''Usage: wrap.py [-fgd] [-i pmpi_init] [-c mpicc_name] [-o file] wrapper.w [...]    35  Python script for creating PMPI wrappers. Roughly follows the syntax of    36    the Argonne PMPI wrapper generator, with some enhancements.    38    -d             Just dump function declarations parsed out of mpi.h    39    -f             Generate fortran wrappers in addition to C wrappers.    40    -g             Generate reentry guards around wrapper functions.    41    -s             Skip writing #includes, #defines, and other front-matter (for non-C output).    42    -c exe         Provide name of MPI compiler (for parsing mpi.h).  Default is \'mpicc\'.    43    -I dir         Provide an extra include directory to use when parsing mpi.h.    44    -i pmpi_init   Specify proper binding for the fortran pmpi_init function.    45                   Default is \'pmpi_init_\'.  Wrappers compiled for PIC will guess the    46                   right binding automatically (use -DPIC when you compile dynamic libs).    47    -o file        Send output to a file instead of stdout.    48  by Todd Gamblin, tgamblin@llnl.gov    50 import tempfile, getopt, subprocess, sys, os, re, StringIO, types, itertools
    55 pmpi_init_binding = 
"pmpi_init_"       56 output_fortran_wrappers = 
False        59 dump_prototypes = 
False                62 pmpi_init_bindings = [
"PMPI_INIT", 
"pmpi_init", 
"pmpi_init_", 
"pmpi_init__"]
    68 rtypes = [
'int', 
'double' ]
    71 exclude_strings = [ 
"c2f", 
"f2c", 
"typedef" ]
    75 begin_decl_re = re.compile(
"(" + 
"|".join(rtypes) + 
")\s+(MPI_\w+)\s*\(")
    76 exclude_re =    re.compile(
"|".join(exclude_strings))
    77 end_decl_re =   re.compile(
"\).*\;")
    81 formal_re = re.compile(
    86     "(?:\s*\*(?:\s*const)?)*" +    
    93 f_wrap_suffix = 
"_fortran_wrapper"    96 wrapper_includes = 
'''   102 #define _EXTERN_C_ extern "C"   103 #else /* __cplusplus */   105 #endif /* __cplusplus */   106 #endif /* _EXTERN_C_ */   108 _EXTERN_C_ void *MPIR_ToPointer(int);   109 #endif // MPICH_HAS_C2F   111 /* For shared libraries, declare these weak and figure out which one was linked   112    based on which init wrapper was called.  See mpi_init wrappers.  */   113 #pragma weak pmpi_init   114 #pragma weak PMPI_INIT   115 #pragma weak pmpi_init_   116 #pragma weak pmpi_init__   118 _EXTERN_C_ void pmpi_init(MPI_Fint *ierr);   119 _EXTERN_C_ void PMPI_INIT(MPI_Fint *ierr);   120 _EXTERN_C_ void pmpi_init_(MPI_Fint *ierr);   121 _EXTERN_C_ void pmpi_init__(MPI_Fint *ierr);   125 default_modifiers = [
"_EXTERN_C_"]  
   128 mpi_handle_types = 
set([
"MPI_Comm", 
"MPI_Errhandler", 
"MPI_File", 
"MPI_Group", 
"MPI_Info",
   129                         "MPI_Op", 
"MPI_Request", 
"MPI_Status", 
"MPI_Datatype", 
"MPI_Win" ])
   134     "MPI_Startall"           : { 1:0 },
   135     "MPI_Testall"            : { 1:0, 3:0 },
   136     "MPI_Testany"            : { 1:0 },
   137     "MPI_Testsome"           : { 1:0, 4:0 },
   138     "MPI_Type_create_struct" : { 3:0 },
   139     "MPI_Type_get_contents"  : { 6:1 },
   140     "MPI_Type_struct"        : { 3:0 },
   141     "MPI_Waitall"            : { 1:0, 2:0 },
   142     "MPI_Waitany"            : { 1:0 },
   143     "MPI_Waitsome"           : { 1:0, 4:0 }
   147 def find_matching_paren(string, index, lparen='(
', rparen=')
'):   148     """Find the closing paren corresponding to the open paren at <index>   149        in <string>.  Optionally, can provide other characters to match on.   150        If found, returns the index of the matching parenthesis.  If not found,   153     if not string[index] == lparen:
   154         raise ValueError(
"Character at index %d is '%s'. Expected '%s'"   155                          % (index, string[index], lparen))
   158     while index < len(string) 
and count > 0:
   159         while index < len(string) 
and string[index] 
not in (lparen, rparen):
   161         if string[index] == lparen:
   163         elif string[index] == rparen:
   173     """True if a string is something we can index an array with."""   181     if not hasattr(function, 
"did_once"):
   183         function.did_once = 
True   186 def conversion_prefix(handle_type):
   187     if handle_type == 
"MPI_Datatype":
   193 def joinlines(list, sep="\n"):
   195         return sep.join(list) + sep
   200 LBRACE, RBRACE, TEXT, IDENTIFIER = range(4)
   203     """Represents tokens; generated from input by lexer and fed to parse()."""   204     def __init__(self, type, value, line=0):
   210         return "'%s'" % re.sub(
r'\n', 
"\\\\n", self.value)
   213         return self.type == type
   216 class LineTrackingLexer(object):
   217     """Base class for Lexers that keep track of line numbers."""   218     def __init__(self, lexicon):
   220         self.scanner = re.Scanner(lexicon)
   222     def make_token(self, type, value):
   223         token = Token(type, value, self.line_no)
   224         self.line_no += value.count(
"\n")
   229         tokens, remainder = self.scanner.scan(text)
   231             sys.stderr.write(
"Unlexable input:\n%s\n" % remainder)
   236 class OuterRegionLexer(LineTrackingLexer):
   238         super(OuterRegionLexer, self).__init__([
   239             (
r'{{',                     self.lbrace),
   240             (
r'}}',                     self.rbrace),
   241             (
r'({(?!{)|}(?!})|[^{}])*', self.text)])
   242     def lbrace(self, scanner, token): 
return self.make_token(LBRACE, token)
   243     def rbrace(self, scanner, token): 
return self.make_token(RBRACE, token)
   244     def text(self, scanner, token):   
return self.make_token(TEXT, token)
   246 class OuterCommentLexer(OuterRegionLexer):
   248         super(OuterRegionLexer, self).__init__([
   249             (
r'/\*(.|[\r\n])*?\*/',                self.text),   
   250             (
r'//(.|[\r\n])*?(?=[\r\n])',          self.text),   
   251             (
r'{{',                                self.lbrace),
   252             (
r'}}',                                self.rbrace),
   253             (
r'({(?!{)|}(?!})|/(?![/*])|[^{}/])*', self.text)])
   255 class InnerLexer(OuterRegionLexer):
   257         super(OuterRegionLexer, self).__init__([
   258             (
r'{{',                               self.lbrace),
   259             (
r'}}',                               self.rbrace),
   260             (
r'(["\'])?((?:(?!\1)[^\\]|\\.)*)\1', self.quoted_id),
   261             (
r'([^\s]+)',                         self.identifier),
   263     def identifier(self, scanner, token): 
return self.make_token(IDENTIFIER, token)
   264     def quoted_id(self, scanner, token):
   267         return self.make_token(IDENTIFIER, re.sub(
r'^["\'](.*)["\']$', 
'\\1', token))
   273 class WrapSyntaxError:
   274     """Simple Class for syntax errors raised by the wrapper generator (rather than python)"""   277 def syntax_error(msg):
   279     sys.stderr.write(
"%s:%d: %s\n" % (cur_filename, 0, msg))
   281         sys.stderr.write(
"    While handling %s.\n" % cur_function)
   282     raise WrapSyntaxError
   290     """ This is the very basic class for scopes in the wrapper generator.  Scopes   291         are hierarchical and support nesting.  They contain string keys mapped   292         to either string values or to macro functions.   293         Scopes also keep track of the particular macro they correspond to (macro_name).   295     def __init__(self, enclosing_scope=None):
   297         self.enclosing_scope = enclosing_scope
   298         self.macro_name = 
None              300     def __getitem__(self, key):
   301         if key 
in self.map:         
return self.map[key]
   302         elif self.enclosing_scope:  
return self.enclosing_scope[key]
   303         else:                       
raise KeyError(key + 
" is not in scope.")
   305     def __contains__(self, key):
   306         if key 
in self.map:         
return True   307         elif self.enclosing_scope:  
return key 
in self.enclosing_scope
   310     def __setitem__(self, key, value):
   311         self.map[key] = value
   313     def include(self, map):
   314         """Add entire contents of the map (or scope) to this scope."""   326     """Descriptor for formal parameters of MPI functions.   327        Doesn't represent a full parse, only the initial type information,   328        name, and array info of the argument split up into strings.   330     def __init__(self, type, pointers, name, array, pos):
   332         self.pointers = pointers       
   338     def setDeclaration(self, decl):
   339         """Needs to be called by Declaration to finish initing the arg."""   342     def isHandleArray(self):
   343         """True if this Param represents an array of MPI handle values."""   344         return (self.decl.name 
in mpi_array_calls
   345                 and self.pos 
in mpi_array_calls[self.decl.name])
   347     def countParam(self):
   348         """If this Param is a handle array, returns the Param that represents the count of its elements"""   349         return self.decl.args[mpi_array_calls[self.decl.name][self.pos]]
   352         """True if this Param is one of the MPI builtin handle types."""   353         return self.type 
in mpi_handle_types
   356         """True if this Param is an MPI_Status.  MPI_Status is handled differently   357            in c2f/f2c calls from the other handle types.   359         return self.type == 
"MPI_Status"   361     def fortranFormal(self):
   362         """Prints out a formal parameter for a fortran wrapper."""   365         if self.type == 
"MPI_Aint" or self.type.endswith(
"_function"):
   373             pointers = self.pointers
   380         arr = self.array 
or ''   381         return "%s %s%s%s" % (ftype, pointers, self.name, arr)
   387             arr = self.array 
or ''   388             pointers = self.pointers 
or ''   389             return "%s%s%s" % (self.type, pointers, arr)
   392         """Prints out a formal parameter for a C wrapper."""   396             arr = self.array 
or ''   397             pointers = self.pointers 
or ''   398             return "%s %s%s%s" % (self.type, pointers, self.name, arr)
   401         arr = self.array 
or ''   402         pointers = self.pointers 
or ''   404             if arr.count(
'[') > 1:
   408             arr = arr.replace(
'[]', 
'')
   409         return "%s%s%s" % (self.type, pointers, arr)
   412         return self.cFormal()
   416     """ Descriptor for simple MPI function declarations.   417         Contains return type, name of function, and a list of args.   419     def __init__(self, rtype, name):
   424     def addArgument(self, arg):
   425         arg.setDeclaration(self)
   426         self.args.append(arg)
   429         for arg 
in self.args: 
yield arg
   432         return self.prototype()
   438         return [arg.cFormal() 
for arg 
in self.args]
   441         return [arg.cType() 
for arg 
in self.args]
   443     def argsNoEllipsis(self):
   444         return filter(
lambda arg: arg.name != 
"...", self.args)
   446     def returnsErrorCode(self):
   447         """This is a special case for MPI_Wtime and MPI_Wtick.   448            These functions actually return a double value instead of an int error code.   450         return self.rtype == 
"int"   453         return [arg.name 
for arg 
in self.argsNoEllipsis()]
   455     def getArgName(self, index):
   456         return self.argsNoEllipsis()[index].name
   458     def fortranFormals(self):
   459         formals = 
map(Param.fortranFormal, self.argsNoEllipsis())
   460         if self.name == 
"MPI_Init": formals = []    
   463         if self.returnsErrorCode(): ierr = [
"MPI_Fint *ierr"]
   464         return formals + ierr
   466     def fortranArgNames(self):
   467         names = self.argNames()
   468         if self.name == 
"MPI_Init": names = []
   471         if self.returnsErrorCode(): ierr = [
"ierr"]
   474     def prototype(self, modifiers=""):
   475         if modifiers: modifiers = joinlines(modifiers, 
" ")
   476         return "%s%s %s(%s)" % (modifiers, self.retType(), self.name, 
", ".join(self.formals()))
   478     def pmpi_prototype(self, modifiers=""):
   479         if modifiers: modifiers = joinlines(modifiers, 
" ")
   480         return "%s%s P%s(%s)" % (modifiers, self.retType(), self.name, 
", ".join(self.formals()))
   482     def fortranPrototype(self, name=None, modifiers=""):
   483         if not name: name = self.name
   484         if modifiers: modifiers = joinlines(modifiers, 
" ")
   486         if self.returnsErrorCode():
   490         return "%s%s %s(%s)" % (modifiers, rtype, name, 
", ".join(self.fortranFormals()))
   496 def enumerate_mpi_declarations(mpicc, includes):
   497     """ Invokes mpicc's C preprocessor on a C file that includes mpi.h.   498         Parses the output for declarations, and yields each declaration to   502     tmpfile = tempfile.NamedTemporaryFile(
'w+b', -1, 
'.c')
   503     tmpname = 
"%s" % tmpfile.name
   504     tmpfile.write(
'#include <mpi.h>')
   510     string_includes = [
"-I"+dir 
for dir 
in includes]
   511     mpicc_cmd = 
"%s -E %s" % (mpicc, 
" ".join(string_includes))
   513         popen = subprocess.Popen(
"%s %s" % (mpicc_cmd, tmpname), shell=
True,
   514                                  stdout=subprocess.PIPE, stderr=subprocess.PIPE)
   516         sys.stderr.write(
"IOError: couldn't run '" + mpicc_cmd + 
"' for parsing mpi.h\n")
   523         begin = begin_decl_re.search(line)
   524         if begin 
and not exclude_re.search(line):
   526             return_type, fn_name = begin.groups()
   529             while not end_decl_re.search(line):
   530                 line += 
" " + mpi_h.next().strip()
   533             fn_and_paren = 
r'(%s\s*\()' % fn_name
   534             match = re.search(fn_and_paren, line)
   535             lparen = match.start(1) + len(match.group(1)) - 1
   536             rparen = find_matching_paren(line, lparen)
   538                 raise ValueError(
"Malformed declaration in header: '%s'" % line)
   540             arg_string = line[lparen+1:rparen]
   541             arg_list = 
map(
lambda s: s.strip(), arg_string.split(
","))
   544             if arg_list == [
'void']:
   548             decl = Declaration(return_type, fn_name)
   552                     decl.addArgument(Param(
None, 
None, 
'...', 
None, arg_num))
   554                     match = formal_re.match(arg)
   556                         sys.stderr.write(
"MATCH FAILED FOR: '%s' in %s\n" % (arg, fn_name))
   559                     type, pointers, name, array = match.groups()
   561                     all_pointers.add(pointers)
   563                     if not name: name = 
"arg_" + str(arg_num)
   565                     decl.addArgument(Param(type.strip(), pointers, name, array, arg_num))
   571     return_code = popen.wait()
   573         sys.stderr.write(
"Error: Couldn't run '%s' for parsing mpi.h.\n" % mpicc_cmd)
   574         sys.stderr.write(
"       Process exited with code %d.\n" % return_code)
   581 def write_enter_guard(out, decl):
   582     """Prevent us from entering wrapper functions if we're already in a wrapper function.   583        Just call the PMPI function w/o the wrapper instead."""   585         out.write(
"    if (in_wrapper) return P%s(%s);\n" % (decl.name, 
", ".join(decl.argNames())))
   586         out.write(
"    in_wrapper = 1;\n")
   588 def write_exit_guard(out):
   589     """After a call, set in_wrapper back to 0 so we can enter the next call."""   591         out.write(
"    in_wrapper = 0;\n")
   594 def write_c_wrapper(out, decl, return_val, write_body):
   595     """Write the C wrapper for an MPI function."""   598     out.write(decl.pmpi_prototype(default_modifiers))
   602     out.write(decl.prototype(default_modifiers))
   604     out.write(
"    %s %s = 0;\n" % (decl.retType(), return_val))
   606     write_enter_guard(out, decl)
   608     write_exit_guard(out)
   610     out.write(
"    return %s;\n" % return_val)
   614 def write_fortran_binding(out, decl, delegate_name, binding, stmts=None):
   615     """Outputs a wrapper for a particular fortran binding that delegates to the   616        primary Fortran wrapper.  Optionally takes a list of statements to execute   619     out.write(decl.fortranPrototype(binding, default_modifiers))
   622         out.write(joinlines(
map(
lambda s: 
"    " + s, stmts)))
   623     if decl.returnsErrorCode():
   625         out.write(
"    %s(%s);\n" % (delegate_name, 
", ".join(decl.fortranArgNames())))
   628         out.write(
"    return %s(%s);\n" % (delegate_name, 
", ".join(decl.fortranArgNames())))
   632 class FortranDelegation:
   633     """Class for constructing a call to a Fortran wrapper delegate function.  Provides   634        storage for local temporary variables, copies of parameters, callsites for MPI-1 and   635        MPI-2, and writebacks to local pointer types.   637     def __init__(self, decl, return_val):
   639         self.return_val = return_val
   645         self.mpich_actuals = []
   647     def addTemp(self, type, name):
   648         """Adds a temp var with a particular name.  Adds the same var only once."""   649         temp = 
"    %s %s;" % (type, name)
   652     def addActual(self, actual):
   653         self.actuals.append(actual)
   654         self.mpich_actuals.append(actual)
   656     def addActualMPICH(self, actual):
   657         self.mpich_actuals.append(actual)
   659     def addActualMPI2(self, actual):
   660         self.actuals.append(actual)
   662     def addWriteback(self, stmt):
   663         self.writebacks.append(
"    %s" % stmt)
   665     def addCopy(self, stmt):
   666         self.copies.append(
"    %s" % stmt)
   668     def write(self, out):
   669         assert len(self.actuals) == len(self.mpich_actuals)
   671         call = 
"    %s = %s" % (self.return_val, self.decl.name)
   672         mpich_call = 
"%s(%s);\n" % (call, 
", ".join(self.mpich_actuals))
   673         mpi2_call = 
"%s(%s);\n" % (call, 
", ".join(self.actuals))
   675         out.write(
"    %s %s = 0;\n" % (self.decl.retType(), self.return_val))
   676         if mpich_call == mpi2_call 
and not (self.temps 
or self.copies 
or self.writebacks):
   677             out.write(mpich_call)
   679             out.write(
"#if (!defined(MPICH_HAS_C2F) && defined(MPICH_NAME) && (MPICH_NAME == 1)) /* MPICH test */\n")
   680             out.write(mpich_call)
   681             out.write(
"#else /* MPI-2 safe call */\n")
   682             out.write(joinlines(self.temps))
   683             out.write(joinlines(self.copies))
   685             out.write(joinlines(self.writebacks))
   686             out.write(
"#endif /* MPICH test */\n")
   689 def write_fortran_wrappers(out, decl, return_val):
   690     """Writes primary fortran wrapper that handles arg translation.   691        Also outputs bindings for this wrapper for different types of fortran compilers.   693     delegate_name = decl.name + f_wrap_suffix
   694     out.write(decl.fortranPrototype(delegate_name, [
"static"]))
   697     call = FortranDelegation(decl, return_val)
   699     if decl.name == 
"MPI_Init":
   701         out.write(
"    int argc = 0;\n");
   702         out.write(
"    char ** argv = NULL;\n");
   703         call.addActual(
"&argc");
   704         call.addActual(
"&argv");
   706         out.write(
"    *ierr = %s;\n" % return_val)
   710         write_fortran_binding(out, decl, delegate_name, 
"MPI_INIT",   [
"fortran_init = 1;"])
   711         write_fortran_binding(out, decl, delegate_name, 
"mpi_init",   [
"fortran_init = 2;"])
   712         write_fortran_binding(out, decl, delegate_name, 
"mpi_init_",  [
"fortran_init = 3;"])
   713         write_fortran_binding(out, decl, delegate_name, 
"mpi_init__", [
"fortran_init = 4;"])
   717     for arg 
in decl.args:
   718         if arg.name == 
"...":   
   721         if not (arg.pointers 
or arg.array):
   722             if not arg.isHandle():
   724                 dereferenced = 
"*%s" % arg.name
   725                 call.addActual(dereferenced)
   729                 call.addActualMPI2(
"%s_f2c(*%s)" % (conversion_prefix(arg.type), arg.name))
   730                 call.addActualMPICH(
"(%s)(*%s)" % (arg.type, arg.name))
   733             if not arg.isHandle():
   736                 call.addActual(
"(%s)%s" % (arg.castType(), arg.name))
   739                 call.addActualMPICH(
"(%s*)%s" % (arg.type, arg.name))
   740                 conv = conversion_prefix(arg.type)
   741                 temp = 
"temp_%s" % arg.name
   744                 if not arg.isHandleArray():
   745                     call.addTemp(arg.type, temp)
   746                     call.addActualMPI2(
"&%s" % temp)
   749                         call.addCopy(
"%s_f2c(%s, &%s);"  % (conv, arg.name, temp))
   750                         call.addWriteback(
"%s_c2f(&%s, %s);" % (conv, temp, arg.name))
   752                         call.addCopy(
"%s = %s_f2c(*%s);"  % (temp, conv, arg.name))
   753                         call.addWriteback(
"*%s = %s_c2f(%s);" % (arg.name, conv, temp))
   756                     temp_arr_type = 
"%s*" % arg.type
   757                     call.addTemp(temp_arr_type, temp)
   758                     call.addTemp(
"int", 
"i")
   762                         copy = 
"    %s_f2c(&%s[i], &%s[i])"  % (conv, arg.name, temp)
   763                         writeback = 
"    %s_c2f(&%s[i], &%s[i])" % (conv, temp, arg.name)
   765                         copy = 
"    temp_%s[i] = %s_f2c(%s[i])"  % (arg.name, conv, arg.name)
   766                         writeback = 
"    %s[i] = %s_c2f(temp_%s[i])" % (arg.name, conv, arg.name)
   769                     count = 
"*%s" % arg.countParam().name
   770                     call.addCopy(
"%s = (%s)malloc(sizeof(%s) * %s);" %
   771                                  (temp, temp_arr_type, arg.type, count))
   772                     call.addCopy(
"for (i=0; i < %s; i++)" % count)
   773                     call.addCopy(
"%s;" % copy)
   774                     call.addActualMPI2(temp)
   775                     call.addWriteback(
"for (i=0; i < %s; i++)" % count)
   776                     call.addWriteback(
"%s;" % writeback)
   777                     call.addWriteback(
"free(%s);" % temp)
   780     if decl.returnsErrorCode():
   781         out.write(
"    *ierr = %s;\n" % return_val)
   783         out.write(
"    return %s;\n" % return_val)
   787     write_fortran_binding(out, decl, delegate_name, decl.name.upper())
   788     write_fortran_binding(out, decl, delegate_name, decl.name.lower())
   789     write_fortran_binding(out, decl, delegate_name, decl.name.lower() + 
"_")
   790     write_fortran_binding(out, decl, delegate_name, decl.name.lower() + 
"__")
   803 def macro(macro_name, **attrs):
   805         macros[macro_name] = fun 
   808             setattr(fun, key, attrs[key])
   812 def handle_list(list_name, list, args):
   813     """This function handles indexing lists used as macros in the wrapper generator.   814        There are two syntaxes:   815        {{<list_name>}}          Evaluates to the whole list, e.g. 'foo, bar, baz'   816        {{<list_name> <index>}}  Evaluates to a particular element of a list.   821         len(args) == 1 
or syntax_error(
"Wrong number of args for list expression.")
   823             return list[int(args[0])]
   825             syntax_error(
"Invald index value: '%s'" % args[0])
   827             syntax_error(
"Index out of range in '%s': %d" % (list_name, index))
   830     """This class implements a Macro function for applying something callable to   831        args in a decl with a particular type.   833     def __init__(self, decl):
   836     def __call__(self, out, scope, args, children):
   837         len(args) == 2 
or syntax_error(
"Wrong number of args in apply macro.")
   838         type, macro_name = args
   839         for arg 
in self.decl.args:
   840             if arg.cType() == type:
   841                 out.write(
"%s(%s);\n" % (macro_name, arg.name))
   843 def include_decl(scope, decl):
   844     """This function is used by macros to include attributes MPI declarations in their scope."""   845     scope[
"ret_type"] = decl.retType()
   846     scope[
"args"]     = decl.argNames()
   847     scope[
"nargs"]    = len(decl.argNames())
   848     scope[
"types"]    = decl.types()
   849     scope[
"formals"]  = decl.formals()
   850     scope[
"apply_to_type"] = TypeApplier(decl)
   851     scope.function_name  = decl.name
   854     def get_arg(out, scope, args, children):
   855         return handle_list(
"args", decl.argNames(), args)
   856     scope[
"get_arg"]     = get_arg
   857     scope[
"applyToType"] = scope[
"apply_to_type"]
   858     scope[
"retType"]     = scope[
"ret_type"]
   859     scope[
"argList"]     = 
"(%s)" % 
", ".join(scope[
"args"])
   860     scope[
"argTypeList"] = 
"(%s)" % 
", ".join(scope[
"formals"])
   862 def all_but(fn_list):
   863     """Return a list of all mpi functions except those in fn_list"""   864     all_mpi = 
set(mpi_functions.keys())
   865     diff = all_mpi - 
set(fn_list)
   866     return [x 
for x 
in diff]
   868 @macro(
"foreachfn", has_body=
True)
   869 def foreachfn(out, scope, args, children):
   870     """Iterate over all functions listed in args."""   871     args 
or syntax_error(
"Error: foreachfn requires function name argument.")
   875     for fn_name 
in args[1:]:
   876         cur_function = fn_name
   877         if not fn_name 
in mpi_functions:
   878             syntax_error(fn_name + 
" is not an MPI function")
   880         fn = mpi_functions[fn_name]
   881         fn_scope = Scope(scope)
   882         fn_scope[fn_var] = fn_name
   883         include_decl(fn_scope, fn)
   885         for child 
in children:
   886             child.evaluate(out, fn_scope)
   889 @macro(
"fn", has_body=
True)
   890 def fn(out, scope, args, children):
   891     """Iterate over listed functions and generate skeleton too."""   892     args 
or syntax_error(
"Error: fn requires function name argument.")
   896     for fn_name 
in args[1:]:
   897         cur_function = fn_name
   898         if not fn_name 
in mpi_functions:
   899             syntax_error(fn_name + 
" is not an MPI function")
   901         fn = mpi_functions[fn_name]
   902         return_val = 
"_wrap_py_return_val"   904         fn_scope = Scope(scope)
   905         fn_scope[fn_var] = fn_name
   906         include_decl(fn_scope, fn)
   908         fn_scope[
"ret_val"] = return_val
   909         fn_scope[
"returnVal"]  = fn_scope[
"ret_val"]  
   911         c_call = 
"%s = P%s(%s);" % (return_val, fn.name, 
", ".join(fn.argNames()))
   912         if fn_name == 
"MPI_Init" and output_fortran_wrappers:
   913             def callfn(out, scope, args, children):
   918                 out.write(
"    if (fortran_init) {\n")
   919                 out.write(
"#ifdef PIC\n")
   920                 out.write(
"        if (!PMPI_INIT && !pmpi_init && !pmpi_init_ && !pmpi_init__) {\n")
   921                 out.write(
"            fprintf(stderr, \"ERROR: Couldn't find fortran pmpi_init function.  Link against static library instead.\\n\");\n")
   922                 out.write(
"            exit(1);\n")
   924                 out.write(
"        switch (fortran_init) {\n")
   925                 out.write(
"        case 1: PMPI_INIT(&%s);   break;\n" % return_val)
   926                 out.write(
"        case 2: pmpi_init(&%s);   break;\n" % return_val)
   927                 out.write(
"        case 3: pmpi_init_(&%s);  break;\n" % return_val)
   928                 out.write(
"        case 4: pmpi_init__(&%s); break;\n" % return_val)
   929                 out.write(
"        default:\n")
   930                 out.write(
"            fprintf(stderr, \"NO SUITABLE FORTRAN MPI_INIT BINDING\\n\");\n")
   931                 out.write(
"            break;\n")
   933                 out.write(
"#else /* !PIC */\n")
   934                 out.write(
"        %s(&%s);\n" % (pmpi_init_binding, return_val))
   935                 out.write(
"#endif /* !PIC */\n")
   936                 out.write(
"    } else {\n")
   937                 out.write(
"        %s\n" % c_call)
   940             fn_scope[
"callfn"] = callfn
   942             def write_fortran_init_flag():
   943                 output.write(
"static int fortran_init = 0;\n")
   944             once(write_fortran_init_flag)
   947             fn_scope[
"callfn"] = c_call
   950             for child 
in children:
   951                 child.evaluate(out, fn_scope)
   953         out.write(
"/* ================== C Wrappers for %s ================== */\n" % fn_name)
   954         write_c_wrapper(out, fn, return_val, write_body)
   955         if output_fortran_wrappers:
   956             out.write(
"/* =============== Fortran Wrappers for %s =============== */\n" % fn_name)
   957             write_fortran_wrappers(out, fn, return_val)
   958             out.write(
"/* ================= End Wrappers for %s ================= */\n\n\n" % fn_name)
   961 @macro(
"forallfn", has_body=
True)
   962 def forallfn(out, scope, args, children):
   963     """Iterate over all but the functions listed in args."""   964     args 
or syntax_error(
"Error: forallfn requires function name argument.")
   965     foreachfn(out, scope, [args[0]] + all_but(args[1:]), children)
   967 @macro(
"fnall", has_body=
True)
   968 def fnall(out, scope, args, children):
   969     """Iterate over all but listed functions and generate skeleton too."""   970     args 
or syntax_error(
"Error: fnall requires function name argument.")
   971     fn(out, scope, [args[0]] + all_but(args[1:]), children)
   974 def sub(out, scope, args, children):
   975     """{{sub <string> <regexp> <substitution>}}   976        Replaces value of <string> with all instances of <regexp> replaced with <substitution>.   978     len(args) == 3 
or syntax_error(
"'sub' macro takes exactly 4 arguments.")
   979     string, regex, substitution = args
   980     if isinstance(string, list):
   981         return [re.sub(regex, substitution, s) 
for s 
in string]
   982     if not isinstance(regex, str):
   983         syntax_error(
"Invalid regular expression in 'sub' macro: '%s'" % regex)
   985         return re.sub(regex, substitution, string)
   988 def zip_macro(out, scope, args, children):
   989     len(args) == 2 
or syntax_error(
"'zip' macro takes exactly 2 arguments.")
   990     if not all([isinstance(a, list) 
for a 
in args]):
   991         syntax_error(
"Arguments to 'zip' macro must be lists.")
   993     return [
"%s %s" % x 
for x 
in zip(a, b)]
   996 def def_macro(out, scope, args, children):
   997     len(args) == 2 
or syntax_error(
"'def' macro takes exactly 2 arguments.")
   998     scope[args[0]] = args[1]
  1001 def list_macro(out, scope, args, children):
  1004         if isinstance(arg, list):
  1011 def filter_macro(out, scope, args, children):
  1012     """{{filter <regex> <list>}}  1013        Returns a list containing all elements of <list> that <regex> matches.  1015     len(args) == 2 
or syntax_error(
"'filter' macro takes exactly 2 arguments.")
  1017     if not isinstance(l, list):
  1018         syntax_error(
"Invalid list in 'filter' macro: '%s'" % str(list))
  1019     if not isinstance(regex, str):
  1020         syntax_error(
"Invalid regex in 'filter' macro: '%s'" % str(regex))
  1022         return re.search(regex, s)
  1023     return filter(match, l)
  1026 def fn_num(out, scope, args, children):
  1039     """Represents a piece of a wrapper file.  Is either a text chunk  1040        or a macro chunk with children to which the macro should be applied.  1041        macros are evaluated lazily, so the macro is just a string until  1042        execute is called and it is fetched from its enclosing scope."""  1049     def iwrite(self, file, level, text):
  1050         """Write indented text."""  1051         for x 
in xrange(level):
  1055     def write(self, file=sys.stdout, l=0):
  1056         if self.macro: self.iwrite(file, l, 
"{{%s %s}}" % (self.macro, 
" ".join([str(arg) 
for arg 
in self.args])))
  1057         if self.text:  self.iwrite(file, l, 
"TEXT\n")
  1058         for child 
in self.children:
  1059             child.write(file, l+1)
  1061     def execute(self, out, scope):
  1062         """This function executes a chunk.  For strings, lists, text chunks, etc., this just  1063            entails returning the chunk's value.  For callable macros, this executes and returns  1067             out.write(self.text)
  1069             if not self.macro 
in scope:
  1070                 error_msg = 
"Invalid macro: '%s'" % self.macro
  1071                 if scope.function_name:
  1072                     error_msg += 
" for " + scope.function_name
  1073                 syntax_error(error_msg)
  1075             value = scope[self.macro]
  1076             if hasattr(value, 
"__call__"):
  1079                     if isinstance(arg, Chunk):
  1080                         return arg.execute(out, scope)
  1083                 args = [eval_arg(arg) 
for arg 
in self.args]
  1084                 return value(out, scope, args, self.children)
  1085             elif isinstance(value, list):
  1087                 return handle_list(self.macro, value, self.args)
  1092     def stringify(self, value):
  1093         """Used by evaluate() to print the return values of chunks out to the output file."""  1094         if isinstance(value, list):
  1095             return ", ".join(value)
  1099     def evaluate(self, out, scope):
  1100         """This is an 'interactive' version of execute.  This should be called when  1101            the chunk's value (if any) should be written out.  Body macros and the outermost  1102            scope should use this instead of execute().  1104         value = self.execute(out, scope)
  1105         if value 
is not None:  
  1106             out.write(self.stringify(value))
  1109     """Parser for the really simple wrappergen grammar.  1110        This parser has support for multiple lexers.  self.tokens is a list of iterables, each  1111        representing a new token stream.  You can add additional tokens to be lexed using push_tokens.  1112        This will cause the pushed tokens to be handled before any others.  This allows us to switch  1113        lexers while parsing, so that the outer part of the file is processed in a language-agnostic  1114        way, but stuff inside macros is handled as its own macro language.  1116     def __init__(self, macros):
  1117         self.macros = macros
  1118         self.macro_lexer = InnerLexer()
  1119         self.tokens = iter([]) 
  1124         """Puts the next token in the input stream into self.next."""  1126             self.next = self.tokens.next()
  1127         except StopIteration:
  1130     def push_tokens(self, iterable):
  1131         """Adds all tokens in some iterable to the token stream."""  1132         self.tokens = itertools.chain(iter(iterable), iter([self.next]), self.tokens)
  1135     def accept(self, id):
  1136         """Puts the next symbol in self.token if we like it.  Then calls gettok()"""  1137         if self.next.isa(id):
  1138             self.token = self.next
  1143     def unexpected_token(self):
  1144         syntax_error(
"Unexpected token: %s." % self.next)
  1146     def expect(self, id):
  1147         """Like accept(), but fails if we don't like the next token."""  1152                 self.unexpected_token()
  1154                 syntax_error(
"Unexpected end of file.")
  1157     def is_body_macro(self, name):
  1158         """Shorthand for testing whether a particular name is the name of a macro that has a body.  1159            Need this for parsing the language b/c things like {{fn}} need a corresponding {{endfn}}.  1161         return name 
in self.macros 
and self.macros[name].has_body
  1163     def macro(self, accept_body_macros=True):
  1165         if self.accept(TEXT):
  1166             self.push_tokens(self.macro_lexer.lex(self.token.value))
  1170         self.expect(IDENTIFIER)
  1171         chunk.macro = self.token.value
  1173         if not accept_body_macros 
and self.is_body_macro(chunk.macro):
  1174             syntax_error(
"Cannot use body macros in expression context: '%s'" % chunk.macro)
  1178             if self.accept(LBRACE):
  1179                 chunk.args.append(self.macro(
False))
  1180             elif self.accept(IDENTIFIER):
  1181                 chunk.args.append(self.token.value)
  1182             elif self.accept(TEXT):
  1183                 self.push_tokens(self.macro_lexer.lex(self.token.value))
  1189     def text(self, end_macro = None):
  1192             if self.accept(TEXT):
  1194                 chunk.text = self.token.value
  1195                 chunks.append(chunk)
  1196             elif self.accept(LBRACE):
  1197                 chunk = self.macro()
  1200                 if name == end_macro:
  1203                 elif isindex(chunk.macro):
  1205                     chunk.macro = 
"args"  1207                 elif self.is_body_macro(name):
  1208                     chunk.children = self.text(
"end"+name)
  1209                 chunks.append(chunk)
  1211                 self.unexpected_token()
  1215     def parse(self, text):
  1217             outer_lexer = OuterRegionLexer()   
  1219             outer_lexer = OuterCommentLexer()  
  1220         self.push_tokens(outer_lexer.lex(text))
  1228     sys.stderr.write(usage_string)
  1233 output_filename = 
None  1236     opts, args = getopt.gnu_getopt(sys.argv[1:], 
"fsgdc:o:i:I:")
  1237 except getopt.GetoptError, err:
  1238     sys.stderr.write(err + 
"\n")
  1241 for opt, arg 
in opts:
  1242     if opt == 
"-d": dump_prototypes = 
True  1243     if opt == 
"-f": output_fortran_wrappers = 
True  1244     if opt == 
"-s": skip_headers = 
True  1245     if opt == 
"-g": output_guards = 
True  1246     if opt == 
"-c": mpicc = arg
  1247     if opt == 
"-o": output_filename = arg
  1249         stripped = arg.strip()
  1250         if stripped: includes.append(stripped)
  1252         if not arg 
in pmpi_init_bindings:
  1253             sys.stderr.write(
"ERROR: PMPI_Init binding must be one of:\n    %s\n" % 
" ".join(possible_bindings))
  1256             pmpi_init_binding = arg
  1258 if len(args) < 1 
and not dump_prototypes:
  1262 for decl 
in enumerate_mpi_declarations(mpicc, includes):
  1263     mpi_functions[decl.name] = decl
  1264     if dump_prototypes: 
print decl
  1267 if not mpi_functions:
  1268     sys.stderr.write(
"Error: Found no declarations in mpi.h.\n")
  1272 if dump_prototypes: sys.exit(0)
  1277         output = open(output_filename, 
"w")
  1279         sys.stderr.write(
"Error: couldn't open file " + arg + 
" for writing.\n")
  1284     if not skip_headers:
  1285         output.write(wrapper_includes)
  1286         if output_guards: output.write(
"static int in_wrapper = 0;\n")
  1293         file = open(cur_filename)
  1296         outer_scope = Scope()
  1297         outer_scope[
"fileno"] = str(fileno)
  1298         outer_scope.include(macros)
  1300         parser = Parser(macros)
  1301         chunks = parser.parse(file.read())
  1303         for chunk 
in chunks:
  1304             chunk.evaluate(output, Scope(outer_scope))
  1307 except WrapSyntaxError:
  1309     if output_filename: os.remove(output_filename)
 __host__ __device__ double set(double &x)
 
static void sub(Float *dst, Float *a, Float *b, int cnt)
 
std::map< TuneKey, TuneParam > map
 
__host__ __device__ constexpr bool match()