grunwald@uiucdcsb.UUCP (10/28/84)
I'm trying to understand the UCB PC compiler a little more, particularly with
an eye to improving the quality of some of the code produced.
Most of these are issues regarding inefficiencies I've noticed when looking at
the code produced for the 68000.
My first point concerns constants. When emitting a small constant, say "5",
to an integer, you'll often see the code sequence:
movql #5,d0
extw d0
extl d0
The compiler says "Ah, 5 fits in one byte, so emit a P2ICON 5, P2CHAR, and then
do an SCONV to promote it to an integer. This is really a problem with the
68000 (I was using Sun) /lib/f1 phase -- Why doesn't it catch the fact that
the SCONV is not needed in this case? This seems to be fairly frequent.
I'm not familar with the /lib/f1 phase, but it seems that a little work on
this would cut out a lot of useless code in Pascal programs.
The next thing I noticed was in for loops in the Pascal compiler. They shadow
the iteration variable, hopefully in a register. This works O.K., but I've
noticed two things which seem to be very easy to improve:
(1) The shadow variable has the same type as the iteration variable. The
increment is done by:
Emit RV of shadow
Emit RV of shadow
Convert shadow to integer
Emit 1, Integer
Plus
Convert to shadow-type
Assign
If the shadow type is "integer", this produces:
movl d7,d0
addql #1,d0
movl d0,d7
The "movl" stuff is caused by the type conversions.
(2) When the loop iteration variable is anything but an integer, it never
is really put into a register, which is the intent of shadowing in the
first place. This might be considered a fault of the temporary allocator,
but I think there are some sound reasons for not putting shorts and chars
in registers.
Now, since the we know that the iteration variable is within the range of the
lower and upper bounds (a call to RANG is done if -C was specified), we can
actually use any kind of integer which is at least as large as the iteration
variable. So, if we set the shadow variable to be an integer, it gets cast
to a register and we get better code. This is typically very true if you use
sub-ranges for indicies (1..10, etc) or characters to index an array.
An example of the improvements is shown: This is from the following program:
var
k : 0..10;
s : array[0..10] of integer;
begin
for k := 0 to 10 do s[k] := 0;
Ignoring the initilization, etc, which doesn't change much, the loop body is:
L6: L6:
movb a6@(-77),_k movb d7,d0
movb a6@(-77),d0 movb d0,_k
extw d0 movl d7,d0
extl d0 lsll #2,d0
lsll #2,d0 movl d0,a0
movl d0,a0 addl #_s,a0
addl #_s,a0 moveq #0,d0
moveq #0,d0 extw d0
extw d0 extl d0
extl d0 movl d0,a0@
movl d0,a0@ cmpl a6@(-82),d7
movb a6@(-77),d0 jge L5
extw d0 addql #1,d7
extl d0 jra L6
cmpl a6@(-76),d0
jge L5
movb a6@(-77),d0
extw d0
extl d0
addql #1,d0
movb d0,a6@(-77)
jra L6
As I said, a lot more data remains in the registers longer, and the actuall
code is smaller for this admittedly simple (but common) example.
These changes were seen by making the shadow variable be of type integer all
the time and changing the last increment to be a P2ASG P2PLUS instead of the
longer increment given above in (1). The fact that the 0 is extended is still
annoying in my book, but I think that it is really a problem for the code
generator.
If anyone sees a problem with these changes that I don't, please give a yell.
If you're interested in the code for the changes, I can assure you it is very
simple, and I can mail you a DIFF of the 4.2 copies of forop.c and mine.
Dirk Grunwald
{ihnp4, pur-ee} ! uiucdcs ! grunwald
grunwald@uiuc.CSNETgrunwald@uiucdcsb.UUCP (10/29/84)
Actually, I fibbed a bit -- you have to ensure that the for loop index is type compatible with integers before making the shadow variable be a full integer in a register. Otherwise, you'll get typing violations and whatnot. But, that's a simple test to "compat", and the change to the increment still holds.