4 ms·
x86 also uses 2-address instructions which means that you often need to use moves between registers (additional instructions), example: [1]. ARM uses 3-address
by codedokode 3y ago
x86 also uses 2-address instructions which means that you often need to use moves between registers (additional instructions), example: [1]. ARM uses 3-address instructions.
Also, x86 code is compact, but not as compact as in era of 8080 [2] - here addition and multiplication require 3 bytes each, 6 bytes total. To my surprise, ARM has an add-multiply instruction and it uses just 4 bytes (instead of 8) [3].
And RISC-V uses 6 bytes because of shortened instruction for addition [4]
Of course, this simple function cannot be a replacement for proper analysis, but it seems that x86 code is not significantly denser.
Also to my great disappoitment none of those CPUs has checked overflow for arithmetic operation.
[1] https://godbolt.org/z/jsoccE5jv https://godbolt.org/z/jsoccE5jv
[2] https://godbolt.org/z/jTMs1MEzh https://godbolt.org/z/jTMs1MEzh
[3] https://godbolt.org/z/nGb8qKcxe https://godbolt.org/z/nGb8qKcxe
[4] https://godbolt.org/z/x9c115crY https://godbolt.org/z/x9c115crY
- BeeOnRope 3y agox86-64 is not even a particularly compact encoding even compared to contemporary fixed length encodings. The inherent advantage of variable length encoding is largely cancelled out by wasted encoding space for legacy cruft. Aarch64 is roughly on par for encoding density.
- kazinator 3y agoIt's incredible how large the code is when you compile some trivial piece of C with GCC for x86 or amd64, compared to one's memory of working with C on 386 boxes. What? I just wrote a simple main and a couple of small helper functions. How can we be past 20 kB of .text section?
- throwaway2037 3y agoCan you share a sample with Godbolt? It might foster some good discussion here.
- userbinator 3y agoOf course, this simple function cannot be a replacement for proper analysis, but it seems that x86 code is not significantly denser. Look at the demoscene for an example of dense x86 code, especially in the sub-1K categories. They routinely achieve code densities for x86 that no compilers I know of can get close to, and AFAIK I have not seen the same happen with ARM, nor MIPS or any other well-known RISC. 3-address instructions improve code density only in situations where both source operands are needed later.
- brigade 3y agoWhat percentage of code that a CPU will run over its lifetime is demoscene code? Heck, even of just simple hand-optimized assembly a CPU is likely to encounter, what percentage is not vector code? Because x86 vector code typically averages more than 4 bytes per instruction, and I have a suspicion that at least five nines of scalar instructions a CPU executes were generated by a compiler.
- userbinator 3y agoI mention that to point out the code density limits of x86 are much higher than what measurements using compiler output will show, while on the other hand I haven't seen the same for ARM and suspect that one can't really get much better than compiler output for it or other RISCs. Having had to patch binaries on multiple occasions by inserting instructions, it is definitely not hard to do so for x86 as one can easily find "slack" that the compiler left behind[1], but I once had to do it for a MIPS binary, and it was definitely not easy to squeeze in the few extra instructions I needed inline; I ended up having to detour to another area with jumps instead. Here's an old paper where the authors tried to optimise for code density manually, and you can consistently see x86 beating ARM and MIPS: https://web.eece.maine.edu/~vweaver/papers/iccd09/iccd09_density.pdf https://web.eece.maine.edu/~vweaver/papers/iccd09/iccd09_den... [1] See https://news.ycombinator.com/item?id=15720923 https://news.ycombinator.com/item?id=15720923 for an example.
- brigade 3y agoYeah if code size is the only metric you care about. The second link is an excellent example of code you do not want a compiler to generate by default. Like, besides all the well-known performance pitfalls of microcoded instructions, jeczx is unfusable on I think all relevant CPUs, so it’s both an additional uop and an additional cycle of latency over a tst/jz sequence.
- drpixie 3y ago> Also to my great disappoitment none of those CPUs has checked overflow for arithmetic operation. Yes - we're stuck with the historically convenient collection of operations and types. Our CPUs are amazingly fast but very little smarter than decades ago. Backwards-compatibility pretty much locks us into the same logical space. At least when people were designing new and amazing computers using actual wire (!) they felt free to implement what they thought would be useful, not just copy the existing model.
- renox 3y agoThe only CPU I know which had integer overflow detection was MIPS. RISC V is somewhat based on MIPS but they removed this part :-(
- smallstepforman 3y ago6502/6510 had integer add overflow …
- Findecanor 3y agoIndeed it is weird to see the trend in hardware to remove overflow checking when the trend in programming languages is to have more. While MIPS can trap on overflow, most architectures can at least set flags for conditional branch. PowerPC OR's the overflow flag into another flag, so you can choose to check that flag for overflow first after a block of calculations. I really want Mill to become successful. It has "NaR" (Not A Result) - like NaN but for integers. For every arithmetic instruction, there is has a variant that can set NaR. Like a NaN it is carried through the data-flow, and there's a trap first when it reaches a store or conditional instruction.
- saagarjha 3y agoModern CPUs are plenty fast at doing overflow checks in software.
- Someone 3y ago> To my surprise, ARM has an add-multiply instruction Fused multiply-add is (https://en.m.wikipedia.org/wiki/Multiply%E2%80%93accumulate_operation#Fused_multiply%E2%80%93add https://en.m.wikipedia.org/wiki/Multiply%E2%80%93accumulate_...) is extremely useful and part of IEEE754-2008. Because of that, it would surprise me if a modern CPU with floating point wouldn’t have it. > And RISC-V uses 6 bytes because of shortened instruction for addition That Wikipedia page claims RISC-V has fused multiply-add, so that may be compiler inefficiency. An answer to https://stackoverflow.com/questions/57248403/why-fused-multiply-add-operation-is-not-used https://stackoverflow.com/questions/57248403/why-fused-multi... says gcc can generate it at -O3)
- Findecanor 3y agoI think the parent poster might have been referring to the integer multiply-add instruction. In fact, 64-bit ARM does not have a regular MUL instruction. "MUL" is an alias to MADD with the zero register as addend. BTW. There is also no REM instruction. Flipping one parameter bit in the instruction word of an MADD makes the unit negate the product, changing it into a MSUB. That instruction is intended for computing the remainder after a DIV. So, when you need only a remainder there are eight instruction bytes — and high latency on small cores. Bigger ARM cores (such as Apple M1) perform macro-op fusion of DIV and MSUB to deliver both quotient and remainder in one operation.