Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=02828845dda5ccf921ab2557c6ca17b6e7fc70e2
Commit:     02828845dda5ccf921ab2557c6ca17b6e7fc70e2
Parent:     386b0ce25ae16eb1d25db6a004c959e3a9003ce3
Author:     Nicolas Pitre <[EMAIL PROTECTED]>
AuthorDate: Wed Dec 13 18:39:26 2006 +0100
Committer:  Russell King <[EMAIL PROTECTED]>
CommitDate: Wed Dec 13 18:30:20 2006 +0000

    [ARM] 4016/1: prefetch macro is wrong wrt gcc's "delete-null-pointer-checks"
     optimization
    
    The gcc manual says:
    
    |`-fdelete-null-pointer-checks'
    |     Use global dataflow analysis to identify and eliminate useless
    |     checks for null pointers.  The compiler assumes that dereferencing
    |     a null pointer would have halted the program.  If a pointer is
    |     checked after it has already been dereferenced, it cannot be null.
    |     Enabled at levels `-O2', `-O3', `-Os'.
    
    Now the problem can be seen with this test case:
    
    #include <linux/prefetch.h>
    extern void bar(char *x);
    void foo(char *x)
    {
        prefetch(x);
        if (x)
                bar(x);
    }
    
    Because the constraint to the inline asm used in the prefetch() macro is
    a memory operand, gcc assumes that the asm code does dereference the
    pointer and the delete-null-pointer-checks optimization kicks in.
    Inspection of generated assembly for the above example shows that bar()
    is indeed called unconditionally without any test on the value of x.
    
    Of course in the prefetch case there is no real dereference and it
    cannot be assumed that a null pointer would have been caught at that
    point. This causes kernel oopses with constructs like
    hlist_for_each_entry() where the list's 'next' content is prefetched
    before the pointer is tested against NULL, and only when gcc feels like
    applying this optimization which doesn't happen all the time with more
    complex code.
    
    It appears that the way to prevent delete-null-pointer-checks
    optimization to occur in this case is to make prefetch() into a static
    inline function instead of a macro. At least this is what is done on
    x86_64 where a similar inline asm memory operand is used (I presume they
    would have seen the same problem if it didn't work) and resulting code
    for the above example confirms that.
    
    An alternative would consist of replacing the memory operand by a
    register operand containing the pointer, and use the addressing mode
    explicitly in the asm template. But that would be less optimal than an
    offsettable memory reference.
    
    Signed-off-by: Nicolas Pitre <[EMAIL PROTECTED]>
    Signed-off-by: Russell King <[EMAIL PROTECTED]>
---
 include/asm-arm/processor.h |   16 ++++++++--------
 1 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/include/asm-arm/processor.h b/include/asm-arm/processor.h
index b442e8e..1bbf161 100644
--- a/include/asm-arm/processor.h
+++ b/include/asm-arm/processor.h
@@ -103,14 +103,14 @@ extern int kernel_thread(int (*fn)(void *), void *arg, 
unsigned long flags);
 #if __LINUX_ARM_ARCH__ >= 5
 
 #define ARCH_HAS_PREFETCH
-#define prefetch(ptr)                          \
-       ({                                      \
-               __asm__ __volatile__(           \
-               "pld\t%0"                       \
-               :                               \
-               : "o" (*(char *)(ptr))          \
-               : "cc");                        \
-       })
+static inline void prefetch(const void *ptr)
+{
+       __asm__ __volatile__(
+               "pld\t%0"
+               :
+               : "o" (*(char *)ptr)
+               : "cc");
+}
 
 #define ARCH_HAS_PREFETCHW
 #define prefetchw(ptr) prefetch(ptr)
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to