Newsgroups: comp.robotics
Path: brunix!uunet!paladin.american.edu!darwin.sura.net!zaphod.mps.ohio-state.edu!uwm.edu!spool.mu.edu!umn.edu!lynx!nmsu.edu!opus!ted
From: ted@nmsu.edu (Classic Ted)
Subject: Re: HC16 C Compiler info
In-Reply-To: imagecft@world.std.com's message of Thu, 15 Oct 1992 04:17:54 GMT
Message-ID: <TED.92Oct20155521@lole.nmsu.edu>
Followup-To: comp.robotics, comp.lang.prolog
Sender: usenet@nmsu.edu
Reply-To: ted@nmsu.edu
Organization: Computing Research Lab
References: <Bw5ALz.4IH@world.std.com>
Date: Tue, 20 Oct 1992 22:55:21 GMT
Lines: 161



In article <Bw5ALz.4IH@world.std.com> imagecft@world.std.com (Christina J Willrich) writes:


   Expected features within a year of first release:
   ------------------------------------------------
	...
   . Peephole optimizer



well, shoot.... that is the part of my compiler that i have had time
to get in pretty good shape.


here it is (in prolog).  anybody who wants to use it is welcome to,
but please provide source and send any changes or derivative code back
to me.  in particular, i would like to start a collection of
optimizations.  any prolog hacks who want to critique the code are
welcome to (hence the cross posting).

it needs customization for whatever compiler you use and will exhibit
quadratic behavior unless fixed up a little to avoid rescanning the
entire program each time a fix is made.  be careful about the
optimizations listed, they may well be buggy.

================================================================

/* scans through code looking for sequences it knows how to fix and 
   splices in a replacement and then tries again.

   the top level call is to optimize/2.  it expects a code/1 structure whose
   one argument is a list of op-codes.  these op-codes are written in 
   whatever abstract syntax is used by the frontend.  i use a pretty
   obvious prolog encoding.  optimize/2 returns another code/1
   structure with the cleaned up code.

   if a scan finds no sequences to fix, it returns the sequence
   unchanged


optimizations are written as clauses in the following form:

OldList => NewList, Code; Qualifications.  

or

OldList => NewList; Qualifications.  

or

OldList => NewList.

these clauses are transformed into 

fixup(FirstOld, OldList, NewList, Code) :- Qualifications.

where OldList and NewList are lists of assembler codes The tails of
OldList and NewList are unified to the same variable to assist in
constructing the new sequence.

*/

:- op(1200, xfx, '=>').

convert_fixup((Old => New,Code;Qualifications),
	      (fixup(FirstOld, OldList, Code, NewList) :- Qualifications)) :-
    append(Old,Tail,OldList), append(New,Tail,NewList),
    OldList = [FirstOld|_].

convert_fixup((Old => New;Qualifications),
	      (fixup(FirstOld, OldList, _Code, NewList) :- Qualifications)) :-
    append(Old,Tail,OldList), append(New,Tail,NewList),
    OldList = [FirstOld|_].

convert_fixup((Old => New,Code),
	      (fixup(FirstOld, OldList, Code, NewList))) :-
    append(Old,Tail,OldList), append(New,Tail,NewList),
    OldList = [FirstOld|_].

convert_fixup((Old => New),
	      (fixup(FirstOld, OldList, _Code, NewList))) :-
    append(Old,Tail,OldList), append(New,Tail,NewList),
    OldList = [FirstOld|_].

term_expansion(X,Y) :- convert_fixup(X,Y).


/* ================================================================ */

optimize(code(Old), code(New)) :-
    fixup_once(Old, Old, N1), optimize(code(N1), code(New)).
optimize(New, New).

fixup_once(Part, Whole, New) :-
    Part = [Head|_],
    fixup(Head, Part, Whole, New).
fixup_once([X|Part], Whole, [X|New]) :-
    fixup_once(Part, Whole, New).

find_label(L, Code, After) :-
    append(_, [label(L)|After], Code).

find_ref(L, Code, Ref) :-
    append(_, [Ref| _], Code), is_ref(Ref, _, L).

is_ref(Op, Ins, L) :- is_cond(Op, Ins, L).
is_ref(Op, Ins, L) :- is_jump(Op, Ins, L).
is_ref(jsr(L), jsr, L).

is_cond(beq(L), beq, L).
is_cond(bne(L), bne, L).
is_cond(blt(L), blt, L).
is_cond(bge(L), bge, L).
is_cond(ble(L), ble, L).
is_cond(bhi(L), bhi, L).
is_cond(blo(L), blo, L).
is_cond(bmi(L), bmi, L).
is_cond(bpl(L), bpl, L).

is_jump(jmp(L), jmp, L).
is_jump(bra(L), bra, L).

/* ================================================================ */

[pha, phb, ldad(X), tsy, addd(index(0,y)),ins,ins] =>
 [addd(X)].

[pha, phb, ldad(X), tsy, subd(index(0,y)), negd, ins,ins] =>
 [subd(X)].

[pha, phb, ldad(X), tsy, cmpd(index(0,y)), tca,
 ins, ins, clrb, tac, Tst1, incb, label(In), clra, beq(L)] =>
    [cmpd(X), Tst2]; is_cond(Tst1, Op, In), is_cond(Tst2, Op, L).

[label(L)] => [],C; \+find_ref(L,C,_).

/* jumps to jumps */
[Hop] => [Skip],C;
    is_cond(Hop, Op, L), is_cond(Skip, Op, L1), is_jump(Jump, _, L1),
    find_label(L, C, [Jump|_]).

[Hop] => [Skip],C;
    is_jump(Hop, Op, L), is_jump(Skip, Op, L1), is_jump(Jump, _, L1),
    find_label(L, C, [Jump|_]).

/* dead code elimination */
[rts, Op] => [rts],_; \+ Op = label(_).
[bra(L), Op] => [bra(L)],_; \+ Op = label(_).
[jmp(L), Op] => [jmp(L)],_; \+ Op = label(_).

/* jumps to following locations */
[jmp(L), label(L)] => [].
[bra(L), label(L)] => [].

/* last call optimization */
[jsr(L), rts] => [jmp(L)].

/* redundant load */
[stad(A), ldad(A)] => [stad(A)].
