brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.7 KiB · d916fca Raw
442 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt -S -passes=jump-threading,dce < %s | FileCheck %s3 4declare void @llvm.experimental.guard(i1, ...)5 6declare i32 @f1()7declare i32 @f2()8 9define i32 @branch_implies_guard(i32 %a) {10; CHECK-LABEL: @branch_implies_guard(11; CHECK-NEXT:    [[COND:%.*]] = icmp slt i32 [[A:%.*]], 1012; CHECK-NEXT:    br i1 [[COND]], label [[T1_SPLIT:%.*]], label [[F1_SPLIT:%.*]]13; CHECK:       T1.split:14; CHECK-NEXT:    [[V1:%.*]] = call i32 @f1()15; CHECK-NEXT:    [[RETVAL3:%.*]] = add i32 [[V1]], 1016; CHECK-NEXT:    br label [[MERGE:%.*]]17; CHECK:       F1.split:18; CHECK-NEXT:    [[V2:%.*]] = call i32 @f2()19; CHECK-NEXT:    [[RETVAL1:%.*]] = add i32 [[V2]], 1020; CHECK-NEXT:    [[CONDGUARD2:%.*]] = icmp slt i32 [[A]], 2021; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[CONDGUARD2]]) [ "deopt"() ]22; CHECK-NEXT:    br label [[MERGE]]23; CHECK:       Merge:24; CHECK-NEXT:    [[TMP1:%.*]] = phi i32 [ [[RETVAL3]], [[T1_SPLIT]] ], [ [[RETVAL1]], [[F1_SPLIT]] ]25; CHECK-NEXT:    ret i32 [[TMP1]]26;27  %cond = icmp slt i32 %a, 1028  br i1 %cond, label %T1, label %F129 30T1:31  %v1 = call i32 @f1()32  br label %Merge33 34F1:35  %v2 = call i32 @f2()36  br label %Merge37 38Merge:39  %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ]40  %retVal = add i32 %retPhi, 1041  %condGuard = icmp slt i32 %a, 2042  call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]43  ret i32 %retVal44}45 46define i32 @not_branch_implies_guard(i32 %a) {47; CHECK-LABEL: @not_branch_implies_guard(48; CHECK-NEXT:    [[COND:%.*]] = icmp slt i32 [[A:%.*]], 2049; CHECK-NEXT:    br i1 [[COND]], label [[T1_SPLIT:%.*]], label [[F1_SPLIT:%.*]]50; CHECK:       T1.split:51; CHECK-NEXT:    [[V1:%.*]] = call i32 @f1()52; CHECK-NEXT:    [[RETVAL1:%.*]] = add i32 [[V1]], 1053; CHECK-NEXT:    [[CONDGUARD2:%.*]] = icmp sgt i32 [[A]], 1054; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[CONDGUARD2]]) [ "deopt"() ]55; CHECK-NEXT:    br label [[MERGE:%.*]]56; CHECK:       F1.split:57; CHECK-NEXT:    [[V2:%.*]] = call i32 @f2()58; CHECK-NEXT:    [[RETVAL3:%.*]] = add i32 [[V2]], 1059; CHECK-NEXT:    br label [[MERGE]]60; CHECK:       Merge:61; CHECK-NEXT:    [[TMP1:%.*]] = phi i32 [ [[RETVAL3]], [[F1_SPLIT]] ], [ [[RETVAL1]], [[T1_SPLIT]] ]62; CHECK-NEXT:    ret i32 [[TMP1]]63;64  %cond = icmp slt i32 %a, 2065  br i1 %cond, label %T1, label %F166 67T1:68  %v1 = call i32 @f1()69  br label %Merge70 71F1:72  %v2 = call i32 @f2()73  br label %Merge74 75Merge:76  %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ]77  %retVal = add i32 %retPhi, 1078  %condGuard = icmp sgt i32 %a, 1079  call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]80  ret i32 %retVal81}82 83define i32 @branch_overlaps_guard(i32 %a) {84; CHECK-LABEL: @branch_overlaps_guard(85; CHECK-NEXT:    [[COND:%.*]] = icmp slt i32 [[A:%.*]], 2086; CHECK-NEXT:    br i1 [[COND]], label [[T1:%.*]], label [[F1:%.*]]87; CHECK:       T1:88; CHECK-NEXT:    [[V1:%.*]] = call i32 @f1()89; CHECK-NEXT:    br label [[MERGE:%.*]]90; CHECK:       F1:91; CHECK-NEXT:    [[V2:%.*]] = call i32 @f2()92; CHECK-NEXT:    br label [[MERGE]]93; CHECK:       Merge:94; CHECK-NEXT:    [[RETPHI:%.*]] = phi i32 [ [[V1]], [[T1]] ], [ [[V2]], [[F1]] ]95; CHECK-NEXT:    [[RETVAL:%.*]] = add i32 [[RETPHI]], 1096; CHECK-NEXT:    [[CONDGUARD:%.*]] = icmp slt i32 [[A]], 1097; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[CONDGUARD]]) [ "deopt"() ]98; CHECK-NEXT:    ret i32 [[RETVAL]]99;100  %cond = icmp slt i32 %a, 20101  br i1 %cond, label %T1, label %F1102 103T1:104  %v1 = call i32 @f1()105  br label %Merge106 107F1:108  %v2 = call i32 @f2()109  br label %Merge110 111Merge:112  %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ]113  %retVal = add i32 %retPhi, 10114  %condGuard = icmp slt i32 %a, 10115  call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]116  ret i32 %retVal117}118 119define i32 @branch_doesnt_overlap_guard(i32 %a) {120; CHECK-LABEL: @branch_doesnt_overlap_guard(121; CHECK-NEXT:    [[COND:%.*]] = icmp slt i32 [[A:%.*]], 10122; CHECK-NEXT:    br i1 [[COND]], label [[T1:%.*]], label [[F1:%.*]]123; CHECK:       T1:124; CHECK-NEXT:    [[V1:%.*]] = call i32 @f1()125; CHECK-NEXT:    br label [[MERGE:%.*]]126; CHECK:       F1:127; CHECK-NEXT:    [[V2:%.*]] = call i32 @f2()128; CHECK-NEXT:    br label [[MERGE]]129; CHECK:       Merge:130; CHECK-NEXT:    [[RETPHI:%.*]] = phi i32 [ [[V1]], [[T1]] ], [ [[V2]], [[F1]] ]131; CHECK-NEXT:    [[RETVAL:%.*]] = add i32 [[RETPHI]], 10132; CHECK-NEXT:    [[CONDGUARD:%.*]] = icmp sgt i32 [[A]], 20133; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[CONDGUARD]]) [ "deopt"() ]134; CHECK-NEXT:    ret i32 [[RETVAL]]135;136  %cond = icmp slt i32 %a, 10137  br i1 %cond, label %T1, label %F1138 139T1:140  %v1 = call i32 @f1()141  br label %Merge142 143F1:144  %v2 = call i32 @f2()145  br label %Merge146 147Merge:148  %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ]149  %retVal = add i32 %retPhi, 10150  %condGuard = icmp sgt i32 %a, 20151  call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]152  ret i32 %retVal153}154 155define i32 @not_a_diamond1(i32 %a, i1 %cond1) {156; CHECK-LABEL: @not_a_diamond1(157; CHECK-NEXT:    br i1 [[COND1:%.*]], label [[PRED:%.*]], label [[EXIT:%.*]]158; CHECK:       Pred:159; CHECK-NEXT:    switch i32 [[A:%.*]], label [[EXIT]] [160; CHECK-NEXT:    i32 10, label [[MERGE:%.*]]161; CHECK-NEXT:    i32 20, label [[MERGE]]162; CHECK-NEXT:    ]163; CHECK:       Merge:164; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND1]]) [ "deopt"() ]165; CHECK-NEXT:    br label [[EXIT]]166; CHECK:       Exit:167; CHECK-NEXT:    ret i32 [[A]]168;169  br i1 %cond1, label %Pred, label %Exit170 171Pred:172  switch i32 %a, label %Exit [173  i32 10, label %Merge174  i32 20, label %Merge175  ]176 177Merge:178  call void(i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ]179  br label %Exit180 181Exit:182  ret i32 %a183}184 185define void @not_a_diamond2(i32 %a, i1 %cond1) {186; CHECK-LABEL: @not_a_diamond2(187; CHECK-NEXT:  Pred:188; CHECK-NEXT:    switch i32 [[A:%.*]], label [[EXIT:%.*]] [189; CHECK-NEXT:    i32 10, label [[MERGE:%.*]]190; CHECK-NEXT:    i32 20, label [[MERGE]]191; CHECK-NEXT:    ]192; CHECK:       Merge:193; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND1:%.*]]) [ "deopt"() ]194; CHECK-NEXT:    ret void195; CHECK:       Exit:196; CHECK-NEXT:    ret void197;198  br label %Parent199 200Merge:201  call void(i1, ...) @llvm.experimental.guard(i1 %cond1)[ "deopt"() ]202  ret void203 204Pred:205  switch i32 %a, label %Exit [206  i32 10, label %Merge207  i32 20, label %Merge208  ]209 210Parent:211  br label %Pred212 213Exit:214  ret void215}216 217declare void @never_called(i1)218 219; LVI uses guard to identify value of %c2 in branch as true, we cannot replace that220; guard with guard(true & c1).221define void @dont_fold_guard(ptr %addr, i32 %i, i32 %length) {222; CHECK-LABEL: @dont_fold_guard(223; CHECK-NEXT:  BB1:224; CHECK-NEXT:    [[C1:%.*]] = icmp ult i32 [[I:%.*]], [[LENGTH:%.*]]225; CHECK-NEXT:    [[C2:%.*]] = icmp eq i32 [[I]], 0226; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[C1]], [[C2]]227; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]228; CHECK-NEXT:    call void @never_called(i1 true)229; CHECK-NEXT:    ret void230;231  %c1 = icmp ult i32 %i, %length232  %c2 = icmp eq i32 %i, 0233  %wide.chk = and i1 %c1, %c2234  call void(i1, ...) @llvm.experimental.guard(i1 %wide.chk) [ "deopt"() ]235  br i1 %c2, label %BB1, label %BB2236 237BB1:238  call void @never_called(i1 %c2)239  ret void240 241BB2:242  ret void243}244 245declare void @dummy(i1) nounwind willreturn246; same as dont_fold_guard1 but there's a use immediately after guard and before247; branch. We can fold that use.248define void @dont_fold_guard2(ptr %addr, i32 %i, i32 %length) {249; CHECK-LABEL: @dont_fold_guard2(250; CHECK-NEXT:  BB1:251; CHECK-NEXT:    [[C1:%.*]] = icmp ult i32 [[I:%.*]], [[LENGTH:%.*]]252; CHECK-NEXT:    [[C2:%.*]] = icmp eq i32 [[I]], 0253; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[C1]], [[C2]]254; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]255; CHECK-NEXT:    call void @dummy(i1 true)256; CHECK-NEXT:    call void @never_called(i1 true)257; CHECK-NEXT:    ret void258;259  %c1 = icmp ult i32 %i, %length260  %c2 = icmp eq i32 %i, 0261  %wide.chk = and i1 %c1, %c2262  call void(i1, ...) @llvm.experimental.guard(i1 %wide.chk) [ "deopt"() ]263  call void @dummy(i1 %c2)264  br i1 %c2, label %BB1, label %BB2265 266BB1:267  call void @never_called(i1 %c2)268  ret void269 270BB2:271  ret void272}273 274; same as dont_fold_guard1 but condition %cmp is not an instruction.275; We cannot fold the guard under any circumstance.276; FIXME: We can merge unreachableBB2 into not_zero.277define void @dont_fold_guard3(ptr %addr, i1 %cmp, i32 %i, i32 %length) {278; CHECK-LABEL: @dont_fold_guard3(279; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[CMP:%.*]]) [ "deopt"() ]280; CHECK-NEXT:    br i1 [[CMP]], label [[BB1:%.*]], label [[BB2:%.*]]281; CHECK:       BB1:282; CHECK-NEXT:    call void @never_called(i1 [[CMP]])283; CHECK-NEXT:    ret void284; CHECK:       BB2:285; CHECK-NEXT:    ret void286;287  call void(i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]288  br i1 %cmp, label %BB1, label %BB2289 290BB1:291  call void @never_called(i1 %cmp)292  ret void293 294BB2:295  ret void296}297 298declare void @f(i1)299; Same as dont_fold_guard1 but use switch instead of branch.300; triggers source code `ProcessThreadableEdges`.301define void @dont_fold_guard4(i1 %cmp1, i32 %i) nounwind {302; CHECK-LABEL: @dont_fold_guard4(303; CHECK-NEXT:  entry:304; CHECK-NEXT:    br i1 [[CMP1:%.*]], label [[L2:%.*]], label [[L3:%.*]]305; CHECK:       L2:306; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0307; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[CMP]]) [ "deopt"() ]308; CHECK-NEXT:    call void @dummy(i1 true)309; CHECK-NEXT:    call void @f(i1 true)310; CHECK-NEXT:    ret void311; CHECK:       L3:312; CHECK-NEXT:    ret void313;314entry:315  br i1 %cmp1, label %L0, label %L3316L0:317  %cmp = icmp eq i32 %i, 0318  call void(i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]319  call void @dummy(i1 %cmp)320  switch i1 %cmp, label %L3 [321  i1 false, label %L1322  i1 true, label %L2323  ]324 325L1:326  ret void327L2:328  call void @f(i1 %cmp)329  ret void330L3:331  ret void332}333 334; Make sure that we don't PRE a non-speculable load across a guard.335define void @unsafe_pre_across_guard(ptr %p, i1 %load.is.valid) {336; CHECK-LABEL: @unsafe_pre_across_guard(337; CHECK-NEXT:  entry:338; CHECK-NEXT:    br label [[LOOP:%.*]]339; CHECK:       loop:340; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[LOAD_IS_VALID:%.*]]) [ "deopt"() ]341; CHECK-NEXT:    [[LOADED:%.*]] = load i8, ptr [[P:%.*]], align 1342; CHECK-NEXT:    [[CONTINUE:%.*]] = icmp eq i8 [[LOADED]], 0343; CHECK-NEXT:    br i1 [[CONTINUE]], label [[EXIT:%.*]], label [[LOOP]]344; CHECK:       exit:345; CHECK-NEXT:    ret void346;347entry:348  br label %loop349 350loop:                                             ; preds = %loop, %entry351  call void (i1, ...) @llvm.experimental.guard(i1 %load.is.valid) [ "deopt"() ]352  %loaded = load i8, ptr %p353  %continue = icmp eq i8 %loaded, 0354  br i1 %continue, label %exit, label %loop355 356exit:                                             ; preds = %loop357  ret void358}359 360; Make sure that we can safely PRE a speculable load across a guard.361define void @safe_pre_across_guard(ptr noalias nocapture readonly dereferenceable(8) %p, i1 %load.is.valid) nofree nosync {362; CHECK-LABEL: @safe_pre_across_guard(363; CHECK-NEXT:  entry:364; CHECK-NEXT:    [[LOADED_PR:%.*]] = load i8, ptr [[P:%.*]], align 1365; CHECK-NEXT:    br label [[LOOP:%.*]]366; CHECK:       loop:367; CHECK-NEXT:    [[LOADED:%.*]] = phi i8 [ [[LOADED]], [[LOOP]] ], [ [[LOADED_PR]], [[ENTRY:%.*]] ]368; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[LOAD_IS_VALID:%.*]]) [ "deopt"() ]369; CHECK-NEXT:    [[CONTINUE:%.*]] = icmp eq i8 [[LOADED]], 0370; CHECK-NEXT:    br i1 [[CONTINUE]], label [[EXIT:%.*]], label [[LOOP]]371; CHECK:       exit:372; CHECK-NEXT:    ret void373;374 375entry:376  br label %loop377 378loop:                                             ; preds = %loop, %entry379  call void (i1, ...) @llvm.experimental.guard(i1 %load.is.valid) [ "deopt"() ]380  %loaded = load i8, ptr %p381  %continue = icmp eq i8 %loaded, 0382  br i1 %continue, label %exit, label %loop383 384exit:                                             ; preds = %loop385  ret void386}387 388; Make sure that we don't PRE a non-speculable load across a call which may389; alias with the load.390define void @unsafe_pre_across_call(ptr %p) {391; CHECK-LABEL: @unsafe_pre_across_call(392; CHECK-NEXT:  entry:393; CHECK-NEXT:    br label [[LOOP:%.*]]394; CHECK:       loop:395; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @f1()396; CHECK-NEXT:    [[LOADED:%.*]] = load i8, ptr [[P:%.*]], align 1397; CHECK-NEXT:    [[CONTINUE:%.*]] = icmp eq i8 [[LOADED]], 0398; CHECK-NEXT:    br i1 [[CONTINUE]], label [[EXIT:%.*]], label [[LOOP]]399; CHECK:       exit:400; CHECK-NEXT:    ret void401;402entry:403  br label %loop404 405loop:                                             ; preds = %loop, %entry406  call i32 @f1()407  %loaded = load i8, ptr %p408  %continue = icmp eq i8 %loaded, 0409  br i1 %continue, label %exit, label %loop410 411exit:                                             ; preds = %loop412  ret void413}414 415; Make sure that we can safely PRE a speculable load across a call.416define void @safe_pre_across_call(ptr noalias nocapture readonly dereferenceable(8) %p) nofree nosync {417; CHECK-LABEL: @safe_pre_across_call(418; CHECK-NEXT:  entry:419; CHECK-NEXT:    [[LOADED_PR:%.*]] = load i8, ptr [[P:%.*]], align 1420; CHECK-NEXT:    br label [[LOOP:%.*]]421; CHECK:       loop:422; CHECK-NEXT:    [[LOADED:%.*]] = phi i8 [ [[LOADED]], [[LOOP]] ], [ [[LOADED_PR]], [[ENTRY:%.*]] ]423; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @f1()424; CHECK-NEXT:    [[CONTINUE:%.*]] = icmp eq i8 [[LOADED]], 0425; CHECK-NEXT:    br i1 [[CONTINUE]], label [[EXIT:%.*]], label [[LOOP]]426; CHECK:       exit:427; CHECK-NEXT:    ret void428;429 430entry:431  br label %loop432 433loop:                                             ; preds = %loop, %entry434  call i32 @f1()435  %loaded = load i8, ptr %p436  %continue = icmp eq i8 %loaded, 0437  br i1 %continue, label %exit, label %loop438 439exit:                                             ; preds = %loop440  ret void441}442