We've had a lot of problems that have been traced back to the Zilog compiler for eZ80 during the years.
Sure, our project is big, has many files, some of them pretty big - but they are all well formed and strictly typed.
We have not been able to compile our project with optimizations for the past 6 years because the optimizations simply break the compiled code in a variety of locations (in most cases, complete nonsense code is generated) but when 4.11.1 was released we were still happy, because that was the first compiler version that we could trust *without optimizations* and we have been using it ever since, but trying every new release to see if it works properly. Never does, at least not consistently.
When 5.1.1 was released, I did - as usual - try it out with and without optimizations and to my great joy it actually seemed to be working, even with optimizations turned on! I announced the great news and we danced, drank and celebrated... but alas, 'twas too soon.
I've been compiling releases with this version of the compiler since then, but recently I had to track down a strange bug and lo and behold - yet another deal breaker.
Again, our company looses a sizeable portion of income due to semi-broken Zilog tools.
Below is an extract from the assembly code generated with 4.11.1, our compiler of choice, and the 5.1.1 with optimizations.
The code produced by the 5.1.1 (left side) version is clearly not working, while the 4.11.1 (right side) is.
| Code: |
ZDS II 5.1.1 with Optimizations ZDS 4.11.1 without Optimizations
; 739 link = a_links[ index ]; ; 739 link = a_links[ index ];
.LINE 739 . LINE 739
LD HL,(IX+-6) LD HL,(IX+-6)
ADD HL,HL ADD HL,HL
LD BC,_a_links LD BC,_a_links
ADD HL,BC ADD HL,BC
LD BC,(HL) LD BC,(HL)
LD (IX+-8),C LD (IX+-8),C
LD (IX+-7),B LD (IX+-7),B
; 741 if( FIRST( link ) || !VALID( link ) ) { ; 741 if( FIRST( link ) || !VALID( link ) ) {
.LINE 741 .LINE 741
LD A,(IX+-28) LEA HL,IX+-6
OR A,A DEC HL
JR NZ,L_278 LD A,(HL)
LD A,(IX+-23) AND A,64
OR A,A UEXT HL
JR NZ,L_278 LD L,A
LD A,(IX+-27) CALL __icmpzero
OR A,A JR NZ,L_275
JR Z,L_280 LEA HL,IX+-6
L_278: DEC HL
; Code within if-statement LD A,(HL)
L_280: AND A,128
UEXT HL
LD L,A
CALL __icmpzero
JR Z,L_275
LEA HL,IX+-8
LD A,(HL)
AND A,128
UEXT HL
LD L,A
CALL __icmpzero
JR Z,L_277
L_275:
; Code within if-statement
L_277:
|
For reference, the macros are:
| Code: |
#define VALID( l ) ( ( HIGH8( l ) & LINK_CB_VALID ) && !( LOW8( l ) & LINK_S_INVALID ) )
#define FIRST( l ) ( ( HIGH8( l ) & LINK_CB_FIRST ) )
|
HIGH8 and LOW8 are macro references to the high/low bytes of a 16-bit word, others are 8-bit patterns - 0x80, 0x80, 0x40 in order of appearance.
Now, the code produced by the 4.11.1 compiler is a whole story in and of itself (simple boolean 8-bit operations being upconverted to 24-bit and checked agains zero by the insanely slow __icmpzero function) at least it works and later versions have fixed/"fixed" this problem. Since we are, again, stuck with this compiler we simply cannot move our products forward due to performance issues caused by these insane boolean operations that
often has execution times of more than 40 times that of properly generated code - and
yes I've done the math, and the benchmark, it's 40x.
The 5.1.1 compiler on the other hand - I have no clue what's going on there...
The data (link) is placed in the current functions stack frame at address IX-8 and -7 (16-bit) but when it is read back (for no reason, it's already available in BC and it's not volatile - i thought this was what optimizations should be doing) it is read from IX-28, -27 and -23.
What's interesting here is that it is not only incorrect, but the same referenced data is read from different addresses at different points (it's 16-bit, but has reads from three different locations) and hear this - the stack frame for this function is only 18 bytes which means that it's actually reading data from outside of the current stack frame - that is - data that the function has no knowledge or control over, or from the functions point of view - gibberish.
As if that weren't enough it fails to AND the data to produce the specified checks and basically translates back to:
| Code: |
if( foo1 || foo2 || foo3 ) {
|
where foo are all references to data that cannot (legally) be referenced by this function.
I swear on my mothers grave, to god and the great turtle that carries the earth that
Zilog has not release a single stable, reliable and consistent compiler for at least eight years by now - I've used them for the past 6 years, and my colleagues have told me many similar stories of the even earlier ones.
But you are using the 4.11.1 one successfully you say? Yes, true! But it is, in addition to the 8-bit boolean performance issues mentioned above, plagued by random "Internal Compiler Error" issues, and when I say random I mean that simply hitting recompile over and over again eventually gives me a working file. That's consistency (and productivity) out the window.
Smaller projects
mostly compile well, but I would be lying if I said I haven't seen bugs even in the most simple programs (we're talking a single file, less than 50 lines of code, compiled for the Zilog Ethernet module - nothing custom at all) so saying that this isn't a problem for the majority of users just isn't true - while it doesn't happen often it CAN happen any time and the compiler can as such simply not be trusted to produce correct code.
Another similar anecdote of historical interest was when an earlier version sometimes (like 1 in 3) translated
| Code: |
a[ 0 ] = b[ 0 ];
a[ 1 ] = b[ 1 ];
...
a[ 7 ] = b[ 7 ];
a[ 8 ] = b[ 8 ];
a[ 9 ] = b[ 9 ];
a[ 10 ] = b[ 10 ];
|
into assembly code equivalent to:
| Code: |
a[ 0 ] = b[ 0 ];
a[ 1 ] = b[ 1 ];
...
a[ 7 ] = b[ 7 ];
a[ 8 ] = a[ 8 ]; // Copies from a to a!
a[ 9 ] = a[ 9 ]; // Copies from a to a!
a[ 10 ] = b[ 10 ];
|
That is, at the eight and ninth copy it starts doing nonsense copies to and from the same location, while at the tenth copy reverts to normal behaviour. Mind-boggling. The support response was, as it always is for these kinds of more technical issues, "cannot reproduce".
For the love of all things sacred:
SCRAP ZDS II AND MOVE TO ECLIPSE!
REPLACE YOUR COMPILER TECHNOLOGY WITH A BACK-END FOR GCC, LLVM OR SIMILAR!
Or, at the
very least - make your compiler open source
so we can fix the bugs ourselves - we already know the code is bad, don't be ashamed of showing it to us. Whatever all of you executives may think there are no secrets in there, you do not have compiler technology you need to protect, there are many open source projects that have done things better and therefore no-one will have any reason to steal your IP any more than the broken 16" CRT TV that is gathering dust in my attic.
Please, I'm on my knees here and the mental health of our entire development force is on the verge of collapse.
We need working software, we needed it 5 years ago, things went critical a long time ago and has only been getting worse ever since.