1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -simplifycfg-max-small-block-size=6 -S < %s | FileCheck %s 3; RUN: opt -passes=simplify-cfg -simplifycfg-max-small-block-size=6 -S < %s | FileCheck %s 4 5target datalayout = "e-p:64:64-p5:32:32-A5" 6 7declare void @llvm.assume(i1) 8declare i1 @llvm.type.test(i8*, metadata) nounwind readnone 9 10define void @test_01(i1 %c, i64* align 1 %ptr) local_unnamed_addr #0 { 11; CHECK-LABEL: @test_01( 12; CHECK-NEXT: br i1 [[C:%.*]], label [[TRUE2_CRITEDGE:%.*]], label [[FALSE1:%.*]] 13; CHECK: false1: 14; CHECK-NEXT: store volatile i64 1, i64* [[PTR:%.*]], align 4 15; CHECK-NEXT: [[PTRINT:%.*]] = ptrtoint i64* [[PTR]] to i64 16; CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 7 17; CHECK-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0 18; CHECK-NEXT: tail call void @llvm.assume(i1 [[MASKCOND]]) 19; CHECK-NEXT: store volatile i64 0, i64* [[PTR]], align 8 20; CHECK-NEXT: store volatile i64 3, i64* [[PTR]], align 8 21; CHECK-NEXT: ret void 22; CHECK: true2.critedge: 23; CHECK-NEXT: [[PTRINT_C:%.*]] = ptrtoint i64* [[PTR]] to i64 24; CHECK-NEXT: [[MASKEDPTR_C:%.*]] = and i64 [[PTRINT_C]], 7 25; CHECK-NEXT: [[MASKCOND_C:%.*]] = icmp eq i64 [[MASKEDPTR_C]], 0 26; CHECK-NEXT: tail call void @llvm.assume(i1 [[MASKCOND_C]]) 27; CHECK-NEXT: store volatile i64 0, i64* [[PTR]], align 8 28; CHECK-NEXT: store volatile i64 2, i64* [[PTR]], align 8 29; CHECK-NEXT: ret void 30; 31 br i1 %c, label %true1, label %false1 32 33true1: ; preds = %false1, %0 34 %ptrint = ptrtoint i64* %ptr to i64 35 %maskedptr = and i64 %ptrint, 7 36 %maskcond = icmp eq i64 %maskedptr, 0 37 tail call void @llvm.assume(i1 %maskcond) 38 store volatile i64 0, i64* %ptr, align 8 39 br i1 %c, label %true2, label %false2 40 41false1: ; preds = %0 42 store volatile i64 1, i64* %ptr, align 4 43 br label %true1 44 45true2: ; preds = %true1 46 store volatile i64 2, i64* %ptr, align 8 47 ret void 48 49false2: ; preds = %true1 50 store volatile i64 3, i64* %ptr, align 8 51 ret void 52} 53 54; Corner case: the block has max possible size for which we still do PRE. 55define void @test_02(i1 %c, i64* align 1 %ptr) local_unnamed_addr #0 { 56; CHECK-LABEL: @test_02( 57; CHECK-NEXT: br i1 [[C:%.*]], label [[TRUE2_CRITEDGE:%.*]], label [[FALSE1:%.*]] 58; CHECK: false1: 59; CHECK-NEXT: store volatile i64 1, i64* [[PTR:%.*]], align 4 60; CHECK-NEXT: [[PTRINT:%.*]] = ptrtoint i64* [[PTR]] to i64 61; CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 7 62; CHECK-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0 63; CHECK-NEXT: tail call void @llvm.assume(i1 [[MASKCOND]]) 64; CHECK-NEXT: store volatile i64 0, i64* [[PTR]], align 8 65; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 66; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 67; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 68; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 69; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 70; CHECK-NEXT: store volatile i64 3, i64* [[PTR]], align 8 71; CHECK-NEXT: ret void 72; CHECK: true2.critedge: 73; CHECK-NEXT: [[PTRINT_C:%.*]] = ptrtoint i64* [[PTR]] to i64 74; CHECK-NEXT: [[MASKEDPTR_C:%.*]] = and i64 [[PTRINT_C]], 7 75; CHECK-NEXT: [[MASKCOND_C:%.*]] = icmp eq i64 [[MASKEDPTR_C]], 0 76; CHECK-NEXT: tail call void @llvm.assume(i1 [[MASKCOND_C]]) 77; CHECK-NEXT: store volatile i64 0, i64* [[PTR]], align 8 78; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 79; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 80; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 81; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 82; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 83; CHECK-NEXT: store volatile i64 2, i64* [[PTR]], align 8 84; CHECK-NEXT: ret void 85; 86 br i1 %c, label %true1, label %false1 87 88true1: ; preds = %false1, %0 89 %ptrint = ptrtoint i64* %ptr to i64 90 %maskedptr = and i64 %ptrint, 7 91 %maskcond = icmp eq i64 %maskedptr, 0 92 tail call void @llvm.assume(i1 %maskcond) 93 store volatile i64 0, i64* %ptr, align 8 94 store volatile i64 -1, i64* %ptr, align 8 95 store volatile i64 -1, i64* %ptr, align 8 96 store volatile i64 -1, i64* %ptr, align 8 97 store volatile i64 -1, i64* %ptr, align 8 98 store volatile i64 -1, i64* %ptr, align 8 99 br i1 %c, label %true2, label %false2 100 101false1: ; preds = %0 102 store volatile i64 1, i64* %ptr, align 4 103 br label %true1 104 105true2: ; preds = %true1 106 store volatile i64 2, i64* %ptr, align 8 107 ret void 108 109false2: ; preds = %true1 110 store volatile i64 3, i64* %ptr, align 8 111 ret void 112} 113 114; This block is too huge for PRE. 115define void @test_03(i1 %c, i64* align 1 %ptr) local_unnamed_addr #0 { 116; CHECK-LABEL: @test_03( 117; CHECK-NEXT: br i1 [[C:%.*]], label [[TRUE1:%.*]], label [[FALSE1:%.*]] 118; CHECK: true1: 119; CHECK-NEXT: [[PTRINT:%.*]] = ptrtoint i64* [[PTR:%.*]] to i64 120; CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 7 121; CHECK-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0 122; CHECK-NEXT: tail call void @llvm.assume(i1 [[MASKCOND]]) 123; CHECK-NEXT: store volatile i64 0, i64* [[PTR]], align 8 124; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 125; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 126; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 127; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 128; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 129; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 130; CHECK-NEXT: br i1 [[C]], label [[TRUE2:%.*]], label [[FALSE2:%.*]] 131; CHECK: false1: 132; CHECK-NEXT: store volatile i64 1, i64* [[PTR]], align 4 133; CHECK-NEXT: br label [[TRUE1]] 134; CHECK: true2: 135; CHECK-NEXT: store volatile i64 2, i64* [[PTR]], align 8 136; CHECK-NEXT: ret void 137; CHECK: false2: 138; CHECK-NEXT: store volatile i64 3, i64* [[PTR]], align 8 139; CHECK-NEXT: ret void 140; 141 br i1 %c, label %true1, label %false1 142 143true1: ; preds = %false1, %0 144 %ptrint = ptrtoint i64* %ptr to i64 145 %maskedptr = and i64 %ptrint, 7 146 %maskcond = icmp eq i64 %maskedptr, 0 147 tail call void @llvm.assume(i1 %maskcond) 148 store volatile i64 0, i64* %ptr, align 8 149 store volatile i64 -1, i64* %ptr, align 8 150 store volatile i64 -1, i64* %ptr, align 8 151 store volatile i64 -1, i64* %ptr, align 8 152 store volatile i64 -1, i64* %ptr, align 8 153 store volatile i64 -1, i64* %ptr, align 8 154 store volatile i64 -1, i64* %ptr, align 8 155 br i1 %c, label %true2, label %false2 156 157false1: ; preds = %0 158 store volatile i64 1, i64* %ptr, align 4 159 br label %true1 160 161true2: ; preds = %true1 162 store volatile i64 2, i64* %ptr, align 8 163 ret void 164 165false2: ; preds = %true1 166 store volatile i64 3, i64* %ptr, align 8 167 ret void 168} 169 170; Try the max block size for PRE again but with the bitcast/type test/assume 171; sequence used for whole program devirt. 172define void @test_04(i1 %c, i64* align 1 %ptr, [3 x i8*]* %vtable) local_unnamed_addr #0 { 173; CHECK-LABEL: @test_04( 174; CHECK-NEXT: br i1 [[C:%.*]], label [[TRUE2_CRITEDGE:%.*]], label [[FALSE1:%.*]] 175; CHECK: false1: 176; CHECK-NEXT: store volatile i64 1, i64* [[PTR:%.*]], align 4 177; CHECK-NEXT: [[VTABLE:%.*]] = bitcast [3 x i8*]* %vtable to i8* 178; CHECK-NEXT: [[P:%.*]] = call i1 @llvm.type.test(i8* [[VTABLE]], metadata !"foo") 179; CHECK-NEXT: tail call void @llvm.assume(i1 [[P]]) 180; CHECK-NEXT: store volatile i64 0, i64* [[PTR]], align 8 181; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 182; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 183; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 184; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 185; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 186; CHECK-NEXT: store volatile i64 3, i64* [[PTR]], align 8 187; CHECK-NEXT: ret void 188; CHECK: true2.critedge: 189; CHECK-NEXT: [[VTABLE:%.*]] = bitcast [3 x i8*]* %vtable to i8* 190; CHECK-NEXT: [[P:%.*]] = call i1 @llvm.type.test(i8* [[VTABLE]], metadata !"foo") 191; CHECK-NEXT: tail call void @llvm.assume(i1 [[P]]) 192; CHECK-NEXT: store volatile i64 0, i64* [[PTR]], align 8 193; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 194; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 195; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 196; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 197; CHECK-NEXT: store volatile i64 -1, i64* [[PTR]], align 8 198; CHECK-NEXT: store volatile i64 2, i64* [[PTR]], align 8 199; CHECK-NEXT: ret void 200; 201 br i1 %c, label %true1, label %false1 202 203true1: ; preds = %false1, %0 204 %vtablei8 = bitcast [3 x i8*]* %vtable to i8* 205 %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"foo") 206 tail call void @llvm.assume(i1 %p) 207 store volatile i64 0, i64* %ptr, align 8 208 store volatile i64 -1, i64* %ptr, align 8 209 store volatile i64 -1, i64* %ptr, align 8 210 store volatile i64 -1, i64* %ptr, align 8 211 store volatile i64 -1, i64* %ptr, align 8 212 store volatile i64 -1, i64* %ptr, align 8 213 br i1 %c, label %true2, label %false2 214 215false1: ; preds = %0 216 store volatile i64 1, i64* %ptr, align 4 217 br label %true1 218 219true2: ; preds = %true1 220 store volatile i64 2, i64* %ptr, align 8 221 ret void 222 223false2: ; preds = %true1 224 store volatile i64 3, i64* %ptr, align 8 225 ret void 226} 227