Exemple #1
0
def insert_bottom_labels(sig, lines, v):
  """
  Insert bottom labels for each function.
  """
  # Look for the structure and insert:
  # > .globl <bottom-label>
  #   foo:
  #   ...
  # > <bottom-label>
  #   .cc_bottom foo.function
  
  vmsg(v, '  Inserting function labels')
  
  # For each function, for each line...
  # (Create a new list and modify it each time...)
  b = False
  for x in sig.mobile_proc_names:
    new = []
    for (i, y) in enumerate(lines):
      new.append(y)
      if y == x+':\n' and not b:
        new.insert(len(new)-1, 
            '.globl '+function_label_bottom(x)+'\n')
        b = True
      elif y[0] == '.' and b:
        if y.split()[0] == '.cc_bottom':
          new.insert(len(new)-1, 
              function_label_bottom(x)+':\n')
          b = False
    lines = new

  return lines
Exemple #2
0
def assemble_builtins(show_calls, v):
    vmsg(v, 'Compiling builtins:')
    for x in BUILTIN_FILES:
        objfile = x+'.o'
        vmsg(v, '  '+x+' -> '+objfile)
        util.call([CC, config.MPI_SYSTEM_PATH+'/'+x, 
            '-o', objfile] + ASSEMBLE_FLAGS, show_calls)
Exemple #3
0
def replace_images(show_calls, v):
  vmsg(v, 'Creating new executable')
  util.call([XCC, target_2core(), config.XS1_RUNTIME_PATH+'/container.xc', '-o', FINAL_XE])
  util.call([XOBJDUMP, '--split', MASTER_XE], v=show_calls)
  util.call([XOBJDUMP, FINAL_XE, '-r', '0,0,image_n0c0.elf'], v=show_calls)
  util.call([XOBJDUMP, '--split', SLAVE_XE], v=show_calls)
  util.call([XOBJDUMP, FINAL_XE, '-r', '0,1,image_n0c0.elf'], v=show_calls)
Exemple #4
0
def link_master(device, show_calls, v):
  """ 
  The jump table must be located at _cp and the common elements of the
  constant and data pools must be in the same positions relative to _cp and
  _dp in the master and slave images.
  """
  vmsg(v, 'Linking master -> '+MASTER_XE)
  s = util.call([XCC, target_1core(), 
    'system.S.o', 
    'system.xc.o',
    'control.xc.o',
    'worker.xc.o',
    'source.xc.o', 
    'host.xc.o', 
    'host.S.o',
    'connect.xc.o',
    'master.xc.o', 
    'master.S.o',
    'program.o',
    'memory.c.o', 
    'pointer.c.o', 
    'util.xc.o',
    MASTER_TABLES+'.o', 
    CONST_POOL+'.o',
    'globals.S.o',
    '-o', MASTER_XE] + LINK_FLAGS, 
    v=show_calls)
  print(s, end='')
Exemple #5
0
def assemble_runtime(show_calls, v):
    vmsg(v, 'Compiling runtime:')
    for x in RUNTIME_FILES:
        objfile = x+'.o'
        vmsg(v, '  '+x+' -> '+objfile)
        util.call([MPICC, config.MPI_RUNTIME_PATH+'/'+x, 
            '-o', objfile] + ASSEMBLE_FLAGS, show_calls)
Exemple #6
0
def translate(ast, sig, child, device, outfile, translate_only, v):
  """ 
  Translate the AST to target system.
  """
  vmsg(v, 'Translating AST...')

  buf = io.StringIO()
  ext = None

  # Create a tranlator AST walker
  if device.system == SYSTEM_TYPE_XS1:
    walker = TranslateXS1(sig, child, buf)
  elif device.system == SYSTEM_TYPE_MPI:
    walker = TranslateMPI(sig, child, buf)

  walker.walk_program(ast)
  
  if translate_only:
    outfile = (outfile if outfile!=defs.DEFAULT_OUT_FILE else
        outfile+'.'+device.source_file_ext())
    util.write_file(outfile, buf.getvalue())
    vmsg(v, 'Produced file: '+outfile)
    raise SystemExit()

  return buf
Exemple #7
0
def assemble_runtime(device, show_calls, v):
  vmsg(v, 'Compiling runtime:')
  for x in RUNTIME_FILES:
    objfile = x+'.o'
    vmsg(v, '  '+x+' -> '+objfile)
    s = util.call([XCC, config.XS1_RUNTIME_PATH+'/'+x, 
      '-o', objfile] + ASSEMBLE_FLAGS, v=show_calls)
    print(s, end='')
Exemple #8
0
def child_analysis(sig, ast):
  """ 
  Determine children.
  """
  vmsg(v, "Performing child analysis")
  child = Children(sig)
  ast.accept(child)
  child.build()
  #child.display()
  return child
Exemple #9
0
def link(show_calls, v):
    """ 
    Link the complete executable.
    """
    vmsg(v, 'Linking executable -> '+BINARY)
    util.call([MPICC, 'program.c.o'] 
        + [x+'.o' for x in RUNTIME_FILES] 
        + [x+'.o' for x in BUILTIN_FILES]
        + ['-o', BINARY] 
        + LINK_FLAGS, 
        show_calls)
Exemple #10
0
def append_header(device, outfile, show_calls, v):
  vmsg(v, 'Appending binary header')
  xe = open(FINAL_XE, "rb")
  se = open(outfile, "wb")
  try:
    se.write(bytes('SIRE', 'UTF-8'))
    se.write(struct.pack('I', device.num_cores()))
    se.write(xe.read())
  finally:
    xe.close()
    se.close()
Exemple #11
0
def assemble_str(name, string, show_calls, v, cleanup=True):
    """ 
    Assemble a buffer containing a c program.
    """
    srcfile = name + '.c'
    outfile = name + '.o'
    vmsg(v, 'Assembling '+srcfile+' -> '+outfile)
    util.write_file(srcfile, string)
    util.call([MPICC, srcfile, '-o', outfile] + ASSEMBLE_FLAGS, show_calls)
    if cleanup: 
        os.remove(srcfile)
Exemple #12
0
def compile_str(name, string, show_calls, v, save_temps=True):
  """ 
  Compile a buffer containing an XC program.
  """
  srcfile = name + '.xc'
  outfile = name + '.S'
  vmsg(v, 'Compiling '+srcfile+' -> '+outfile)
  util.write_file(srcfile, string)
  util.call([XCC, srcfile, '-o', outfile] + COMPILE_FLAGS, v=show_calls)
  if not save_temps:
    os.remove(srcfile)
Exemple #13
0
def cleanup(v):
    """ 
    Renanme the output file and delete any temporary files.
    """
    vmsg(v, 'Cleaning up')
    
    # Remove specific files
    util.remove_file(DEVICE_HDR)
    
    # Remove runtime objects
    for x in glob.glob('*.o'):
        util.remove_file(x)
Exemple #14
0
def rewrite_calls(sig, lines, v):
  """ 
  Rewrite calls to program functions to branch through the jump table.
  """
  vmsg(v, '  Rewriting calls')
  for (i, x) in enumerate(lines):
    frags = x.strip().split()
    names = builtin.runtime_functions + sig.mobile_proc_names 
    if frags and frags[0] == 'bl' and frags[1] in names:
      lines[i] = '\tbla cp[{}+{}]\n'.format(defs.LABEL_JUMP_TABLE, 
          names.index(frags[1])*defs.BYTES_PER_WORD)
  return lines
Exemple #15
0
def build(sig, buf, device, outfile, 
    compile_only, display_memory, show_calls, save_temps, v):
  """ 
  Compile the translated AST for the target system.
  """
  vmsg(v, 'Creating executable...')

  # Create a Build object
  if device.system == SYSTEM_TYPE_XS1:
    build_xs1(sig, device, buf, outfile, 
        compile_only, display_memory, show_calls, save_temps, v)
  elif device.system == SYSTEM_TYPE_MPI:
    build_mpi(device, buf, outfile, compile_only, show_calls, v)
Exemple #16
0
def modify_assembly(sig, lines, v):
  """ 
  Perform modifications on assembly output.
  """
  vmsg(v, 'Modifying assembly output')
  
  #print(''.join(lines))
  (lines, cp) = extract_constants(lines, v)
  lines = insert_bottom_labels(sig, lines, v)
  #lines = insert_frame_sizes(sig, lines, v)
  lines = rewrite_calls(sig, lines, v)
  lines.insert(0, '###### MODIFIED ######\n')
  #print(''.join(lines))

  return (lines, cp)
Exemple #17
0
def assemble_str(name, ext, string, show_calls, v, save_temps=False):
  """ 
  Assemble a buffer containing an XC or assembly program.
  """
  srcfile = name + '.' + ext
  outfile = name + '.o'
  vmsg(v, 'Assembling '+srcfile+' -> '+outfile)
  util.write_file(srcfile, string)
  if ext == 'xc':
    s = util.call([XCC, srcfile, '-o', outfile] + ASSEMBLE_FLAGS, v=show_calls)
    print(s, end='')
  elif ext == 'S':
    s = util.call([XAS, srcfile, '-o', outfile], v=show_calls)
    print(s, end='')
  if not save_temps: 
    os.remove(srcfile)
Exemple #18
0
    def walk_program(self, node, v):

        # All processes have been flattened into 'main'
        self.defs = node.defs
        debug(self.debug, 'd before program = {}'.format(0))
        d = self.stmt(node.defs[-1].stmt, node.defs[-1].name, 0)
        debug(self.debug, 'd after program = {}'.format(d))

        # Check the available number of processors has not been exceeded
        if d > self.device.num_cores():
            self.errorlog.report_error(
                'insufficient processors: {} required, {} available'.format(
                    d, self.device.num_cores()))

        # Report processor usage
        vmsg(v, '  {}/{} processors used'.format(d, self.device.num_cores()))
Exemple #19
0
  def walk_program(self, node, v):
  
    # All processes have been flattened into 'main'
    self.defs = node.defs
    debug(self.debug, 'd before program = {}'.format(0))
    d = self.stmt(node.defs[-1].stmt, node.defs[-1].name, 0)
    debug(self.debug, 'd after program = {}'.format(d))
    
    # Check the available number of processors has not been exceeded
    if d > self.device.num_cores():
      self.errorlog.report_error(
      'insufficient processors: {} required, {} available'
          .format(d, self.device.num_cores()))

    # Report processor usage
    vmsg(v, '  {}/{} processors used'.format(d, self.device.num_cores()))
Exemple #20
0
def semantic_analysis(sym, sig, ast, device, errorlog):
  """ 
  Perform semantic analysis on an AST.
  """
  vmsg(v, "Performing semantic analysis")
  sem = Semantics(sym, sig, device, errorlog)
  sem.walk_program(ast)
  
  # Check for any errors
  if errorlog.any():
    raise QuietError()
   
  # Quit if we're only performing semantic analysis
  if sem_only: 
    raise SystemExit()

  return sem
Exemple #21
0
def create_headers(device, v):
  vmsg(v, 'Creating device header '+DEVICE_HDR)
  s =  '#define NUM_CORES {}\n'.format(device.num_cores())
  s += '#define NUM_CORES_LOG {}\n'.format(
      int(math.log(device.num_cores())/math.log(2)))
  s += '#define NUM_CORES_SQRT {}\n'.format(
      int(math.sqrt(device.num_cores())))
  s += '#define NUM_NODES 0\n'
  s += '#define NUM_CORES_PER_NODE NUM_CORES\n'
  s += '#define XS1_L\n'
  #s += '#define NUM_NODES {}\n'.format(device.num_nodes)
  #s += '#define NUM_CORES_PER_NODE {}\n'.format(device.num_cores_per_node)
  #if device.type == XS1_DEVICE_TYPE_G:
  #  s +=  '#define XS1_G\n'
  #elif device.type == XS1_DEVICE_TYPE_L:
  #  s +=  '#define XS1_L\n'
  util.write_file(DEVICE_HDR, s)
Exemple #22
0
def produce_ast(input_file, errorlog, log=True):
  """ 
  Parse an input string to produce an AST.
  """
  vmsg(v, "Parsing file '{}'".format(infile if infile else 'stdin'))
   
  # Setup logging if we need to
  if log:
    logging.basicConfig(
      level = logging.DEBUG,
      filename = defs.PARSE_LOG_FILE,
      filemode = "w",
      format = "%(filename)10s:%(lineno)4d:%(message)s")
    logger = logging.getLogger()
  else:
    logger = 0
   
  # Create the parser and produce the AST
  parser = Parser(errorlog, lex_optimise=True, 
      yacc_debug=False, yacc_optimise=False)
  ast = parser.parse(input_file, infile, debug=logger)
  
  if errorlog.any():
    raise QuietError()
  
  # Perform parsing only
  if parse_only: 
    raise SystemExit()
  
  # Display (dump) the AST
  if print_ast:
    ast.accept(Dump())
    raise SystemExit()

  # Display (pretty-print) the AST
  if pprint_raw_ast: 
    Printer().walk_program(ast)
    raise SystemExit()

  return ast
Exemple #23
0
def build_mpi(device, buf, outfile, 
        compile_only, show_calls=False, v=False):
    """
    Run the build process to create either the assembly output or the complete
    binary.
    """
    # Add the include paths once they have been set
    include_dirs = ['-I', '.']
    include_dirs += ['-I', config.INSTALL_PATH]
    
    global COMPILE_FLAGS
    global ASSEMBLE_FLAGS
    COMPILE_FLAGS += include_dirs
    ASSEMBLE_FLAGS += include_dirs

    try:
        
        # Create headers
        create_headers(device, v)

        if compile_only:
            raise SystemExit() 

        # Compile the program and runtime
        assemble_str(PROGRAM, buf.getvalue(), show_calls, v)
        buf.close()
        assemble_runtime(show_calls, v)
        assemble_builtins(show_calls, v)
        link(show_calls, v)

        # Rename the output file
        outfile = (outfile if outfile!=defs.DEFAULT_OUT_FILE else
                outfile+'.'+device.binary_file_ext())
        os.rename(BINARY, outfile)

        vmsg(v, 'Produced file: '+outfile)

    finally:
        cleanup(v)
Exemple #24
0
def cleanup(v):
  """ 
  Renanme the output file and delete any temporary files.
  """
  vmsg(v, 'Cleaning up')
  
  # Remove specific files
  util.remove_file(MASTER_XE)
  util.remove_file(SLAVE_XE)
  util.remove_file('image_n0c0.elf')
  util.remove_file('config.xml')
  util.remove_file('platform_def.xn')
  util.remove_file('program_info.txt')
  util.remove_file(DEVICE_HDR)
  
  # Remove unused master images
  for x in glob.glob('image_n*c*elf'):
    util.remove_file(x)

  # Remove runtime objects
  for x in glob.glob('*.o'):
    util.remove_file(x)
Exemple #25
0
def build_master_tab_init(sig, buf, v):
  assert (len(sig.mobile_proc_names) + defs.JUMP_INDEX_OFFSET) <= defs.JUMP_TABLE_SIZE
  vmsg(v, 'Building master table initialisation ({}/{})'.format(
    len(sig.mobile_proc_names), defs.JUMP_TABLE_SIZE))
  buf.write('#include "xs1/definitions.h"\n')

  # Data section
  buf.write('.section .dp.data, "awd", @progbits\n')
  buf.write('.align {}\n'.format(defs.BYTES_PER_WORD))
  
  buf.write('_numProgEntries:\n')
  buf.write('.globl _numProgEntries\n')
  buf.write('.set _numProgEntries.globound, {}\n'.format(defs.BYTES_PER_WORD))
  buf.write('\t.word {}\n'.format(len(sig.mobile_proc_names)))

  buf.write('_jumpLocations:\n')
  buf.write('.globl _jumpLocations\n')
  buf.write('.set _jumpLocations.globound, {}\n'.format(
      len(sig.mobile_proc_names)*defs.BYTES_PER_WORD))
  for x in sig.mobile_proc_names:
    buf.write('\t.word {}\n'.format(x))
  
  buf.write('.align {}\n'.format(defs.BYTES_PER_WORD))
  buf.write('.globl '+defs.LABEL_SIZE_TABLE+', "a(:ui)"\n')
  buf.write('.set {}.globound, {}\n'.format(
    defs.LABEL_SIZE_TABLE, defs.BYTES_PER_WORD*defs.SIZE_TABLE_SIZE))
  buf.write(defs.LABEL_SIZE_TABLE+':\n')
  # Pad runtime entries
  for x in range(defs.JUMP_INDEX_OFFSET):
    buf.write('\t.word 0\n')
  # Program procedure entries
  for x in sig.mobile_proc_names:
    buf.write('\t.word {}-{}+{}\n'.format(
      function_label_bottom(x), x, defs.BYTES_PER_WORD))
  # Pad any unused space
  remaining = defs.SIZE_TABLE_SIZE - (defs.JUMP_INDEX_OFFSET +
      len(sig.mobile_proc_names))
  buf.write('\t.space {}\n'.format(remaining*defs.BYTES_PER_WORD))
Exemple #26
0
def link_slave(device, show_calls, v):
  """
  As above.
  """
  vmsg(v, 'Linking slave -> '+SLAVE_XE)
  s = util.call([XCC, target_1core(), 
    'system.S.o', 
    'system.xc.o',
    'control.xc.o',
    'worker.xc.o',
    'source.xc.o', 
    'host.xc.o', 
    'host.S.o',
    'connect.xc.o',
    'slave.S.o',
    'memory.c.o', 
    'pointer.c.o', 
    'util.xc.o', 
    CONST_POOL+'.o',
    'globals.S.o',
    '-o', SLAVE_XE] + LINK_FLAGS,
    v=show_calls)
  print(s, end='')
Exemple #27
0
def create_headers(device, v):
    vmsg(v, 'Creating device header '+DEVICE_HDR)
    s = ''
    s += '#define NUM_CORES {}\n'.format(device.num_cores())
    util.write_file(DEVICE_HDR, s)
Exemple #28
0
def extract_constants(lines, v):
  """ 
  Extract constant sections only within the elimination block of a function.
  This covers all constants local to a function. This is to differentiate
  constants associated with and declared global.
   - Don't include elimination blocks for strings.
   - Make extracted labels global.
  NOTE: this assumes a constant section will be terminated with a .text,
  (which may not always be true?).
  """
  vmsg(v, '  Extracting constants')
  cp = []
  new = []
  sect = False
  func = False
  for x in lines:

    # If we have entered a function elimination block
    if re.match(r'\.cc_top [_A-Za-z][A-Za-z0-9_]*\.function', x):
      func = True

    # If we have left
    if re.match(r'\.cc_bottom [_A-Za-z][A-Za-z0-9_]*\.function', x):
      func = False

    if func:

      # If this is a cp section
      if x.find('.section .cp') >= 0:
        sect = True
      
      # If we have left the cp section
      if x.find('.text') >= 0:
        sect = False

      if sect: 
        # If we are in the seciton: replace labels with externs, 
        # declare them as global in the new cp.
        if x.find(':\n') > 0:
          cp.append('\t.globl '+x[:-2]+'\n')
          new.insert(0, '\t.extern '+x[:-2]+'\n')
        
        # Rename .const4 and const8 to rodata
        if x.find('.section .cp.const') >= 0:
          x = '\t.section .cp.rodata, "ac", @progbits\n'

        # Leave .call and .globreads where they are
        if (x.find('.call')!=-1 or x.find('.globread')!=-1):
          new.append(x)
        # Omit elimination directives (for strings), 
        elif (x.find('.cc_top')==-1 and x.find('.cc_bottom')==-1):
          cp.append(x)

      # If we're outside a cp section, add to a new list
      else:
        if x.find('.text')==-1:
          new.append(x)
    
    # If we're outside a function block, add to a new list
    else:
      new.append(x)

  return (new, cp)
Exemple #29
0
def transform_ast(sem, sym, sig, ast, errorlog, device, v):
  """
  Perform transformations on the AST.
  """

  # 1. Distribute processes
  vmsg(v, "Expanding processes")
  ExpandProcs(sig, ast).walk_program(ast)
  if errorlog.any(): raise Error()

  # 2. Flatten nested parallel composition
  #vmsg(v, "Flattening nested parallel composition")
  #FlattenPar().walk_program(ast)

  # 3. Distribute processes
  vmsg(v, "Distributing processes")
  InsertOns(device, errorlog).walk_program(ast, v)
  if errorlog.any(): raise Error()

  # 4. Label process locations
  vmsg(v, "Labelling processes")
  LabelProcs(sym, device).walk_program(ast)

  # 5. Label channels
  vmsg(v, "Labelling channels")
  LabelChans(device, errorlog).walk_program(ast)
  if errorlog.any(): raise Error()

  # 6. Label connections
  vmsg(v, "Labelling connections")
  LabelConns().walk_program(ast)
  
  #DisplayConns(device).walk_program(ast)

  # 7. Insert channel ends
  vmsg(v, "Inserting connections")
  InsertConns(sym).walk_program(ast)

  # 8. Rename channel uses
  vmsg(v, "Renaming channel uses")
  RenameChans().walk_program(ast)
 
  # 9. Build the control-flow graph and initialise sets for liveness analysis
  vmsg(v, "Building the control flow graph")
  BuildCFG().run(ast)

  # 10. Perform liveness analysis
  vmsg(v, "Performing liveness analysis")
  Liveness().run(ast)
  
  # 13. Transform server processes
  vmsg(v, "Transforming server processes")
  TransformServer().walk_program(ast)

  # 11. Transform parallel composition
  vmsg(v, "Transforming parallel composition")
  TransformPar(sem, sig).walk_program(ast)
 
  # 12. Transform parallel replication
  vmsg(v, "Transforming parallel replication")
  TransformRep(sym, sem, sig, device).walk_program(ast)
  
  # 14. Flatten nested calls
  vmsg(v, "Flattening nested calls")
  FlattenCalls(sig).walk_program(ast)
  
  # 15. Remove unused declarations
  vmsg(v, "Removing unused declarations")
  RemoveDecls().walk_program(ast)
   
  # Display (pretty-print) the transformed AST
  if pprint_trans_ast: 
    Printer().walk_program(ast)
    raise SystemExit()
Exemple #30
0
def build_xs1(sig, device, program_buf, outfile, 
    compile_only, display_memory, 
    show_calls=False, save_temps=False, v=False):
  """ 
  Run the build process to create either the assembly output or the complete
  binary.
  """
  # Add the include paths once they have been set
  include_dirs = ['-I', '.']
  include_dirs += ['-I', config.INSTALL_PATH]
  
  global COMPILE_FLAGS
  global ASSEMBLE_FLAGS
  COMPILE_FLAGS += include_dirs
  ASSEMBLE_FLAGS += include_dirs

  # Try to run the build, pass any Error or SystemExit exceptions along to
  # main driver after having cleaned up and temporary files.
  try:

    # Create headers
    create_headers(device, v)

    # Generate the assembly
    (lines, cp) = generate_assembly(sig, program_buf, show_calls, v, save_temps)

    if compile_only:
      
      # Write the program back out and assemble
      util.write_file(PROGRAM_ASM, ''.join(lines))

      # Rename the output file
      outfile = (outfile if outfile!=defs.DEFAULT_OUT_FILE else
          outfile+'.'+device.assembly_file_ext())
      os.rename(PROGRAM_ASM, outfile)

      raise SystemExit() 

    # Write the program back out and assemble
    assemble_str(PROGRAM, 'S', ''.join(lines), show_calls, v)

    # Write the cp out and assemble
    assemble_str(CONST_POOL, 'S', ''.join(cp), show_calls, v)

    # Output and assemble the master jump table
    buf = io.StringIO()
    build_master_tab_init(sig, buf, v)
    #print(buf.getvalue())
    assemble_str(MASTER_TABLES, 'S', buf.getvalue(), show_calls, v, save_temps)

    # Assemble and link the rest
    assemble_runtime(device, show_calls, v)
    link_master(device, show_calls, v)
    link_slave(device, show_calls, v)
    replace_images(show_calls, v)
    
    # Dump memory usage information
    if display_memory:
      dump_memory_use()

    # Append XE to header in output file
    outfile = (outfile if outfile!=defs.DEFAULT_OUT_FILE else
        outfile+'.se')
    append_header(device, outfile, show_calls, v)
    vmsg(v, 'Produced file: '+outfile)

  except Error as e:
    raise Error(e.args)
  
  except SystemExit:
    raise SystemExit()
  
  except:
    raise
    
  finally:
    if not save_temps:
      cleanup(v)