5 ms·
What I'm wondering about now is: does that 'adc' opcode have any other useful application except for adding numbers bigger than the width of a single register?
by Slartie 6y ago
What I'm wondering about now is: does that 'adc' opcode have any other useful application except for adding numbers bigger than the width of a single register?
Because it does look a little bit as if it was engineered for that particular situation, and if that was the case, with this situation now in practice being solved much more efficiently without a single 'adc' instruction, the opcode might suddenly be completely useless bloat - which of course still had to be maintained forever, even though nobody uses it in practice, because it's part of the spec.
- andrewla 6y agoThat might be another reason why it is slow -- it is an old opcode that has to be supported for compatibility, but isn't prioritized in any of the pipelines in newer chip designs.
- 0x0 6y agox86 has a lot of "useless bloat" with legacy high-level instructions. Modern compilers avoid those and newer cpus aren't engineered with performance in mind for those instructions since nobody sane uses them anymore.
- FartyMcFarter 6y agoIt's not useless bloat though. It's probably hard to beat in terms of code size, which is often even relevant for performance (due to cache size considerations). Furthermore, the article is talking about adding many numbers, which is just one of the possible use cases. As far as I can tell, adc is still useful for adding a pair of 128-bit numbers on a 64-bit CPU for example.
- mrfredward 6y agoI believe adc is still commonly used as a way of reading the carry bit. For example, assuming eax has already been zeroed, adc eax, eax would be the idiomatic way of reading the carry bit into eax. The carry flag gets set by all sorts of instructions other than addition and subtraction (comparisons, bit shifts, multiplication, etc) so this is more useful than you might think.
- giovannibajo1 6y agoActually, setc is the idiomatic way, and doesn’t depend on the previous value of the destination register so it’s much faster to execute because it has no dependencies
- zwegner 6y agoNo, setcc actually does depend on the previous value of the register, because it only comes in the low-byte variants (i.e. al, bl, cl, dl etc)--the top 7 bytes of the destination are left unmodified. A one-instruction variant I've seen that gets you the negated value of the carry flag is sbb rax, rax. This doesn't depend on the previous value of rax in a mathematical sense, though I'm unsure if it depends in an out-of-order sense; that is, if it's recognized as a zeroing idiom (or rather, zeroing or all-one-ing in this case). Probably not. EDIT: did a quick test, and sbb rax, rax etc are not recognized to be a zeroing idiom, at least on my old Haswell. So it's still one instruction, but has a dependency on the previous register value.
- nayuki 6y ago> setcc actually does depend on the previous value of the register, because it only comes in the low-byte variants You should be able to break the dependency and avoid the partial register stall by doing: movzx eax, ax See: https://stackoverflow.com/questions/41573502/why-doesnt-gcc-use-partial-registers https://stackoverflow.com/questions/41573502/why-doesnt-gcc-... ; https://software.intel.com/en-us/forums/intel-isa-extensions/topic/297441 https://software.intel.com/en-us/forums/intel-isa-extensions... ; https://www.agner.org/optimize/microarchitecture.pdf https://www.agner.org/optimize/microarchitecture.pdf (section 6.8)
- zwegner 6y agoYou're right, but only for pre-Haswell chips, where al etc. are renamed separately. From Haswell onwards, they aren't, and depend on the old value. So movzx eax, al gets you mathematical independence, but not out-of-order independence. There's a bunch more detail in this Stack Overflow question (referenced in the one you linked): https://stackoverflow.com/questions/45660139/how-exactly-do-partial-registers-on-haswell-skylake-perform-writing-al-seems-to https://stackoverflow.com/questions/45660139/how-exactly-do-...
- fegu 6y agoThis is the reason some of the esoteric x86 instructions actually perform slower on newer hardware. They are just there for backwards compatibility.
- waynecochran 6y agoHopefully this will all be replaced with quantum computer that does addition with ripple carry or uses QFT... :) https://link.springer.com/article/10.1007/s11432-015-5411-x https://link.springer.com/article/10.1007/s11432-015-5411-x https://arxiv.org/pdf/1411.5949.pdf https://arxiv.org/pdf/1411.5949.pdf
- londons_explore 6y agoADC is still the quickest way if you need to add two 256 bit numbers.