# HG changeset patch # User Windel Bouwman # Date 1378308906 -7200 # Node ID ea93e0a7a31e5154a31f676a24d0e219a2f3696f # Parent 6b3a874edd6ec59630f53c4bd6e1dda93238f6b6 Move docs diff -r 6b3a874edd6e -r ea93e0a7a31e .hgignore --- a/.hgignore Mon Sep 02 17:40:21 2013 +0200 +++ b/.hgignore Wed Sep 04 17:35:06 2013 +0200 @@ -8,5 +8,5 @@ cos/bootdisk.img cos/lcfosinitrd.img cos/kernel/kernel.map -python/doc/_build +doc/_build diff -r 6b3a874edd6e -r ea93e0a7a31e doc/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/Makefile Wed Sep 04 17:35:06 2013 +0200 @@ -0,0 +1,153 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/lcfos.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/lcfos.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/lcfos" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/lcfos" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff -r 6b3a874edd6e -r ea93e0a7a31e doc/compiler.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/compiler.rst Wed Sep 04 17:35:06 2013 +0200 @@ -0,0 +1,110 @@ + + +Compiler +======== + +This chapter describes the design of the compiler. + + +Overview +-------- + +The compiler consists a frontend, mid-end and back-end. The frontend deals with +source file parsing and semantics checking. The mid-end performs optimizations. +This is optional. The back-end generates machine code. The front-end produces +intermediate code. This is a simple representation of the source. The back-end +can accept this kind of representation. This way the compiler is portable and +a front end can be constructed without having to do the rest. + +.. graphviz:: + + digraph x { + rankdir="LR" + 1 [label="c3 source file"] + 10 [label="c3 front end" ] + 11 [label="language X front end" ] + 20 [label="mid end" ] + 30 [label="back end for X86" ] + 31 [label="back end for ARM" ] + 40 [label="object file"] + 1 -> 10 + 10 -> 20 [label="IR-code"] + 11 -> 20 [label="IR-code"] + 20 -> 30 [label="IR-code"] + 20 -> 31 [label="IR-code"] + 30 -> 40 + } + +IR-code +------- +The IR-code is implemented in the ir package. + +.. autoclass:: ir.Module + +.. autoclass:: ir.Function + +.. autoclass:: ir.Block + +.. autoclass:: ir.Statement + +.. autoclass:: ir.Expression + +.. # .. inheritance-diagram:: ir.Statement + +C3 Front-end +------------ + +For the front-end a recursive descent parser is created for the c3 language. +This is a subset of the C language with some additional features. + +.. graphviz:: + + digraph c3 { + rankdir="LR" + 1 [label="source text"] + 10 [label="lexer" ] + 20 [label="parser" ] + 30 [label="semantic checks" ] + 40 [label="code generation"] + 99 [label="IR-code object"] + 1 -> 20 + 20 -> 30 + 30 -> 40 + 40 -> 99 + subgraph rel1 { + edge [dir=none] + 10 -> 20 + } + } + +.. autoclass:: c3.Builder + +.. autoclass:: c3.Parser + +.. autoclass:: c3.CodeGenerator + +Back-end +-------- + +The back-end is more complicated. There are several steps to be taken here. + +1. Instruction selection +2. register allocation +3. Peep hole optimization? +4. real code generation + +.. automodule:: codegenarm + :members: + +Instruction selection +~~~~~~~~~~~~~~~~~~~~~ + +The instruction selection phase takes care of scheduling and instruction +selection. The output of this phase is a one frame per function with a flat +list of abstract machine instructions. + +.. autoclass:: irmach.Frame + +.. autoclass:: irmach.AbstractInstruction + + diff -r 6b3a874edd6e -r ea93e0a7a31e doc/conf.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/conf.py Wed Sep 04 17:35:06 2013 +0200 @@ -0,0 +1,244 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# lcfos documentation build configuration file, created by +# sphinx-quickstart on Sat Aug 31 18:04:20 2013. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('../python')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.graphviz', 'sphinx.ext.autodoc'] +# 'sphinx.ext.inheritance_diagram'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'lcfos' +copyright = '2013, Windel Bouwman' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0.1' +# The full version, including alpha/beta/rc tags. +release = '0.1' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'lcfosdoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'lcfos.tex', 'lcfos Documentation', + 'Windel Bouwman', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'lcfos', 'lcfos Documentation', + ['Windel Bouwman'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'lcfos', 'lcfos Documentation', + 'Windel Bouwman', 'lcfos', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' diff -r 6b3a874edd6e -r ea93e0a7a31e doc/design.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/design.rst Wed Sep 04 17:35:06 2013 +0200 @@ -0,0 +1,103 @@ +Design +====== + +OS +-- + +Processes / threads +~~~~~~~~~~~~~~~~~~~ + +Processes are completely seperated and fully pre-emptive. +This means a process can be unscheduled at any moment. + +Threads are co-operative. This means they yield control +voluntary. This means that mutexes and locks are not required. +This is done with the built-in language feature called tasks. + +If some heavy duty task must be performed, either way spawn +a new process, or yield frequently from this hard labour. + +tasks +~~~~~ + +Consider the following: + +.. code:: + + function int insanemath(int a) + { + while (a > 0) + { + a = a -1; + resume agent1; + } + return a - 1; + } + + task agent1() + { + start agent2; + } + + task agent2() + { + insanemath(55); + insanemath(44); + } + + task main() + { + start agent1; + join agent1; + } + + +Say to tasks are running in concurrent / parallel. + + + +Stack layout for tasks. +|| +|| +\/ ++---------+ +| return address +| locals +| ++------ +| return address +| locals +| ++--- + +Assembly code for the functions above: + +.. code:: + + .code + insanemath: + L1: + load r0, sp - 4 + cmp r0, 0 + jl L2 + dec r0 + store r0, sp - 4 + jmp L1 + L2: + ret + + agent1: + hlt? + + agent2: + hlt? + + main: + jmp agent1 + + .data + agent1_task: + dd 0 + agent2_task: + dd 0 + diff -r 6b3a874edd6e -r ea93e0a7a31e doc/index.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/index.rst Wed Sep 04 17:35:06 2013 +0200 @@ -0,0 +1,26 @@ +.. lcfos documentation master file, created by + sphinx-quickstart on Sat Aug 31 18:04:20 2013. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to lcfos's documentation! +================================= + +Contents: + +.. toctree:: + :maxdepth: 2 + + readme_link + design + compiler + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff -r 6b3a874edd6e -r ea93e0a7a31e doc/readme_link.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/readme_link.rst Wed Sep 04 17:35:06 2013 +0200 @@ -0,0 +1,3 @@ + +.. include:: ../readme.rst + diff -r 6b3a874edd6e -r ea93e0a7a31e python/c3/codegenerator.py --- a/python/c3/codegenerator.py Mon Sep 02 17:40:21 2013 +0200 +++ b/python/c3/codegenerator.py Wed Sep 04 17:35:06 2013 +0200 @@ -7,7 +7,14 @@ class CodeGenerator(ir.Builder): - """ Generates intermediate code from a package """ + """ + Generates intermediate (IR) code from a package. The entry function is + 'genModule'. The main task of this part is to rewrite complex control + structures, such as while and for loops into simple conditional + jump statements. Also complex conditional statements are simplified. + Such as 'and' and 'or' statements are rewritten in conditional jumps. + And structured datatypes are rewritten. + """ def __init__(self): self.logger = logging.getLogger('c3cgen') @@ -48,11 +55,14 @@ # TODO: handle parameters different if sym.isParameter: print('param', sym) - ir.Parameter(sym.name) - if sym.isLocal: + v = ir.Parameter(sym.name) + f.addParameter(v) + elif sym.isLocal: print('local', sym) - - v = self.newTemp() + v = self.newTemp() + else: + v = self.newTemp() + #raise NotImplementedError('{}'.format(sym)) # TODO: make this ssa here?? self.varMap[sym] = v @@ -93,6 +103,8 @@ re = self.genExprCode(code.expr) self.emit(ir.Move(self.fn.return_value, re)) self.emit(ir.Jump(self.fn.epiloog)) + b = self.newBlock() + self.setBlock(b) else: self.builder.addIns(ir.Return()) elif type(code) is astnodes.WhileStatement: diff -r 6b3a874edd6e -r ea93e0a7a31e python/codegen.py --- a/python/codegen.py Mon Sep 02 17:40:21 2013 +0200 +++ b/python/codegen.py Wed Sep 04 17:35:06 2013 +0200 @@ -20,7 +20,7 @@ print(gvar) print('TODO') for f in ircode.Functions: - for bb in f.BasicBlocks: + for bb in f.Blocks: for ins in bb.Instructions: # Instruction selection: #mi = self.tryMap(ins) diff -r 6b3a874edd6e -r ea93e0a7a31e python/codegenarm.py --- a/python/codegenarm.py Mon Sep 02 17:40:21 2013 +0200 +++ b/python/codegenarm.py Wed Sep 04 17:35:06 2013 +0200 @@ -8,8 +8,19 @@ from instructionselector import InstructionSelector import irmach + +class ArmFrame(irmach.Frame): + """ + Arm specific frame for functions. + """ + pass + + class ArmInstructionSelector(InstructionSelector): """ Instruction selector for the arm architecture """ + def newFrame(self, name): + return ArmFrame(name) + def munchExpr(self, e): if isinstance(e, ir.Alloc): return 0 @@ -58,9 +69,15 @@ return d elif isinstance(e, ir.Temp): return self.getTempReg(e) + elif isinstance(e, ir.Parameter): + offset = 1337 # TODO: determine offset in frame?? + d = self.newTmp() + self.emit('ldr %d0, [sp + {}]'.format(offset), dst=[d]) + return d elif isinstance(e, ir.Call): args = [self.munchExpr(a) for a in e.arguments] - self.emit('add sp, sp, 22') + frame_size = 222 # TODO: determine frame size? + self.emit('add sp, sp, {}'.format(frame_size)) # TODO: save frame for a in args: self.emit('push %s0', src=[a]) @@ -73,28 +90,31 @@ if isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem): memloc = self.munchExpr(s.dst.e) val = self.munchExpr(s.src) - self.emit('str [%s0], %s1') + self.emit('str [%s0], %s1', src=[memloc, val]) elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp): val = self.munchExpr(s.src) dreg = self.getTempReg(s.dst) self.emit('mov %d0, %s0', dst=[dreg], src=[val]) elif isinstance(s, ir.Jump): tgt = self.targets[s.target] - self.emit('jmp {}'.format(s), jumps=[tgt]) + self.emit('jmp %l0', jumps=[tgt]) elif isinstance(s, ir.CJump): a = self.munchExpr(s.a) b = self.munchExpr(s.b) self.emit('cmp %s0, %s1', src=[a, b]) ntgt = self.targets[s.lab_no] ytgt = self.targets[s.lab_yes] - jmp_ins = self.makeIns('jmp {}'.format(s.lab_no), jumps=[ntgt]) + jmp_ins = self.makeIns('jmp %l0', jumps=[ntgt]) # Explicitely add fallthrough: - self.emit('jeq {}'.format(s.lab_yes), jumps=[ytgt, jmp_ins]) + self.emit('jeq %l0', jumps=[ytgt, jmp_ins]) self.emit2(jmp_ins) + elif isinstance(s, ir.Terminator): + pass else: - raise NotImplementedError('--> {}'.format(s)) + raise NotImplementedError('Stmt --> {}'.format(s)) +# TODO: this class could be target independent: class ArmCodeGenerator: def __init__(self, outs): # TODO: schedule traces in better order. @@ -116,31 +136,42 @@ defTemps = set(defTemps) useTemps = set(useTemps) unUsed = defTemps - useTemps - #print('Unused:', unUsed) + print('Unused:', unUsed) for uu in unUsed: inslist.append(irmach.AbstractInstruction('use %s0', src=[uu])) #print(useTemps) - def generate(self, ircode, cfg_file=None, ig_file=None): - ir2 = self.ins_sel.munchProgram(ircode) - self.useUnused(ir2) - cfg = flowgraph.FlowGraph(ir2) - if cfg_file: - cfg.to_dot(cfg_file) + def allocFrame(self, f): + """ + Do register allocation for a single stack frame. + """ + ilist = f.instructions + self.useUnused(ilist) + cfg = flowgraph.FlowGraph(ilist) + f.cfg = cfg ig = registerallocator.InterferenceGraph(cfg) - if ig_file: - ig.to_dot(ig_file) + f.ig = ig regs = ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7'] ra = registerallocator.RegisterAllocator() regMap = ra.registerAllocate(ig, regs) #print(regMap) # Use allocated registers: - for i in ir2: + for i in ilist: i.src = tuple(regMap[t] for t in i.src) i.dst = tuple(regMap[t] for t in i.dst) #print(i) - return ir2 + + def generate(self, ircode): + # Munch program into a bunch of frames. One frame per function. + # Each frame has a flat list of abstract instructions. + frames = self.ins_sel.munchProgram(ircode) + self.frames = frames + for f in frames: + self.allocFrame(f) + + # TODO: Peep-hole here + # TODO: Materialize assembly + return frames - diff -r 6b3a874edd6e -r ea93e0a7a31e python/doc/Makefile --- a/python/doc/Makefile Mon Sep 02 17:40:21 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,153 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/lcfos.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/lcfos.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/lcfos" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/lcfos" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." diff -r 6b3a874edd6e -r ea93e0a7a31e python/doc/compiler.rst --- a/python/doc/compiler.rst Mon Sep 02 17:40:21 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ - - -Compiler -======== - -This chapter describes the design of the compiler. - - -Overview --------- - -The compiler consists a frontend, mid-end and back-end. The frontend deals with -source file parsing and semantics checking. The mid-end performs optimizations. -This is optional. The back-end generates machine code. The front-end produces -intermediate code. This is a simple representation of the source. The back-end -can accept this kind of representation. This way the compiler is portable and -a front end can be constructed without having to do the rest. - -.. graphviz:: - - - digraph x { - rankdir="LR" - 1 [label="c3 source file"] - 10 [label="c3 front end" ] - 11 [label="language X front end" ] - 20 [label="mid end" ] - 30 [label="back end for X86" ] - 31 [label="back end for ARM" ] - 40 [label="object file"] - 1 -> 10 - 10 -> 20 [label="IR-code"] - 11 -> 20 [label="IR-code"] - 20 -> 30 [label="IR-code"] - 20 -> 31 [label="IR-code"] - 30 -> 40 - } - -IR-code -------- -The IR-code is implemented in the ir package. - -.. autoclass:: ir.Module - :members: - -.. autoclass:: ir.Function - :members: - -.. autoclass:: ir.Block - :members: - -.. autoclass:: ir.Statement - :members: - -.. autoclass:: ir.Expression - :members: - -.. # .. inheritance-diagram:: ir.Statement - -Front-end ---------- - -For the front-end a recursive descent parser is created for the c3 language. -This is a subset of the C language with some additional features. - -.. automodule:: c3 - :members: - :undoc-members: - -.. autoclass:: c3.Parser - :members: - -.. autoclass:: c3.Builder - :members: - -.. autoclass:: c3.CodeGenerator - :members: - -Back-end --------- - -The back-end is more complicated. There are several steps to be taken here. - -1. Instruction selection -2. register allocation -3. Peep hole optimization? -4. real code generation - -.. automodule:: codegenarm - :members: - diff -r 6b3a874edd6e -r ea93e0a7a31e python/doc/conf.py --- a/python/doc/conf.py Mon Sep 02 17:40:21 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,244 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# lcfos documentation build configuration file, created by -# sphinx-quickstart on Sat Aug 31 18:04:20 2013. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys, os - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.insert(0, os.path.abspath('..')) - -# -- General configuration ----------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.graphviz', 'sphinx.ext.autodoc'] -# 'sphinx.ext.inheritance_diagram'] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = 'lcfos' -copyright = '2013, Windel Bouwman' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '0.1' -# The full version, including alpha/beta/rc tags. -release = '0.1' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'default' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'lcfosdoc' - - -# -- Options for LaTeX output -------------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ('index', 'lcfos.tex', 'lcfos Documentation', - 'Windel Bouwman', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output -------------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'lcfos', 'lcfos Documentation', - ['Windel Bouwman'], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------------ - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'lcfos', 'lcfos Documentation', - 'Windel Bouwman', 'lcfos', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' diff -r 6b3a874edd6e -r ea93e0a7a31e python/doc/design.rst --- a/python/doc/design.rst Mon Sep 02 17:40:21 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -Design -====== - -OS --- - -Processes / threads -~~~~~~~~~~~~~~~~~~~ - -Processes are completely seperated and fully pre-emptive. -This means a process can be unscheduled at any moment. - -Threads are co-operative. This means they yield control -voluntary. This means that mutexes and locks are not required. -This is done with the built-in language feature called tasks. - -If some heavy duty task must be performed, either way spawn -a new process, or yield frequently from this hard labour. - -tasks -~~~~~ - -Consider the following: - -.. code:: - - function int insanemath(int a) - { - while (a > 0) - { - a = a -1; - resume agent1; - } - return a - 1; - } - - task agent1() - { - start agent2; - } - - task agent2() - { - insanemath(55); - insanemath(44); - } - - task main() - { - start agent1; - join agent1; - } - - -Say to tasks are running in concurrent / parallel. - - - -Stack layout for tasks. -|| -|| -\/ -+---------+ -| return address -| locals -| -+------ -| return address -| locals -| -+--- - -Assembly code for the functions above: - -.. code:: - - .code - insanemath: - L1: - load r0, sp - 4 - cmp r0, 0 - jl L2 - dec r0 - store r0, sp - 4 - jmp L1 - L2: - ret - - agent1: - hlt? - - agent2: - hlt? - - main: - jmp agent1 - - .data - agent1_task: - dd 0 - agent2_task: - dd 0 - diff -r 6b3a874edd6e -r ea93e0a7a31e python/doc/index.rst --- a/python/doc/index.rst Mon Sep 02 17:40:21 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -.. lcfos documentation master file, created by - sphinx-quickstart on Sat Aug 31 18:04:20 2013. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to lcfos's documentation! -================================= - -Contents: - -.. toctree:: - :maxdepth: 2 - - readme_link - design - compiler - - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - diff -r 6b3a874edd6e -r ea93e0a7a31e python/doc/readme_link.rst --- a/python/doc/readme_link.rst Mon Sep 02 17:40:21 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ - - - -.. include:: ../../readme.rst diff -r 6b3a874edd6e -r ea93e0a7a31e python/flowgraph.py --- a/python/flowgraph.py Mon Sep 02 17:40:21 2013 +0200 +++ b/python/flowgraph.py Wed Sep 04 17:35:06 2013 +0200 @@ -13,7 +13,12 @@ self.live_out = set() def __repr__(self): - return '{}, use={}, def={}'.format(self.ins, self.uses, self.defs) + r = '{}'.format(self.ins) + if self.uses: + r += ' uses:' + ', '.join(str(u) for u in self.uses) + if self.defs: + r += ' defs:' + ', '.join(str(d) for d in self.defs) + return r class FlowGraph(graph.Graph): diff -r 6b3a874edd6e -r ea93e0a7a31e python/graph.py --- a/python/graph.py Mon Sep 02 17:40:21 2013 +0200 +++ b/python/graph.py Wed Sep 04 17:35:06 2013 +0200 @@ -26,12 +26,12 @@ def to_dot(self, f): """ Generate graphviz dot representation """ - print('digraph G {', file=f) + #print('digraph G {', file=f) for node in self.nodes: print('{} [label="{}" shape=box3d];'.format(id(node), node), file=f) for n, m in self.edges: print('{} -> {};'.format(id(n), id(m)), file=f) - print('}', file=f) + #print('}', file=f) class Node: diff -r 6b3a874edd6e -r ea93e0a7a31e python/instructionselector.py --- a/python/instructionselector.py Mon Sep 02 17:40:21 2013 +0200 +++ b/python/instructionselector.py Wed Sep 04 17:35:06 2013 +0200 @@ -25,20 +25,23 @@ # Entry point for instruction selection self.temps = genTemps() assert isinstance(p, ir.Module) - self.result = [] + self.frames = [] self.targets = {} self.tempMap = {} # Mapping from temporaries to infinite register for f in p.Functions: + # Enter a frame per function: + self.frame = self.newFrame(f.name) + self.frames.append(self.frame) # First define labels: - for bb in f.BasicBlocks: + for bb in f.Blocks: itgt = self.makeIns('{}:'.format(bb.name)) self.targets[bb] = itgt - for bb in f.BasicBlocks: + for bb in f.Blocks: self.emit2(self.targets[bb]) for i in bb.Instructions: self.munchStm(i) - bb.machIns = self.result - return self.result + #bb.machIns = self.result + return self.frames def makeIns(self, *args, **kwargs): return irmach.AbstractInstruction(*args, **kwargs) @@ -49,12 +52,17 @@ return self.emit2(i) def emit2(self, i): - self.result.append(i) + self.frame.instructions.append(i) return i + def newFrame(self, name): + raise NotImplementedError() + def munchStm(self, s): + """ Implement this in the target specific back-end """ raise NotImplementedError() def munchExpr(self, e): + """ Implement this in the target specific back-end """ raise NotImplementedError() diff -r 6b3a874edd6e -r ea93e0a7a31e python/ir/__init__.py --- a/python/ir/__init__.py Mon Sep 02 17:40:21 2013 +0200 +++ b/python/ir/__init__.py Wed Sep 04 17:35:06 2013 +0200 @@ -1,4 +1,3 @@ -from .module import Module, Function, Block -from .instruction import * +from .module import * from .builder import Builder diff -r 6b3a874edd6e -r ea93e0a7a31e python/ir/instruction.py --- a/python/ir/instruction.py Mon Sep 02 17:40:21 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,144 +0,0 @@ -from .module import Function - -class Expression: - pass - - -class Const(Expression): - def __init__(self, value): - self.value = value - - def __repr__(self): - return 'Constant {}'.format(self.value) - - -# Function calling: -class Call(Expression): - def __init__(self, f, arguments): - self.f = f - assert type(f) is Function - self.arguments = arguments - - def __repr__(self): - args = ','.join([str(arg) for arg in self.arguments]) - return '{}({})'.format(self.f.name, args) - - -# Data operations -class Binop(Expression): - ops = ['+', '-', '*', '/', '|', '&', '<<', '>>'] - def __init__(self, value1, operation, value2): - assert operation in Binop.ops - self.value1 = value1 - self.value2 = value2 - self.operation = operation - - def __repr__(self): - a, b = self.value1, self.value2 - return '({} {} {})'.format(a, self.operation, b) - - -def Add(a, b): - """ Convenience call """ - return Binop(a, '+', b) - - -class Alloc(Expression): - """ Allocates space on the stack """ - def __init__(self): - super().__init__() - - def __repr__(self): - return 'Alloc' - - -class Variable(Expression): - def __init__(self, offset): - self.offset = offset - - def __repr__(self): - return 'Variable' - - -class LocalVariable(Variable): - pass - - -class GlobalVariable(Variable): - pass - - -class Parameter(Variable): - pass - - -class Temp(Expression): - """ Temporary storage, same as register """ - def __init__(self, name): - self.name = name - - def __repr__(self): - return 'T_{}_'.format(self.name) - - -class Mem(Expression): - def __init__(self, e): - self.e = e - - def __repr__(self): - return '[{}]'.format(self.e) - - -class Statement: - """ Base class for all instructions. """ - pass - - -class Move(Statement): - def __init__(self, dst, src): - self.dst = dst - self.src = src - - def __repr__(self): - return '{} = {}'.format(self.dst, self.src) - - -class Exp(Statement): - def __init__(self, e): - self.e = e - - -class Label(Statement): - def __init__(self, name): - self.name = name - self.statements = [] - - def __repr__(self): - return 'LABEL {}:'.format(self.name) - - -# Branching: -class Jump(Statement): - def __init__(self, target): - self.target = target - self.Targets = [target] - - def __repr__(self): - return 'BRANCH {}'.format(self.target.name) - - -class CJump(Statement): - def __init__(self, a, cond, b, lab_yes, lab_no): - assert cond in ['==', '<', '>', '>=', '<=', '!='] - self.a = a - self.cond = cond - self.b = b - self.lab_yes = lab_yes - self.lab_no = lab_no - self.Targets = [lab_yes, lab_no] - - def __repr__(self): - return 'IF {} {} {} THEN {} ELSE {}'.format(self.a, self.cond, self.b, self.lab_yes, self.lab_no) - - - diff -r 6b3a874edd6e -r ea93e0a7a31e python/ir/module.py --- a/python/ir/module.py Mon Sep 02 17:40:21 2013 +0200 +++ b/python/ir/module.py Wed Sep 04 17:35:06 2013 +0200 @@ -1,8 +1,24 @@ # IR-Structures: +def dumpgv(m, outf): + print('digraph G ', file=outf) + print('{', file=outf) + for f in m.Functions: + print('{} [label="{}" shape=box3d]'.format(id(f), f),file=outf) + for bb in f.Blocks: + contents = str(bb) + '\n' + contents += '\n'.join([str(i) for i in bb.Instructions]) + outf.write('{0} [shape=note label="{1}"];\n'.format(id(bb), contents)) + for successor in bb.Successors: + print('"{}" -> "{}"\n'.format(id(bb), id(successor)), file=outf) + + outf.write('"{}" -> "{}" [label="entry"]\n'.format(id(f), id(f.entry))) + print('}', file=outf) + + class Module: - """ Main container for a piece of code. """ + """ Main container of variables and functions. """ def __init__(self, name): self.name = name self.funcs = [] @@ -38,29 +54,16 @@ getFunction = findFunction def dump(self): - print(self) - for v in self.Variables: - print(' ', v) - for fn in self.Functions: - print(fn) - for bb in fn.BasicBlocks: - print(' ', bb) - for ins in bb.Instructions: - print(' ', ins) - - def dumpgv(self, outf): - outf.write('digraph G \n{\n') - for f in self.Functions: - outf.write('{0} [label="{1}" shape=box3d]\n'.format(id(f), f)) - for bb in f.BasicBlocks: - contents = str(bb) + '\n' - contents += '\n'.join([str(i) for i in bb.Instructions]) - outf.write('{0} [shape=note label="{1}"];\n'.format(id(bb), contents)) - for successor in bb.Successors: - outf.write('"{0}" -> "{1}"\n'.format(id(bb), id(successor))) - - outf.write('"{0}" -> "{1}" [label="entry"]\n'.format(id(f), id(f.entry))) - outf.write('}\n') + print(self) + indent = ' ' + for v in self.Variables: + print(indent, v) + for fn in self.Functions: + print(fn) + for bb in fn.Blocks: + print(indent+str(bb)) + for ins in bb.Instructions: + print(indent * 2 + str(ins)) # Analysis functions: def check(self): @@ -70,19 +73,24 @@ class Function: + """ + Function definition. Contains an entry block. + """ def __init__(self, name): self.name = name self.entry = Block('{}_entry'.format(name)) self.epiloog = Block('{}_epilog'.format(name)) + self.epiloog.addInstruction(Terminator()) self.arguments = [] def __repr__(self): - return 'Function {0}'.format(self.name) + args = ','.join(str(a) for a in self.arguments) + return 'Function {}({})'.format(self.name, args) def addBB(self, bb): self.bbs.append(bb) bb.parent = self - addBasicBlock = addBB + addBlock = addBB def removeBasicBlock(self, bb): self.bbs.remove(bb) @@ -110,14 +118,18 @@ return bb raise KeyError(name) - BasicBlocks = property(getBBs) + Blocks = property(getBBs) @property def Entry(self): return self.entry def check(self): - pass + for b in self.Blocks: + b.check() + + def addParameter(self, pname): + self.arguments.append(pname) def call(self, *args): varmap = {} @@ -142,6 +154,7 @@ def addInstruction(self, i): i.parent = self + assert not isinstance(self.LastInstruction, LastStatement) self.instructions.append(i) def replaceInstruction(self, i1, i2): @@ -161,7 +174,8 @@ Instructions = property(getInstructions) def getLastIns(self): - return self.instructions[-1] + if not self.Empty: + return self.instructions[-1] LastInstruction = property(getLastIns) @property @@ -190,6 +204,163 @@ raise NotImplementedError() def check(self): - pass + assert isinstance(self.LastInstruction, LastStatement) + for i in self.instructions[:-1]: + assert not isinstance(i, LastStatement) + + +# Instructions: + +class Expression: + pass + + +class Const(Expression): + def __init__(self, value): + self.value = value + + def __repr__(self): + return 'Constant {}'.format(self.value) + + +# Function calling: +class Call(Expression): + def __init__(self, f, arguments): + self.f = f + assert type(f) is Function + self.arguments = arguments + + def __repr__(self): + args = ','.join([str(arg) for arg in self.arguments]) + return '{}({})'.format(self.f.name, args) + + +# Data operations +class Binop(Expression): + ops = ['+', '-', '*', '/', '|', '&', '<<', '>>'] + def __init__(self, value1, operation, value2): + assert operation in Binop.ops + self.value1 = value1 + self.value2 = value2 + self.operation = operation + + def __repr__(self): + a, b = self.value1, self.value2 + return '({} {} {})'.format(a, self.operation, b) + + +def Add(a, b): + """ Convenience call """ + return Binop(a, '+', b) + + +class Alloc(Expression): + """ Allocates space on the stack """ + def __init__(self): + super().__init__() + + def __repr__(self): + return 'Alloc' + + +class Variable(Expression): + def __init__(self, name): + self.name = name + + def __repr__(self): + return 'Var {}'.format(self.name) + + +class LocalVariable(Variable): + pass + + +class GlobalVariable(Variable): + pass + + +class Parameter(Variable): + def __repr__(self): + return 'Param {}'.format(self.name) +class Temp(Expression): + """ Temporary storage, same as register """ + def __init__(self, name): + self.name = name + + def __repr__(self): + return 'T_{}_'.format(self.name) + + +class Mem(Expression): + def __init__(self, e): + self.e = e + + def __repr__(self): + return '[{}]'.format(self.e) + + +class Statement: + """ Base class for all instructions. """ + pass + + +class Move(Statement): + def __init__(self, dst, src): + self.dst = dst + self.src = src + + def __repr__(self): + return '{} = {}'.format(self.dst, self.src) + + +class Exp(Statement): + def __init__(self, e): + self.e = e + + +class Label(Statement): + def __init__(self, name): + self.name = name + self.statements = [] + + def __repr__(self): + return 'LABEL {}:'.format(self.name) + + +# Branching: +class LastStatement(Statement): + pass + + +class Terminator(LastStatement): + """ Instruction that terminates the terminal block """ + Targets = [] + def __repr__(self): + return 'Terminator' + + +class Jump(LastStatement): + def __init__(self, target): + self.target = target + self.Targets = [target] + + def __repr__(self): + return 'BRANCH {}'.format(self.target.name) + + +class CJump(LastStatement): + def __init__(self, a, cond, b, lab_yes, lab_no): + assert cond in ['==', '<', '>', '>=', '<=', '!='] + self.a = a + self.cond = cond + self.b = b + self.lab_yes = lab_yes + self.lab_no = lab_no + self.Targets = [lab_yes, lab_no] + + def __repr__(self): + return 'IF {} {} {} THEN {} ELSE {}'.format(self.a, self.cond, self.b, self.lab_yes, self.lab_no) + + diff -r 6b3a874edd6e -r ea93e0a7a31e python/irmach.py --- a/python/irmach.py Mon Sep 02 17:40:21 2013 +0200 +++ b/python/irmach.py Wed Sep 04 17:35:06 2013 +0200 @@ -7,9 +7,25 @@ Instructions are selected and scheduled at this stage. """ +class Frame: + """ + Activation record abstraction. This class contains a flattened + function. Instructions are selected and scheduled at this stage. + Frames differ per machine. + """ + def __init__(self, name): + self.name = name + self.instructions = [] + + def __repr__(self): + return 'Frame' + class AbstractInstruction: - """ Absract machine instruction """ + """ + Abstract machine instruction class. This is a very simple + abstraction of machine instructions. + """ def __init__(self, assem, src=(), dst=(), jumps=()): self.assem = assem self.src = tuple(src) @@ -17,6 +33,9 @@ self.jumps = tuple(jumps) def __repr__(self): - return self.assem + str(self.src) + str(self.dst) + s = str(self.src) if self.src else '' + d = str(self.dst) if self.dst else '' + l = str(self.jumps) if self.jumps else '' + return self.assem + s + d + l diff -r 6b3a874edd6e -r ea93e0a7a31e python/tcodegen.py --- a/python/tcodegen.py Mon Sep 02 17:40:21 2013 +0200 +++ b/python/tcodegen.py Wed Sep 04 17:35:06 2013 +0200 @@ -7,6 +7,7 @@ import ppci import codegenarm import outstream +import ir testsrc = """ package test2; @@ -16,7 +17,18 @@ function int insanemath(int a, int b) { var int c; - c = a + b + 1; + c = 0; + var int i; + i = 9; + while (i > 1) + { + c = a + b + 1 + c; + i = i - 1; + if (c > 90) + { + return 42; + } + } return c; } @@ -31,7 +43,7 @@ if (cee + a > b and b - a+b== 3*6-b) { var int x = a; - x = b - a + insanemath(3, 4); + x = b - a + insanemath(3, 4) - insanemath(33,2); a = x * (x + a); } else @@ -46,15 +58,44 @@ if __name__ == '__main__': diag = ppci.DiagnosticsManager() builder = c3.Builder(diag) - ir = builder.build(testsrc) - ir.dump() + irc = builder.build(testsrc) + if not irc: + diag.printErrors(testsrc) + irc.check() + irc.dump() + with open('ir.gv', 'w') as f: + ir.dumpgv(irc, f) outs = outstream.TextOutputStream() cga = codegenarm.ArmCodeGenerator(outs) - cfg_file = open('cfg.gv', 'w') - ig_file = open('ig.gv', 'w') - ir2 = cga.generate(ir, cfg_file=cfg_file, ig_file=ig_file) - cfg_file.close() - ig_file.close() - for i in ir2: - print(i) + ir2 = cga.generate(irc) + + with open('cfg.gv', 'w') as cfg_file: + print('digraph G {', file=cfg_file) + #print('edge [constraint=none]', file=cfg_file) + print('rankdir=TB', file=cfg_file) + for f in cga.frames: + print('subgraph cluster_{} {{'.format(f.name), file=cfg_file) + print('label={};'.format(f.name), file=cfg_file) + print('color=lightgrey;', file=cfg_file) + print('style=filled;', file=cfg_file) + f.cfg.to_dot(cfg_file) + print('}', file=cfg_file) + print('}', file=cfg_file) + with open('ig.gv', 'w') as ig_file: + print('digraph G {', file=ig_file) + print('edge [arrowhead=none]', file=ig_file) + for f in cga.frames: + print('subgraph cluster_{} {{'.format(f.name), file=ig_file) + print('label={};'.format(f.name), file=ig_file) + print('color=lightgrey;', file=ig_file) + print('style=filled;', file=ig_file) + f.ig.to_dot(ig_file) + print('}', file=ig_file) + print('}', file=ig_file) + + for f in ir2: + print(f) + for i in f.instructions: + print(' {}'.format(i)) + diff -r 6b3a874edd6e -r ea93e0a7a31e python/testir.py --- a/python/testir.py Mon Sep 02 17:40:21 2013 +0200 +++ b/python/testir.py Wed Sep 04 17:35:06 2013 +0200 @@ -16,8 +16,10 @@ f = self.b.newFunction('add') self.b.setFunction(f) bb = self.b.newBlock() + self.b.emit(ir.Jump(bb)) self.b.setBlock(bb) self.b.emit(ir.Exp(ir.Const(0))) + self.b.emit(ir.Jump(f.epiloog)) self.m.check() # Run interpreter: # r = self.m.getFunction('add').call(1, 2) @@ -34,11 +36,14 @@ def testBuilder(self): f = self.b.newFunction('test') self.b.setFunction(f) - self.b.setBlock(self.b.newBlock()) + bb = self.b.newBlock() + self.b.emit(ir.Jump(bb)) + self.b.setBlock(bb) v1 = ir.Const(5) v2 = ir.Const(7) v3 = ir.Add(v1, v2) - self.cf.run(self.m) + self.b.emit(ir.Jump(f.epiloog)) + #self.cf.run(self.m) def testAdd0(self): f = self.b.newFunction('test') diff -r 6b3a874edd6e -r ea93e0a7a31e python/transform.py --- a/python/transform.py Mon Sep 02 17:40:21 2013 +0200 +++ b/python/transform.py Wed Sep 04 17:35:06 2013 +0200 @@ -29,7 +29,7 @@ class BasicBlockPass(FunctionPass): def onFunction(self, f): - for bb in f.BasicBlocks: + for bb in f.Blocks: self.onBasicBlock(bb) def onBasicBlock(self, bb): diff -r 6b3a874edd6e -r ea93e0a7a31e python/trunner2.sh --- a/python/trunner2.sh Mon Sep 02 17:40:21 2013 +0200 +++ b/python/trunner2.sh Wed Sep 04 17:35:06 2013 +0200 @@ -5,6 +5,7 @@ python tcodegen.py # Create svg from dot file: + dot -Tpdf -o ir.pdf ir.gv dot -Tpdf -o cfg.pdf cfg.gv dot -Tpdf -o ig.pdf ig.gv echo "Awaiting changes in $DIR"