; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -S < %s -basic-aa -gvn -dce | FileCheck %s ; Analyze Load from clobbering Load. define @load_store_clobber_load( *%p) { ; CHECK-LABEL: @load_store_clobber_load( ; CHECK-NEXT: [[LOAD1:%.*]] = load , * [[P:%.*]], align 16 ; CHECK-NEXT: store zeroinitializer, * undef, align 16 ; CHECK-NEXT: [[ADD:%.*]] = add [[LOAD1]], [[LOAD1]] ; CHECK-NEXT: ret [[ADD]] ; %load1 = load , * %p store zeroinitializer, * undef %load2 = load , * %p ; <- load to be eliminated %add = add %load1, %load2 ret %add } define @load_store_clobber_load_mayalias(* %p, * %p2) { ; CHECK-LABEL: @load_store_clobber_load_mayalias( ; CHECK-NEXT: [[LOAD1:%.*]] = load , * [[P:%.*]], align 16 ; CHECK-NEXT: store zeroinitializer, * [[P2:%.*]], align 16 ; CHECK-NEXT: [[LOAD2:%.*]] = load , * [[P]], align 16 ; CHECK-NEXT: [[SUB:%.*]] = sub [[LOAD1]], [[LOAD2]] ; CHECK-NEXT: ret [[SUB]] ; %load1 = load , * %p store zeroinitializer, * %p2 %load2 = load , * %p %sub = sub %load1, %load2 ret %sub } define @load_store_clobber_load_noalias(* noalias %p, * noalias %p2) { ; CHECK-LABEL: @load_store_clobber_load_noalias( ; CHECK-NEXT: [[LOAD1:%.*]] = load , * [[P:%.*]], align 16 ; CHECK-NEXT: store zeroinitializer, * [[P2:%.*]], align 16 ; CHECK-NEXT: [[ADD:%.*]] = add [[LOAD1]], [[LOAD1]] ; CHECK-NEXT: ret [[ADD]] ; %load1 = load , * %p store zeroinitializer, * %p2 %load2 = load , * %p ; <- load to be eliminated %add = add %load1, %load2 ret %add } ; TODO: BasicAA return MayAlias for %gep1,%gep2, could improve as MustAlias. define i32 @load_clobber_load_gep1(* %p) { ; CHECK-LABEL: @load_clobber_load_gep1( ; CHECK-NEXT: [[GEP1:%.*]] = getelementptr , * [[P:%.*]], i64 0, i64 1 ; CHECK-NEXT: [[LOAD1:%.*]] = load i32, i32* [[GEP1]], align 4 ; CHECK-NEXT: [[P2:%.*]] = bitcast * [[P]] to i32* ; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i32, i32* [[P2]], i64 1 ; CHECK-NEXT: [[LOAD2:%.*]] = load i32, i32* [[GEP2]], align 4 ; CHECK-NEXT: [[ADD:%.*]] = add i32 [[LOAD1]], [[LOAD2]] ; CHECK-NEXT: ret i32 [[ADD]] ; %gep1 = getelementptr , * %p, i64 0, i64 1 %load1 = load i32, i32* %gep1 %p2 = bitcast * %p to i32* %gep2 = getelementptr i32, i32* %p2, i64 1 %load2 = load i32, i32* %gep2 ; <- load could be eliminated %add = add i32 %load1, %load2 ret i32 %add } define i32 @load_clobber_load_gep2(* %p) { ; CHECK-LABEL: @load_clobber_load_gep2( ; CHECK-NEXT: [[GEP1:%.*]] = getelementptr , * [[P:%.*]], i64 1, i64 0 ; CHECK-NEXT: [[LOAD1:%.*]] = load i32, i32* [[GEP1]], align 4 ; CHECK-NEXT: [[P2:%.*]] = bitcast * [[P]] to i32* ; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i32, i32* [[P2]], i64 4 ; CHECK-NEXT: [[LOAD2:%.*]] = load i32, i32* [[GEP2]], align 4 ; CHECK-NEXT: [[ADD:%.*]] = add i32 [[LOAD1]], [[LOAD2]] ; CHECK-NEXT: ret i32 [[ADD]] ; %gep1 = getelementptr , * %p, i64 1, i64 0 %load1 = load i32, i32* %gep1 %p2 = bitcast * %p to i32* %gep2 = getelementptr i32, i32* %p2, i64 4 %load2 = load i32, i32* %gep2 ; <- can not determine at compile-time if %load1 and %load2 are same addr %add = add i32 %load1, %load2 ret i32 %add } ; TODO: BasicAA return MayAlias for %gep1,%gep2, could improve as MustAlias. define i32 @load_clobber_load_gep3(* %p) { ; CHECK-LABEL: @load_clobber_load_gep3( ; CHECK-NEXT: [[GEP1:%.*]] = getelementptr , * [[P:%.*]], i64 1, i64 0 ; CHECK-NEXT: [[LOAD1:%.*]] = load i32, i32* [[GEP1]], align 4 ; CHECK-NEXT: [[P2:%.*]] = bitcast * [[P]] to * ; CHECK-NEXT: [[GEP2:%.*]] = getelementptr , * [[P2]], i64 1, i64 0 ; CHECK-NEXT: [[LOAD2:%.*]] = load float, float* [[GEP2]], align 4 ; CHECK-NEXT: [[CAST:%.*]] = bitcast float [[LOAD2]] to i32 ; CHECK-NEXT: [[ADD:%.*]] = add i32 [[LOAD1]], [[CAST]] ; CHECK-NEXT: ret i32 [[ADD]] ; %gep1 = getelementptr , * %p, i64 1, i64 0 %load1 = load i32, i32* %gep1 %p2 = bitcast * %p to * %gep2 = getelementptr , * %p2, i64 1, i64 0 %load2 = load float, float* %gep2 ; <- load could be eliminated %cast = bitcast float %load2 to i32 %add = add i32 %load1, %cast ret i32 %add } define @load_clobber_load_fence(* %p) { ; CHECK-LABEL: @load_clobber_load_fence( ; CHECK-NEXT: [[LOAD1:%.*]] = load , * [[P:%.*]], align 16 ; CHECK-NEXT: call void asm "", "~{memory}"() ; CHECK-NEXT: [[LOAD2:%.*]] = load , * [[P]], align 16 ; CHECK-NEXT: [[SUB:%.*]] = sub [[LOAD1]], [[LOAD2]] ; CHECK-NEXT: ret [[SUB]] ; %load1 = load , * %p call void asm "", "~{memory}"() %load2 = load , * %p %sub = sub %load1, %load2 ret %sub } define @load_clobber_load_sideeffect(* %p) { ; CHECK-LABEL: @load_clobber_load_sideeffect( ; CHECK-NEXT: [[LOAD1:%.*]] = load , * [[P:%.*]], align 16 ; CHECK-NEXT: call void asm sideeffect "", ""() ; CHECK-NEXT: [[LOAD2:%.*]] = load , * [[P]], align 16 ; CHECK-NEXT: [[ADD:%.*]] = add [[LOAD1]], [[LOAD2]] ; CHECK-NEXT: ret [[ADD]] ; %load1 = load , * %p call void asm sideeffect "", ""() %load2 = load , * %p %add = add %load1, %load2 ret %add } ; Analyze Load from clobbering Store. define @store_forward_to_load(* %p) { ; CHECK-LABEL: @store_forward_to_load( ; CHECK-NEXT: store zeroinitializer, * [[P:%.*]], align 16 ; CHECK-NEXT: ret zeroinitializer ; store zeroinitializer, * %p %load = load , * %p ret %load } define @store_forward_to_load_sideeffect(* %p) { ; CHECK-LABEL: @store_forward_to_load_sideeffect( ; CHECK-NEXT: store zeroinitializer, * [[P:%.*]], align 16 ; CHECK-NEXT: call void asm sideeffect "", ""() ; CHECK-NEXT: [[LOAD:%.*]] = load , * [[P]], align 16 ; CHECK-NEXT: ret [[LOAD]] ; store zeroinitializer, * %p call void asm sideeffect "", ""() %load = load , * %p ret %load } define i32 @store_clobber_load() { ; CHECK-LABEL: @store_clobber_load( ; CHECK-NEXT: [[ALLOC:%.*]] = alloca ; CHECK-NEXT: store undef, * [[ALLOC]], align 16 ; CHECK-NEXT: [[PTR:%.*]] = getelementptr , * [[ALLOC]], i32 0, i32 1 ; CHECK-NEXT: [[LOAD:%.*]] = load i32, i32* [[PTR]], align 4 ; CHECK-NEXT: ret i32 [[LOAD]] ; %alloc = alloca store undef, * %alloc %ptr = getelementptr , * %alloc, i32 0, i32 1 %load = load i32, i32* %ptr ret i32 %load } ; Analyze Load from clobbering MemInst. declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i1) define i32 @memset_clobber_load( *%p) { ; CHECK-LABEL: @memset_clobber_load( ; CHECK-NEXT: [[CONV:%.*]] = bitcast * [[P:%.*]] to i8* ; CHECK-NEXT: tail call void @llvm.memset.p0i8.i64(i8* [[CONV]], i8 1, i64 200, i1 false) ; CHECK-NEXT: ret i32 16843009 ; %conv = bitcast * %p to i8* tail call void @llvm.memset.p0i8.i64(i8* %conv, i8 1, i64 200, i1 false) %gep = getelementptr , * %p, i64 0, i64 5 %load = load i32, i32* %gep ret i32 %load } define i32 @memset_clobber_load_vscaled_base( *%p) { ; CHECK-LABEL: @memset_clobber_load_vscaled_base( ; CHECK-NEXT: [[CONV:%.*]] = bitcast * [[P:%.*]] to i8* ; CHECK-NEXT: tail call void @llvm.memset.p0i8.i64(i8* [[CONV]], i8 1, i64 200, i1 false) ; CHECK-NEXT: [[GEP:%.*]] = getelementptr , * [[P]], i64 1, i64 1 ; CHECK-NEXT: [[LOAD:%.*]] = load i32, i32* [[GEP]], align 4 ; CHECK-NEXT: ret i32 [[LOAD]] ; %conv = bitcast * %p to i8* tail call void @llvm.memset.p0i8.i64(i8* %conv, i8 1, i64 200, i1 false) %gep = getelementptr , * %p, i64 1, i64 1 %load = load i32, i32* %gep ret i32 %load } define i32 @memset_clobber_load_nonconst_index( *%p, i64 %idx1, i64 %idx2) { ; CHECK-LABEL: @memset_clobber_load_nonconst_index( ; CHECK-NEXT: [[CONV:%.*]] = bitcast * [[P:%.*]] to i8* ; CHECK-NEXT: tail call void @llvm.memset.p0i8.i64(i8* [[CONV]], i8 1, i64 200, i1 false) ; CHECK-NEXT: [[GEP:%.*]] = getelementptr , * [[P]], i64 [[IDX1:%.*]], i64 [[IDX2:%.*]] ; CHECK-NEXT: [[LOAD:%.*]] = load i32, i32* [[GEP]], align 4 ; CHECK-NEXT: ret i32 [[LOAD]] ; %conv = bitcast * %p to i8* tail call void @llvm.memset.p0i8.i64(i8* %conv, i8 1, i64 200, i1 false) %gep = getelementptr , * %p, i64 %idx1, i64 %idx2 %load = load i32, i32* %gep ret i32 %load } ; Load elimination across BBs define * @load_from_alloc_replaced_with_undef() { ; CHECK-LABEL: @load_from_alloc_replaced_with_undef( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = alloca ; CHECK-NEXT: br i1 undef, label [[IF_END:%.*]], label [[IF_THEN:%.*]] ; CHECK: if.then: ; CHECK-NEXT: store zeroinitializer, * [[A]], align 16 ; CHECK-NEXT: br label [[IF_END]] ; CHECK: if.end: ; CHECK-NEXT: ret * [[A]] ; entry: %a = alloca %gep = getelementptr , * %a, i64 0, i64 1 %load = load i32, i32* %gep ; <- load to be eliminated %tobool = icmp eq i32 %load, 0 ; <- icmp to be eliminated br i1 %tobool, label %if.end, label %if.then if.then: store zeroinitializer, * %a br label %if.end if.end: ret * %a } define i32 @redundant_load_elimination_1(* %p) { ; CHECK-LABEL: @redundant_load_elimination_1( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[GEP:%.*]] = getelementptr , * [[P:%.*]], i64 1, i64 1 ; CHECK-NEXT: [[LOAD1:%.*]] = load i32, i32* [[GEP]], align 4 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[LOAD1]], 0 ; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] ; CHECK: if.then: ; CHECK-NEXT: br label [[IF_END]] ; CHECK: if.end: ; CHECK-NEXT: ret i32 [[LOAD1]] ; entry: %gep = getelementptr , * %p, i64 1, i64 1 %load1 = load i32, i32* %gep %cmp = icmp eq i32 %load1, 0 br i1 %cmp, label %if.then, label %if.end if.then: %load2 = load i32, i32* %gep ; <- load to be eliminated %add = add i32 %load1, %load2 br label %if.end if.end: %result = phi i32 [ %add, %if.then ], [ %load1, %entry ] ret i32 %result } ; TODO: BasicAA return MayAlias for %gep1,%gep2, could improve as NoAlias. define void @redundant_load_elimination_2(i1 %c, * %p, i32* %q, %v) { ; CHECK-LABEL: @redundant_load_elimination_2( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[GEP1:%.*]] = getelementptr , * [[P:%.*]], i64 1, i64 1 ; CHECK-NEXT: store i32 0, i32* [[GEP1]], align 4 ; CHECK-NEXT: [[GEP2:%.*]] = getelementptr , * [[P]], i64 1, i64 0 ; CHECK-NEXT: store i32 1, i32* [[GEP2]], align 4 ; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]] ; CHECK: if.then: ; CHECK-NEXT: [[T:%.*]] = load i32, i32* [[GEP1]], align 4 ; CHECK-NEXT: store i32 [[T]], i32* [[Q:%.*]], align 4 ; CHECK-NEXT: ret void ; CHECK: if.else: ; CHECK-NEXT: ret void ; entry: %gep1 = getelementptr , * %p, i64 1, i64 1 store i32 0, i32* %gep1 %gep2 = getelementptr , * %p, i64 1, i64 0 store i32 1, i32* %gep2 br i1 %c, label %if.else, label %if.then if.then: %t = load i32, i32* %gep1 ; <- load could be eliminated store i32 %t, i32* %q ret void if.else: ret void } ; TODO: load in if.then could have been eliminated define void @missing_load_elimination(i1 %c, * %p, * %q, %v) { ; CHECK-LABEL: @missing_load_elimination( ; CHECK-NEXT: entry: ; CHECK-NEXT: store zeroinitializer, * [[P:%.*]], align 16 ; CHECK-NEXT: [[P1:%.*]] = getelementptr , * [[P]], i64 1 ; CHECK-NEXT: store [[V:%.*]], * [[P1]], align 16 ; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]] ; CHECK: if.then: ; CHECK-NEXT: [[T:%.*]] = load , * [[P]], align 16 ; CHECK-NEXT: store [[T]], * [[Q:%.*]], align 16 ; CHECK-NEXT: ret void ; CHECK: if.else: ; CHECK-NEXT: ret void ; entry: store zeroinitializer, * %p %p1 = getelementptr , * %p, i64 1 store %v, * %p1 br i1 %c, label %if.else, label %if.then if.then: %t = load , * %p ; load could be eliminated store %t, * %q ret void if.else: ret void }