<< 2012-3 >>
Department of
Computer Science
 

Introduction

This document gives a guide to using the compiler system to compile programs written in the PRE high level language.

Installing The Compiler

The compiler system is written in Java and so to use it you must have a recent version of the Java runtime system installed. Once this is achieved, you should be able to sucessfully issue the following command : machine% java -version java version "1.1.3" Having installed a Java runtime system, you should set up your CLASSPATH environment variable to point at the installation JAR file containing the compiler system : machine% CLASSPATH=$CLASSPATH:compiler.jar From now on you should be able to compile programs written in the PRE language by issuing commands as discussed below : machine% java compiler.Compiler -line 512 -words 4 -source in.pre -target out.preasm

Customizing The Compiler Behaviour

The behaviour of the compiler is changed by the use of the command line options shown below :

Switch Default Value Resulting Behaviour
-source <file> stdin The -source option directs the compiler to read the source code for the PRE program from the specified file instead of from stdin.
-target <file> stdout The -target option directs the compiler to write the compiled assembly language program to the specified file instead of to stdout.
-hlp <on|off> on To instruct the compiler to switch between two different partitioning strategies, the -hlp option is used. When set to the default value of on, the compiler used the HLP partitioning strategy and when set to off, it uses the OLP method. This is mainly an obsolete option as the HLP method is generally better.
-commentCode <on|off> on The compiler generates a number of comments in the generated assembly language to aid the users understanding of the code. To supress these comments, use the -commentCode off option.
-spaceTabs <on|off> on In generating the resulting assembly language program, indentation may be used to aid the readability of the code. If the default option of -spaceTabs on is used, this indentation will be made purely of space characters while -spaceTabs off makes the indentation with tab characters.
-tabSize <int> 4 If the indentation of the resulting assembly language program is made from space characters, this option dictates how many spaces are equivalent to one tab.
-lines <int> 256 To enable the compiler to make the best use of the cache, the -lines option is used to tell it how many cache lines are present in the cache system of the target machine.
-words <int> 4 To enable the compiler to make the best use of the cache, the -words option is used to tell it how many words are in each cache line in the cache system of the target machine.
-stackSize <int> 2048 Specify the size of the stack which will be allocated to the program.
-help Prints a help screen with a brief rundown of availible options.
-moveForLoopInvariants Pre-compute invariants into registers.
-moveWhileLoopInvariants Pre-compute invariants into registers.
-emitForLoopInvariants Enable nested loop invariants to move further.
-emitWhileLoopInvariants Enable nested loop invariants to move further.
-passArgumentsInRegisters Pass procedure arguments in registers rather than on the stack.
-passReturnInRegister Pass procedure return value in register rather than on the stack.
-numberOfArgumentsInRegisters <int> 4 Specify the number of arguments to pass in registers.
-reusePartitions Perform cache size optimisation reusing partitions where possible.
-O0 No optimisations are attempted.
-O1 Only optimisations that are considered safe and stable are attempted.
-O2 All availible optimisations are attempted which may result in some problems in the resulting code.
-dumpFirstPass Show the code generated during the first code generation pass.
-instructionCacheThreshold <int> 128 Limit the size of the instruction partition to hold this number of instructions.

Dealing With Compiler Errors

During compilation of the program, the compiler may produce some error reports when it encounters a problem which is can not resolve. Due to the simple nature of the compiler, any error messages are terse and can be hard to resolve. Shown below is a list of potential errors and possible solutions. It is useful to note that in all cases, the number NNNN is the line number at which the error occurs.

Error Cause Solution
ERROR : Syntax error The program is syntactically incorrect ie. the compiler is unable to parse the program. Check the syntax of the program locating any statements that do not match the expected syntax as shown in the grammar. Amend the source code to comply with the grammar and recompile the program.
ERROR : Invalid type for assignment The left hand side of an expression is of an invalid type to be assigned to. Check that the left hand side of the assignment is a user defined variable, that it is not being used as a loop counter inside a bounded loop and that, if it is a vector, its subscripts are correct to allow it to be assigned to. Amend the source code so a valid variable expression appears on the left hand side of the expression and recompile the program.
ERROR : Invalid type in expression The type of part of an expression is incorrect. Check that you are using operators in the expression on the correct data types. Also check that user defined variables are of the correct type. Amend the source code to comply with the type rules and recompile the program.
ERROR : Invalid type of argument in call to X The type of an argument in a procedure call does not match the parameters delcared by that procedure. Check the type of the parameters as declared in the function definition. Amend the source code so that the types of the procedure parameters and procedure call arguments match and recompile the program.
ERROR : Wrong number of arguments in call to X The number of arguments supplied in a procedure call does not match the number of parameters declared by that procedure. Check the type of the parameters as declared in the function definition. Amend the source code so that the number of the procedure parameters and procedure call arguments match and recompile the program.
ERROR : Call to nonexistant procedure named X There is a call to a procedure that is not defined in the program. Check the identifier of the procedure call, being careful of spelling and case, and amend the source code so that the identifier matches that of a procedure that is defined in the program.
ERROR : Return statement must return a value A return statement doesn't provide a return value when one is needed. Alter the statement so that a value is returned and recompile the program.
ERROR : Return statement must not return a value A return statement provides a return value when none is needed. Alter the statement so that no value is returned and recompile the program.
ERROR : Return statement must return a value of correct type The types of the return value and the return type of its containing procedure don't match. Check that the type of the expression returned in the return statement is the same as that of the return type in the procedure prototype. Alter the source code so that these types are the same and recompile the program.
Anything Else The compiler is broken. This is a research compiler and as such it will regularly change in operational state and hence some features may not work to their full potential. Inform someone of the error and wait until a new compiler is released.

Compiler Optimisations

Currently, the PRE compiler attempts a number of conventional and partitioned cache specific optimisation while generating the target code. The actual optimisations used can be specified by the user using the command line options detailed above.

The first run-time optimisations relate to how arguments to procedures are passed from the caller to the callee. In a worst case, all arguments and return values are passed on the stack with the caller pushing the arguments onto the stack for the callee to pop them off as needed. This can generate more memory traffic than is needed as we can pass both the arguments and return values in registers. This decreases the amount of memory traffic although the amount of instructions to achive the procedure call will increase.

The second run-time optimisations deals with reducing the cost of computing invarients within loops. If a value is invarient within a for or while loop, it may be pre-computed outside the loop body thus eliminating the need to re-compute it in every iteration of the loop. The success of the movement of such invarients is dependant on there being enough free registers to hold them.

With the memory access segregation performed while partitioning, it is clear that not all objects are in use simultaneously, and in all the perspectives (multiple partitions per object). While an optimal solution to this problem would be achievable, it requires more analysis than that available currently. However, satisfactory results are obtainable with more simple heuristics drawing on the information available.

© 1995-2013 University of Bristol  |  Terms and Conditions  |  Use of Cookies
About this Page