1; RUN: opt -passes='print<access-info>' -disable-output < %s 2>&1 | FileCheck %s 2 3target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 4 5; Check that the compile-time-unknown depenendece-distance is resolved 6; statically. Due to the non-unit stride of the accesses in this testcase 7; we are currently not able to create runtime dependence checks, and therefore 8; if we don't resolve the dependence statically we cannot vectorize the loop. 9; 10; Specifically in this example, during dependence analysis we get 6 unknown 11; dependence distances between the 8 real/imaginary accesses below: 12; dist = 8*D, 4+8*D, -4+8*D, -8*D, 4-8*D, -4-8*D. 13; At compile time we can prove for all of the above that |dist|>loopBound*step 14; (where the step is 8bytes, and the loopBound is D-1), and thereby conclude 15; that there are no dependencies (without runtime tests): 16; |8*D|>8*D-8, |4+8*D|>8*D-8, |-4+8*D|>8*D-8, etc. 17 18; #include <stdlib.h> 19; class Complex { 20; private: 21; float real_; 22; float imaginary_; 23; 24; public: 25; Complex() : real_(0), imaginary_(0) { } 26; Complex(float real, float imaginary) : real_(real), imaginary_(imaginary) { } 27; Complex(const Complex &rhs) : real_(rhs.real()), imaginary_(rhs.imaginary()) { } 28; 29; inline float real() const { return real_; } 30; inline float imaginary() const { return imaginary_; } 31; 32; Complex operator+(const Complex& rhs) const 33; { 34; return Complex(real_ + rhs.real_, imaginary_ + rhs.imaginary_); 35; } 36; 37; Complex operator-(const Complex& rhs) const 38; { 39; return Complex(real_ - rhs.real_, imaginary_ - rhs.imaginary_); 40; } 41; }; 42; 43; void Test(Complex *out, size_t size) 44; { 45; size_t D = size / 2; 46; for (size_t offset = 0; offset < D; ++offset) 47; { 48; Complex t0 = out[offset]; 49; Complex t1 = out[offset + D]; 50; out[offset] = t1 + t0; 51; out[offset + D] = t0 - t1; 52; } 53; } 54 55; CHECK-LABEL: Test 56; CHECK: Memory dependences are safe 57 58 59%class.Complex = type { float, float } 60 61define void @Test(ptr nocapture %out, i64 %size) local_unnamed_addr { 62entry: 63 %div = lshr i64 %size, 1 64 %cmp47 = icmp eq i64 %div, 0 65 br i1 %cmp47, label %for.cond.cleanup, label %for.body.preheader 66 67for.body.preheader: 68 br label %for.body 69 70for.cond.cleanup.loopexit: 71 br label %for.cond.cleanup 72 73for.cond.cleanup: 74 ret void 75 76for.body: 77 %offset.048 = phi i64 [ %inc, %for.body ], [ 0, %for.body.preheader ] 78 %0 = getelementptr inbounds %class.Complex, ptr %out, i64 %offset.048, i32 0 79 %1 = load float, ptr %0, align 4 80 %imaginary_.i.i = getelementptr inbounds %class.Complex, ptr %out, i64 %offset.048, i32 1 81 %2 = load float, ptr %imaginary_.i.i, align 4 82 %add = add nuw i64 %offset.048, %div 83 %3 = getelementptr inbounds %class.Complex, ptr %out, i64 %add, i32 0 84 %4 = load float, ptr %3, align 4 85 %imaginary_.i.i28 = getelementptr inbounds %class.Complex, ptr %out, i64 %add, i32 1 86 %5 = load float, ptr %imaginary_.i.i28, align 4 87 %add.i = fadd fast float %4, %1 88 %add4.i = fadd fast float %5, %2 89 store float %add.i, ptr %0, align 4 90 store float %add4.i, ptr %imaginary_.i.i, align 4 91 %sub.i = fsub fast float %1, %4 92 %sub4.i = fsub fast float %2, %5 93 store float %sub.i, ptr %3, align 4 94 store float %sub4.i, ptr %imaginary_.i.i28, align 4 95 %inc = add nuw nsw i64 %offset.048, 1 96 %exitcond = icmp eq i64 %inc, %div 97 br i1 %exitcond, label %for.cond.cleanup.loopexit, label %for.body 98} 99