1; RUN: opt < %s -basic-aa -sink -S | FileCheck %s 2 3declare i32 @f_load_global() nounwind readonly 4declare i32 @f_load_global_throwable() readonly 5declare i32 @f_load_arg(i32*) nounwind readonly argmemonly 6declare void @f_store_global(i32) nounwind 7declare void @f_store_arg(i32*) nounwind argmemonly 8declare void @f_readonly_arg(i32* readonly, i32*) nounwind argmemonly 9declare i32 @f_readnone(i32) nounwind readnone 10 11@A = external global i32 12@B = external global i32 13 14; Sink readonly call if no stores are in the way. 15; 16; CHECK-LABEL: @test_sink_no_stores( 17; CHECK: true: 18; CHECK-NEXT: %l = call i32 @f_load_global 19; CHECK-NEXT: ret i32 %l 20define i32 @test_sink_no_stores(i1 %z) { 21 %l = call i32 @f_load_global() 22 br i1 %z, label %true, label %false 23true: 24 ret i32 %l 25false: 26 ret i32 0 27} 28 29; CHECK-LABEL: @test_throwable_no_stores( 30; CHECK: %l = call i32 @f_load_global 31; CHECK-NEXT: br i1 %z 32define i32 @test_throwable_no_stores(i1 %z) { 33 %l = call i32 @f_load_global_throwable() 34 br i1 %z, label %true, label %false 35true: 36 ret i32 %l 37false: 38 ret i32 0 39} 40 41; CHECK-LABEL: @test_sink_argmem_store( 42; CHECK: true: 43; CHECK-NEXT: %l = call i32 @f_load_arg 44; CHECK-NEXT: ret i32 %l 45define i32 @test_sink_argmem_store(i1 %z) { 46 %l = call i32 @f_load_arg(i32* @A) 47 store i32 0, i32* @B 48 br i1 %z, label %true, label %false 49true: 50 ret i32 %l 51false: 52 ret i32 0 53} 54 55; CHECK-LABEL: @test_sink_argmem_call( 56; CHECK: true: 57; CHECK-NEXT: %l = call i32 @f_load_arg 58; CHECK-NEXT: ret i32 %l 59define i32 @test_sink_argmem_call(i1 %z) { 60 %l = call i32 @f_load_arg(i32* @A) 61 call void @f_store_arg(i32* @B) 62 br i1 %z, label %true, label %false 63true: 64 ret i32 %l 65false: 66 ret i32 0 67} 68 69; CHECK-LABEL: @test_sink_argmem_multiple( 70; CHECK: true: 71; CHECK-NEXT: %l = call i32 @f_load_arg 72; CHECK-NEXT: ret i32 %l 73define i32 @test_sink_argmem_multiple(i1 %z) { 74 %l = call i32 @f_load_arg(i32* @A) 75 call void @f_readonly_arg(i32* @A, i32* @B) 76 br i1 %z, label %true, label %false 77true: 78 ret i32 %l 79false: 80 ret i32 0 81} 82 83; But don't sink if there is a store. 84; 85; CHECK-LABEL: @test_nosink_store( 86; CHECK: call i32 @f_load_global 87; CHECK-NEXT: store i32 88define i32 @test_nosink_store(i1 %z) { 89 %l = call i32 @f_load_global() 90 store i32 0, i32* @A 91 br i1 %z, label %true, label %false 92true: 93 ret i32 %l 94false: 95 ret i32 0 96} 97 98; CHECK-LABEL: @test_nosink_call( 99; CHECK: call i32 @f_load_global 100; CHECK-NEXT: call void @f_store_global 101define i32 @test_nosink_call(i1 %z) { 102 %l = call i32 @f_load_global() 103 call void @f_store_global(i32 0) 104 br i1 %z, label %true, label %false 105true: 106 ret i32 %l 107false: 108 ret i32 0 109} 110 111; readnone calls are sunk across stores. 112; 113; CHECK-LABEL: @test_sink_readnone( 114; CHECK: true: 115; CHECK-NEXT: %l = call i32 @f_readnone( 116; CHECK-NEXT: ret i32 %l 117define i32 @test_sink_readnone(i1 %z) { 118 %l = call i32 @f_readnone(i32 0) 119 store i32 0, i32* @A 120 br i1 %z, label %true, label %false 121true: 122 ret i32 %l 123false: 124 ret i32 0 125} 126