| ; RUN: opt < %s -S -early-cse | FileCheck %s |
| ; RUN: opt < %s -S -basicaa -early-cse-memssa | FileCheck %s |
| |
| ; CHECK-LABEL: @test12( |
| define i32 @test12(i1 %B, i32* %P1, i32* %P2) { |
| %load0 = load i32, i32* %P1 |
| %1 = load atomic i32, i32* %P2 seq_cst, align 4 |
| %load1 = load i32, i32* %P1 |
| %sel = select i1 %B, i32 %load0, i32 %load1 |
| ret i32 %sel |
| ; CHECK: load i32, i32* %P1 |
| ; CHECK: load i32, i32* %P1 |
| } |
| |
| ; CHECK-LABEL: @test13( |
| ; atomic to non-atomic forwarding is legal |
| define i32 @test13(i1 %B, i32* %P1) { |
| %a = load atomic i32, i32* %P1 seq_cst, align 4 |
| %b = load i32, i32* %P1 |
| %res = sub i32 %a, %b |
| ret i32 %res |
| ; CHECK: load atomic i32, i32* %P1 |
| ; CHECK: ret i32 0 |
| } |
| |
| ; CHECK-LABEL: @test14( |
| ; atomic to unordered atomic forwarding is legal |
| define i32 @test14(i1 %B, i32* %P1) { |
| %a = load atomic i32, i32* %P1 seq_cst, align 4 |
| %b = load atomic i32, i32* %P1 unordered, align 4 |
| %res = sub i32 %a, %b |
| ret i32 %res |
| ; CHECK: load atomic i32, i32* %P1 seq_cst |
| ; CHECK-NEXT: ret i32 0 |
| } |
| |
| ; CHECK-LABEL: @test15( |
| ; implementation restriction: can't forward to stonger |
| ; than unordered |
| define i32 @test15(i1 %B, i32* %P1, i32* %P2) { |
| %a = load atomic i32, i32* %P1 seq_cst, align 4 |
| %b = load atomic i32, i32* %P1 seq_cst, align 4 |
| %res = sub i32 %a, %b |
| ret i32 %res |
| ; CHECK: load atomic i32, i32* %P1 |
| ; CHECK: load atomic i32, i32* %P1 |
| } |
| |
| ; CHECK-LABEL: @test16( |
| ; forwarding non-atomic to atomic is wrong! (However, |
| ; it would be legal to use the later value in place of the |
| ; former in this particular example. We just don't |
| ; do that right now.) |
| define i32 @test16(i1 %B, i32* %P1, i32* %P2) { |
| %a = load i32, i32* %P1, align 4 |
| %b = load atomic i32, i32* %P1 unordered, align 4 |
| %res = sub i32 %a, %b |
| ret i32 %res |
| ; CHECK: load i32, i32* %P1 |
| ; CHECK: load atomic i32, i32* %P1 |
| } |
| |
| ; Can't DSE across a full fence |
| define void @fence_seq_cst_store(i1 %B, i32* %P1, i32* %P2) { |
| ; CHECK-LABEL: @fence_seq_cst_store |
| ; CHECK: store |
| ; CHECK: store atomic |
| ; CHECK: store |
| store i32 0, i32* %P1, align 4 |
| store atomic i32 0, i32* %P2 seq_cst, align 4 |
| store i32 0, i32* %P1, align 4 |
| ret void |
| } |
| |
| ; Can't DSE across a full fence |
| define void @fence_seq_cst(i1 %B, i32* %P1, i32* %P2) { |
| ; CHECK-LABEL: @fence_seq_cst |
| ; CHECK: store |
| ; CHECK: fence seq_cst |
| ; CHECK: store |
| store i32 0, i32* %P1, align 4 |
| fence seq_cst |
| store i32 0, i32* %P1, align 4 |
| ret void |
| } |
| |
| ; Can't DSE across a full fence |
| define void @fence_asm_sideeffect(i1 %B, i32* %P1, i32* %P2) { |
| ; CHECK-LABEL: @fence_asm_sideeffect |
| ; CHECK: store |
| ; CHECK: call void asm sideeffect |
| ; CHECK: store |
| store i32 0, i32* %P1, align 4 |
| call void asm sideeffect "", ""() |
| store i32 0, i32* %P1, align 4 |
| ret void |
| } |
| |
| ; Can't DSE across a full fence |
| define void @fence_asm_memory(i1 %B, i32* %P1, i32* %P2) { |
| ; CHECK-LABEL: @fence_asm_memory |
| ; CHECK: store |
| ; CHECK: call void asm |
| ; CHECK: store |
| store i32 0, i32* %P1, align 4 |
| call void asm "", "~{memory}"() |
| store i32 0, i32* %P1, align 4 |
| ret void |
| } |
| |
| ; Can't remove a volatile load |
| define i32 @volatile_load(i1 %B, i32* %P1, i32* %P2) { |
| %a = load i32, i32* %P1, align 4 |
| %b = load volatile i32, i32* %P1, align 4 |
| %res = sub i32 %a, %b |
| ret i32 %res |
| ; CHECK-LABEL: @volatile_load |
| ; CHECK: load i32, i32* %P1 |
| ; CHECK: load volatile i32, i32* %P1 |
| } |
| |
| ; Can't remove redundant volatile loads |
| define i32 @redundant_volatile_load(i1 %B, i32* %P1, i32* %P2) { |
| %a = load volatile i32, i32* %P1, align 4 |
| %b = load volatile i32, i32* %P1, align 4 |
| %res = sub i32 %a, %b |
| ret i32 %res |
| ; CHECK-LABEL: @redundant_volatile_load |
| ; CHECK: load volatile i32, i32* %P1 |
| ; CHECK: load volatile i32, i32* %P1 |
| ; CHECK: sub |
| } |
| |
| ; Can't DSE a volatile store |
| define void @volatile_store(i1 %B, i32* %P1, i32* %P2) { |
| ; CHECK-LABEL: @volatile_store |
| ; CHECK: store volatile |
| ; CHECK: store |
| store volatile i32 0, i32* %P1, align 4 |
| store i32 3, i32* %P1, align 4 |
| ret void |
| } |
| |
| ; Can't DSE a redundant volatile store |
| define void @redundant_volatile_store(i1 %B, i32* %P1, i32* %P2) { |
| ; CHECK-LABEL: @redundant_volatile_store |
| ; CHECK: store volatile |
| ; CHECK: store volatile |
| store volatile i32 0, i32* %P1, align 4 |
| store volatile i32 0, i32* %P1, align 4 |
| ret void |
| } |
| |
| ; Can value forward from volatiles |
| define i32 @test20(i1 %B, i32* %P1, i32* %P2) { |
| %a = load volatile i32, i32* %P1, align 4 |
| %b = load i32, i32* %P1, align 4 |
| %res = sub i32 %a, %b |
| ret i32 %res |
| ; CHECK-LABEL: @test20 |
| ; CHECK: load volatile i32, i32* %P1 |
| ; CHECK: ret i32 0 |
| } |
| |
| ; Can DSE a non-volatile store in favor of a volatile one |
| ; currently a missed optimization |
| define void @test21(i1 %B, i32* %P1, i32* %P2) { |
| ; CHECK-LABEL: @test21 |
| ; CHECK: store |
| ; CHECK: store volatile |
| store i32 0, i32* %P1, align 4 |
| store volatile i32 3, i32* %P1, align 4 |
| ret void |
| } |
| |
| ; Can DSE a normal store in favor of a unordered one |
| define void @test22(i1 %B, i32* %P1, i32* %P2) { |
| ; CHECK-LABEL: @test22 |
| ; CHECK-NEXT: store atomic |
| store i32 0, i32* %P1, align 4 |
| store atomic i32 3, i32* %P1 unordered, align 4 |
| ret void |
| } |
| |
| ; Can also DSE a unordered store in favor of a normal one |
| define void @test23(i1 %B, i32* %P1, i32* %P2) { |
| ; CHECK-LABEL: @test23 |
| ; CHECK-NEXT: store i32 0 |
| store atomic i32 3, i32* %P1 unordered, align 4 |
| store i32 0, i32* %P1, align 4 |
| ret void |
| } |
| |
| ; As an implementation limitation, can't remove ordered stores |
| ; Note that we could remove the earlier store if we could |
| ; represent the required ordering. |
| define void @test24(i1 %B, i32* %P1, i32* %P2) { |
| ; CHECK-LABEL: @test24 |
| ; CHECK-NEXT: store atomic |
| ; CHECK-NEXT: store i32 0 |
| store atomic i32 3, i32* %P1 release, align 4 |
| store i32 0, i32* %P1, align 4 |
| ret void |
| } |
| |
| ; Can't remove volatile stores - each is independently observable and |
| ; the count of such stores is an observable program side effect. |
| define void @test25(i1 %B, i32* %P1, i32* %P2) { |
| ; CHECK-LABEL: @test25 |
| ; CHECK-NEXT: store volatile |
| ; CHECK-NEXT: store volatile |
| store volatile i32 3, i32* %P1, align 4 |
| store volatile i32 0, i32* %P1, align 4 |
| ret void |
| } |
| |
| ; Can DSE a unordered store in favor of a unordered one |
| define void @test26(i1 %B, i32* %P1, i32* %P2) { |
| ; CHECK-LABEL: @test26 |
| ; CHECK-NEXT: store atomic i32 3, i32* %P1 unordered, align 4 |
| ; CHECK-NEXT: ret |
| store atomic i32 0, i32* %P1 unordered, align 4 |
| store atomic i32 3, i32* %P1 unordered, align 4 |
| ret void |
| } |
| |
| ; Can DSE a unordered store in favor of a ordered one, |
| ; but current don't due to implementation limits |
| define void @test27(i1 %B, i32* %P1, i32* %P2) { |
| ; CHECK-LABEL: @test27 |
| ; CHECK-NEXT: store atomic i32 0, i32* %P1 unordered, align 4 |
| ; CHECK-NEXT: store atomic i32 3, i32* %P1 release, align 4 |
| ; CHECK-NEXT: ret |
| store atomic i32 0, i32* %P1 unordered, align 4 |
| store atomic i32 3, i32* %P1 release, align 4 |
| ret void |
| } |
| |
| ; Can DSE an unordered atomic store in favor of an |
| ; ordered one, but current don't due to implementation limits |
| define void @test28(i1 %B, i32* %P1, i32* %P2) { |
| ; CHECK-LABEL: @test28 |
| ; CHECK-NEXT: store atomic i32 0, i32* %P1 unordered, align 4 |
| ; CHECK-NEXT: store atomic i32 3, i32* %P1 release, align 4 |
| ; CHECK-NEXT: ret |
| store atomic i32 0, i32* %P1 unordered, align 4 |
| store atomic i32 3, i32* %P1 release, align 4 |
| ret void |
| } |
| |
| ; As an implementation limitation, can't remove ordered stores |
| ; see also: @test24 |
| define void @test29(i1 %B, i32* %P1, i32* %P2) { |
| ; CHECK-LABEL: @test29 |
| ; CHECK-NEXT: store atomic |
| ; CHECK-NEXT: store atomic |
| store atomic i32 3, i32* %P1 release, align 4 |
| store atomic i32 0, i32* %P1 unordered, align 4 |
| ret void |
| } |