; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -S -passes=gvn-hoist < %s | FileCheck %s ; Check that the call and fcmp are hoisted. define void @fun(float %__b) minsize { ; CHECK-LABEL: @fun( ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[IF_THEN:%.*]] ; CHECK: if.then: ; CHECK-NEXT: [[TMP0:%.*]] = call float @llvm.fabs.f32(float [[__B:%.*]]) ; CHECK-NEXT: [[CMPINF7:%.*]] = fcmp oeq float [[TMP0]], 0x7FF0000000000000 ; CHECK-NEXT: br i1 undef, label [[IF_THEN8:%.*]], label [[LOR_LHS_FALSE:%.*]] ; CHECK: lor.lhs.false: ; CHECK-NEXT: unreachable ; CHECK: if.then8: ; CHECK-NEXT: ret void ; entry: br label %if.then if.then: ; preds = %entry br i1 undef, label %if.then8, label %lor.lhs.false lor.lhs.false: ; preds = %if.then %0 = call float @llvm.fabs.f32(float %__b) #2 %cmpinf7 = fcmp oeq float %0, 0x7FF0000000000000 unreachable if.then8: ; preds = %if.then %1 = call float @llvm.fabs.f32(float %__b) #2 %cmpinf10 = fcmp oeq float %1, 0x7FF0000000000000 ret void } declare float @llvm.fabs.f32(float) ; Check that extractvalues are not hoisted into entry, but that non-dependent ; adds are. define i32 @foo(i32 %x) { ; CHECK-LABEL: @foo( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[X:%.*]], 1 ; CHECK-NEXT: [[TMP0:%.*]] = callbr { i32, i32 } asm sideeffect "somestuff", "=r,=r,!i"() ; CHECK-NEXT: to label [[ASM_FALLTHROUGH:%.*]] [label %err.split] ; CHECK: asm.fallthrough: ; CHECK-NEXT: [[ASMRESULT:%.*]] = extractvalue { i32, i32 } [[TMP0]], 0 ; CHECK-NEXT: ret i32 [[ADD]] ; CHECK: err.split: ; CHECK-NEXT: [[ASMRESULT2:%.*]] = extractvalue { i32, i32 } [[TMP0]], 0 ; CHECK-NEXT: ret i32 [[ADD]] ; entry: %0 = callbr { i32, i32 } asm sideeffect "somestuff", "=r,=r,!i"() to label %asm.fallthrough [label %err.split] asm.fallthrough: ; preds = %entry %asmresult = extractvalue { i32, i32 } %0, 0 %add = add nsw i32 %x, 1 ret i32 %add err.split: ; preds = %entry %asmresult2 = extractvalue { i32, i32 } %0, 0 %add2 = add nsw i32 %x, 1 ret i32 %add2 } ; Check that extractvalues and dependent adds are not hoisted into entry. define i32 @foo2() { ; CHECK-LABEL: @foo2( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = callbr { i32, i32 } asm sideeffect "somestuff", "=r,=r,!i"() ; CHECK-NEXT: to label [[ASM_FALLTHROUGH:%.*]] [label %err.split] ; CHECK: asm.fallthrough: ; CHECK-NEXT: [[ASMRESULT:%.*]] = extractvalue { i32, i32 } [[TMP0]], 0 ; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[ASMRESULT]], 1 ; CHECK-NEXT: ret i32 [[ADD]] ; CHECK: err.split: ; CHECK-NEXT: [[ASMRESULT2:%.*]] = extractvalue { i32, i32 } [[TMP0]], 0 ; CHECK-NEXT: [[ADD2:%.*]] = add nsw i32 [[ASMRESULT2]], 1 ; CHECK-NEXT: ret i32 [[ADD2]] ; entry: %0 = callbr { i32, i32 } asm sideeffect "somestuff", "=r,=r,!i"() to label %asm.fallthrough [label %err.split] asm.fallthrough: ; preds = %entry %asmresult = extractvalue { i32, i32 } %0, 0 %add = add nsw i32 %asmresult, 1 ret i32 %add err.split: ; preds = %entry %asmresult2 = extractvalue { i32, i32 } %0, 0 %add2 = add nsw i32 %asmresult2, 1 ret i32 %add2 } ; Ensure we don't hoist loads that are modified by callbr. @x = global i32 0 define i32 @foo3() { ; CHECK-LABEL: @foo3( ; CHECK-NEXT: entry: ; CHECK-NEXT: callbr void asm "", "=*m,!i"(ptr elementtype(i32) @x) ; CHECK-NEXT: to label [[ASM_FALLTHROUGH:%.*]] [label %err.split] ; CHECK: asm.fallthrough: ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr @x, align 4 ; CHECK-NEXT: ret i32 [[TMP0]] ; CHECK: err.split: ; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr @x, align 4 ; CHECK-NEXT: ret i32 [[TMP1]] ; entry: callbr void asm "", "=*m,!i"(ptr elementtype(i32) @x) to label %asm.fallthrough [label %err.split] asm.fallthrough: ; preds = %entry %0 = load i32, ptr @x ret i32 %0 err.split: ; preds = %entry %1 = load i32, ptr @x ret i32 %1 } ; Ensure we do hoist loads that aren't modified by callbr, if the callbr has ; the attribute memory(argmem:readwrite). @y = global i32 0 define i32 @foo4() { ; CHECK-LABEL: @foo4( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr @y, align 4 ; CHECK-NEXT: callbr void asm "", "=*m,!i"(ptr elementtype(i32) @x) #[[ATTR2:[0-9]+]] ; CHECK-NEXT: to label [[A:%.*]] [label %b] ; CHECK: a: ; CHECK-NEXT: ret i32 [[TMP0]] ; CHECK: b: ; CHECK-NEXT: ret i32 [[TMP0]] ; entry: callbr void asm "", "=*m,!i"(ptr elementtype(i32) @x) memory(argmem: readwrite) to label %a [label %b] a: ; preds = %entry %0 = load i32, ptr @y ret i32 %0 b: ; preds = %entry %1 = load i32, ptr @y ret i32 %1 } ; Ensure we don't hoist loads that are modified by callbr, if the callbr has ; the attribute memory(argmem:readwrite). define i32 @foo5() { ; CHECK-LABEL: @foo5( ; CHECK-NEXT: entry: ; CHECK-NEXT: callbr void asm "", "=*m,!i"(ptr elementtype(i32) @x) #[[ATTR2]] ; CHECK-NEXT: to label [[A:%.*]] [label %b] ; CHECK: a: ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr @x, align 4 ; CHECK-NEXT: ret i32 [[TMP0]] ; CHECK: b: ; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr @x, align 4 ; CHECK-NEXT: ret i32 [[TMP1]] ; entry: callbr void asm "", "=*m,!i"(ptr elementtype(i32) @x) memory(argmem: readwrite) to label %a [label %b] a: ; preds = %entry %0 = load i32, ptr @x ret i32 %0 b: ; preds = %entry %1 = load i32, ptr @x ret i32 %1 } ; Ensure we hoist loads that are modified by callbr, if the callbr has the ; attribute memory(argmem:none). define i32 @foo6() { ; CHECK-LABEL: @foo6( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr @x, align 4 ; CHECK-NEXT: callbr void asm "", "=*m,!i"(ptr elementtype(i32) @x) #[[ATTR3:[0-9]+]] ; CHECK-NEXT: to label [[A:%.*]] [label %b] ; CHECK: a: ; CHECK-NEXT: ret i32 [[TMP0]] ; CHECK: b: ; CHECK-NEXT: ret i32 [[TMP0]] ; entry: callbr void asm "", "=*m,!i"(ptr elementtype(i32) @x) memory(argmem: none) to label %a [label %b] a: ; preds = %entry %0 = load i32, ptr @x ret i32 %0 b: ; preds = %entry %1 = load i32, ptr @x ret i32 %1 }