Fix misc style and spelling errors.
[matthijs/projects/internship.git] / Report / Main / Problems / Challenges.tex
index 39806fae30510fa7f35b4f5904c97cdcf14c37d3..1fccb19c67e23c98f22ceacbd8d6f1e66c6ed673 100644 (file)
@@ -12,12 +12,12 @@ was ``whatever the compiler eats''.
 To be able to create a proper set of transformations, the constraints on the
 input and output of that transformation process should be properly specified.
 This entails two parts: Specifying the MontiumC language, and specifying the
-Montium IR constraints, which is is the input to the backend.
+Montium IR constraints, which is the input to the backend.
 
 Specifying Montium IR was relatively easy, since it is defined directly by the
-backend. The MontiumC specification is slightly more complex. There are two
+backend. The MontiumC specification was slightly more complex. There are two
 different angles to it: What does the compiler support, and what do we want the
-compiler to support.
+compiler to support?
 
 \subsubsection{What is supported?}
 One angle for looking at MontiumC is seeing what the compiler can currently
@@ -33,13 +33,14 @@ makes use of corner cases in the compiler that have been missed in (or left out
 of) the specification, because they will not work reliably in all cases.
 
 The best way to detect these cases is making the compiler check its input using
-an the specification. This way, any code operating outside of the specification
-can be detected automatically. Writing such checks has not happened yet, mainly
+the specification. This way, any code operating outside of the specification
+can be detected automatically. Writing such checks has not happened so far, mainly
 because the impact of the new hardware on MontiumC is not quite clear yet.
 
 Existing transformations, on the other hand, might miss a few corner cases. When
 writing the specification, a particular feature might appear supported by the
-compiler. On closer inspection, the transformation passes might miss some corner
+compiler. On closer inspection, the transformation passes might not do
+the right thing when faced with particular corner
 cases, which either need to be fixed or put into the specification.
 
 The best way to detect these cases is writing a lot of structured testing code,
@@ -48,8 +49,8 @@ specification. This way, corner cases exposed by the testing code can be
 detected automatically. A framework for this testing has been set up and
 partially filled with small tests.
 
-Building this initial specification did pose a number of challenges. Since
-simply trying all possible C features to see if they are accepted by the
+Building this initial specification did pose a number of challenges.
+Simply trying all possible C features to see if they are accepted by the
 MontiumC compiler and thus valid MontiumC is a lengthy process and only useful
 in a limited way. A more constructive way would be to examine the compiler
 components to see what transformations are applied and from that derive the
@@ -64,10 +65,11 @@ Another problem is the complexity of the C language. Although individual
 features can be described and supported with relative ease, combining features
 can easily lead to complex constructs which are hard to transform into supported
 Montium IR. This became more of an issue after adding features to the base
-specification of MontiumC, though.
+specification of MontiumC, since the base specification only supports a
+few C features.
 
 \subsubsection{What is wanted?}
-A completely different angle of looking at this, is from the requirements point
+A completely different angle of looking at this specification is from the requirements point
 of view. What do we want MontiumC to support? This angle is even harder than the
 previous one, since there are a lot of levels of requirements. Ideally, MontiumC
 would not exist and our compiler would support the C language fully. However,
@@ -81,22 +83,105 @@ anything is mappable, but with a simple compiler this will not result in the
 most efficient code. In the Montium case, a lot of things simply cannot be
 mapped on the hardware at all.
 
-Considering that our ideal is not reachable (by far), every feature in our
-wanted MontiumC should be evaluated thoroughly for feasibility, both in hardware
+Considering that our ideal is not reachable (though the new hardware might take
+us a lot closer), every feature
+considered for MontiumC was evaluated thoroughly for feasibility, both in hardware
 and in the compiler. In practice, this meant that new language features would be
 informally expressed and discussed, and only added to the specification after
 being succesfully implemented. This is conforming to the incremental development
 of MontiumC that was envisioned at the outset of its development.
 
+To get a feeling for what MontiumC looks like, consider the fragment in
+figure \ref{ExampleLow}. This is a piece of code that reads values from
+one memory, multiplies them by two, and writes them back to another
+memory. As you can see, this is an awful lot of code. This has two main
+reasons. First, looping and memory indexing is very explicit and takes a
+lot of instructions. Second, the code is effectively software pipelined
+to make it run more efficiently.
+
+In figure \ref{ExampleHigh} the same code is displayed, but this time
+using higer level C features (for loops, array indexing). This is the
+level of code we are trying to achieve, but we're not there yet. It
+should be noted that this is still not "normal" C, since we use the
+"imul" function instead of the normal * operator. However, since the
+Montium defines a lot of different operations, most of which have a
+number of options (saturation, truncation, post shifting, etc.) these
+cannot all be mapped onto normal C operators. By using a specific
+function call for each, we can still distinguish between all the
+different operations and add extra arguments where needed.
+
+\subsubsection{What do we have now?}
+The result of this work is a usable, but conservative, specification. It
+defines the subset of features that should certainly be supported. In practice,
+some other features will also work, but not reliably. Therefore, these are left
+out of the specification.
+
+It is not unlikely that the specification is still incorrect in a few places (or
+rather, that the code does not implement the specification properly). Since
+so far there has not been any automated checking of programs against the
+specification, these errors have not been uncovered. Once the new hardware is
+more clearly defined and the MontiumC specification is updated for it, this
+checking should be added so the specification and compiler can be better
+matched.
+
+\begin{figure}
+       \caption{Low level MontiumC example}
+\label{ExampleLow}
+\begin{verbatim}
+mem input;
+mem output;
+word factor;
+
+void run(void) {
+  factor = from_int(2);
+  input  = alloc_mem(P0M0);
+  output = alloc_mem(P0M1);
+  set_base(input, 0);
+  set_offset(input, 0);
+  set_base(output, -1);
+  set_offset(output, -1);
+
+  next_cycle();
+  word in = read_mem(input);
+  word out = p0o0(imul(ra1(in), rc1(factor)))
+  add_offset(input, 1);
+  add_offset(output, 1);
+  init_loop(LC1, 8);
+  do {
+    write_mem(output, out);
+    in = read_mem(input);
+    out = p0m0(imul(ra1(in), rc1(factor)))
+    add_offset(input, 1);
+    add_offset(output, 1);
+  } while(loop_next(LC1));
+
+  write_mem(output, out);
+\end{verbatim}
+\end{figure}
+
+\begin{figure}
+       \caption{High level MontiumC example}
+       \label{ExampleHigh}
+\begin{verbatim}
+P0M0 int input[10];
+P0M1 int output[10];
+
+void run(void) {
+  for (int i=0; i<10; ++i)
+    output[i] = mul(input[i], 2);
+}
+\end{verbatim}
+\end{figure}
+
 \subsection{Familiarizing with LLVM}
 Since the frontend heavily relies on the LLVM project for doing it's work, one
-of the first challenges was to get myself familiar with LLVM. There are two main
+of the first challenges was to get myself familiar with LLVM. There were two main
 aspects to this: Getting to know my way around the LLVM codebase and getting to
 know the LLVM community.
 
-Since LLVM has a pretty large amount of documentation, I spent most of my first
+LLVM has a pretty large amount of documentation, I spent most of my first
 weeks with reading tutorials and documents. Since there was already a (very
-preliminary) version of the clang-based frontend, I also had some code to play
+preliminary) version of the Clang-based frontend, I also had some code to play
 with.
 
 During this period, it was not completely clear what the frontend should
@@ -106,24 +191,26 @@ written, but I can't really tell what's needed until I know how the code works,
 which I can't effectively learn without actively working with it, etc.) I
 started out with adapting the loop unrolling pass in LLVM to be better suited to
 the Montium architecture. Eventually, this code didn't turn out to be
-immediately useful (it's still not included currently), but it proved very
-insightful as to how the LLVM framework is built and what its possibilities are.
+immediately useful because deciding when to unroll a loop and when not to turned
+out rather hard (it's still not included currently). Working with this pass did
+prove very insightful, however, as to how the LLVM framework is built and what its
+possibilities are.
 
-Additionally, during my working with the code in this internship I also produced
+Additionally, during my working with the code during this internship I also produced
 a number of patches for LLVM, containing bugfixes, some cleanup and
 documentation improvements. Since the best way to integrate with any open source
-project seems to be contributing code, I was giving commit access to the LLVM
+project seems to be contributing code, I was given commit access to the LLVM
 tree not long thereafter. This access has proved very useful during the rest of
 the internship, since it was now a a lot easier to make (simple) changes to the
 LLVM framework to better suit the needs of Recore.
 
 A major challenge during my internship was to find the balance between doing
 work specifically for Recore, and doing work that is useful for LLVM in general.
-Any tasks that are required by the Montium frontend and the LLVM changes they
-directly need are obvious. However, usually when making changes to the main LLVM
-code, just changing enough for Recore is not engough for LLVM. Since the LLVM
+Any changes that are directly required by the Montium frontend and the LLVM changes they
+need are obvious. However, usually when making changes to the main LLVM
+tree, just changing enough for Recore is not engough for LLVM. Since the LLVM
 code must work on any program, not just MontiumC programs, extra changes are
-required (see also parapgrah \ref{StayingGeneric}. This is also an issue of
+required (see also parapgrah \ref{StayingGeneric}). Additionally, this is an issue of
 building up credit within the LLVM community: The more you contribute to LLVM,
 the more influence you have when things need changing. 
 
@@ -134,11 +221,6 @@ interfere with the MontiumC frontend. In the end, I think I managed to find a
 decent balance, though it might have been tipped slighly in favour of the LLVM
 project.
 
-\subsection{Coding}
-This section says something about the challenges encountered while actually
-writing code, if I can think of enough things to say here. So far, haven't
-thought of anything particularly interesting yet.
-
 \subsection{Working together}
 Since the compiler plays a fairly central role in the development process at
 Recore, I have been cooperating with a number of different people, in different
@@ -149,24 +231,24 @@ often providing bug reports and other feedback, which ensures regular contact.
 On the other end, I have been in contact with the developer of the backend very
 intensively, since most changes made to either component needed changes in the
 other one as well. Compiler changes also require hardware support, so working
-with the hardware developers was not uncommon either. In practice, most of this
-communication went through the backend developer, except for the design
-discussion concerning the new Montium hardware design (also see section
-\ref{Pipelining} below).
+with the hardware developers was not uncommon either. In practice, most
+communication with the hardware developers went through the backend
+developer, except for the design discussion concerning the new Montium
+hardware design (also see section \ref{Pipelining}).
 
 In addition, discussions regarding design issues at various levels often happen
-out in the open, which easily invites people with an opinion about something to
-chime in, without having to gather people around for every discussion that
-happens. This allows for very quick feedback on ideas from people in all areas
+out in the open, which invites people with an opinion about something to
+chime in, without the overhead of planning a seperate meeting for each
+topic. This allows for very quick feedback on ideas from people in all areas
 in an efficient way.
 
 \subsection{Staying generic}
 \label{StayingGeneric}
 The toughest challenge by far was to fit the features and changes required by
 Recore into code that is maintained by the LLVM project. The main problem here
-is clash of goals: The LLVM project aims for code that performs well for their
+is clash of goals: The LLVM project aims for code that performs well for their
 supported architectures, while Recore aims for code that performs well (or more
-often, can compile MontiumC at all) for the Montium architecture.
+often, can compile at all) for the Montium architecture.
 
 In general, these problems mainly occur because MontiumC and in particular
 MontiumIR poses a number of constraints that are not present in other
@@ -176,12 +258,32 @@ architectures) resulting in miscompiled or uncompilable code.
 
 In some cases, these extra constraints can be formulated in a generic way, such
 that the LLVM code can handle architectures with or without the constraint.
+Examples include providing Montium specific parameters through LLVM's 
+``\verb TargetData '' class and modifications to the loop unroller to support
+custom policies.
+
 In a lot of cases, however, the constraint is so Montium specific that changing
-LLVM to support it is not feasible. In a few cases, this meant that the backend
-was changed to support more features of the LLVM IR. In other cases, a
-Recore-specific transformations was added to solve these problems. In a few more
-cases, the problems are still unresolved, effectively resulting in additional
-constraints on the MontiumC language.
+LLVM to support it is not feasible.
+
+In a few of these cases, this meant that the backend was changed to support more
+features of the LLVM IR. An example of this is finding datapath constants (which
+are the result of a function in MontiumC, so hard to track by LLVM).
+
+In other cases, Recore-specific transformations were added to solve these
+problems. Examples of these are a transformation that removes all global
+variables and passes them as arguments and return values instead, a
+transformation that forcibly inlines all functions marked as ``\verb inline ''
+and a transformation that limits variable lifetimes by introducing extra phi
+nodes.
+
+In a few more cases, the problems are still unresolved, effectively resulting in
+additional constraints on the MontiumC language. Examples of these are
+preventing instructions from being moved out of if/else blocks (which is
+perfectly fine from an LLVM IR point of view, but does not take into account the
+extra meaning that an if statement has in MontiumIR) and removal of unused bits
+from a constant (which could introduce more different constants than the Montium
+has registers for them).
+
 
 \subsection{New hardware design}
 \label{Pipelining}
@@ -189,8 +291,8 @@ I've also been involved for a bit with the instruction scheduling algorithm
 required for the new (pipelined) hardware design and the hardware design itself.
 Even though this is completely outside of the area of my assignment, the initial
 prototype of that scheduler was created by someone else using LLVM. Because of
-my experience with LLVM, I have been assisting him with that.  Initially mostly
-helping out with hints on LLVM coding, but later also with thinking about the
+my experience with LLVM, I have been assisting him with it. Initially I
+helped him by giving hints on LLVM coding, but later also with thinking about the
 scheduler and hardware design.
 
 I will not go into much detail about the new hardware and its scheduler here,
@@ -199,8 +301,8 @@ but I will highlight the most important challenges and tradeoffs.
 \subsubsection{Tradeoffs}
 In general, the most important tradeoff seems to be between flexibility and
 everything else (code size, performance, complexity, hardware area). This
-flexibility is expressed in which instructions are possible, which connections
-are present, how big register files are, etc.
+flexibility is defined in terms of possible instructions, present
+connections, register files sizes, etc.
 
 An important reason to be flexible is for programmability. If the hardware is
 regular, making a compiler that produces optimal code gets a lot easier.
@@ -209,16 +311,17 @@ has flexibility that the compiler will never use, it's better to save
 area and complexity by making the hardware less flexible. Exactly for this
 reason, it is important to develop hardware and supporting software in parallel,
 instead of using the hardware first, software later approach used with the
-initial Montium (TODO: Is this true?). This allows for a much better balanced
-and usable design, without any unused extras.
+initial Montium. This allows for a much better balanced and usable design,
+without any unused extras.
 
 \subsubsection{Inner loop pipelining}
 When trying to improve runtime performance, the main focus is on
 optimizing loops, and inner loops (loops that contain no other loops) in
-particular. Since the inner loop is executed the most often, it is the most
-efficient to optimize the inner loop. Also, the inner loop is also the piece of
-code that can most optimally use the parellel processing power of the Montium,
-because it can be software pipelined. 
+particular. Since inner loops are executed the most often (compared to
+other loops and code), it is the most
+efficient to optimize inner loops. Also, inner loops can most optimally
+use the parellel processing power of the Montium, because they can be
+software pipelined. 
 
 Software pipelining means that the compiler will emit code that performs
 operations that belong in different iterations of the original loop during the
@@ -236,14 +339,14 @@ first and last few iterations (the prologue and epilogue) are distinctly
 different from the loop "kernel", the number of instructions needed for
 a pipelined loop can easily increase a lot.
 
-However, all pipelined loops share a very distinct structure (first
+However, all pipelined loops share a very distinct structurefirst
 stage 1, then stage 1+2, then stage 1+2+3, etc, then all stages at the
-same time, similar for the epilogue). Also, every instruction in the
+same time, similar for the epilogue. Also, every instruction in the
 prologue and epilogue are a strict subset of the instructions in the
 kernel. By adding some hardware support for exactly this structure, the
 code size increase for the prologue and epilogue can be effectively
 reduced to a fixed number of instructions (which take the number of stages as a
-parameter and uses preloaded instructions with explicit stage annotation).
+parameter and use preloaded instructions with explicit stage annotation).
 
 The tradeoff here is that this hardware is only usable specifically for these
 inner loops, any other code will leave this extra hardware unused. However,
@@ -262,7 +365,7 @@ but those will be a lot smaller than the full instruction).
 On the new hardware, however, function calls are more powerful, which should
 lead to a lot less code duplication. For this reason, putting every instruction
 in configuration registers might actually take more space instead of less. It
-should be noted that, the configuration registers of the old Montium are
+should be noted that the configuration registers of the old Montium are
 effectively a compiler controlled cache that is mandatory and static
 (instructions must be in the cache and the cache cannot be modified at runtime).
 By lifting these limitations, we get a cache that is a lot more flexible.