1; RUN: opt -S -jump-threading -dce < %s | FileCheck %s 2target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 3target triple = "x86_64-unknown-linux-gnu" 4 5; Function Attrs: nounwind uwtable 6define i32 @test1(i32 %a, i32 %b) #0 { 7entry: 8 %cmp = icmp sgt i32 %a, 5 9 tail call void @llvm.assume(i1 %cmp) 10 %cmp1 = icmp sgt i32 %b, 1234 11 br i1 %cmp1, label %if.then, label %if.else 12 13; CHECK-LABEL: @test1 14; CHECK: icmp sgt i32 %a, 5 15; CHECK: call void @llvm.assume 16; CHECK-NOT: icmp sgt i32 %a, 3 17; CHECK: ret i32 18 19if.then: ; preds = %entry 20 %cmp2 = icmp sgt i32 %a, 3 21 br i1 %cmp2, label %if.then3, label %return 22 23if.then3: ; preds = %if.then 24 tail call void (...) @bar() #1 25 br label %return 26 27if.else: ; preds = %entry 28 tail call void (...) @car() #1 29 br label %return 30 31return: ; preds = %if.else, %if.then, %if.then3 32 %retval.0 = phi i32 [ 1, %if.then3 ], [ 0, %if.then ], [ 0, %if.else ] 33 ret i32 %retval.0 34} 35 36define i32 @test2(i32 %a) #0 { 37entry: 38 %cmp = icmp sgt i32 %a, 5 39 tail call void @llvm.assume(i1 %cmp) 40 %cmp1 = icmp sgt i32 %a, 3 41 br i1 %cmp1, label %if.then, label %return 42 43; CHECK-LABEL: @test2 44; CHECK: icmp sgt i32 %a, 5 45; CHECK: tail call void @llvm.assume 46; CHECK: tail call void (...) @bar() 47; CHECK: ret i32 1 48 49 50if.then: ; preds = %entry 51 tail call void (...) @bar() #1 52 br label %return 53 54return: ; preds = %entry, %if.then 55 %retval.0 = phi i32 [ 1, %if.then ], [ 0, %entry ] 56 ret i32 %retval.0 57} 58 59@g = external global i32 60 61; Check that we do prove a fact using an assume within the block. 62; We can fold the assume based on the semantics of assume. 63define void @can_fold_assume(i32* %array) { 64; CHECK-LABEL: @can_fold_assume 65; CHECK-NOT: call void @llvm.assume 66; CHECK-NOT: br 67; CHECK: ret void 68 %notnull = icmp ne i32* %array, null 69 call void @llvm.assume(i1 %notnull) 70 br i1 %notnull, label %normal, label %error 71 72normal: 73 ret void 74 75error: 76 store atomic i32 0, i32* @g unordered, align 4 77 ret void 78} 79 80declare void @f(i1) 81declare void @exit() 82; We can fold the assume but not the uses before the assume. 83define void @cannot_fold_use_before_assume(i32* %array) { 84; CHECK-LABEL:@cannot_fold_use_before_assume 85; CHECK: @f(i1 %notnull) 86; CHECK-NEXT: exit() 87; CHECK-NOT: assume 88; CHECK-NEXT: ret void 89 %notnull = icmp ne i32* %array, null 90 call void @f(i1 %notnull) 91 call void @exit() 92 call void @llvm.assume(i1 %notnull) 93 br i1 %notnull, label %normal, label %error 94 95normal: 96 ret void 97 98error: 99 store atomic i32 0, i32* @g unordered, align 4 100 ret void 101} 102 103declare void @dummy(i1) nounwind argmemonly 104define void @can_fold_some_use_before_assume(i32* %array) { 105 106; CHECK-LABEL:@can_fold_some_use_before_assume 107; CHECK: @f(i1 %notnull) 108; CHECK-NEXT: @dummy(i1 true) 109; CHECK-NOT: assume 110; CHECK-NEXT: ret void 111 %notnull = icmp ne i32* %array, null 112 call void @f(i1 %notnull) 113 call void @dummy(i1 %notnull) 114 call void @llvm.assume(i1 %notnull) 115 br i1 %notnull, label %normal, label %error 116 117normal: 118 ret void 119 120error: 121 store atomic i32 0, i32* @g unordered, align 4 122 ret void 123 124} 125 126; FIXME: can fold assume and all uses before/after assume. 127; because the trapping exit call is after the assume. 128define void @can_fold_assume_and_all_uses(i32* %array) { 129; CHECK-LABEL:@can_fold_assume_and_all_uses 130; CHECK: @dummy(i1 %notnull) 131; CHECK-NEXT: assume(i1 %notnull) 132; CHECK-NEXT: exit() 133; CHECK-NEXT: %notnull2 = or i1 true, false 134; CHECK-NEXT: @f(i1 %notnull2) 135; CHECK-NEXT: ret void 136 %notnull = icmp ne i32* %array, null 137 call void @dummy(i1 %notnull) 138 call void @llvm.assume(i1 %notnull) 139 call void @exit() 140 br i1 %notnull, label %normal, label %error 141 142normal: 143 %notnull2 = or i1 %notnull, false 144 call void @f(i1 %notnull2) 145 ret void 146 147error: 148 store atomic i32 0, i32* @g unordered, align 4 149 ret void 150} 151 152declare void @fz(i8) 153; FIXME: We can fold assume to true, and the use after assume, but we do not do so 154; currently, because of the function call after the assume. 155define void @can_fold_assume2(i32* %array) { 156 157; CHECK-LABEL:@can_fold_assume2 158; CHECK: @f(i1 %notnull) 159; CHECK-NEXT: assume(i1 %notnull) 160; CHECK-NEXT: znotnull = zext i1 %notnull to i8 161; CHECK-NEXT: @f(i1 %notnull) 162; CHECK-NEXT: @f(i1 true) 163; CHECK-NEXT: @fz(i8 %znotnull) 164; CHECK-NEXT: ret void 165 %notnull = icmp ne i32* %array, null 166 call void @f(i1 %notnull) 167 call void @llvm.assume(i1 %notnull) 168 %znotnull = zext i1 %notnull to i8 169 call void @f(i1 %notnull) 170 br i1 %notnull, label %normal, label %error 171 172normal: 173 call void @f(i1 %notnull) 174 call void @fz(i8 %znotnull) 175 ret void 176 177error: 178 store atomic i32 0, i32* @g unordered, align 4 179 ret void 180} 181 182declare void @llvm.experimental.guard(i1, ...) 183; FIXME: We can fold assume to true, but we do not do so 184; because of the guard following the assume. 185define void @can_fold_assume3(i32* %array){ 186 187; CHECK-LABEL:@can_fold_assume3 188; CHECK: @f(i1 %notnull) 189; CHECK-NEXT: assume(i1 %notnull) 190; CHECK-NEXT: guard(i1 %notnull) 191; CHECK-NEXT: znotnull = zext i1 true to i8 192; CHECK-NEXT: @f(i1 true) 193; CHECK-NEXT: @fz(i8 %znotnull) 194; CHECK-NEXT: ret void 195 %notnull = icmp ne i32* %array, null 196 call void @f(i1 %notnull) 197 call void @llvm.assume(i1 %notnull) 198 call void(i1, ...) @llvm.experimental.guard(i1 %notnull) [ "deopt"() ] 199 %znotnull = zext i1 %notnull to i8 200 br i1 %notnull, label %normal, label %error 201 202normal: 203 call void @f(i1 %notnull) 204 call void @fz(i8 %znotnull) 205 ret void 206 207error: 208 store atomic i32 0, i32* @g unordered, align 4 209 ret void 210} 211 212 213; can fold all uses and remove the cond 214define void @can_fold_assume4(i32* %array) { 215; CHECK-LABEL: can_fold_assume4 216; CHECK-NOT: notnull 217; CHECK: dummy(i1 true) 218; CHECK-NEXT: ret void 219 %notnull = icmp ne i32* %array, null 220 call void @exit() 221 call void @dummy(i1 %notnull) 222 call void @llvm.assume(i1 %notnull) 223 br i1 %notnull, label %normal, label %error 224 225normal: 226 ret void 227 228error: 229 store atomic i32 0, i32* @g unordered, align 4 230 ret void 231} 232; Function Attrs: nounwind 233declare void @llvm.assume(i1) #1 234 235declare void @bar(...) 236 237declare void @car(...) 238 239attributes #0 = { nounwind uwtable } 240attributes #1 = { nounwind } 241 242