Author Topic: GNAT: Is the compiler doing a good job?  (Read 5278 times)

Sukaeto

  • *
  • Posts: 570
    • View Profile
    • Sukaeto's web server
GNAT: Is the compiler doing a good job?
« on: 2005-11-27 20:05:31 »
I know I'm supposed to be doing some work right now, but I got side-tracked again (not a hard thing to do, if you're me.)

The other guy (well, other student) invovled in the research paper I'm working on and myself stumbled upon this first little bit accidentally the other day.  I decided I'd start testing a bunch of Ada's features and seeing what kind of code GNAT actually generates for them.

I don't know if any of you guys here use Ada at all (I know we have a few Delphi programmers, the syntax between the two should be fairly similar.), but maybe you'll find this of interest anyway.  All the assembly shown is SPARC.  Their are 2 reasons for this: 1) I know SPARC better than I know x86.  2) SPARC looks prettier than x86.  I would imagine the code generated by the compiler to be quite similar on both architectures, and anyone who knows the differences between a RISC and CISC architecture should be able to figure out what the x86 code would look like.

First off:  the natural, a subtype of integer.  My intial thought on this was that it was stored in only 31 bits (well, that it ignored the last bit) so that it would roll to 0 at MAX_INT and never have to worry about any kind of one's compliment stuff to check for negative numbers.  In reality, though, a natural is stored as an integer, and a comparison against 0 is done any time an operation is done on a natural.  Hence the following Ada code:

Code: [Select]

procedure test_natural is
test : natural;
test1 : integer;
begin
test1 := 5;
test := 25 + test1;
end test_natural;


will generate the following assembly code:

Code: [Select]

_ada_test_natural:
!#PROLOGUE# 0
save %sp,-120,%sp
!#PROLOGUE# 1
mov 5,%o0
st %o0,[%fp-24]
ld [%fp-24],%o0
add %o0,25,%l1
cmp %l1,0
bl .LL4
nop
b .LL2
nop
.LL4:
sethi %hi(.LLC0),%o1
or %o1,%lo(.LLC0),%o0
mov 6,%o1
call __gnat_rcheck_10,0
nop
mov %l1,%l0
b .LL3
nop
.LL2:
mov %l1,%l0


The moral of this story?  Only use a natural when you absolutely MUST have non-negative integers, and won't be able to tell until runtime whether or not said integers are negative.  You'll also notice that I added another variable to 25 for 'test'.  This is because the compiler itself does the computations when only literals are involved.  I like this idea, and I also figure most other compilers for most other languages will do the same thing.  This brings me to my next thing, though.

Constants.  Any operation involving a combination of constants and literals will be done by the compiler.  Hence the following Ada code:

Code: [Select]

procedure test_constant is
test : constant natural := 5;
test1 : natural;
begin
test1 := test + 10;
end test_constant;


will generate the following in assembly:

Code: [Select]

_ada_test_constant:
!#PROLOGUE# 0
save %sp,-120,%sp
!#PROLOGUE# 1
mov 5,%o0
st %o0,[%fp-20]
mov 15,%o0
st %o0,[%fp-24]
b .LL1
nop
.LL1:
ret
restore


As you can see, no add instructions.  It does, interestingly enough, store the constant on the stack.  I'm guessing this has something to do with scope and use of the constant.

I know alot of you are probably thinking "you stupid ass, this is all basic compiler design stuff, I already knew this.  ABC's compiler for language XYZ does this too."  You're right.  These were pretty simple examples.  However, I do intend to check out some of the more unique features of Ada and see what kind of code actually comes up.  If anyone actually gives 2 shits, I'll post what I find  here.

Don't really expect too much until Spring/early summer (when we'll hopefully have an algorithm with interesting enough results to write a paper on.  At that point, I'll be doing some code optimization to make it as quick as possible.)

ficedula

  • *
  • Posts: 2178
    • View Profile
    • http://www.ficedula.co.uk
GNAT: Is the compiler doing a good job?
« Reply #1 on: 2005-11-27 21:28:06 »
I don't really understand SPARC syntax, but something's certainly up, because on any of the compilers I normally work with (nothing to do with Ada, of course), I'd expect something like the following to be generated for both of those procedures (Intel x86 syntax, as if it matters!)

Code: [Select]




Or, possibly, if the compiler had to play it safe:

Code: [Select]

RET


They aren't functions, none of the values you're computing get returned, nor (as far as I can see!) are they affecting global state, so I'd expect the compiler to optimise them out totally.

I can think of a few explanations for the code you found;

1) I've misunderstood how Ada works totally. If that were Delphi code I'd expect something like the above; it's all local variables, after all...

1a) I've not misunderstood how Ada works totally, but there's some bizarre language rules particular to Ada that disallow the types of optimisation I'm thinking of.

2) You turned (some?) optimisation off for this test ... which would be kind of a problem if your paper is on testing GNAT's optimisation ability!

3) GNAT really isn't that good at optimising code.

I wouldn't like to guess which, since it's hardly my area of expertise...

Sukaeto

  • *
  • Posts: 570
    • View Profile
    • Sukaeto's web server
GNAT: Is the compiler doing a good job?
« Reply #2 on: 2005-11-27 22:14:18 »
Well, I guess you're right in the fact that those are useless variables.  However, I didn't use any of the optimization flags.  I'm guessing (by what you said) had I turned them on, I would've just had an empty frame.  Although, I guess that would've defeated the purpose of these tests in the first place.  I wanted to see what kind of code was generated by the legitamate use of a natural or constant.

As far as the paper goes, it's actually completely unrelated to Ada or optimization (save the fact that the algorithm implementation has been WRITTEN in Ada, and The Professor in charge of the whole thing and I are both all about squeezing the most efficiency out of code . . . and yes, I'll use gcc's optimization when I compile my optimized algorithm.)

. . . which puts another idea in my head:  Wouldn't it be possible that the optimizer itself thwarts some of the things you did while writing the code to make it more efficient and vice versa?  I guess you'd have to understand all of the compiler's optimization algorithms to attempt to avoid either situation.

Sukaeto

  • *
  • Posts: 570
    • View Profile
    • Sukaeto's web server
GNAT: Is the compiler doing a good job?
« Reply #3 on: 2005-11-29 02:57:22 »
Well, Fice.  You're right.  When I turn on full optimization this same piece of code:

Code: [Select]

procedure test_natural is
test : natural;
test1 : integer;
begin
test1 := 5;
test := 25 + test1;
end test_natural;


generates this assembly:

Code: [Select]

_ada_test_natural:
!#PROLOGUE# 0
!#PROLOGUE# 1
retl
nop


Good stuff to know.  It seems so obvious once it's pointed out, yet I would've never thought of it on my own.  (I'm guessing this'll be something we'll discuss in Compiler II in the Spring - where 75% of the semester is gonna be spent on code optimization techniques.)