Understanding a function

Discussion in 'C Programming' started by pembed2012, Apr 5, 2012.

  1. pembed2012

    pembed2012 Guest

    Hi

    Can any-1 explain me what it do this function?

    Thankyou very much


    static inline int __try__(struct sl * sl)
    {
    unsigned int rv;

    __asm__ __volatile__(
    "1: lwarx %0,0,%1\n\
    cmpwi 0,%0,0\n\
    li %0,0\n\
    bne- 2f\n\
    li %0,1\n\
    stwcx. %0,0,%1\n\
    bne- 1b\n\
    isync\n\
    2:" : "=&r"(rv)
    : "r"(sl)
    : "cr0", "memory");

    return rv==1 ?0:EBUSY;
    }
    pembed2012, Apr 5, 2012
    #1
    1. Advertising

  2. pembed2012

    jacob navia Guest

    Le 05/04/12 22:46, pembed2012 a écrit :
    > Hi
    >
    > Can any-1 explain me what it do this function?
    >
    > Thankyou very much
    >
    >
    > static inline int __try__(struct sl * sl)
    > {
    > unsigned int rv;
    >
    > __asm__ __volatile__(
    > "1: lwarx %0,0,%1\n\
    > cmpwi 0,%0,0\n\
    > li %0,0\n\
    > bne- 2f\n\
    > li %0,1\n\
    > stwcx. %0,0,%1\n\
    > bne- 1b\n\
    > isync\n\
    > 2:" : "=&r"(rv)
    > : "r"(sl)
    > : "cr0", "memory");
    >
    > return rv==1 ?0:EBUSY;
    > }


    This horror is called "gnu inline assembler".
    I have always refused to learn it.

    Thanks god this is off topic here since just looking at it
    makes me sick.
    jacob navia, Apr 5, 2012
    #2
    1. Advertising

  3. pembed2012

    BGB Guest

    On 4/5/2012 2:04 PM, jacob navia wrote:
    > Le 05/04/12 22:46, pembed2012 a écrit :
    >> Hi
    >>
    >> Can any-1 explain me what it do this function?
    >>
    >> Thankyou very much
    >>
    >>
    >> static inline int __try__(struct sl * sl)
    >> {
    >> unsigned int rv;
    >>
    >> __asm__ __volatile__(
    >> "1: lwarx %0,0,%1\n\
    >> cmpwi 0,%0,0\n\
    >> li %0,0\n\
    >> bne- 2f\n\
    >> li %0,1\n\
    >> stwcx. %0,0,%1\n\
    >> bne- 1b\n\
    >> isync\n\
    >> 2:" : "=&r"(rv)
    >> : "r"(sl)
    >> : "cr0", "memory");
    >>
    >> return rv==1 ?0:EBUSY;
    >> }

    >
    > This horror is called "gnu inline assembler".
    > I have always refused to learn it.
    >
    > Thanks god this is off topic here since just looking at it
    > makes me sick.
    >


    nevermind that it is also not for x86, looks like it is for PowerPC or
    similar...


    but, yes, I much preferred the MS/Borland/... style of inline-ASM, as at
    least it was generally far less horrid looking...
    BGB, Apr 6, 2012
    #3
  4. pembed2012

    Ian Collins Guest

    On 04/ 6/12 12:54 PM, BGB wrote:
    >
    > nevermind that it is also not for x86, looks like it is for PowerPC or
    > similar...


    Since when has this been an x86 group?

    --
    Ian Collins
    Ian Collins, Apr 6, 2012
    #4
  5. pembed2012

    Alan Curry Guest

    In article <>,
    Robert Wessel <> wrote:
    >
    >>> Le 05/04/12 22:46, pembed2012 a écrit :
    >>>>
    >>>> static inline int __try__(struct sl * sl)
    >>>> {
    >>>> unsigned int rv;
    >>>>
    >>>> __asm__ __volatile__(
    >>>> "1: lwarx %0,0,%1\n\
    >>>> cmpwi 0,%0,0\n\
    >>>> li %0,0\n\
    >>>> bne- 2f\n\
    >>>> li %0,1\n\
    >>>> stwcx. %0,0,%1\n\
    >>>> bne- 1b\n\
    >>>> isync\n\
    >>>> 2:" : "=&r"(rv)
    >>>> : "r"(sl)
    >>>> : "cr0", "memory");
    >>>>
    >>>> return rv==1 ?0:EBUSY;
    >>>> }

    [...]
    >
    >
    >It's PPC, and it's some kind of atomic read/update of a shared
    >variable.


    It's a troll designed to start an argument over where the question should
    have been posted.

    There is a comp.lang.asm.x86, but no comp.lang.asm.ppc and instead of
    comp.lang.asm there's alt.lang.asm which is full of... x86 stuff. Or maybe
    the asm part is completely understood and the C-to-asm binding part is under
    question so it should be gnu.gcc.help or something. We've been left to guess.

    In any case, it's been presented without any context. It probably comes from
    someone's pthread library or kernel, and if that original context was given,
    it would be easy to point to the corresponding documentation, so omitting it
    really creates an information gap to help the budding flamewar grow.

    And it's a trylock operation on a spinlock (with the names stripped down to
    make it harder to read, possibly). It returns 0 if it was able to atomically
    read a 0 and then write a 1 to the integer at the beginning of the struct sl.

    --
    Alan Curry
    Alan Curry, Apr 6, 2012
    #5
  6. pembed2012

    pembed2012 Guest

    On Thu, 05 Apr 2012 21:25:18 -0500, Robert Wessel wrote:

    > On Thu, 05 Apr 2012 17:54:22 -0700, BGB <> wrote:
    >
    >>On 4/5/2012 2:04 PM, jacob navia wrote:
    >>> Le 05/04/12 22:46, pembed2012 a écrit :
    >>>> Hi
    >>>>
    >>>> Can any-1 explain me what it do this function?
    >>>>
    >>>> Thankyou very much
    >>>>
    >>>>
    >>>> static inline int __try__(struct sl * sl) {
    >>>> unsigned int rv;
    >>>>
    >>>> __asm__ __volatile__(
    >>>> "1: lwarx %0,0,%1\n\
    >>>> cmpwi 0,%0,0\n\
    >>>> li %0,0\n\
    >>>> bne- 2f\n\
    >>>> li %0,1\n\
    >>>> stwcx. %0,0,%1\n\
    >>>> bne- 1b\n\
    >>>> isync\n\
    >>>> 2:" : "=&r"(rv)
    >>>> : "r"(sl)
    >>>> : "cr0", "memory");
    >>>>
    >>>> return rv==1 ?0:EBUSY;
    >>>> }
    >>>
    >>> This horror is called "gnu inline assembler". I have always refused to
    >>> learn it.
    >>>
    >>> Thanks god this is off topic here since just looking at it makes me
    >>> sick.
    >>>
    >>>

    >>nevermind that it is also not for x86, looks like it is for PowerPC or
    >>similar...
    >>
    >>
    >>but, yes, I much preferred the MS/Borland/... style of inline-ASM, as at
    >>least it was generally far less horrid looking...

    >
    >
    > It's PPC, and it's some kind of atomic read/update of a shared variable.


    OK thanks, what I really want is exact C code for that function (not
    using asm) ----- or second best will be other asm that works. It will not
    compile on my current platform (64bit Linux/gcc)

    Thankyou
    pembed2012, Apr 6, 2012
    #6
  7. pembed2012

    Kaz Kylheku Guest

    On 2012-04-05, jacob navia <> wrote:
    > Le 05/04/12 22:46, pembed2012 a écrit :
    >> Hi
    >>
    >> Can any-1 explain me what it do this function?
    >>
    >> Thankyou very much
    >>
    >>
    >> static inline int __try__(struct sl * sl)
    >> {
    >> unsigned int rv;
    >>
    >> __asm__ __volatile__(
    >> "1: lwarx %0,0,%1\n\
    >> cmpwi 0,%0,0\n\
    >> li %0,0\n\
    >> bne- 2f\n\
    >> li %0,1\n\
    >> stwcx. %0,0,%1\n\
    >> bne- 1b\n\
    >> isync\n\
    >> 2:" : "=&r"(rv)
    >> : "r"(sl)
    >> : "cr0", "memory");
    >>
    >> return rv==1 ?0:EBUSY;
    >> }

    >
    > This horror is called "gnu inline assembler".
    > I have always refused to learn it.


    You're being pretty silly because it is powerful and useful, allowing inline
    assembly to dove-tail nicely with the code generated by the surrounding C.

    GCC can do things like pick registers for you to use and prepare the operands
    in the registers, and take care to reload cached operands.

    You can advise the compiler that your operation clobbers certain registers or
    memory, or other CPU state. That's very good, and we can see it going on in
    the above example.

    %0 and %1 are virtual registers. 0 is the output operand corresponding to rv,
    %and %1 is an input operand corresponding to sl. GCC will choose those
    registers and generate the code to prepare their values before your assembly
    sequence. Terrific! Without this ability you would have to hard-code the
    registers. And since you don't know if they are being used by the compiler or
    not, you would have to save and restore them which is a waste of cycles
    and cache traffic.

    The code also advises GCC that the instruction sequence has an effect on
    cr0 and on memory (the latter being needed in situations when the compiler
    might have that memory operand cached in a register). The memory
    advice is needed here even though the instruction sequence does *not* in fact
    have any effect on some unmentioned memory operand: this is because it
    is a locking primitive which semantically needs a memory barrier, and this
    memory-clobber has the effect of "spooking" the compiler into providing the
    necessary software memory barrier (register spill, reload) to go with the
    hardware one (isync).

    A few years ago I was working on MIPS and needed some
    atomic instructions, making profitable use of this GCC inline syntax.
    Actually, code very similar to what we are dealing with, but on another
    architecture.

    These instructions sequences were to be used in proprietary code so I didn't
    want to just take GNU-licensed anything. But I had a look.

    Other people were defining rigid code templates for the operations, like
    acquiring a spinlock, or compare-and-swap, etc. (Very much like the above:
    the whole thing is "canned": the load, comparison, store, loop and barrier).

    Instead, I wrapped at a lower level: I created the inline primitives to just do
    the "load_linked" and "store_conditional" MIPS operations, with a C interface.

    Then I wrote the algorithms for things like acquiring a lock or
    compare-swap in C syntax instead of assembly, as easy-to-read little
    inline functions:

    uint32_t x;
    /* loop while lock is busy, or we are not successfully able
    to flip it to busy with a store conditional */
    do {
    x = load_linked(&addr);
    } while (x || store_conditional(&addr, 1))
    read_barrier(); /* make sure we don't read stale cached data inside lock */

    Guess what: GCC was able to optimize and shave some instructions out of stuff
    like that, compared to the canned machine language sequences used in other
    projects.

    This is what I mean by dovetailing: you can do inline assembly on a fine
    granularity and let GCC take it into the mix and optimize with it.
    Kaz Kylheku, Apr 7, 2012
    #7
  8. pembed2012

    Jens Gustedt Guest

    Am 04/07/2012 08:13 PM, schrieb Robert Wessel:
    > Anyway, there may not be any equivalent C at all on your target
    > platform (in fact, that's somewhat likely). There may be extensions,
    > usually in the form of library functions that do the atomic
    > operations, but those are OS specific. Also, I agree with Alan that
    > this is probably conditional entry code to a spinlock, and the
    > structure of spinlocks tends to change drastically from
    > implementation-to-implementation.
    >
    > But, on x86 you ought to be able to do the equivalent with roughly:
    >
    > mov eax,0 ;assuming a 32 bit lock word
    > mov ecx,1
    > lock cmpxchg [sl],ecx
    > ;eax now contain zero if if cmpxchg worked,
    > ;or the old value at [sl] if it didn't
    >
    > The above is Intel syntax, and assumes a 32 bit lock word (use rax for
    > a 64 bit lock word). Translating it to GAS and hacking it into a GCC
    > __asm__ block is left as an exercise for the reader. And as I
    > mentioned, there's no guarantee that spinlocks are implemented in a
    > sufficiently compatible way on *this* platform for the above code to
    > be correct.
    >
    > Alternatively, GCC on Linux should be supporting the
    > __sync_val_compare_and_swap() atomic builtin, which could be used to
    > do the same thing.


    atomic operations come with the new C11 standard and gcc is moving
    quickly towards implementations of these. The most appropriate
    gcc builtins to implement a spinlock are probably

    __sync_lock_test_and_set and __sync_lock_release

    that implement just the minimal operations and minimal memory
    consistency that is needed for such locks.

    Since gcc 4.7 there is a new family of builtins with prefix __atomic_
    that implement the new atomic functionalities more closely.

    The __sync builtins also come with most other compilers/platforms that
    try to be gcc compatible. For other compilers, implementing just the
    atomic primitives is usually not a big deal and you should find code
    for the processor of your liking easily on the net.

    Jens
    Jens Gustedt, Apr 7, 2012
    #8
  9. pembed2012

    BartC Guest

    "Kaz Kylheku" <> wrote in message
    news:...
    > On 2012-04-05, jacob navia <> wrote:


    >>> __asm__ __volatile__(
    >>> "1: lwarx %0,0,%1\n\
    >>> cmpwi 0,%0,0\n\
    >>> li %0,0\n\
    >>> bne- 2f\n\
    >>> li %0,1\n\
    >>> stwcx. %0,0,%1\n\
    >>> bne- 1b\n\
    >>> isync\n\
    >>> 2:" : "=&r"(rv)
    >>> : "r"(sl)
    >>> : "cr0", "memory");
    >>>
    >>> return rv==1 ?0:EBUSY;
    >>> }

    >>
    >> This horror is called "gnu inline assembler".
    >> I have always refused to learn it.

    >
    > You're being pretty silly because it is powerful and useful, allowing
    > inline
    > assembly to dove-tail nicely with the code generated by the surrounding C.
    >
    > GCC can do things like pick registers for you to use and prepare the
    > operands
    > in the registers, and take care to reload cached operands.


    This is all well and good (although you are then starting to work with a
    somewhat different language than pure assembly). But why didn't they make
    the extra effort to make their inline asm easy on the eye, and comfortable
    to work with? Why do those last ":" lines need to be so cryptic; would it
    kill someone to have to type a keyword?

    --
    Bartc
    BartC, Apr 7, 2012
    #9
  10. pembed2012

    jacob navia Guest

    Le 07/04/12 21:08, Kaz Kylheku a écrit :
    > On 2012-04-05, jacob navia<> wrote:
    >> Le 05/04/12 22:46, pembed2012 a écrit :
    >>> Hi
    >>>
    >>> Can any-1 explain me what it do this function?
    >>>
    >>> Thankyou very much
    >>>
    >>>
    >>> static inline int __try__(struct sl * sl)
    >>> {
    >>> unsigned int rv;
    >>>
    >>> __asm__ __volatile__(
    >>> "1: lwarx %0,0,%1\n\
    >>> cmpwi 0,%0,0\n\
    >>> li %0,0\n\
    >>> bne- 2f\n\
    >>> li %0,1\n\
    >>> stwcx. %0,0,%1\n\
    >>> bne- 1b\n\
    >>> isync\n\
    >>> 2:" : "=&r"(rv)
    >>> : "r"(sl)
    >>> : "cr0", "memory");
    >>>
    >>> return rv==1 ?0:EBUSY;
    >>> }

    >>
    >> This horror is called "gnu inline assembler".
    >> I have always refused to learn it.

    >
    > You're being pretty silly because it is powerful and useful, allowing inline
    > assembly to dove-tail nicely with the code generated by the surrounding C.
    >
    > GCC can do things like pick registers for you to use and prepare the operands
    > in the registers, and take care to reload cached operands.
    >
    > You can advise the compiler that your operation clobbers certain registers or
    > memory, or other CPU state. That's very good, and we can see it going on in
    > the above example.
    >


    Then, why not like this?

    __asm__ __volatile__ (register arg1, register arg2)
    {
    loop:
    lwarx arg1,0,arg2
    cmpwi 0,arg1,0
    li arg1,0
    bne- endLoop
    li arg1,1
    stwcx. arg1,0,arg2
    bne loop
    isync
    endLoop:
    declarations
    output r:ANY write_only early_clobber subset:r(rv)
    subset:r(sl)
    clobbers:cr0
    clobbers:memory

    }

    This would have needed minimal modifications to the existing parser:
    instead of parsing "=" it would parse ANY... big deal.

    But no, they decided to make it as obscure as possible and they succeeded.
    jacob navia, Apr 8, 2012
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Wenjie
    Replies:
    3
    Views:
    372
    Victor Bazarov
    Jul 26, 2003
  2. Replies:
    5
    Views:
    379
    Earl Purple
    Sep 21, 2007
  3. Sri Harsha Dandibhotla

    Understanding a function declaration.

    Sri Harsha Dandibhotla, Jun 16, 2008, in forum: C Programming
    Replies:
    10
    Views:
    433
    Sri Harsha Dandibhotla
    Jun 16, 2008
  4. Hussein B
    Replies:
    2
    Views:
    217
  5. Chris Saunders

    Help understanding this function

    Chris Saunders, Mar 25, 2009, in forum: C++
    Replies:
    15
    Views:
    608
Loading...

Share This Page