; RUN: opt -S -early-cse < %s | FileCheck %s declare void @clobber_and_use(i32) define void @f_0(i32* %ptr) { ; CHECK-LABEL: @f_0( ; CHECK: %val0 = load i32, i32* %ptr, !invariant.load !0 ; CHECK: call void @clobber_and_use(i32 %val0) ; CHECK: call void @clobber_and_use(i32 %val0) ; CHECK: call void @clobber_and_use(i32 %val0) ; CHECK: ret void %val0 = load i32, i32* %ptr, !invariant.load !{} call void @clobber_and_use(i32 %val0) %val1 = load i32, i32* %ptr, !invariant.load !{} call void @clobber_and_use(i32 %val1) %val2 = load i32, i32* %ptr, !invariant.load !{} call void @clobber_and_use(i32 %val2) ret void } define void @f_1(i32* %ptr) { ; We can forward invariant loads to non-invariant loads, since once an ; invariant load has executed, the location loaded from is known to be ; unchanging. ; CHECK-LABEL: @f_1( ; CHECK: %val0 = load i32, i32* %ptr, !invariant.load !0 ; CHECK: call void @clobber_and_use(i32 %val0) ; CHECK: call void @clobber_and_use(i32 %val0) %val0 = load i32, i32* %ptr, !invariant.load !{} call void @clobber_and_use(i32 %val0) %val1 = load i32, i32* %ptr call void @clobber_and_use(i32 %val1) ret void } define void @f_2(i32* %ptr) { ; Negative test -- we can't forward a non-invariant load into an ; invariant load. ; CHECK-LABEL: @f_2( ; CHECK: %val0 = load i32, i32* %ptr ; CHECK: call void @clobber_and_use(i32 %val0) ; CHECK: %val1 = load i32, i32* %ptr, !invariant.load !0 ; CHECK: call void @clobber_and_use(i32 %val1) %val0 = load i32, i32* %ptr call void @clobber_and_use(i32 %val0) %val1 = load i32, i32* %ptr, !invariant.load !{} call void @clobber_and_use(i32 %val1) ret void } define void @f_3(i1 %cond, i32* %ptr) { ; CHECK-LABEL: @f_3( %val0 = load i32, i32* %ptr, !invariant.load !{} call void @clobber_and_use(i32 %val0) br i1 %cond, label %left, label %right ; CHECK: %val0 = load i32, i32* %ptr, !invariant.load !0 ; CHECK: left: ; CHECK-NEXT: call void @clobber_and_use(i32 %val0) left: %val1 = load i32, i32* %ptr call void @clobber_and_use(i32 %val1) ret void right: ret void } define void @f_4(i1 %cond, i32* %ptr) { ; Negative test -- can't forward %val0 to %va1 because that'll break ; def-dominates-use. ; CHECK-LABEL: @f_4( br i1 %cond, label %left, label %merge left: ; CHECK: left: ; CHECK-NEXT: %val0 = load i32, i32* %ptr, !invariant.load ! ; CHECK-NEXT: call void @clobber_and_use(i32 %val0) %val0 = load i32, i32* %ptr, !invariant.load !{} call void @clobber_and_use(i32 %val0) br label %merge merge: ; CHECK: merge: ; CHECK-NEXT: %val1 = load i32, i32* %ptr ; CHECK-NEXT: call void @clobber_and_use(i32 %val1) %val1 = load i32, i32* %ptr call void @clobber_and_use(i32 %val1) ret void }