1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -passes=gvn -S < %s | FileCheck %s 3 4target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:4:5" 5target triple = "x86_64-unknown-linux-gnu" 6 7define void @f0(i1 %alwaysFalse, i64 %val, ptr %loc) { 8; CHECK-LABEL: @f0( 9; CHECK-NEXT: entry: 10; CHECK-NEXT: store i64 [[VAL:%.*]], ptr [[LOC:%.*]], align 8 11; CHECK-NEXT: br i1 [[ALWAYSFALSE:%.*]], label [[NEVERTAKEN:%.*]], label [[ALWAYSTAKEN:%.*]] 12; CHECK: neverTaken: 13; CHECK-NEXT: [[PTR:%.*]] = load ptr addrspace(4), ptr [[LOC]], align 8 14; CHECK-NEXT: store i8 5, ptr addrspace(4) [[PTR]], align 1 15; CHECK-NEXT: ret void 16; CHECK: alwaysTaken: 17; CHECK-NEXT: ret void 18; 19 entry: 20 store i64 %val, ptr %loc 21 br i1 %alwaysFalse, label %neverTaken, label %alwaysTaken 22 23 neverTaken: 24 %ptr = load ptr addrspace(4), ptr %loc 25 store i8 5, ptr addrspace(4) %ptr 26 ret void 27 28 alwaysTaken: 29 ret void 30} 31 32define i64 @f1(i1 %alwaysFalse, ptr addrspace(4) %val, ptr %loc) { 33; CHECK-LABEL: @f1( 34; CHECK-NEXT: entry: 35; CHECK-NEXT: store ptr addrspace(4) [[VAL:%.*]], ptr [[LOC:%.*]], align 8 36; CHECK-NEXT: br i1 [[ALWAYSFALSE:%.*]], label [[NEVERTAKEN:%.*]], label [[ALWAYSTAKEN:%.*]] 37; CHECK: neverTaken: 38; CHECK-NEXT: [[INT:%.*]] = load i64, ptr [[LOC]], align 8 39; CHECK-NEXT: ret i64 [[INT]] 40; CHECK: alwaysTaken: 41; CHECK-NEXT: ret i64 42 42; 43 entry: 44 store ptr addrspace(4) %val, ptr %loc 45 br i1 %alwaysFalse, label %neverTaken, label %alwaysTaken 46 47 neverTaken: 48 %int = load i64, ptr %loc 49 ret i64 %int 50 51 alwaysTaken: 52 ret i64 42 53} 54 55;; Note: For terseness, we stop using the %alwaysfalse trick for the 56;; tests below and just exercise the bits of forwarding logic directly. 57 58declare void @llvm.memset.p4.i64(ptr addrspace(4) nocapture, i8, i64, i1) nounwind 59 60; Can't forward as the load might be dead. (Pretend we wrote out the alwaysfalse idiom above.) 61define ptr addrspace(4) @neg_forward_memset(ptr addrspace(4) %loc) { 62; CHECK-LABEL: @neg_forward_memset( 63; CHECK-NEXT: entry: 64; CHECK-NEXT: call void @llvm.memset.p4.i64(ptr addrspace(4) align 4 [[LOC:%.*]], i8 7, i64 8, i1 false) 65; CHECK-NEXT: [[REF:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[LOC]], align 8 66; CHECK-NEXT: ret ptr addrspace(4) [[REF]] 67; 68 entry: 69 call void @llvm.memset.p4.i64(ptr addrspace(4) align 4 %loc, i8 7, i64 8, i1 false) 70 %ref = load ptr addrspace(4), ptr addrspace(4) %loc 71 ret ptr addrspace(4) %ref 72} 73 74define <1 x ptr addrspace(4)> @neg_forward_memset_vload(ptr addrspace(4) %loc) { 75; CHECK-LABEL: @neg_forward_memset_vload( 76; CHECK-NEXT: entry: 77; CHECK-NEXT: call void @llvm.memset.p4.i64(ptr addrspace(4) align 4 [[LOC:%.*]], i8 7, i64 8, i1 false) 78; CHECK-NEXT: [[REF:%.*]] = load <1 x ptr addrspace(4)>, ptr addrspace(4) [[LOC]], align 8 79; CHECK-NEXT: ret <1 x ptr addrspace(4)> [[REF]] 80; 81 entry: 82 call void @llvm.memset.p4.i64(ptr addrspace(4) align 4 %loc, i8 7, i64 8, i1 false) 83 %ref = load <1 x ptr addrspace(4)>, ptr addrspace(4) %loc 84 ret <1 x ptr addrspace(4)> %ref 85} 86 87 88; Can forward since we can do so w/o breaking types 89define ptr addrspace(4) @forward_memset_zero(ptr addrspace(4) %loc) { 90; CHECK-LABEL: @forward_memset_zero( 91; CHECK-NEXT: entry: 92; CHECK-NEXT: call void @llvm.memset.p4.i64(ptr addrspace(4) align 4 [[LOC:%.*]], i8 0, i64 8, i1 false) 93; CHECK-NEXT: ret ptr addrspace(4) null 94; 95 entry: 96 call void @llvm.memset.p4.i64(ptr addrspace(4) align 4 %loc, i8 0, i64 8, i1 false) 97 %ref = load ptr addrspace(4), ptr addrspace(4) %loc 98 ret ptr addrspace(4) %ref 99} 100 101; Can't forward as the load might be dead. (Pretend we wrote out the alwaysfalse idiom above.) 102define ptr addrspace(4) @neg_forward_store(ptr addrspace(4) %loc) { 103; CHECK-LABEL: @neg_forward_store( 104; CHECK-NEXT: entry: 105; CHECK-NEXT: store i64 5, ptr addrspace(4) [[LOC:%.*]], align 8 106; CHECK-NEXT: [[REF:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[LOC]], align 8 107; CHECK-NEXT: ret ptr addrspace(4) [[REF]] 108; 109 entry: 110 store i64 5, ptr addrspace(4) %loc 111 %ref = load ptr addrspace(4), ptr addrspace(4) %loc 112 ret ptr addrspace(4) %ref 113} 114 115define <1 x ptr addrspace(4)> @neg_forward_store_vload(ptr addrspace(4) %loc) { 116; CHECK-LABEL: @neg_forward_store_vload( 117; CHECK-NEXT: entry: 118; CHECK-NEXT: store i64 5, ptr addrspace(4) [[LOC:%.*]], align 8 119; CHECK-NEXT: [[REF:%.*]] = load <1 x ptr addrspace(4)>, ptr addrspace(4) [[LOC]], align 8 120; CHECK-NEXT: ret <1 x ptr addrspace(4)> [[REF]] 121; 122 entry: 123 store i64 5, ptr addrspace(4) %loc 124 %ref = load <1 x ptr addrspace(4)>, ptr addrspace(4) %loc 125 ret <1 x ptr addrspace(4)> %ref 126} 127 128; Nulls have known bit patterns, so we can forward 129define ptr addrspace(4) @forward_store_zero(ptr addrspace(4) %loc) { 130; CHECK-LABEL: @forward_store_zero( 131; CHECK-NEXT: entry: 132; CHECK-NEXT: store i64 0, ptr addrspace(4) [[LOC:%.*]], align 8 133; CHECK-NEXT: ret ptr addrspace(4) null 134; 135 entry: 136 store i64 0, ptr addrspace(4) %loc 137 %ref = load ptr addrspace(4), ptr addrspace(4) %loc 138 ret ptr addrspace(4) %ref 139} 140 141; Nulls have known bit patterns, so we can forward 142define ptr addrspace(4) @forward_store_zero2(ptr addrspace(4) %loc) { 143; CHECK-LABEL: @forward_store_zero2( 144; CHECK-NEXT: entry: 145; CHECK-NEXT: store <2 x i32> zeroinitializer, ptr addrspace(4) [[LOC:%.*]], align 8 146; CHECK-NEXT: ret ptr addrspace(4) null 147; 148 entry: 149 store <2 x i32> zeroinitializer, ptr addrspace(4) %loc 150 %ref = load ptr addrspace(4), ptr addrspace(4) %loc 151 ret ptr addrspace(4) %ref 152} 153 154 155 156@NonZeroConstant = constant <4 x i64> <i64 3, i64 3, i64 3, i64 3> 157@NonZeroConstant2 = constant <4 x ptr addrspace(4)> < 158 ptr addrspace(4) getelementptr (i64, ptr addrspace(4) null, i32 3), 159 ptr addrspace(4) getelementptr (i64, ptr addrspace(4) null, i32 3), 160 ptr addrspace(4) getelementptr (i64, ptr addrspace(4) null, i32 3), 161 ptr addrspace(4) getelementptr (i64, ptr addrspace(4) null, i32 3)> 162@ZeroConstant = constant <4 x i64> zeroinitializer 163 164 165; Can't forward as the load might be dead. (Pretend we wrote out the alwaysfalse idiom above.) 166define ptr addrspace(4) @neg_forward_memcopy(ptr addrspace(4) %loc) { 167; CHECK-LABEL: @neg_forward_memcopy( 168; CHECK-NEXT: entry: 169; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant, i64 8, i1 false) 170; CHECK-NEXT: [[REF:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[LOC]], align 8 171; CHECK-NEXT: ret ptr addrspace(4) [[REF]] 172; 173entry: 174 call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant, i64 8, i1 false) 175 %ref = load ptr addrspace(4), ptr addrspace(4) %loc 176 ret ptr addrspace(4) %ref 177} 178 179define ptr addrspace(4) @neg_forward_memcopy2(ptr addrspace(4) %loc) { 180; CHECK-LABEL: @neg_forward_memcopy2( 181; CHECK-NEXT: entry: 182; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant, i64 8, i1 false) 183; CHECK-NEXT: [[REF:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[LOC]], align 8 184; CHECK-NEXT: ret ptr addrspace(4) [[REF]] 185; 186entry: 187 call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant, i64 8, i1 false) 188 %ref = load ptr addrspace(4), ptr addrspace(4) %loc 189 ret ptr addrspace(4) %ref 190} 191 192define ptr addrspace(4) @forward_memcopy(ptr addrspace(4) %loc) { 193; CHECK-LABEL: @forward_memcopy( 194; CHECK-NEXT: entry: 195; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant2, i64 8, i1 false) 196; CHECK-NEXT: ret ptr addrspace(4) getelementptr (i64, ptr addrspace(4) null, i32 3) 197; 198entry: 199 call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant2, i64 8, i1 false) 200 %ref = load ptr addrspace(4), ptr addrspace(4) %loc 201 ret ptr addrspace(4) %ref 202} 203 204define ptr addrspace(4) @forward_memcopy2(ptr addrspace(4) %loc) { 205; CHECK-LABEL: @forward_memcopy2( 206; CHECK-NEXT: entry: 207; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant2, i64 8, i1 false) 208; CHECK-NEXT: ret ptr addrspace(4) getelementptr (i64, ptr addrspace(4) null, i32 3) 209; 210entry: 211 call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant2, i64 8, i1 false) 212 %ref = load ptr addrspace(4), ptr addrspace(4) %loc 213 ret ptr addrspace(4) %ref 214} 215 216define <1 x ptr addrspace(4)> @neg_forward_memcpy_vload(ptr addrspace(4) %loc) { 217; CHECK-LABEL: @neg_forward_memcpy_vload( 218; CHECK-NEXT: entry: 219; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant, i64 8, i1 false) 220; CHECK-NEXT: [[REF:%.*]] = load <1 x ptr addrspace(4)>, ptr addrspace(4) [[LOC]], align 8 221; CHECK-NEXT: ret <1 x ptr addrspace(4)> [[REF]] 222; 223entry: 224 call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant, i64 8, i1 false) 225 %ref = load <1 x ptr addrspace(4)>, ptr addrspace(4) %loc 226 ret <1 x ptr addrspace(4)> %ref 227} 228 229define <4 x ptr addrspace(4)> @neg_forward_memcpy_vload2(ptr addrspace(4) %loc) { 230; CHECK-LABEL: @neg_forward_memcpy_vload2( 231; CHECK-NEXT: entry: 232; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant, i64 32, i1 false) 233; CHECK-NEXT: [[REF:%.*]] = load <4 x ptr addrspace(4)>, ptr addrspace(4) [[LOC]], align 32 234; CHECK-NEXT: ret <4 x ptr addrspace(4)> [[REF]] 235; 236entry: 237 call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant, i64 32, i1 false) 238 %ref = load <4 x ptr addrspace(4)>, ptr addrspace(4) %loc 239 ret <4 x ptr addrspace(4)> %ref 240} 241 242define <4 x i64> @neg_forward_memcpy_vload3(ptr addrspace(4) %loc) { 243; CHECK-LABEL: @neg_forward_memcpy_vload3( 244; CHECK-NEXT: entry: 245; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant2, i64 32, i1 false) 246; CHECK-NEXT: [[REF:%.*]] = load <4 x i64>, ptr addrspace(4) [[LOC]], align 32 247; CHECK-NEXT: ret <4 x i64> [[REF]] 248; 249entry: 250 call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant2, i64 32, i1 false) 251 %ref = load <4 x i64>, ptr addrspace(4) %loc 252 ret <4 x i64> %ref 253} 254 255define <1 x ptr addrspace(4)> @forward_memcpy_vload3(ptr addrspace(4) %loc) { 256; CHECK-LABEL: @forward_memcpy_vload3( 257; CHECK-NEXT: entry: 258; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant2, i64 32, i1 false) 259; CHECK-NEXT: ret <1 x ptr addrspace(4)> <ptr addrspace(4) getelementptr (i64, ptr addrspace(4) null, i32 3)> 260; 261entry: 262 call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant2, i64 32, i1 false) 263 %ref = load <4 x ptr addrspace(4)>, ptr addrspace(4) %loc 264 %val = extractelement <4 x ptr addrspace(4)> %ref, i32 0 265 %ret = insertelement <1 x ptr addrspace(4)> undef, ptr addrspace(4) %val, i32 0 266 ret <1 x ptr addrspace(4)> %ret 267} 268 269; Can forward since we can do so w/o breaking types 270define ptr addrspace(4) @forward_memcpy_zero(ptr addrspace(4) %loc) { 271; CHECK-LABEL: @forward_memcpy_zero( 272; CHECK-NEXT: entry: 273; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @ZeroConstant, i64 8, i1 false) 274; CHECK-NEXT: ret ptr addrspace(4) null 275; 276entry: 277 call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @ZeroConstant, i64 8, i1 false) 278 %ref = load ptr addrspace(4), ptr addrspace(4) %loc 279 ret ptr addrspace(4) %ref 280} 281 282declare void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) nocapture, ptr nocapture, i64, i1) nounwind 283 284 285; Same as the neg_forward_store cases, but for non defs. 286; (Pretend we wrote out the alwaysfalse idiom above.) 287define ptr addrspace(4) @neg_store_clobber(ptr addrspace(4) %loc) { 288; CHECK-LABEL: @neg_store_clobber( 289; CHECK-NEXT: entry: 290; CHECK-NEXT: store <2 x i64> splat (i64 4), ptr addrspace(4) [[LOC:%.*]], align 16 291; CHECK-NEXT: [[LOC_OFF:%.*]] = getelementptr ptr addrspace(4), ptr addrspace(4) [[LOC]], i64 1 292; CHECK-NEXT: [[REF:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[LOC_OFF]], align 8 293; CHECK-NEXT: ret ptr addrspace(4) [[REF]] 294; 295entry: 296 store <2 x i64> <i64 4, i64 4>, ptr addrspace(4) %loc 297 %loc.off = getelementptr ptr addrspace(4), ptr addrspace(4) %loc, i64 1 298 %ref = load ptr addrspace(4), ptr addrspace(4) %loc.off 299 ret ptr addrspace(4) %ref 300} 301 302declare void @use(<2 x i64>) inaccessiblememonly 303 304; Same as the neg_forward_store cases, but for non defs. 305; (Pretend we wrote out the alwaysfalse idiom above.) 306define ptr addrspace(4) @neg_load_clobber(ptr addrspace(4) %loc) { 307; CHECK-LABEL: @neg_load_clobber( 308; CHECK-NEXT: entry: 309; CHECK-NEXT: [[V:%.*]] = load <2 x i64>, ptr addrspace(4) [[LOC:%.*]], align 16 310; CHECK-NEXT: call void @use(<2 x i64> [[V]]) 311; CHECK-NEXT: [[LOC_OFF:%.*]] = getelementptr ptr addrspace(4), ptr addrspace(4) [[LOC]], i64 1 312; CHECK-NEXT: [[REF:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[LOC_OFF]], align 8 313; CHECK-NEXT: ret ptr addrspace(4) [[REF]] 314; 315entry: 316 %v = load <2 x i64>, ptr addrspace(4) %loc 317 call void @use(<2 x i64> %v) 318 %loc.off = getelementptr ptr addrspace(4), ptr addrspace(4) %loc, i64 1 319 %ref = load ptr addrspace(4), ptr addrspace(4) %loc.off 320 ret ptr addrspace(4) %ref 321} 322 323define ptr addrspace(4) @store_clobber_zero(ptr addrspace(4) %loc) { 324; CHECK-LABEL: @store_clobber_zero( 325; CHECK-NEXT: entry: 326; CHECK-NEXT: store <2 x i64> zeroinitializer, ptr addrspace(4) [[LOC:%.*]], align 16 327; CHECK-NEXT: [[LOC_OFF:%.*]] = getelementptr ptr addrspace(4), ptr addrspace(4) [[LOC]], i64 1 328; CHECK-NEXT: ret ptr addrspace(4) null 329; 330entry: 331 store <2 x i64> zeroinitializer, ptr addrspace(4) %loc 332 %loc.off = getelementptr ptr addrspace(4), ptr addrspace(4) %loc, i64 1 333 %ref = load ptr addrspace(4), ptr addrspace(4) %loc.off 334 ret ptr addrspace(4) %ref 335} 336 337 338define void @smaller_vector(ptr %p) { 339; CHECK-LABEL: @smaller_vector( 340; CHECK-NEXT: entry: 341; CHECK-NEXT: [[V4:%.*]] = load <4 x ptr addrspace(4)>, ptr [[P:%.*]], align 32 342; CHECK-NEXT: [[V2:%.*]] = load <2 x ptr addrspace(4)>, ptr [[P]], align 32 343; CHECK-NEXT: call void @use.v2(<2 x ptr addrspace(4)> [[V2]]) 344; CHECK-NEXT: call void @use.v4(<4 x ptr addrspace(4)> [[V4]]) 345; CHECK-NEXT: ret void 346; 347entry: 348 %v4 = load <4 x ptr addrspace(4)>, ptr %p, align 32 349 %v2 = load <2 x ptr addrspace(4)>, ptr %p, align 32 350 call void @use.v2(<2 x ptr addrspace(4)> %v2) 351 call void @use.v4(<4 x ptr addrspace(4)> %v4) 352 ret void 353} 354 355define ptr addrspace(4) @vector_extract(ptr %p) { 356; CHECK-LABEL: @vector_extract( 357; CHECK-NEXT: entry: 358; CHECK-NEXT: [[V4:%.*]] = load <4 x ptr addrspace(4)>, ptr [[P:%.*]], align 32 359; CHECK-NEXT: [[RES:%.*]] = load ptr addrspace(4), ptr [[P]], align 32 360; CHECK-NEXT: call void @use.v4(<4 x ptr addrspace(4)> [[V4]]) 361; CHECK-NEXT: ret ptr addrspace(4) [[RES]] 362; 363entry: 364 %v4 = load <4 x ptr addrspace(4)>, ptr %p, align 32 365 %res = load ptr addrspace(4), ptr %p, align 32 366 call void @use.v4(<4 x ptr addrspace(4)> %v4) 367 ret ptr addrspace(4) %res 368} 369 370declare void @use.v2(<2 x ptr addrspace(4)>) 371declare void @use.v4(<4 x ptr addrspace(4)>) 372define ptr addrspace(5) @multini(i1 %alwaysFalse, ptr addrspace(4) %val, ptr %loc) { 373; CHECK-LABEL: @multini( 374; CHECK-NEXT: entry: 375; CHECK-NEXT: store ptr addrspace(4) [[VAL:%.*]], ptr [[LOC:%.*]], align 8 376; CHECK-NEXT: br i1 [[ALWAYSFALSE:%.*]], label [[NEVERTAKEN:%.*]], label [[ALWAYSTAKEN:%.*]] 377; CHECK: neverTaken: 378; CHECK-NEXT: [[DIFFERENTAS:%.*]] = load ptr addrspace(5), ptr [[LOC]], align 8 379; CHECK-NEXT: ret ptr addrspace(5) [[DIFFERENTAS]] 380; CHECK: alwaysTaken: 381; CHECK-NEXT: ret ptr addrspace(5) null 382; 383entry: 384 store ptr addrspace(4) %val, ptr %loc 385 br i1 %alwaysFalse, label %neverTaken, label %alwaysTaken 386 387neverTaken: 388 %differentas = load ptr addrspace(5), ptr %loc 389 ret ptr addrspace(5) %differentas 390 391alwaysTaken: 392 ret ptr addrspace(5) null 393} 394