1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt %s -instsimplify -S | FileCheck %s 3 4; Here we have add some offset to a non-null pointer, 5; and check that the result does not overflow and is not a null pointer. 6; But since the base pointer is already non-null, and we check for overflow, 7; that will already catch the get null pointer, 8; so the separate null check is redundant and can be dropped. 9 10define i1 @t0(i8* nonnull %base, i64 %offset) { 11; CHECK-LABEL: @t0( 12; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 13; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] 14; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp uge i64 [[ADJUSTED]], [[BASE_INT]] 15; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]] 16; 17 %base_int = ptrtoint i8* %base to i64 18 %adjusted = add i64 %base_int, %offset 19 %non_null_after_adjustment = icmp ne i64 %adjusted, 0 20 %no_overflow_during_adjustment = icmp uge i64 %adjusted, %base_int 21 %res = and i1 %non_null_after_adjustment, %no_overflow_during_adjustment 22 ret i1 %res 23} 24define i1 @t1(i8* nonnull %base, i64 %offset) { 25; CHECK-LABEL: @t1( 26; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 27; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] 28; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ule i64 [[BASE_INT]], [[ADJUSTED]] 29; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]] 30; 31 %base_int = ptrtoint i8* %base to i64 32 %adjusted = add i64 %base_int, %offset 33 %non_null_after_adjustment = icmp ne i64 %adjusted, 0 34 %no_overflow_during_adjustment = icmp ule i64 %base_int, %adjusted ; swapped 35 %res = and i1 %non_null_after_adjustment, %no_overflow_during_adjustment 36 ret i1 %res 37} 38define i1 @t2(i8* nonnull %base, i64 %offset) { 39; CHECK-LABEL: @t2( 40; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 41; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] 42; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp uge i64 [[ADJUSTED]], [[BASE_INT]] 43; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]] 44; 45 %base_int = ptrtoint i8* %base to i64 46 %adjusted = add i64 %base_int, %offset 47 %non_null_after_adjustment = icmp ne i64 %adjusted, 0 48 %no_overflow_during_adjustment = icmp uge i64 %adjusted, %base_int 49 %res = and i1 %no_overflow_during_adjustment, %non_null_after_adjustment ; swapped 50 ret i1 %res 51} 52define i1 @t3(i8* nonnull %base, i64 %offset) { 53; CHECK-LABEL: @t3( 54; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 55; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] 56; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ule i64 [[BASE_INT]], [[ADJUSTED]] 57; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]] 58; 59 %base_int = ptrtoint i8* %base to i64 60 %adjusted = add i64 %base_int, %offset 61 %non_null_after_adjustment = icmp ne i64 %adjusted, 0 62 %no_overflow_during_adjustment = icmp ule i64 %base_int, %adjusted ; swapped 63 %res = and i1 %no_overflow_during_adjustment, %non_null_after_adjustment ; swapped 64 ret i1 %res 65} 66 67; If the joining operator was 'or', i.e. we check that either we produced non-null 68; pointer, or no overflow happened, then the overflow check itself is redundant. 69 70define i1 @t4(i8* nonnull %base, i64 %offset) { 71; CHECK-LABEL: @t4( 72; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 73; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] 74; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp ne i64 [[ADJUSTED]], 0 75; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]] 76; 77 %base_int = ptrtoint i8* %base to i64 78 %adjusted = add i64 %base_int, %offset 79 %non_null_after_adjustment = icmp ne i64 %adjusted, 0 80 %no_overflow_during_adjustment = icmp uge i64 %adjusted, %base_int 81 %res = or i1 %non_null_after_adjustment, %no_overflow_during_adjustment 82 ret i1 %res 83} 84define i1 @t5(i8* nonnull %base, i64 %offset) { 85; CHECK-LABEL: @t5( 86; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 87; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] 88; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp ne i64 [[ADJUSTED]], 0 89; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]] 90; 91 %base_int = ptrtoint i8* %base to i64 92 %adjusted = add i64 %base_int, %offset 93 %non_null_after_adjustment = icmp ne i64 %adjusted, 0 94 %no_overflow_during_adjustment = icmp ule i64 %base_int, %adjusted ; swapped 95 %res = or i1 %non_null_after_adjustment, %no_overflow_during_adjustment 96 ret i1 %res 97} 98define i1 @t6(i8* nonnull %base, i64 %offset) { 99; CHECK-LABEL: @t6( 100; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 101; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] 102; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp ne i64 [[ADJUSTED]], 0 103; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]] 104; 105 %base_int = ptrtoint i8* %base to i64 106 %adjusted = add i64 %base_int, %offset 107 %non_null_after_adjustment = icmp ne i64 %adjusted, 0 108 %no_overflow_during_adjustment = icmp uge i64 %adjusted, %base_int 109 %res = or i1 %no_overflow_during_adjustment, %non_null_after_adjustment ; swapped 110 ret i1 %res 111} 112define i1 @t7(i8* nonnull %base, i64 %offset) { 113; CHECK-LABEL: @t7( 114; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 115; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] 116; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp ne i64 [[ADJUSTED]], 0 117; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]] 118; 119 %base_int = ptrtoint i8* %base to i64 120 %adjusted = add i64 %base_int, %offset 121 %non_null_after_adjustment = icmp ne i64 %adjusted, 0 122 %no_overflow_during_adjustment = icmp ule i64 %base_int, %adjusted ; swapped 123 %res = or i1 %no_overflow_during_adjustment, %non_null_after_adjustment ; swapped 124 ret i1 %res 125} 126 127; Or, we could be checking the reverse condition, that we either get null pointer, 128; or overflow happens, then again, the standalone null check is redundant and 129; can be dropped. 130 131define i1 @t8(i8* nonnull %base, i64 %offset) { 132; CHECK-LABEL: @t8( 133; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 134; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] 135; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ult i64 [[ADJUSTED]], [[BASE_INT]] 136; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]] 137; 138 %base_int = ptrtoint i8* %base to i64 139 %adjusted = add i64 %base_int, %offset 140 %non_null_after_adjustment = icmp eq i64 %adjusted, 0 141 %no_overflow_during_adjustment = icmp ult i64 %adjusted, %base_int 142 %res = or i1 %non_null_after_adjustment, %no_overflow_during_adjustment 143 ret i1 %res 144} 145define i1 @t9(i8* nonnull %base, i64 %offset) { 146; CHECK-LABEL: @t9( 147; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 148; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] 149; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ugt i64 [[BASE_INT]], [[ADJUSTED]] 150; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]] 151; 152 %base_int = ptrtoint i8* %base to i64 153 %adjusted = add i64 %base_int, %offset 154 %non_null_after_adjustment = icmp eq i64 %adjusted, 0 155 %no_overflow_during_adjustment = icmp ugt i64 %base_int, %adjusted ; swapped 156 %res = or i1 %non_null_after_adjustment, %no_overflow_during_adjustment 157 ret i1 %res 158} 159define i1 @t10(i8* nonnull %base, i64 %offset) { 160; CHECK-LABEL: @t10( 161; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 162; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] 163; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ult i64 [[ADJUSTED]], [[BASE_INT]] 164; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]] 165; 166 %base_int = ptrtoint i8* %base to i64 167 %adjusted = add i64 %base_int, %offset 168 %non_null_after_adjustment = icmp eq i64 %adjusted, 0 169 %no_overflow_during_adjustment = icmp ult i64 %adjusted, %base_int 170 %res = or i1 %no_overflow_during_adjustment, %non_null_after_adjustment ; swapped 171 ret i1 %res 172} 173define i1 @t11(i8* nonnull %base, i64 %offset) { 174; CHECK-LABEL: @t11( 175; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 176; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] 177; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ugt i64 [[BASE_INT]], [[ADJUSTED]] 178; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]] 179; 180 %base_int = ptrtoint i8* %base to i64 181 %adjusted = add i64 %base_int, %offset 182 %non_null_after_adjustment = icmp eq i64 %adjusted, 0 183 %no_overflow_during_adjustment = icmp ugt i64 %base_int, %adjusted ; swapped 184 %res = or i1 %no_overflow_during_adjustment, %non_null_after_adjustment ; swapped 185 ret i1 %res 186} 187 188; If the joining operator was 'and', i.e. we check that we both get null pointer 189; AND overflow happens, then the overflow check is redundant. 190 191define i1 @t12(i8* nonnull %base, i64 %offset) { 192; CHECK-LABEL: @t12( 193; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 194; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] 195; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp eq i64 [[ADJUSTED]], 0 196; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]] 197; 198 %base_int = ptrtoint i8* %base to i64 199 %adjusted = add i64 %base_int, %offset 200 %non_null_after_adjustment = icmp eq i64 %adjusted, 0 201 %no_overflow_during_adjustment = icmp ult i64 %adjusted, %base_int 202 %res = and i1 %non_null_after_adjustment, %no_overflow_during_adjustment 203 ret i1 %res 204} 205define i1 @t13(i8* nonnull %base, i64 %offset) { 206; CHECK-LABEL: @t13( 207; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 208; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] 209; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp eq i64 [[ADJUSTED]], 0 210; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]] 211; 212 %base_int = ptrtoint i8* %base to i64 213 %adjusted = add i64 %base_int, %offset 214 %non_null_after_adjustment = icmp eq i64 %adjusted, 0 215 %no_overflow_during_adjustment = icmp ugt i64 %base_int, %adjusted ; swapped 216 %res = and i1 %non_null_after_adjustment, %no_overflow_during_adjustment 217 ret i1 %res 218} 219define i1 @t14(i8* nonnull %base, i64 %offset) { 220; CHECK-LABEL: @t14( 221; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 222; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] 223; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp eq i64 [[ADJUSTED]], 0 224; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]] 225; 226 %base_int = ptrtoint i8* %base to i64 227 %adjusted = add i64 %base_int, %offset 228 %non_null_after_adjustment = icmp eq i64 %adjusted, 0 229 %no_overflow_during_adjustment = icmp ult i64 %adjusted, %base_int 230 %res = and i1 %no_overflow_during_adjustment, %non_null_after_adjustment ; swapped 231 ret i1 %res 232} 233define i1 @t15(i8* nonnull %base, i64 %offset) { 234; CHECK-LABEL: @t15( 235; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 236; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] 237; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp eq i64 [[ADJUSTED]], 0 238; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]] 239; 240 %base_int = ptrtoint i8* %base to i64 241 %adjusted = add i64 %base_int, %offset 242 %non_null_after_adjustment = icmp eq i64 %adjusted, 0 243 %no_overflow_during_adjustment = icmp ugt i64 %base_int, %adjusted ; swapped 244 %res = and i1 %no_overflow_during_adjustment, %non_null_after_adjustment ; swapped 245 ret i1 %res 246} 247 248declare void @llvm.assume(i1) 249define i1 @t16(i64 %base, i64 %offset) { 250; CHECK-LABEL: @t16( 251; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[BASE:%.*]], 0 252; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) 253; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE]], [[OFFSET:%.*]] 254; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp uge i64 [[ADJUSTED]], [[BASE]] 255; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]] 256; 257 %cmp = icmp slt i64 %base, 0 258 call void @llvm.assume(i1 %cmp) 259 260 %adjusted = add i64 %base, %offset 261 %non_null_after_adjustment = icmp ne i64 %adjusted, 0 262 %no_overflow_during_adjustment = icmp uge i64 %adjusted, %base 263 %res = and i1 %non_null_after_adjustment, %no_overflow_during_adjustment 264 ret i1 %res 265} 266