Compiler Const bug?

Coding and general discussion relating to the compiler

Moderators: David Barker, Jerry Messina

SHughes_Fusion
Posts: 219
Joined: Wed Sep 11, 2013 1:27 pm
Location: Chesterfield

Compiler Const bug?

Post by SHughes_Fusion » Tue Oct 27, 2015 4:20 pm

I've found an oddity with consts in the compiler. Not sure if this is a bug or something that is counter-intuitive...

If you enter the following code:

Code: Select all

Public Const TemperatureMultiplier = 64                                 // All temperatures are multiplied by 64 to allow the use of a signed integer rather than floats
Public Const ReadyThreshold1 As Integer = 3.0 * TemperatureMultiplier
Public Const ReadyThreshold2 As Integer = 3 * TemperatureMultiplier
You'd expect ReadyThreshold1 and ReadyThreshold2 to both be 192. However, ReadyThreshold1 is actually -32576...

I'd expect the compiler to evaluate the const initially using floating point then convert it to an integer but something else seems to be happening.
Any ideas?

Jerry Messina
Swordfish Developer
Posts: 1471
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: Compiler Const bug?

Post by Jerry Messina » Tue Oct 27, 2015 5:38 pm

ReadyThreshold1 is actually -32576...
That's "192 with the MSB set", turning it into a negative number

Drop the 'as integer' from the declaration and it works. It'll convert it to an int when it uses it.

Code: Select all

Public Const TemperatureMultiplier = 64                                 // All temperatures are multiplied by 64 to allow the use of a signed integer rather than floats
Public Const ReadyThreshold1 As Integer = 3.0 * TemperatureMultiplier
Public Const ReadyThreshold2 As Integer = 3 * TemperatureMultiplier
Public Const ReadyThreshold3 = 3.0 * TemperatureMultiplier

dim i as integer

i = ReadyThreshold1     // -32576
i = ReadyThreshold2     // 192
i = ReadyThreshold3     // 192

SHughes_Fusion
Posts: 219
Joined: Wed Sep 11, 2013 1:27 pm
Location: Chesterfield

Re: Compiler Const bug?

Post by SHughes_Fusion » Wed Oct 28, 2015 7:55 am

Jerry Messina wrote:
ReadyThreshold1 is actually -32576...
That's "192 with the MSB set", turning it into a negative number

Drop the 'as integer' from the declaration and it works. It'll convert it to an int when it uses it.
I'm not so confident to do that - from an earlier post you'll see that in a similar situation the compiler has created a float, leading to inefficient code.

I've not actually tried it in this case but after that experience I'd rather specify everything in the correct format.

I'll try defining it different ways and check the code side - I have specified it as a Word currently (it is always positive and will be much less than 32768) but I don't know if comparing a word to an integer will take more code space or not...
Last edited by SHughes_Fusion on Wed Oct 28, 2015 8:46 am, edited 1 time in total.

SHughes_Fusion
Posts: 219
Joined: Wed Sep 11, 2013 1:27 pm
Location: Chesterfield

Re: Compiler Const bug?

Post by SHughes_Fusion » Wed Oct 28, 2015 8:45 am

To follow up on this, I've tried declaring this as an integer, a word and with no specific type. All three options end up with different compiled size with the 'no declaration' option being the biggest by 6 bytes.

This const is only used in one place - it is written to EEPROM as a 'default' configuration item. This location is read in to an integer so what is stored needs to at least load correctly in to an integer...

At the moment it seems safest to declare it as a Word - which also gives the smallest code size.

Jerry Messina
Swordfish Developer
Posts: 1471
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: Compiler Const bug?

Post by Jerry Messina » Wed Oct 28, 2015 10:05 am

Good point. I didn't think about that. In the simple example where it was just used in an assignment, it was smart enough to just convert it to an int w/out any addtl overhead.
I changed it to an expression and it did it in floating point before converting it to an int (which is what I asked it to do, I suppose), so good catch.

Code: Select all

Public Const TemperatureMultiplier = 64
Public Const ReadyThreshold3 = 3.0 * TemperatureMultiplier
dim i as integer

i = ReadyThreshold3     // int 192
i = ReadyThreshold3 + i  // floating point add
At the moment it seems safest to declare it as a Word - which also gives the smallest code size
I think you'll find that using unsigned types vs signed types almost always produces smaller code if you can get away with it.

SHughes_Fusion
Posts: 219
Joined: Wed Sep 11, 2013 1:27 pm
Location: Chesterfield

Re: Compiler Const bug?

Post by SHughes_Fusion » Wed Oct 28, 2015 10:17 am

I think you'll find that using unsigned types vs signed types almost always produces smaller code if you can get away with it.
How about in mixed expressions? Some values need to be signed - basically, I'm re-writing a PID routine that previously used floats.

It seems that any const which would result in a positive integer is calculated wrongly. Oddly, however, any const which would result in a negative integer does seem to calculate correctly.

Does David pop by these boards these days or is it better to email him direct about this issue? Would you agree it is a compiler (or IDE?) bug?

User avatar
octal
Registered User
Registered User
Posts: 586
Joined: Thu Jan 11, 2007 12:49 pm
Location: Paris IDF
Contact:

Re: Compiler Const bug?

Post by octal » Wed Oct 28, 2015 10:31 am

I can't see where is the problem.
A "const" is not a variable. It has no memory location. Declaring a const doesn't create any "object". The compiler will internally create and hold a simple value tagged with the correct type obtained either from the numerical constant used, or from the deduced type of the expression affected to it. This tagged (value, type) will be used anywhere you use your "const" in an expression.

When you put

Code: Select all

Public Const TemperatureMultiplier = 64
Public Const ReadyThreshold3 = 3.0 * TemperatureMultiplier
dim i as integer

ReadyThreshold3 is replaced by a Float. So when you write

Code: Select all

i = ReadyThreshold3     // int 192
i = ReadyThreshold3 + i  // floating point add

First affectation of i is done by converting the Float expression to int.
Second affect, compiler will obviously replace ReadyThreshold3 with the Float expression, and thus apply float addition (Float + integer is done by first converting the int to float).

I don't see where is the incorrect behaviour. If you want that compiler generate integer arithmetic, you need to tag your expression with correct type (this is what you have done using AS WORD).

SHughes_Fusion
Posts: 219
Joined: Wed Sep 11, 2013 1:27 pm
Location: Chesterfield

Re: Compiler Const bug?

Post by SHughes_Fusion » Wed Oct 28, 2015 10:34 am

octal wrote: I don't see where is the incorrect behaviour. If you want that compiler generate integer arithmetic, you need to tag your expression with correct type (this is what you have done using AS WORD).
Erm... So you think if I use

Code: Select all

Public Const ReadyThreshold1 As Integer = 3.0 * TemperatureMultiplier
and the compiler sets ReadyThreshold1 to -32576 this is correct?

Jerry Messina
Swordfish Developer
Posts: 1471
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: Compiler Const bug?

Post by Jerry Messina » Wed Oct 28, 2015 1:15 pm

I don't see where is the incorrect behaviour. If you want that compiler generate integer arithmetic, you need to tag your expression with correct type (this is what you have done using AS WORD)
I think we all agree on that. My second example there was just to show that not declaring a type in the 'const' statement might get you something you didn't expect. I don't think it's at all wrong in that case... probably a bad example on my part. Sorry for confusing things.

Code: Select all

Public Const ReadyThreshold1 As Integer = 3.0 * TemperatureMultiplier
Public Const ReadyThreshold2 As Word    = 3.0 * TemperatureMultiplier
I would have thought that they would evaluate to the same value, and not have one end up as -32576.

It sure looks like it evalutes it wrong to me...

Code: Select all

?I000000_F000_000013_M000000 ; L#MK I = READYTHRESHOLD1     // -32576
    MOVLW 128			<<<<< MSB SET???? SHOULD BE 0
    MOVWF M2_S16H,0
    MOVLW 192
    MOVWF M2_S16,0
How about in mixed expressions? Some values need to be signed - basically, I'm re-writing a PID routine that previously used floats
If you're mixing them then I think you'll end up with less code if you just use ints for everything.


David does drop by the forum from time to time (depending on how busy he is), but if you want to bring it to his attention drop him an email/PM.

User avatar
octal
Registered User
Registered User
Posts: 586
Joined: Thu Jan 11, 2007 12:49 pm
Location: Paris IDF
Contact:

Re: Compiler Const bug?

Post by octal » Wed Oct 28, 2015 1:27 pm

@SHughes_Fusion

sorry, I read the thread too quickly, and I misunderstood the problem. I thought you were asking why does compiler use Float arithmetic instead of int one even when using integers.
I see that there is a problem with signed interger arithmetic. I think there were already a bug like this with Byte variables sometimes ago and that was fixed by David.

SHughes_Fusion
Posts: 219
Joined: Wed Sep 11, 2013 1:27 pm
Location: Chesterfield

Re: Compiler Const bug?

Post by SHughes_Fusion » Wed Oct 28, 2015 1:32 pm

I wonder if the issue is something as simple as the fact the compiler is assuming any integer const will be negative and sets the MSB regardless?

The fault persists even with a simple Const as Integer = 3.0 declaration yet Const as Integer = -3.0 works as expected.

I've PM'd David, hopefully it is something trivial that he can fix quickly.

Jerry Messina
Swordfish Developer
Posts: 1471
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: Compiler Const bug?

Post by Jerry Messina » Wed Oct 28, 2015 2:44 pm

as simple as the fact the compiler is assuming any integer const will be negative and sets the MSB regardless?
I think it probably has more to do with converting the float value to an int.

It seems to get it right when only ints are in the expression.

User avatar
David Barker
Swordfish Developer
Posts: 1214
Joined: Tue Oct 03, 2006 7:01 pm
Location: Saltburn by the Sea, UK
Contact:

Re: Compiler Const bug?

Post by David Barker » Thu Oct 29, 2015 8:46 am

I'll take a look when I get some time, but here are some workarounds for your problem:

Code: Select all

Public Const TemperatureMultiplier = 64                                 
Public Const ReadyThreshold1 As Integer = 3 * TemperatureMultiplier
or

Code: Select all

Public Const TemperatureMultiplier = 64                              
Public Const ReadyThreshold1 As longint = 3.0 * TemperatureMultiplier
Fortunately, the code explorer will always display the value of the computed const so it should not catch anyone out.

SHughes_Fusion
Posts: 219
Joined: Wed Sep 11, 2013 1:27 pm
Location: Chesterfield

Re: Compiler Const bug?

Post by SHughes_Fusion » Thu Oct 29, 2015 9:45 am

Unfortunately neither of those work-around work in my scenario. I'm writing this const directly to EEPROM so using a LongInt would over-write data in another location. Using an integer value is also not ideal - for initial testing I'm using a whole number but I may need to tweak these defaults to use a fraction.

Also, it did catch me out initially - it was only when I noticed the value being reported back wasn't what I was expecting that I dug deeper. The code explorer doesn't expand consts by default and if you have a lot you can easily miss one not being as you expect. In this case it was obvious, in others you might think it is a coding error without realising the const is wrong.

You are right though that it is easy enough to check in the code explorer so from now on I know to do this.

User avatar
David Barker
Swordfish Developer
Posts: 1214
Joined: Tue Oct 03, 2006 7:01 pm
Location: Saltburn by the Sea, UK
Contact:

Re: Compiler Const bug?

Post by David Barker » Thu Oct 29, 2015 3:14 pm

> Unfortunately neither of those work-around work in my scenario. I'm writing this const
> directly to EEPROM so using a LongInt would over-write data in another location.

That doesn't make sense - it would only over write your data if you called WriteLongWord()

Code: Select all

Public Const TemperatureMultiplier = 64                              
Public Const ReadyThreshold1 As LongInt = 3.0 * TemperatureMultiplier
EE.WriteWord(0, ReadyThreshold1)
will work fine.

> Using an integer value is also not ideal - for initial testing I'm using a whole number but
> I may need to tweak these defaults to use a fraction.

I don't understand - I thought you wanted to avoid floats?

> The code explorer doesn't expand consts by default

Code Explorer Drop Down -> Auto Expand -> Constants

Post Reply