401 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 22; RUN: opt < %s -passes=correlated-propagation -S | FileCheck %s3 4declare void @use(i8, i8)5 6define i8 @simple_phi(i1 %c, i8 %a, i8 %b) {7; CHECK-LABEL: define i8 @simple_phi8; CHECK-SAME: (i1 [[C:%.*]], i8 [[A:%.*]], i8 [[B:%.*]]) {9; CHECK-NEXT: entry:10; CHECK-NEXT: br i1 [[C]], label [[THEN:%.*]], label [[ELSE:%.*]]11; CHECK: then:12; CHECK-NEXT: ret i8 [[A]]13; CHECK: else:14; CHECK-NEXT: ret i8 [[B]]15;16entry:17 %s = select i1 %c, i8 %a, i8 %b18 br i1 %c, label %then, label %else19 20then:21 %phi1 = phi i8 [ %s, %entry ]22 ret i8 %phi123 24else:25 %phi2 = phi i8 [ %s, %entry ]26 ret i8 %phi227}28 29define i8 @phi_other_edge(i1 %c, i8 %a, i8 %b, i32 %sw) {30; CHECK-LABEL: define i8 @phi_other_edge31; CHECK-SAME: (i1 [[C:%.*]], i8 [[A:%.*]], i8 [[B:%.*]], i32 [[SW:%.*]]) {32; CHECK-NEXT: entry:33; CHECK-NEXT: switch i32 [[SW]], label [[TEST:%.*]] [34; CHECK-NEXT: i32 0, label [[THEN:%.*]]35; CHECK-NEXT: i32 1, label [[ELSE:%.*]]36; CHECK-NEXT: ]37; CHECK: test:38; CHECK-NEXT: br i1 [[C]], label [[THEN]], label [[ELSE]]39; CHECK: then:40; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ [[A]], [[TEST]] ], [ 1, [[ENTRY:%.*]] ]41; CHECK-NEXT: ret i8 [[PHI1]]42; CHECK: else:43; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ [[B]], [[TEST]] ], [ 2, [[ENTRY]] ]44; CHECK-NEXT: ret i8 [[PHI2]]45;46entry:47 switch i32 %sw, label %test [48 i32 0, label %then49 i32 1, label %else50 ]51 52test:53 %s = select i1 %c, i8 %a, i8 %b54 br i1 %c, label %then, label %else55 56then:57 %phi1 = phi i8 [ %s, %test ], [ 1, %entry ]58 ret i8 %phi159 60else:61 %phi2 = phi i8 [ %s, %test ], [ 2, %entry ]62 ret i8 %phi263}64 65define void @phi_loop(i32) {66; CHECK-LABEL: define void @phi_loop67; CHECK-SAME: (i32 [[TMP0:%.*]]) {68; CHECK-NEXT: entry:69; CHECK-NEXT: br label [[LOOP:%.*]]70; CHECK: loop:71; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[TMP0]], [[ENTRY:%.*]] ], [ [[TMP2:%.*]], [[LOOP]] ]72; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[IDX]], 073; CHECK-NEXT: [[TMP2]] = add i32 [[IDX]], -174; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP1]], i32 0, i32 [[TMP2]]75; CHECK-NEXT: br i1 [[TMP1]], label [[OUT:%.*]], label [[LOOP]]76; CHECK: out:77; CHECK-NEXT: ret void78;79entry:80 br label %loop81 82loop:83 %idx = phi i32 [ %0, %entry ], [ %sel, %loop ]84 %1 = icmp eq i32 %idx, 085 %2 = add i32 %idx, -186 %sel = select i1 %1, i32 0, i32 %287 br i1 %1, label %out, label %loop88 89out:90 ret void91}92 93define i8 @simple_non_phi(i1 %c, i8 %a, i8 %b) {94; CHECK-LABEL: define i8 @simple_non_phi95; CHECK-SAME: (i1 [[C:%.*]], i8 [[A:%.*]], i8 [[B:%.*]]) {96; CHECK-NEXT: entry:97; CHECK-NEXT: br i1 [[C]], label [[THEN:%.*]], label [[ELSE:%.*]]98; CHECK: then:99; CHECK-NEXT: ret i8 [[A]]100; CHECK: else:101; CHECK-NEXT: ret i8 [[B]]102;103entry:104 %s = select i1 %c, i8 %a, i8 %b105 br i1 %c, label %then, label %else106 107then:108 ret i8 %s109 110else:111 ret i8 %s112}113 114 115define void @simple_multiple_uses(i1 %c, i8 %a, i8 %b) {116; CHECK-LABEL: define void @simple_multiple_uses117; CHECK-SAME: (i1 [[C:%.*]], i8 [[A:%.*]], i8 [[B:%.*]]) {118; CHECK-NEXT: entry:119; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i8 [[A]], i8 [[B]]120; CHECK-NEXT: call void @use(i8 [[S]], i8 [[S]])121; CHECK-NEXT: br i1 [[C]], label [[THEN:%.*]], label [[ELSE:%.*]]122; CHECK: then:123; CHECK-NEXT: call void @use(i8 [[A]], i8 [[A]])124; CHECK-NEXT: ret void125; CHECK: else:126; CHECK-NEXT: call void @use(i8 [[B]], i8 [[B]])127; CHECK-NEXT: ret void128;129entry:130 %s = select i1 %c, i8 %a, i8 %b131 call void @use(i8 %s, i8 %s)132 br i1 %c, label %then, label %else133 134then:135 call void @use(i8 %s, i8 %s)136 ret void137 138else:139 call void @use(i8 %s, i8 %s)140 ret void141}142 143define i8 @not_correlated(i1, i1) {144; CHECK-LABEL: define range(i8 0, 2) i8 @not_correlated145; CHECK-SAME: (i1 [[TMP0:%.*]], i1 [[TMP1:%.*]]) {146; CHECK-NEXT: entry:147; CHECK-NEXT: [[S:%.*]] = select i1 [[TMP0]], i8 0, i8 1148; CHECK-NEXT: br i1 [[TMP1]], label [[THEN:%.*]], label [[ELSE:%.*]]149; CHECK: then:150; CHECK-NEXT: ret i8 [[S]]151; CHECK: else:152; CHECK-NEXT: ret i8 [[S]]153;154entry:155 %s = select i1 %0, i8 0, i8 1156 br i1 %1, label %then, label %else157 158then:159 %a = phi i8 [ %s, %entry ]160 ret i8 %a161 162else:163 %b = phi i8 [ %s, %entry ]164 ret i8 %b165}166 167@c = global i32 0, align 4168@b = global i32 0, align 4169 170define i32 @PR23752() {171; CHECK-LABEL: define i32 @PR23752() {172; CHECK-NEXT: entry:173; CHECK-NEXT: br label [[FOR_BODY:%.*]]174; CHECK: for.body:175; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt ptr @b, @c176; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP2]], i32 0, i32 1177; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[SEL]], 1178; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[IF_END:%.*]]179; CHECK: if.end:180; CHECK-NEXT: ret i32 1181;182entry:183 br label %for.body184 185for.body:186 %phi = phi i32 [ 0, %entry ], [ %sel, %for.body ]187 %cmp2 = icmp sgt ptr @b, @c188 %sel = select i1 %cmp2, i32 %phi, i32 1189 %cmp = icmp ne i32 %sel, 1190 br i1 %cmp, label %for.body, label %if.end191 192 193if.end:194 ret i32 %sel195}196 197define i1 @test1(ptr %p, i1 %unknown) {198; CHECK-LABEL: define i1 @test1199; CHECK-SAME: (ptr [[P:%.*]], i1 [[UNKNOWN:%.*]]) {200; CHECK-NEXT: [[PVAL:%.*]] = load i32, ptr [[P]], align 4201; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[PVAL]], 255202; CHECK-NEXT: br i1 [[CMP1]], label [[NEXT:%.*]], label [[EXIT:%.*]]203; CHECK: next:204; CHECK-NEXT: [[MIN:%.*]] = select i1 [[UNKNOWN]], i32 [[PVAL]], i32 5205; CHECK-NEXT: ret i1 false206; CHECK: exit:207; CHECK-NEXT: ret i1 true208;209 %pval = load i32, ptr %p210 %cmp1 = icmp slt i32 %pval, 255211 br i1 %cmp1, label %next, label %exit212 213next:214 %min = select i1 %unknown, i32 %pval, i32 5215 %res = icmp eq i32 %min, 255216 ret i1 %res217 218exit:219 ret i1 true220}221 222; Check that we take a conservative meet223define i1 @test2(ptr %p, i32 %qval, i1 %unknown) {224; CHECK-LABEL: define i1 @test2225; CHECK-SAME: (ptr [[P:%.*]], i32 [[QVAL:%.*]], i1 [[UNKNOWN:%.*]]) {226; CHECK-NEXT: [[PVAL:%.*]] = load i32, ptr [[P]], align 4227; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[PVAL]], 255228; CHECK-NEXT: br i1 [[CMP1]], label [[NEXT:%.*]], label [[EXIT:%.*]]229; CHECK: next:230; CHECK-NEXT: [[MIN:%.*]] = select i1 [[UNKNOWN]], i32 [[PVAL]], i32 [[QVAL]]231; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[MIN]], 255232; CHECK-NEXT: ret i1 [[RES]]233; CHECK: exit:234; CHECK-NEXT: ret i1 true235;236 %pval = load i32, ptr %p237 %cmp1 = icmp slt i32 %pval, 255238 br i1 %cmp1, label %next, label %exit239 240next:241 %min = select i1 %unknown, i32 %pval, i32 %qval242 %res = icmp eq i32 %min, 255243 ret i1 %res244 245exit:246 ret i1 true247}248 249; Same as @test2, but for the opposite select input250define i1 @test3(ptr %p, i32 %qval, i1 %unknown) {251; CHECK-LABEL: define i1 @test3252; CHECK-SAME: (ptr [[P:%.*]], i32 [[QVAL:%.*]], i1 [[UNKNOWN:%.*]]) {253; CHECK-NEXT: [[PVAL:%.*]] = load i32, ptr [[P]], align 4254; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[PVAL]], 255255; CHECK-NEXT: br i1 [[CMP1]], label [[NEXT:%.*]], label [[EXIT:%.*]]256; CHECK: next:257; CHECK-NEXT: [[MIN:%.*]] = select i1 [[UNKNOWN]], i32 [[QVAL]], i32 [[PVAL]]258; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[MIN]], 255259; CHECK-NEXT: ret i1 [[RES]]260; CHECK: exit:261; CHECK-NEXT: ret i1 true262;263 %pval = load i32, ptr %p264 %cmp1 = icmp slt i32 %pval, 255265 br i1 %cmp1, label %next, label %exit266 267next:268 %min = select i1 %unknown, i32 %qval, i32 %pval269 %res = icmp eq i32 %min, 255270 ret i1 %res271 272exit:273 ret i1 true274}275 276; Conflicting constants (i.e. isOverdefined result)277; NOTE: Using doubles in this version is a bit of a hack. This278; is to get around the fact that all integers (including constants279; and non-constants) are actually represented as constant-ranges.280define i1 @test4(ptr %p, i32 %qval, i1 %unknown) {281; CHECK-LABEL: define i1 @test4282; CHECK-SAME: (ptr [[P:%.*]], i32 [[QVAL:%.*]], i1 [[UNKNOWN:%.*]]) {283; CHECK-NEXT: [[PVAL:%.*]] = load i32, ptr [[P]], align 4284; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[PVAL]], 255285; CHECK-NEXT: br i1 [[CMP1]], label [[NEXT:%.*]], label [[EXIT:%.*]]286; CHECK: next:287; CHECK-NEXT: [[MIN:%.*]] = select i1 [[UNKNOWN]], double 1.000000e+00, double 0.000000e+00288; CHECK-NEXT: [[RES:%.*]] = fcmp oeq double [[MIN]], 3.000000e+02289; CHECK-NEXT: ret i1 [[RES]]290; CHECK: exit:291; CHECK-NEXT: ret i1 true292;293 %pval = load i32, ptr %p294 %cmp1 = icmp slt i32 %pval, 255295 br i1 %cmp1, label %next, label %exit296 297next:298 %min = select i1 %unknown, double 1.0, double 0.0299 %res = fcmp oeq double %min, 300.0300 ret i1 %res301 302exit:303 ret i1 true304}305 306;; Using the condition to clamp the result307;;308 309define i1 @test5(ptr %p, i1 %unknown) {310; CHECK-LABEL: define i1 @test5311; CHECK-SAME: (ptr [[P:%.*]], i1 [[UNKNOWN:%.*]]) {312; CHECK-NEXT: [[PVAL:%.*]] = load i32, ptr [[P]], align 4, !noundef [[META0:![0-9]+]]313; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[PVAL]], 255314; CHECK-NEXT: br i1 [[CMP1]], label [[NEXT:%.*]], label [[EXIT:%.*]]315; CHECK: next:316; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[PVAL]], 0317; CHECK-NEXT: [[MIN:%.*]] = select i1 [[COND]], i32 [[PVAL]], i32 5318; CHECK-NEXT: ret i1 false319; CHECK: exit:320; CHECK-NEXT: ret i1 true321;322 %pval = load i32, ptr %p, !noundef !0323 %cmp1 = icmp slt i32 %pval, 255324 br i1 %cmp1, label %next, label %exit325 326next:327 %cond = icmp sgt i32 %pval, 0328 %min = select i1 %cond, i32 %pval, i32 5329 %res = icmp eq i32 %min, -1330 ret i1 %res331 332exit:333 ret i1 true334}335 336define i1 @test6(ptr %p, i1 %unknown) {337; CHECK-LABEL: define i1 @test6338; CHECK-SAME: (ptr [[P:%.*]], i1 [[UNKNOWN:%.*]]) {339; CHECK-NEXT: [[PVAL:%.*]] = load i32, ptr [[P]], align 4, !noundef [[META0]]340; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[PVAL]], 255341; CHECK-NEXT: br i1 [[CMP1]], label [[NEXT:%.*]], label [[EXIT:%.*]]342; CHECK: next:343; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[PVAL]], 254344; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND]], i32 [[PVAL]], i32 1345; CHECK-NEXT: ret i1 true346; CHECK: exit:347; CHECK-NEXT: ret i1 true348;349 %pval = load i32, ptr %p, !noundef !0350 %cmp1 = icmp ult i32 %pval, 255351 br i1 %cmp1, label %next, label %exit352 353next:354 %cond = icmp ne i32 %pval, 254355 %sel = select i1 %cond, i32 %pval, i32 1356 %res = icmp slt i32 %sel, 254357 ret i1 %res358 359exit:360 ret i1 true361}362 363define i64 @select_cond_may_undef(i32 %a) {364; CHECK-LABEL: define range(i64 -2147483648, 2147483648) i64 @select_cond_may_undef365; CHECK-SAME: (i32 [[A:%.*]]) {366; CHECK-NEXT: [[IS_A_NONNEGATIVE:%.*]] = icmp sgt i32 [[A]], 1367; CHECK-NEXT: [[NARROW:%.*]] = select i1 [[IS_A_NONNEGATIVE]], i32 [[A]], i32 0368; CHECK-NEXT: [[MAX:%.*]] = sext i32 [[NARROW]] to i64369; CHECK-NEXT: ret i64 [[MAX]]370;371 %is_a_nonnegative = icmp sgt i32 %a, 1372 %narrow = select i1 %is_a_nonnegative, i32 %a, i32 0373 %max = sext i32 %narrow to i64374 ret i64 %max375}376 377define i32 @test_solve_select_at_use(i32 %a, i32 %b, i32 %c) {378; CHECK-LABEL: define i32 @test_solve_select_at_use379; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {380; CHECK-NEXT: entry:381; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[A]], 0382; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[A]], -1383; CHECK-NEXT: br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]384; CHECK: if.then:385; CHECK-NEXT: ret i32 [[C]]386; CHECK: if.else:387; CHECK-NEXT: ret i32 [[B]]388;389entry:390 %cmp = icmp slt i32 %a, 0391 %retval = select i1 %cmp, i32 %b, i32 %c392 %cond = icmp sgt i32 %a, -1393 br i1 %cond, label %if.then, label %if.else394if.then:395 ret i32 %retval396if.else:397 ret i32 %retval398}399 400!0 = !{}401