1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s 3 4; Tests for using inbounds information from GEPs where the GEP only causes UB in the use blocks. 5 6declare void @noundef(ptr noundef) willreturn nounwind 7declare void @noundef2(ptr noundef) 8 9declare void @use(i1) 10 11; %start + %n.ext is guaranteed to not overflow (due to inbounds). 12; %start + %idx.ext does not overflow if %idx.ext <= %n.ext. 13define i1 @inbounds_poison_is_ub_in_use_block_1(ptr %src, i32 %n, i32 %idx) { 14; CHECK-LABEL: @inbounds_poison_is_ub_in_use_block_1( 15; CHECK-NEXT: entry: 16; CHECK-NEXT: [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64 17; CHECK-NEXT: [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[SRC:%.*]], i64 [[N_EXT]] 18; CHECK-NEXT: [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]] 19; CHECK-NEXT: [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64 20; CHECK-NEXT: [[SRC_IDX:%.*]] = getelementptr i32, ptr [[SRC]], i64 [[IDX_EXT]] 21; CHECK-NEXT: br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]] 22; CHECK: then: 23; CHECK-NEXT: call void @noundef(ptr [[UPPER]]) 24; CHECK-NEXT: [[CMP_UPPER_1:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]] 25; CHECK-NEXT: ret i1 [[CMP_UPPER_1]] 26; CHECK: else: 27; CHECK-NEXT: [[CMP_UPPER_2:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]] 28; CHECK-NEXT: ret i1 [[CMP_UPPER_2]] 29; 30entry: 31 %n.ext = zext i32 %n to i64 32 %upper = getelementptr inbounds i32, ptr %src, i64 %n.ext 33 %cmp.idx = icmp ult i32 %idx, %n 34 %idx.ext = zext i32 %idx to i64 35 %src.idx = getelementptr i32, ptr %src, i64 %idx.ext 36 br i1 %cmp.idx, label %then, label %else 37 38then: 39 call void @noundef(ptr %upper) 40 %cmp.upper.1 = icmp ule ptr %src.idx, %upper 41 ret i1 %cmp.upper.1 42 43else: 44 %cmp.upper.2 = icmp ule ptr %src.idx, %upper 45 ret i1 %cmp.upper.2 46} 47 48define i1 @inbounds_poison_is_ub_in_use_block_2(ptr %src, i32 %n, i32 %idx, i1 %c) { 49; CHECK-LABEL: @inbounds_poison_is_ub_in_use_block_2( 50; CHECK-NEXT: entry: 51; CHECK-NEXT: [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64 52; CHECK-NEXT: [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[SRC:%.*]], i64 [[N_EXT]] 53; CHECK-NEXT: [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]] 54; CHECK-NEXT: [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64 55; CHECK-NEXT: [[SRC_IDX:%.*]] = getelementptr i32, ptr [[SRC]], i64 [[IDX_EXT]] 56; CHECK-NEXT: br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]] 57; CHECK: then: 58; CHECK-NEXT: [[CMP_UPPER_1:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]] 59; CHECK-NEXT: call void @noundef(ptr [[UPPER]]) 60; CHECK-NEXT: ret i1 [[CMP_UPPER_1]] 61; CHECK: else: 62; CHECK-NEXT: [[CMP_UPPER_2:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]] 63; CHECK-NEXT: ret i1 [[CMP_UPPER_2]] 64; 65entry: 66 %n.ext = zext i32 %n to i64 67 %upper = getelementptr inbounds i32, ptr %src, i64 %n.ext 68 %cmp.idx = icmp ult i32 %idx, %n 69 %idx.ext = zext i32 %idx to i64 70 %src.idx = getelementptr i32, ptr %src, i64 %idx.ext 71 br i1 %cmp.idx, label %then, label %else 72 73then: 74 %cmp.upper.1 = icmp ule ptr %src.idx, %upper 75 call void @noundef(ptr %upper) 76 ret i1 %cmp.upper.1 77 78else: 79 %cmp.upper.2 = icmp ule ptr %src.idx, %upper 80 ret i1 %cmp.upper.2 81} 82 83declare void @llvm.assume(i1) 84 85; %start + %n.ext is guaranteed to not overflow (due to inbounds). 86; %start + %idx.ext does not overflow if %idx.ext <= %n.ext. 87define i1 @inbounds_poison_is_ub_in_use_block_by_assume(ptr %src, i32 %n, i32 %idx) { 88; CHECK-LABEL: @inbounds_poison_is_ub_in_use_block_by_assume( 89; CHECK-NEXT: entry: 90; CHECK-NEXT: [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64 91; CHECK-NEXT: [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[SRC:%.*]], i64 [[N_EXT]] 92; CHECK-NEXT: [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]] 93; CHECK-NEXT: [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64 94; CHECK-NEXT: [[SRC_IDX:%.*]] = getelementptr i32, ptr [[SRC]], i64 [[IDX_EXT]] 95; CHECK-NEXT: br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]] 96; CHECK: then: 97; CHECK-NEXT: [[CMP_NE:%.*]] = icmp ule ptr null, [[UPPER]] 98; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_NE]]) 99; CHECK-NEXT: [[CMP_UPPER_1:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]] 100; CHECK-NEXT: ret i1 [[CMP_UPPER_1]] 101; CHECK: else: 102; CHECK-NEXT: [[CMP_UPPER_2:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]] 103; CHECK-NEXT: ret i1 [[CMP_UPPER_2]] 104; 105entry: 106 %n.ext = zext i32 %n to i64 107 %upper = getelementptr inbounds i32, ptr %src, i64 %n.ext 108 %cmp.idx = icmp ult i32 %idx, %n 109 %idx.ext = zext i32 %idx to i64 110 %src.idx = getelementptr i32, ptr %src, i64 %idx.ext 111 br i1 %cmp.idx, label %then, label %else 112 113then: 114 %cmp.ne = icmp ule ptr null, %upper 115 call void @llvm.assume(i1 %cmp.ne) 116 %cmp.upper.1 = icmp ule ptr %src.idx, %upper 117 ret i1 %cmp.upper.1 118 119else: 120 %cmp.upper.2 = icmp ule ptr %src.idx, %upper 121 ret i1 %cmp.upper.2 122} 123 124 125; %start + %n.ext is guaranteed to not overflow (due to inbounds). 126; %start + %idx.ext does not overflow if %idx.ext <= %n.ext. 127define i1 @inbounds_poison_is_ub_in_in_multiple_use_blocks_1(ptr %src, i32 %n, i32 %idx, i1 %c) { 128; CHECK-LABEL: @inbounds_poison_is_ub_in_in_multiple_use_blocks_1( 129; CHECK-NEXT: entry: 130; CHECK-NEXT: [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64 131; CHECK-NEXT: [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[SRC:%.*]], i64 [[N_EXT]] 132; CHECK-NEXT: br i1 [[C:%.*]], label [[CHECK_BB:%.*]], label [[EXIT:%.*]] 133; CHECK: check.bb: 134; CHECK-NEXT: call void @noundef(ptr [[UPPER]]) 135; CHECK-NEXT: [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]] 136; CHECK-NEXT: [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64 137; CHECK-NEXT: [[SRC_IDX:%.*]] = getelementptr i32, ptr [[SRC]], i64 [[IDX_EXT]] 138; CHECK-NEXT: br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]] 139; CHECK: then: 140; CHECK-NEXT: call void @noundef(ptr [[UPPER]]) 141; CHECK-NEXT: [[CMP_UPPER_1:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]] 142; CHECK-NEXT: ret i1 [[CMP_UPPER_1]] 143; CHECK: else: 144; CHECK-NEXT: [[CMP_UPPER_2:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]] 145; CHECK-NEXT: ret i1 [[CMP_UPPER_2]] 146; CHECK: exit: 147; CHECK-NEXT: ret i1 false 148; 149entry: 150 %n.ext = zext i32 %n to i64 151 %upper = getelementptr inbounds i32, ptr %src, i64 %n.ext 152 br i1 %c, label %check.bb, label %exit 153 154check.bb: 155 call void @noundef(ptr %upper) 156 %cmp.idx = icmp ult i32 %idx, %n 157 %idx.ext = zext i32 %idx to i64 158 %src.idx = getelementptr i32, ptr %src, i64 %idx.ext 159 br i1 %cmp.idx, label %then, label %else 160 161then: 162 call void @noundef(ptr %upper) 163 %cmp.upper.1 = icmp ule ptr %src.idx, %upper 164 ret i1 %cmp.upper.1 165 166else: 167 %cmp.upper.2 = icmp ule ptr %src.idx, %upper 168 ret i1 %cmp.upper.2 169 170exit: 171 ret i1 false 172} 173 174define i1 @may_exit_before_ub_is_caused(ptr %src, i32 %n, i32 %idx) { 175; CHECK-LABEL: @may_exit_before_ub_is_caused( 176; CHECK-NEXT: entry: 177; CHECK-NEXT: [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64 178; CHECK-NEXT: [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[SRC:%.*]], i64 [[N_EXT]] 179; CHECK-NEXT: [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]] 180; CHECK-NEXT: [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64 181; CHECK-NEXT: [[SRC_IDX:%.*]] = getelementptr i32, ptr [[SRC]], i64 [[IDX_EXT]] 182; CHECK-NEXT: br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]] 183; CHECK: then: 184; CHECK-NEXT: [[CMP_UPPER_1:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]] 185; CHECK-NEXT: call void @use(i1 [[CMP_UPPER_1]]) 186; CHECK-NEXT: call void @noundef(ptr [[UPPER]]) 187; CHECK-NEXT: ret i1 [[CMP_UPPER_1]] 188; CHECK: else: 189; CHECK-NEXT: [[CMP_UPPER_2:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]] 190; CHECK-NEXT: ret i1 [[CMP_UPPER_2]] 191; 192entry: 193 %n.ext = zext i32 %n to i64 194 %upper = getelementptr inbounds i32, ptr %src, i64 %n.ext 195 %cmp.idx = icmp ult i32 %idx, %n 196 %idx.ext = zext i32 %idx to i64 197 %src.idx = getelementptr i32, ptr %src, i64 %idx.ext 198 br i1 %cmp.idx, label %then, label %else 199 200then: 201 %cmp.upper.1 = icmp ule ptr %src.idx, %upper 202 call void @use(i1 %cmp.upper.1); 203 call void @noundef(ptr %upper) 204 ret i1 %cmp.upper.1 205 206else: 207 %cmp.upper.2 = icmp ule ptr %src.idx, %upper 208 ret i1 %cmp.upper.2 209} 210 211define i1 @only_UB_in_false_block(ptr %src, i32 %n, i32 %idx) { 212; CHECK-LABEL: @only_UB_in_false_block( 213; CHECK-NEXT: entry: 214; CHECK-NEXT: [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64 215; CHECK-NEXT: [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[SRC:%.*]], i64 [[N_EXT]] 216; CHECK-NEXT: [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]] 217; CHECK-NEXT: [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64 218; CHECK-NEXT: [[SRC_IDX:%.*]] = getelementptr i32, ptr [[SRC]], i64 [[IDX_EXT]] 219; CHECK-NEXT: br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]] 220; CHECK: then: 221; CHECK-NEXT: [[CMP_UPPER_1:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]] 222; CHECK-NEXT: ret i1 [[CMP_UPPER_1]] 223; CHECK: else: 224; CHECK-NEXT: call void @noundef(ptr [[UPPER]]) 225; CHECK-NEXT: [[CMP_UPPER_2:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]] 226; CHECK-NEXT: ret i1 [[CMP_UPPER_2]] 227; 228entry: 229 %n.ext = zext i32 %n to i64 230 %upper = getelementptr inbounds i32, ptr %src, i64 %n.ext 231 %cmp.idx = icmp ult i32 %idx, %n 232 %idx.ext = zext i32 %idx to i64 233 %src.idx = getelementptr i32, ptr %src, i64 %idx.ext 234 br i1 %cmp.idx, label %then, label %else 235 236then: 237 %cmp.upper.1 = icmp ule ptr %src.idx, %upper 238 ret i1 %cmp.upper.1 239 240else: 241 call void @noundef(ptr %upper) 242 %cmp.upper.2 = icmp ule ptr %src.idx, %upper 243 ret i1 %cmp.upper.2 244} 245 246define i1 @only_ub_by_assume_in_false_block(ptr %src, i32 %n, i32 %idx) { 247; CHECK-LABEL: @only_ub_by_assume_in_false_block( 248; CHECK-NEXT: entry: 249; CHECK-NEXT: [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64 250; CHECK-NEXT: [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[SRC:%.*]], i64 [[N_EXT]] 251; CHECK-NEXT: [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]] 252; CHECK-NEXT: [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64 253; CHECK-NEXT: [[SRC_IDX:%.*]] = getelementptr i32, ptr [[SRC]], i64 [[IDX_EXT]] 254; CHECK-NEXT: br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]] 255; CHECK: then: 256; CHECK-NEXT: [[CMP_UPPER_1:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]] 257; CHECK-NEXT: ret i1 [[CMP_UPPER_1]] 258; CHECK: else: 259; CHECK-NEXT: [[CMP_NE:%.*]] = icmp ule ptr null, [[UPPER]] 260; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_NE]]) 261; CHECK-NEXT: [[CMP_UPPER_2:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]] 262; CHECK-NEXT: ret i1 [[CMP_UPPER_2]] 263; 264entry: 265 %n.ext = zext i32 %n to i64 266 %upper = getelementptr inbounds i32, ptr %src, i64 %n.ext 267 %cmp.idx = icmp ult i32 %idx, %n 268 %idx.ext = zext i32 %idx to i64 269 %src.idx = getelementptr i32, ptr %src, i64 %idx.ext 270 br i1 %cmp.idx, label %then, label %else 271 272then: 273 %cmp.upper.1 = icmp ule ptr %src.idx, %upper 274 ret i1 %cmp.upper.1 275 276else: 277 %cmp.ne = icmp ule ptr null, %upper 278 call void @llvm.assume(i1 %cmp.ne) 279 %cmp.upper.2 = icmp ule ptr %src.idx, %upper 280 ret i1 %cmp.upper.2 281} 282