brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.9 KiB · 96a8fc3 Raw
265 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt -S -passes='early-cse' -earlycse-debug-hash < %s | FileCheck %s --check-prefixes=CHECK,NO_ASSUME3; RUN: opt -S -passes='early-cse<memssa>' < %s | FileCheck %s --check-prefixes=CHECK,NO_ASSUME4; RUN: opt -S -passes='early-cse<memssa>' --enable-knowledge-retention < %s | FileCheck %s --check-prefixes=CHECK,USE_ASSUME5 6declare void @clobber_and_use(i32)7declare void @clobber_and_combine(i32, i32)8 9define void @f_0(ptr %ptr) {10; NO_ASSUME-LABEL: @f_0(11; NO_ASSUME-NEXT:    [[VAL0:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !invariant.load !012; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])13; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])14; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])15; NO_ASSUME-NEXT:    ret void16;17; USE_ASSUME-LABEL: @f_0(18; USE_ASSUME-NEXT:    [[VAL0:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !invariant.load !019; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])20; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[PTR]], i64 4), "nonnull"(ptr [[PTR]]), "align"(ptr [[PTR]], i64 4) ]21; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])22; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])23; USE_ASSUME-NEXT:    ret void24;25 26  %val0 = load i32, ptr %ptr, !invariant.load !{}27  call void @clobber_and_use(i32 %val0)28  %val1 = load i32, ptr %ptr, !invariant.load !{}29  call void @clobber_and_use(i32 %val1)30  %val2 = load i32, ptr %ptr, !invariant.load !{}31  call void @clobber_and_use(i32 %val2)32  ret void33}34 35define void @f_1(ptr %ptr) {36; We can forward invariant loads to non-invariant loads.37; NO_ASSUME-LABEL: @f_1(38; NO_ASSUME-NEXT:    [[VAL0:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !invariant.load !039; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])40; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])41; NO_ASSUME-NEXT:    ret void42;43; USE_ASSUME-LABEL: @f_1(44; USE_ASSUME-NEXT:    [[VAL0:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !invariant.load !045; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])46; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[PTR]], i64 4), "nonnull"(ptr [[PTR]]), "align"(ptr [[PTR]], i64 4) ]47; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])48; USE_ASSUME-NEXT:    ret void49;50 51  %val0 = load i32, ptr %ptr, !invariant.load !{}52  call void @clobber_and_use(i32 %val0)53  %val1 = load i32, ptr %ptr54  call void @clobber_and_use(i32 %val1)55  ret void56}57 58define void @f_2(ptr %ptr) {59; We can forward a non-invariant load into an invariant load.60; NO_ASSUME-LABEL: @f_2(61; NO_ASSUME-NEXT:    [[VAL0:%.*]] = load i32, ptr [[PTR:%.*]], align 462; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])63; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])64; NO_ASSUME-NEXT:    ret void65;66; USE_ASSUME-LABEL: @f_2(67; USE_ASSUME-NEXT:    [[VAL0:%.*]] = load i32, ptr [[PTR:%.*]], align 468; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])69; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[PTR]], i64 4), "nonnull"(ptr [[PTR]]), "align"(ptr [[PTR]], i64 4) ]70; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])71; USE_ASSUME-NEXT:    ret void72;73 74  %val0 = load i32, ptr %ptr75  call void @clobber_and_use(i32 %val0)76  %val1 = load i32, ptr %ptr, !invariant.load !{}77  call void @clobber_and_use(i32 %val1)78  ret void79}80 81define void @f_3(i1 %cond, ptr %ptr) {82; NO_ASSUME-LABEL: @f_3(83; NO_ASSUME-NEXT:    [[VAL0:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !invariant.load !084; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])85; NO_ASSUME-NEXT:    br i1 [[COND:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]86; NO_ASSUME:       left:87; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])88; NO_ASSUME-NEXT:    ret void89; NO_ASSUME:       right:90; NO_ASSUME-NEXT:    ret void91;92; USE_ASSUME-LABEL: @f_3(93; USE_ASSUME-NEXT:    [[VAL0:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !invariant.load !094; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])95; USE_ASSUME-NEXT:    br i1 [[COND:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]96; USE_ASSUME:       left:97; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[PTR]], i64 4), "nonnull"(ptr [[PTR]]), "align"(ptr [[PTR]], i64 4) ]98; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])99; USE_ASSUME-NEXT:    ret void100; USE_ASSUME:       right:101; USE_ASSUME-NEXT:    ret void102;103  %val0 = load i32, ptr %ptr, !invariant.load !{}104  call void @clobber_and_use(i32 %val0)105  br i1 %cond, label %left, label %right106 107 108left:109  %val1 = load i32, ptr %ptr110  call void @clobber_and_use(i32 %val1)111  ret void112 113right:114  ret void115}116 117define void @f_4(i1 %cond, ptr %ptr) {118; Negative test -- can't forward %val0 to %va1 because that'll break119; def-dominates-use.120; CHECK-LABEL: @f_4(121; CHECK-NEXT:    br i1 [[COND:%.*]], label [[LEFT:%.*]], label [[MERGE:%.*]]122; CHECK:       left:123; CHECK-NEXT:    [[VAL0:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !invariant.load !0124; CHECK-NEXT:    call void @clobber_and_use(i32 [[VAL0]])125; CHECK-NEXT:    br label [[MERGE]]126; CHECK:       merge:127; CHECK-NEXT:    [[VAL1:%.*]] = load i32, ptr [[PTR]], align 4128; CHECK-NEXT:    call void @clobber_and_use(i32 [[VAL1]])129; CHECK-NEXT:    ret void130;131  br i1 %cond, label %left, label %merge132 133left:134 135  %val0 = load i32, ptr %ptr, !invariant.load !{}136  call void @clobber_and_use(i32 %val0)137  br label %merge138 139merge:140 141  %val1 = load i32, ptr %ptr142  call void @clobber_and_use(i32 %val1)143  ret void144}145 146; By assumption, the call can't change contents of p147; LangRef is a bit unclear about whether the store is reachable, so148; for the moment we chose to be conservative and just assume it's valid149; to restore the same unchanging value.150define void @test_dse1(ptr %p) {151; NO_ASSUME-LABEL: @test_dse1(152; NO_ASSUME-NEXT:    [[V1:%.*]] = load i32, ptr [[P:%.*]], align 4, !invariant.load !0153; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[V1]])154; NO_ASSUME-NEXT:    ret void155;156; USE_ASSUME-LABEL: @test_dse1(157; USE_ASSUME-NEXT:    [[V1:%.*]] = load i32, ptr [[P:%.*]], align 4, !invariant.load !0158; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[V1]])159; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]160; USE_ASSUME-NEXT:    ret void161;162  %v1 = load i32, ptr %p, !invariant.load !{}163  call void @clobber_and_use(i32 %v1)164  store i32 %v1, ptr %p165  ret void166}167 168; Extending @test_dse1, the call can't change the contents of p.invariant.169; Moreover, the contents of p.invariant cannot change from the store to p.170define void @test_dse2(ptr noalias %p, ptr noalias %p.invariant) {171; NO_ASSUME-LABEL: @test_dse2(172; NO_ASSUME-NEXT:    [[V:%.*]] = load i32, ptr [[P:%.*]], align 4173; NO_ASSUME-NEXT:    [[V_INVARIANT:%.*]] = load i32, ptr [[P_INVARIANT:%.*]], align 4, !invariant.load !0174; NO_ASSUME-NEXT:    [[V_COMB:%.*]] = call i32 @clobber_and_combine(i32 [[V]], i32 [[V_INVARIANT]])175; NO_ASSUME-NEXT:    store i32 [[V_COMB]], ptr [[P]], align 4176; NO_ASSUME-NEXT:    ret void177;178; USE_ASSUME-LABEL: @test_dse2(179; USE_ASSUME-NEXT:    [[V:%.*]] = load i32, ptr [[P:%.*]], align 4180; USE_ASSUME-NEXT:    [[V_INVARIANT:%.*]] = load i32, ptr [[P_INVARIANT:%.*]], align 4, !invariant.load !0181; USE_ASSUME-NEXT:    [[V_COMB:%.*]] = call i32 @clobber_and_combine(i32 [[V]], i32 [[V_INVARIANT]])182; USE_ASSUME-NEXT:    store i32 [[V_COMB]], ptr [[P]], align 4183; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P_INVARIANT]], i64 4), "nonnull"(ptr [[P_INVARIANT]]), "align"(ptr [[P_INVARIANT]], i64 4) ]184; USE_ASSUME-NEXT:    ret void185;186  %v = load i32, ptr %p187  %v.invariant = load i32, ptr %p.invariant, !invariant.load !{}188  %v.comb = call i32 @clobber_and_combine(i32 %v, i32 %v.invariant)189  store i32 %v.comb, ptr %p190  store i32 %v.invariant, ptr %p.invariant191  ret void192}193 194; By assumption, v1 must equal v2 (TODO)195define void @test_false_negative_dse2(ptr %p, i32 %v2) {196; CHECK-LABEL: @test_false_negative_dse2(197; CHECK-NEXT:    [[V1:%.*]] = load i32, ptr [[P:%.*]], align 4, !invariant.load !0198; CHECK-NEXT:    call void @clobber_and_use(i32 [[V1]])199; CHECK-NEXT:    store i32 [[V2:%.*]], ptr [[P]], align 4200; CHECK-NEXT:    ret void201;202  %v1 = load i32, ptr %p, !invariant.load !{}203  call void @clobber_and_use(i32 %v1)204  store i32 %v2, ptr %p205  ret void206}207 208; If we remove the load, we still start an invariant scope since209; it lets us remove later loads not explicitly marked invariant210define void @test_scope_start_without_load(ptr %p) {211; NO_ASSUME-LABEL: @test_scope_start_without_load(212; NO_ASSUME-NEXT:    [[V1:%.*]] = load i32, ptr [[P:%.*]], align 4213; NO_ASSUME-NEXT:    [[ADD:%.*]] = add i32 [[V1]], [[V1]]214; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[ADD]])215; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[V1]])216; NO_ASSUME-NEXT:    ret void217;218; USE_ASSUME-LABEL: @test_scope_start_without_load(219; USE_ASSUME-NEXT:    [[V1:%.*]] = load i32, ptr [[P:%.*]], align 4220; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]221; USE_ASSUME-NEXT:    [[ADD:%.*]] = add i32 [[V1]], [[V1]]222; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[ADD]])223; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[V1]])224; USE_ASSUME-NEXT:    ret void225;226  %v1 = load i32, ptr %p227  %v2 = load i32, ptr %p, !invariant.load !{}228  %add = add i32 %v1, %v2229  call void @clobber_and_use(i32 %add)230  %v3 = load i32, ptr %p231  call void @clobber_and_use(i32 %v3)232  ret void233}234 235; If we already have an invariant scope, don't want to start a new one236; with a potentially greater generation.  This hides the earlier invariant237; load238define void @test_scope_restart(ptr %p) {239; NO_ASSUME-LABEL: @test_scope_restart(240; NO_ASSUME-NEXT:    [[V1:%.*]] = load i32, ptr [[P:%.*]], align 4, !invariant.load !0241; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[V1]])242; NO_ASSUME-NEXT:    [[ADD:%.*]] = add i32 [[V1]], [[V1]]243; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[ADD]])244; NO_ASSUME-NEXT:    call void @clobber_and_use(i32 [[V1]])245; NO_ASSUME-NEXT:    ret void246;247; USE_ASSUME-LABEL: @test_scope_restart(248; USE_ASSUME-NEXT:    [[V1:%.*]] = load i32, ptr [[P:%.*]], align 4, !invariant.load !0249; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[V1]])250; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ]251; USE_ASSUME-NEXT:    [[ADD:%.*]] = add i32 [[V1]], [[V1]]252; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[ADD]])253; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[V1]])254; USE_ASSUME-NEXT:    ret void255;256  %v1 = load i32, ptr %p, !invariant.load !{}257  call void @clobber_and_use(i32 %v1)258  %v2 = load i32, ptr %p, !invariant.load !{}259  %add = add i32 %v1, %v2260  call void @clobber_and_use(i32 %add)261  %v3 = load i32, ptr %p262  call void @clobber_and_use(i32 %v3)263  ret void264}265