1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=sink -S | FileCheck %s 3 4declare i32 @f_load_global() nounwind willreturn readonly 5declare i32 @f_load_global_throwable() willreturn readonly 6declare i32 @f_load_global_may_not_return() nounwind readonly 7declare i32 @f_load_arg(ptr) nounwind willreturn readonly argmemonly 8declare void @f_store_global(i32) nounwind willreturn 9declare void @f_store_arg(ptr) nounwind willreturn argmemonly 10declare void @f_readonly_arg(ptr readonly, ptr) nounwind willreturn argmemonly 11declare i32 @f_readnone(i32) nounwind willreturn readnone 12 13@A = external global i32 14@B = external global i32 15 16; Sink readonly call if no stores are in the way. 17; 18define i32 @test_sink_no_stores(i1 %z) { 19; CHECK-LABEL: @test_sink_no_stores( 20; CHECK-NEXT: br i1 [[Z:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]] 21; CHECK: true: 22; CHECK-NEXT: [[L:%.*]] = call i32 @f_load_global() 23; CHECK-NEXT: ret i32 [[L]] 24; CHECK: false: 25; CHECK-NEXT: ret i32 0 26; 27 %l = call i32 @f_load_global() 28 br i1 %z, label %true, label %false 29true: 30 ret i32 %l 31false: 32 ret i32 0 33} 34 35define i32 @test_throwable_no_stores(i1 %z) { 36; CHECK-LABEL: @test_throwable_no_stores( 37; CHECK-NEXT: [[L:%.*]] = call i32 @f_load_global_throwable() 38; CHECK-NEXT: br i1 [[Z:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]] 39; CHECK: true: 40; CHECK-NEXT: ret i32 [[L]] 41; CHECK: false: 42; CHECK-NEXT: ret i32 0 43; 44 %l = call i32 @f_load_global_throwable() 45 br i1 %z, label %true, label %false 46true: 47 ret i32 %l 48false: 49 ret i32 0 50} 51 52define i32 @test_may_not_return_no_stores(i1 %z) { 53; CHECK-LABEL: @test_may_not_return_no_stores( 54; CHECK-NEXT: [[L:%.*]] = call i32 @f_load_global_may_not_return() 55; CHECK-NEXT: br i1 [[Z:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]] 56; CHECK: true: 57; CHECK-NEXT: ret i32 [[L]] 58; CHECK: false: 59; CHECK-NEXT: ret i32 0 60; 61 %l = call i32 @f_load_global_may_not_return() 62 br i1 %z, label %true, label %false 63true: 64 ret i32 %l 65false: 66 ret i32 0 67} 68 69define i32 @test_sink_argmem_store(i1 %z) { 70; CHECK-LABEL: @test_sink_argmem_store( 71; CHECK-NEXT: store i32 0, ptr @B, align 4 72; CHECK-NEXT: br i1 [[Z:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]] 73; CHECK: true: 74; CHECK-NEXT: [[L:%.*]] = call i32 @f_load_arg(ptr @A) 75; CHECK-NEXT: ret i32 [[L]] 76; CHECK: false: 77; CHECK-NEXT: ret i32 0 78; 79 %l = call i32 @f_load_arg(ptr @A) 80 store i32 0, ptr @B 81 br i1 %z, label %true, label %false 82true: 83 ret i32 %l 84false: 85 ret i32 0 86} 87 88define i32 @test_sink_argmem_call(i1 %z) { 89; CHECK-LABEL: @test_sink_argmem_call( 90; CHECK-NEXT: call void @f_store_arg(ptr @B) 91; CHECK-NEXT: br i1 [[Z:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]] 92; CHECK: true: 93; CHECK-NEXT: [[L:%.*]] = call i32 @f_load_arg(ptr @A) 94; CHECK-NEXT: ret i32 [[L]] 95; CHECK: false: 96; CHECK-NEXT: ret i32 0 97; 98 %l = call i32 @f_load_arg(ptr @A) 99 call void @f_store_arg(ptr @B) 100 br i1 %z, label %true, label %false 101true: 102 ret i32 %l 103false: 104 ret i32 0 105} 106 107define i32 @test_sink_argmem_multiple(i1 %z) { 108; CHECK-LABEL: @test_sink_argmem_multiple( 109; CHECK-NEXT: call void @f_readonly_arg(ptr @A, ptr @B) 110; CHECK-NEXT: br i1 [[Z:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]] 111; CHECK: true: 112; CHECK-NEXT: [[L:%.*]] = call i32 @f_load_arg(ptr @A) 113; CHECK-NEXT: ret i32 [[L]] 114; CHECK: false: 115; CHECK-NEXT: ret i32 0 116; 117 %l = call i32 @f_load_arg(ptr @A) 118 call void @f_readonly_arg(ptr @A, ptr @B) 119 br i1 %z, label %true, label %false 120true: 121 ret i32 %l 122false: 123 ret i32 0 124} 125 126; But don't sink if there is a store. 127define i32 @test_nosink_store(i1 %z) { 128; CHECK-LABEL: @test_nosink_store( 129; CHECK-NEXT: [[L:%.*]] = call i32 @f_load_global() 130; CHECK-NEXT: store i32 0, ptr @A, align 4 131; CHECK-NEXT: br i1 [[Z:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]] 132; CHECK: true: 133; CHECK-NEXT: ret i32 [[L]] 134; CHECK: false: 135; CHECK-NEXT: ret i32 0 136; 137 %l = call i32 @f_load_global() 138 store i32 0, ptr @A 139 br i1 %z, label %true, label %false 140true: 141 ret i32 %l 142false: 143 ret i32 0 144} 145 146define i32 @test_nosink_call(i1 %z) { 147; CHECK-LABEL: @test_nosink_call( 148; CHECK-NEXT: [[L:%.*]] = call i32 @f_load_global() 149; CHECK-NEXT: call void @f_store_global(i32 0) 150; CHECK-NEXT: br i1 [[Z:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]] 151; CHECK: true: 152; CHECK-NEXT: ret i32 [[L]] 153; CHECK: false: 154; CHECK-NEXT: ret i32 0 155; 156 %l = call i32 @f_load_global() 157 call void @f_store_global(i32 0) 158 br i1 %z, label %true, label %false 159true: 160 ret i32 %l 161false: 162 ret i32 0 163} 164 165; readnone calls are sunk across stores. 166define i32 @test_sink_readnone(i1 %z) { 167; CHECK-LABEL: @test_sink_readnone( 168; CHECK-NEXT: store i32 0, ptr @A, align 4 169; CHECK-NEXT: br i1 [[Z:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]] 170; CHECK: true: 171; CHECK-NEXT: [[L:%.*]] = call i32 @f_readnone(i32 0) 172; CHECK-NEXT: ret i32 [[L]] 173; CHECK: false: 174; CHECK-NEXT: ret i32 0 175; 176 %l = call i32 @f_readnone(i32 0) 177 store i32 0, ptr @A 178 br i1 %z, label %true, label %false 179true: 180 ret i32 %l 181false: 182 ret i32 0 183} 184