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