1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -passes=dse -S %s | FileCheck %s 3 4; Both the stores in %then and %else can be eliminated by translating %p 5; through the phi. 6define void @memoryphi_translate_1(i1 %c) { 7; CHECK-LABEL: @memoryphi_translate_1( 8; CHECK-NEXT: entry: 9; CHECK-NEXT: [[A_1:%.*]] = alloca i8, align 1 10; CHECK-NEXT: [[A_2:%.*]] = alloca i8, align 1 11; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] 12; CHECK: then: 13; CHECK-NEXT: br label [[END:%.*]] 14; CHECK: else: 15; CHECK-NEXT: br label [[END]] 16; CHECK: end: 17; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[A_1]], [[THEN]] ], [ [[A_2]], [[ELSE]] ] 18; CHECK-NEXT: store i8 10, ptr [[P]], align 1 19; CHECK-NEXT: ret void 20; 21entry: 22 %a.1 = alloca i8 23 %a.2 = alloca i8 24 br i1 %c, label %then, label %else 25 26then: 27 store i8 0, ptr %a.1 28 br label %end 29 30else: 31 store i8 9, ptr %a.2 32 br label %end 33 34end: 35 %p = phi ptr [ %a.1, %then ], [ %a.2, %else ] 36 store i8 10, ptr %p 37 ret void 38} 39 40; The store in %else can be eliminated by translating %p through the phi. 41; The store in %then cannot be eliminated, because %a.1 is read before the final 42; store. 43define i8 @memoryphi_translate_2(i1 %c) { 44; CHECK-LABEL: @memoryphi_translate_2( 45; CHECK-NEXT: entry: 46; CHECK-NEXT: [[A_1:%.*]] = alloca i8, align 1 47; CHECK-NEXT: [[A_2:%.*]] = alloca i8, align 1 48; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] 49; CHECK: then: 50; CHECK-NEXT: store i8 0, ptr [[A_1]], align 1 51; CHECK-NEXT: br label [[END:%.*]] 52; CHECK: else: 53; CHECK-NEXT: br label [[END]] 54; CHECK: end: 55; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[A_1]], [[THEN]] ], [ [[A_2]], [[ELSE]] ] 56; CHECK-NEXT: [[L:%.*]] = load i8, ptr [[A_1]], align 1 57; CHECK-NEXT: store i8 10, ptr [[P]], align 1 58; CHECK-NEXT: ret i8 [[L]] 59; 60entry: 61 %a.1 = alloca i8 62 %a.2 = alloca i8 63 br i1 %c, label %then, label %else 64 65then: 66 store i8 0, ptr %a.1 67 br label %end 68 69else: 70 store i8 9, ptr %a.2 71 br label %end 72 73end: 74 %p = phi ptr [ %a.1, %then ], [ %a.2, %else ] 75 %l = load i8, ptr %a.1 76 store i8 10, ptr %p 77 ret i8 %l 78} 79 80; The store in %then can be eliminated by translating %p through the phi. 81; The store in %else cannot be eliminated, because %a.2 is read before the final 82; store. 83define i8 @memoryphi_translate_3(i1 %c) { 84; CHECK-LABEL: @memoryphi_translate_3( 85; CHECK-NEXT: entry: 86; CHECK-NEXT: [[A_1:%.*]] = alloca i8, align 1 87; CHECK-NEXT: [[A_2:%.*]] = alloca i8, align 1 88; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] 89; CHECK: then: 90; CHECK-NEXT: br label [[END:%.*]] 91; CHECK: else: 92; CHECK-NEXT: store i8 9, ptr [[A_2]], align 1 93; CHECK-NEXT: br label [[END]] 94; CHECK: end: 95; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[A_1]], [[THEN]] ], [ [[A_2]], [[ELSE]] ] 96; CHECK-NEXT: [[L:%.*]] = load i8, ptr [[A_2]], align 1 97; CHECK-NEXT: store i8 10, ptr [[P]], align 1 98; CHECK-NEXT: ret i8 [[L]] 99; 100entry: 101 %a.1 = alloca i8 102 %a.2 = alloca i8 103 br i1 %c, label %then, label %else 104 105then: 106 store i8 0, ptr %a.1 107 br label %end 108 109else: 110 store i8 9, ptr %a.2 111 br label %end 112 113end: 114 %p = phi ptr [ %a.1, %then ], [ %a.2, %else ] 115 %l = load i8, ptr %a.2 116 store i8 10, ptr %p 117 ret i8 %l 118} 119 120; No stores can be eliminated, because there's a load from the phi. 121define i8 @memoryphi_translate_4(i1 %c) { 122; CHECK-LABEL: @memoryphi_translate_4( 123; CHECK-NEXT: entry: 124; CHECK-NEXT: [[A_1:%.*]] = alloca i8, align 1 125; CHECK-NEXT: [[A_2:%.*]] = alloca i8, align 1 126; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] 127; CHECK: then: 128; CHECK-NEXT: store i8 0, ptr [[A_1]], align 1 129; CHECK-NEXT: br label [[END:%.*]] 130; CHECK: else: 131; CHECK-NEXT: store i8 9, ptr [[A_2]], align 1 132; CHECK-NEXT: br label [[END]] 133; CHECK: end: 134; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[A_1]], [[THEN]] ], [ [[A_2]], [[ELSE]] ] 135; CHECK-NEXT: [[L:%.*]] = load i8, ptr [[P]], align 1 136; CHECK-NEXT: store i8 10, ptr [[P]], align 1 137; CHECK-NEXT: ret i8 [[L]] 138; 139entry: 140 %a.1 = alloca i8 141 %a.2 = alloca i8 142 br i1 %c, label %then, label %else 143 144then: 145 store i8 0, ptr %a.1 146 br label %end 147 148else: 149 store i8 9, ptr %a.2 150 br label %end 151 152end: 153 %p = phi ptr [ %a.1, %then ], [ %a.2, %else ] 154 %l = load i8, ptr %p 155 store i8 10, ptr %p 156 ret i8 %l 157} 158 159; TODO: The store in %entry can be removed by translating %p through the phi. 160define void @memoryphi_translate_5(i1 %cond) { 161; CHECK-LABEL: @memoryphi_translate_5( 162; CHECK-NEXT: entry: 163; CHECK-NEXT: [[A:%.*]] = alloca i8, align 1 164; CHECK-NEXT: [[B:%.*]] = alloca i8, align 1 165; CHECK-NEXT: store i8 0, ptr [[A]], align 1 166; CHECK-NEXT: br i1 [[COND:%.*]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] 167; CHECK: cond.true: 168; CHECK-NEXT: br label [[COND_END]] 169; CHECK: cond.end: 170; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[B]], [[COND_TRUE]] ], [ [[A]], [[ENTRY:%.*]] ] 171; CHECK-NEXT: store i8 0, ptr [[P]], align 1 172; CHECK-NEXT: call void @use(ptr [[P]]) 173; CHECK-NEXT: ret void 174; 175entry: 176 %a = alloca i8 177 %b = alloca i8 178 %c = alloca i8 179 store i8 0, ptr %a 180 br i1 %cond, label %cond.true, label %cond.end 181 182cond.true: 183 store i8 0, ptr %c 184 br label %cond.end 185 186cond.end: 187 %p = phi ptr [ %b, %cond.true ], [ %a, %entry ] 188 store i8 0, ptr %p 189 call void @use(ptr %p) 190 ret void 191} 192 193; TODO: The store in %entry can be removed by translating %p through the phi. 194; Same as @memoryphi_translate_5, but without stores in %cond.true, so there 195; is no MemoryPhi. 196define void @translate_without_memoryphi_1(i1 %cond) { 197; CHECK-LABEL: @translate_without_memoryphi_1( 198; CHECK-NEXT: entry: 199; CHECK-NEXT: [[A:%.*]] = alloca i8, align 1 200; CHECK-NEXT: [[B:%.*]] = alloca i8, align 1 201; CHECK-NEXT: store i8 0, ptr [[A]], align 1 202; CHECK-NEXT: br i1 [[COND:%.*]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] 203; CHECK: cond.true: 204; CHECK-NEXT: br label [[COND_END]] 205; CHECK: cond.end: 206; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[B]], [[COND_TRUE]] ], [ [[A]], [[ENTRY:%.*]] ] 207; CHECK-NEXT: store i8 0, ptr [[P]], align 1 208; CHECK-NEXT: call void @use(ptr [[P]]) 209; CHECK-NEXT: ret void 210; 211entry: 212 %a = alloca i8 213 %b = alloca i8 214 store i8 0, ptr %a 215 br i1 %cond, label %cond.true, label %cond.end 216 217cond.true: 218 br label %cond.end 219 220cond.end: 221 %p = phi ptr [ %b, %cond.true ], [ %a, %entry ] 222 store i8 0, ptr %p 223 call void @use(ptr %p) 224 ret void 225} 226 227; In the test, translating through the phi results in a null address. Make sure 228; this does not cause a crash. 229define void @test_trans_null(i1 %c, ptr %ptr) { 230; CHECK-LABEL: @test_trans_null( 231; CHECK-NEXT: entry: 232; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] 233; CHECK: then: 234; CHECK-NEXT: br label [[EXIT:%.*]] 235; CHECK: else: 236; CHECK-NEXT: call void @fn() 237; CHECK-NEXT: [[GEP_1:%.*]] = getelementptr inbounds i16, ptr undef, i64 2 238; CHECK-NEXT: store i16 8, ptr [[GEP_1]], align 2 239; CHECK-NEXT: br label [[EXIT]] 240; CHECK: exit: 241; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[PTR:%.*]], [[THEN]] ], [ undef, [[ELSE]] ] 242; CHECK-NEXT: [[GEP_2:%.*]] = getelementptr inbounds i16, ptr [[P]], i64 2 243; CHECK-NEXT: store i16 8, ptr [[GEP_2]], align 2 244; CHECK-NEXT: ret void 245; 246entry: 247 br i1 %c, label %then, label %else 248 249then: 250 br label %exit 251 252else: 253 call void @fn() 254 %gep.1 = getelementptr inbounds i16, ptr undef, i64 2 255 store i16 8, ptr %gep.1, align 2 256 br label %exit 257 258exit: 259 %p = phi ptr [ %ptr, %then ], [ undef, %else ] 260 %gep.2 = getelementptr inbounds i16, ptr %p, i64 2 261 store i16 8, ptr %gep.2, align 2 262 ret void 263} 264 265 266declare void @use(ptr) 267declare void @fn() 268