\documentclass[a4paper]{article}

% lang
\usepackage[utf8]{inputenc}
\usepackage[english]{babel}

% others
\usepackage{hyperref}
\usepackage{color}
\definecolor{freeblue}{rgb}{0.25,0.41,0.88}
\definecolor{thingray}{rgb}{0.9,0.9,0.95}

\usepackage{listings}

\lstset{basicstyle=\ttfamily\small,keywordstyle=\bfseries,stringstyle=\it\color{blue},commentstyle=\color{blue},breaklines=true,language=python,moredelim=[is][\bfseries\color{blue}]{!}{!},
framerule=2mm,framexleftmargin=5mm, frame=leftline, rulecolor=\color{freeblue}, breaklines=true, backgroundcolor=\color{thingray}
}

% For the smileys :-)
\usepackage{wasysym}

\makeatletter

% Test for a TeX4ht command:
\@ifundefined{HCode}{%
  % We are generating PDF, so allow to break down URL which is nicer
  % instead of ugly line overflows:
  \usepackage{breakurl}}{%
  % else we are generating HTML with TeX4ht, use plain url:
  \usepackage{url}}

\usepackage{acronym,xspace}

\usepackage{tikz}

%%%% begin tikz macros for nice icons
\newcommand{\fileicon}{
  \ifx\du\undefined
	\newlength{\du}
  \fi
	\setlength{\du}{0.25em}
\begin{tikzpicture}
\pgftransformxscale{1.000000}
\pgftransformyscale{-1.000000}
\definecolor{dialinecolor}{rgb}{0.000000, 0.000000, 1.000000}
\pgfsetstrokecolor{dialinecolor}
\definecolor{dialinecolor}{rgb}{0.000000, 0.000000, 1.000000}
\pgfsetfillcolor{dialinecolor}
\pgfsetlinewidth{0.100000\du}
\pgfsetdash{}{0pt}
\pgfsetdash{}{0pt}
\pgfsetbuttcap
\pgfsetmiterjoin
\pgfsetlinewidth{0.100000\du}
\pgfsetbuttcap
\pgfsetmiterjoin
\pgfsetdash{}{0pt}
\definecolor{dialinecolor}{rgb}{1.000000, 1.000000, 1.000000}
\pgfsetfillcolor{dialinecolor}
\fill (13.950000\du,3.650000\du)--(15.150000\du,3.650000\du)--(15.550000\du,4.050000\du)--(15.550000\du,5.650000\du)--(13.950000\du,5.650000\du)--cycle;
\definecolor{dialinecolor}{rgb}{0.000000, 0.000000, 1.000000}
\pgfsetstrokecolor{dialinecolor}
\draw (13.950000\du,3.650000\du)--(15.150000\du,3.650000\du)--(15.550000\du,4.050000\du)--(15.550000\du,5.650000\du)--(13.950000\du,5.650000\du)--cycle;
\pgfsetbuttcap
\pgfsetmiterjoin
\pgfsetdash{}{0pt}
\definecolor{dialinecolor}{rgb}{0.000000, 0.000000, 1.000000}
\pgfsetstrokecolor{dialinecolor}
\draw (15.150000\du,3.650000\du)--(15.150000\du,4.050000\du)--(15.550000\du,4.050000\du)--(15.550000\du,4.050000\du);
\end{tikzpicture}
}
\newcommand{\diricon}{
\ifx\du\undefined
  \newlength{\du}
\fi
\setlength{\du}{0.25em}
\begin{tikzpicture}
\pgftransformxscale{1.000000}
\pgftransformyscale{-1.000000}
\definecolor{dialinecolor}{rgb}{0.000000, 0.000000, 1.000000}
\pgfsetstrokecolor{dialinecolor}
\definecolor{dialinecolor}{rgb}{1.000000, 1.000000, 1.000000}
\pgfsetfillcolor{dialinecolor}
\pgfsetlinewidth{0.100000\du}
\pgfsetdash{}{0pt}
\pgfsetdash{}{0pt}
\pgfsetbuttcap
\pgfsetmiterjoin
\pgfsetlinewidth{0.100000\du}
\pgfsetbuttcap
\pgfsetmiterjoin
\pgfsetdash{}{0pt}
\definecolor{dialinecolor}{rgb}{0.901961, 0.901961, 0.901961}
\pgfsetfillcolor{dialinecolor}
\pgfpathmoveto{\pgfpoint{12.850000\du}{5.751777\du}}
\pgfpathcurveto{\pgfpoint{12.850000\du}{5.350000\du}}{\pgfpoint{12.850000\du}{5.350000\du}}{\pgfpoint{13.100000\du}{5.350000\du}}
\pgfpathcurveto{\pgfpoint{13.350000\du}{5.350000\du}}{\pgfpoint{13.350000\du}{5.350000\du}}{\pgfpoint{13.600000\du}{5.350000\du}}
\pgfpathcurveto{\pgfpoint{13.850000\du}{5.350000\du}}{\pgfpoint{13.850000\du}{5.350000\du}}{\pgfpoint{13.850000\du}{5.751777\du}}
\pgfpathcurveto{\pgfpoint{13.850000\du}{5.751777\du}}{\pgfpoint{14.600000\du}{5.751777\du}}{\pgfpoint{14.600000\du}{5.751777\du}}
\pgfpathcurveto{\pgfpoint{14.600000\du}{5.751777\du}}{\pgfpoint{14.600000\du}{7.358884\du}}{\pgfpoint{14.600000\du}{7.358884\du}}
\pgfpathcurveto{\pgfpoint{14.600000\du}{7.358884\du}}{\pgfpoint{12.850000\du}{7.358884\du}}{\pgfpoint{12.850000\du}{7.358884\du}}
\pgfpathcurveto{\pgfpoint{12.850000\du}{7.358884\du}}{\pgfpoint{12.850000\du}{6.153554\du}}{\pgfpoint{12.850000\du}{5.751777\du}}
\pgfusepath{fill}
\definecolor{dialinecolor}{rgb}{0.000000, 0.000000, 1.000000}
\pgfsetstrokecolor{dialinecolor}
\pgfpathmoveto{\pgfpoint{12.850000\du}{5.751777\du}}
\pgfpathcurveto{\pgfpoint{12.850000\du}{5.350000\du}}{\pgfpoint{12.850000\du}{5.350000\du}}{\pgfpoint{13.100000\du}{5.350000\du}}
\pgfpathcurveto{\pgfpoint{13.350000\du}{5.350000\du}}{\pgfpoint{13.350000\du}{5.350000\du}}{\pgfpoint{13.600000\du}{5.350000\du}}
\pgfpathcurveto{\pgfpoint{13.850000\du}{5.350000\du}}{\pgfpoint{13.850000\du}{5.350000\du}}{\pgfpoint{13.850000\du}{5.751777\du}}
\pgfpathcurveto{\pgfpoint{13.850000\du}{5.751777\du}}{\pgfpoint{14.600000\du}{5.751777\du}}{\pgfpoint{14.600000\du}{5.751777\du}}
\pgfpathcurveto{\pgfpoint{14.600000\du}{5.751777\du}}{\pgfpoint{14.600000\du}{7.358884\du}}{\pgfpoint{14.600000\du}{7.358884\du}}
\pgfpathcurveto{\pgfpoint{14.600000\du}{7.358884\du}}{\pgfpoint{12.850000\du}{7.358884\du}}{\pgfpoint{12.850000\du}{7.358884\du}}
\pgfpathcurveto{\pgfpoint{12.850000\du}{7.358884\du}}{\pgfpoint{12.850000\du}{6.153554\du}}{\pgfpoint{12.850000\du}{5.751777\du}}
\pgfusepath{stroke}
\pgfsetlinewidth{0.010000\du}
\pgfsetbuttcap
\pgfsetmiterjoin
\pgfsetdash{}{0pt}
\definecolor{dialinecolor}{rgb}{0.000000, 0.000000, 1.000000}
\pgfsetstrokecolor{dialinecolor}
\pgfpathmoveto{\pgfpoint{12.850000\du}{5.751777\du}}
\pgfpathcurveto{\pgfpoint{12.850000\du}{5.350000\du}}{\pgfpoint{12.850000\du}{5.350000\du}}{\pgfpoint{13.100000\du}{5.350000\du}}
\pgfpathcurveto{\pgfpoint{13.350000\du}{5.350000\du}}{\pgfpoint{13.350000\du}{5.350000\du}}{\pgfpoint{13.600000\du}{5.350000\du}}
\pgfpathcurveto{\pgfpoint{13.850000\du}{5.350000\du}}{\pgfpoint{13.850000\du}{5.350000\du}}{\pgfpoint{13.850000\du}{5.751777\du}}
\pgfpathcurveto{\pgfpoint{13.850000\du}{5.751777\du}}{\pgfpoint{14.600000\du}{5.751777\du}}{\pgfpoint{14.600000\du}{5.751777\du}}
\pgfpathcurveto{\pgfpoint{14.600000\du}{5.751777\du}}{\pgfpoint{14.600000\du}{7.358884\du}}{\pgfpoint{14.600000\du}{7.358884\du}}
\pgfpathcurveto{\pgfpoint{14.600000\du}{7.358884\du}}{\pgfpoint{12.850000\du}{7.358884\du}}{\pgfpoint{12.850000\du}{7.358884\du}}
\pgfpathcurveto{\pgfpoint{12.850000\du}{7.358884\du}}{\pgfpoint{12.850000\du}{6.153554\du}}{\pgfpoint{12.850000\du}{5.751777\du}}
\pgfusepath{stroke}
\pgfsetlinewidth{0.100000\du}
\pgfsetbuttcap
\pgfsetmiterjoin
\pgfsetdash{}{0pt}
\definecolor{dialinecolor}{rgb}{1.000000, 1.000000, 1.000000}
\pgfsetfillcolor{dialinecolor}
\fill (12.850000\du,7.358884\du)--(12.600000\du,5.952665\du)--(14.350000\du,5.952665\du)--(14.600000\du,7.358884\du)--cycle;
\definecolor{dialinecolor}{rgb}{0.000000, 0.000000, 1.000000}
\pgfsetstrokecolor{dialinecolor}
\draw (12.850000\du,7.358884\du)--(12.600000\du,5.952665\du)--(14.350000\du,5.952665\du)--(14.600000\du,7.358884\du)--cycle;
\pgfsetlinewidth{0.010000\du}
\pgfsetbuttcap
\pgfsetmiterjoin
\pgfsetdash{}{0pt}
\definecolor{dialinecolor}{rgb}{0.000000, 0.000000, 1.000000}
\pgfsetstrokecolor{dialinecolor}
\draw (12.850000\du,7.358884\du)--(12.600000\du,5.952665\du)--(14.350000\du,5.952665\du)--(14.600000\du,7.358884\du)--cycle;
% setfont left to latex
\definecolor{dialinecolor}{rgb}{0.000000, 0.000000, 1.000000}
\pgfsetstrokecolor{dialinecolor}
\node[anchor=west] at (13.600000\du,6.454886\du){};
\end{tikzpicture}
}

\newcommand{\PIPS}{\textbf{\texttt{PIPS}}}
\newcommand{\PYPS}{\textbf{\texttt{PyPs}}}
\newcommand{\autoconf}{\texttt{autoconf}}
\newcommand{\file}[1]{\fileicon{}\texttt{#1}}
\newcommand{\cmd}[1]{\textbf{`}\texttt{#1}\textbf{`}}
\newcommand{\dir}[1]{\diricon\texttt{#1}}

 
\title{A tutorial for \PYPS}
\author{Grégoire Payen de La Garanderie \and Serge Guelton}

\begin{document}

\maketitle

\section{Introduction}
\PYPS{} is a Python interface to \PIPS{} source-to-source compiler.
It is in fact a Python API to write your own pass manager and
quickly build a new compiler.
The focus of \PYPS{} is to provide an interface for both high-level scripts for transformation automation
and for interactive use of \PIPS{} with auto-completion and inline documentation of \PIPS{} transformations.
\PYPS{} provides the \cmd{ipyps} interpreter based on ipython interpreter shell which have a reacher feature set than \cmd{tpips}.
Simple scripting with \PYPS{} doesn't require a strong knowledge of Python language and allows to deal with \PIPS{} in a more structured and intuitive way than \cmd{tpips}.

\PYPS{} can only be built using auto-pips, and needs the \texttt{--enable-pyps} flag in the \cmd{configure} script.

\section{Running Example}

This tutorial will show the functionality of \PYPS{} using the C code
that can be retrieved  from the subversion repository:
\begin{lstlisting}[language=sh]
wget http://svn.cri.ensmp.fr/svn/validation/trunk/Pyps/silber.c
\end{lstlisting}

\section{First steps with \PYPS{}}

There is two ways to work with \PYPS{}, either importing pyps package in Python or using the interactive Pyps environnement based on iPython : iPyps (running command \cmd{ipyps}).
The last method should be preferred for interactive use of Pyps.

\begin{lstlisting}
from pyps import !workspace!, !module! #iPyps takes care of this for you
\end{lstlisting}

To begin, you should create a new \PIPS{} workspace. \PIPS{} workspace are represented by Python's \emph{workspace} class.
To create a new workspace, you need the list of all source files that you want to handle.
Note that you can't add source file to the project after its creation.
In this example, we have only the [[silber.c]] source file.

\begin{lstlisting}
ws = workspace("silber.c")
# If you have more than one source file, you should use something like :
# ws = workspace("somesource.c","someothersource.c","lastsource.c")
\end{lstlisting}

Running this, \PIPS{} parses files, functions and procedures.
You can disable the verbose output using \lstinline{verbose=False} as an extra parameter.
Each functions and source files are represented in Python by an object of type \emph{module} :

\begin{lstlisting}
t=ws.fun.transfo #Retrieve function transfo and bind it to variable t
m=ws.fun.main #Retrieve function main
g=ws.cu.silber #Retrieve compilation unit silber.c
\end{lstlisting}

For iPyps users, completion function and source name completion is available using TAB key after typing \lstinline|ws.fun.| and \lstinline|ws.cu.|

You can print function information and documentation extracted from \LaTeX\  source file \file{properties\_rc.tex} by using ‘?’ :
\begin{lstlisting}
ws.fun.transfo.inlining? #Print documentation
\end{lstlisting}

This should output something like :
\begin{lstlisting}
Type:		instancemethod
Base Class:	<type 'instancemethod'>
String Form:	<bound method module.inlining of <pyps.module instance at 0x9e0718c>>
Namespace:	Interactive
File:		/usr/lib/python2.6/site-packages/pips/pyps.py
Definition:	ws.fun.foo.inlining(self, callers='', use_initialization_list=True, **props)
Docstring:
    Inlining is a well known technique.  Basically, it replaces a function call by the function body. The current implementation does not work if the function has static declarations, access global variables  can be set to define the list of functions where the call sites have to be inlined. By default, all call sites of the inlined function are inlined.
\end{lstlisting}

In this brouhaha, the more relevant informations are \emph{Definition} and \emph{Docstring}. Looking at the definition of the function, we know that it takes two arguments. Each argument have a default value, so you can skip a parameter if you are pleased with the default value. For instance :
\begin{lstlisting}
ws.fun.copy.inlining(callers="transfo")
#The call is threated as if USE_INITIALIZATION_LIST is set to True 
#because of the default value
\end{lstlisting}

Value of properties are automatically restored after transformation call to their orignal state to avoid side effects onto other transformation, whereas in tpips properties are set at global scope and can interact with transformations sometimes by mistake.

Sometimes, dependency between transformations and properties are not dectected because of missing or implicit relation in \file{properties-rc.tex}.
It is still possible to pass a property as parameter even if Pyps don't know about the relation :
\begin{lstlisting}
ws.fun.light.inlining(callers="transfo", purge_labels=False);
\end{lstlisting}

As you can see, we add an extra property purge\_labels which is not listed in Python inlining function prototype. Furthermore, the real Pips name of the property is \texttt{INLINING\_PURGE\_LABELS}. \PYPS{} automatically append transformation’s name at the begining of a property when needed and also automatically convert property name to upper case.

Sometimes, you need to specify which transformations should be used by Pips to get some ressources. This is accomplish by doing the following in \PYPS{} :
\begin{lstlisting}
ws.activate(module.preconditions_inter_fast) #To activate transformation preconditions_inter_fast
#or alternatively
ws.activate("preconditions_inter_fast")
\end{lstlisting}

The advantage of the first form over the second is that you can use auto-completion over transformation name.

\section{Looping, filtering and transforming a bench of module}

It is possible to loop on every module. For instance :
\begin{lstlisting}
for i in ws.fun:
	i.display()
\end{lstlisting}

The former is equivalent to :
\begin{lstlisting}
ws.all.display()
\end{lstlisting}

\lstinline|ws.all| returns an object of type \emph{modules}.
\emph{modules} objects have the same interface as \emph{module}:
when a function from a \emph{modules} object is called, it calls the same function of every listed module.

It is also possible to find modules using a filter :
\begin{lstlisting}
#Print all functions which call function ``transfo''.
m = ws.filter(lambda x: ws.fun.transfo in x.callees)
m.display()
\end{lstlisting}

The former is equivalent to using the \lstinline|callers| attribute:
\begin{lstlisting}
m = ws.fun.transfo.callers
\end{lstlisting}

\section{Loop transformations}

Transformations can also be made on loops.
In this example, we have a loop in \emph{curve} function.
You can access to a loop either by iterating over each loop with something like :

\begin{lstlisting}
for l in ws.fun.curve.loops():
	print "Loop labeld ",l.label , "from module", l.module #Do something in the loop
\end{lstlisting}

or by label, if you know it :

\begin{lstlisting}
l = ws.fun.curve.loops("l99999")
#Do something with loop l
\end{lstlisting}

When manipulating code for the first time, Pips has not yet assigned labels to loops because Pips delayed it until labels are required (eg. by a transformation). You can ask Pips to insert loop labels in code by using method \emph{flag\_loops} :

\begin{lstlisting}
m.display()
#There is no loop label
m.flag_loops()
m.display()
#You can see loop label and do something with them
l = m.loops("l99999")
l.unroll(rate=3) #Call Unroll transformation
\end{lstlisting}

\section{Global properties}

\PIPS{} properties can be accessed and modified at global scope using \lstinline|ws.props.|.
For instance, you can get or set property \texttt{INLINING\_PURGE\_LABELS} using :

\begin{lstlisting}
print ws.props.INLINING_PURGE_LABELS #Print it
ws.props.INLINING_PURGE_LABELS = False
ws.props.INLINING_PURGE_LABELS = True
\end{lstlisting}

If a property is redefined in a method, the global value is pushed on a stock and restored after the method call.

\section{Checkpoints}

\PYPS{} provides a basic feature for checkpoints.
They can be used to save and then restore back \PYPS{} state when trying to do a potentially wrong transformation. 
Checkpointing returns a handle that must be used to restore the previous workspace.

\begin{lstlisting}
a=ws.checkpoint()
l.unroll(rate=3) #Call Unroll transformation
ws.fun.main.display()
ws.restore(a)
ws.fun.main.display()
\end{lstlisting}

\section{Pyrops}
It is not possible to work on several workspaces in Pips at the same time in a script.
To bypass this limitation in Pyps, a Python module named Pyrops transparently encapsulate each workspace in a separate program.
It’s more an elegant workaround than a true solution however it works well despite it is complicated to debug Pips C libraries through this extension.
Pyrops provides a new workspace inherited of Pyps workspace :

\begin{lstlisting}
from pyrops import pworkspace
ws = pworkspace("test.c")
\end{lstlisting}

Here, ws is a remote workspace. You can add a second workspace :
\begin{lstlisting}
ws2 = pworkspace("test.c")
\end{lstlisting}

After creation, you can apply transformations to your remotes workspaces as if they were true Pyps workspace.
\begin{lstlisting}
ws.all.display()
#...
\end{lstlisting}

To close a workspace, you can do :
\begin{lstlisting}
ws.close()
\end{lstlisting}

And just before to terminate the program :
\begin{lstlisting}
pyrops.Launcher.shutdown()
\end{lstlisting}

Sometimes, some errors occured in Python internals during Python exit. They are not harmeful nor important.

\section{pips-make}
When having a large project with many GCC options, it can be difficult to create a Pyps workspace. pips-make is a tool which try to create a workspace for you by instrumenting the compilation process.

For instance, if you have a project which use a classic compilation process. You can do :

\begin{lstlisting}
./configure
pips-make
make install
\end{lstlisting}

Here, the pips-make step do the same thing as make but records also useful informations about the project and put them in a new directory \emph{pips.ws}.
If your project doesn't use a Makefile, you can use commande \emph{pips-make --env} to open a new shell where GCC calls are recorded. To do the trick, pips-make change PATH variable in such way that calls to GCC are intercepted by pips-make version of them instead of the original. After processing, pips-make forward calls to GCC.

pips-make use the following environnement variables :
\begin{enumerate}
  \item PIPS\_WORKSPACE : where to put files (default: directory pips.ws) ;
  \item PIPS\_WORKINGDIR : base directory used to construct files relative path (default: .) ;
  \item PIPS\_BINPATH : path to pips-make binaries (default: installation dependant hard-coded in pips-make prefix/lib/pips-make) ;
  \item PIPS\_CC : compiler which should be called by pips-make (default: gcc) ;
  \item PIPS\_LD : linker which should be called by pips-make (default: \$PIPS\_CC) ;
  \item PIPS\_AR : archiver which should be called by pips-make (default: ar).
\end{enumerate}

Currently, pips-make registers calls to the compiler, the linker and ar.
After this preprocessing step, you can import your new workspace using the Python class \emph{CCWorkspace} which have the same behaviour as \emph{workspace}.
\begin{lstlisting}
from pipsgcc import CCWorkspace
import pyps

w = workspace("pips.ws", parents = [CCWorkspace]) \footnote{+\nomgen{see section \ref{wpcomposition} for more information on this workspace instanciation syntax}+}

ws.all.display() #Display it
ws.compile() #Replay compilation
\end{lstlisting}

pips-make try to record the whole compilation process of the Makefile. Library makefiles often recompile source files more than once with differents flags, for instance to build static and shared library versions. pips-make store preprocessed versions of the files to avoid dependancy problems or so. When a file is compiled twice or more, pips-make stores the file preprocessed with the last set of flags and emits a warning if preprocessed files are differents. An other problem is that sometimes examples are compiled by the Makefile, this result in having more than once \emph{main} function which of course Pyps dislike. When using Pyps, be sure to deactivate example compilation in the build configuration, otherwise you may encountered problems.

\section{Workspace composition} \label{wpcomposition}
Pyps is a quite simple interface for Pips usage, furthermore, it is extensible and allow you to develop high level task onto Pips.

Of note is the worksapce `parents' attribute, which allows to define advices
before, around and after the initial functions.

In order to use this, create a workspace, for instance:

\begin{lstlisting}
# File foo.py
class workspace:
	# No need to inherit
	def __init__(self, ws, sources, **kwargs):
		# Given the same arguments as pyps.workspace, plus the workspace
		# itself as the first argument
		pass # nothing to do, maybe `self.ws = ws' to save the `real'
			 # workspace if necessary.

	def pre_bar(self, arg...):
		# Same arguments as pyps.workspace.bar()
		print "foo.pre_bar: running just before pyps.workspace.bar()"
\end{lstlisting}

The users will need to `import foo', and create their workspace as \lstinline|ws = pyps.workspace(sources, parents = [foo.workspace])|.

With a `pre\_' suffix, the function will be called before the function of
the same name; with a `post\_', it will be run after. Without a prefix,
it will entirely replace the initial function. In other words, defining
pre\_bar is similar to saying in emacs:
\begin{lstlisting}
(defadvice foo-pre-bar (before bar (arg...) (progn ...)))
(ad-activate foo-pre-bar)
\end{lstlisting}

Defining \lstinline|foo.workspace.baz()| when \lstinline|pyps.workspace.baz()| already exists
will \emph{replace} \lstinline|pyps.workspace.baz()| (of course, foo's version of baz()
may call the initial one.

If the workspace is created as: \lstinline|ws = pyps.workspace(..., parents = [foo, bar])|, a call to ws.quux will call:

\begin{enumerate}
\item foo.pre\_quux
\item bar.pre\_quux
\item foo.quux
\item at foo.quux' discretion, bar.quux
\item at bar.quux's discretion, pyps.workspace.quux
\item bar.post\_quux
\item foo.post\_quux
\end{enumerate}

This is not an error if any (or even all) intermediate functions don't
exist.


\end{document}
