http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58118

            Bug ID: 58118
           Summary: Local variables specified with asm("reg") may not work
           Product: gcc
           Version: 4.7.2
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: nate at verse dot com

In some cases, local variables specified with asm("reg") do not use the
assigned register.  Additionally, assignments to these variables may not be
correct.  The worst behaviour is seen only in templated classes. 

-------------------
class Foo { };

class Parent {
public:
    virtual void func();
};

long foo();

template <class Foo>
class Child: public Parent {
public:
    void func() {
        register long A asm("rax");
        register long B asm("rbx");
        A = foo();
        B = foo();
        __asm volatile("and %1, %0" : "+r" (A) : "r" (B));
    }

};

void *check_source = new Child<Foo>();

g++ -O1, g++ -O3: Neither register is used as assigned.
         Second call to foo() as if return is in %rbx!
        call    _Z3foov
        movq    %rax, %rbx
        call    _Z3foov
        movq    %rbx, %rdx
        and %rax, %rdx

-------  

    void func() {  // in context of sample above
        register long A asm("rax");
        register long C asm("rcx");
        C = foo();  // <- Switched
        A = foo();  //  order here
        __asm volatile("and %1, %0" : "+r" (A) : "r" (C));
    }

g++ -O1:  Inline assembly uses neither specified register.
          Assignments correct apart from that.
        call    _Z3foov
        movq    %rax, %rbx
        call    _Z3foov
        movq    %rax, %rdx
        and %rbx, %rdx

g++ -03:  One register correct, optimization correct.
        call    _Z3foov
        movq    %rax, %rbx
        call    _Z3foov
        and %rbx, %rax

--------

    void func() {  // in context of sample above
        register long B asm("rbx");
        register long C asm("rcx");
        B = foo();  // no conflict with
        C = foo();  // %rax for return
        __asm volatile("and %1, %0" : "+r" (B) : "r" (C));
    }

g++ -O1, g++ -O3:  First register assigned correctly.
          Second assignment is from %rbx.
          Neither desired register in assembly.
        call    _Z3foov
        movq    %rax, %rbx
        call    _Z3foov
        movq    %rbx, %rdx
        and %rax, %rdx

--------

    void func() {  // Without "template<Foo>" or "Child<Foo>"
        register long A asm("rax");
        register long B asm("rbx");
        A = foo();
        B = foo();
        __asm volatile("and %1, %0" : "+r" (A) : "r" (B));
    }

g++ -O1, g++ -O3:  Arguably 'correct' but unhelpful.
                   Variable A is clobbered by second call.
                   Correct variables in assembly!
        call    _Z3foov
        call    _Z3foov
        movq    %rax, %rbx
        and %rbx, %rax

---------

    void func() {  // Without "template<Foo>" or "Child<Foo>"
        register long A asm("rax");
        register long B asm("rbx");
        B = foo();  // Switched
        A = foo();  // order here
        __asm volatile("and %1, %0" : "+r" (A) : "r" (B));
    }

g++ -O1, g++ -O3:  Correct and well optimized!
        call    _Z3foov
        movq    %rax, %rbx
        call    _Z3foov
        and %rbx, %rax

-----------

    void func() {  // Without "template<Foo>" or "Child<Foo>"
        register long B asm("rbx");
        register long C asm("rcx");
        B = foo();
        C = foo();
        __asm volatile("and %1, %0" : "+r" (B) : "r" (C));
    }

g++ -O1, g++ -O3: All correct and as desired.
        call    _Z3foov
        movq    %rax, %rbx
        call    _Z3foov
        movq    %rax, %rcx
        and %rcx, %rbx

Reply via email to