; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -passes=gvn -S < %s | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:4:5" target triple = "x86_64-unknown-linux-gnu" define void @f0(i1 %alwaysFalse, i64 %val, ptr %loc) { ; CHECK-LABEL: @f0( ; CHECK-NEXT: entry: ; CHECK-NEXT: store i64 [[VAL:%.*]], ptr [[LOC:%.*]], align 8 ; CHECK-NEXT: br i1 [[ALWAYSFALSE:%.*]], label [[NEVERTAKEN:%.*]], label [[ALWAYSTAKEN:%.*]] ; CHECK: neverTaken: ; CHECK-NEXT: [[PTR:%.*]] = load ptr addrspace(4), ptr [[LOC]], align 8 ; CHECK-NEXT: store i8 5, ptr addrspace(4) [[PTR]], align 1 ; CHECK-NEXT: ret void ; CHECK: alwaysTaken: ; CHECK-NEXT: ret void ; entry: store i64 %val, ptr %loc br i1 %alwaysFalse, label %neverTaken, label %alwaysTaken neverTaken: %ptr = load ptr addrspace(4), ptr %loc store i8 5, ptr addrspace(4) %ptr ret void alwaysTaken: ret void } define i64 @f1(i1 %alwaysFalse, ptr addrspace(4) %val, ptr %loc) { ; CHECK-LABEL: @f1( ; CHECK-NEXT: entry: ; CHECK-NEXT: store ptr addrspace(4) [[VAL:%.*]], ptr [[LOC:%.*]], align 8 ; CHECK-NEXT: br i1 [[ALWAYSFALSE:%.*]], label [[NEVERTAKEN:%.*]], label [[ALWAYSTAKEN:%.*]] ; CHECK: neverTaken: ; CHECK-NEXT: [[INT:%.*]] = load i64, ptr [[LOC]], align 8 ; CHECK-NEXT: ret i64 [[INT]] ; CHECK: alwaysTaken: ; CHECK-NEXT: ret i64 42 ; entry: store ptr addrspace(4) %val, ptr %loc br i1 %alwaysFalse, label %neverTaken, label %alwaysTaken neverTaken: %int = load i64, ptr %loc ret i64 %int alwaysTaken: ret i64 42 } ;; Note: For terseness, we stop using the %alwaysfalse trick for the ;; tests below and just exercise the bits of forwarding logic directly. declare void @llvm.memset.p4.i64(ptr addrspace(4) nocapture, i8, i64, i1) nounwind ; Can't forward as the load might be dead. (Pretend we wrote out the alwaysfalse idiom above.) define ptr addrspace(4) @neg_forward_memset(ptr addrspace(4) %loc) { ; CHECK-LABEL: @neg_forward_memset( ; CHECK-NEXT: entry: ; CHECK-NEXT: call void @llvm.memset.p4.i64(ptr addrspace(4) align 4 [[LOC:%.*]], i8 7, i64 8, i1 false) ; CHECK-NEXT: [[REF:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[LOC]], align 8 ; CHECK-NEXT: ret ptr addrspace(4) [[REF]] ; entry: call void @llvm.memset.p4.i64(ptr addrspace(4) align 4 %loc, i8 7, i64 8, i1 false) %ref = load ptr addrspace(4), ptr addrspace(4) %loc ret ptr addrspace(4) %ref } define <1 x ptr addrspace(4)> @neg_forward_memset_vload(ptr addrspace(4) %loc) { ; CHECK-LABEL: @neg_forward_memset_vload( ; CHECK-NEXT: entry: ; CHECK-NEXT: call void @llvm.memset.p4.i64(ptr addrspace(4) align 4 [[LOC:%.*]], i8 7, i64 8, i1 false) ; CHECK-NEXT: [[REF:%.*]] = load <1 x ptr addrspace(4)>, ptr addrspace(4) [[LOC]], align 8 ; CHECK-NEXT: ret <1 x ptr addrspace(4)> [[REF]] ; entry: call void @llvm.memset.p4.i64(ptr addrspace(4) align 4 %loc, i8 7, i64 8, i1 false) %ref = load <1 x ptr addrspace(4)>, ptr addrspace(4) %loc ret <1 x ptr addrspace(4)> %ref } ; Can forward since we can do so w/o breaking types define ptr addrspace(4) @forward_memset_zero(ptr addrspace(4) %loc) { ; CHECK-LABEL: @forward_memset_zero( ; CHECK-NEXT: entry: ; CHECK-NEXT: call void @llvm.memset.p4.i64(ptr addrspace(4) align 4 [[LOC:%.*]], i8 0, i64 8, i1 false) ; CHECK-NEXT: ret ptr addrspace(4) null ; entry: call void @llvm.memset.p4.i64(ptr addrspace(4) align 4 %loc, i8 0, i64 8, i1 false) %ref = load ptr addrspace(4), ptr addrspace(4) %loc ret ptr addrspace(4) %ref } ; Can't forward as the load might be dead. (Pretend we wrote out the alwaysfalse idiom above.) define ptr addrspace(4) @neg_forward_store(ptr addrspace(4) %loc) { ; CHECK-LABEL: @neg_forward_store( ; CHECK-NEXT: entry: ; CHECK-NEXT: store i64 5, ptr addrspace(4) [[LOC:%.*]], align 8 ; CHECK-NEXT: [[REF:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[LOC]], align 8 ; CHECK-NEXT: ret ptr addrspace(4) [[REF]] ; entry: store i64 5, ptr addrspace(4) %loc %ref = load ptr addrspace(4), ptr addrspace(4) %loc ret ptr addrspace(4) %ref } define <1 x ptr addrspace(4)> @neg_forward_store_vload(ptr addrspace(4) %loc) { ; CHECK-LABEL: @neg_forward_store_vload( ; CHECK-NEXT: entry: ; CHECK-NEXT: store i64 5, ptr addrspace(4) [[LOC:%.*]], align 8 ; CHECK-NEXT: [[REF:%.*]] = load <1 x ptr addrspace(4)>, ptr addrspace(4) [[LOC]], align 8 ; CHECK-NEXT: ret <1 x ptr addrspace(4)> [[REF]] ; entry: store i64 5, ptr addrspace(4) %loc %ref = load <1 x ptr addrspace(4)>, ptr addrspace(4) %loc ret <1 x ptr addrspace(4)> %ref } ; Nulls have known bit patterns, so we can forward define ptr addrspace(4) @forward_store_zero(ptr addrspace(4) %loc) { ; CHECK-LABEL: @forward_store_zero( ; CHECK-NEXT: entry: ; CHECK-NEXT: store i64 0, ptr addrspace(4) [[LOC:%.*]], align 8 ; CHECK-NEXT: ret ptr addrspace(4) null ; entry: store i64 0, ptr addrspace(4) %loc %ref = load ptr addrspace(4), ptr addrspace(4) %loc ret ptr addrspace(4) %ref } ; Nulls have known bit patterns, so we can forward define ptr addrspace(4) @forward_store_zero2(ptr addrspace(4) %loc) { ; CHECK-LABEL: @forward_store_zero2( ; CHECK-NEXT: entry: ; CHECK-NEXT: store <2 x i32> zeroinitializer, ptr addrspace(4) [[LOC:%.*]], align 8 ; CHECK-NEXT: ret ptr addrspace(4) null ; entry: store <2 x i32> zeroinitializer, ptr addrspace(4) %loc %ref = load ptr addrspace(4), ptr addrspace(4) %loc ret ptr addrspace(4) %ref } @NonZeroConstant = constant <4 x i64> @NonZeroConstant2 = constant <4 x ptr addrspace(4)> < ptr addrspace(4) getelementptr (i64, ptr addrspace(4) null, i32 3), ptr addrspace(4) getelementptr (i64, ptr addrspace(4) null, i32 3), ptr addrspace(4) getelementptr (i64, ptr addrspace(4) null, i32 3), ptr addrspace(4) getelementptr (i64, ptr addrspace(4) null, i32 3)> @ZeroConstant = constant <4 x i64> zeroinitializer ; Can't forward as the load might be dead. (Pretend we wrote out the alwaysfalse idiom above.) define ptr addrspace(4) @neg_forward_memcopy(ptr addrspace(4) %loc) { ; CHECK-LABEL: @neg_forward_memcopy( ; CHECK-NEXT: entry: ; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant, i64 8, i1 false) ; CHECK-NEXT: [[REF:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[LOC]], align 8 ; CHECK-NEXT: ret ptr addrspace(4) [[REF]] ; entry: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant, i64 8, i1 false) %ref = load ptr addrspace(4), ptr addrspace(4) %loc ret ptr addrspace(4) %ref } define ptr addrspace(4) @neg_forward_memcopy2(ptr addrspace(4) %loc) { ; CHECK-LABEL: @neg_forward_memcopy2( ; CHECK-NEXT: entry: ; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant, i64 8, i1 false) ; CHECK-NEXT: [[REF:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[LOC]], align 8 ; CHECK-NEXT: ret ptr addrspace(4) [[REF]] ; entry: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant, i64 8, i1 false) %ref = load ptr addrspace(4), ptr addrspace(4) %loc ret ptr addrspace(4) %ref } define ptr addrspace(4) @forward_memcopy(ptr addrspace(4) %loc) { ; CHECK-LABEL: @forward_memcopy( ; CHECK-NEXT: entry: ; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant2, i64 8, i1 false) ; CHECK-NEXT: ret ptr addrspace(4) getelementptr (i64, ptr addrspace(4) null, i32 3) ; entry: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant2, i64 8, i1 false) %ref = load ptr addrspace(4), ptr addrspace(4) %loc ret ptr addrspace(4) %ref } define ptr addrspace(4) @forward_memcopy2(ptr addrspace(4) %loc) { ; CHECK-LABEL: @forward_memcopy2( ; CHECK-NEXT: entry: ; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant2, i64 8, i1 false) ; CHECK-NEXT: ret ptr addrspace(4) getelementptr (i64, ptr addrspace(4) null, i32 3) ; entry: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant2, i64 8, i1 false) %ref = load ptr addrspace(4), ptr addrspace(4) %loc ret ptr addrspace(4) %ref } define <1 x ptr addrspace(4)> @neg_forward_memcpy_vload(ptr addrspace(4) %loc) { ; CHECK-LABEL: @neg_forward_memcpy_vload( ; CHECK-NEXT: entry: ; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant, i64 8, i1 false) ; CHECK-NEXT: [[REF:%.*]] = load <1 x ptr addrspace(4)>, ptr addrspace(4) [[LOC]], align 8 ; CHECK-NEXT: ret <1 x ptr addrspace(4)> [[REF]] ; entry: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant, i64 8, i1 false) %ref = load <1 x ptr addrspace(4)>, ptr addrspace(4) %loc ret <1 x ptr addrspace(4)> %ref } define <4 x ptr addrspace(4)> @neg_forward_memcpy_vload2(ptr addrspace(4) %loc) { ; CHECK-LABEL: @neg_forward_memcpy_vload2( ; CHECK-NEXT: entry: ; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant, i64 32, i1 false) ; CHECK-NEXT: [[REF:%.*]] = load <4 x ptr addrspace(4)>, ptr addrspace(4) [[LOC]], align 32 ; CHECK-NEXT: ret <4 x ptr addrspace(4)> [[REF]] ; entry: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant, i64 32, i1 false) %ref = load <4 x ptr addrspace(4)>, ptr addrspace(4) %loc ret <4 x ptr addrspace(4)> %ref } define <4 x i64> @neg_forward_memcpy_vload3(ptr addrspace(4) %loc) { ; CHECK-LABEL: @neg_forward_memcpy_vload3( ; CHECK-NEXT: entry: ; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant2, i64 32, i1 false) ; CHECK-NEXT: [[REF:%.*]] = load <4 x i64>, ptr addrspace(4) [[LOC]], align 32 ; CHECK-NEXT: ret <4 x i64> [[REF]] ; entry: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant2, i64 32, i1 false) %ref = load <4 x i64>, ptr addrspace(4) %loc ret <4 x i64> %ref } define <1 x ptr addrspace(4)> @forward_memcpy_vload3(ptr addrspace(4) %loc) { ; CHECK-LABEL: @forward_memcpy_vload3( ; CHECK-NEXT: entry: ; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @NonZeroConstant2, i64 32, i1 false) ; CHECK-NEXT: ret <1 x ptr addrspace(4)> ; entry: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @NonZeroConstant2, i64 32, i1 false) %ref = load <4 x ptr addrspace(4)>, ptr addrspace(4) %loc %val = extractelement <4 x ptr addrspace(4)> %ref, i32 0 %ret = insertelement <1 x ptr addrspace(4)> poison, ptr addrspace(4) %val, i32 0 ret <1 x ptr addrspace(4)> %ret } ; Can forward since we can do so w/o breaking types define ptr addrspace(4) @forward_memcpy_zero(ptr addrspace(4) %loc) { ; CHECK-LABEL: @forward_memcpy_zero( ; CHECK-NEXT: entry: ; CHECK-NEXT: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 [[LOC:%.*]], ptr @ZeroConstant, i64 8, i1 false) ; CHECK-NEXT: ret ptr addrspace(4) null ; entry: call void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) align 4 %loc, ptr @ZeroConstant, i64 8, i1 false) %ref = load ptr addrspace(4), ptr addrspace(4) %loc ret ptr addrspace(4) %ref } declare void @llvm.memcpy.p4.p0.i64(ptr addrspace(4) nocapture, ptr nocapture, i64, i1) nounwind ; Same as the neg_forward_store cases, but for non defs. ; (Pretend we wrote out the alwaysfalse idiom above.) define ptr addrspace(4) @neg_store_clobber(ptr addrspace(4) %loc) { ; CHECK-LABEL: @neg_store_clobber( ; CHECK-NEXT: entry: ; CHECK-NEXT: store <2 x i64> , ptr addrspace(4) [[LOC:%.*]], align 16 ; CHECK-NEXT: [[LOC_OFF:%.*]] = getelementptr ptr addrspace(4), ptr addrspace(4) [[LOC]], i64 1 ; CHECK-NEXT: [[REF:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[LOC_OFF]], align 8 ; CHECK-NEXT: ret ptr addrspace(4) [[REF]] ; entry: store <2 x i64> , ptr addrspace(4) %loc %loc.off = getelementptr ptr addrspace(4), ptr addrspace(4) %loc, i64 1 %ref = load ptr addrspace(4), ptr addrspace(4) %loc.off ret ptr addrspace(4) %ref } declare void @use(<2 x i64>) inaccessiblememonly ; Same as the neg_forward_store cases, but for non defs. ; (Pretend we wrote out the alwaysfalse idiom above.) define ptr addrspace(4) @neg_load_clobber(ptr addrspace(4) %loc) { ; CHECK-LABEL: @neg_load_clobber( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[V:%.*]] = load <2 x i64>, ptr addrspace(4) [[LOC:%.*]], align 16 ; CHECK-NEXT: call void @use(<2 x i64> [[V]]) ; CHECK-NEXT: [[LOC_OFF:%.*]] = getelementptr ptr addrspace(4), ptr addrspace(4) [[LOC]], i64 1 ; CHECK-NEXT: [[REF:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[LOC_OFF]], align 8 ; CHECK-NEXT: ret ptr addrspace(4) [[REF]] ; entry: %v = load <2 x i64>, ptr addrspace(4) %loc call void @use(<2 x i64> %v) %loc.off = getelementptr ptr addrspace(4), ptr addrspace(4) %loc, i64 1 %ref = load ptr addrspace(4), ptr addrspace(4) %loc.off ret ptr addrspace(4) %ref } define ptr addrspace(4) @store_clobber_zero(ptr addrspace(4) %loc) { ; CHECK-LABEL: @store_clobber_zero( ; CHECK-NEXT: entry: ; CHECK-NEXT: store <2 x i64> zeroinitializer, ptr addrspace(4) [[LOC:%.*]], align 16 ; CHECK-NEXT: [[LOC_OFF:%.*]] = getelementptr ptr addrspace(4), ptr addrspace(4) [[LOC]], i64 1 ; CHECK-NEXT: ret ptr addrspace(4) null ; entry: store <2 x i64> zeroinitializer, ptr addrspace(4) %loc %loc.off = getelementptr ptr addrspace(4), ptr addrspace(4) %loc, i64 1 %ref = load ptr addrspace(4), ptr addrspace(4) %loc.off ret ptr addrspace(4) %ref } define void @smaller_vector(ptr %p) { ; CHECK-LABEL: @smaller_vector( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[V4:%.*]] = load <4 x ptr addrspace(4)>, ptr [[P:%.*]], align 32 ; CHECK-NEXT: [[V2:%.*]] = load <2 x ptr addrspace(4)>, ptr [[P]], align 32 ; CHECK-NEXT: call void @use.v2(<2 x ptr addrspace(4)> [[V2]]) ; CHECK-NEXT: call void @use.v4(<4 x ptr addrspace(4)> [[V4]]) ; CHECK-NEXT: ret void ; entry: %v4 = load <4 x ptr addrspace(4)>, ptr %p, align 32 %v2 = load <2 x ptr addrspace(4)>, ptr %p, align 32 call void @use.v2(<2 x ptr addrspace(4)> %v2) call void @use.v4(<4 x ptr addrspace(4)> %v4) ret void } define ptr addrspace(4) @vector_extract(ptr %p) { ; CHECK-LABEL: @vector_extract( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[V4:%.*]] = load <4 x ptr addrspace(4)>, ptr [[P:%.*]], align 32 ; CHECK-NEXT: [[RES:%.*]] = load ptr addrspace(4), ptr [[P]], align 32 ; CHECK-NEXT: call void @use.v4(<4 x ptr addrspace(4)> [[V4]]) ; CHECK-NEXT: ret ptr addrspace(4) [[RES]] ; entry: %v4 = load <4 x ptr addrspace(4)>, ptr %p, align 32 %res = load ptr addrspace(4), ptr %p, align 32 call void @use.v4(<4 x ptr addrspace(4)> %v4) ret ptr addrspace(4) %res } declare void @use.v2(<2 x ptr addrspace(4)>) declare void @use.v4(<4 x ptr addrspace(4)>) define ptr addrspace(5) @multini(i1 %alwaysFalse, ptr addrspace(4) %val, ptr %loc) { ; CHECK-LABEL: @multini( ; CHECK-NEXT: entry: ; CHECK-NEXT: store ptr addrspace(4) [[VAL:%.*]], ptr [[LOC:%.*]], align 8 ; CHECK-NEXT: br i1 [[ALWAYSFALSE:%.*]], label [[NEVERTAKEN:%.*]], label [[ALWAYSTAKEN:%.*]] ; CHECK: neverTaken: ; CHECK-NEXT: [[DIFFERENTAS:%.*]] = load ptr addrspace(5), ptr [[LOC]], align 8 ; CHECK-NEXT: ret ptr addrspace(5) [[DIFFERENTAS]] ; CHECK: alwaysTaken: ; CHECK-NEXT: ret ptr addrspace(5) null ; entry: store ptr addrspace(4) %val, ptr %loc br i1 %alwaysFalse, label %neverTaken, label %alwaysTaken neverTaken: %differentas = load ptr addrspace(5), ptr %loc ret ptr addrspace(5) %differentas alwaysTaken: ret ptr addrspace(5) null }