staroselskii
staroselskii

Reputation: 365

GCC fails to generate 32-bit code from a function with inline assembly

I try to generate 32-bit code like this: gcc -S -m32 BMPTransformer.c -o BMPTransformer.s

I'm using Ubuntu 13.04. People with similar problems seem to have overcome their difficulties by installing libc6-dev-i386. It hadn't worked for me, though.

The compiler complains:

BMPTransformer.c:243:6: error: can’t find a register in class ‘GENERAL_REGS’ while reloading ‘asm’ BMPTransformer.c:243:6: error: ‘asm’ operand has impossible constraints

Code as is:

216 static void ASM_reverse_image(BMPImage *image)
217 {
218      asm (
219             "movl $0, %%eax\n"
220 
221             "cmpl %%eax, %1\n"
222             "jl end\n"
223 
224             "row:\n"
225                  "movl (%0, %%eax, 4), %%edx\n"
226                  "decl %1\n"
227                  "movl (%0, %1, 4), %%esi\n"
228                  "movl %%esi, (%0,%%eax, 4)\n"
229                  "incl %%eax\n"
230                  "movl %%edx, (%0, %1, 4)\n"
231                  "cmpl %%eax, %1\n"
232                  "jg row\n"
233 
234             "end:\n"
235 
236             : : "r"(image->pixel_data), "r"(image->header.height): "%eax", "%edx", "%esi"
237       );
238 }

The code that used the 64-bits a,b,c registers had worked perfectly. But I need a 32-bit version.

Upvotes: 0

Views: 418

Answers (2)

FrankH.
FrankH.

Reputation: 18217

code it as plain C:

static void ASM_reverse_image(BMPImage *image)
{
    int *pixel_data = image->pixel_data;
    int tmp;
    size_t idx = 0, height = image->header.height;

    for (idx = 0; idx < height; idx++) {
        tmp = pixel_data[idx];
        pixel_data[idx] = pixel_data[height - idx];
        pixel_data[height - idx] = tmp;
    }
}

or, if you're using C++, just:

    for (idx = 0; idx < height; idx++)
        std::swap(pixel_data[idx], pixel_data[height - idx]);

Edit: For assembly exercise, this would do:

int tmp;

asm("row:
     mov (%0), %2
     xchg %2, (%0, %1, 4)
     lea 4(%0), %0
     dec %1
     jns row"
    : : "r"(image->pixel_data), "r"(image->header.height), "r"(tmp)
    : "memory", "cc");

but this isn't good code - largely because this is a "streaming" type of processing and should be done via the vector units.

It's always a good idea in gcc inline assembly to avoid requesting specific registers. Let the compiler choose instead. That might mean you'll have to declare one or more "pseudovariables" as assembly register operands (to get a "reg reservation").

Upvotes: -1

Jester
Jester

Reputation: 58762

The error usually signals that the compiler has run out of registers. From the small fragment you posted that should not be the case, and indeed it compiles fine for me. You are probably not telling some important detail.

Anyway, there is absolutely no reason to write this in inline asm in its current form. The compiler can easily generate better (and working) code. The initial comparison certainly should be in C.

Side note: when using gcc inline asm the general idea is to leave as many possibilities to the compiler as possible. For example you don't specifically need any of the registers, you could have used generic constraints.

Upvotes: 2

Related Questions