18

I was looking through the Intel software developer manual when I encountered the ADCX instruction, which was previously unknown to me; its encoding is 66 0F 38 F6. It seems to be almost identical to the ADC instruction, so why would you use ADCX when:

  • it is only supported in modern CPUs
  • instruction encoding takes more space (4 bytes versus 1 for ADC)

Is there some other side effect, or special case, where ADCX proves advantageous over ADC? There must have been some good reason why this was added to the instruction repertoire.

John Källén
  • 7,220
  • 30
  • 55

2 Answers2

24

These instructions are used to speed up large integer arithmetic.

Before these instructions adding large numbers often resulted in a code-sequence that looked like this:

  add  
  adc  
  adc  
  adc  
  adc  

The important part here to note is, that if the result of an addition would not fit into a machine word, the carry flag gets set and is 'carried over' to the next higher machine word. All these instructions depend on each other because they take the previous addition carry flag into account and generate a new carry flag value after execution.

Since x86 processors are capable to execute several instructions at once this became a huge bottleneck. The dependency chain just made it impossible for the processor to execute any of the arithmetic in parallel. (to be correct in practice you'll find a loads and stores between the add/adc sequences, but the performance was still limited by the carry dependency).

To improve upon this Intel added a second carry chain by reinterpreting the overflow flag.

The adc instruction got two news variants: adcx and adox

adcx is the same as adc, except that it does not modify the OF (overflow) flag anymore.

adox is the same as adc, but it stores the carry information in the OF flag. It also does not modify the carry-flag anymore.

As you can see the two new adc variants don't influence each other with regards to the flag usage. This allows you to run two long integer additions in parallel by interleaving the instructions and use adcx for one sequence and adox for the other sequence.

Nils Pipenbrinck
  • 80,578
  • 28
  • 146
  • 217
  • I've read a lot about these instructions but never understood how they actually benefit performance or what considerations there for their use until this answer. Everything else appears to just say "oh, the old one changes flags; this one doesn't", which made me think it was `rorx` but for `adc` and somehow that was actually a good thing. – jeteon Nov 17 '17 at 19:37
  • 1
    I think you missed a point, naturally, this chain of operations is written in a loop and the increment of the loop variable changes the carry flag. Thus this requires saving the carry flag, incrementing loop counter, setting carry flag, perform `adc,adc,adc...`. – madhur4127 May 03 '20 at 12:57
10

To quote from the paper New Instructions Support Large Integer Arithmetic by Intel:

The adcx and adox instructions are extensions of the adc instruction, designed to support two separate carry chains. They are defined as:

adcx dest/src1, src2
adox dest/src1, src2

Both instructions compute the sum of src1 and src2 plus a carry-in and generate an output sum dest and a carry-out. The difference between these two instructions is that adcx uses the CF flag for the carry in and carry out (leaving the OF flag unchanged), whereas the adox instruction uses the OF flag for the carry in and carry out (leaving the CF flag unchanged).

The primary advantage of these instructions over adc is that they support two independent carry chains.

Jeff Hammond
  • 4,945
  • 3
  • 26
  • 45
Jester
  • 54,538
  • 4
  • 72
  • 115
  • The question was about adc/adcx, not between adox/adcx. So far, adcx sounds exactly like adc. – Seva Alekseyev Apr 20 '15 at 12:31
  • 11
    @SevaAlekseyev the classic `adc` modifies all the flags, in particular **both `CF` and `OF`**. The new instructions only modify a single flag: `adcx` only `CF`, adox only `OF`. – Jester Apr 20 '15 at 12:34