Home > other >  In assembly, how to add integers without destroying either operand?
In assembly, how to add integers without destroying either operand?

Time:11-17

Using AT&T syntax on x86-64, I wish to assemble c = a b; as

add %[a], %[b], %[c]

Unfortunately, GNU's assembler will not do it. Why not?

DETAILS

According to Intel's Software Developer's Manual, rev. 75 (June 2021), vol. 2, section 2.5,

VEX-encoded general-purpose-register instructions have ... instruction syntax support for three encodable operands.

The VEX prefix is an AVX feature, so x86-64 CPUs from Sandy Bridge/Bulldozer onward implement it. That's ten years ago, so GNU's assembler ought to assemble my three-operand instruction, oughtn't it?

To clarify, I am aware that one can write it in the old style as

mov %[a], %[c]
add %[b], %[c]

However, I wish to write it in the new, VEX style. Incidentally, I have informed the assembler that I have a modern CPU by issuing GCC the -march=skylake command-line option.

What is my mistake, please?

SAMPLE CODE

In a C wrapper,

#include <cstddef>
#include <iostream>

int main()
{
    volatile int a{8};
    volatile int b{5};
    volatile int c{0};
    //c = a   b;
    asm volatile (
        //"mov %[a], %[c]\n\t"
        //"add %[b], %[c]\n\t"
        "add %[a], %[b], %[c]\n\t"
        : [c] " r" (c)
        : [a] "r" (a), [b] "r" (b)
        : "cc"
    );
    std::cout << c << "\n";
}

CodePudding user response:

I believe only a few specific GPR instructions have VEX encodings, primarily the BMI1/BMI2 instructions. See the list in Table 2-28, which has ANDN, BEXTR, BLSI, BLSMSK, BLSR, BZHI, MULX, PDEP, PEXT, RORX, SARX, SHLX, SHRX, as well as the same list in 5.1.16.1.

So Intel didn't introduce a brand new three-operand alternate encoding for the entire instruction set. They just introduced a few specific instructions that have a three-operand form. In some cases these have similar or equivalent functionality to an existing instruction, e.g. SHLX for SHL, and so effectively provide a three-operand version of the previous two-operand instruction, but only in those special cases. There are not equivalent instructions across the board.

You are stuck with the "old style" which remains the only way to add two general-purpose registers.

  • Related