1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -passes=sccp < %s | FileCheck %s 3 4declare { i8, i1 } @llvm.uadd.with.overflow.i8(i8, i8) 5declare { i8, i1 } @llvm.usub.with.overflow.i8(i8, i8) 6declare { i8, i1 } @llvm.umul.with.overflow.i8(i8, i8) 7declare { i8, i1 } @llvm.sadd.with.overflow.i8(i8, i8) 8declare { i8, i1 } @llvm.ssub.with.overflow.i8(i8, i8) 9declare { i8, i1 } @llvm.smul.with.overflow.i8(i8, i8) 10declare { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow.v2i8(<2 x i8>, <2 x i8>) 11declare void @use.i1(i1) 12 13define void @unsigned_overflow(ptr %p) { 14; CHECK-LABEL: @unsigned_overflow( 15; CHECK-NEXT: [[V0_100:%.*]] = load i8, ptr [[P:%.*]], align 1, !range [[RNG0:![0-9]+]] 16; CHECK-NEXT: [[V0_155:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG1:![0-9]+]] 17; CHECK-NEXT: [[V0_156:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG2:![0-9]+]] 18; CHECK-NEXT: [[V100_255:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG3:![0-9]+]] 19; CHECK-NEXT: [[V99_255:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG4:![0-9]+]] 20; CHECK-NEXT: [[V1_2:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG5:![0-9]+]] 21; CHECK-NEXT: [[V1_3:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG6:![0-9]+]] 22; CHECK-NEXT: [[WO1:%.*]] = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 [[V0_100]], i8 [[V0_155]]) 23; CHECK-NEXT: call void @use.i1(i1 false) 24; CHECK-NEXT: [[WO2:%.*]] = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 [[V0_100]], i8 [[V0_156]]) 25; CHECK-NEXT: [[OV2:%.*]] = extractvalue { i8, i1 } [[WO2]], 1 26; CHECK-NEXT: call void @use.i1(i1 [[OV2]]) 27; CHECK-NEXT: [[WO3:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[V100_255]], i8 [[V0_100]]) 28; CHECK-NEXT: call void @use.i1(i1 false) 29; CHECK-NEXT: [[WO4:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[V99_255]], i8 [[V0_100]]) 30; CHECK-NEXT: [[OV4:%.*]] = extractvalue { i8, i1 } [[WO4]], 1 31; CHECK-NEXT: call void @use.i1(i1 [[OV4]]) 32; CHECK-NEXT: [[WO5:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[V0_100]], i8 [[V1_2]]) 33; CHECK-NEXT: call void @use.i1(i1 false) 34; CHECK-NEXT: [[WO6:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[V0_100]], i8 [[V1_3]]) 35; CHECK-NEXT: [[OV6:%.*]] = extractvalue { i8, i1 } [[WO6]], 1 36; CHECK-NEXT: call void @use.i1(i1 [[OV6]]) 37; CHECK-NEXT: ret void 38; 39 %v0_100 = load i8, ptr %p, !range !{i8 0, i8 101} 40 %v0_155 = load i8, ptr %p, !range !{i8 0, i8 156} 41 %v0_156 = load i8, ptr %p, !range !{i8 0, i8 157} 42 %v100_255 = load i8, ptr %p, !range !{i8 100, i8 0} 43 %v99_255 = load i8, ptr %p, !range !{i8 99, i8 0} 44 %v1_2 = load i8, ptr %p, !range !{i8 1, i8 3} 45 %v1_3 = load i8, ptr %p, !range !{i8 1, i8 4} 46 47 %wo1 = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %v0_100, i8 %v0_155) 48 %ov1 = extractvalue { i8, i1 } %wo1, 1 49 call void @use.i1(i1 %ov1) 50 51 %wo2 = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %v0_100, i8 %v0_156) 52 %ov2 = extractvalue { i8, i1 } %wo2, 1 53 call void @use.i1(i1 %ov2) 54 55 %wo3 = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %v100_255, i8 %v0_100) 56 %ov3 = extractvalue { i8, i1 } %wo3, 1 57 call void @use.i1(i1 %ov3) 58 59 %wo4 = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %v99_255, i8 %v0_100) 60 %ov4 = extractvalue { i8, i1 } %wo4, 1 61 call void @use.i1(i1 %ov4) 62 63 %wo5 = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 %v0_100, i8 %v1_2) 64 %ov5 = extractvalue { i8, i1 } %wo5, 1 65 call void @use.i1(i1 %ov5) 66 67 %wo6 = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 %v0_100, i8 %v1_3) 68 %ov6 = extractvalue { i8, i1 } %wo6, 1 69 call void @use.i1(i1 %ov6) 70 ret void 71} 72 73define void @signed_overflow(ptr %p) { 74; CHECK-LABEL: @signed_overflow( 75; CHECK-NEXT: [[V0_100:%.*]] = load i8, ptr [[P:%.*]], align 1, !range [[RNG0]] 76; CHECK-NEXT: [[V0_27:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG7:![0-9]+]] 77; CHECK-NEXT: [[V0_28:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG8:![0-9]+]] 78; CHECK-NEXT: [[VM27_0:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG9:![0-9]+]] 79; CHECK-NEXT: [[VM28_0:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG10:![0-9]+]] 80; CHECK-NEXT: [[V1_4:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG11:![0-9]+]] 81; CHECK-NEXT: [[V1_5:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG12:![0-9]+]] 82; CHECK-NEXT: [[WO1:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[V0_100]], i8 [[V0_27]]) 83; CHECK-NEXT: call void @use.i1(i1 false) 84; CHECK-NEXT: [[WO2:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[V0_100]], i8 [[V0_28]]) 85; CHECK-NEXT: [[OV2:%.*]] = extractvalue { i8, i1 } [[WO2]], 1 86; CHECK-NEXT: call void @use.i1(i1 [[OV2]]) 87; CHECK-NEXT: [[WO3:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[V0_100]], i8 [[VM27_0]]) 88; CHECK-NEXT: call void @use.i1(i1 false) 89; CHECK-NEXT: [[WO4:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[V0_100]], i8 [[VM28_0]]) 90; CHECK-NEXT: [[OV4:%.*]] = extractvalue { i8, i1 } [[WO4]], 1 91; CHECK-NEXT: call void @use.i1(i1 [[OV4]]) 92; CHECK-NEXT: [[WO5:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[V0_27]], i8 [[V1_4]]) 93; CHECK-NEXT: call void @use.i1(i1 false) 94; CHECK-NEXT: [[WO6:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[V0_27]], i8 [[V1_5]]) 95; CHECK-NEXT: [[OV6:%.*]] = extractvalue { i8, i1 } [[WO6]], 1 96; CHECK-NEXT: call void @use.i1(i1 [[OV6]]) 97; CHECK-NEXT: ret void 98; 99 %v0_100 = load i8, ptr %p, !range !{i8 0, i8 101} 100 %v0_27 = load i8, ptr %p, !range !{i8 0, i8 28} 101 %v0_28 = load i8, ptr %p, !range !{i8 0, i8 29} 102 %vm27_0 = load i8, ptr %p, !range !{i8 -27, i8 0} 103 %vm28_0 = load i8, ptr %p, !range !{i8 -28, i8 0} 104 %v1_4 = load i8, ptr %p, !range !{i8 1, i8 5} 105 %v1_5 = load i8, ptr %p, !range !{i8 1, i8 6} 106 107 %wo1 = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %v0_100, i8 %v0_27) 108 %ov1 = extractvalue { i8, i1 } %wo1, 1 109 call void @use.i1(i1 %ov1) 110 111 %wo2 = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %v0_100, i8 %v0_28) 112 %ov2 = extractvalue { i8, i1 } %wo2, 1 113 call void @use.i1(i1 %ov2) 114 115 %wo3 = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %v0_100, i8 %vm27_0) 116 %ov3 = extractvalue { i8, i1 } %wo3, 1 117 call void @use.i1(i1 %ov3) 118 119 %wo4 = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %v0_100, i8 %vm28_0) 120 %ov4 = extractvalue { i8, i1 } %wo4, 1 121 call void @use.i1(i1 %ov4) 122 123 %wo5 = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 %v0_27, i8 %v1_4) 124 %ov5 = extractvalue { i8, i1 } %wo5, 1 125 call void @use.i1(i1 %ov5) 126 127 %wo6 = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 %v0_27, i8 %v1_5) 128 %ov6 = extractvalue { i8, i1 } %wo6, 1 129 call void @use.i1(i1 %ov6) 130 ret void 131} 132 133define void @unsigned_result(ptr %p) { 134; CHECK-LABEL: @unsigned_result( 135; CHECK-NEXT: [[V0_20:%.*]] = load i8, ptr [[P:%.*]], align 1, !range [[RNG13:![0-9]+]] 136; CHECK-NEXT: [[V20_40:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG14:![0-9]+]] 137; CHECK-NEXT: [[V0_10:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG15:![0-9]+]] 138; CHECK-NEXT: [[V2_3:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG16:![0-9]+]] 139; CHECK-NEXT: [[WO1:%.*]] = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 [[V0_20]], i8 [[V20_40]]) 140; CHECK-NEXT: [[RES1:%.*]] = extractvalue { i8, i1 } [[WO1]], 0 141; CHECK-NEXT: call void @use.i1(i1 true) 142; CHECK-NEXT: call void @use.i1(i1 true) 143; CHECK-NEXT: [[CMP1_3:%.*]] = icmp ugt i8 [[RES1]], 20 144; CHECK-NEXT: call void @use.i1(i1 [[CMP1_3]]) 145; CHECK-NEXT: [[CMP1_4:%.*]] = icmp ult i8 [[RES1]], 60 146; CHECK-NEXT: call void @use.i1(i1 [[CMP1_4]]) 147; CHECK-NEXT: [[WO2:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[V0_10]], i8 [[V20_40]]) 148; CHECK-NEXT: [[RES2:%.*]] = extractvalue { i8, i1 } [[WO2]], 0 149; CHECK-NEXT: call void @use.i1(i1 true) 150; CHECK-NEXT: call void @use.i1(i1 true) 151; CHECK-NEXT: [[CMP2_3:%.*]] = icmp ugt i8 [[RES2]], -40 152; CHECK-NEXT: call void @use.i1(i1 [[CMP2_3]]) 153; CHECK-NEXT: [[CMP2_4:%.*]] = icmp ult i8 [[RES2]], -10 154; CHECK-NEXT: call void @use.i1(i1 [[CMP2_4]]) 155; CHECK-NEXT: [[WO3:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[V20_40]], i8 [[V2_3]]) 156; CHECK-NEXT: [[RES3:%.*]] = extractvalue { i8, i1 } [[WO3]], 0 157; CHECK-NEXT: call void @use.i1(i1 true) 158; CHECK-NEXT: call void @use.i1(i1 true) 159; CHECK-NEXT: [[CMP3_3:%.*]] = icmp ugt i8 [[RES3]], 40 160; CHECK-NEXT: call void @use.i1(i1 [[CMP3_3]]) 161; CHECK-NEXT: [[CMP3_4:%.*]] = icmp ult i8 [[RES3]], 120 162; CHECK-NEXT: call void @use.i1(i1 [[CMP3_4]]) 163; CHECK-NEXT: ret void 164; 165 %v0_20 = load i8, ptr %p, !range !{i8 0, i8 21} 166 %v20_40 = load i8, ptr %p, !range !{i8 20, i8 41} 167 %v0_10 = load i8, ptr %p, !range !{i8 0, i8 11} 168 %v2_3 = load i8, ptr %p, !range !{i8 2, i8 4} 169 %wo1 = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %v0_20, i8 %v20_40) 170 %res1 = extractvalue { i8, i1 } %wo1, 0 171 %cmp1.1 = icmp uge i8 %res1, 20 172 call void @use.i1(i1 %cmp1.1) 173 %cmp1.2 = icmp ule i8 %res1, 60 174 call void @use.i1(i1 %cmp1.2) 175 %cmp1.3 = icmp ugt i8 %res1, 20 176 call void @use.i1(i1 %cmp1.3) 177 %cmp1.4 = icmp ult i8 %res1, 60 178 call void @use.i1(i1 %cmp1.4) 179 180 ; This case actually does overflow, but we can still determine the range. 181 %wo2 = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %v0_10, i8 %v20_40) 182 %res2 = extractvalue { i8, i1 } %wo2, 0 183 %cmp2.1 = icmp uge i8 %res2, -40 184 call void @use.i1(i1 %cmp2.1) 185 %cmp2.2 = icmp ule i8 %res2, -10 186 call void @use.i1(i1 %cmp2.2) 187 %cmp2.3 = icmp ugt i8 %res2, -40 188 call void @use.i1(i1 %cmp2.3) 189 %cmp2.4 = icmp ult i8 %res2, -10 190 call void @use.i1(i1 %cmp2.4) 191 192 %wo3 = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 %v20_40, i8 %v2_3) 193 %res3 = extractvalue { i8, i1 } %wo3, 0 194 %cmp3.1 = icmp uge i8 %res3, 40 195 call void @use.i1(i1 %cmp3.1) 196 %cmp3.2 = icmp ule i8 %res3, 120 197 call void @use.i1(i1 %cmp3.2) 198 %cmp3.3 = icmp ugt i8 %res3, 40 199 call void @use.i1(i1 %cmp3.3) 200 %cmp3.4 = icmp ult i8 %res3, 120 201 call void @use.i1(i1 %cmp3.4) 202 ret void 203} 204 205define void @signed_result(ptr %p) { 206; CHECK-LABEL: @signed_result( 207; CHECK-NEXT: [[V0_20:%.*]] = load i8, ptr [[P:%.*]], align 1, !range [[RNG13]] 208; CHECK-NEXT: [[V20_40:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG14]] 209; CHECK-NEXT: [[V0_10:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG15]] 210; CHECK-NEXT: [[V2_3:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG16]] 211; CHECK-NEXT: [[WO1:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[V0_20]], i8 [[V20_40]]) 212; CHECK-NEXT: [[RES1:%.*]] = extractvalue { i8, i1 } [[WO1]], 0 213; CHECK-NEXT: call void @use.i1(i1 true) 214; CHECK-NEXT: call void @use.i1(i1 true) 215; CHECK-NEXT: [[CMP1_3:%.*]] = icmp ugt i8 [[RES1]], 20 216; CHECK-NEXT: call void @use.i1(i1 [[CMP1_3]]) 217; CHECK-NEXT: [[CMP1_4:%.*]] = icmp ult i8 [[RES1]], 60 218; CHECK-NEXT: call void @use.i1(i1 [[CMP1_4]]) 219; CHECK-NEXT: [[WO2:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[V0_10]], i8 [[V20_40]]) 220; CHECK-NEXT: [[RES2:%.*]] = extractvalue { i8, i1 } [[WO2]], 0 221; CHECK-NEXT: call void @use.i1(i1 true) 222; CHECK-NEXT: call void @use.i1(i1 true) 223; CHECK-NEXT: [[CMP2_3:%.*]] = icmp ugt i8 [[RES2]], -40 224; CHECK-NEXT: call void @use.i1(i1 [[CMP2_3]]) 225; CHECK-NEXT: [[CMP2_4:%.*]] = icmp ult i8 [[RES2]], -10 226; CHECK-NEXT: call void @use.i1(i1 [[CMP2_4]]) 227; CHECK-NEXT: [[WO3:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[V20_40]], i8 [[V2_3]]) 228; CHECK-NEXT: [[RES3:%.*]] = extractvalue { i8, i1 } [[WO3]], 0 229; CHECK-NEXT: call void @use.i1(i1 true) 230; CHECK-NEXT: call void @use.i1(i1 true) 231; CHECK-NEXT: [[CMP3_3:%.*]] = icmp ugt i8 [[RES3]], 40 232; CHECK-NEXT: call void @use.i1(i1 [[CMP3_3]]) 233; CHECK-NEXT: [[CMP3_4:%.*]] = icmp ult i8 [[RES3]], 120 234; CHECK-NEXT: call void @use.i1(i1 [[CMP3_4]]) 235; CHECK-NEXT: ret void 236; 237 %v0_20 = load i8, ptr %p, !range !{i8 0, i8 21} 238 %v20_40 = load i8, ptr %p, !range !{i8 20, i8 41} 239 %v0_10 = load i8, ptr %p, !range !{i8 0, i8 11} 240 %v2_3 = load i8, ptr %p, !range !{i8 2, i8 4} 241 %wo1 = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %v0_20, i8 %v20_40) 242 %res1 = extractvalue { i8, i1 } %wo1, 0 243 %cmp1.1 = icmp uge i8 %res1, 20 244 call void @use.i1(i1 %cmp1.1) 245 %cmp1.2 = icmp ule i8 %res1, 60 246 call void @use.i1(i1 %cmp1.2) 247 %cmp1.3 = icmp ugt i8 %res1, 20 248 call void @use.i1(i1 %cmp1.3) 249 %cmp1.4 = icmp ult i8 %res1, 60 250 call void @use.i1(i1 %cmp1.4) 251 252 %wo2 = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %v0_10, i8 %v20_40) 253 %res2 = extractvalue { i8, i1 } %wo2, 0 254 %cmp2.1 = icmp uge i8 %res2, -40 255 call void @use.i1(i1 %cmp2.1) 256 %cmp2.2 = icmp ule i8 %res2, -10 257 call void @use.i1(i1 %cmp2.2) 258 %cmp2.3 = icmp ugt i8 %res2, -40 259 call void @use.i1(i1 %cmp2.3) 260 %cmp2.4 = icmp ult i8 %res2, -10 261 call void @use.i1(i1 %cmp2.4) 262 263 %wo3 = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 %v20_40, i8 %v2_3) 264 %res3 = extractvalue { i8, i1 } %wo3, 0 265 %cmp3.1 = icmp uge i8 %res3, 40 266 call void @use.i1(i1 %cmp3.1) 267 %cmp3.2 = icmp ule i8 %res3, 120 268 call void @use.i1(i1 %cmp3.2) 269 %cmp3.3 = icmp ugt i8 %res3, 40 270 call void @use.i1(i1 %cmp3.3) 271 %cmp3.4 = icmp ult i8 %res3, 120 272 call void @use.i1(i1 %cmp3.4) 273 ret void 274} 275 276; SCCP doesn't really support vector ranges yet, just make sure we don't crash. 277define <2 x i1> @vec(<2 x i8> %v1, <2 x i8> %v2) { 278; CHECK-LABEL: @vec( 279; CHECK-NEXT: [[WO:%.*]] = call { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow.v2i8(<2 x i8> [[V1:%.*]], <2 x i8> [[V2:%.*]]) 280; CHECK-NEXT: [[OV:%.*]] = extractvalue { <2 x i8>, <2 x i1> } [[WO]], 1 281; CHECK-NEXT: ret <2 x i1> [[OV]] 282; 283 %wo = call { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow.v2i8(<2 x i8> %v1, <2 x i8> %v2) 284 %ov = extractvalue { <2 x i8>, <2 x i1> } %wo, 1 285 ret <2 x i1> %ov 286} 287