diff options
Diffstat (limited to 'test/Transforms/GVN/volatile.ll')
-rw-r--r-- | test/Transforms/GVN/volatile.ll | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/test/Transforms/GVN/volatile.ll b/test/Transforms/GVN/volatile.ll new file mode 100644 index 0000000..5ba03d9 --- /dev/null +++ b/test/Transforms/GVN/volatile.ll @@ -0,0 +1,157 @@ +; Tests that check our handling of volatile instructions encountered +; when scanning for dependencies +; RUN: opt -basicaa -gvn -S < %s | FileCheck %s + +; Check that we can bypass a volatile load when searching +; for dependencies of a non-volatile load +define i32 @test1(i32* nocapture %p, i32* nocapture %q) { +; CHECK-LABEL: test1 +; CHECK: %0 = load volatile i32* %q +; CHECK-NEXT: ret i32 0 +entry: + %x = load i32* %p + load volatile i32* %q + %y = load i32* %p + %add = sub i32 %y, %x + ret i32 %add +} + +; We can not value forward if the query instruction is +; volatile, this would be (in effect) removing the volatile load +define i32 @test2(i32* nocapture %p, i32* nocapture %q) { +; CHECK-LABEL: test2 +; CHECK: %x = load i32* %p +; CHECK-NEXT: %y = load volatile i32* %p +; CHECK-NEXT: %add = sub i32 %y, %x +entry: + %x = load i32* %p + %y = load volatile i32* %p + %add = sub i32 %y, %x + ret i32 %add +} + +; If the query instruction is itself volatile, we *cannot* +; reorder it even if p and q are noalias +define i32 @test3(i32* noalias nocapture %p, i32* noalias nocapture %q) { +; CHECK-LABEL: test3 +; CHECK: %x = load i32* %p +; CHECK-NEXT: %0 = load volatile i32* %q +; CHECK-NEXT: %y = load volatile i32* %p +entry: + %x = load i32* %p + load volatile i32* %q + %y = load volatile i32* %p + %add = sub i32 %y, %x + ret i32 %add +} + +; If an encountered instruction is both volatile and ordered, +; we need to use the strictest ordering of either. In this +; case, the ordering prevents forwarding. +define i32 @test4(i32* noalias nocapture %p, i32* noalias nocapture %q) { +; CHECK-LABEL: test4 +; CHECK: %x = load i32* %p +; CHECK-NEXT: %0 = load atomic volatile i32* %q seq_cst +; CHECK-NEXT: %y = load atomic i32* %p seq_cst +entry: + %x = load i32* %p + load atomic volatile i32* %q seq_cst, align 4 + %y = load atomic i32* %p seq_cst, align 4 + %add = sub i32 %y, %x + ret i32 %add +} + +; Value forwarding from a volatile load is perfectly legal +define i32 @test5(i32* nocapture %p, i32* nocapture %q) { +; CHECK-LABEL: test5 +; CHECK: %x = load volatile i32* %p +; CHECK-NEXT: ret i32 0 +entry: + %x = load volatile i32* %p + %y = load i32* %p + %add = sub i32 %y, %x + ret i32 %add +} + +; Does cross block redundancy elimination work with volatiles? +define i32 @test6(i32* noalias nocapture %p, i32* noalias nocapture %q) { +; CHECK-LABEL: test6 +; CHECK: %y1 = load i32* %p +; CHECK-LABEL: header +; CHECK: %x = load volatile i32* %q +; CHECK-NEXT: %add = sub i32 %y1, %x +entry: + %y1 = load i32* %p + call void @use(i32 %y1) + br label %header +header: + %x = load volatile i32* %q + %y = load i32* %p + %add = sub i32 %y, %x + %cnd = icmp eq i32 %add, 0 + br i1 %cnd, label %exit, label %header +exit: + ret i32 %add +} + +; Does cross block PRE work with volatiles? +define i32 @test7(i1 %c, i32* noalias nocapture %p, i32* noalias nocapture %q) { +; CHECK-LABEL: test7 +; CHECK-LABEL: entry.header_crit_edge: +; CHECK: %y.pre = load i32* %p +; CHECK-LABEL: skip: +; CHECK: %y1 = load i32* %p +; CHECK-LABEL: header: +; CHECK: %y = phi i32 +; CHECK-NEXT: %x = load volatile i32* %q +; CHECK-NEXT: %add = sub i32 %y, %x +entry: + br i1 %c, label %header, label %skip +skip: + %y1 = load i32* %p + call void @use(i32 %y1) + br label %header +header: + %x = load volatile i32* %q + %y = load i32* %p + %add = sub i32 %y, %x + %cnd = icmp eq i32 %add, 0 + br i1 %cnd, label %exit, label %header +exit: + ret i32 %add +} + +; Another volatile PRE case - two paths through a loop +; load in preheader, one path read only, one not +define i32 @test8(i1 %b, i1 %c, i32* noalias %p, i32* noalias %q) { +; CHECK-LABEL: test8 +; CHECK-LABEL: entry +; CHECK: %y1 = load i32* %p +; CHECK-LABEL: header: +; CHECK: %y = phi i32 +; CHECK-NEXT: %x = load volatile i32* %q +; CHECK-NOT: load +; CHECK-LABEL: skip.header_crit_edge: +; CHECK: %y.pre = load i32* %p +entry: + %y1 = load i32* %p + call void @use(i32 %y1) + br label %header +header: + %x = load volatile i32* %q + %y = load i32* %p + call void @use(i32 %y) + br i1 %b, label %skip, label %header +skip: + ; escaping the arguments is explicitly required since we marked + ; them noalias + call void @clobber(i32* %p, i32* %q) + br i1 %c, label %header, label %exit +exit: + %add = sub i32 %y, %x + ret i32 %add +} + +declare void @use(i32) readonly +declare void @clobber(i32* %p, i32* %q) + |