You've already forked linux-packaging-mono
Imported Upstream version 5.18.0.167
Former-commit-id: 289509151e0fee68a1b591a20c9f109c3c789d3a
This commit is contained in:
parent
e19d552987
commit
b084638f15
@ -1,234 +0,0 @@
|
||||
; RUN: opt < %s -S -mtriple=aarch64-none-linux-gnu -mattr=+neon -early-cse | FileCheck %s
|
||||
; RUN: opt < %s -S -mtriple=aarch64-none-linux-gnu -mattr=+neon -basicaa -early-cse-memssa | FileCheck %s
|
||||
; RUN: opt < %s -S -mtriple=aarch64-none-linux-gnu -mattr=+neon -passes=early-cse | FileCheck %s
|
||||
; RUN: opt < %s -S -mtriple=aarch64-none-linux-gnu -mattr=+neon -aa-pipeline=basic-aa -passes=early-cse-memssa | FileCheck %s
|
||||
|
||||
define <4 x i32> @test_cse(i32* %a, [2 x <4 x i32>] %s.coerce, i32 %n) {
|
||||
entry:
|
||||
; Check that @llvm.aarch64.neon.ld2 is optimized away by Early CSE.
|
||||
; CHECK-LABEL: @test_cse
|
||||
; CHECK-NOT: call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld2.v4i32.p0i8
|
||||
%s.coerce.fca.0.extract = extractvalue [2 x <4 x i32>] %s.coerce, 0
|
||||
%s.coerce.fca.1.extract = extractvalue [2 x <4 x i32>] %s.coerce, 1
|
||||
br label %for.cond
|
||||
|
||||
for.cond: ; preds = %for.body, %entry
|
||||
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
|
||||
%res.0 = phi <4 x i32> [ undef, %entry ], [ %call, %for.body ]
|
||||
%cmp = icmp slt i32 %i.0, %n
|
||||
br i1 %cmp, label %for.body, label %for.end
|
||||
|
||||
for.body: ; preds = %for.cond
|
||||
%0 = bitcast i32* %a to i8*
|
||||
%1 = bitcast <4 x i32> %s.coerce.fca.0.extract to <16 x i8>
|
||||
%2 = bitcast <4 x i32> %s.coerce.fca.1.extract to <16 x i8>
|
||||
%3 = bitcast <16 x i8> %1 to <4 x i32>
|
||||
%4 = bitcast <16 x i8> %2 to <4 x i32>
|
||||
call void @llvm.aarch64.neon.st2.v4i32.p0i8(<4 x i32> %3, <4 x i32> %4, i8* %0)
|
||||
%5 = bitcast i32* %a to i8*
|
||||
%vld2 = call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld2.v4i32.p0i8(i8* %5)
|
||||
%vld2.fca.0.extract = extractvalue { <4 x i32>, <4 x i32> } %vld2, 0
|
||||
%vld2.fca.1.extract = extractvalue { <4 x i32>, <4 x i32> } %vld2, 1
|
||||
%call = call <4 x i32> @vaddq_s32(<4 x i32> %vld2.fca.0.extract, <4 x i32> %vld2.fca.0.extract)
|
||||
%inc = add nsw i32 %i.0, 1
|
||||
br label %for.cond
|
||||
|
||||
for.end: ; preds = %for.cond
|
||||
ret <4 x i32> %res.0
|
||||
}
|
||||
|
||||
define <4 x i32> @test_cse2(i32* %a, [2 x <4 x i32>] %s.coerce, i32 %n) {
|
||||
entry:
|
||||
; Check that the first @llvm.aarch64.neon.st2 is optimized away by Early CSE.
|
||||
; CHECK-LABEL: @test_cse2
|
||||
; CHECK-NOT: call void @llvm.aarch64.neon.st2.v4i32.p0i8(<4 x i32> %3, <4 x i32> %3, i8* %0)
|
||||
; CHECK: call void @llvm.aarch64.neon.st2.v4i32.p0i8(<4 x i32> %s.coerce.fca.0.extract, <4 x i32> %s.coerce.fca.1.extract, i8* %0)
|
||||
%s.coerce.fca.0.extract = extractvalue [2 x <4 x i32>] %s.coerce, 0
|
||||
%s.coerce.fca.1.extract = extractvalue [2 x <4 x i32>] %s.coerce, 1
|
||||
br label %for.cond
|
||||
|
||||
for.cond: ; preds = %for.body, %entry
|
||||
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
|
||||
%res.0 = phi <4 x i32> [ undef, %entry ], [ %call, %for.body ]
|
||||
%cmp = icmp slt i32 %i.0, %n
|
||||
br i1 %cmp, label %for.body, label %for.end
|
||||
|
||||
for.body: ; preds = %for.cond
|
||||
%0 = bitcast i32* %a to i8*
|
||||
%1 = bitcast <4 x i32> %s.coerce.fca.0.extract to <16 x i8>
|
||||
%2 = bitcast <4 x i32> %s.coerce.fca.1.extract to <16 x i8>
|
||||
%3 = bitcast <16 x i8> %1 to <4 x i32>
|
||||
%4 = bitcast <16 x i8> %2 to <4 x i32>
|
||||
call void @llvm.aarch64.neon.st2.v4i32.p0i8(<4 x i32> %3, <4 x i32> %3, i8* %0)
|
||||
call void @llvm.aarch64.neon.st2.v4i32.p0i8(<4 x i32> %3, <4 x i32> %4, i8* %0)
|
||||
%5 = bitcast i32* %a to i8*
|
||||
%vld2 = call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld2.v4i32.p0i8(i8* %5)
|
||||
%vld2.fca.0.extract = extractvalue { <4 x i32>, <4 x i32> } %vld2, 0
|
||||
%vld2.fca.1.extract = extractvalue { <4 x i32>, <4 x i32> } %vld2, 1
|
||||
%call = call <4 x i32> @vaddq_s32(<4 x i32> %vld2.fca.0.extract, <4 x i32> %vld2.fca.0.extract)
|
||||
%inc = add nsw i32 %i.0, 1
|
||||
br label %for.cond
|
||||
|
||||
for.end: ; preds = %for.cond
|
||||
ret <4 x i32> %res.0
|
||||
}
|
||||
|
||||
define <4 x i32> @test_cse3(i32* %a, [2 x <4 x i32>] %s.coerce, i32 %n) #0 {
|
||||
entry:
|
||||
; Check that the first @llvm.aarch64.neon.ld2 is optimized away by Early CSE.
|
||||
; CHECK-LABEL: @test_cse3
|
||||
; CHECK: call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld2.v4i32.p0i8
|
||||
; CHECK-NOT: call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld2.v4i32.p0i8
|
||||
%s.coerce.fca.0.extract = extractvalue [2 x <4 x i32>] %s.coerce, 0
|
||||
%s.coerce.fca.1.extract = extractvalue [2 x <4 x i32>] %s.coerce, 1
|
||||
br label %for.cond
|
||||
|
||||
for.cond: ; preds = %for.body, %entry
|
||||
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
|
||||
%res.0 = phi <4 x i32> [ undef, %entry ], [ %call, %for.body ]
|
||||
%cmp = icmp slt i32 %i.0, %n
|
||||
br i1 %cmp, label %for.body, label %for.end
|
||||
|
||||
for.body: ; preds = %for.cond
|
||||
%0 = bitcast i32* %a to i8*
|
||||
%vld2 = call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld2.v4i32.p0i8(i8* %0)
|
||||
%vld2.fca.0.extract = extractvalue { <4 x i32>, <4 x i32> } %vld2, 0
|
||||
%vld2.fca.1.extract = extractvalue { <4 x i32>, <4 x i32> } %vld2, 1
|
||||
%1 = bitcast i32* %a to i8*
|
||||
%vld22 = call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld2.v4i32.p0i8(i8* %1)
|
||||
%vld22.fca.0.extract = extractvalue { <4 x i32>, <4 x i32> } %vld22, 0
|
||||
%vld22.fca.1.extract = extractvalue { <4 x i32>, <4 x i32> } %vld22, 1
|
||||
%call = call <4 x i32> @vaddq_s32(<4 x i32> %vld2.fca.0.extract, <4 x i32> %vld22.fca.0.extract)
|
||||
%inc = add nsw i32 %i.0, 1
|
||||
br label %for.cond
|
||||
|
||||
for.end: ; preds = %for.cond
|
||||
ret <4 x i32> %res.0
|
||||
}
|
||||
|
||||
|
||||
define <4 x i32> @test_nocse(i32* %a, i32* %b, [2 x <4 x i32>] %s.coerce, i32 %n) {
|
||||
entry:
|
||||
; Check that the store prevents @llvm.aarch64.neon.ld2 from being optimized
|
||||
; away by Early CSE.
|
||||
; CHECK-LABEL: @test_nocse
|
||||
; CHECK: call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld2.v4i32.p0i8
|
||||
%s.coerce.fca.0.extract = extractvalue [2 x <4 x i32>] %s.coerce, 0
|
||||
%s.coerce.fca.1.extract = extractvalue [2 x <4 x i32>] %s.coerce, 1
|
||||
br label %for.cond
|
||||
|
||||
for.cond: ; preds = %for.body, %entry
|
||||
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
|
||||
%res.0 = phi <4 x i32> [ undef, %entry ], [ %call, %for.body ]
|
||||
%cmp = icmp slt i32 %i.0, %n
|
||||
br i1 %cmp, label %for.body, label %for.end
|
||||
|
||||
for.body: ; preds = %for.cond
|
||||
%0 = bitcast i32* %a to i8*
|
||||
%1 = bitcast <4 x i32> %s.coerce.fca.0.extract to <16 x i8>
|
||||
%2 = bitcast <4 x i32> %s.coerce.fca.1.extract to <16 x i8>
|
||||
%3 = bitcast <16 x i8> %1 to <4 x i32>
|
||||
%4 = bitcast <16 x i8> %2 to <4 x i32>
|
||||
call void @llvm.aarch64.neon.st2.v4i32.p0i8(<4 x i32> %3, <4 x i32> %4, i8* %0)
|
||||
store i32 0, i32* %b, align 4
|
||||
%5 = bitcast i32* %a to i8*
|
||||
%vld2 = call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld2.v4i32.p0i8(i8* %5)
|
||||
%vld2.fca.0.extract = extractvalue { <4 x i32>, <4 x i32> } %vld2, 0
|
||||
%vld2.fca.1.extract = extractvalue { <4 x i32>, <4 x i32> } %vld2, 1
|
||||
%call = call <4 x i32> @vaddq_s32(<4 x i32> %vld2.fca.0.extract, <4 x i32> %vld2.fca.0.extract)
|
||||
%inc = add nsw i32 %i.0, 1
|
||||
br label %for.cond
|
||||
|
||||
for.end: ; preds = %for.cond
|
||||
ret <4 x i32> %res.0
|
||||
}
|
||||
|
||||
define <4 x i32> @test_nocse2(i32* %a, [2 x <4 x i32>] %s.coerce, i32 %n) {
|
||||
entry:
|
||||
; Check that @llvm.aarch64.neon.ld3 is not optimized away by Early CSE due
|
||||
; to mismatch between st2 and ld3.
|
||||
; CHECK-LABEL: @test_nocse2
|
||||
; CHECK: call { <4 x i32>, <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld3.v4i32.p0i8
|
||||
%s.coerce.fca.0.extract = extractvalue [2 x <4 x i32>] %s.coerce, 0
|
||||
%s.coerce.fca.1.extract = extractvalue [2 x <4 x i32>] %s.coerce, 1
|
||||
br label %for.cond
|
||||
|
||||
for.cond: ; preds = %for.body, %entry
|
||||
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
|
||||
%res.0 = phi <4 x i32> [ undef, %entry ], [ %call, %for.body ]
|
||||
%cmp = icmp slt i32 %i.0, %n
|
||||
br i1 %cmp, label %for.body, label %for.end
|
||||
|
||||
for.body: ; preds = %for.cond
|
||||
%0 = bitcast i32* %a to i8*
|
||||
%1 = bitcast <4 x i32> %s.coerce.fca.0.extract to <16 x i8>
|
||||
%2 = bitcast <4 x i32> %s.coerce.fca.1.extract to <16 x i8>
|
||||
%3 = bitcast <16 x i8> %1 to <4 x i32>
|
||||
%4 = bitcast <16 x i8> %2 to <4 x i32>
|
||||
call void @llvm.aarch64.neon.st2.v4i32.p0i8(<4 x i32> %3, <4 x i32> %4, i8* %0)
|
||||
%5 = bitcast i32* %a to i8*
|
||||
%vld3 = call { <4 x i32>, <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld3.v4i32.p0i8(i8* %5)
|
||||
%vld3.fca.0.extract = extractvalue { <4 x i32>, <4 x i32>, <4 x i32> } %vld3, 0
|
||||
%vld3.fca.2.extract = extractvalue { <4 x i32>, <4 x i32>, <4 x i32> } %vld3, 2
|
||||
%call = call <4 x i32> @vaddq_s32(<4 x i32> %vld3.fca.0.extract, <4 x i32> %vld3.fca.2.extract)
|
||||
%inc = add nsw i32 %i.0, 1
|
||||
br label %for.cond
|
||||
|
||||
for.end: ; preds = %for.cond
|
||||
ret <4 x i32> %res.0
|
||||
}
|
||||
|
||||
define <4 x i32> @test_nocse3(i32* %a, [2 x <4 x i32>] %s.coerce, i32 %n) {
|
||||
entry:
|
||||
; Check that @llvm.aarch64.neon.st3 is not optimized away by Early CSE due to
|
||||
; mismatch between st2 and st3.
|
||||
; CHECK-LABEL: @test_nocse3
|
||||
; CHECK: call void @llvm.aarch64.neon.st3.v4i32.p0i8
|
||||
; CHECK: call void @llvm.aarch64.neon.st2.v4i32.p0i8
|
||||
%s.coerce.fca.0.extract = extractvalue [2 x <4 x i32>] %s.coerce, 0
|
||||
%s.coerce.fca.1.extract = extractvalue [2 x <4 x i32>] %s.coerce, 1
|
||||
br label %for.cond
|
||||
|
||||
for.cond: ; preds = %for.body, %entry
|
||||
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
|
||||
%res.0 = phi <4 x i32> [ undef, %entry ], [ %call, %for.body ]
|
||||
%cmp = icmp slt i32 %i.0, %n
|
||||
br i1 %cmp, label %for.body, label %for.end
|
||||
|
||||
for.body: ; preds = %for.cond
|
||||
%0 = bitcast i32* %a to i8*
|
||||
%1 = bitcast <4 x i32> %s.coerce.fca.0.extract to <16 x i8>
|
||||
%2 = bitcast <4 x i32> %s.coerce.fca.1.extract to <16 x i8>
|
||||
%3 = bitcast <16 x i8> %1 to <4 x i32>
|
||||
%4 = bitcast <16 x i8> %2 to <4 x i32>
|
||||
call void @llvm.aarch64.neon.st3.v4i32.p0i8(<4 x i32> %4, <4 x i32> %3, <4 x i32> %3, i8* %0)
|
||||
call void @llvm.aarch64.neon.st2.v4i32.p0i8(<4 x i32> %3, <4 x i32> %3, i8* %0)
|
||||
%5 = bitcast i32* %a to i8*
|
||||
%vld3 = call { <4 x i32>, <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld3.v4i32.p0i8(i8* %5)
|
||||
%vld3.fca.0.extract = extractvalue { <4 x i32>, <4 x i32>, <4 x i32> } %vld3, 0
|
||||
%vld3.fca.1.extract = extractvalue { <4 x i32>, <4 x i32>, <4 x i32> } %vld3, 1
|
||||
%call = call <4 x i32> @vaddq_s32(<4 x i32> %vld3.fca.0.extract, <4 x i32> %vld3.fca.0.extract)
|
||||
%inc = add nsw i32 %i.0, 1
|
||||
br label %for.cond
|
||||
|
||||
for.end: ; preds = %for.cond
|
||||
ret <4 x i32> %res.0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @llvm.aarch64.neon.st2.v4i32.p0i8(<4 x i32>, <4 x i32>, i8* nocapture)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @llvm.aarch64.neon.st3.v4i32.p0i8(<4 x i32>, <4 x i32>, <4 x i32>, i8* nocapture)
|
||||
|
||||
; Function Attrs: nounwind readonly
|
||||
declare { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld2.v4i32.p0i8(i8*)
|
||||
|
||||
; Function Attrs: nounwind readonly
|
||||
declare { <4 x i32>, <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld3.v4i32.p0i8(i8*)
|
||||
|
||||
define internal fastcc <4 x i32> @vaddq_s32(<4 x i32> %__p0, <4 x i32> %__p1) {
|
||||
entry:
|
||||
%add = add <4 x i32> %__p0, %__p1
|
||||
ret <4 x i32> %add
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
; RUN: opt -S -early-cse < %s | FileCheck %s
|
||||
; RUN: opt -S -basicaa -early-cse-memssa < %s | FileCheck %s
|
||||
target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"
|
||||
target triple = "aarch64--linux-gnu"
|
||||
|
||||
declare { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld4.v4i16.p0v4i16(<4 x i16>*)
|
||||
|
||||
; Although the store and the ld4 are using the same pointer, the
|
||||
; data can not be reused because ld4 accesses multiple elements.
|
||||
define { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @foo() {
|
||||
entry:
|
||||
store <4 x i16> undef, <4 x i16>* undef, align 8
|
||||
%0 = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld4.v4i16.p0v4i16(<4 x i16>* undef)
|
||||
ret { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } %0
|
||||
; CHECK-LABEL: @foo(
|
||||
; CHECK: store
|
||||
; CHECK-NEXT: call
|
||||
; CHECK-NEXT: ret
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
config.suffixes = ['.ll']
|
||||
|
||||
targets = set(config.root.targets_to_build.split())
|
||||
if not 'AArch64' in targets:
|
||||
config.unsupported = True
|
260
external/llvm/test/Transforms/EarlyCSE/atomics.ll
vendored
260
external/llvm/test/Transforms/EarlyCSE/atomics.ll
vendored
@ -1,260 +0,0 @@
|
||||
; 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
|
||||
}
|
293
external/llvm/test/Transforms/EarlyCSE/basic.ll
vendored
293
external/llvm/test/Transforms/EarlyCSE/basic.ll
vendored
@ -1,293 +0,0 @@
|
||||
; RUN: opt < %s -S -early-cse | FileCheck %s
|
||||
; RUN: opt < %s -S -basicaa -early-cse-memssa | FileCheck %s
|
||||
; RUN: opt < %s -S -passes=early-cse | FileCheck %s
|
||||
|
||||
declare void @llvm.assume(i1) nounwind
|
||||
|
||||
; CHECK-LABEL: @test1(
|
||||
define void @test1(i8 %V, i32 *%P) {
|
||||
%A = bitcast i64 42 to double ;; dead
|
||||
%B = add i32 4, 19 ;; constant folds
|
||||
store i32 %B, i32* %P
|
||||
; CHECK-NEXT: store i32 23, i32* %P
|
||||
|
||||
%C = zext i8 %V to i32
|
||||
%D = zext i8 %V to i32 ;; CSE
|
||||
store volatile i32 %C, i32* %P
|
||||
store volatile i32 %D, i32* %P
|
||||
; CHECK-NEXT: %C = zext i8 %V to i32
|
||||
; CHECK-NEXT: store volatile i32 %C
|
||||
; CHECK-NEXT: store volatile i32 %C
|
||||
|
||||
%E = add i32 %C, %C
|
||||
%F = add i32 %C, %C
|
||||
store volatile i32 %E, i32* %P
|
||||
store volatile i32 %F, i32* %P
|
||||
; CHECK-NEXT: %E = add i32 %C, %C
|
||||
; CHECK-NEXT: store volatile i32 %E
|
||||
; CHECK-NEXT: store volatile i32 %E
|
||||
|
||||
%G = add nuw i32 %C, %C
|
||||
store volatile i32 %G, i32* %P
|
||||
; CHECK-NEXT: store volatile i32 %E
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
;; Simple load value numbering.
|
||||
; CHECK-LABEL: @test2(
|
||||
define i32 @test2(i32 *%P) {
|
||||
%V1 = load i32, i32* %P
|
||||
%V2 = load i32, i32* %P
|
||||
%Diff = sub i32 %V1, %V2
|
||||
ret i32 %Diff
|
||||
; CHECK: ret i32 0
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @test2a(
|
||||
define i32 @test2a(i32 *%P, i1 %b) {
|
||||
%V1 = load i32, i32* %P
|
||||
tail call void @llvm.assume(i1 %b)
|
||||
%V2 = load i32, i32* %P
|
||||
%Diff = sub i32 %V1, %V2
|
||||
ret i32 %Diff
|
||||
; CHECK: ret i32 0
|
||||
}
|
||||
|
||||
;; Cross block load value numbering.
|
||||
; CHECK-LABEL: @test3(
|
||||
define i32 @test3(i32 *%P, i1 %Cond) {
|
||||
%V1 = load i32, i32* %P
|
||||
br i1 %Cond, label %T, label %F
|
||||
T:
|
||||
store i32 4, i32* %P
|
||||
ret i32 42
|
||||
F:
|
||||
%V2 = load i32, i32* %P
|
||||
%Diff = sub i32 %V1, %V2
|
||||
ret i32 %Diff
|
||||
; CHECK: F:
|
||||
; CHECK: ret i32 0
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @test3a(
|
||||
define i32 @test3a(i32 *%P, i1 %Cond, i1 %b) {
|
||||
%V1 = load i32, i32* %P
|
||||
br i1 %Cond, label %T, label %F
|
||||
T:
|
||||
store i32 4, i32* %P
|
||||
ret i32 42
|
||||
F:
|
||||
tail call void @llvm.assume(i1 %b)
|
||||
%V2 = load i32, i32* %P
|
||||
%Diff = sub i32 %V1, %V2
|
||||
ret i32 %Diff
|
||||
; CHECK: F:
|
||||
; CHECK: ret i32 0
|
||||
}
|
||||
|
||||
;; Cross block load value numbering stops when stores happen.
|
||||
; CHECK-LABEL: @test4(
|
||||
define i32 @test4(i32 *%P, i1 %Cond) {
|
||||
%V1 = load i32, i32* %P
|
||||
br i1 %Cond, label %T, label %F
|
||||
T:
|
||||
ret i32 42
|
||||
F:
|
||||
; Clobbers V1
|
||||
store i32 42, i32* %P
|
||||
|
||||
%V2 = load i32, i32* %P
|
||||
%Diff = sub i32 %V1, %V2
|
||||
ret i32 %Diff
|
||||
; CHECK: F:
|
||||
; CHECK: ret i32 %Diff
|
||||
}
|
||||
|
||||
declare i32 @func(i32 *%P) readonly
|
||||
|
||||
;; Simple call CSE'ing.
|
||||
; CHECK-LABEL: @test5(
|
||||
define i32 @test5(i32 *%P) {
|
||||
%V1 = call i32 @func(i32* %P)
|
||||
%V2 = call i32 @func(i32* %P)
|
||||
%Diff = sub i32 %V1, %V2
|
||||
ret i32 %Diff
|
||||
; CHECK: ret i32 0
|
||||
}
|
||||
|
||||
;; Trivial Store->load forwarding
|
||||
; CHECK-LABEL: @test6(
|
||||
define i32 @test6(i32 *%P) {
|
||||
store i32 42, i32* %P
|
||||
%V1 = load i32, i32* %P
|
||||
ret i32 %V1
|
||||
; CHECK: ret i32 42
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @test6a(
|
||||
define i32 @test6a(i32 *%P, i1 %b) {
|
||||
store i32 42, i32* %P
|
||||
tail call void @llvm.assume(i1 %b)
|
||||
%V1 = load i32, i32* %P
|
||||
ret i32 %V1
|
||||
; CHECK: ret i32 42
|
||||
}
|
||||
|
||||
;; Trivial dead store elimination.
|
||||
; CHECK-LABEL: @test7(
|
||||
define void @test7(i32 *%P) {
|
||||
store i32 42, i32* %P
|
||||
store i32 45, i32* %P
|
||||
ret void
|
||||
; CHECK-NEXT: store i32 45
|
||||
; CHECK-NEXT: ret void
|
||||
}
|
||||
|
||||
;; Readnone functions aren't invalidated by stores.
|
||||
; CHECK-LABEL: @test8(
|
||||
define i32 @test8(i32 *%P) {
|
||||
%V1 = call i32 @func(i32* %P) readnone
|
||||
store i32 4, i32* %P
|
||||
%V2 = call i32 @func(i32* %P) readnone
|
||||
%Diff = sub i32 %V1, %V2
|
||||
ret i32 %Diff
|
||||
; CHECK: ret i32 0
|
||||
}
|
||||
|
||||
;; Trivial DSE can't be performed across a readonly call. The call
|
||||
;; can observe the earlier write.
|
||||
; CHECK-LABEL: @test9(
|
||||
define i32 @test9(i32 *%P) {
|
||||
store i32 4, i32* %P
|
||||
%V1 = call i32 @func(i32* %P) readonly
|
||||
store i32 5, i32* %P
|
||||
ret i32 %V1
|
||||
; CHECK: store i32 4, i32* %P
|
||||
; CHECK-NEXT: %V1 = call i32 @func(i32* %P)
|
||||
; CHECK-NEXT: store i32 5, i32* %P
|
||||
; CHECK-NEXT: ret i32 %V1
|
||||
}
|
||||
|
||||
;; Trivial DSE can be performed across a readnone call.
|
||||
; CHECK-LABEL: @test10
|
||||
define i32 @test10(i32 *%P) {
|
||||
store i32 4, i32* %P
|
||||
%V1 = call i32 @func(i32* %P) readnone
|
||||
store i32 5, i32* %P
|
||||
ret i32 %V1
|
||||
; CHECK-NEXT: %V1 = call i32 @func(i32* %P)
|
||||
; CHECK-NEXT: store i32 5, i32* %P
|
||||
; CHECK-NEXT: ret i32 %V1
|
||||
}
|
||||
|
||||
;; Trivial dead store elimination - should work for an entire series of dead stores too.
|
||||
; CHECK-LABEL: @test11(
|
||||
define void @test11(i32 *%P) {
|
||||
store i32 42, i32* %P
|
||||
store i32 43, i32* %P
|
||||
store i32 44, i32* %P
|
||||
store i32 45, i32* %P
|
||||
ret void
|
||||
; CHECK-NEXT: store i32 45
|
||||
; CHECK-NEXT: ret void
|
||||
}
|
||||
|
||||
; 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
|
||||
}
|
||||
|
||||
define void @dse1(i32 *%P) {
|
||||
; CHECK-LABEL: @dse1
|
||||
; CHECK-NOT: store
|
||||
%v = load i32, i32* %P
|
||||
store i32 %v, i32* %P
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @dse2(i32 *%P) {
|
||||
; CHECK-LABEL: @dse2
|
||||
; CHECK-NOT: store
|
||||
%v = load atomic i32, i32* %P seq_cst, align 4
|
||||
store i32 %v, i32* %P
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @dse3(i32 *%P) {
|
||||
; CHECK-LABEL: @dse3
|
||||
; CHECK-NOT: store
|
||||
%v = load atomic i32, i32* %P seq_cst, align 4
|
||||
store atomic i32 %v, i32* %P unordered, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @dse4(i32 *%P, i32 *%Q) {
|
||||
; CHECK-LABEL: @dse4
|
||||
; CHECK-NOT: store
|
||||
; CHECK: ret i32 0
|
||||
%a = load i32, i32* %Q
|
||||
%v = load atomic i32, i32* %P unordered, align 4
|
||||
store atomic i32 %v, i32* %P unordered, align 4
|
||||
%b = load i32, i32* %Q
|
||||
%res = sub i32 %a, %b
|
||||
ret i32 %res
|
||||
}
|
||||
|
||||
; Note that in this example, %P and %Q could in fact be the same
|
||||
; pointer. %v could be different than the value observed for %a
|
||||
; and that's okay because we're using relaxed memory ordering.
|
||||
; The only guarantee we have to provide is that each of the loads
|
||||
; has to observe some value written to that location. We do
|
||||
; not have to respect the order in which those writes were done.
|
||||
define i32 @dse5(i32 *%P, i32 *%Q) {
|
||||
; CHECK-LABEL: @dse5
|
||||
; CHECK-NOT: store
|
||||
; CHECK: ret i32 0
|
||||
%v = load atomic i32, i32* %P unordered, align 4
|
||||
%a = load atomic i32, i32* %Q unordered, align 4
|
||||
store atomic i32 %v, i32* %P unordered, align 4
|
||||
%b = load atomic i32, i32* %Q unordered, align 4
|
||||
%res = sub i32 %a, %b
|
||||
ret i32 %res
|
||||
}
|
||||
|
||||
|
||||
define void @dse_neg1(i32 *%P) {
|
||||
; CHECK-LABEL: @dse_neg1
|
||||
; CHECK: store
|
||||
%v = load i32, i32* %P
|
||||
store i32 5, i32* %P
|
||||
ret void
|
||||
}
|
||||
|
||||
; Could remove the store, but only if ordering was somehow
|
||||
; encoded.
|
||||
define void @dse_neg2(i32 *%P) {
|
||||
; CHECK-LABEL: @dse_neg2
|
||||
; CHECK: store
|
||||
%v = load i32, i32* %P
|
||||
store atomic i32 %v, i32* %P seq_cst, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
@c = external global i32, align 4
|
||||
declare i32 @reads_c(i32 returned)
|
||||
define void @pr28763() {
|
||||
entry:
|
||||
; CHECK-LABEL: @pr28763(
|
||||
; CHECK: store i32 0, i32* @c, align 4
|
||||
; CHECK: call i32 @reads_c(i32 0)
|
||||
; CHECK: store i32 2, i32* @c, align 4
|
||||
%load = load i32, i32* @c, align 4
|
||||
store i32 0, i32* @c, align 4
|
||||
%call = call i32 @reads_c(i32 0)
|
||||
store i32 2, i32* @c, align 4
|
||||
ret void
|
||||
}
|
254
external/llvm/test/Transforms/EarlyCSE/commute.ll
vendored
254
external/llvm/test/Transforms/EarlyCSE/commute.ll
vendored
@ -1,254 +0,0 @@
|
||||
; RUN: opt < %s -S -early-cse | FileCheck %s
|
||||
; RUN: opt < %s -S -basicaa -early-cse-memssa | FileCheck %s
|
||||
|
||||
define void @test1(float %A, float %B, float* %PA, float* %PB) {
|
||||
; CHECK-LABEL: @test1(
|
||||
; CHECK-NEXT: [[C:%.*]] = fadd float %A, %B
|
||||
; CHECK-NEXT: store float [[C]], float* %PA
|
||||
; CHECK-NEXT: store float [[C]], float* %PB
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%C = fadd float %A, %B
|
||||
store float %C, float* %PA
|
||||
%D = fadd float %B, %A
|
||||
store float %D, float* %PB
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @test2(float %A, float %B, i1* %PA, i1* %PB) {
|
||||
; CHECK-LABEL: @test2(
|
||||
; CHECK-NEXT: [[C:%.*]] = fcmp oeq float %A, %B
|
||||
; CHECK-NEXT: store i1 [[C]], i1* %PA
|
||||
; CHECK-NEXT: store i1 [[C]], i1* %PB
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%C = fcmp oeq float %A, %B
|
||||
store i1 %C, i1* %PA
|
||||
%D = fcmp oeq float %B, %A
|
||||
store i1 %D, i1* %PB
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @test3(float %A, float %B, i1* %PA, i1* %PB) {
|
||||
; CHECK-LABEL: @test3(
|
||||
; CHECK-NEXT: [[C:%.*]] = fcmp uge float %A, %B
|
||||
; CHECK-NEXT: store i1 [[C]], i1* %PA
|
||||
; CHECK-NEXT: store i1 [[C]], i1* %PB
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%C = fcmp uge float %A, %B
|
||||
store i1 %C, i1* %PA
|
||||
%D = fcmp ule float %B, %A
|
||||
store i1 %D, i1* %PB
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @test4(i32 %A, i32 %B, i1* %PA, i1* %PB) {
|
||||
; CHECK-LABEL: @test4(
|
||||
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 %A, %B
|
||||
; CHECK-NEXT: store i1 [[C]], i1* %PA
|
||||
; CHECK-NEXT: store i1 [[C]], i1* %PB
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%C = icmp eq i32 %A, %B
|
||||
store i1 %C, i1* %PA
|
||||
%D = icmp eq i32 %B, %A
|
||||
store i1 %D, i1* %PB
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @test5(i32 %A, i32 %B, i1* %PA, i1* %PB) {
|
||||
; CHECK-LABEL: @test5(
|
||||
; CHECK-NEXT: [[C:%.*]] = icmp sgt i32 %A, %B
|
||||
; CHECK-NEXT: store i1 [[C]], i1* %PA
|
||||
; CHECK-NEXT: store i1 [[C]], i1* %PB
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%C = icmp sgt i32 %A, %B
|
||||
store i1 %C, i1* %PA
|
||||
%D = icmp slt i32 %B, %A
|
||||
store i1 %D, i1* %PB
|
||||
ret void
|
||||
}
|
||||
|
||||
; Min/max operands may be commuted in the compare and select.
|
||||
|
||||
define i8 @smin_commute(i8 %a, i8 %b) {
|
||||
; CHECK-LABEL: @smin_commute(
|
||||
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %b, %a
|
||||
; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %a, i8 %b
|
||||
; CHECK-NEXT: [[R:%.*]] = mul i8 [[M1]], [[M1]]
|
||||
; CHECK-NEXT: ret i8 [[R]]
|
||||
;
|
||||
%cmp1 = icmp slt i8 %a, %b
|
||||
%cmp2 = icmp slt i8 %b, %a
|
||||
%m1 = select i1 %cmp1, i8 %a, i8 %b
|
||||
%m2 = select i1 %cmp2, i8 %b, i8 %a
|
||||
%r = mul i8 %m1, %m2
|
||||
ret i8 %r
|
||||
}
|
||||
|
||||
; Min/max can also have a swapped predicate and select operands.
|
||||
|
||||
define i1 @smin_swapped(i8 %a, i8 %b) {
|
||||
; CHECK-LABEL: @smin_swapped(
|
||||
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, %b
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %a, %b
|
||||
; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %b, i8 %a
|
||||
; CHECK-NEXT: ret i1 true
|
||||
;
|
||||
%cmp1 = icmp sgt i8 %a, %b
|
||||
%cmp2 = icmp slt i8 %a, %b
|
||||
%m1 = select i1 %cmp1, i8 %b, i8 %a
|
||||
%m2 = select i1 %cmp2, i8 %a, i8 %b
|
||||
%r = icmp eq i8 %m2, %m1
|
||||
ret i1 %r
|
||||
}
|
||||
|
||||
define i8 @smax_commute(i8 %a, i8 %b) {
|
||||
; CHECK-LABEL: @smax_commute(
|
||||
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, %b
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %b, %a
|
||||
; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %a, i8 %b
|
||||
; CHECK-NEXT: ret i8 0
|
||||
;
|
||||
%cmp1 = icmp sgt i8 %a, %b
|
||||
%cmp2 = icmp sgt i8 %b, %a
|
||||
%m1 = select i1 %cmp1, i8 %a, i8 %b
|
||||
%m2 = select i1 %cmp2, i8 %b, i8 %a
|
||||
%r = urem i8 %m2, %m1
|
||||
ret i8 %r
|
||||
}
|
||||
|
||||
define i8 @smax_swapped(i8 %a, i8 %b) {
|
||||
; CHECK-LABEL: @smax_swapped(
|
||||
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %a, %b
|
||||
; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %b, i8 %a
|
||||
; CHECK-NEXT: ret i8 1
|
||||
;
|
||||
%cmp1 = icmp slt i8 %a, %b
|
||||
%cmp2 = icmp sgt i8 %a, %b
|
||||
%m1 = select i1 %cmp1, i8 %b, i8 %a
|
||||
%m2 = select i1 %cmp2, i8 %a, i8 %b
|
||||
%r = sdiv i8 %m1, %m2
|
||||
ret i8 %r
|
||||
}
|
||||
|
||||
define i8 @umin_commute(i8 %a, i8 %b) {
|
||||
; CHECK-LABEL: @umin_commute(
|
||||
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i8 %b, %a
|
||||
; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %a, i8 %b
|
||||
; CHECK-NEXT: ret i8 0
|
||||
;
|
||||
%cmp1 = icmp ult i8 %a, %b
|
||||
%cmp2 = icmp ult i8 %b, %a
|
||||
%m1 = select i1 %cmp1, i8 %a, i8 %b
|
||||
%m2 = select i1 %cmp2, i8 %b, i8 %a
|
||||
%r = sub i8 %m2, %m1
|
||||
ret i8 %r
|
||||
}
|
||||
|
||||
; Choose a vector type just to show that works.
|
||||
|
||||
define <2 x i8> @umin_swapped(<2 x i8> %a, <2 x i8> %b) {
|
||||
; CHECK-LABEL: @umin_swapped(
|
||||
; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt <2 x i8> %a, %b
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult <2 x i8> %a, %b
|
||||
; CHECK-NEXT: [[M1:%.*]] = select <2 x i1> [[CMP1]], <2 x i8> %b, <2 x i8> %a
|
||||
; CHECK-NEXT: ret <2 x i8> zeroinitializer
|
||||
;
|
||||
%cmp1 = icmp ugt <2 x i8> %a, %b
|
||||
%cmp2 = icmp ult <2 x i8> %a, %b
|
||||
%m1 = select <2 x i1> %cmp1, <2 x i8> %b, <2 x i8> %a
|
||||
%m2 = select <2 x i1> %cmp2, <2 x i8> %a, <2 x i8> %b
|
||||
%r = sub <2 x i8> %m2, %m1
|
||||
ret <2 x i8> %r
|
||||
}
|
||||
|
||||
define i8 @umax_commute(i8 %a, i8 %b) {
|
||||
; CHECK-LABEL: @umax_commute(
|
||||
; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 %a, %b
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 %b, %a
|
||||
; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %a, i8 %b
|
||||
; CHECK-NEXT: ret i8 1
|
||||
;
|
||||
%cmp1 = icmp ugt i8 %a, %b
|
||||
%cmp2 = icmp ugt i8 %b, %a
|
||||
%m1 = select i1 %cmp1, i8 %a, i8 %b
|
||||
%m2 = select i1 %cmp2, i8 %b, i8 %a
|
||||
%r = udiv i8 %m1, %m2
|
||||
ret i8 %r
|
||||
}
|
||||
|
||||
define i8 @umax_swapped(i8 %a, i8 %b) {
|
||||
; CHECK-LABEL: @umax_swapped(
|
||||
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 %a, %b
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 %a, %b
|
||||
; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %b, i8 %a
|
||||
; CHECK-NEXT: [[R:%.*]] = add i8 [[M1]], [[M1]]
|
||||
; CHECK-NEXT: ret i8 [[R]]
|
||||
;
|
||||
%cmp1 = icmp ult i8 %a, %b
|
||||
%cmp2 = icmp ugt i8 %a, %b
|
||||
%m1 = select i1 %cmp1, i8 %b, i8 %a
|
||||
%m2 = select i1 %cmp2, i8 %a, i8 %b
|
||||
%r = add i8 %m2, %m1
|
||||
ret i8 %r
|
||||
}
|
||||
|
||||
; Min/max may exist with non-canonical operands. Value tracking can match those.
|
||||
|
||||
define i8 @smax_nsw(i8 %a, i8 %b) {
|
||||
; CHECK-LABEL: @smax_nsw(
|
||||
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i8 %a, %b
|
||||
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, %b
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 [[SUB]], 0
|
||||
; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 0, i8 [[SUB]]
|
||||
; CHECK-NEXT: ret i8 0
|
||||
;
|
||||
%sub = sub nsw i8 %a, %b
|
||||
%cmp1 = icmp slt i8 %a, %b
|
||||
%cmp2 = icmp sgt i8 %sub, 0
|
||||
%m1 = select i1 %cmp1, i8 0, i8 %sub
|
||||
%m2 = select i1 %cmp2, i8 %sub, i8 0
|
||||
%r = sub i8 %m2, %m1
|
||||
ret i8 %r
|
||||
}
|
||||
|
||||
define i8 @abs_swapped(i8 %a) {
|
||||
; CHECK-LABEL: @abs_swapped(
|
||||
; CHECK-NEXT: [[NEG:%.*]] = sub i8 0, %a
|
||||
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 %a, 0
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 %a, 0
|
||||
; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %a, i8 [[NEG]]
|
||||
; CHECK-NEXT: ret i8 [[M1]]
|
||||
;
|
||||
%neg = sub i8 0, %a
|
||||
%cmp1 = icmp sgt i8 %a, 0
|
||||
%cmp2 = icmp slt i8 %a, 0
|
||||
%m1 = select i1 %cmp1, i8 %a, i8 %neg
|
||||
%m2 = select i1 %cmp2, i8 %neg, i8 %a
|
||||
%r = or i8 %m2, %m1
|
||||
ret i8 %r
|
||||
}
|
||||
|
||||
define i8 @nabs_swapped(i8 %a) {
|
||||
; CHECK-LABEL: @nabs_swapped(
|
||||
; CHECK-NEXT: [[NEG:%.*]] = sub i8 0, %a
|
||||
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 %a, 0
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 %a, 0
|
||||
; CHECK-NEXT: [[M1:%.*]] = select i1 [[CMP1]], i8 %a, i8 [[NEG]]
|
||||
; CHECK-NEXT: ret i8 0
|
||||
;
|
||||
%neg = sub i8 0, %a
|
||||
%cmp1 = icmp slt i8 %a, 0
|
||||
%cmp2 = icmp sgt i8 %a, 0
|
||||
%m1 = select i1 %cmp1, i8 %a, i8 %neg
|
||||
%m2 = select i1 %cmp2, i8 %neg, i8 %a
|
||||
%r = xor i8 %m2, %m1
|
||||
ret i8 %r
|
||||
}
|
||||
|
@ -1,108 +0,0 @@
|
||||
; RUN: opt -early-cse -S < %s | FileCheck %s
|
||||
; RUN: opt -basicaa -early-cse-memssa -S < %s | FileCheck %s
|
||||
|
||||
; Can we CSE a known condition to a constant?
|
||||
define i1 @test(i8* %p) {
|
||||
; CHECK-LABEL: @test
|
||||
entry:
|
||||
%cnd1 = icmp eq i8* %p, null
|
||||
br i1 %cnd1, label %taken, label %untaken
|
||||
|
||||
taken:
|
||||
; CHECK-LABEL: taken:
|
||||
; CHECK-NEXT: ret i1 true
|
||||
%cnd2 = icmp eq i8* %p, null
|
||||
ret i1 %cnd2
|
||||
|
||||
untaken:
|
||||
; CHECK-LABEL: untaken:
|
||||
; CHECK-NEXT: ret i1 false
|
||||
%cnd3 = icmp eq i8* %p, null
|
||||
ret i1 %cnd3
|
||||
}
|
||||
|
||||
; We can CSE the condition, but we *don't* know it's value after the merge
|
||||
define i1 @test_neg1(i8* %p) {
|
||||
; CHECK-LABEL: @test_neg1
|
||||
entry:
|
||||
%cnd1 = icmp eq i8* %p, null
|
||||
br i1 %cnd1, label %taken, label %untaken
|
||||
|
||||
taken:
|
||||
br label %merge
|
||||
|
||||
untaken:
|
||||
br label %merge
|
||||
|
||||
merge:
|
||||
; CHECK-LABEL: merge:
|
||||
; CHECK-NEXT: ret i1 %cnd1
|
||||
%cnd3 = icmp eq i8* %p, null
|
||||
ret i1 %cnd3
|
||||
}
|
||||
|
||||
; Check specifically for a case where we have a unique predecessor, but
|
||||
; not a single predecessor. We can not know the value of the condition here.
|
||||
define i1 @test_neg2(i8* %p) {
|
||||
; CHECK-LABEL: @test_neg2
|
||||
entry:
|
||||
%cnd1 = icmp eq i8* %p, null
|
||||
br i1 %cnd1, label %merge, label %merge
|
||||
|
||||
merge:
|
||||
; CHECK-LABEL: merge:
|
||||
; CHECK-NEXT: ret i1 %cnd1
|
||||
%cnd3 = icmp eq i8* %p, null
|
||||
ret i1 %cnd3
|
||||
}
|
||||
|
||||
; Replace a use rather than CSE
|
||||
define i1 @test2(i8* %p) {
|
||||
; CHECK-LABEL: @test2
|
||||
entry:
|
||||
%cnd = icmp eq i8* %p, null
|
||||
br i1 %cnd, label %taken, label %untaken
|
||||
|
||||
taken:
|
||||
; CHECK-LABEL: taken:
|
||||
; CHECK-NEXT: ret i1 true
|
||||
ret i1 %cnd
|
||||
|
||||
untaken:
|
||||
; CHECK-LABEL: untaken:
|
||||
; CHECK-NEXT: ret i1 false
|
||||
ret i1 %cnd
|
||||
}
|
||||
|
||||
; Not legal to replace use given it's not dominated by edge
|
||||
define i1 @test2_neg1(i8* %p) {
|
||||
; CHECK-LABEL: @test2_neg1
|
||||
entry:
|
||||
%cnd1 = icmp eq i8* %p, null
|
||||
br i1 %cnd1, label %taken, label %untaken
|
||||
|
||||
taken:
|
||||
br label %merge
|
||||
|
||||
untaken:
|
||||
br label %merge
|
||||
|
||||
merge:
|
||||
; CHECK-LABEL: merge:
|
||||
; CHECK-NEXT: ret i1 %cnd1
|
||||
ret i1 %cnd1
|
||||
}
|
||||
|
||||
; Another single predecessor test, but for dominated use
|
||||
define i1 @test2_neg2(i8* %p) {
|
||||
; CHECK-LABEL: @test2_neg2
|
||||
entry:
|
||||
%cnd1 = icmp eq i8* %p, null
|
||||
br i1 %cnd1, label %merge, label %merge
|
||||
|
||||
merge:
|
||||
; CHECK-LABEL: merge:
|
||||
; CHECK-NEXT: ret i1 %cnd1
|
||||
ret i1 %cnd1
|
||||
}
|
||||
|
@ -1,39 +0,0 @@
|
||||
; RUN: opt -early-cse -S %s | FileCheck %s
|
||||
|
||||
%mystruct = type { i32 }
|
||||
|
||||
; @var is global so that *every* GEP argument is Constant.
|
||||
@var = external global %mystruct
|
||||
|
||||
; Control flow is to make the dominance tree consider the final icmp before it
|
||||
; gets to simplify the purely constant one (%tst). Since that icmp uses the
|
||||
; select that gets considered next. Finally the select simplification looks at
|
||||
; the %tst icmp and we don't want it to speculate about what happens if "i32 0"
|
||||
; is actually "i32 1", broken universes are automatic UB.
|
||||
;
|
||||
; In this case doing the speculation would create an invalid GEP(@var, 0, 1) and
|
||||
; crash.
|
||||
|
||||
define i1 @test_constant_speculation() {
|
||||
; CHECK-LABEL: define i1 @test_constant_speculation
|
||||
entry:
|
||||
br i1 undef, label %end, label %select
|
||||
|
||||
select:
|
||||
; CHECK: select:
|
||||
; CHECK-NOT: icmp
|
||||
; CHECK-NOT: getelementptr
|
||||
; CHECK-NOT: select
|
||||
|
||||
%tst = icmp eq i32 1, 0
|
||||
%elt = getelementptr %mystruct, %mystruct* @var, i64 0, i32 0
|
||||
%sel = select i1 %tst, i32* null, i32* %elt
|
||||
br label %end
|
||||
|
||||
end:
|
||||
; CHECK: end:
|
||||
; CHECK: %tmp = phi i32* [ null, %entry ], [ getelementptr inbounds (%mystruct, %mystruct* @var, i64 0, i32 0), %select ]
|
||||
%tmp = phi i32* [null, %entry], [%sel, %select]
|
||||
%res = icmp eq i32* %tmp, null
|
||||
ret i1 %res
|
||||
}
|
174
external/llvm/test/Transforms/EarlyCSE/edge.ll
vendored
174
external/llvm/test/Transforms/EarlyCSE/edge.ll
vendored
@ -1,174 +0,0 @@
|
||||
; RUN: opt -early-cse -S < %s | FileCheck %s
|
||||
; RUN: opt -basicaa -early-cse-memssa -S < %s | FileCheck %s
|
||||
; Same as GVN/edge.ll, but updated to reflect EarlyCSE's less powerful
|
||||
; implementation. EarlyCSE currently doesn't exploit equality comparisons
|
||||
; against constants.
|
||||
|
||||
define i32 @f1(i32 %x) {
|
||||
; CHECK-LABEL: define i32 @f1(
|
||||
bb0:
|
||||
%cmp = icmp eq i32 %x, 0
|
||||
br i1 %cmp, label %bb2, label %bb1
|
||||
bb1:
|
||||
br label %bb2
|
||||
bb2:
|
||||
%cond = phi i32 [ %x, %bb0 ], [ 0, %bb1 ]
|
||||
%foo = add i32 %cond, %x
|
||||
ret i32 %foo
|
||||
; CHECK: bb2:
|
||||
; CHECK: %cond = phi i32 [ %x, %bb0 ], [ 0, %bb1 ]
|
||||
}
|
||||
|
||||
define i32 @f2(i32 %x) {
|
||||
; CHECK-LABEL: define i32 @f2(
|
||||
bb0:
|
||||
%cmp = icmp ne i32 %x, 0
|
||||
br i1 %cmp, label %bb1, label %bb2
|
||||
bb1:
|
||||
br label %bb2
|
||||
bb2:
|
||||
%cond = phi i32 [ %x, %bb0 ], [ 0, %bb1 ]
|
||||
%foo = add i32 %cond, %x
|
||||
ret i32 %foo
|
||||
; CHECK: bb2:
|
||||
; CHECK: %cond = phi i32 [ %x, %bb0 ], [ 0, %bb1 ]
|
||||
}
|
||||
|
||||
define i32 @f3(i32 %x) {
|
||||
; CHECK-LABEL: define i32 @f3(
|
||||
bb0:
|
||||
switch i32 %x, label %bb1 [ i32 0, label %bb2]
|
||||
bb1:
|
||||
br label %bb2
|
||||
bb2:
|
||||
%cond = phi i32 [ %x, %bb0 ], [ 0, %bb1 ]
|
||||
%foo = add i32 %cond, %x
|
||||
ret i32 %foo
|
||||
; CHECK: bb2:
|
||||
; CHECK: %cond = phi i32 [ %x, %bb0 ], [ 0, %bb1 ]
|
||||
}
|
||||
|
||||
declare void @g(i1)
|
||||
define void @f4(i8 * %x) {
|
||||
; CHECK-LABEL: define void @f4(
|
||||
bb0:
|
||||
%y = icmp eq i8* null, %x
|
||||
br i1 %y, label %bb2, label %bb1
|
||||
bb1:
|
||||
br label %bb2
|
||||
bb2:
|
||||
%zed = icmp eq i8* null, %x
|
||||
call void @g(i1 %zed)
|
||||
; CHECK: call void @g(i1 %y)
|
||||
ret void
|
||||
}
|
||||
|
||||
define double @fcmp_oeq_not_zero(double %x, double %y) {
|
||||
entry:
|
||||
%cmp = fcmp oeq double %y, 2.0
|
||||
br i1 %cmp, label %if, label %return
|
||||
|
||||
if:
|
||||
%div = fdiv double %x, %y
|
||||
br label %return
|
||||
|
||||
return:
|
||||
%retval = phi double [ %div, %if ], [ %x, %entry ]
|
||||
ret double %retval
|
||||
|
||||
; CHECK-LABEL: define double @fcmp_oeq_not_zero(
|
||||
; CHECK: %div = fdiv double %x, %y
|
||||
}
|
||||
|
||||
define double @fcmp_une_not_zero(double %x, double %y) {
|
||||
entry:
|
||||
%cmp = fcmp une double %y, 2.0
|
||||
br i1 %cmp, label %return, label %else
|
||||
|
||||
else:
|
||||
%div = fdiv double %x, %y
|
||||
br label %return
|
||||
|
||||
return:
|
||||
%retval = phi double [ %div, %else ], [ %x, %entry ]
|
||||
ret double %retval
|
||||
|
||||
; CHECK-LABEL: define double @fcmp_une_not_zero(
|
||||
; CHECK: %div = fdiv double %x, %y
|
||||
}
|
||||
|
||||
; PR22376 - We can't propagate zero constants because -0.0
|
||||
; compares equal to 0.0. If %y is -0.0 in this test case,
|
||||
; we would produce the wrong sign on the infinity return value.
|
||||
define double @fcmp_oeq_zero(double %x, double %y) {
|
||||
entry:
|
||||
%cmp = fcmp oeq double %y, 0.0
|
||||
br i1 %cmp, label %if, label %return
|
||||
|
||||
if:
|
||||
%div = fdiv double %x, %y
|
||||
br label %return
|
||||
|
||||
return:
|
||||
%retval = phi double [ %div, %if ], [ %x, %entry ]
|
||||
ret double %retval
|
||||
|
||||
; CHECK-LABEL: define double @fcmp_oeq_zero(
|
||||
; CHECK: %div = fdiv double %x, %y
|
||||
}
|
||||
|
||||
define double @fcmp_une_zero(double %x, double %y) {
|
||||
entry:
|
||||
%cmp = fcmp une double %y, -0.0
|
||||
br i1 %cmp, label %return, label %else
|
||||
|
||||
else:
|
||||
%div = fdiv double %x, %y
|
||||
br label %return
|
||||
|
||||
return:
|
||||
%retval = phi double [ %div, %else ], [ %x, %entry ]
|
||||
ret double %retval
|
||||
|
||||
; CHECK-LABEL: define double @fcmp_une_zero(
|
||||
; CHECK: %div = fdiv double %x, %y
|
||||
}
|
||||
|
||||
; We also cannot propagate a value if it's not a constant.
|
||||
; This is because the value could be 0.0 or -0.0.
|
||||
|
||||
define double @fcmp_oeq_maybe_zero(double %x, double %y, double %z1, double %z2) {
|
||||
entry:
|
||||
%z = fadd double %z1, %z2
|
||||
%cmp = fcmp oeq double %y, %z
|
||||
br i1 %cmp, label %if, label %return
|
||||
|
||||
if:
|
||||
%div = fdiv double %x, %z
|
||||
br label %return
|
||||
|
||||
return:
|
||||
%retval = phi double [ %div, %if ], [ %x, %entry ]
|
||||
ret double %retval
|
||||
|
||||
; CHECK-LABEL: define double @fcmp_oeq_maybe_zero(
|
||||
; CHECK: %div = fdiv double %x, %z
|
||||
}
|
||||
|
||||
define double @fcmp_une_maybe_zero(double %x, double %y, double %z1, double %z2) {
|
||||
entry:
|
||||
%z = fadd double %z1, %z2
|
||||
%cmp = fcmp une double %y, %z
|
||||
br i1 %cmp, label %return, label %else
|
||||
|
||||
else:
|
||||
%div = fdiv double %x, %z
|
||||
br label %return
|
||||
|
||||
return:
|
||||
%retval = phi double [ %div, %else ], [ %x, %entry ]
|
||||
ret double %retval
|
||||
|
||||
; CHECK-LABEL: define double @fcmp_une_maybe_zero(
|
||||
; CHECK: %div = fdiv double %x, %z
|
||||
}
|
87
external/llvm/test/Transforms/EarlyCSE/fence.ll
vendored
87
external/llvm/test/Transforms/EarlyCSE/fence.ll
vendored
@ -1,87 +0,0 @@
|
||||
; RUN: opt -S -early-cse < %s | FileCheck %s
|
||||
; RUN: opt < %s -S -basicaa -early-cse-memssa | FileCheck %s
|
||||
; NOTE: This file is testing the current implementation. Some of
|
||||
; the transforms used as negative tests below would be legal, but
|
||||
; only if reached through a chain of logic which EarlyCSE is incapable
|
||||
; of performing. To say it differently, this file tests a conservative
|
||||
; version of the memory model. If we want to extend EarlyCSE to be more
|
||||
; aggressive in the future, we may need to relax some of the negative tests.
|
||||
|
||||
; We can value forward across the fence since we can (semantically)
|
||||
; reorder the following load before the fence.
|
||||
define i32 @test(i32* %addr.i) {
|
||||
; CHECK-LABEL: @test
|
||||
; CHECK: store
|
||||
; CHECK: fence
|
||||
; CHECK-NOT: load
|
||||
; CHECK: ret
|
||||
store i32 5, i32* %addr.i, align 4
|
||||
fence release
|
||||
%a = load i32, i32* %addr.i, align 4
|
||||
ret i32 %a
|
||||
}
|
||||
|
||||
; Same as above
|
||||
define i32 @test2(i32* noalias %addr.i, i32* noalias %otheraddr) {
|
||||
; CHECK-LABEL: @test2
|
||||
; CHECK: load
|
||||
; CHECK: fence
|
||||
; CHECK-NOT: load
|
||||
; CHECK: ret
|
||||
%a = load i32, i32* %addr.i, align 4
|
||||
fence release
|
||||
%a2 = load i32, i32* %addr.i, align 4
|
||||
%res = sub i32 %a, %a2
|
||||
ret i32 %a
|
||||
}
|
||||
|
||||
; We can not value forward across an acquire barrier since we might
|
||||
; be syncronizing with another thread storing to the same variable
|
||||
; followed by a release fence. If this thread observed the release
|
||||
; had happened, we must present a consistent view of memory at the
|
||||
; fence. Note that it would be legal to reorder '%a' after the fence
|
||||
; and then remove '%a2'. The current implementation doesn't know how
|
||||
; to do this, but if it learned, this test will need revised.
|
||||
define i32 @test3(i32* noalias %addr.i, i32* noalias %otheraddr) {
|
||||
; CHECK-LABEL: @test3
|
||||
; CHECK: load
|
||||
; CHECK: fence
|
||||
; CHECK: load
|
||||
; CHECK: sub
|
||||
; CHECK: ret
|
||||
%a = load i32, i32* %addr.i, align 4
|
||||
fence acquire
|
||||
%a2 = load i32, i32* %addr.i, align 4
|
||||
%res = sub i32 %a, %a2
|
||||
ret i32 %res
|
||||
}
|
||||
|
||||
; We can not dead store eliminate accross the fence. We could in
|
||||
; principal reorder the second store above the fence and then DSE either
|
||||
; store, but this is beyond the simple last-store DSE which EarlyCSE
|
||||
; implements.
|
||||
define void @test4(i32* %addr.i) {
|
||||
; CHECK-LABEL: @test4
|
||||
; CHECK: store
|
||||
; CHECK: fence
|
||||
; CHECK: store
|
||||
; CHECK: ret
|
||||
store i32 5, i32* %addr.i, align 4
|
||||
fence release
|
||||
store i32 5, i32* %addr.i, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; We *could* DSE across this fence, but don't. No other thread can
|
||||
; observe the order of the acquire fence and the store.
|
||||
define void @test5(i32* %addr.i) {
|
||||
; CHECK-LABEL: @test5
|
||||
; CHECK: store
|
||||
; CHECK: fence
|
||||
; CHECK: store
|
||||
; CHECK: ret
|
||||
store i32 5, i32* %addr.i, align 4
|
||||
fence acquire
|
||||
store i32 5, i32* %addr.i, align 4
|
||||
ret void
|
||||
}
|
19
external/llvm/test/Transforms/EarlyCSE/flags.ll
vendored
19
external/llvm/test/Transforms/EarlyCSE/flags.ll
vendored
@ -1,19 +0,0 @@
|
||||
; RUN: opt -early-cse -S < %s | FileCheck %s
|
||||
; RUN: opt -basicaa -early-cse-memssa -S < %s | FileCheck %s
|
||||
|
||||
declare void @use(i1)
|
||||
|
||||
define void @test1(float %x, float %y) {
|
||||
entry:
|
||||
%cmp1 = fcmp nnan oeq float %y, %x
|
||||
%cmp2 = fcmp oeq float %x, %y
|
||||
call void @use(i1 %cmp1)
|
||||
call void @use(i1 %cmp2)
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define void @test1(
|
||||
; CHECK: %[[cmp:.*]] = fcmp oeq float %y, %x
|
||||
; CHECK-NEXT: call void @use(i1 %[[cmp]])
|
||||
; CHECK-NEXT: call void @use(i1 %[[cmp]])
|
||||
; CHECK-NEXT: ret void
|
@ -1,15 +0,0 @@
|
||||
; RUN: opt < %s -S -early-cse | FileCheck %s
|
||||
; RUN: opt < %s -S -basicaa -early-cse-memssa | FileCheck %s
|
||||
|
||||
; Ensure we don't simplify away additions vectors of +0.0's (same as scalars).
|
||||
define <4 x float> @fV( <4 x float> %a) {
|
||||
; CHECK: %b = fadd <4 x float> %a, zeroinitializer
|
||||
%b = fadd <4 x float> %a, <float 0.0,float 0.0,float 0.0,float 0.0>
|
||||
ret <4 x float> %b
|
||||
}
|
||||
|
||||
define <4 x float> @fW( <4 x float> %a) {
|
||||
; CHECK: ret <4 x float> %a
|
||||
%b = fadd <4 x float> %a, <float -0.0,float -0.0,float -0.0,float -0.0>
|
||||
ret <4 x float> %b
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt < %s -S -globals-aa -early-cse-memssa | FileCheck %s
|
||||
|
||||
define i16 @f1() readonly {
|
||||
ret i16 0
|
||||
}
|
||||
|
||||
declare void @f2()
|
||||
|
||||
; Check that EarlyCSE correctly handles function calls that don't have
|
||||
; a MemoryAccess. In this case the calls to @f1 have no
|
||||
; MemoryAccesses since globals-aa determines that @f1 doesn't
|
||||
; read/write memory at all.
|
||||
|
||||
define void @f3() {
|
||||
; CHECK-LABEL: @f3(
|
||||
; CHECK-NEXT: [[CALL1:%.*]] = call i16 @f1()
|
||||
; CHECK-NEXT: call void @f2()
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%call1 = call i16 @f1()
|
||||
call void @f2()
|
||||
%call2 = call i16 @f1()
|
||||
ret void
|
||||
}
|
528
external/llvm/test/Transforms/EarlyCSE/guards.ll
vendored
528
external/llvm/test/Transforms/EarlyCSE/guards.ll
vendored
File diff suppressed because it is too large
Load Diff
@ -1,20 +0,0 @@
|
||||
; RUN: opt -early-cse -S < %s | FileCheck %s
|
||||
; RUN: opt -basicaa -early-cse-memssa -S < %s | FileCheck %s
|
||||
; PR12231
|
||||
|
||||
declare i32 @f()
|
||||
|
||||
define i32 @fn() {
|
||||
entry:
|
||||
br label %lbl_1215
|
||||
|
||||
lbl_1215:
|
||||
%ins34 = phi i32 [ %ins35, %xxx ], [ undef, %entry ]
|
||||
ret i32 %ins34
|
||||
|
||||
xxx:
|
||||
%ins35 = call i32 @f()
|
||||
br label %lbl_1215
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define i32 @fn(
|
@ -1,27 +0,0 @@
|
||||
; RUN: opt -S < %s -early-cse | FileCheck %s
|
||||
|
||||
declare void @llvm.sideeffect()
|
||||
|
||||
; Store-to-load forwarding across a @llvm.sideeffect.
|
||||
|
||||
; CHECK-LABEL: s2l
|
||||
; CHECK-NOT: load
|
||||
define float @s2l(float* %p) {
|
||||
store float 0.0, float* %p
|
||||
call void @llvm.sideeffect()
|
||||
%t = load float, float* %p
|
||||
ret float %t
|
||||
}
|
||||
|
||||
; Redundant load elimination across a @llvm.sideeffect.
|
||||
|
||||
; CHECK-LABEL: rle
|
||||
; CHECK: load
|
||||
; CHECK-NOT: load
|
||||
define float @rle(float* %p) {
|
||||
%r = load float, float* %p
|
||||
call void @llvm.sideeffect()
|
||||
%s = load float, float* %p
|
||||
%t = fadd float %r, %s
|
||||
ret float %t
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
; RUN: opt -S -early-cse < %s | FileCheck %s
|
||||
; RUN: opt -S -basicaa -early-cse-memssa < %s | FileCheck %s
|
||||
|
||||
declare void @clobber_and_use(i32)
|
||||
|
||||
define void @f_0(i32* %ptr) {
|
||||
; CHECK-LABEL: @f_0(
|
||||
; CHECK: %val0 = load i32, i32* %ptr, !invariant.load !0
|
||||
; CHECK: call void @clobber_and_use(i32 %val0)
|
||||
; CHECK: call void @clobber_and_use(i32 %val0)
|
||||
; CHECK: call void @clobber_and_use(i32 %val0)
|
||||
; CHECK: ret void
|
||||
|
||||
%val0 = load i32, i32* %ptr, !invariant.load !{}
|
||||
call void @clobber_and_use(i32 %val0)
|
||||
%val1 = load i32, i32* %ptr, !invariant.load !{}
|
||||
call void @clobber_and_use(i32 %val1)
|
||||
%val2 = load i32, i32* %ptr, !invariant.load !{}
|
||||
call void @clobber_and_use(i32 %val2)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f_1(i32* %ptr) {
|
||||
; We can forward invariant loads to non-invariant loads.
|
||||
|
||||
; CHECK-LABEL: @f_1(
|
||||
; CHECK: %val0 = load i32, i32* %ptr, !invariant.load !0
|
||||
; CHECK: call void @clobber_and_use(i32 %val0)
|
||||
; CHECK: call void @clobber_and_use(i32 %val0)
|
||||
|
||||
%val0 = load i32, i32* %ptr, !invariant.load !{}
|
||||
call void @clobber_and_use(i32 %val0)
|
||||
%val1 = load i32, i32* %ptr
|
||||
call void @clobber_and_use(i32 %val1)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f_2(i32* %ptr) {
|
||||
; We can forward a non-invariant load into an invariant load.
|
||||
|
||||
; CHECK-LABEL: @f_2(
|
||||
; CHECK: %val0 = load i32, i32* %ptr
|
||||
; CHECK: call void @clobber_and_use(i32 %val0)
|
||||
; CHECK: call void @clobber_and_use(i32 %val0)
|
||||
|
||||
%val0 = load i32, i32* %ptr
|
||||
call void @clobber_and_use(i32 %val0)
|
||||
%val1 = load i32, i32* %ptr, !invariant.load !{}
|
||||
call void @clobber_and_use(i32 %val1)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f_3(i1 %cond, i32* %ptr) {
|
||||
; CHECK-LABEL: @f_3(
|
||||
%val0 = load i32, i32* %ptr, !invariant.load !{}
|
||||
call void @clobber_and_use(i32 %val0)
|
||||
br i1 %cond, label %left, label %right
|
||||
|
||||
; CHECK: %val0 = load i32, i32* %ptr, !invariant.load !0
|
||||
; CHECK: left:
|
||||
; CHECK-NEXT: call void @clobber_and_use(i32 %val0)
|
||||
|
||||
left:
|
||||
%val1 = load i32, i32* %ptr
|
||||
call void @clobber_and_use(i32 %val1)
|
||||
ret void
|
||||
|
||||
right:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f_4(i1 %cond, i32* %ptr) {
|
||||
; Negative test -- can't forward %val0 to %va1 because that'll break
|
||||
; def-dominates-use.
|
||||
|
||||
; CHECK-LABEL: @f_4(
|
||||
br i1 %cond, label %left, label %merge
|
||||
|
||||
left:
|
||||
; CHECK: left:
|
||||
; CHECK-NEXT: %val0 = load i32, i32* %ptr, !invariant.load !
|
||||
; CHECK-NEXT: call void @clobber_and_use(i32 %val0)
|
||||
|
||||
%val0 = load i32, i32* %ptr, !invariant.load !{}
|
||||
call void @clobber_and_use(i32 %val0)
|
||||
br label %merge
|
||||
|
||||
merge:
|
||||
; CHECK: merge:
|
||||
; CHECK-NEXT: %val1 = load i32, i32* %ptr
|
||||
; CHECK-NEXT: call void @clobber_and_use(i32 %val1)
|
||||
|
||||
%val1 = load i32, i32* %ptr
|
||||
call void @clobber_and_use(i32 %val1)
|
||||
ret void
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
; RUN: opt < %s -S -early-cse | FileCheck %s
|
||||
; RUN: opt < %s -S -passes=early-cse | FileCheck %s
|
||||
|
||||
declare {}* @llvm.invariant.start.p0i8(i64, i8* nocapture) nounwind readonly
|
||||
declare void @llvm.invariant.end.p0i8({}*, i64, i8* nocapture) nounwind
|
||||
|
||||
; Check that we do load-load forwarding over invariant.start, since it does not
|
||||
; clobber memory
|
||||
define i8 @test1(i8 *%P) {
|
||||
; CHECK-LABEL: @test1(
|
||||
; CHECK-NEXT: %V1 = load i8, i8* %P
|
||||
; CHECK-NEXT: %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
|
||||
; CHECK-NEXT: ret i8 0
|
||||
|
||||
|
||||
%V1 = load i8, i8* %P
|
||||
%i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
|
||||
%V2 = load i8, i8* %P
|
||||
%Diff = sub i8 %V1, %V2
|
||||
ret i8 %Diff
|
||||
}
|
||||
|
||||
|
||||
; Trivial Store->load forwarding over invariant.start
|
||||
define i8 @test2(i8 *%P) {
|
||||
; CHECK-LABEL: @test2(
|
||||
; CHECK-NEXT: store i8 42, i8* %P
|
||||
; CHECK-NEXT: %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
|
||||
; CHECK-NEXT: ret i8 42
|
||||
|
||||
|
||||
store i8 42, i8* %P
|
||||
%i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
|
||||
%V1 = load i8, i8* %P
|
||||
ret i8 %V1
|
||||
}
|
||||
|
||||
; We can DSE over invariant.start calls, since the first store to
|
||||
; %P is valid, and the second store is actually unreachable based on semantics
|
||||
; of invariant.start.
|
||||
define void @test3(i8* %P) {
|
||||
|
||||
; CHECK-LABEL: @test3(
|
||||
; CHECK-NEXT: %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
|
||||
; CHECK-NEXT: store i8 60, i8* %P
|
||||
|
||||
|
||||
store i8 50, i8* %P
|
||||
%i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
|
||||
store i8 60, i8* %P
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
; FIXME: Now the first store can actually be eliminated, since there is no read within
|
||||
; the invariant region, between start and end.
|
||||
define void @test4(i8* %P) {
|
||||
|
||||
; CHECK-LABEL: @test4(
|
||||
; CHECK-NEXT: store i8 50, i8* %P
|
||||
; CHECK-NEXT: %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
|
||||
; CHECK-NEXT: call void @llvm.invariant.end.p0i8({}* %i, i64 1, i8* %P)
|
||||
; CHECK-NEXT: store i8 60, i8* %P
|
||||
|
||||
|
||||
store i8 50, i8* %P
|
||||
%i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P)
|
||||
call void @llvm.invariant.end.p0i8({}* %i, i64 1, i8* %P)
|
||||
store i8 60, i8* %P
|
||||
ret void
|
||||
}
|
108
external/llvm/test/Transforms/EarlyCSE/memoryssa.ll
vendored
108
external/llvm/test/Transforms/EarlyCSE/memoryssa.ll
vendored
@ -1,108 +0,0 @@
|
||||
; RUN: opt < %s -S -early-cse | FileCheck %s --check-prefix=CHECK-NOMEMSSA
|
||||
; RUN: opt < %s -S -basicaa -early-cse-memssa | FileCheck %s
|
||||
; RUN: opt < %s -S -passes='early-cse' | FileCheck %s --check-prefix=CHECK-NOMEMSSA
|
||||
; RUN: opt < %s -S -aa-pipeline=basic-aa -passes='early-cse-memssa' | FileCheck %s
|
||||
|
||||
@G1 = global i32 zeroinitializer
|
||||
@G2 = global i32 zeroinitializer
|
||||
@G3 = global i32 zeroinitializer
|
||||
|
||||
;; Simple load value numbering across non-clobbering store.
|
||||
; CHECK-LABEL: @test1(
|
||||
; CHECK-NOMEMSSA-LABEL: @test1(
|
||||
define i32 @test1() {
|
||||
%V1 = load i32, i32* @G1
|
||||
store i32 0, i32* @G2
|
||||
%V2 = load i32, i32* @G1
|
||||
; CHECK-NOMEMSSA: sub i32 %V1, %V2
|
||||
%Diff = sub i32 %V1, %V2
|
||||
ret i32 %Diff
|
||||
; CHECK: ret i32 0
|
||||
}
|
||||
|
||||
;; Simple dead store elimination across non-clobbering store.
|
||||
; CHECK-LABEL: @test2(
|
||||
; CHECK-NOMEMSSA-LABEL: @test2(
|
||||
define void @test2() {
|
||||
entry:
|
||||
%V1 = load i32, i32* @G1
|
||||
; CHECK: store i32 0, i32* @G2
|
||||
store i32 0, i32* @G2
|
||||
; CHECK-NOT: store
|
||||
; CHECK-NOMEMSSA: store i32 %V1, i32* @G1
|
||||
store i32 %V1, i32* @G1
|
||||
ret void
|
||||
}
|
||||
|
||||
;; Check that memoryphi optimization happens during EarlyCSE, enabling
|
||||
;; more load CSE opportunities.
|
||||
; CHECK-LABEL: @test_memphiopt(
|
||||
; CHECK-NOMEMSSA-LABEL: @test_memphiopt(
|
||||
define void @test_memphiopt(i1 %c, i32* %p) {
|
||||
; CHECK-LABEL: entry:
|
||||
; CHECK-NOMEMSSA-LABEL: entry:
|
||||
entry:
|
||||
; CHECK: load
|
||||
; CHECK-NOMEMSSA: load
|
||||
%v1 = load i32, i32* @G1
|
||||
br i1 %c, label %then, label %end
|
||||
|
||||
; CHECK-LABEL: then:
|
||||
; CHECK-NOMEMSSA-LABEL: then:
|
||||
then:
|
||||
; CHECK: load
|
||||
; CHECK-NOMEMSSA: load
|
||||
%pv = load i32, i32* %p
|
||||
; CHECK-NOT: store
|
||||
; CHECK-NOMEMSSA-NOT: store
|
||||
store i32 %pv, i32* %p
|
||||
br label %end
|
||||
|
||||
; CHECK-LABEL: end:
|
||||
; CHECK-NOMEMSSA-LABEL: end:
|
||||
end:
|
||||
; CHECK-NOT: load
|
||||
; CHECK-NOMEMSSA: load
|
||||
%v2 = load i32, i32* @G1
|
||||
%sum = add i32 %v1, %v2
|
||||
store i32 %sum, i32* @G2
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
;; Check that MemoryPhi optimization and MemoryUse re-optimization
|
||||
;; happens during EarlyCSE, enabling more load CSE opportunities.
|
||||
; CHECK-LABEL: @test_memphiopt2(
|
||||
; CHECK-NOMEMSSA-LABEL: @test_memphiopt2(
|
||||
define void @test_memphiopt2(i1 %c, i32* %p) {
|
||||
; CHECK-LABEL: entry:
|
||||
; CHECK-NOMEMSSA-LABEL: entry:
|
||||
entry:
|
||||
; CHECK: load
|
||||
; CHECK-NOMEMSSA: load
|
||||
%v1 = load i32, i32* @G1
|
||||
; CHECK: store
|
||||
; CHECK-NOMEMSSA: store
|
||||
store i32 %v1, i32* @G2
|
||||
br i1 %c, label %then, label %end
|
||||
|
||||
; CHECK-LABEL: then:
|
||||
; CHECK-NOMEMSSA-LABEL: then:
|
||||
then:
|
||||
; CHECK: load
|
||||
; CHECK-NOMEMSSA: load
|
||||
%pv = load i32, i32* %p
|
||||
; CHECK-NOT: store
|
||||
; CHECK-NOMEMSSA-NOT: store
|
||||
store i32 %pv, i32* %p
|
||||
br label %end
|
||||
|
||||
; CHECK-LABEL: end:
|
||||
; CHECK-NOMEMSSA-LABEL: end:
|
||||
end:
|
||||
; CHECK-NOT: load
|
||||
; CHECK-NOMEMSSA: load
|
||||
%v2 = load i32, i32* @G1
|
||||
store i32 %v2, i32* @G3
|
||||
ret void
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
; RUN: opt -early-cse-memssa -S %s | FileCheck %s
|
||||
|
||||
; CHECK: define void @patatino() {
|
||||
; CHECK: for.cond:
|
||||
; CHECK-NEXT: br i1 true, label %if.end, label %for.inc
|
||||
; CHECK: if.end:
|
||||
; CHECK-NEXT: %tinkywinky = load i32, i32* @b
|
||||
; CHECK-NEXT: br i1 true, label %for.inc, label %for.inc
|
||||
; CHECK: for.inc:
|
||||
; CHECK-NEXT: ret void
|
||||
|
||||
|
||||
@b = external global i32
|
||||
|
||||
define void @patatino() {
|
||||
for.cond:
|
||||
br i1 true, label %if.end, label %for.inc
|
||||
|
||||
if.end:
|
||||
%tinkywinky = load i32, i32* @b
|
||||
store i32 %tinkywinky, i32* @b
|
||||
br i1 true, label %for.inc, label %for.inc
|
||||
|
||||
for.inc:
|
||||
ret void
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user