288 lines · plain
1; RUN: opt -passes='print<access-info>' -disable-output < %s 2>&1 | FileCheck %s2 3target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"4target triple = "aarch64"5 6; 3 reads and 3 writes should need 12 memchecks7; CHECK: function 'testf':8; CHECK: Memory dependences are safe with run-time checks9 10; Memory dependencies have labels starting from 0, so in11; order to verify that we have n checks, we look for12; (n-1): and not n:.13 14; CHECK: Run-time memory checks:15; CHECK-NEXT: Check 0:16; CHECK: Check 11:17; CHECK-NOT: Check 12:18 19define void @testf(ptr %a,20 ptr %b,21 ptr %c,22 ptr %d,23 ptr %e,24 ptr %f) {25entry:26 br label %for.body27 28for.body: ; preds = %for.body, %entry29 %ind = phi i64 [ 0, %entry ], [ %add, %for.body ]30 31 %add = add nuw nsw i64 %ind, 132 33 %arrayidxA = getelementptr inbounds i16, ptr %a, i64 %ind34 %loadA = load i16, ptr %arrayidxA, align 235 36 %arrayidxB = getelementptr inbounds i16, ptr %b, i64 %ind37 %loadB = load i16, ptr %arrayidxB, align 238 39 %arrayidxC = getelementptr inbounds i16, ptr %c, i64 %ind40 %loadC = load i16, ptr %arrayidxC, align 241 42 %mul = mul i16 %loadB, %loadA43 %mul1 = mul i16 %mul, %loadC44 45 %arrayidxD = getelementptr inbounds i16, ptr %d, i64 %ind46 store i16 %mul1, ptr %arrayidxD, align 247 48 %arrayidxE = getelementptr inbounds i16, ptr %e, i64 %ind49 store i16 %mul, ptr %arrayidxE, align 250 51 %arrayidxF = getelementptr inbounds i16, ptr %f, i64 %ind52 store i16 %mul1, ptr %arrayidxF, align 253 54 %exitcond = icmp eq i64 %add, 2055 br i1 %exitcond, label %for.end, label %for.body56 57for.end: ; preds = %for.body58 ret void59}60 61; The following (testg and testh) check that we can group62; memory checks of accesses which differ by a constant value.63; Both tests are based on the following C code:64;65; void testh(short *a, short *b, short *c) {66; unsigned long ind = 0;67; for (unsigned long ind = 0; ind < 20; ++ind) {68; c[2 * ind] = a[ind] * a[ind + 1];69; c[2 * ind + 1] = a[ind] * a[ind] * b[ind];70; }71; }72;73; It is sufficient to check the intervals74; [a, a + 21], [b, b + 20] against [c, c + 41].75 76; 3 reads and 2 writes - two of the reads can be merged,77; and the writes can be merged as well. This gives us a78; total of 2 memory checks.79 80; CHECK: function 'testg':81 82; CHECK: Run-time memory checks:83; CHECK-NEXT: Check 0:84; CHECK-NEXT: Comparing group GRP0:85; CHECK-NEXT: %arrayidxC1 = getelementptr inbounds i16, ptr %c, i64 %store_ind_inc86; CHECK-NEXT: %arrayidxC = getelementptr inbounds i16, ptr %c, i64 %store_ind87; CHECK-NEXT: Against group GRP1:88; CHECK-NEXT: %arrayidxA1 = getelementptr inbounds i16, ptr %a, i64 %add89; CHECK-NEXT: %arrayidxA = getelementptr inbounds i16, ptr %a, i64 %ind90; CHECK-NEXT: Check 1:91; CHECK-NEXT: Comparing group GRP0:92; CHECK-NEXT: %arrayidxC1 = getelementptr inbounds i16, ptr %c, i64 %store_ind_inc93; CHECK-NEXT: %arrayidxC = getelementptr inbounds i16, ptr %c, i64 %store_ind94; CHECK-NEXT: Against group GRP2:95; CHECK-NEXT: %arrayidxB = getelementptr inbounds i16, ptr %b, i64 %ind96; CHECK-NEXT: Grouped accesses:97; CHECK-NEXT: Group GRP0:98; CHECK-NEXT: (Low: %c High: (80 + %c))99; CHECK-NEXT: Member: {(2 + %c)<nuw>,+,4}100; CHECK-NEXT: Member: {%c,+,4}101; CHECK-NEXT: Group GRP1:102; CHECK-NEXT: (Low: %a High: (42 + %a))103; CHECK-NEXT: Member: {(2 + %a)<nuw>,+,2}104; CHECK-NEXT: Member: {%a,+,2}105; CHECK-NEXT: Group GRP2:106; CHECK-NEXT: (Low: %b High: (40 + %b))107; CHECK-NEXT: Member: {%b,+,2}108 109define void @testg(ptr %a,110 ptr %b,111 ptr %c) {112entry:113 br label %for.body114 115for.body: ; preds = %for.body, %entry116 %ind = phi i64 [ 0, %entry ], [ %add, %for.body ]117 %store_ind = phi i64 [ 0, %entry ], [ %store_ind_next, %for.body ]118 119 %add = add nuw nsw i64 %ind, 1120 %store_ind_inc = add nuw nsw i64 %store_ind, 1121 %store_ind_next = add nuw nsw i64 %store_ind_inc, 1122 123 %arrayidxA = getelementptr inbounds i16, ptr %a, i64 %ind124 %loadA = load i16, ptr %arrayidxA, align 2125 126 %arrayidxA1 = getelementptr inbounds i16, ptr %a, i64 %add127 %loadA1 = load i16, ptr %arrayidxA1, align 2128 129 %arrayidxB = getelementptr inbounds i16, ptr %b, i64 %ind130 %loadB = load i16, ptr %arrayidxB, align 2131 132 %mul = mul i16 %loadA, %loadA1133 %mul1 = mul i16 %mul, %loadB134 135 %arrayidxC = getelementptr inbounds i16, ptr %c, i64 %store_ind136 store i16 %mul1, ptr %arrayidxC, align 2137 138 %arrayidxC1 = getelementptr inbounds i16, ptr %c, i64 %store_ind_inc139 store i16 %mul, ptr %arrayidxC1, align 2140 141 %exitcond = icmp eq i64 %add, 20142 br i1 %exitcond, label %for.end, label %for.body143 144for.end: ; preds = %for.body145 ret void146}147 148; 3 reads and 2 writes - the writes can be merged into a single149; group, but the GEPs used for the reads are not marked as inbounds.150; We can still merge them because we are using a unit stride for151; accesses, so we cannot overflow the GEPs.152 153; CHECK: function 'testh':154; CHECK: Run-time memory checks:155; CHECK-NEXT: Check 0:156; CHECK-NEXT: Comparing group GRP0:157; CHECK-NEXT: %arrayidxC1 = getelementptr inbounds i16, ptr %c, i64 %store_ind_inc158; CHECK-NEXT: %arrayidxC = getelementptr inbounds i16, ptr %c, i64 %store_ind159; CHECK-NEXT: Against group GRP1:160; CHECK-NEXT: %arrayidxA1 = getelementptr i16, ptr %a, i64 %add161; CHECK-NEXT: %arrayidxA = getelementptr i16, ptr %a, i64 %ind162; CHECK-NEXT: Check 1:163; CHECK-NEXT: Comparing group GRP0:164; CHECK-NEXT: %arrayidxC1 = getelementptr inbounds i16, ptr %c, i64 %store_ind_inc165; CHECK-NEXT: %arrayidxC = getelementptr inbounds i16, ptr %c, i64 %store_ind166; CHECK-NEXT: Against group GRP2:167; CHECK-NEXT: %arrayidxB = getelementptr i16, ptr %b, i64 %ind168; CHECK-NEXT: Grouped accesses:169; CHECK-NEXT: Group GRP0:170; CHECK-NEXT: (Low: %c High: (80 + %c))171; CHECK-NEXT: Member: {(2 + %c)<nuw>,+,4}172; CHECK-NEXT: Member: {%c,+,4}173; CHECK-NEXT: Group GRP1:174; CHECK-NEXT: (Low: %a High: (42 + %a))175; CHECK-NEXT: Member: {(2 + %a),+,2}176; CHECK-NEXT: Member: {%a,+,2}177; CHECK-NEXT: Group GRP2:178; CHECK-NEXT: (Low: %b High: (40 + %b))179; CHECK-NEXT: Member: {%b,+,2}180 181define void @testh(ptr %a,182 ptr %b,183 ptr %c) {184entry:185 br label %for.body186 187for.body: ; preds = %for.body, %entry188 %ind = phi i64 [ 0, %entry ], [ %add, %for.body ]189 %store_ind = phi i64 [ 0, %entry ], [ %store_ind_next, %for.body ]190 191 %add = add nuw nsw i64 %ind, 1192 %store_ind_inc = add nuw nsw i64 %store_ind, 1193 %store_ind_next = add nuw nsw i64 %store_ind_inc, 1194 195 %arrayidxA = getelementptr i16, ptr %a, i64 %ind196 %loadA = load i16, ptr %arrayidxA, align 2197 198 %arrayidxA1 = getelementptr i16, ptr %a, i64 %add199 %loadA1 = load i16, ptr %arrayidxA1, align 2200 201 %arrayidxB = getelementptr i16, ptr %b, i64 %ind202 %loadB = load i16, ptr %arrayidxB, align 2203 204 %mul = mul i16 %loadA, %loadA1205 %mul1 = mul i16 %mul, %loadB206 207 %arrayidxC = getelementptr inbounds i16, ptr %c, i64 %store_ind208 store i16 %mul1, ptr %arrayidxC, align 2209 210 %arrayidxC1 = getelementptr inbounds i16, ptr %c, i64 %store_ind_inc211 store i16 %mul, ptr %arrayidxC1, align 2212 213 %exitcond = icmp eq i64 %add, 20214 br i1 %exitcond, label %for.end, label %for.body215 216for.end: ; preds = %for.body217 ret void218}219 220; Don't merge pointers if we need to perform a check against a pointer221; to the same underlying object (doing so would emit a check that could be222; falsely invalidated) For example, in the following loop:223;224; for (i = 0; i < 5000; ++i)225; a[i + offset] = a[i] + a[i + 10000]226;227; we should not merge the intervals associated with the reads (0,5000) and228; (10000, 15000) into (0, 15000) as this will pottentially fail the check229; against the interval associated with the write.230;231; We cannot have this check unless ShouldRetryWithRuntimeCheck is set,232; and therefore the grouping algorithm would create a separate group for233; each pointer.234 235; CHECK: function 'testi':236; CHECK: Run-time memory checks:237; CHECK-NEXT: Check 0:238; CHECK-NEXT: Comparing group GRP0:239; CHECK-NEXT: %storeidx = getelementptr inbounds i16, ptr %a, i64 %store_ind240; CHECK-NEXT: Against group GRP1:241; CHECK-NEXT: %arrayidxA1 = getelementptr i16, ptr %a, i64 %ind242; CHECK-NEXT: Check 1:243; CHECK-NEXT: Comparing group GRP0:244; CHECK-NEXT: %storeidx = getelementptr inbounds i16, ptr %a, i64 %store_ind245; CHECK-NEXT: Against group GRP2:246; CHECK-NEXT: %arrayidxA2 = getelementptr i16, ptr %a, i64 %ind2247; CHECK-NEXT: Grouped accesses:248; CHECK-NEXT: Group GRP0:249; CHECK-NEXT: (Low: ((2 * %offset) + %a) High: (10000 + (2 * %offset) + %a))250; CHECK-NEXT: Member: {((2 * %offset) + %a),+,2}<%for.body>251; CHECK-NEXT: Group GRP1:252; CHECK-NEXT: (Low: %a High: (10000 + %a))253; CHECK-NEXT: Member: {%a,+,2}<nw><%for.body>254; CHECK-NEXT: Group GRP2:255; CHECK-NEXT: (Low: (20000 + %a) High: (30000 + %a))256; CHECK-NEXT: Member: {(20000 + %a),+,2}<nw><%for.body>257 258define void @testi(ptr %a,259 i64 %offset) {260entry:261 br label %for.body262 263for.body: ; preds = %for.body, %entry264 %ind = phi i64 [ 0, %entry ], [ %add, %for.body ]265 %store_ind = phi i64 [ %offset, %entry ], [ %store_ind_inc, %for.body ]266 267 %add = add nuw nsw i64 %ind, 1268 %store_ind_inc = add nuw nsw i64 %store_ind, 1269 270 %arrayidxA1 = getelementptr i16, ptr %a, i64 %ind271 %ind2 = add nuw nsw i64 %ind, 10000272 %arrayidxA2 = getelementptr i16, ptr %a, i64 %ind2273 274 %loadA1 = load i16, ptr %arrayidxA1, align 2275 %loadA2 = load i16, ptr %arrayidxA2, align 2276 277 %addres = add i16 %loadA1, %loadA2278 279 %storeidx = getelementptr inbounds i16, ptr %a, i64 %store_ind280 store i16 %addres, ptr %storeidx, align 2281 282 %exitcond = icmp eq i64 %add, 5000283 br i1 %exitcond, label %for.end, label %for.body284 285for.end: ; preds = %for.body286 ret void287}288