Hello. http://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Local-Reg-Vars.html#Local-Reg-Vars "However, using the variable as an asm operand guarantees that the specified register is used for the operand." This does not always work if the code is inside a template method which gets inlined. For this testcase, imagine a system call invoked by trap #0. It returns a pointer into d0, and clobbers d1/a0/a1. $ cat a.cpp template<class T> class Tpl { public: static long* MySysCall() { register long retval __asm__("d0"); asm ( "trap #0\n\t" "move.l %0,%0\n\t" : "=r"(retval) : : "d1", "a0", "a1" ); return (long*)retval; } }; void f() { long* p = Tpl<char>::MySysCall(); *p = 1; } Note that I added an extra "move.l %0,%0" to see which register is affected to %0. $ g++ -S a.cpp -O1 -o - #NO_APP .file "a.cpp" .text .align 2 .globl _Z1fv .type _Z1fv, @function _Z1fv: .LFB3: link.w %fp,#0 .LCFI0: move.l %a2,-(%sp) .LCFI1: #APP trap #0 move.l %a2,%a2 #NO_APP moveq #1,%d0 move.l %d0,(%a2) move.l (%sp)+,%a2 unlk %fp rts .LFE3: .size _Z1fv, .-_Z1fv .globl __gxx_personality_v0 .ident "GCC: (GNU) 4.2.1" .section .note.GNU-stack,"",@progbits We can see that even though we requested "retval" to be mapped to d0, it has been mapped to a2. The problem does not appear if the code is in a method of a standard class (not a method of a template). Another way to get it work is to add "volatile" to the register variable declaration.
Confirmed, It also fails with 3.3 so this is not a regression. A testcase for PPC: template<class T> class Tpl { public: static long* MySysCall() { register long retval __asm__("r3"); asm ( "trap #0\n\t" "move.l %0,%0\n\t" : "=r"(retval) : : "r4" ); return (long*)retval; } }; void f() { long* p = Tpl<char>::MySysCall(); *p = 1; } Note I did not change the inline-asm's string though so it will not assemble.
Still fails in GCC release 4.2.3
This works for me on x86_64 with 4.3.0.
Same problem with GCC 4.3-20080201 on target i686-pc-linux-gnu
*** Bug 36080 has been marked as a duplicate of this bug. ***
Even if this is not a regression it would be very helpful if g++ would emit a warning that the register allocation will be ignored. Those bugs are subtle.
This is not a regression, however it is a bug, it has to be fixed. Inline assembly coupled with templates is very powerful, however because of this bug it is unusable :-( If I remember well, a workaround is to put the assembly in an inline global function, then call it from the template method.
(In reply to comment #7) > This is not a regression, however it is a bug, it has to be fixed. Inline > assembly coupled with templates is very powerful, however because of this bug > it is unusable :-( I fully agree. I don't know how hard this one is to fix so at least a warning/error would be good to have. Silently ignoring the allocation just causes bugs nobody wants to have.
I can confirm this bug in gcc version 4.5.2 on i686-linux-gnu and in gcc version 4.6.0 on s390x-ibm-linux-gnu
Confirming that the bug still exists on ARM, x86 and x86_64 as of GCC 4.6.3.
Confirming issue still exists for 4.7.4, 4.8.4, 4.9.2 and 5.0 (tested on x86_64).
*** Bug 66393 has been marked as a duplicate of this bug. ***
Created attachment 35723 [details] Experimental fix The attached patch fixes the problem for me. There appear to be two problems: 1. When parsing a template function cp_finish_decl returns before the asmspec is set in a var decl. 2. When expanding the template function the assembler_name is zeroed out.
*** Bug 64951 has been marked as a duplicate of this bug. ***
I can only reconfirm this bug still exists with 8.2.0 after rediscovering it independently. Linux system calls taking 4+ arguments can't be templatized as they require register T3 _a3 asm("r10") = a3; But using "r10" (a3) in assembly input constraints doesn't work either.
Tested on g++ 9.1.0, the bug is still present. Is there any chance of having the Andreas' fix pushed upstream?
Hello, I found a bug, which I think is a duplicate of this one, but am not 100% sure. Below is a minimal piece of code which triggers the bug. All versions of gcc seem to be affected, as seen on compiler explorer, https://godbolt.org/z/jFMj8b, which also shows a difference in gimple, the templated version is missing the explicit naming attributes. Is this the same bug? If so, is there some technical reason why a clear miscompilation persists for as long as it seems to? What I mean is this, if a bug like this persists for this long, it could be taken to mean that the bug is too big for a casual volunteer. Would that be the case? Can someone familiar with the code base tell me what I'd need to know to fix this, e.g. what's wrong with the patch, is it better to fix the patch or start from scratch. $ cat bug.cpp #define DEMONSTRABLY_IDENTICAL \ long ret; \ register long r10 __asm__("r10") = (long)a4; \ __asm__ __volatile__ ("syscall" \ : "=a"(ret) \ : "a"(n), "D"(a1), "S"(a2), "d"(a3), "r"(r10) \ : "rcx", "r11", "memory" \ ); enum class sysnr : long { // accept4 has enough parameters to require extra registers and trigger the bug accept4 = 0x120 }; static __inline long sys_01(long n, long a1, long a2, long a3, long a4) { DEMONSTRABLY_IDENTICAL return ret; } template <sysnr SYS_NR, typename RET, typename T1, typename T2, typename T3, typename T4> RET sys_02(T1 a1, T2 a2, T3 a3, T4 a4) { constexpr long n = (long) SYS_NR; DEMONSTRABLY_IDENTICAL return (RET)ret; } void test_01 () { sys_01( (long)sysnr::accept4, 0xfeed01, 0xfeed02, 0xfeed03, 0xfeed04 ); } void test_02() { sys_02<sysnr::accept4, long>( 0xfeed01, 0xfeed02, 0xfeed03, 0xfeed04 ); } void test_03() { sys_02<sysnr::accept4, long, long, long, long, long>( 0xfeed01, 0xfeed02, 0xfeed03, 0xfeed04 ); } $ g++ -std=c++11 -O1 bug.cpp -c -o bug.c $ objdump -Cd bug.o bug.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <test_01()>: 0: 41 ba 04 ed fe 00 mov $0xfeed04,%r10d 6: b8 20 01 00 00 mov $0x120,%eax b: bf 01 ed fe 00 mov $0xfeed01,%edi 10: be 02 ed fe 00 mov $0xfeed02,%esi 15: ba 03 ed fe 00 mov $0xfeed03,%edx 1a: 0f 05 syscall 1c: c3 retq 000000000000001d <test_02()>: 1d: b8 20 01 00 00 mov $0x120,%eax 22: bf 01 ed fe 00 mov $0xfeed01,%edi 27: be 02 ed fe 00 mov $0xfeed02,%esi 2c: ba 03 ed fe 00 mov $0xfeed03,%edx 31: 41 b8 04 ed fe 00 mov $0xfeed04,%r8d 37: 0f 05 syscall 39: c3 retq 000000000000003a <test_03()>: 3a: b8 20 01 00 00 mov $0x120,%eax 3f: bf 01 ed fe 00 mov $0xfeed01,%edi 44: be 02 ed fe 00 mov $0xfeed02,%esi 49: ba 03 ed fe 00 mov $0xfeed03,%edx 4e: 41 b8 04 ed fe 00 mov $0xfeed04,%r8d 54: 0f 05 syscall 56: c3 retq
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>: https://gcc.gnu.org/g:6bb207b468da36d9d99c63409dc4098514759c90 commit r11-6958-g6bb207b468da36d9d99c63409dc4098514759c90 Author: Jakub Jelinek <jakub@redhat.com> Date: Thu Jan 28 16:13:11 2021 +0100 c++: Fix up handling of register ... asm ("...") vars in templates [PR33661, PR98847] As the testcase shows, for vars appearing in templates, we don't attach the asm spec string to the pattern decls, nor pass it back to cp_finish_decl during instantiation. The following patch does that. 2021-01-28 Jakub Jelinek <jakub@redhat.com> PR c++/33661 PR c++/98847 * decl.c (cp_finish_decl): For register vars with asmspec in templates call set_user_assembler_name and set DECL_HARD_REGISTER. * pt.c (tsubst_expr): When instantiating DECL_HARD_REGISTER vars, pass asmspec_tree to cp_finish_decl. * g++.target/i386/pr98847.C: New test.
The releases/gcc-10 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>: https://gcc.gnu.org/g:cf93f94b3498f3925895fb0bbfd4b64232b9987a commit r10-9323-gcf93f94b3498f3925895fb0bbfd4b64232b9987a Author: Jakub Jelinek <jakub@redhat.com> Date: Thu Jan 28 16:13:11 2021 +0100 c++: Fix up handling of register ... asm ("...") vars in templates [PR33661, PR98847] As the testcase shows, for vars appearing in templates, we don't attach the asm spec string to the pattern decls, nor pass it back to cp_finish_decl during instantiation. The following patch does that. 2021-01-28 Jakub Jelinek <jakub@redhat.com> PR c++/33661 PR c++/98847 * decl.c (cp_finish_decl): For register vars with asmspec in templates call set_user_assembler_name and set DECL_HARD_REGISTER. * pt.c (tsubst_expr): When instantiating DECL_HARD_REGISTER vars, pass asmspec_tree to cp_finish_decl. * g++.target/i386/pr98847.C: New test.
*** Bug 58118 has been marked as a duplicate of this bug. ***
The releases/gcc-9 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>: https://gcc.gnu.org/g:ef5db37cc4e80b229502bea7d6e2daa95ad6f805 commit r9-9412-gef5db37cc4e80b229502bea7d6e2daa95ad6f805 Author: Jakub Jelinek <jakub@redhat.com> Date: Thu Jan 28 16:13:11 2021 +0100 c++: Fix up handling of register ... asm ("...") vars in templates [PR33661, PR98847] As the testcase shows, for vars appearing in templates, we don't attach the asm spec string to the pattern decls, nor pass it back to cp_finish_decl during instantiation. The following patch does that. 2021-01-28 Jakub Jelinek <jakub@redhat.com> PR c++/33661 PR c++/98847 * decl.c (cp_finish_decl): For register vars with asmspec in templates call set_user_assembler_name and set DECL_HARD_REGISTER. * pt.c (tsubst_expr): When instantiating DECL_HARD_REGISTER vars, pass asmspec_tree to cp_finish_decl. * g++.target/i386/pr98847.C: New test. (cherry picked from commit cf93f94b3498f3925895fb0bbfd4b64232b9987a)
The releases/gcc-8 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>: https://gcc.gnu.org/g:712ffc0ad150aadfa5b91f493075e88fd050189f commit r8-10878-g712ffc0ad150aadfa5b91f493075e88fd050189f Author: Jakub Jelinek <jakub@redhat.com> Date: Thu Jan 28 16:13:11 2021 +0100 c++: Fix up handling of register ... asm ("...") vars in templates [PR33661, PR98847] As the testcase shows, for vars appearing in templates, we don't attach the asm spec string to the pattern decls, nor pass it back to cp_finish_decl during instantiation. The following patch does that. 2021-01-28 Jakub Jelinek <jakub@redhat.com> PR c++/33661 PR c++/98847 * decl.c (cp_finish_decl): For register vars with asmspec in templates call set_user_assembler_name and set DECL_HARD_REGISTER. * pt.c (tsubst_expr): When instantiating DECL_HARD_REGISTER vars, pass asmspec_tree to cp_finish_decl. * g++.dg/opt/pr98847.C: New test. (cherry picked from commit cf93f94b3498f3925895fb0bbfd4b64232b9987a)
Fixed.