diff options
Diffstat (limited to 'llvm/test/Transforms/JumpThreading/assume.ll')
-rw-r--r-- | llvm/test/Transforms/JumpThreading/assume.ll | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/llvm/test/Transforms/JumpThreading/assume.ll b/llvm/test/Transforms/JumpThreading/assume.ll new file mode 100644 index 00000000000..f58ee299cba --- /dev/null +++ b/llvm/test/Transforms/JumpThreading/assume.ll @@ -0,0 +1,241 @@ +; RUN: opt -S -jump-threading -dce < %s | FileCheck %s +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: nounwind uwtable +define i32 @test1(i32 %a, i32 %b) #0 { +entry: + %cmp = icmp sgt i32 %a, 5 + tail call void @llvm.assume(i1 %cmp) + %cmp1 = icmp sgt i32 %b, 1234 + br i1 %cmp1, label %if.then, label %if.else + +; CHECK-LABEL: @test1 +; CHECK: icmp sgt i32 %a, 5 +; CHECK: call void @llvm.assume +; CHECK-NOT: icmp sgt i32 %a, 3 +; CHECK: ret i32 + +if.then: ; preds = %entry + %cmp2 = icmp sgt i32 %a, 3 + br i1 %cmp2, label %if.then3, label %return + +if.then3: ; preds = %if.then + tail call void (...) @bar() #1 + br label %return + +if.else: ; preds = %entry + tail call void (...) @car() #1 + br label %return + +return: ; preds = %if.else, %if.then, %if.then3 + %retval.0 = phi i32 [ 1, %if.then3 ], [ 0, %if.then ], [ 0, %if.else ] + ret i32 %retval.0 +} + +define i32 @test2(i32 %a) #0 { +entry: + %cmp = icmp sgt i32 %a, 5 + tail call void @llvm.assume(i1 %cmp) + %cmp1 = icmp sgt i32 %a, 3 + br i1 %cmp1, label %if.then, label %return + +; CHECK-LABEL: @test2 +; CHECK: icmp sgt i32 %a, 5 +; CHECK: tail call void @llvm.assume +; CHECK: tail call void (...) @bar() +; CHECK: ret i32 1 + + +if.then: ; preds = %entry + tail call void (...) @bar() #1 + br label %return + +return: ; preds = %entry, %if.then + %retval.0 = phi i32 [ 1, %if.then ], [ 0, %entry ] + ret i32 %retval.0 +} + +@g = external global i32 + +; Check that we do prove a fact using an assume within the block. +; We can fold the assume based on the semantics of assume. +define void @can_fold_assume(i32* %array) { +; CHECK-LABEL: @can_fold_assume +; CHECK-NOT: call void @llvm.assume +; CHECK-NOT: br +; CHECK: ret void + %notnull = icmp ne i32* %array, null + call void @llvm.assume(i1 %notnull) + br i1 %notnull, label %normal, label %error + +normal: + ret void + +error: + store atomic i32 0, i32* @g unordered, align 4 + ret void +} + +declare void @f(i1) +declare void @exit() +; We can fold the assume but not the uses before the assume. +define void @cannot_fold_use_before_assume(i32* %array) { +; CHECK-LABEL:@cannot_fold_use_before_assume +; CHECK: @f(i1 %notnull) +; CHECK-NEXT: exit() +; CHECK-NOT: assume +; CHECK-NEXT: ret void + %notnull = icmp ne i32* %array, null + call void @f(i1 %notnull) + call void @exit() + call void @llvm.assume(i1 %notnull) + br i1 %notnull, label %normal, label %error + +normal: + ret void + +error: + store atomic i32 0, i32* @g unordered, align 4 + ret void +} + +declare void @dummy(i1) nounwind argmemonly +define void @can_fold_some_use_before_assume(i32* %array) { + +; CHECK-LABEL:@can_fold_some_use_before_assume +; CHECK: @f(i1 %notnull) +; CHECK-NEXT: @dummy(i1 true) +; CHECK-NOT: assume +; CHECK-NEXT: ret void + %notnull = icmp ne i32* %array, null + call void @f(i1 %notnull) + call void @dummy(i1 %notnull) + call void @llvm.assume(i1 %notnull) + br i1 %notnull, label %normal, label %error + +normal: + ret void + +error: + store atomic i32 0, i32* @g unordered, align 4 + ret void + +} + +; FIXME: can fold assume and all uses before/after assume. +; because the trapping exit call is after the assume. +define void @can_fold_assume_and_all_uses(i32* %array) { +; CHECK-LABEL:@can_fold_assume_and_all_uses +; CHECK: @dummy(i1 %notnull) +; CHECK-NEXT: assume(i1 %notnull) +; CHECK-NEXT: exit() +; CHECK-NEXT: %notnull2 = or i1 true, false +; CHECK-NEXT: @f(i1 %notnull2) +; CHECK-NEXT: ret void + %notnull = icmp ne i32* %array, null + call void @dummy(i1 %notnull) + call void @llvm.assume(i1 %notnull) + call void @exit() + br i1 %notnull, label %normal, label %error + +normal: + %notnull2 = or i1 %notnull, false + call void @f(i1 %notnull2) + ret void + +error: + store atomic i32 0, i32* @g unordered, align 4 + ret void +} + +declare void @fz(i8) +; FIXME: We can fold assume to true, and the use after assume, but we do not do so +; currently, because of the function call after the assume. +define void @can_fold_assume2(i32* %array) { + +; CHECK-LABEL:@can_fold_assume2 +; CHECK: @f(i1 %notnull) +; CHECK-NEXT: assume(i1 %notnull) +; CHECK-NEXT: znotnull = zext i1 %notnull to i8 +; CHECK-NEXT: @f(i1 %notnull) +; CHECK-NEXT: @f(i1 true) +; CHECK-NEXT: @fz(i8 %znotnull) +; CHECK-NEXT: ret void + %notnull = icmp ne i32* %array, null + call void @f(i1 %notnull) + call void @llvm.assume(i1 %notnull) + %znotnull = zext i1 %notnull to i8 + call void @f(i1 %notnull) + br i1 %notnull, label %normal, label %error + +normal: + call void @f(i1 %notnull) + call void @fz(i8 %znotnull) + ret void + +error: + store atomic i32 0, i32* @g unordered, align 4 + ret void +} + +declare void @llvm.experimental.guard(i1, ...) +; FIXME: We can fold assume to true, but we do not do so +; because of the guard following the assume. +define void @can_fold_assume3(i32* %array){ + +; CHECK-LABEL:@can_fold_assume3 +; CHECK: @f(i1 %notnull) +; CHECK-NEXT: assume(i1 %notnull) +; CHECK-NEXT: guard(i1 %notnull) +; CHECK-NEXT: znotnull = zext i1 true to i8 +; CHECK-NEXT: @f(i1 true) +; CHECK-NEXT: @fz(i8 %znotnull) +; CHECK-NEXT: ret void + %notnull = icmp ne i32* %array, null + call void @f(i1 %notnull) + call void @llvm.assume(i1 %notnull) + call void(i1, ...) @llvm.experimental.guard(i1 %notnull) [ "deopt"() ] + %znotnull = zext i1 %notnull to i8 + br i1 %notnull, label %normal, label %error + +normal: + call void @f(i1 %notnull) + call void @fz(i8 %znotnull) + ret void + +error: + store atomic i32 0, i32* @g unordered, align 4 + ret void +} + + +; can fold all uses and remove the cond +define void @can_fold_assume4(i32* %array) { +; CHECK-LABEL: can_fold_assume4 +; CHECK-NOT: notnull +; CHECK: dummy(i1 true) +; CHECK-NEXT: ret void + %notnull = icmp ne i32* %array, null + call void @exit() + call void @dummy(i1 %notnull) + call void @llvm.assume(i1 %notnull) + br i1 %notnull, label %normal, label %error + +normal: + ret void + +error: + store atomic i32 0, i32* @g unordered, align 4 + ret void +} +; Function Attrs: nounwind +declare void @llvm.assume(i1) #1 + +declare void @bar(...) + +declare void @car(...) + +attributes #0 = { nounwind uwtable } +attributes #1 = { nounwind } + |