1; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<target-ir>,require<scalar-evolution>,require<opt-remark-emit>,loop-mssa(licm)' < %s -S | FileCheck %s 2 3declare i32 @foo() readonly argmemonly nounwind 4declare i32 @foo2() readonly nounwind 5declare i32 @bar(ptr %loc2) readonly argmemonly nounwind 6 7define void @test(ptr %loc) { 8; CHECK-LABEL: @test 9; CHECK: @foo 10; CHECK-LABEL: loop: 11 br label %loop 12 13loop: 14 %res = call i32 @foo() 15 store i32 %res, ptr %loc 16 br label %loop 17} 18 19; Negative test: show argmemonly is required 20define void @test_neg(ptr %loc) { 21; CHECK-LABEL: @test_neg 22; CHECK-LABEL: loop: 23; CHECK: @foo 24 br label %loop 25 26loop: 27 %res = call i32 @foo2() 28 store i32 %res, ptr %loc 29 br label %loop 30} 31 32define void @test2(ptr noalias %loc, ptr noalias %loc2) { 33; CHECK-LABEL: @test2 34; CHECK: @bar 35; CHECK-LABEL: loop: 36 br label %loop 37 38loop: 39 %res = call i32 @bar(ptr %loc2) 40 store i32 %res, ptr %loc 41 br label %loop 42} 43 44; Negative test: %might clobber gep 45define void @test3(ptr %loc) { 46; CHECK-LABEL: @test3 47; CHECK-LABEL: loop: 48; CHECK: @bar 49 br label %loop 50 51loop: 52 %res = call i32 @bar(ptr %loc) 53 %gep = getelementptr i32, ptr %loc, i64 1000000 54 store i32 %res, ptr %gep 55 br label %loop 56} 57 58 59; Negative test: %loc might alias %loc2 60define void @test4(ptr %loc, ptr %loc2) { 61; CHECK-LABEL: @test4 62; CHECK-LABEL: loop: 63; CHECK: @bar 64 br label %loop 65 66loop: 67 %res = call i32 @bar(ptr %loc2) 68 store i32 %res, ptr %loc 69 br label %loop 70} 71 72declare i32 @foo_new(ptr) readonly 73 74define void @test5(ptr %loc2, ptr noalias %loc) { 75; CHECK-LABEL: @test5 76; CHECK: @bar 77; CHECK-LABEL: loop: 78 br label %loop 79 80loop: 81 %res1 = call i32 @bar(ptr %loc2) 82 %res = call i32 @foo_new(ptr %loc2) 83 store volatile i32 %res1, ptr %loc 84 br label %loop 85} 86 87 88; memcpy doesn't write to it's source argument, so loads to that location 89; can still be hoisted 90define void @test6(ptr noalias %loc, ptr noalias %loc2) { 91; CHECK-LABEL: @test6 92; CHECK: %val = load i32, ptr %loc2 93; CHECK-LABEL: loop: 94; CHECK: @llvm.memcpy 95 br label %loop 96 97loop: 98 %val = load i32, ptr %loc2 99 store i32 %val, ptr %loc 100 call void @llvm.memcpy.p0.p0.i64(ptr %loc, ptr %loc2, i64 8, i1 false) 101 br label %loop 102} 103 104define void @test7(ptr noalias %loc, ptr noalias %loc2) { 105; CHECK-LABEL: @test7 106; CHECK: %val = load i32, ptr %loc2 107; CHECK-LABEL: loop: 108; CHECK: @custom_memcpy 109 br label %loop 110 111loop: 112 %val = load i32, ptr %loc2 113 store i32 %val, ptr %loc 114 call void @custom_memcpy(ptr %loc, ptr %loc2) 115 br label %loop 116} 117 118declare void @llvm.memcpy.p0.p0.i64(ptr nocapture writeonly, ptr nocapture readonly, i64, i1) 119declare void @custom_memcpy(ptr nocapture writeonly, ptr nocapture readonly) argmemonly nounwind 120