Unboxed Values As Rst Class Citizens in a Non-Strict Functional Language 1
Total Page:16
File Type:pdf, Size:1020Kb
Unboxed values as rst class citizens in a nonstrict functional language Simon L Peyton Jones and John Launchbury Department of Computing Science University of Glasgow G QQ fsimonp j jlgdcsglasgowacuk July Abstract The co de compiled from a nonstrict functional program usually manipulates heap allo cated boxed numbers Compilers for such languages often go to considerable trouble to optimise op erations on b oxed numbers into simpler op erations on their unboxed forms These optimisations are usually handled in an ad hoc manner in the co de generator b ecause earlier phases of the compiler have no way to talk ab out unboxed values We present a new approach which makes unboxed values into nearly rstclass citizens The language including its type system is extended to handle unboxed values The optimisation of b oxing and unboxing op erations can now b e reinterpreted as a set of correctnesspre se rving program transformations Indeed the particular transformations required are ones which a compiler would want to implement anyway The compiler b ecomes b oth simpler and more mo dular Two other b enets accrue Firstly the results of strictness analysis can b e exploited within the same uniform transformational framework Secondly new algebraic data types with unboxed comp onents can b e declared Values of these types can b e manipulated much more eciently than the corresp onding b oxed versions Both a static and a dynamic semantics are given for the augmented language The denotational dynamic semantics is notable for its use of unpointed domains Introduction Most compilers have a phase during which they attempt to optimise the program by applying correctnesspreserving transformations to it Constant folding is a particular example of this sort of transformation pro cedure inlining is another Functional languages are esp ecially amenable to such transformation b ecause of their simple semantics Nonstrict functional languages are nicest of all b ecause reduction sometimes called unfolding in a transformational context is always valid in a strict language it is only valid if the b o dy of the function b eing unfolded is guaranteed to evaluate the argument This pap er app ears in the Pro ceedings of the Conference on Functional Programming Languages and Computer Architecture Cambridge Sept Several researchers have b egun to express more and more of the work of the compiler in the form of correctnesspreserving transformations see Section Such an approach has obvious advantages Firstly each transformation can b e proved to b e correct indep endent of the others When more of the compiler takes the form of such transformations it is easier to prove the compiler correct Secondly each transformation exp oses opp ortunities for other transformations The more that is done within a transformation phase the more chance there is for such b enecial interactions There is an imp ortant class of optimisations for nonstrict languages which has so far b een b eyond the scop e of program transformation These all relate to the treatment of socalled unboxed values which we introduce in the next section Instead this family of optimisations is generally implemented in an ad hoc manner in the co de generator Following some preliminaries Sections and this pap er makes four main contributions Most imp ortant we show how the class of unboxedvalue optimisations can formulated as correctnesspreserving transformations Section Unboxed values are made rst class citizens distinguished from their b oxed counterparts by the type system These transformations do not generate much b etter co de than current compilers do our in tention is only to present the optimisations in a new and elegant way We show how to apply the same idea to express and exploit the results of strictness analysis in a uniform way Section We show how the approach can b e generalised to other algebraic data types Section Declaring and using such unboxed data types gives a substantial p erformance improve ment We provide a formal underpinning for the approach by giving b oth a static semantics and a denotational dynamic semantics for the language extended with unboxed values Sections and The dynamic semantics has the desirable prop erty that the semantic equations are unchanged from those for the language without unboxed values despite the extra strictness of the extended language This eect is achieved by using unpointed domains We conclude by discussing some languagedesign issues reviewing related work and mention ing some areas for further work The problem Consider the following function denition double x x x In a nonstrict language x may b e unevaluated when double is called in which case a p ointer to a heapallo cated closure or susp ension for x is passed to double When double needs xs value in this case right away it evaluates the closure As a side eect of this evaluation the closure of x is overwritten with its value Any further attempts to evaluate x will succeed immediately returning its value This way of ensuring that unevaluated closures are evaluated at most once is called lazy evaluation Unfortunately lazy evaluation tends to make arithmetic horribly inecient if some care is not taken In particular in a nave implementation numbers are always represented by a p ointer to a heapallo cated ob ject which is either an unevaluated closure or is a b ox containing the numbers actual value which has now overwritten the closure This means that a simple arithmetic op eration which would take a single machine instruction in a strict language requires quite a long sequence of instructions the two op erands are fetched from their b oxes the op eration p erformed a new b ox allo cated to contain the result and the result placed in it The bitpattern representing the value itself on which the builtin machine instructions op er ate is called an unboxed value Unboxed values come in a variety of shap es and sizes bit integers bit integers single and doubleprecision oating p oint numbers and so on are all unboxed values A p ointer to a heapallo cated b ox containing an unboxed value is called a boxed value Clearly it is vastly more ecient to manipulate unboxed values than b oxed ones Quite a lot can b e done For example consider again the denition of double given ab ove A nave compiler would compile co de for double which would evaluate x extract its unboxed value then evaluate x again and extract the value again then add the two and b ox the result A slightly cleverer compiler would realise that it already had xs value in hand and refrain from the second evaluation As another example consider the following denition f x y z x y z A nave compiler might generate co de to b ox the value of yz only to unbox it again right away A cleverer compiler can elide these unnecessary op erations As a nal example consider the following call to double double pq The straightforward approach is to build a closure for pq and pass it to double which will evaluate it But double is clearly going to evaluate its argument so it is a waste to allo cate the closure only for double to evaluate it and discard it for the garbage collector to recover later It would b e much b etter for the caller to evaluate p and q add their values and pass pq to double in unboxed form The Core language We b egin with a few preliminaries to set the scene for our new prop osals Our compilation route involves the following steps The source language is Haskell Hudak et al a stronglytyped nonstrict purelyfunctional language Haskells main innovative feature is its supp ort for sys tematic overloading but we do not discuss this asp ect at all here Haskell is compiled to the Core language All Haskells syntactic sugar has b een compiled out type checking p erformed and overloading resolved Patternmatching has b een compiled into case expressions each of which p erforms only a single level of matching Boxing and unboxing are explicit as describ ed b elow Program analyses and transformations are applied to the Core language In particular the b oxingunboxing optimisations are carried out here The Core language is translated to the STG language the abstract machine co de for the Spineless Tagless Gmachine our evaluation mo del The Spineless Tagless Gmachine was initially presented in Peyton Jones Salkild but the latter has b een com pletely rewritten as a companion to this pap er Peyton Jones The STG language is translated to Abstract C This is just an internal data type which can b e simply printed out as C co de and thence compiled to native co de with standard C compilers Abstract C can also serve serve as an input to a co de generator thereby generating native co de directly but we have not yet implemented this route In this pap er we only concern ourselves with the Core language which is introduced in the next section However since the Core language do es not have explicit algebraic type declarations we b orrow Haskells syntax for this purp ose when required The syntax of the Core language The abstract syntax of the Core language is given in Figure The binds constituting a prog should dene main which is taken to b e the value of the program The concrete syntax we use is conventional parentheses are used to disambiguate application asso ciates to the left and binds more tightly than any other op erator the b o dy of a lambda abstraction extends as far to the right as p ossible the usual inx arithmetic op erators are p ermitted the usual syntax for lists is allowed with inx constructor and empty list and where the layout