brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.4 KiB · 3623f01 Raw
253 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt -S -passes=guard-widening,dce < %s | FileCheck %s3 4declare void @llvm.experimental.guard(i1,...)5declare i1 @dummy()6 7; This tests shows the incorrect behavior of guard widening in terms of8; interaction with poison values.9 10; Let x incoming parameter is used for rane checks.11; Test generates 5 checks. One of them (c2) is used to get the corretness12; of nuw/nsw flags for x3 and x5. Others are used in guards and represent13; the checks x + 10 u< L, x + 15 u< L, x + 20 u< L and x + 3 u< L.14; The first two checks are in the first basic block and guard widening15; considers them as profitable to combine.16; When c4 and c3 are considered, number of check becomes more than two17; and combineRangeCheck consider them as profitable even if they are in18; different basic blocks.19; Accoding to algorithm of combineRangeCheck it detects that c3 and c420; are enough to cover c1 and c5, so it ends up with guard of c3 && c421; while both of them are poison at entry. This is a bug.22 23define void @combine_range_checks(i32 %x) {24; CHECK-LABEL: @combine_range_checks(25; CHECK-NEXT:  entry:26; CHECK-NEXT:    [[X_GW_FR:%.*]] = freeze i32 [[X:%.*]]27; CHECK-NEXT:    [[X2:%.*]] = add i32 [[X_GW_FR]], 028; CHECK-NEXT:    [[C2:%.*]] = icmp ult i32 [[X2]], 20029; CHECK-NEXT:    [[X3:%.*]] = add i32 [[X_GW_FR]], 330; CHECK-NEXT:    [[C3:%.*]] = icmp ult i32 [[X3]], 10031; CHECK-NEXT:    [[X4:%.*]] = add i32 [[X_GW_FR]], 2032; CHECK-NEXT:    [[C4:%.*]] = icmp ult i32 [[X4]], 10033; CHECK-NEXT:    [[WIDE_CHK2:%.*]] = and i1 [[C4]], [[C3]]34; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"(i64 1) ]35; CHECK-NEXT:    br i1 [[C2]], label [[OK:%.*]], label [[OUT:%.*]]36; CHECK:       ok:37; CHECK-NEXT:    br label [[OUT]]38; CHECK:       out:39; CHECK-NEXT:    ret void40;41entry:42  %x1 = add i32 %x, 1043  %c1 = icmp ult i32 %x1, 10044  %x2 = add i32 %x, 045  %c2 = icmp ult i32 %x2, 20046  %x3 = add nuw nsw i32 %x, 347  %c3 = icmp ult i32 %x3, 10048  %x4 = add nuw nsw i32 %x, 2049  %c4 = icmp ult i32 %x4, 10050  %x5 = add i32 %x, 1551  %c5 = icmp ult i32 %x5, 10052  call void(i1, ...) @llvm.experimental.guard(i1 %c1) [ "deopt"(i64 1) ]53  call void(i1, ...) @llvm.experimental.guard(i1 %c5) [ "deopt"(i64 5) ]54  br i1 %c2, label %ok, label %out55ok:56  call void(i1, ...) @llvm.experimental.guard(i1 %c4) [ "deopt"(i64 4) ]57  call void(i1, ...) @llvm.experimental.guard(i1 %c3) [ "deopt"(i64 3) ]58  br label %out59out:60  ret void61}62 63; This is similar to @combine_range_checks but shows that simple freeze64; over c3 and c4 will not help due to with X = SMAX_INT, guard with c1 will65; go to deoptimization. But after guard widening freeze of c3 and c4 may return66; true due to c3 and c4 are poisons and we pass guard executing side effect store67; which never been executed in original program.68define void @combine_range_checks_with_side_effect(i32 %x, ptr %p) {69; CHECK-LABEL: @combine_range_checks_with_side_effect(70; CHECK-NEXT:  entry:71; CHECK-NEXT:    [[X_GW_FR:%.*]] = freeze i32 [[X:%.*]]72; CHECK-NEXT:    [[X2:%.*]] = add i32 [[X_GW_FR]], 073; CHECK-NEXT:    [[C2:%.*]] = icmp ult i32 [[X2]], 20074; CHECK-NEXT:    [[X3:%.*]] = add i32 [[X_GW_FR]], 375; CHECK-NEXT:    [[C3:%.*]] = icmp ult i32 [[X3]], 10076; CHECK-NEXT:    [[X4:%.*]] = add i32 [[X_GW_FR]], 2077; CHECK-NEXT:    [[C4:%.*]] = icmp ult i32 [[X4]], 10078; CHECK-NEXT:    [[WIDE_CHK2:%.*]] = and i1 [[C4]], [[C3]]79; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"(i64 1) ]80; CHECK-NEXT:    store i32 0, ptr [[P:%.*]], align 481; CHECK-NEXT:    br i1 [[C2]], label [[OK:%.*]], label [[OUT:%.*]]82; CHECK:       ok:83; CHECK-NEXT:    br label [[OUT]]84; CHECK:       out:85; CHECK-NEXT:    ret void86;87entry:88  %x1 = add i32 %x, 1089  %c1 = icmp ult i32 %x1, 10090  %x2 = add i32 %x, 091  %c2 = icmp ult i32 %x2, 20092  %x3 = add nuw nsw i32 %x, 393  %c3 = icmp ult i32 %x3, 10094  %x4 = add nuw nsw i32 %x, 2095  %c4 = icmp ult i32 %x4, 10096  %x5 = add i32 %x, 1597  %c5 = icmp ult i32 %x5, 10098  call void(i1, ...) @llvm.experimental.guard(i1 %c1) [ "deopt"(i64 1) ]99  call void(i1, ...) @llvm.experimental.guard(i1 %c5) [ "deopt"(i64 5) ]100  store i32 0, ptr %p101  br i1 %c2, label %ok, label %out102ok:103  call void(i1, ...) @llvm.experimental.guard(i1 %c4) [ "deopt"(i64 4) ]104  call void(i1, ...) @llvm.experimental.guard(i1 %c3) [ "deopt"(i64 3) ]105  br label %out106out:107  ret void108}109 110 111; The test shows the bug in guard widening. Critical pieces.112; There is a %cond_1 check which provides the correctness of nuw nsw in %b.shift.113; %b.shift and %cond_2 are poisons and after guard widening it leads to UB114; for both arithmetic and logcal and.115define void @simple_case(i32 %a, i32 %b, i1 %cnd) {116; CHECK-LABEL: @simple_case(117; CHECK-NEXT:  entry:118; CHECK-NEXT:    [[B_GW_FR:%.*]] = freeze i32 [[B:%.*]]119; CHECK-NEXT:    [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10120; CHECK-NEXT:    [[B_SHIFT:%.*]] = add i32 [[B_GW_FR]], 5121; CHECK-NEXT:    [[COND_2:%.*]] = icmp ult i32 [[B_SHIFT]], 10122; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_2]]123; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]124; CHECK-NEXT:    br label [[LOOP:%.*]]125; CHECK:       loop:126; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B_GW_FR]], 10127; CHECK-NEXT:    br i1 [[COND_1]], label [[OK:%.*]], label [[LEAVE_LOOPEXIT:%.*]]128; CHECK:       ok:129; CHECK-NEXT:    br i1 [[CND:%.*]], label [[LOOP]], label [[LEAVE_LOOPEXIT]]130; CHECK:       leave.loopexit:131; CHECK-NEXT:    br label [[LEAVE:%.*]]132; CHECK:       leave:133; CHECK-NEXT:    ret void134;135entry:136  %cond_0 = icmp ult i32 %a, 10137  %b.shift = add nuw nsw i32 %b, 5138  %cond_2 = icmp ult i32 %b.shift, 10139  call void (i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]140  br label %loop141 142loop:143  %cond_1 = icmp ult i32 %b, 10144  br i1 %cond_1, label %ok, label %leave.loopexit145ok:146  call void (i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"() ]147  br i1 %cnd, label %loop, label %leave.loopexit148 149leave.loopexit:150  br label %leave151 152leave:153  ret void154}155 156declare ptr @fake_personality_function()157 158define void @case_with_invoke(i1 %c, i1 %gc) personality ptr @fake_personality_function {159; CHECK-LABEL: @case_with_invoke(160; CHECK-NEXT:  entry:161; CHECK-NEXT:    br i1 [[C:%.*]], label [[NORMAL:%.*]], label [[INVOK:%.*]]162; CHECK:       invok:163; CHECK-NEXT:    [[INVOKE_RESULT:%.*]] = invoke i1 @dummy()164; CHECK-NEXT:    to label [[NORMAL]] unwind label [[EXCEPTION:%.*]]165; CHECK:       normal:166; CHECK-NEXT:    [[PHI_C:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ [[INVOKE_RESULT]], [[INVOK]] ]167; CHECK-NEXT:    [[PHI_C_GW_FR:%.*]] = freeze i1 [[PHI_C]]168; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[GC:%.*]], [[PHI_C_GW_FR]]169; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]170; CHECK-NEXT:    ret void171; CHECK:       exception:172; CHECK-NEXT:    [[LANDING_PAD:%.*]] = landingpad { ptr, i32 }173; CHECK-NEXT:    cleanup174; CHECK-NEXT:    ret void175;176entry:177  br i1 %c, label %normal, label %invok178 179invok:180  %invoke.result = invoke i1 @dummy() to label %normal unwind label %exception181 182normal:183  %phi.c = phi i1 [true, %entry], [%invoke.result, %invok]184  call void (i1, ...) @llvm.experimental.guard(i1 %gc) [ "deopt"() ]185  call void (i1, ...) @llvm.experimental.guard(i1 %phi.c) [ "deopt"() ]186  ret void187 188exception:189  %landing_pad = landingpad { ptr, i32 } cleanup190  ret void191}192 193define void @case_with_invoke_in_latch(i1 %c, i1 %gc) personality ptr @fake_personality_function {194; CHECK-LABEL: @case_with_invoke_in_latch(195; CHECK-NEXT:  entry:196; CHECK-NEXT:    br label [[HEADER:%.*]]197; CHECK:       header:198; CHECK-NEXT:    [[PHI_C:%.*]] = phi i1 [ false, [[ENTRY:%.*]] ], [ [[INVOKE_RESULT:%.*]], [[HEADER]] ]199; CHECK-NEXT:    [[PHI_C_GW_FR:%.*]] = freeze i1 [[PHI_C]]200; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[GC:%.*]], [[PHI_C_GW_FR]]201; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]202; CHECK-NEXT:    [[INVOKE_RESULT]] = invoke i1 @dummy()203; CHECK-NEXT:    to label [[HEADER]] unwind label [[EXCEPTION:%.*]]204; CHECK:       exception:205; CHECK-NEXT:    [[LANDING_PAD:%.*]] = landingpad { ptr, i32 }206; CHECK-NEXT:    cleanup207; CHECK-NEXT:    ret void208;209entry:210  br label %header211 212header:213  %phi.c = phi i1 [false, %entry], [%invoke.result, %header]214  call void (i1, ...) @llvm.experimental.guard(i1 %gc) [ "deopt"() ]215  call void (i1, ...) @llvm.experimental.guard(i1 %phi.c) [ "deopt"() ]216  %invoke.result = invoke i1 @dummy() to label %header unwind label %exception217 218exception:219  %landing_pad = landingpad { ptr, i32 } cleanup220  ret void221}222 223declare void @dummy_vec(<4 x i1> %arg)224 225define void @freeze_poison(i1 %c, i1 %g) {226; CHECK-LABEL: @freeze_poison(227; CHECK-NEXT:  entry:228; CHECK-NEXT:    [[DOTGW_FR:%.*]] = freeze i1 poison229; CHECK-NEXT:    br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]230; CHECK:       left:231; CHECK-NEXT:    call void @dummy_vec(<4 x i1> <i1 false, i1 poison, i1 poison, i1 poison>)232; CHECK-NEXT:    ret void233; CHECK:       right:234; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[G:%.*]], [[DOTGW_FR]]235; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]236; CHECK-NEXT:    ret void237;238entry:239  br i1 %c, label %left, label %right240 241left:242  call void @dummy_vec(<4 x i1> <i1 0, i1 poison, i1 poison, i1 poison>)243  ret void244 245 246right:247  call void (i1, ...) @llvm.experimental.guard(i1 %g) [ "deopt"() ]248  call void (i1, ...) @llvm.experimental.guard(i1 poison) [ "deopt"() ]249  ret void250 251}252 253