287 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt -S -passes=sccp < %s | FileCheck %s3 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]], 126; 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]], 131; 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]], 136; CHECK-NEXT: call void @use.i1(i1 [[OV6]])37; CHECK-NEXT: ret void38;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, 149 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, 153 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, 157 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, 161 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, 165 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, 169 call void @use.i1(i1 %ov6)70 ret void71}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]], 186; 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]], 191; 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]], 196; CHECK-NEXT: call void @use.i1(i1 [[OV6]])97; CHECK-NEXT: ret void98;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, 1109 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, 1113 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, 1117 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, 1121 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, 1125 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, 1129 call void @use.i1(i1 %ov6)130 ret void131}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]], 0141; 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]], 20144; CHECK-NEXT: call void @use.i1(i1 [[CMP1_3]])145; CHECK-NEXT: [[CMP1_4:%.*]] = icmp ult i8 [[RES1]], 60146; 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]], 0149; 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]], -40152; CHECK-NEXT: call void @use.i1(i1 [[CMP2_3]])153; CHECK-NEXT: [[CMP2_4:%.*]] = icmp ult i8 [[RES2]], -10154; 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]], 0157; 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]], 40160; CHECK-NEXT: call void @use.i1(i1 [[CMP3_3]])161; CHECK-NEXT: [[CMP3_4:%.*]] = icmp ult i8 [[RES3]], 120162; CHECK-NEXT: call void @use.i1(i1 [[CMP3_4]])163; CHECK-NEXT: ret void164;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, 0171 %cmp1.1 = icmp uge i8 %res1, 20172 call void @use.i1(i1 %cmp1.1)173 %cmp1.2 = icmp ule i8 %res1, 60174 call void @use.i1(i1 %cmp1.2)175 %cmp1.3 = icmp ugt i8 %res1, 20176 call void @use.i1(i1 %cmp1.3)177 %cmp1.4 = icmp ult i8 %res1, 60178 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, 0183 %cmp2.1 = icmp uge i8 %res2, -40184 call void @use.i1(i1 %cmp2.1)185 %cmp2.2 = icmp ule i8 %res2, -10186 call void @use.i1(i1 %cmp2.2)187 %cmp2.3 = icmp ugt i8 %res2, -40188 call void @use.i1(i1 %cmp2.3)189 %cmp2.4 = icmp ult i8 %res2, -10190 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, 0194 %cmp3.1 = icmp uge i8 %res3, 40195 call void @use.i1(i1 %cmp3.1)196 %cmp3.2 = icmp ule i8 %res3, 120197 call void @use.i1(i1 %cmp3.2)198 %cmp3.3 = icmp ugt i8 %res3, 40199 call void @use.i1(i1 %cmp3.3)200 %cmp3.4 = icmp ult i8 %res3, 120201 call void @use.i1(i1 %cmp3.4)202 ret void203}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]], 0213; 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]], 20216; CHECK-NEXT: call void @use.i1(i1 [[CMP1_3]])217; CHECK-NEXT: [[CMP1_4:%.*]] = icmp ult i8 [[RES1]], 60218; 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]], 0221; 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]], -40224; CHECK-NEXT: call void @use.i1(i1 [[CMP2_3]])225; CHECK-NEXT: [[CMP2_4:%.*]] = icmp ult i8 [[RES2]], -10226; 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]], 0229; 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]], 40232; CHECK-NEXT: call void @use.i1(i1 [[CMP3_3]])233; CHECK-NEXT: [[CMP3_4:%.*]] = icmp ult i8 [[RES3]], 120234; CHECK-NEXT: call void @use.i1(i1 [[CMP3_4]])235; CHECK-NEXT: ret void236;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, 0243 %cmp1.1 = icmp uge i8 %res1, 20244 call void @use.i1(i1 %cmp1.1)245 %cmp1.2 = icmp ule i8 %res1, 60246 call void @use.i1(i1 %cmp1.2)247 %cmp1.3 = icmp ugt i8 %res1, 20248 call void @use.i1(i1 %cmp1.3)249 %cmp1.4 = icmp ult i8 %res1, 60250 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, 0254 %cmp2.1 = icmp uge i8 %res2, -40255 call void @use.i1(i1 %cmp2.1)256 %cmp2.2 = icmp ule i8 %res2, -10257 call void @use.i1(i1 %cmp2.2)258 %cmp2.3 = icmp ugt i8 %res2, -40259 call void @use.i1(i1 %cmp2.3)260 %cmp2.4 = icmp ult i8 %res2, -10261 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, 0265 %cmp3.1 = icmp uge i8 %res3, 40266 call void @use.i1(i1 %cmp3.1)267 %cmp3.2 = icmp ule i8 %res3, 120268 call void @use.i1(i1 %cmp3.2)269 %cmp3.3 = icmp ugt i8 %res3, 40270 call void @use.i1(i1 %cmp3.3)271 %cmp3.4 = icmp ult i8 %res3, 120272 call void @use.i1(i1 %cmp3.4)273 ret void274}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]], 1281; 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, 1285 ret <2 x i1> %ov286}287