; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -passes=sink -S < %s | FileCheck %s ; Loads marked invariant can be sunk across critical edges. define <4 x float> @invariant_load(ptr %in, i32 %s) { ; CHECK-LABEL: @invariant_load( ; CHECK-NEXT: main_body: ; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[S:%.*]], 0 ; CHECK-NEXT: br i1 [[C]], label [[BLOCK:%.*]], label [[END:%.*]] ; CHECK: block: ; CHECK-NEXT: [[Z:%.*]] = add i32 [[S]], 1 ; CHECK-NEXT: br label [[END]] ; CHECK: end: ; CHECK-NEXT: [[V:%.*]] = load <4 x float>, ptr [[IN:%.*]], align 16, !invariant.load [[META0:![0-9]+]] ; CHECK-NEXT: ret <4 x float> [[V]] ; main_body: %v = load <4 x float>, ptr %in, !invariant.load !0 %c = icmp eq i32 %s, 0 br i1 %c, label %block, label %end block: %z = add i32 %s, 1 br label %end end: ret <4 x float> %v } ; Loads that aren't marked invariant but used in one branch ; can be sunk to that branch. define void @invariant_load_use_in_br(ptr %p, i1 %cond) { ; CHECK-LABEL: @invariant_load_use_in_br( ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 [[COND:%.*]], label [[TRUE_BR:%.*]], label [[FALSE_BR:%.*]] ; CHECK: true.br: ; CHECK-NEXT: call void @fn() ; CHECK-NEXT: br label [[EXIT:%.*]] ; CHECK: false.br: ; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[P:%.*]], align 4 ; CHECK-NEXT: call void @fn(i32 [[VAL]]) ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void ; entry: %val = load i32, ptr %p br i1 %cond, label %true.br, label %false.br true.br: call void @fn() br label %exit false.br: call void @fn(i32 %val) br label %exit exit: ret void } ; TODO: Invariant loads marked with metadata can be sunk past calls. define void @invariant_load_metadata_call(ptr %p, i1 %cond) { ; CHECK-LABEL: @invariant_load_metadata_call( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[P:%.*]], align 4, !invariant.load [[META0]] ; CHECK-NEXT: call void @fn() ; CHECK-NEXT: br i1 [[COND:%.*]], label [[TRUE_BR:%.*]], label [[FALSE_BR:%.*]] ; CHECK: true.br: ; CHECK-NEXT: call void @fn() ; CHECK-NEXT: br label [[EXIT:%.*]] ; CHECK: false.br: ; CHECK-NEXT: call void @fn(i32 [[VAL]]) ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void ; entry: %val = load i32, ptr %p, !invariant.load !0 call void @fn() br i1 %cond, label %true.br, label %false.br true.br: call void @fn() br label %exit false.br: call void @fn(i32 %val) br label %exit exit: ret void } declare void @fn() !0 = !{}