def run_all(self, max_passes): """ Optimizer main function, which runs the implemented optimizations on the codes. """ if max_passes == 0: debug('optimizer disabled') return self.run_opt(self.del_unused_results) # no need to run this one multiple times for count in xrange(max_passes): debug('------------- global optimizer pass %d (of max %d) -------------' % ( count+1, max_passes)) sum_counters = sum(self.opt_counters.values()) self.run_opt(self.del_jumps_to_next, max_passes=self.INF_PASSES) self.run_opt(self.del_unused_labels) self.run_opt(self.reduce_push_pop, max_passes=self.INF_PASSES) self.run_opt(self.propagate_constants) #self.run_opt(self.clear_deleted_codes) if sum(self.opt_counters.values()) == sum_counters: debug('------------------ all optimizations returned finish -----------------') break # TODO don't assign dead vars # TODO free string memory # TODO [mov mem regA, mov regA regB] # TODO [mov regA memX, mov memX regB] if Flags.optimizer_summary: Status.add_note(LatteError('optimizer case counters:')) for name, count in self.opt_counters.iteritems(): Status.add_note(LatteError(name + ': ' + str(count)))
def parse_args(cls, argv): parser = argparse.ArgumentParser(description='Latte x86 compiler', prog='latc_x86') parser.add_argument( 'input_file', help='Latte source file (\'-\' for stdin, implies asm_output=\'-\')' ) parser.add_argument('-o', '--output', dest='bin_file', help='custom output executable file') parser.add_argument('-s', '--asm-output', dest='asm_file', help="""custom output assembly file ('-' for stdout, does not create executable)""" ) parser.add_argument('-d', '--debug', action='store_true', help="""print debug messages and output messages immediately (in particular, omit the requirement for 'OK'/'ERROR' to be in the first line)""") parser.add_argument( '-r', '--runtime', dest='runtime_file', default='runtime.o', help='path to latte runtime library (default runtime.o)') parser.add_argument('-C', '--no-color', dest='output_colors', action='store_false', help='disable output coloring') parser.add_argument('-O', '--optimizer-passes', type=int, help='max optimizer loop iterations') parser.add_argument('--optimizer-summary', action='store_true', help='note optimization counters to output') parser.parse_args( namespace=cls) # Saves values in this class, exits on error. # Set output file names, if not provided. if not cls.asm_file: (cls.asm_file, _) = splitext(cls.input_file) if (cls.asm_file != '-'): cls.asm_file += '.s' if cls.asm_file == cls.input_file and cls.asm_file != '-': Status.add_error(LatteError( 'assembly output cannot be the same file as the source code' ), fatal=True) if (not cls.bin_file) and cls.asm_file != '-': (cls.bin_file, _) = splitext(cls.input_file) if cls.bin_file == cls.input_file: Status.add_error(LatteError( 'output binary cannot be the same file as the source code' ), fatal=True)
def run_typechecks(cls): debug('--------------- TYPECHECK ---------------------') """ Run type and return checks. """ cls.prog_tree.check_types() if Status.errors() > 0: Status.add_error(LatteError('compilation failed'), fatal=True) debug('-------------- CHECKED TREE -------------------') cls.prog_tree.print_tree()
def build_code(cls): """ Generate intermediate code from the tree. """ debug('------------- BUILD CODE TREE -----------------') cls.prog_code = ProgCode(cls.prog_tree) debug('--------------- GEN CODES ---------------------') cls.prog_code.gen_code() cls.codes = [i for i in cls.prog_code.codes()] if Status.errors() > 0: Status.add_error(LatteError('compilation failed'), fatal=True)
def parse_code(cls): """ Parse the source code. """ cls.lexer = LatteLexer(cls.filestream) cls.tokens = CommonTokenStream(cls.lexer) Status.set_token_stream(cls.tokens) cls.parser = LatteParser(cls.tokens) cls.parsed_prog = cls.parser.prog() if Status.errors() > 0: Status.add_error(LatteError('parsing failed'), fatal=True) debug('----------------- AST -------------------------') debug('Tree: ', cls.parsed_prog.tree.toStringTree())
def main(argv): Latc.setup_args(argv) Latc.parse_code() Latc.build_code_tree() Latc.run_typechecks() Latc.build_code() Latc.run_optimizer() Latc.output_assembly() Latc.link_executable() Status.flush() sys.exit(Status.errors())
def output_assembly(cls): """ Output the assembly code. """ debug('-------------- ASM OUTPUT ---------------------') try: asm_file = sys.stdout if Flags.output_to_stdout() else open( Flags.asm_file, 'w') for instr in Codes.gen_asm(cls.optimizer.codes): print(str(instr), file=asm_file) if not Flags.output_to_stdout(): asm_file.close() except IOError as err: Status.add_error(err, fatal=True)
def build_code_tree(cls): """ Build the tree from code AST. """ debug('-------------- BUILD TREE ---------------------') cls.nodes = CommonTreeNodeStream(cls.parsed_prog.tree) cls.nodes.setTokenStream(cls.tokens) Status.set_node_stream(cls.nodes) cls.builder = LatteTreeBuilder(cls.nodes) cls.prog_tree = cls.builder.prog() if Status.errors() > 0: Status.add_error(LatteError('parsing failed'), fatal=True) debug('---------------- TREE -------------------------') cls.prog_tree.print_tree()
def setup_args(cls, argv): """ Read arguments and open input stream. """ Flags.parse_args(argv) # Exits on error. if Flags.input_from_stdin(): cls.filestream = ANTLRInputStream(sys.stdin) debug('INPUT: stdin') else: try: cls.filestream = ANTLRFileStream(Flags.input_file) except IOError as err: Status.add_error(err, fatal=True) debug('INPUT: ', Flags.input_file) debug('ASM OUTPUT: ', Flags.asm_file) debug('BIN OUTPUT: ', Flags.bin_file)
def link_executable(cls): """ Make the executable file from assembly and Latte runtime library. """ if not Flags.output_to_stdout(): # capture the output, so the possible 'ERROR' message is still in first line try: gcc_out = check_output([ 'gcc', '-m32', Flags.runtime_file, Flags.asm_file, '-o', Flags.bin_file ], stderr=STDOUT) if gcc_out: Status.add_warning( LatteError('linking messages:\n' + gcc_out)) except CalledProcessError as err: Status.add_error(LatteError('linking failed:\n' + err.output), fatal=True)