214 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; Tests that check our handling of volatile instructions encountered3; when scanning for dependencies4; RUN: opt -passes=gvn -enable-split-backedge-in-load-pre -S < %s | FileCheck %s5 6; Check that we can bypass a volatile load when searching7; for dependencies of a non-volatile load8define i32 @test1(ptr nocapture %p, ptr nocapture %q) {9; CHECK-LABEL: @test1(10; CHECK-NEXT: entry:11; CHECK-NEXT: [[TMP0:%.*]] = load volatile i32, ptr [[Q:%.*]], align 412; CHECK-NEXT: ret i32 013;14entry:15 %x = load i32, ptr %p16 load volatile i32, ptr %q17 %y = load i32, ptr %p18 %add = sub i32 %y, %x19 ret i32 %add20}21 22; We can not value forward if the query instruction is23; volatile, this would be (in effect) removing the volatile load24define i32 @test2(ptr nocapture %p, ptr nocapture %q) {25; CHECK-LABEL: @test2(26; CHECK-NEXT: entry:27; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[P:%.*]], align 428; CHECK-NEXT: [[Y:%.*]] = load volatile i32, ptr [[P]], align 429; CHECK-NEXT: [[ADD:%.*]] = sub i32 [[Y]], [[X]]30; CHECK-NEXT: ret i32 [[ADD]]31;32entry:33 %x = load i32, ptr %p34 %y = load volatile i32, ptr %p35 %add = sub i32 %y, %x36 ret i32 %add37}38 39; If the query instruction is itself volatile, we *cannot*40; reorder it even if p and q are noalias41define i32 @test3(ptr noalias nocapture %p, ptr noalias nocapture %q) {42; CHECK-LABEL: @test3(43; CHECK-NEXT: entry:44; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[P:%.*]], align 445; CHECK-NEXT: [[TMP0:%.*]] = load volatile i32, ptr [[Q:%.*]], align 446; CHECK-NEXT: [[Y:%.*]] = load volatile i32, ptr [[P]], align 447; CHECK-NEXT: [[ADD:%.*]] = sub i32 [[Y]], [[X]]48; CHECK-NEXT: ret i32 [[ADD]]49;50entry:51 %x = load i32, ptr %p52 load volatile i32, ptr %q53 %y = load volatile i32, ptr %p54 %add = sub i32 %y, %x55 ret i32 %add56}57 58; If an encountered instruction is both volatile and ordered,59; we need to use the strictest ordering of either. In this60; case, the ordering prevents forwarding.61define i32 @test4(ptr noalias nocapture %p, ptr noalias nocapture %q) {62; CHECK-LABEL: @test4(63; CHECK-NEXT: entry:64; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[P:%.*]], align 465; CHECK-NEXT: [[TMP0:%.*]] = load atomic volatile i32, ptr [[Q:%.*]] seq_cst, align 466; CHECK-NEXT: [[Y:%.*]] = load atomic i32, ptr [[P]] seq_cst, align 467; CHECK-NEXT: [[ADD:%.*]] = sub i32 [[Y]], [[X]]68; CHECK-NEXT: ret i32 [[ADD]]69;70entry:71 %x = load i32, ptr %p72 load atomic volatile i32, ptr %q seq_cst, align 473 %y = load atomic i32, ptr %p seq_cst, align 474 %add = sub i32 %y, %x75 ret i32 %add76}77 78; Value forwarding from a volatile load is perfectly legal79define i32 @test5(ptr nocapture %p, ptr nocapture %q) {80; CHECK-LABEL: @test5(81; CHECK-NEXT: entry:82; CHECK-NEXT: [[X:%.*]] = load volatile i32, ptr [[P:%.*]], align 483; CHECK-NEXT: ret i32 084;85entry:86 %x = load volatile i32, ptr %p87 %y = load i32, ptr %p88 %add = sub i32 %y, %x89 ret i32 %add90}91 92; Does cross block redundancy elimination work with volatiles?93define i32 @test6(ptr noalias nocapture %p, ptr noalias nocapture %q) {94; CHECK-LABEL: @test6(95; CHECK-NEXT: entry:96; CHECK-NEXT: [[Y1:%.*]] = load i32, ptr [[P:%.*]], align 497; CHECK-NEXT: call void @use(i32 [[Y1]])98; CHECK-NEXT: br label [[HEADER:%.*]]99; CHECK: header:100; CHECK-NEXT: [[X:%.*]] = load volatile i32, ptr [[Q:%.*]], align 4101; CHECK-NEXT: [[ADD:%.*]] = sub i32 [[Y1]], [[X]]102; CHECK-NEXT: [[CND:%.*]] = icmp eq i32 [[ADD]], 0103; CHECK-NEXT: br i1 [[CND]], label [[EXIT:%.*]], label [[HEADER]]104; CHECK: exit:105; CHECK-NEXT: ret i32 0106;107entry:108 %y1 = load i32, ptr %p109 call void @use(i32 %y1)110 br label %header111header:112 %x = load volatile i32, ptr %q113 %y = load i32, ptr %p114 %add = sub i32 %y, %x115 %cnd = icmp eq i32 %add, 0116 br i1 %cnd, label %exit, label %header117exit:118 ret i32 %add119}120 121; Does cross block PRE work with volatiles?122define i32 @test7(i1 %c, ptr noalias nocapture %p, ptr noalias nocapture %q) {123; CHECK-LABEL: @test7(124; CHECK-NEXT: entry:125; CHECK-NEXT: [[Y_PRE:%.*]] = load i32, ptr [[P:%.*]], align 4126; CHECK-NEXT: br i1 [[C:%.*]], label [[HEADER:%.*]], label [[SKIP:%.*]]127; CHECK: skip:128; CHECK-NEXT: call void @use(i32 [[Y_PRE]])129; CHECK-NEXT: br label [[HEADER]]130; CHECK: header:131; CHECK-NEXT: [[X:%.*]] = load volatile i32, ptr [[Q:%.*]], align 4132; CHECK-NEXT: [[ADD:%.*]] = sub i32 [[Y_PRE]], [[X]]133; CHECK-NEXT: [[CND:%.*]] = icmp eq i32 [[ADD]], 0134; CHECK-NEXT: br i1 [[CND]], label [[EXIT:%.*]], label [[HEADER]]135; CHECK: exit:136; CHECK-NEXT: ret i32 0137;138entry:139 br i1 %c, label %header, label %skip140skip:141 %y1 = load i32, ptr %p142 call void @use(i32 %y1)143 br label %header144header:145 %x = load volatile i32, ptr %q146 %y = load i32, ptr %p147 %add = sub i32 %y, %x148 %cnd = icmp eq i32 %add, 0149 br i1 %cnd, label %exit, label %header150exit:151 ret i32 %add152}153 154; Another volatile PRE case - two paths through a loop155; load in preheader, one path read only, one not156define i32 @test8(i1 %b, i1 %c, ptr noalias %p, ptr noalias %q) {157; CHECK-LABEL: @test8(158; CHECK-NEXT: entry:159; CHECK-NEXT: [[Y1:%.*]] = load i32, ptr [[P:%.*]], align 4160; CHECK-NEXT: call void @use(i32 [[Y1]])161; CHECK-NEXT: br label [[HEADER:%.*]]162; CHECK: header:163; CHECK-NEXT: [[Y:%.*]] = phi i32 [ [[Y_PRE:%.*]], [[SKIP_HEADER_CRIT_EDGE:%.*]] ], [ [[Y]], [[HEADER]] ], [ [[Y1]], [[ENTRY:%.*]] ]164; CHECK-NEXT: [[X:%.*]] = load volatile i32, ptr [[Q:%.*]], align 4165; CHECK-NEXT: call void @use(i32 [[Y]])166; CHECK-NEXT: br i1 [[B:%.*]], label [[SKIP:%.*]], label [[HEADER]]167; CHECK: skip:168; CHECK-NEXT: call void @clobber(ptr [[P]], ptr [[Q]])169; CHECK-NEXT: br i1 [[C:%.*]], label [[SKIP_HEADER_CRIT_EDGE]], label [[EXIT:%.*]]170; CHECK: skip.header_crit_edge:171; CHECK-NEXT: [[Y_PRE]] = load i32, ptr [[P]], align 4172; CHECK-NEXT: br label [[HEADER]]173; CHECK: exit:174; CHECK-NEXT: [[ADD:%.*]] = sub i32 [[Y]], [[X]]175; CHECK-NEXT: ret i32 [[ADD]]176;177entry:178 %y1 = load i32, ptr %p179 call void @use(i32 %y1)180 br label %header181header:182 %x = load volatile i32, ptr %q183 %y = load i32, ptr %p184 call void @use(i32 %y)185 br i1 %b, label %skip, label %header186skip:187 ; escaping the arguments is explicitly required since we marked188 ; them noalias189 call void @clobber(ptr %p, ptr %q)190 br i1 %c, label %header, label %exit191exit:192 %add = sub i32 %y, %x193 ret i32 %add194}195 196; This test checks that we don't optimize away instructions that are197; simplified by SimplifyInstruction(), but are not trivially dead.198 199define i32 @test9(ptr %V) {200; CHECK-LABEL: @test9(201; CHECK-NEXT: entry:202; CHECK-NEXT: [[LOAD:%.*]] = call i32 undef()203; CHECK-NEXT: ret i32 poison204;205entry:206 %load = call i32 undef()207 ret i32 %load208}209 210declare void @use(i32) readonly211declare void @clobber(ptr %p, ptr %q)212 213!0 = !{ i32 0, i32 1 }214