Previous: , Up: Backend creation   [Contents][Index]


6.2.4 Internals

codegen_c_generic.py is a fairly substantial piece of code. It is divided into ten sections:

  1. methods exported to the compiler front end
  2. utility functions that do not generate code
  3. utility functions that do generate code
  4. methods for outputting language atoms (see Primitives)
  5. methods for outputting miscellaneous language constructs (e.g., restricted identifiers; see Restricted identifiers)
  6. methods for outputting expressions (see Expressions)
  7. methods for outputting complete programs (see Complete programs)
  8. methods for outputting complex statements (see Complex statements)
  9. methods for outputting simple statements (e.g., communication statements; see Communication statements)
  10. methods for outputting nodes with non-textual names (e.g., ‘...’ and various operators)

The NCPTL_CodeGen class defined in codegen_c_generic.py generates code as follows. The generate method, which is invoked by ncptl.py, calls upon PLY to process the abstract-syntax tree ( AST) in postorder fashion. NCPTL_CodeGen maintains a stack ( codestack) on which code fragments are pushed and popped but that ends up containing a complete line of C code in each element. For example, in the coNCePTuaL program ‘TASK 0 OUTPUTS 1+2*3’, the n_outputs method will pop ‘[('expr', '(1)+((2)*(3))')]’ (a list containing the single expression ‘1+2*3’) and ‘('task_expr', '0')’ (a tuple designating a task by the expression ‘0’) and push multiple lines of code that prepare task 0 to evaluate and output the given expression.

The utility functions are the most useful for backend developers to understand, as they are frequently called from hook methods (see Hook methods). The following should be of particular importance:

push
pushmany

Push a single value (typically a string of C code) or each value in a list of values onto a stack.

error_fatal
error_internal

Output a generic error message or an “internal error” error message and abort the program.

code_declare_var

Push (using the push method) a line of C code that declares a variable with an optionally specified type, name, initial value, and comment. Return the variable name actually used.

See the definitions in codegen_c_generic.py of each of the above to determine required and optional parameters. The following, adapted from codegen_c_udgram.py demonstrates some of the preceding methods:

def n_for_count_SYNC_ALL(self, localvars):
    "Synchronize all of the tasks in the job."
    synccode = []
    self.push("{", synccode)
    loopvar = self.code_declare_var(suffix="task",
      comment="Loop variable that iterates over all (physical) ranks",
      stack=synccode)
    self.pushmany([
      "thisev_sync->s.sync.peerqueue = ncptl_queue_init (sizeof(int));",
      "for (%s=0; %s<var_num_tasks; %s++)" %
      (loopvar, loopvar, loopvar),
      "*(int *)ncptl_queue_allocate(thisev_sync->s.sync.peerqueue) = %s;" %
      loopvar,
      "thisev_sync->s.sync.syncrank = physrank;",
      "}"],
                  stack=synccode)
    return synccode

That definition of the n_for_count_SYNC_ALL hook method defines a new stack (synccode) and pushes a ‘{’ onto it. It then declares a loop variable, letting code_declare_var select a name but dictating that it end in ‘_task’. The hook method then pushes some additional C code onto the synccode stack and finally returns the stack (which is really just a list of lines of C code).

Some useful variables defined by NCPTL_CodeGen include the following:

base_global_parameters

a list of 6-ary tuples defining extra command-line parameters to parse (format: {type, variable, long_name, short_name, description, default_value})

events_used

a dictionary containing the names of events actually used by the program being compiled

Some methods in codegen_c_generic.py that are worth understanding but are unlikely to be used directly in a derived backend include the following:

pop

Pop a value from a stack.

push_marker

Push a specially designated “marker” value onto a stack.

combine_to_marker

Pop all items off a stack up to the first marker value found; discard the marker; then, push the popped items as a single list of items. This is used, for example, by a complex statement (see Complex statements) that applies to a list of statements, which can be popped as a unit using combine_to_marker.

invoke_hook

Call a hook method, specifying code to be pushed before/after the hook-produced code and alternative text (or Python code) to be pushed (or executed) in the case that a hook method is not provided.


Previous: , Up: Backend creation   [Contents][Index]

Scott Pakin, pakin@lanl.gov