[llvm-bugs] [Bug 39240] New: clang/llvm looses restrictness, resulting in wrong code

via llvm-bugs llvm-bugs at lists.llvm.org
Wed Oct 10 00:38:07 PDT 2018


https://bugs.llvm.org/show_bug.cgi?id=39240

            Bug ID: 39240
           Summary: clang/llvm looses restrictness, resulting in wrong
                    code
           Product: libraries
           Version: trunk
          Hardware: PC
                OS: Windows NT
            Status: NEW
          Severity: enhancement
          Priority: P
         Component: Scalar Optimizations
          Assignee: unassignedbugs at nondot.org
          Reporter: jeroen.dobbelaere at synopsys.com
                CC: llvm-bugs at lists.llvm.org

clang/llvm implements argument restrictness by putting a 'noalias' on the the
restrict argument. When alias analysis traces the base object of a pointer to
two different base objects of which one is marked with 'noalias', it concludes
that these pointers do not alias.

This mapping results in wrong behavior according to the restrict specification:
(or my interpretation of it is wrong ;) ):

6.7.3.1, 4: 'every other lvalue used to access the value of X shall also have
its address based on P.'

where P is the restrict annotated pointer. This means that in following code
*tmp and *pA might alias:

  // Assume pA and pB point to the same set of objects X
  // restrict rules dictate that all accesses in the scope must happen through
  // the restrict pointer (pA) or a pointer based on it.
  int foo(int* __restrict pA, int* pB, int* pC) {
    int *tmp=pA; // tmp is based on pA 
    pA=pB; // pB also points into the set of objects X, but, accessing it must
happen through a pointer based on pA

    *tmp=42; // tmp points into the set of objects X
    *pA=43;  // pA points into the set of objects X
    *pC=99;  // pC does not point into the set of objects X
    return *tmp; // fail: needs a load !!! (either 42 or 43)
  }

results in:
  define dso_local i32 @foo(i32* noalias nocapture, i32* nocapture, i32*
nocapture) local_unnamed_addr #0 {
    store i32 42, i32* %0, align 4, !tbaa !2
    store i32 43, i32* %1, align 4, !tbaa !2
    store i32 99, i32* %2, align 4, !tbaa !2
    ret i32 42 ; WRONG! %0 must be reloaded
  }

But, clang/llvm assumes that *tmp and *pA will never alias, and propagates the
42.

NOTES:
- gcc has the same issue
- icc has the correct behavior
- for this example, moving the __restrict from pA to the pC argument, results
in equivalent code with the correct behavior.
- llvm + Hal Finkels local restrict patches has the correct behavior, IF the
restrict is made local:

  int foo(int* pA_, int* pB, int* pC) {
    int* __restrict pA=pA_;
    int *tmp=pA; // tmp is based on pA 
    ....

results in:
  define dso_local i32 @foo(i32* nocapture %pA_, i32* nocapture %pB, i32*
nocapture %pC) local_unnamed_addr #1 {
  entry:
    %0 = tail call i32* @llvm.noalias.p0i32(i32* %pA_, metadata !6)
    store i32 42, i32* %0, align 4, !tbaa !2, !noalias !6
    %1 = tail call i32* @llvm.noalias.p0i32(i32* %pB, metadata !6)
    store i32 43, i32* %1, align 4, !tbaa !2, !noalias !6
    store i32 99, i32* %pC, align 4, !tbaa !2, !noalias !6
    %2 = load i32, i32* %0, align 4, !tbaa !2, !noalias !6
    ret i32 %2
  }

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20181010/c7f450fe/attachment-0001.html>


More information about the llvm-bugs mailing list