190 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 52; RUN: opt < %s -passes=gvn -enable-load-pre -S | FileCheck %s --check-prefixes=CHECK,MDEP3; RUN: opt < %s -passes='gvn<memoryssa>' -enable-load-pre -S | FileCheck %s --check-prefixes=CHECK,MSSA4target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"5 6declare void @llvm.experimental.guard(i1, ...)7 8; This is a motivating example on why we prohibit hoisting through guards.9; In the bottom block, we check that the index is within bounds and only access10; the element in this case and deoptimize otherwise. If we hoist the load to a11; place above the guard, it will may lead to out-of-bound array access.12define i32 @test_motivation(ptr %p, ptr %q, i1 %C, i32 %index, i32 %len) {13; CHECK-LABEL: define i32 @test_motivation(14; CHECK-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i1 [[C:%.*]], i32 [[INDEX:%.*]], i32 [[LEN:%.*]]) {15; CHECK-NEXT: [[BLOCK1:.*:]]16; CHECK-NEXT: [[EL1:%.*]] = getelementptr inbounds i32, ptr [[Q]], i32 [[INDEX]]17; CHECK-NEXT: [[EL2:%.*]] = getelementptr inbounds i32, ptr [[P]], i32 [[INDEX]]18; CHECK-NEXT: br i1 [[C]], label %[[BLOCK2:.*]], label %[[BLOCK3:.*]]19; CHECK: [[BLOCK2]]:20; CHECK-NEXT: br label %[[BLOCK4:.*]]21; CHECK: [[BLOCK3]]:22; CHECK-NEXT: store i32 0, ptr [[EL1]], align 423; CHECK-NEXT: br label %[[BLOCK4]]24; CHECK: [[BLOCK4]]:25; CHECK-NEXT: [[P2:%.*]] = phi ptr [ [[EL2]], %[[BLOCK3]] ], [ [[EL1]], %[[BLOCK2]] ]26; CHECK-NEXT: [[COND1:%.*]] = icmp sge i32 [[INDEX]], 027; CHECK-NEXT: [[COND2:%.*]] = icmp slt i32 [[INDEX]], [[LEN]]28; CHECK-NEXT: [[IN_BOUNDS:%.*]] = and i1 [[COND1]], [[COND2]]29; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[IN_BOUNDS]]) [ "deopt"() ]30; CHECK-NEXT: [[PRE:%.*]] = load i32, ptr [[P2]], align 431; CHECK-NEXT: ret i32 [[PRE]]32;33block1:34 %el1 = getelementptr inbounds i32, ptr %q, i32 %index35 %el2 = getelementptr inbounds i32, ptr %p, i32 %index36 br i1 %C, label %block2, label %block337 38block2:39 40 br label %block441 42block3:43 store i32 0, ptr %el144 br label %block445 46block4:47 48 49 %P2 = phi ptr [%el2, %block3], [%el1, %block2]50 %cond1 = icmp sge i32 %index, 051 %cond2 = icmp slt i32 %index, %len52 %in.bounds = and i1 %cond1, %cond253 call void (i1, ...) @llvm.experimental.guard(i1 %in.bounds) [ "deopt"() ]54 %PRE = load i32, ptr %P255 ret i32 %PRE56}57 58; Guard in load's block that is above the load should prohibit the PRE.59define i32 @test_guard_01(ptr %p, ptr %q, i1 %C, i1 %G) {60; CHECK-LABEL: define i32 @test_guard_01(61; CHECK-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i1 [[C:%.*]], i1 [[G:%.*]]) {62; CHECK-NEXT: [[BLOCK1:.*:]]63; CHECK-NEXT: br i1 [[C]], label %[[BLOCK2:.*]], label %[[BLOCK3:.*]]64; CHECK: [[BLOCK2]]:65; CHECK-NEXT: br label %[[BLOCK4:.*]]66; CHECK: [[BLOCK3]]:67; CHECK-NEXT: store i32 0, ptr [[P]], align 468; CHECK-NEXT: br label %[[BLOCK4]]69; CHECK: [[BLOCK4]]:70; CHECK-NEXT: [[P2:%.*]] = phi ptr [ [[P]], %[[BLOCK3]] ], [ [[Q]], %[[BLOCK2]] ]71; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[G]]) [ "deopt"() ]72; CHECK-NEXT: [[PRE:%.*]] = load i32, ptr [[P2]], align 473; CHECK-NEXT: ret i32 [[PRE]]74;75block1:76 br i1 %C, label %block2, label %block377 78block2:79 80 81 br label %block482 83block3:84 store i32 0, ptr %p85 br label %block486 87block4:88 89 90 %P2 = phi ptr [%p, %block3], [%q, %block2]91 call void (i1, ...) @llvm.experimental.guard(i1 %G) [ "deopt"() ]92 %PRE = load i32, ptr %P293 ret i32 %PRE94}95 96; Guard in load's block that is below the load should not prohibit the PRE.97define i32 @test_guard_02(ptr %p, ptr %q, i1 %C, i1 %G) {98; MDEP-LABEL: define i32 @test_guard_02(99; MDEP-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i1 [[C:%.*]], i1 [[G:%.*]]) {100; MDEP-NEXT: [[BLOCK1:.*:]]101; MDEP-NEXT: br i1 [[C]], label %[[BLOCK2:.*]], label %[[BLOCK3:.*]]102; MDEP: [[BLOCK2]]:103; MDEP-NEXT: [[PRE_PRE:%.*]] = load i32, ptr [[Q]], align 4104; MDEP-NEXT: br label %[[BLOCK4:.*]]105; MDEP: [[BLOCK3]]:106; MDEP-NEXT: store i32 0, ptr [[P]], align 4107; MDEP-NEXT: br label %[[BLOCK4]]108; MDEP: [[BLOCK4]]:109; MDEP-NEXT: [[PRE:%.*]] = phi i32 [ 0, %[[BLOCK3]] ], [ [[PRE_PRE]], %[[BLOCK2]] ]110; MDEP-NEXT: [[P2:%.*]] = phi ptr [ [[P]], %[[BLOCK3]] ], [ [[Q]], %[[BLOCK2]] ]111; MDEP-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[G]]) [ "deopt"() ]112; MDEP-NEXT: ret i32 [[PRE]]113;114; MSSA-LABEL: define i32 @test_guard_02(115; MSSA-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i1 [[C:%.*]], i1 [[G:%.*]]) {116; MSSA-NEXT: [[BLOCK1:.*:]]117; MSSA-NEXT: br i1 [[C]], label %[[BLOCK2:.*]], label %[[BLOCK3:.*]]118; MSSA: [[BLOCK2]]:119; MSSA-NEXT: br label %[[BLOCK4:.*]]120; MSSA: [[BLOCK3]]:121; MSSA-NEXT: store i32 0, ptr [[P]], align 4122; MSSA-NEXT: br label %[[BLOCK4]]123; MSSA: [[BLOCK4]]:124; MSSA-NEXT: [[P2:%.*]] = phi ptr [ [[P]], %[[BLOCK3]] ], [ [[Q]], %[[BLOCK2]] ]125; MSSA-NEXT: [[PRE:%.*]] = load i32, ptr [[P2]], align 4126; MSSA-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[G]]) [ "deopt"() ]127; MSSA-NEXT: ret i32 [[PRE]]128;129block1:130 br i1 %C, label %block2, label %block3131 132block2:133 134 135 br label %block4136 137block3:138 store i32 0, ptr %p139 br label %block4140 141block4:142 143 144 %P2 = phi ptr [%p, %block3], [%q, %block2]145 %PRE = load i32, ptr %P2146 call void (i1, ...) @llvm.experimental.guard(i1 %G) [ "deopt"() ]147 ret i32 %PRE148}149 150; Guard above the load's block should prevent PRE from hoisting through it.151define i32 @test_guard_03(ptr %p, ptr %q, i1 %C, i1 %G) {152; CHECK-LABEL: define i32 @test_guard_03(153; CHECK-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i1 [[C:%.*]], i1 [[G:%.*]]) {154; CHECK-NEXT: [[BLOCK1:.*:]]155; CHECK-NEXT: br i1 [[C]], label %[[BLOCK2:.*]], label %[[BLOCK3:.*]]156; CHECK: [[BLOCK2]]:157; CHECK-NEXT: br label %[[BLOCK4:.*]]158; CHECK: [[BLOCK3]]:159; CHECK-NEXT: store i32 0, ptr [[P]], align 4160; CHECK-NEXT: br label %[[BLOCK4]]161; CHECK: [[BLOCK4]]:162; CHECK-NEXT: [[P2:%.*]] = phi ptr [ [[P]], %[[BLOCK3]] ], [ [[Q]], %[[BLOCK2]] ]163; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[G]]) [ "deopt"() ]164; CHECK-NEXT: [[PRE:%.*]] = load i32, ptr [[P2]], align 4165; CHECK-NEXT: ret i32 [[PRE]]166;167block1:168 br i1 %C, label %block2, label %block3169 170block2:171 172 173 br label %block4174 175block3:176 store i32 0, ptr %p177 br label %block4178 179block4:180 181 182 %P2 = phi ptr [%p, %block3], [%q, %block2]183 call void (i1, ...) @llvm.experimental.guard(i1 %G) [ "deopt"() ]184 br label %block5185 186block5:187 %PRE = load i32, ptr %P2188 ret i32 %PRE189}190