1; RUN: opt < %s -S -early-cse | FileCheck %s 2; RUN: opt < %s -S -basicaa -early-cse-memssa | FileCheck %s 3 4; CHECK-LABEL: @test12( 5define i32 @test12(i1 %B, i32* %P1, i32* %P2) { 6 %load0 = load i32, i32* %P1 7 %1 = load atomic i32, i32* %P2 seq_cst, align 4 8 %load1 = load i32, i32* %P1 9 %sel = select i1 %B, i32 %load0, i32 %load1 10 ret i32 %sel 11 ; CHECK: load i32, i32* %P1 12 ; CHECK: load i32, i32* %P1 13} 14 15; CHECK-LABEL: @test13( 16; atomic to non-atomic forwarding is legal 17define i32 @test13(i1 %B, i32* %P1) { 18 %a = load atomic i32, i32* %P1 seq_cst, align 4 19 %b = load i32, i32* %P1 20 %res = sub i32 %a, %b 21 ret i32 %res 22 ; CHECK: load atomic i32, i32* %P1 23 ; CHECK: ret i32 0 24} 25 26; CHECK-LABEL: @test14( 27; atomic to unordered atomic forwarding is legal 28define i32 @test14(i1 %B, i32* %P1) { 29 %a = load atomic i32, i32* %P1 seq_cst, align 4 30 %b = load atomic i32, i32* %P1 unordered, align 4 31 %res = sub i32 %a, %b 32 ret i32 %res 33 ; CHECK: load atomic i32, i32* %P1 seq_cst 34 ; CHECK-NEXT: ret i32 0 35} 36 37; CHECK-LABEL: @test15( 38; implementation restriction: can't forward to stonger 39; than unordered 40define i32 @test15(i1 %B, i32* %P1, i32* %P2) { 41 %a = load atomic i32, i32* %P1 seq_cst, align 4 42 %b = load atomic i32, i32* %P1 seq_cst, align 4 43 %res = sub i32 %a, %b 44 ret i32 %res 45 ; CHECK: load atomic i32, i32* %P1 46 ; CHECK: load atomic i32, i32* %P1 47} 48 49; CHECK-LABEL: @test16( 50; forwarding non-atomic to atomic is wrong! (However, 51; it would be legal to use the later value in place of the 52; former in this particular example. We just don't 53; do that right now.) 54define i32 @test16(i1 %B, i32* %P1, i32* %P2) { 55 %a = load i32, i32* %P1, align 4 56 %b = load atomic i32, i32* %P1 unordered, align 4 57 %res = sub i32 %a, %b 58 ret i32 %res 59 ; CHECK: load i32, i32* %P1 60 ; CHECK: load atomic i32, i32* %P1 61} 62 63; Can't DSE across a full fence 64define void @fence_seq_cst_store(i1 %B, i32* %P1, i32* %P2) { 65; CHECK-LABEL: @fence_seq_cst_store 66; CHECK: store 67; CHECK: store atomic 68; CHECK: store 69 store i32 0, i32* %P1, align 4 70 store atomic i32 0, i32* %P2 seq_cst, align 4 71 store i32 0, i32* %P1, align 4 72 ret void 73} 74 75; Can't DSE across a full fence 76define void @fence_seq_cst(i1 %B, i32* %P1, i32* %P2) { 77; CHECK-LABEL: @fence_seq_cst 78; CHECK: store 79; CHECK: fence seq_cst 80; CHECK: store 81 store i32 0, i32* %P1, align 4 82 fence seq_cst 83 store i32 0, i32* %P1, align 4 84 ret void 85} 86 87; Can't DSE across a full fence 88define void @fence_asm_sideeffect(i1 %B, i32* %P1, i32* %P2) { 89; CHECK-LABEL: @fence_asm_sideeffect 90; CHECK: store 91; CHECK: call void asm sideeffect 92; CHECK: store 93 store i32 0, i32* %P1, align 4 94 call void asm sideeffect "", ""() 95 store i32 0, i32* %P1, align 4 96 ret void 97} 98 99; Can't DSE across a full fence 100define void @fence_asm_memory(i1 %B, i32* %P1, i32* %P2) { 101; CHECK-LABEL: @fence_asm_memory 102; CHECK: store 103; CHECK: call void asm 104; CHECK: store 105 store i32 0, i32* %P1, align 4 106 call void asm "", "~{memory}"() 107 store i32 0, i32* %P1, align 4 108 ret void 109} 110 111; Can't remove a volatile load 112define i32 @volatile_load(i1 %B, i32* %P1, i32* %P2) { 113 %a = load i32, i32* %P1, align 4 114 %b = load volatile i32, i32* %P1, align 4 115 %res = sub i32 %a, %b 116 ret i32 %res 117 ; CHECK-LABEL: @volatile_load 118 ; CHECK: load i32, i32* %P1 119 ; CHECK: load volatile i32, i32* %P1 120} 121 122; Can't remove redundant volatile loads 123define i32 @redundant_volatile_load(i1 %B, i32* %P1, i32* %P2) { 124 %a = load volatile i32, i32* %P1, align 4 125 %b = load volatile i32, i32* %P1, align 4 126 %res = sub i32 %a, %b 127 ret i32 %res 128 ; CHECK-LABEL: @redundant_volatile_load 129 ; CHECK: load volatile i32, i32* %P1 130 ; CHECK: load volatile i32, i32* %P1 131 ; CHECK: sub 132} 133 134; Can't DSE a volatile store 135define void @volatile_store(i1 %B, i32* %P1, i32* %P2) { 136; CHECK-LABEL: @volatile_store 137; CHECK: store volatile 138; CHECK: store 139 store volatile i32 0, i32* %P1, align 4 140 store i32 3, i32* %P1, align 4 141 ret void 142} 143 144; Can't DSE a redundant volatile store 145define void @redundant_volatile_store(i1 %B, i32* %P1, i32* %P2) { 146; CHECK-LABEL: @redundant_volatile_store 147; CHECK: store volatile 148; CHECK: store volatile 149 store volatile i32 0, i32* %P1, align 4 150 store volatile i32 0, i32* %P1, align 4 151 ret void 152} 153 154; Can value forward from volatiles 155define i32 @test20(i1 %B, i32* %P1, i32* %P2) { 156 %a = load volatile i32, i32* %P1, align 4 157 %b = load i32, i32* %P1, align 4 158 %res = sub i32 %a, %b 159 ret i32 %res 160 ; CHECK-LABEL: @test20 161 ; CHECK: load volatile i32, i32* %P1 162 ; CHECK: ret i32 0 163} 164 165; Can DSE a non-volatile store in favor of a volatile one 166; currently a missed optimization 167define void @test21(i1 %B, i32* %P1, i32* %P2) { 168; CHECK-LABEL: @test21 169; CHECK: store 170; CHECK: store volatile 171 store i32 0, i32* %P1, align 4 172 store volatile i32 3, i32* %P1, align 4 173 ret void 174} 175 176; Can DSE a normal store in favor of a unordered one 177define void @test22(i1 %B, i32* %P1, i32* %P2) { 178; CHECK-LABEL: @test22 179; CHECK-NEXT: store atomic 180 store i32 0, i32* %P1, align 4 181 store atomic i32 3, i32* %P1 unordered, align 4 182 ret void 183} 184 185; Can also DSE a unordered store in favor of a normal one 186define void @test23(i1 %B, i32* %P1, i32* %P2) { 187; CHECK-LABEL: @test23 188; CHECK-NEXT: store i32 0 189 store atomic i32 3, i32* %P1 unordered, align 4 190 store i32 0, i32* %P1, align 4 191 ret void 192} 193 194; As an implementation limitation, can't remove ordered stores 195; Note that we could remove the earlier store if we could 196; represent the required ordering. 197define void @test24(i1 %B, i32* %P1, i32* %P2) { 198; CHECK-LABEL: @test24 199; CHECK-NEXT: store atomic 200; CHECK-NEXT: store i32 0 201 store atomic i32 3, i32* %P1 release, align 4 202 store i32 0, i32* %P1, align 4 203 ret void 204} 205 206; Can't remove volatile stores - each is independently observable and 207; the count of such stores is an observable program side effect. 208define void @test25(i1 %B, i32* %P1, i32* %P2) { 209; CHECK-LABEL: @test25 210; CHECK-NEXT: store volatile 211; CHECK-NEXT: store volatile 212 store volatile i32 3, i32* %P1, align 4 213 store volatile i32 0, i32* %P1, align 4 214 ret void 215} 216 217; Can DSE a unordered store in favor of a unordered one 218define void @test26(i1 %B, i32* %P1, i32* %P2) { 219; CHECK-LABEL: @test26 220; CHECK-NEXT: store atomic i32 3, i32* %P1 unordered, align 4 221; CHECK-NEXT: ret 222 store atomic i32 0, i32* %P1 unordered, align 4 223 store atomic i32 3, i32* %P1 unordered, align 4 224 ret void 225} 226 227; Can DSE a unordered store in favor of a ordered one, 228; but current don't due to implementation limits 229define void @test27(i1 %B, i32* %P1, i32* %P2) { 230; CHECK-LABEL: @test27 231; CHECK-NEXT: store atomic i32 0, i32* %P1 unordered, align 4 232; CHECK-NEXT: store atomic i32 3, i32* %P1 release, align 4 233; CHECK-NEXT: ret 234 store atomic i32 0, i32* %P1 unordered, align 4 235 store atomic i32 3, i32* %P1 release, align 4 236 ret void 237} 238 239; Can DSE an unordered atomic store in favor of an 240; ordered one, but current don't due to implementation limits 241define void @test28(i1 %B, i32* %P1, i32* %P2) { 242; CHECK-LABEL: @test28 243; CHECK-NEXT: store atomic i32 0, i32* %P1 unordered, align 4 244; CHECK-NEXT: store atomic i32 3, i32* %P1 release, align 4 245; CHECK-NEXT: ret 246 store atomic i32 0, i32* %P1 unordered, align 4 247 store atomic i32 3, i32* %P1 release, align 4 248 ret void 249} 250 251; As an implementation limitation, can't remove ordered stores 252; see also: @test24 253define void @test29(i1 %B, i32* %P1, i32* %P2) { 254; CHECK-LABEL: @test29 255; CHECK-NEXT: store atomic 256; CHECK-NEXT: store atomic 257 store atomic i32 3, i32* %P1 release, align 4 258 store atomic i32 0, i32* %P1 unordered, align 4 259 ret void 260} 261