144 lines
5.3 KiB
Plaintext
144 lines
5.3 KiB
Plaintext
%if false
|
|
Copyright (c) 2009, ETH Zurich.
|
|
All rights reserved.
|
|
|
|
This file is distributed under the terms in the attached LICENSE file.
|
|
If you do not find this file, copies can be found by writing to:
|
|
ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
|
|
%endif
|
|
|
|
%include polycode.fmt
|
|
|
|
%if false
|
|
|
|
> module IL.Paka.Syntax where
|
|
|
|
> import Text.PrettyPrint.HughesPJ
|
|
> import qualified Data.Map as Map
|
|
|
|
> import PureExpressions
|
|
|
|
%endif
|
|
|
|
\section{The Paka Intermediate Language}
|
|
\label{sec:il_paka_syntax}
|
|
|
|
The purpose of Paka is to ease the task of tracking down unnecessary
|
|
variable assignment in the to-be-generated C code. Therefore, its
|
|
syntax is extremely close to C and focused on intra-procedural
|
|
statements. This is reflected by the definition of |PakaCode|: the
|
|
structure of the C file is almost here, with includes, type
|
|
definitions and prototypes, function prototypes, and function
|
|
definitions, in this order.
|
|
|
|
Note that they are all defined by a |Map| or associative list from
|
|
|String| to something else. The |String| plays the role of an
|
|
identifier which should be compiled only once in the C
|
|
code. Typically, a type definition should appear only once, otherwise
|
|
the C compiler will complain. |Map| is used when the definition order
|
|
is not important, associative list is used when we want to keep it
|
|
(when a declaration might be defined in term of another
|
|
declaration defined earlier).
|
|
|
|
> data PakaCode
|
|
> = PakaCode { includes :: Map.Map String Doc,
|
|
> types :: Map.Map String Doc,
|
|
> declarations :: [(String, Doc)],
|
|
> prototypes :: Map.Map String Doc,
|
|
> globalVars :: [(String, Doc)],
|
|
> functions :: Map.Map String (Doc, Doc, String, Doc, PakaIntra, ILPaka) }
|
|
>
|
|
> emptyCode = PakaCode { includes = Map.empty,
|
|
> types = Map.empty,
|
|
> declarations = [],
|
|
> prototypes = Map.empty,
|
|
> globalVars = [],
|
|
> functions = Map.empty }
|
|
|
|
Each function is defined by a |PakaIntra| record, which stands for
|
|
\emph{intra-procedural}. In there, we find local variable definitions
|
|
and, potentially, a constant. This constant is used to carry the
|
|
result of a side-effecting test: the side-effecting is compiled before
|
|
the test-handler and the constant is tested instead.
|
|
|
|
> data PakaIntra
|
|
> = PakaIntra { localVars :: Map.Map String Doc,
|
|
> expr :: (Maybe PureExpr)}
|
|
> deriving Show
|
|
>
|
|
> emptyIntra = PakaIntra { localVars = Map.empty,
|
|
> expr = Nothing }
|
|
|
|
As part of the definition of functions, we find the body of the
|
|
function. This is presented as an |ILPaka| data-type. This is a
|
|
strip-down version of the |FoF| IL: we have kept most of the
|
|
control-flow structures (at the exception of the @for@ loop,
|
|
translated into @while@ loops) and statements. Because we are
|
|
describing intra-procedural code, we have removed the function
|
|
definition construct.
|
|
|
|
> data ILPaka
|
|
> = PVoid
|
|
> | PClosing PakaClosing
|
|
> | PStatement PakaStatement ILPaka
|
|
> | PIf ILPaka PureExpr ILPaka ILPaka ILPaka
|
|
> | PWhile ILPaka PureExpr ILPaka ILPaka
|
|
> | PDoWhile ILPaka ILPaka PureExpr ILPaka
|
|
> | PSwitch PureExpr [(PureExpr, ILPaka)] ILPaka ILPaka
|
|
|
|
However, the major specificity of Paka is its definition of a
|
|
statement: a statement is either an assigment or an instruction. An
|
|
assignment |PAssign x t ys| is a term |t| in which the variable |x| is
|
|
assigned a value computed from the variables |ys|. On the other hand,
|
|
an instruction |PInstruction t ys| is a side-effecting operation |t|
|
|
making use of the variables |ys|.
|
|
|
|
In a nutshell, when chasing redundant assignments, we will track down
|
|
raw assignment |PAssign x t [y]|, remove the assignment, and replace
|
|
all use of |x| by |y|.
|
|
|
|
> data PakaStatement
|
|
> = PAssign PakaVarName Term [PakaVarName]
|
|
> | PInstruction Term [PakaVarName]
|
|
|
|
A |Term| is an almost valid C statement, with holes in it. The holes
|
|
correspond to the variable names: provided with the list of variable
|
|
names, it computes a C statement.
|
|
|
|
Hence, when we have settled the input and output variables of a
|
|
|PAssign x t ys|, we obtain the corresponding C statement by applying
|
|
|t x:xs|. Similarly, we get the C code from an instruction
|
|
|PInstruction t ys| by computing |t ys|.
|
|
|
|
> type Term = [Doc] -> Doc
|
|
|
|
However, things are not that simple. First, we need more information
|
|
about the variable: are they raw C variables, or pointers, or
|
|
dereferenced from somewhere else? This information is vital to avoid
|
|
aliasing issues.
|
|
|
|
Similarly, when a variable |y| is used in some operationally
|
|
non-trivial term |t|, we cannot simply replace |x| by |y|: we would
|
|
have to compute some sort of |t y| to be correct. Although it would be
|
|
doable, we do not support that at the moment and tag the variable name
|
|
as |Complex|, meaning ``non prone to simplification''.
|
|
|
|
Finally, constants are a gold opportunity we don't want to miss, hence
|
|
we explicitly carry the value instead of variable name. Therefore, we
|
|
are able to do some naive constant propagation for free.
|
|
|
|
> data PakaVarName
|
|
> = Var String
|
|
> | Ptr PakaVarName
|
|
> | Deref PakaVarName
|
|
> | Complex PakaVarName
|
|
> | K PureExpr
|
|
> deriving (Show, Eq)
|
|
|
|
|
|
> data PakaClosing
|
|
> = PReturn PureExpr
|
|
> | PBreak
|
|
> | PContinue
|
|
> deriving Show
|