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