1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -passes=sink -S < %s | FileCheck %s 3 4; Loads marked invariant can be sunk across critical edges. 5 6define <4 x float> @invariant_load(ptr %in, i32 %s) { 7; CHECK-LABEL: @invariant_load( 8; CHECK-NEXT: main_body: 9; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[S:%.*]], 0 10; CHECK-NEXT: br i1 [[C]], label [[BLOCK:%.*]], label [[END:%.*]] 11; CHECK: block: 12; CHECK-NEXT: [[Z:%.*]] = add i32 [[S]], 1 13; CHECK-NEXT: br label [[END]] 14; CHECK: end: 15; CHECK-NEXT: [[V:%.*]] = load <4 x float>, ptr [[IN:%.*]], align 16, !invariant.load [[META0:![0-9]+]] 16; CHECK-NEXT: ret <4 x float> [[V]] 17; 18main_body: 19 %v = load <4 x float>, ptr %in, !invariant.load !0 20 %c = icmp eq i32 %s, 0 21 br i1 %c, label %block, label %end 22block: 23 %z = add i32 %s, 1 24 br label %end 25end: 26 ret <4 x float> %v 27} 28 29; Loads that aren't marked invariant but used in one branch 30; can be sunk to that branch. 31 32define void @invariant_load_use_in_br(ptr %p, i1 %cond) { 33; CHECK-LABEL: @invariant_load_use_in_br( 34; CHECK-NEXT: entry: 35; CHECK-NEXT: br i1 [[COND:%.*]], label [[TRUE_BR:%.*]], label [[FALSE_BR:%.*]] 36; CHECK: true.br: 37; CHECK-NEXT: call void @fn() 38; CHECK-NEXT: br label [[EXIT:%.*]] 39; CHECK: false.br: 40; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[P:%.*]], align 4 41; CHECK-NEXT: call void @fn(i32 [[VAL]]) 42; CHECK-NEXT: br label [[EXIT]] 43; CHECK: exit: 44; CHECK-NEXT: ret void 45; 46entry: 47 %val = load i32, ptr %p 48 br i1 %cond, label %true.br, label %false.br 49true.br: 50 call void @fn() 51 br label %exit 52false.br: 53 call void @fn(i32 %val) 54 br label %exit 55exit: 56 ret void 57} 58 59; TODO: Invariant loads marked with metadata can be sunk past calls. 60 61define void @invariant_load_metadata_call(ptr %p, i1 %cond) { 62; CHECK-LABEL: @invariant_load_metadata_call( 63; CHECK-NEXT: entry: 64; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[P:%.*]], align 4, !invariant.load [[META0]] 65; CHECK-NEXT: call void @fn() 66; CHECK-NEXT: br i1 [[COND:%.*]], label [[TRUE_BR:%.*]], label [[FALSE_BR:%.*]] 67; CHECK: true.br: 68; CHECK-NEXT: call void @fn() 69; CHECK-NEXT: br label [[EXIT:%.*]] 70; CHECK: false.br: 71; CHECK-NEXT: call void @fn(i32 [[VAL]]) 72; CHECK-NEXT: br label [[EXIT]] 73; CHECK: exit: 74; CHECK-NEXT: ret void 75; 76entry: 77 %val = load i32, ptr %p, !invariant.load !0 78 call void @fn() 79 br i1 %cond, label %true.br, label %false.br 80true.br: 81 call void @fn() 82 br label %exit 83false.br: 84 call void @fn(i32 %val) 85 br label %exit 86exit: 87 ret void 88} 89 90declare void @fn() 91 92!0 = !{} 93