-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Maths doesn't promote to destination type #119
Comments
All math has the same rules: the following three pieces of code should all succeed to compile and should all have the same effect:
You cannot have an introduction of a variable of a correct type change the overall result. Most programming languages do something similar. For this reason, the correct value of 148 << 6 has to be 0. However, this is a good place to introduce a compile warning. |
No.
From the C11 6.3.1.1 Boolean, characters and integers standard
Of which C++, Obj-C, C# and Swift also follow suite. 64tass does int or float and promotes to either as needed but doesn't do maths internally as byte or word, you can't cast mid operation to a smaller type. If you know of any languages that don't follow such rules, I am very interested is seeing them. To which
While the tmp is a byte and a variable the code generated should promote it to a word and perform a 16 bit operation and again the result is 9472 as calculated by the 6502/6809/Z80 or if you detect this is a constant case and optimize it away with a single immediate load.
Since we are shifting a byte and storing it in a byte, in 6502 code tmp2 will be 0 and thus CurrentNumMovesLeft when assigned the byte variable tmp2 will also be 0, with both bytes being set to 0 as the byte is promoted to a word on assignment. If you detect this as a constant case and optimize it then the result is still 0 as we have requested that result of tmp << 6 to be stored in a byte sized container. like wise
tmp is assigned the value 131, not 3
tmp is assigned the value 43 not 42 as all sub parts of the expression should be promoted to a floating point number before being converted back to a byte. |
Those languages were designed for 16-bit or 32-bit machines, and that's why they're incapable of doing arithmetic on anything smaller. Smaller types exist in them only as a storage mechanism and an overload disambiguation hint. In each of those languages, the In none of the languages you mentioned (on any common implementation at least) Millfork does exactly the same. It is a fully 8-bit language, that's why its "int" is 8-bit. Any arithmetic on 8-bit operands yields 8-bit results. If Millfork ever gets a 4-bit or a 1-bit integer type (quite usable, some languages like Batari Basic have those), it could promote them to 8-bits, but right now 8-bit is both the smallest type and the default type. Just like in all the other languages you mentioned, if you want your operation to be done at a larger size, you need to provide at least one of the arguments of that larger size. Going back to my example: If byte << byte yielded a word, then either you couldn't assign it to a byte (which would be very annoying, just see any bit-twiddling code in Java), or you could, but then you could assign any word to a byte, yielding tons of bugs (like C, I mean I know that it is sometimes annoying, but it was a trade-off. Other options would have been much worse (inconsistent, slow or error-prone), with a negative impact over the entire language. I'll add warnings to catch some of such overflow cases, but the behaviour won't change, as it is working as intended. As for 64tass, the expressions you write have no chance of being compiled into executable code, they are all preevaluated constants, so the assembler is free to use whatever. |
indeed long x = 4 << 30 does yield 0. really would have hoped that got fixed somewhere along the lines, but I'm sure the code that uses GCC will give you
while VS will give you nothing. Thanks VS.
Don't you just love standards, there are so many to choose form 😄 But if we only have bytes then how does
since i is a byte and we only assign a byte, temp now equals $4004 and to get it to perform the operation as intended I need to to temp = word(i) so the byte is promoted to word and thus $0004 is assigned to temp? How about There is a missing distinction, there is code and there is compile time constants as you noted.
in this case
it is a constant I'm getting the compiler to generate for me, the same as when I do in 64Tass or any other compiler/assembler. If I write While
is not compile time constant as it involves variables that are not const defines. Your optimiser may resolve it to be a const value, but it is an expression that then has a byte cast in it. i.e To make it more explicit perhaps say a [form] could be introduced so one does
And all of those(except the last one) will fail at the moment. And if you add a warning saying |
Assembly? 😄 I mention it because Millfork is targeted somewhere between Assembly and C. Yes, it is a rather unusual decision, but like with avoiding recursion (which is also unusual in most modern languages) it was chosen to help fit the language to the target platform. It's intentionally lower-level than C, and C was already barely a high level language. Integer promotion is costly. Almost any operation that compares a byte to a 16-bit value ends up promoted in C, for example. A simple byte comparison that would be a CMP b / BNE sequence for 6502 becomes a subroutine to promote the byte to 16 bits and then do a 16 bit comparison. This is one of the main reasons that compliant C compliers for 8-bit machines are so bad at generating code. |
So if you compare a byte to a word you want it to do this?
because that is wrong and is going bug quite a lot. Any byte being compared to word has to convert the byte to a word which it can do by checking the high byte and if it is not zero then it fails. If zero then it compares the low byte. I figured this might actually need to be tested. So
yields
so the compiler has worked out the constant values are always false, and it has auto promoted j to a word to do the comparison.
yields
again it does a cmp #0 check on the upper byte, so the byte has been auto promoted to a word for the comparison. |
– Detection of simple byte overflow cases. – Optimization of 8×8→16 multiplication on 6809. – Multiplication optimizations on Z80.
So Given
You then get
Which is wrong. You have to do
; CurrentNumMovesLeft = word(148) << 6
Which then gets you
It should detect that the destination is a word and limit the value to the size of the destination without having everything cast. It should also perform all maths at the highest needed and then only truncate at the end.
The text was updated successfully, but these errors were encountered: