This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: inline asm in an inline function


>>>>> "Geoff" == Geoff Keating <geoffk@geoffk.org> writes:

 > aldyh@redhat.com (Aldy Hernandez) writes:
 >> a customer is having problems with some inline asms.  they have the
 >> following code that is supposed to clobber %r4:
 >> 
 >> unsigned inline flying_carpet( ) {
 >> unsigned tmp ;
 >> asm (" mfmsr %0;"
 >> " rlwinm %%r4,%0,0,17,15;"
 >> " mtmsr %%r4"
 >> : "=r" (tmp) /* outputs */
 >> : /* no inputs */
 >> : "%r4", "%r5" /* trashes r4 */);	<-- clobber %r4, %r5 please
 >> return (int) tmp;
 >> }
 >> 
 >> however, gcc doesn't respect that and expects %r4 to be live across the
 >> asm:
 >> 
 >> lwz %r0,0(%r4)		<-- use of %r4
 >> cmpwi %cr0,%r0,-1
 >> bc 12,2,.L7
 >> mfmsr %r29; rlwinm %r4,%r29,0,17,15; mtmsr %r4
 >> .L8:
 >> lwz %r0,0(%r4)		<-- use of r4 (boo hiss!)
 >> 
 >> is this actually a bug, or should they be using "asm volatile" (cuz that
 >> for sure fixes the problem)?

 > That seems to be a bug.  Most likely, the '%' is confusing GCC.

Actually, I don't think that's the case.

gcc translates the above into:

(insn/i 79 78 80 (parallel[ 
            (set (reg/v:SI 90)
                (asm_operands (" mfmsr %0; rlwinm %%r4,%0,0,17,15; mtmsr
%%r4") ("=r") 0[ ] 
                    [ ]  ("test.cc") 8))
            (clobber (reg:QI 5 r5))
            (clobber (reg:QI 4 r4))
        ] ) -1 (nil)
    (nil))

the clobbers are exactly what we need, however later on, scan_loop wants
to combine these two insns:

(insn/i 79 78 80 (parallel[ 
            (set (reg/v:SI 90)
                (asm_operands (" mfmsr %0; rlwinm %%r4,%0,0,17,15; mtmsr
%%r4") ("=r") 0[ ] 
                    [ ]  ("test.cc") 8))
            (clobber (reg:QI 5 r5))
            (clobber (reg:QI 4 r4))
        ] ) -1 (nil)
    (nil))

(insn/i 80 79 83 (set (reg/v:SI 89)
        (reg/v:SI 90)) 541 {movsi+1} (nil)
    (nil))

the code in loop that wants to do it is around this:

         Therefore, if this register is marked as being used exactly
        once if we are in a loop with calls (a "large loop"),see if
        we can replace the usage of this register with the source
        of this SET.  If we can, delete this insn. 


the prob is that replace_rtx() is called with a "to" of:

(asm_operands (" mfmsr %0; rlwinm %%r4,%0,0,17,15; mtmsr %%r4") ("=r")
0[ ] 
    [ ]  ("test.cc") 8)

we have lost our clobbers (!@#$), because scan_loop did:

     if (GET_CODE (p) == INSN
          && (set = single_set (p)) <-- single_set(), boo hiss

and single_set ripped the original parallel of the clobbers because
that is what single_set is supposed to do.

so.. what should i do?

i'm thinking i can:

1. save the clobbers, or whatever follows the set in a parallel
2. do the replace_rtx
3. parallelize the replaced insn and add the clobbers to the resulting
insn.

so basically, remember what was clobbered and add it later after
scan_loop combined the insns.

ideas welcome.

cheers
aldy


--
Aldy Hernandez                  E-mail: aldyh@redhat.com
Professional Gypsy
Red Hat, Inc.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]