[Bug inline-asm/88952] New: [powerpc] asm input from C expression with type larger than GPRs loads wrong value
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88952 Bug ID: 88952 Summary: [powerpc] asm input from C expression with type larger than GPRs loads wrong value Product: gcc Version: 4.2.2 Status: UNCONFIRMED Severity: normal Priority: P3 Component: inline-asm Assignee: unassigned at gcc dot gnu.org Reporter: christopher.leonard at abaco dot com Target Milestone: --- When giving a C expression as input to an extended asm statement the wrong value is loaded if the type happens to be 64-bit (with 32-bit powerpc target). Happens regardless of optimization level, use of 'volatile'. Also happens in compiler explorer with GCC 4.8.5 <https://godbolt.org/z/hZAEEy>. This subtle behavior is not too hard to track down but will probably defy the expectations of the programmer, and could be introduced into a program with seemingly innocuous changes that result in the overall expression type being larger. I assume this is a bug and not the intention of the input operand feature. If this is the intended functionality I would suggest adding a warning for this situation. Source "ex.c": void bad_asm(void) { asm volatile ("stw %0, 50(0)" : :"r"(20ull)); } Build command: /opt/eldk/4.2/usr/ppc-linux/bin/gcc -mregnames -O3 -c -o ex.o ex.c Disassembly: ex.o: file format elf32-powerpc Disassembly of section .text: : 0: 39 20 00 00 li r9,0 4: 39 40 00 14 li r10,20 8: 91 20 00 32 stw r9,50(0) c: 4e 80 00 20 blr Output of gcc -v: Reading specs from /opt/eldk/4.2/usr/bin/../lib/gcc/powerpc-linux/4.2.2/specs Target: powerpc-linux Configured with: /opt/eldk/build/ppc-2008-04-01/work/usr/src/denx/BUILD/crosstool-0.43/build/gcc-4.2.2-glibc-20070515T2025-eldk/powerpc-linux/gcc-4.2.2/configure --target=powerpc-linux --host=i686-host_pc-linux-gnu --prefix=/var/tmp/eldk.UZpAG7/usr/crosstool/gcc-4.2.2-glibc-20070515T2025-eldk/powerpc-linux --disable-hosted-libstdcxx --with-headers=/var/tmp/eldk.UZpAG7/usr/crosstool/gcc-4.2.2-glibc-20070515T2025-eldk/powerpc-linux/powerpc-linux/include --with-local-prefix=/var/tmp/eldk.UZpAG7/usr/crosstool/gcc-4.2.2-glibc-20070515T2025-eldk/powerpc-linux/powerpc-linux --disable-nls --enable-threads=posix --enable-symvers=gnu --enable-__cxa_atexit --enable-languages=c,c++,java --enable-shared --enable-c99 --enable-long-long --without-x Thread model: posix gcc version 4.2.2
[Bug inline-asm/88952] [powerpc] asm input from C expression with type larger than GPRs loads wrong value
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88952 --- Comment #2 from Christopher Leonard --- Surely then in the example if r9 is loaded with high and r10 with low then %0 should be r10, not r9?
[Bug inline-asm/88952] [powerpc] asm input from C expression with type larger than GPRs loads wrong value
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88952 --- Comment #3 from Christopher Leonard --- I understand it has to split it, the problem is that %0 defaults to the register holding the most-significant part of the integer. Is this really the desired behavior?
[Bug target/88952] The asm operator modifiers for rs6000 should be documented like they are for x86
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88952 --- Comment #5 from Christopher Leonard --- Is the order at least consistant with x86-32? i.e. if you give a 64-bit input operand to inline assembly the order is hi:lo? I'm worried this is a bizarre convention imposed on high endian architectures.
[Bug target/88952] The asm operator modifiers for rs6000 should be documented like they are for x86
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88952 --- Comment #9 from Christopher Leonard --- (In reply to Andrew Pinski from comment #6) > Yes the order is always hi:lo (reg:reg+1) on all targets I know of This is definitely not the natural choice (on any platform: I agree, endianness is irrelevant here) so I would recommend documenting this as well, and potentially recommending in the docs to explicitly cast e.g. a parameter for a function-style macro used as an input operand expression for inline asm, (%L0 is no help when the size is unknown, it seems to select the "next" register when you give a 32-bit type, which isn't even loaded with a value in the generated PPC assembly). This is how the code messed up for me, I wrote a macro function to generate MTSPR instructions for a given SPR and load value (this is needed since the SPR number used in MTSPR is immediate, there is not alternative where you can take the SPR from a register). One of the constants I used in the calculation of an SPR's load value became a 64-bit type in a later code change, making the input operand 64-bit instead of 32-bit, breaking my code.
[Bug target/88952] The asm operator modifiers for rs6000 should be documented like they are for x86
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88952 --- Comment #10 from Christopher Leonard --- Getting contradictory statements now: >reg:reg+1 maps to lo:hi on x86. >On x86, we don't allow register pairs in asm at all. Not allowing, or printing a warning, is much better behavior than what I have been getting on PPC.
[Bug target/88952] The asm operator modifiers for rs6000 should be documented like they are for x86
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88952 --- Comment #13 from Christopher Leonard --- (In reply to Segher Boessenkool from comment #12) > the oldest GCC still supported is GCC 7. Apologies if it was not clear, but I am just reporting the issue for posterity and it was not easy for me to check on a newer version at the time. If you are wondering why people use old versions of GCC, my usecase is working on a codebase where consistent output is desirable over new features or bugfixes, going back to when 4.x was new.