diff options
Diffstat (limited to 'llvm/test/Transforms/EarlyCSE')
29 files changed, 0 insertions, 3571 deletions
diff --git a/llvm/test/Transforms/EarlyCSE/AArch64/intrinsics.ll b/llvm/test/Transforms/EarlyCSE/AArch64/intrinsics.ll deleted file mode 100644 index bec6a7539ae..00000000000 --- a/llvm/test/Transforms/EarlyCSE/AArch64/intrinsics.ll +++ /dev/null @@ -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 -} diff --git a/llvm/test/Transforms/EarlyCSE/AArch64/ldstN.ll b/llvm/test/Transforms/EarlyCSE/AArch64/ldstN.ll deleted file mode 100644 index e3c6c8d9417..00000000000 --- a/llvm/test/Transforms/EarlyCSE/AArch64/ldstN.ll +++ /dev/null @@ -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 -} diff --git a/llvm/test/Transforms/EarlyCSE/AArch64/lit.local.cfg b/llvm/test/Transforms/EarlyCSE/AArch64/lit.local.cfg deleted file mode 100644 index 6642d287068..00000000000 --- a/llvm/test/Transforms/EarlyCSE/AArch64/lit.local.cfg +++ /dev/null @@ -1,5 +0,0 @@ -config.suffixes = ['.ll'] - -targets = set(config.root.targets_to_build.split()) -if not 'AArch64' in targets: - config.unsupported = True diff --git a/llvm/test/Transforms/EarlyCSE/AMDGPU/lit.local.cfg b/llvm/test/Transforms/EarlyCSE/AMDGPU/lit.local.cfg deleted file mode 100644 index 4536d089640..00000000000 --- a/llvm/test/Transforms/EarlyCSE/AMDGPU/lit.local.cfg +++ /dev/null @@ -1,5 +0,0 @@ -config.suffixes = ['.ll'] - -targets = set(config.root.targets_to_build.split()) -if not 'AMDGPU' in targets: - config.unsupported = True diff --git a/llvm/test/Transforms/EarlyCSE/AMDGPU/memrealtime.ll b/llvm/test/Transforms/EarlyCSE/AMDGPU/memrealtime.ll deleted file mode 100644 index 6b42ee8d71e..00000000000 --- a/llvm/test/Transforms/EarlyCSE/AMDGPU/memrealtime.ll +++ /dev/null @@ -1,43 +0,0 @@ -; RUN: opt -S -mtriple=amdgcn-amd-amdhsa -early-cse-memssa < %s | FileCheck %s -target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5" - -; CHECK-LABEL: @memrealtime( -; CHECK: call i64 @llvm.amdgcn.s.memrealtime() -; CHECK: call i64 @llvm.amdgcn.s.memrealtime() -define amdgpu_kernel void @memrealtime(i64 %cycles) #0 { -entry: - %0 = tail call i64 @llvm.amdgcn.s.memrealtime() - %cmp3 = icmp sgt i64 %cycles, 0 - br i1 %cmp3, label %while.body, label %while.end - -while.body: - %1 = tail call i64 @llvm.amdgcn.s.memrealtime() - %sub = sub nsw i64 %1, %0 - %cmp = icmp slt i64 %sub, %cycles - br i1 %cmp, label %while.body, label %while.end - -while.end: - ret void -} - -; CHECK-LABEL: @memtime( -; CHECK: call i64 @llvm.amdgcn.s.memtime() -; CHECK: call i64 @llvm.amdgcn.s.memtime() -define amdgpu_kernel void @memtime(i64 %cycles) #0 { -entry: - %0 = tail call i64 @llvm.amdgcn.s.memtime() - %cmp3 = icmp sgt i64 %cycles, 0 - br i1 %cmp3, label %while.body, label %while.end - -while.body: - %1 = tail call i64 @llvm.amdgcn.s.memtime() - %sub = sub nsw i64 %1, %0 - %cmp = icmp slt i64 %sub, %cycles - br i1 %cmp, label %while.body, label %while.end - -while.end: - ret void -} - -declare i64 @llvm.amdgcn.s.memrealtime() -declare i64 @llvm.amdgcn.s.memtime() diff --git a/llvm/test/Transforms/EarlyCSE/and_or.ll b/llvm/test/Transforms/EarlyCSE/and_or.ll deleted file mode 100644 index f9b88fea402..00000000000 --- a/llvm/test/Transforms/EarlyCSE/and_or.ll +++ /dev/null @@ -1,144 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -early-cse -S < %s | FileCheck %s -; RUN: opt -basicaa -early-cse-memssa -S < %s | FileCheck %s - -define i32 @test_01(i32 %a, i32 %b) { -; CHECK-LABEL: @test_01( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] -; CHECK: if.true: -; CHECK-NEXT: ret i32 [[A]] -; CHECK: if.false: -; CHECK-NEXT: ret i32 [[B]] -; -entry: - %cond = icmp slt i32 %a, %b - br i1 %cond, label %if.true, label %if.false - -if.true: - %cond2 = icmp slt i32 %a, %b - %x = select i1 %cond2, i32 %a, i32 %b - ret i32 %x - -if.false: - %cond3 = icmp slt i32 %a, %b - %y = select i1 %cond3, i32 %a, i32 %b - ret i32 %y -} - -define i32 @test_02(i32 %a, i32 %b, i1 %c) { -; CHECK-LABEL: @test_02( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[AND_COND:%.*]] = and i1 [[COND]], [[C:%.*]] -; CHECK-NEXT: br i1 [[AND_COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] -; CHECK: if.true: -; CHECK-NEXT: ret i32 [[A]] -; CHECK: if.false: -; CHECK-NEXT: [[Y:%.*]] = select i1 [[COND]], i32 [[A]], i32 [[B]] -; CHECK-NEXT: ret i32 [[Y]] -; -entry: - %cond = icmp slt i32 %a, %b - %and.cond = and i1 %cond, %c - br i1 %and.cond, label %if.true, label %if.false - -if.true: - %cond2 = icmp slt i32 %a, %b - %x = select i1 %cond2, i32 %a, i32 %b - ret i32 %x - -if.false: - %cond3 = icmp slt i32 %a, %b - %y = select i1 %cond3, i32 %a, i32 %b - ret i32 %y -} - -define i32 @test_03(i32 %a, i32 %b, i1 %c) { -; CHECK-LABEL: @test_03( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[COND]], [[C:%.*]] -; CHECK-NEXT: br i1 [[OR_COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] -; CHECK: if.true: -; CHECK-NEXT: [[X:%.*]] = select i1 [[COND]], i32 [[A]], i32 [[B]] -; CHECK-NEXT: ret i32 [[X]] -; CHECK: if.false: -; CHECK-NEXT: ret i32 [[B]] -; -entry: - %cond = icmp slt i32 %a, %b - %or.cond = or i1 %cond, %c - br i1 %or.cond, label %if.true, label %if.false - -if.true: - %cond2 = icmp slt i32 %a, %b - %x = select i1 %cond2, i32 %a, i32 %b - ret i32 %x - -if.false: - %cond3 = icmp slt i32 %a, %b - %y = select i1 %cond3, i32 %a, i32 %b - ret i32 %y -} - -define i32 @test_04(i32 %a, i32 %b, i1 %c1, i1 %c2) { -; CHECK-LABEL: @test_04( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[AND_COND1:%.*]] = and i1 [[COND]], [[C1:%.*]] -; CHECK-NEXT: [[AND_COND2:%.*]] = and i1 [[AND_COND1]], [[C2:%.*]] -; CHECK-NEXT: br i1 [[AND_COND2]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] -; CHECK: if.true: -; CHECK-NEXT: ret i32 [[A]] -; CHECK: if.false: -; CHECK-NEXT: [[Y:%.*]] = select i1 [[COND]], i32 [[A]], i32 [[B]] -; CHECK-NEXT: ret i32 [[Y]] -; -entry: - %cond = icmp slt i32 %a, %b - %and.cond1 = and i1 %cond, %c1 - %and.cond2 = and i1 %and.cond1, %c2 - br i1 %and.cond2, label %if.true, label %if.false - -if.true: - %cond2 = icmp slt i32 %a, %b - %x = select i1 %cond2, i32 %a, i32 %b - ret i32 %x - -if.false: - %cond3 = icmp slt i32 %a, %b - %y = select i1 %cond3, i32 %a, i32 %b - ret i32 %y -} - -define i32 @test_05(i32 %a, i32 %b, i1 %c1, i1 %c2) { -; CHECK-LABEL: @test_05( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[OR_COND1:%.*]] = or i1 [[COND]], [[C1:%.*]] -; CHECK-NEXT: [[OR_COND2:%.*]] = or i1 [[OR_COND1]], [[C2:%.*]] -; CHECK-NEXT: br i1 [[OR_COND2]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] -; CHECK: if.true: -; CHECK-NEXT: [[X:%.*]] = select i1 [[COND]], i32 [[A]], i32 [[B]] -; CHECK-NEXT: ret i32 [[X]] -; CHECK: if.false: -; CHECK-NEXT: ret i32 [[B]] -; -entry: - %cond = icmp slt i32 %a, %b - %or.cond1 = or i1 %cond, %c1 - %or.cond2 = or i1 %or.cond1, %c2 - br i1 %or.cond2, label %if.true, label %if.false - -if.true: - %cond2 = icmp slt i32 %a, %b - %x = select i1 %cond2, i32 %a, i32 %b - ret i32 %x - -if.false: - %cond3 = icmp slt i32 %a, %b - %y = select i1 %cond3, i32 %a, i32 %b - ret i32 %y -} diff --git a/llvm/test/Transforms/EarlyCSE/atomics.ll b/llvm/test/Transforms/EarlyCSE/atomics.ll deleted file mode 100644 index 7881be7bd9e..00000000000 --- a/llvm/test/Transforms/EarlyCSE/atomics.ll +++ /dev/null @@ -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 -} diff --git a/llvm/test/Transforms/EarlyCSE/basic.ll b/llvm/test/Transforms/EarlyCSE/basic.ll deleted file mode 100644 index 5797475c809..00000000000 --- a/llvm/test/Transforms/EarlyCSE/basic.ll +++ /dev/null @@ -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 -} diff --git a/llvm/test/Transforms/EarlyCSE/commute.ll b/llvm/test/Transforms/EarlyCSE/commute.ll deleted file mode 100644 index 488acf69ea4..00000000000 --- a/llvm/test/Transforms/EarlyCSE/commute.ll +++ /dev/null @@ -1,546 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; 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 -} - -; These two tests make sure we still consider it a match when the RHS of the -; compares are different. -define i8 @abs_different_constants(i8 %a) { -; CHECK-LABEL: @abs_different_constants( -; CHECK-NEXT: [[NEG:%.*]] = sub i8 0, [[A:%.*]] -; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i8 [[A]], -1 -; 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, -1 - %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_different_constants(i8 %a) { -; CHECK-LABEL: @nabs_different_constants( -; CHECK-NEXT: [[NEG:%.*]] = sub i8 0, [[A:%.*]] -; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 [[A]], 0 -; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 [[A]], -1 -; 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, -1 - %m1 = select i1 %cmp1, i8 %a, i8 %neg - %m2 = select i1 %cmp2, i8 %neg, i8 %a - %r = xor i8 %m2, %m1 - ret i8 %r -} - -; https://bugs.llvm.org/show_bug.cgi?id=41101 -; Detect equivalence of selects with commuted operands: 'not' cond. - -define i32 @select_not_cond(i1 %cond, i32 %t, i32 %f) { -; CHECK-LABEL: @select_not_cond( -; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[COND:%.*]], true -; CHECK-NEXT: [[M1:%.*]] = select i1 [[COND]], i32 [[T:%.*]], i32 [[F:%.*]] -; CHECK-NEXT: ret i32 0 -; - %not = xor i1 %cond, -1 - %m1 = select i1 %cond, i32 %t, i32 %f - %m2 = select i1 %not, i32 %f, i32 %t - %r = xor i32 %m2, %m1 - ret i32 %r -} - -; Detect equivalence of selects with commuted operands: 'not' cond with vector select. - -define <2 x double> @select_not_cond_commute_vec(<2 x i1> %cond, <2 x double> %t, <2 x double> %f) { -; CHECK-LABEL: @select_not_cond_commute_vec( -; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i1> [[COND:%.*]], <i1 true, i1 true> -; CHECK-NEXT: [[M1:%.*]] = select <2 x i1> [[COND]], <2 x double> [[T:%.*]], <2 x double> [[F:%.*]] -; CHECK-NEXT: ret <2 x double> <double 1.000000e+00, double 1.000000e+00> -; - %not = xor <2 x i1> %cond, <i1 -1, i1 -1> - %m1 = select <2 x i1> %cond, <2 x double> %t, <2 x double> %f - %m2 = select <2 x i1> %not, <2 x double> %f, <2 x double> %t - %r = fdiv nnan <2 x double> %m1, %m2 - ret <2 x double> %r -} - -; Negative test - select ops must be commuted. - -define i32 @select_not_cond_wrong_select_ops(i1 %cond, i32 %t, i32 %f) { -; CHECK-LABEL: @select_not_cond_wrong_select_ops( -; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[COND:%.*]], true -; CHECK-NEXT: [[M1:%.*]] = select i1 [[COND]], i32 [[T:%.*]], i32 [[F:%.*]] -; CHECK-NEXT: [[M2:%.*]] = select i1 [[NOT]], i32 [[T]], i32 [[F]] -; CHECK-NEXT: [[R:%.*]] = xor i32 [[M2]], [[M1]] -; CHECK-NEXT: ret i32 [[R]] -; - %not = xor i1 %cond, -1 - %m1 = select i1 %cond, i32 %t, i32 %f - %m2 = select i1 %not, i32 %t, i32 %f - %r = xor i32 %m2, %m1 - ret i32 %r -} - -; Negative test - not a 'not'. - -define i32 @select_not_cond_wrong_cond(i1 %cond, i32 %t, i32 %f) { -; CHECK-LABEL: @select_not_cond_wrong_cond( -; CHECK-NEXT: [[M1:%.*]] = select i1 [[COND:%.*]], i32 [[T:%.*]], i32 [[F:%.*]] -; CHECK-NEXT: [[M2:%.*]] = select i1 [[COND]], i32 [[F]], i32 [[T]] -; CHECK-NEXT: [[R:%.*]] = xor i32 [[M2]], [[M1]] -; CHECK-NEXT: ret i32 [[R]] -; - %not = xor i1 %cond, -2 - %m1 = select i1 %cond, i32 %t, i32 %f - %m2 = select i1 %not, i32 %f, i32 %t - %r = xor i32 %m2, %m1 - ret i32 %r -} - -; Detect equivalence of selects with commuted operands: inverted pred with fcmps. - -define i32 @select_invert_pred_cond(float %x, i32 %t, i32 %f) { -; CHECK-LABEL: @select_invert_pred_cond( -; CHECK-NEXT: [[COND:%.*]] = fcmp ueq float [[X:%.*]], 4.200000e+01 -; CHECK-NEXT: [[INVCOND:%.*]] = fcmp one float [[X]], 4.200000e+01 -; CHECK-NEXT: [[M1:%.*]] = select i1 [[COND]], i32 [[T:%.*]], i32 [[F:%.*]] -; CHECK-NEXT: ret i32 0 -; - %cond = fcmp ueq float %x, 42.0 - %invcond = fcmp one float %x, 42.0 - %m1 = select i1 %cond, i32 %t, i32 %f - %m2 = select i1 %invcond, i32 %f, i32 %t - %r = xor i32 %m2, %m1 - ret i32 %r -} - -; Detect equivalence of selects with commuted operands: inverted pred with icmps and vectors. - -define <2 x i32> @select_invert_pred_cond_commute_vec(<2 x i8> %x, <2 x i32> %t, <2 x i32> %f) { -; CHECK-LABEL: @select_invert_pred_cond_commute_vec( -; CHECK-NEXT: [[COND:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 42, i8 -1> -; CHECK-NEXT: [[INVCOND:%.*]] = icmp sle <2 x i8> [[X]], <i8 42, i8 -1> -; CHECK-NEXT: [[M1:%.*]] = select <2 x i1> [[COND]], <2 x i32> [[T:%.*]], <2 x i32> [[F:%.*]] -; CHECK-NEXT: ret <2 x i32> zeroinitializer -; - %cond = icmp sgt <2 x i8> %x, <i8 42, i8 -1> - %invcond = icmp sle <2 x i8> %x, <i8 42, i8 -1> - %m1 = select <2 x i1> %cond, <2 x i32> %t, <2 x i32> %f - %m2 = select <2 x i1> %invcond, <2 x i32> %f, <2 x i32> %t - %r = xor <2 x i32> %m1, %m2 - ret <2 x i32> %r -} - -; Negative test - select ops must be commuted. - -define i32 @select_invert_pred_wrong_select_ops(float %x, i32 %t, i32 %f) { -; CHECK-LABEL: @select_invert_pred_wrong_select_ops( -; CHECK-NEXT: [[COND:%.*]] = fcmp ueq float [[X:%.*]], 4.200000e+01 -; CHECK-NEXT: [[INVCOND:%.*]] = fcmp one float [[X]], 4.200000e+01 -; CHECK-NEXT: [[M1:%.*]] = select i1 [[COND]], i32 [[F:%.*]], i32 [[T:%.*]] -; CHECK-NEXT: [[M2:%.*]] = select i1 [[INVCOND]], i32 [[F]], i32 [[T]] -; CHECK-NEXT: [[R:%.*]] = xor i32 [[M2]], [[M1]] -; CHECK-NEXT: ret i32 [[R]] -; - %cond = fcmp ueq float %x, 42.0 - %invcond = fcmp one float %x, 42.0 - %m1 = select i1 %cond, i32 %f, i32 %t - %m2 = select i1 %invcond, i32 %f, i32 %t - %r = xor i32 %m2, %m1 - ret i32 %r -} - -; Negative test - not an inverted predicate. - -define i32 @select_invert_pred_wrong_cond(float %x, i32 %t, i32 %f) { -; CHECK-LABEL: @select_invert_pred_wrong_cond( -; CHECK-NEXT: [[COND:%.*]] = fcmp ueq float [[X:%.*]], 4.200000e+01 -; CHECK-NEXT: [[INVCOND:%.*]] = fcmp une float [[X]], 4.200000e+01 -; CHECK-NEXT: [[M1:%.*]] = select i1 [[COND]], i32 [[T:%.*]], i32 [[F:%.*]] -; CHECK-NEXT: [[M2:%.*]] = select i1 [[INVCOND]], i32 [[F]], i32 [[T]] -; CHECK-NEXT: [[R:%.*]] = xor i32 [[M2]], [[M1]] -; CHECK-NEXT: ret i32 [[R]] -; - %cond = fcmp ueq float %x, 42.0 - %invcond = fcmp une float %x, 42.0 - %m1 = select i1 %cond, i32 %t, i32 %f - %m2 = select i1 %invcond, i32 %f, i32 %t - %r = xor i32 %m2, %m1 - ret i32 %r -} - -; Negative test - cmp ops must match. - -define i32 @select_invert_pred_wrong_cmp_ops(float %x, i32 %t, i32 %f) { -; CHECK-LABEL: @select_invert_pred_wrong_cmp_ops( -; CHECK-NEXT: [[COND:%.*]] = fcmp ueq float [[X:%.*]], 4.200000e+01 -; CHECK-NEXT: [[INVCOND:%.*]] = fcmp one float [[X]], 4.300000e+01 -; CHECK-NEXT: [[M1:%.*]] = select i1 [[COND]], i32 [[T:%.*]], i32 [[F:%.*]] -; CHECK-NEXT: [[M2:%.*]] = select i1 [[INVCOND]], i32 [[F]], i32 [[T]] -; CHECK-NEXT: [[R:%.*]] = xor i32 [[M2]], [[M1]] -; CHECK-NEXT: ret i32 [[R]] -; - %cond = fcmp ueq float %x, 42.0 - %invcond = fcmp one float %x, 43.0 - %m1 = select i1 %cond, i32 %t, i32 %f - %m2 = select i1 %invcond, i32 %f, i32 %t - %r = xor i32 %m2, %m1 - ret i32 %r -} - -; If we have both an inverted predicate and a 'not' op, recognize the double-negation. - -define i32 @select_not_invert_pred_cond(i8 %x, i32 %t, i32 %f) { -; CHECK-LABEL: @select_not_invert_pred_cond( -; CHECK-NEXT: [[COND:%.*]] = icmp ugt i8 [[X:%.*]], 42 -; CHECK-NEXT: [[INVCOND:%.*]] = icmp ule i8 [[X]], 42 -; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[INVCOND]], true -; CHECK-NEXT: [[M1:%.*]] = select i1 [[COND]], i32 [[T:%.*]], i32 [[F:%.*]] -; CHECK-NEXT: ret i32 0 -; - %cond = icmp ugt i8 %x, 42 - %invcond = icmp ule i8 %x, 42 - %not = xor i1 %invcond, -1 - %m1 = select i1 %cond, i32 %t, i32 %f - %m2 = select i1 %not, i32 %t, i32 %f - %r = sub i32 %m1, %m2 - ret i32 %r -} - -; If we have both an inverted predicate and a 'not' op, recognize the double-negation. - -define i32 @select_not_invert_pred_cond_commute(i8 %x, i8 %y, i32 %t, i32 %f) { -; CHECK-LABEL: @select_not_invert_pred_cond_commute( -; CHECK-NEXT: [[INVCOND:%.*]] = icmp ule i8 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[INVCOND]], true -; CHECK-NEXT: [[M2:%.*]] = select i1 [[NOT]], i32 [[T:%.*]], i32 [[F:%.*]] -; CHECK-NEXT: [[COND:%.*]] = icmp ugt i8 [[X]], [[Y]] -; CHECK-NEXT: ret i32 0 -; - %invcond = icmp ule i8 %x, %y - %not = xor i1 %invcond, -1 - %m2 = select i1 %not, i32 %t, i32 %f - %cond = icmp ugt i8 %x, %y - %m1 = select i1 %cond, i32 %t, i32 %f - %r = sub i32 %m2, %m1 - ret i32 %r -} - -; Negative test - not an inverted predicate. - -define i32 @select_not_invert_pred_cond_wrong_pred(i8 %x, i8 %y, i32 %t, i32 %f) { -; CHECK-LABEL: @select_not_invert_pred_cond_wrong_pred( -; CHECK-NEXT: [[INVCOND:%.*]] = icmp ult i8 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[INVCOND]], true -; CHECK-NEXT: [[M2:%.*]] = select i1 [[NOT]], i32 [[T:%.*]], i32 [[F:%.*]] -; CHECK-NEXT: [[COND:%.*]] = icmp ugt i8 [[X]], [[Y]] -; CHECK-NEXT: [[M1:%.*]] = select i1 [[COND]], i32 [[T]], i32 [[F]] -; CHECK-NEXT: [[R:%.*]] = sub i32 [[M2]], [[M1]] -; CHECK-NEXT: ret i32 [[R]] -; - %invcond = icmp ult i8 %x, %y - %not = xor i1 %invcond, -1 - %m2 = select i1 %not, i32 %t, i32 %f - %cond = icmp ugt i8 %x, %y - %m1 = select i1 %cond, i32 %t, i32 %f - %r = sub i32 %m2, %m1 - ret i32 %r -} - -; Negative test - cmp ops must match. - -define i32 @select_not_invert_pred_cond_wrong_cmp_op(i8 %x, i8 %y, i32 %t, i32 %f) { -; CHECK-LABEL: @select_not_invert_pred_cond_wrong_cmp_op( -; CHECK-NEXT: [[INVCOND:%.*]] = icmp ule i8 [[X:%.*]], 42 -; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[INVCOND]], true -; CHECK-NEXT: [[M2:%.*]] = select i1 [[NOT]], i32 [[T:%.*]], i32 [[F:%.*]] -; CHECK-NEXT: [[COND:%.*]] = icmp ugt i8 [[X]], [[Y:%.*]] -; CHECK-NEXT: [[M1:%.*]] = select i1 [[COND]], i32 [[T]], i32 [[F]] -; CHECK-NEXT: [[R:%.*]] = sub i32 [[M2]], [[M1]] -; CHECK-NEXT: ret i32 [[R]] -; - %invcond = icmp ule i8 %x, 42 - %not = xor i1 %invcond, -1 - %m2 = select i1 %not, i32 %t, i32 %f - %cond = icmp ugt i8 %x, %y - %m1 = select i1 %cond, i32 %t, i32 %f - %r = sub i32 %m2, %m1 - ret i32 %r -} - -; Negative test - select ops must be same (and not commuted). - -define i32 @select_not_invert_pred_cond_wrong_select_op(i8 %x, i8 %y, i32 %t, i32 %f) { -; CHECK-LABEL: @select_not_invert_pred_cond_wrong_select_op( -; CHECK-NEXT: [[INVCOND:%.*]] = icmp ule i8 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[INVCOND]], true -; CHECK-NEXT: [[M2:%.*]] = select i1 [[NOT]], i32 [[T:%.*]], i32 [[F:%.*]] -; CHECK-NEXT: [[COND:%.*]] = icmp ugt i8 [[X]], [[Y]] -; CHECK-NEXT: [[M1:%.*]] = select i1 [[COND]], i32 [[F]], i32 [[T]] -; CHECK-NEXT: [[R:%.*]] = sub i32 [[M2]], [[M1]] -; CHECK-NEXT: ret i32 [[R]] -; - %invcond = icmp ule i8 %x, %y - %not = xor i1 %invcond, -1 - %m2 = select i1 %not, i32 %t, i32 %f - %cond = icmp ugt i8 %x, %y - %m1 = select i1 %cond, i32 %f, i32 %t - %r = sub i32 %m2, %m1 - ret i32 %r -} diff --git a/llvm/test/Transforms/EarlyCSE/conditional.ll b/llvm/test/Transforms/EarlyCSE/conditional.ll deleted file mode 100644 index d2bab4c9aca..00000000000 --- a/llvm/test/Transforms/EarlyCSE/conditional.ll +++ /dev/null @@ -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 -} - diff --git a/llvm/test/Transforms/EarlyCSE/const-speculation.ll b/llvm/test/Transforms/EarlyCSE/const-speculation.ll deleted file mode 100644 index 5b7f2f5b698..00000000000 --- a/llvm/test/Transforms/EarlyCSE/const-speculation.ll +++ /dev/null @@ -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 -} diff --git a/llvm/test/Transforms/EarlyCSE/debug-info-undef.ll b/llvm/test/Transforms/EarlyCSE/debug-info-undef.ll deleted file mode 100644 index 4615aa264b6..00000000000 --- a/llvm/test/Transforms/EarlyCSE/debug-info-undef.ll +++ /dev/null @@ -1,69 +0,0 @@ -; RUN: opt -S %s -early-cse | FileCheck %s - -target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" - -@a = global i8 25, align 1, !dbg !0 - -define signext i16 @b() !dbg !12 { -entry: - call void @llvm.dbg.value(metadata i16 23680, metadata !17, metadata !DIExpression()), !dbg !18 - %0 = load i8, i8* @a, align 1, !dbg !19, !tbaa !20 - %conv = sext i8 %0 to i16, !dbg !19 - -; CHECK: call void @llvm.dbg.value(metadata i16 undef, metadata !17, metadata !DIExpression()), !dbg !18 -; CHECK-NEXT: call i32 (...) @optimize_me_not() - - call void @llvm.dbg.value(metadata i16 %conv, metadata !17, metadata !DIExpression()), !dbg !18 - %call = call i32 (...) @optimize_me_not(), !dbg !23 - %1 = load i8, i8* @a, align 1, !dbg !24, !tbaa !20 - %conv1 = sext i8 %1 to i16, !dbg !24 - ret i16 %conv1, !dbg !25 -} - -declare void @llvm.dbg.declare(metadata, metadata, metadata) -declare i32 @optimize_me_not(...) - -define i32 @main() !dbg !26 { -entry: - %call = call signext i16 @b(), !dbg !30 - ret i32 0, !dbg !31 -} - -declare void @llvm.dbg.value(metadata, metadata, metadata) - -!llvm.dbg.cu = !{!2} -!llvm.module.flags = !{!7, !8, !9, !10} -!llvm.ident = !{!11} - -!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) -!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) -!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) -!3 = !DIFile(filename: "patatino.c", directory: "/Users/davide/llvm-monorepo/llvm-mono/build/bin") -!4 = !{} -!5 = !{!0} -!6 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) -!7 = !{i32 2, !"Dwarf Version", i32 4} -!8 = !{i32 2, !"Debug Info Version", i32 3} -!9 = !{i32 1, !"wchar_size", i32 4} -!10 = !{i32 7, !"PIC Level", i32 2} -!11 = !{!"clang version 8.0.0 "} -!12 = distinct !DISubprogram(name: "b", scope: !3, file: !3, line: 2, type: !13, scopeLine: 2, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !16) -!13 = !DISubroutineType(types: !14) -!14 = !{!15} -!15 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed) -!16 = !{!17} -!17 = !DILocalVariable(name: "i", scope: !12, file: !3, line: 3, type: !15) -!18 = !DILocation(line: 3, column: 9, scope: !12) -!19 = !DILocation(line: 4, column: 7, scope: !12) -!20 = !{!21, !21, i64 0} -!21 = !{!"omnipotent char", !22, i64 0} -!22 = !{!"Simple C/C++ TBAA"} -!23 = !DILocation(line: 5, column: 3, scope: !12) -!24 = !DILocation(line: 6, column: 10, scope: !12) -!25 = !DILocation(line: 6, column: 3, scope: !12) -!26 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 8, type: !27, scopeLine: 8, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4) -!27 = !DISubroutineType(types: !28) -!28 = !{!29} -!29 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) -!30 = !DILocation(line: 8, column: 14, scope: !26) -!31 = !DILocation(line: 8, column: 19, scope: !26) diff --git a/llvm/test/Transforms/EarlyCSE/debuginfo-dce.ll b/llvm/test/Transforms/EarlyCSE/debuginfo-dce.ll deleted file mode 100644 index 35d0fd18496..00000000000 --- a/llvm/test/Transforms/EarlyCSE/debuginfo-dce.ll +++ /dev/null @@ -1,64 +0,0 @@ -; RUN: opt -early-cse -S %s -o - | FileCheck %s -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" - -; Function Attrs: nounwind uwtable -define i32 @foo() !dbg !6 { -entry: - %0 = call i64 @llvm.ctpop.i64(i64 0), !dbg !14 - %1 = inttoptr i64 %0 to i32*, !dbg !14 - call void @llvm.dbg.value(metadata i32* %1, i64 0, metadata !11, metadata !13), !dbg !14 -; CHECK: call void @llvm.dbg.value(metadata i64 0, metadata !11, metadata !DIExpression()), !dbg !13 - %call = call i32* (...) @baa(), !dbg !15 - %2 = ptrtoint i32* %call to i64, !dbg !16 - %3 = inttoptr i64 %2 to i32*, !dbg !16 - call void @llvm.dbg.value(metadata i32* %3, i64 0, metadata !11, metadata !13), !dbg !14 - %tobool = icmp ne i32* %3, null, !dbg !17 - br i1 %tobool, label %if.end, label %if.then, !dbg !19 - -if.then: ; preds = %entry - br label %cleanup, !dbg !20 - -if.end: ; preds = %entry - %4 = ptrtoint i32* %3 to i32, !dbg !21 - br label %cleanup, !dbg !22 - -cleanup: ; preds = %if.end, %if.then - %retval.0 = phi i32 [ %4, %if.end ], [ 0, %if.then ] - ret i32 %retval.0, !dbg !22 -} - -declare i32* @baa(...) - -; Function Attrs: nounwind readnone -declare i64 @llvm.ctpop.i64(i64) - -; Function Attrs: nounwind readnone -declare void @llvm.dbg.value(metadata, i64, metadata, metadata) - -!llvm.dbg.cu = !{!0} -!llvm.module.flags = !{!3, !4} -!llvm.ident = !{!5} - -!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) -!1 = !DIFile(filename: "test.c", directory: "/dir") -!2 = !{} -!3 = !{i32 2, !"Dwarf Version", i32 4} -!4 = !{i32 2, !"Debug Info Version", i32 3} -!5 = !{!"clang version 6.0.0"} -!6 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 3, type: !7, isLocal: false, isDefinition: true, scopeLine: 3, isOptimized: true, unit: !0, retainedNodes: !10) -!7 = !DISubroutineType(types: !8) -!8 = !{!9} -!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) -!10 = !{!11} -!11 = !DILocalVariable(name: "ptr", scope: !6, file: !1, line: 4, type: !12) -!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 64) -!13 = !DIExpression() -!14 = !DILocation(line: 4, column: 8, scope: !6) -!15 = !DILocation(line: 5, column: 9, scope: !6) -!16 = !DILocation(line: 5, column: 7, scope: !6) -!17 = !DILocation(line: 7, column: 7, scope: !18) -!18 = distinct !DILexicalBlock(scope: !6, file: !1, line: 7, column: 6) -!19 = !DILocation(line: 7, column: 6, scope: !6) -!20 = !DILocation(line: 8, column: 5, scope: !18) -!21 = !DILocation(line: 10, column: 10, scope: !6) -!22 = !DILocation(line: 11, column: 1, scope: !6) diff --git a/llvm/test/Transforms/EarlyCSE/edge.ll b/llvm/test/Transforms/EarlyCSE/edge.ll deleted file mode 100644 index dd8c1b7671f..00000000000 --- a/llvm/test/Transforms/EarlyCSE/edge.ll +++ /dev/null @@ -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 -} diff --git a/llvm/test/Transforms/EarlyCSE/fence.ll b/llvm/test/Transforms/EarlyCSE/fence.ll deleted file mode 100644 index 5eefe82cd49..00000000000 --- a/llvm/test/Transforms/EarlyCSE/fence.ll +++ /dev/null @@ -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 -} diff --git a/llvm/test/Transforms/EarlyCSE/flags.ll b/llvm/test/Transforms/EarlyCSE/flags.ll deleted file mode 100644 index 41ad20cf57c..00000000000 --- a/llvm/test/Transforms/EarlyCSE/flags.ll +++ /dev/null @@ -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 diff --git a/llvm/test/Transforms/EarlyCSE/floatingpoint.ll b/llvm/test/Transforms/EarlyCSE/floatingpoint.ll deleted file mode 100644 index d6811a3d648..00000000000 --- a/llvm/test/Transforms/EarlyCSE/floatingpoint.ll +++ /dev/null @@ -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 -} diff --git a/llvm/test/Transforms/EarlyCSE/globalsaa-memoryssa.ll b/llvm/test/Transforms/EarlyCSE/globalsaa-memoryssa.ll deleted file mode 100644 index 57dbdd88319..00000000000 --- a/llvm/test/Transforms/EarlyCSE/globalsaa-memoryssa.ll +++ /dev/null @@ -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 -} diff --git a/llvm/test/Transforms/EarlyCSE/guards.ll b/llvm/test/Transforms/EarlyCSE/guards.ll deleted file mode 100644 index de43264db6f..00000000000 --- a/llvm/test/Transforms/EarlyCSE/guards.ll +++ /dev/null @@ -1,528 +0,0 @@ -; RUN: opt -S -early-cse < %s | FileCheck %s -; RUN: opt < %s -S -basicaa -early-cse-memssa | FileCheck %s - -declare void @llvm.experimental.guard(i1,...) - -declare void @llvm.assume(i1) - -define i32 @test0(i32* %ptr, i1 %cond) { -; We can do store to load forwarding over a guard, since it does not -; clobber memory - -; CHECK-LABEL: @test0( -; CHECK-NEXT: store i32 40, i32* %ptr -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ] -; CHECK-NEXT: ret i32 40 - - store i32 40, i32* %ptr - call void(i1,...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ] - %rval = load i32, i32* %ptr - ret i32 %rval -} - -define i32 @test1(i32* %val, i1 %cond) { -; We can CSE loads over a guard, since it does not clobber memory - -; CHECK-LABEL: @test1( -; CHECK-NEXT: %val0 = load i32, i32* %val -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ] -; CHECK-NEXT: ret i32 0 - - %val0 = load i32, i32* %val - call void(i1,...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ] - %val1 = load i32, i32* %val - %rval = sub i32 %val0, %val1 - ret i32 %rval -} - -define i32 @test2() { -; Guards on "true" get removed - -; CHECK-LABEL: @test2( -; CHECK-NEXT: ret i32 0 - call void(i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ] - ret i32 0 -} - -define i32 @test3(i32 %val) { -; After a guard has executed the condition it was guarding is known to -; be true. - -; CHECK-LABEL: @test3( -; CHECK-NEXT: %cond0 = icmp slt i32 %val, 40 -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cond0) [ "deopt"() ] -; CHECK-NEXT: ret i32 -1 - - %cond0 = icmp slt i32 %val, 40 - call void(i1,...) @llvm.experimental.guard(i1 %cond0) [ "deopt"() ] - %cond1 = icmp slt i32 %val, 40 - call void(i1,...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ] - - %cond2 = icmp slt i32 %val, 40 - %rval = sext i1 %cond2 to i32 - ret i32 %rval -} - -define i32 @test3.unhandled(i32 %val) { -; After a guard has executed the condition it was guarding is known to -; be true. - -; CHECK-LABEL: @test3.unhandled( -; CHECK-NEXT: %cond0 = icmp slt i32 %val, 40 -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cond0) [ "deopt"() ] -; CHECK-NEXT: %cond1 = icmp sge i32 %val, 40 -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ] -; CHECK-NEXT: ret i32 0 - -; Demonstrates a case we do not yet handle (it is legal to fold %cond2 -; to false) - %cond0 = icmp slt i32 %val, 40 - call void(i1,...) @llvm.experimental.guard(i1 %cond0) [ "deopt"() ] - %cond1 = icmp sge i32 %val, 40 - call void(i1,...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ] - ret i32 0 -} - -define i32 @test4(i32 %val, i1 %c) { -; Same as test3, but with some control flow involved. - -; CHECK-LABEL: @test4( -; CHECK: entry: -; CHECK-NEXT: %cond0 = icmp slt i32 %val, 40 -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cond0 -; CHECK-NEXT: br label %bb0 - -; CHECK: bb0: -; CHECK-NEXT: %cond2 = icmp ult i32 %val, 200 -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cond2 -; CHECK-NEXT: br i1 %c, label %left, label %right - -; CHECK: left: -; CHECK-NEXT: ret i32 0 - -; CHECK: right: -; CHECK-NEXT: ret i32 20 - -entry: - %cond0 = icmp slt i32 %val, 40 - call void(i1,...) @llvm.experimental.guard(i1 %cond0) [ "deopt"() ] - %cond1 = icmp slt i32 %val, 40 - call void(i1,...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ] - br label %bb0 - -bb0: - %cond2 = icmp ult i32 %val, 200 - call void(i1,...) @llvm.experimental.guard(i1 %cond2) [ "deopt"() ] - br i1 %c, label %left, label %right - -left: - %cond3 = icmp ult i32 %val, 200 - call void(i1,...) @llvm.experimental.guard(i1 %cond3) [ "deopt"() ] - ret i32 0 - -right: - ret i32 20 -} - -define i32 @test5(i32 %val, i1 %c) { -; Same as test4, but the %left block has mutliple predecessors. - -; CHECK-LABEL: @test5( - -; CHECK: entry: -; CHECK-NEXT: %cond0 = icmp slt i32 %val, 40 -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cond0 -; CHECK-NEXT: br label %bb0 - -; CHECK: bb0: -; CHECK-NEXT: %cond2 = icmp ult i32 %val, 200 -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cond2 -; CHECK-NEXT: br i1 %c, label %left, label %right - -; CHECK: left: -; CHECK-NEXT: br label %right - -; CHECK: right: -; CHECK-NEXT: br label %left - -entry: - %cond0 = icmp slt i32 %val, 40 - call void(i1,...) @llvm.experimental.guard(i1 %cond0) [ "deopt"() ] - %cond1 = icmp slt i32 %val, 40 - call void(i1,...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ] - br label %bb0 - -bb0: - %cond2 = icmp ult i32 %val, 200 - call void(i1,...) @llvm.experimental.guard(i1 %cond2) [ "deopt"() ] - br i1 %c, label %left, label %right - -left: - %cond3 = icmp ult i32 %val, 200 - call void(i1,...) @llvm.experimental.guard(i1 %cond3) [ "deopt"() ] - br label %right - -right: - br label %left -} - -define void @test6(i1 %c, i32* %ptr) { -; Check that we do not DSE over calls to @llvm.experimental.guard. -; Guard intrinsics do _read_ memory, so th call to guard below needs -; to see the store of 500 to %ptr - -; CHECK-LABEL: @test6( -; CHECK-NEXT: store i32 500, i32* %ptr -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %c) [ "deopt"() ] -; CHECK-NEXT: store i32 600, i32* %ptr - - - store i32 500, i32* %ptr - call void(i1,...) @llvm.experimental.guard(i1 %c) [ "deopt"() ] - store i32 600, i32* %ptr - ret void -} - -define void @test07(i32 %a, i32 %b) { -; Check that we are able to remove the guards on the same condition even if the -; condition is not being recalculated. - -; CHECK-LABEL: @test07( -; CHECK-NEXT: %cmp = icmp eq i32 %a, %b -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] -; CHECK-NEXT: ret void - - %cmp = icmp eq i32 %a, %b - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - ret void -} - -define void @test08(i32 %a, i32 %b, i32* %ptr) { -; Check that we deal correctly with stores when removing guards in the same -; block in case when the condition is not recalculated. - -; CHECK-LABEL: @test08( -; CHECK-NEXT: %cmp = icmp eq i32 %a, %b -; CHECK-NEXT: store i32 100, i32* %ptr -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] -; CHECK-NEXT: store i32 400, i32* %ptr -; CHECK-NEXT: ret void - - %cmp = icmp eq i32 %a, %b - store i32 100, i32* %ptr - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - store i32 200, i32* %ptr - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - store i32 300, i32* %ptr - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - store i32 400, i32* %ptr - ret void -} - -define void @test09(i32 %a, i32 %b, i1 %c, i32* %ptr) { -; Similar to test08, but with more control flow. -; TODO: Can we get rid of the store in the end of entry given that it is -; post-dominated by other stores? - -; CHECK-LABEL: @test09( -; CHECK: entry: -; CHECK-NEXT: %cmp = icmp eq i32 %a, %b -; CHECK-NEXT: store i32 100, i32* %ptr -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] -; CHECK-NEXT: store i32 400, i32* %ptr -; CHECK-NEXT: br i1 %c, label %if.true, label %if.false -; CHECK: if.true: -; CHECK-NEXT: store i32 500, i32* %ptr -; CHECK-NEXT: br label %merge -; CHECK: if.false: -; CHECK-NEXT: store i32 600, i32* %ptr -; CHECK-NEXT: br label %merge -; CHECK: merge: -; CHECK-NEXT: ret void - -entry: - %cmp = icmp eq i32 %a, %b - store i32 100, i32* %ptr - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - store i32 200, i32* %ptr - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - store i32 300, i32* %ptr - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - store i32 400, i32* %ptr - br i1 %c, label %if.true, label %if.false - -if.true: - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - store i32 500, i32* %ptr - br label %merge - -if.false: - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - store i32 600, i32* %ptr - br label %merge - -merge: - ret void -} - -define void @test10(i32 %a, i32 %b, i1 %c, i32* %ptr) { -; Make sure that non-dominating guards do not cause other guards removal. - -; CHECK-LABEL: @test10( -; CHECK: entry: -; CHECK-NEXT: %cmp = icmp eq i32 %a, %b -; CHECK-NEXT: br i1 %c, label %if.true, label %if.false -; CHECK: if.true: -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] -; CHECK-NEXT: store i32 100, i32* %ptr -; CHECK-NEXT: br label %merge -; CHECK: if.false: -; CHECK-NEXT: store i32 200, i32* %ptr -; CHECK-NEXT: br label %merge -; CHECK: merge: -; CHECK-NEXT: store i32 300, i32* %ptr -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] -; CHECK-NEXT: store i32 400, i32* %ptr -; CHECK-NEXT: ret void - -entry: - %cmp = icmp eq i32 %a, %b - br i1 %c, label %if.true, label %if.false - -if.true: - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - store i32 100, i32* %ptr - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - br label %merge - -if.false: - store i32 200, i32* %ptr - br label %merge - -merge: - store i32 300, i32* %ptr - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - store i32 400, i32* %ptr - ret void -} - -define void @test11(i32 %a, i32 %b, i32* %ptr) { -; Make sure that branching condition is applied to guards. - -; CHECK-LABEL: @test11( -; CHECK: entry: -; CHECK-NEXT: %cmp = icmp eq i32 %a, %b -; CHECK-NEXT: br i1 %cmp, label %if.true, label %if.false -; CHECK: if.true: -; CHECK-NEXT: br label %merge -; CHECK: if.false: -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ] -; CHECK-NEXT: br label %merge -; CHECK: merge: -; CHECK-NEXT: ret void - -entry: - %cmp = icmp eq i32 %a, %b - br i1 %cmp, label %if.true, label %if.false - -if.true: - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - br label %merge - -if.false: - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - br label %merge - -merge: - ret void -} - -define void @test12(i32 %a, i32 %b) { -; Check that the assume marks its condition as being true (and thus allows to -; eliminate the dominated guards). - -; CHECK-LABEL: @test12( -; CHECK-NEXT: %cmp = icmp eq i32 %a, %b -; CHECK-NEXT: call void @llvm.assume(i1 %cmp) -; CHECK-NEXT: ret void - - %cmp = icmp eq i32 %a, %b - call void @llvm.assume(i1 %cmp) - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - ret void -} - -define void @test13(i32 %a, i32 %b, i32* %ptr) { -; Check that we deal correctly with stores when removing guards due to assume. - -; CHECK-LABEL: @test13( -; CHECK-NEXT: %cmp = icmp eq i32 %a, %b -; CHECK-NEXT: call void @llvm.assume(i1 %cmp) -; CHECK-NEXT: store i32 400, i32* %ptr -; CHECK-NEXT: ret void - - %cmp = icmp eq i32 %a, %b - call void @llvm.assume(i1 %cmp) - store i32 100, i32* %ptr - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - store i32 200, i32* %ptr - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - store i32 300, i32* %ptr - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - store i32 400, i32* %ptr - ret void -} - -define void @test14(i32 %a, i32 %b, i1 %c, i32* %ptr) { -; Similar to test13, but with more control flow. -; TODO: Can we get rid of the store in the end of entry given that it is -; post-dominated by other stores? - -; CHECK-LABEL: @test14( -; CHECK: entry: -; CHECK-NEXT: %cmp = icmp eq i32 %a, %b -; CHECK-NEXT: call void @llvm.assume(i1 %cmp) -; CHECK-NEXT: store i32 400, i32* %ptr -; CHECK-NEXT: br i1 %c, label %if.true, label %if.false -; CHECK: if.true: -; CHECK-NEXT: store i32 500, i32* %ptr -; CHECK-NEXT: br label %merge -; CHECK: if.false: -; CHECK-NEXT: store i32 600, i32* %ptr -; CHECK-NEXT: br label %merge -; CHECK: merge: -; CHECK-NEXT: ret void - -entry: - %cmp = icmp eq i32 %a, %b - call void @llvm.assume(i1 %cmp) - store i32 100, i32* %ptr - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - store i32 200, i32* %ptr - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - store i32 300, i32* %ptr - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - store i32 400, i32* %ptr - br i1 %c, label %if.true, label %if.false - -if.true: - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - store i32 500, i32* %ptr - br label %merge - -if.false: - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - store i32 600, i32* %ptr - br label %merge - -merge: - ret void -} - -define void @test15(i32 %a, i32 %b, i1 %c, i32* %ptr) { -; Make sure that non-dominating assumes do not cause guards removal. - -; CHECK-LABEL: @test15( -; CHECK: entry: -; CHECK-NEXT: %cmp = icmp eq i32 %a, %b -; CHECK-NEXT: br i1 %c, label %if.true, label %if.false -; CHECK: if.true: -; CHECK-NEXT: call void @llvm.assume(i1 %cmp) -; CHECK-NEXT: store i32 100, i32* %ptr -; CHECK-NEXT: br label %merge -; CHECK: if.false: -; CHECK-NEXT: store i32 200, i32* %ptr -; CHECK-NEXT: br label %merge -; CHECK: merge: -; CHECK-NEXT: store i32 300, i32* %ptr -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] -; CHECK-NEXT: store i32 400, i32* %ptr -; CHECK-NEXT: ret void - -entry: - %cmp = icmp eq i32 %a, %b - br i1 %c, label %if.true, label %if.false - -if.true: - call void @llvm.assume(i1 %cmp) - store i32 100, i32* %ptr - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - br label %merge - -if.false: - store i32 200, i32* %ptr - br label %merge - -merge: - store i32 300, i32* %ptr - call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] - store i32 400, i32* %ptr - ret void -} - -define void @test16(i32 %a, i32 %b) { -; Check that we don't bother to do anything with assumes even if we know the -; condition being true. - -; CHECK-LABEL: @test16( -; CHECK-NEXT: %cmp = icmp eq i32 %a, %b -; CHECK-NEXT: call void @llvm.assume(i1 %cmp) -; CHECK-NEXT: call void @llvm.assume(i1 %cmp) -; CHECK-NEXT: ret void - - %cmp = icmp eq i32 %a, %b - call void @llvm.assume(i1 %cmp) - call void @llvm.assume(i1 %cmp) - ret void -} - -define void @test17(i32 %a, i32 %b, i1 %c, i32* %ptr) { -; Check that we don't bother to do anything with assumes even if we know the -; condition being true or false (includes come control flow). - -; CHECK-LABEL: @test17( -; CHECK: entry: -; CHECK-NEXT: %cmp = icmp eq i32 %a, %b -; CHECK-NEXT: br i1 %c, label %if.true, label %if.false -; CHECK: if.true: -; CHECK-NEXT: call void @llvm.assume(i1 %cmp) -; CHECK-NEXT: br label %merge -; CHECK: if.false: -; CHECK-NEXT: call void @llvm.assume(i1 %cmp) -; CHECK-NEXT: br label %merge -; CHECK: merge: -; CHECK-NEXT: ret void - -entry: - %cmp = icmp eq i32 %a, %b - br i1 %c, label %if.true, label %if.false - -if.true: - call void @llvm.assume(i1 %cmp) - br label %merge - -if.false: - call void @llvm.assume(i1 %cmp) - br label %merge - -merge: - ret void -} - -define void @test18(i1 %c) { -; Check that we don't bother to do anything with assumes even if we know the -; condition being true and not being an instruction. - -; CHECK-LABEL: @test18( -; CHECK-NEXT: call void @llvm.assume(i1 %c) -; CHECK-NEXT: call void @llvm.assume(i1 %c) -; CHECK-NEXT: ret void - - call void @llvm.assume(i1 %c) - call void @llvm.assume(i1 %c) - ret void -} diff --git a/llvm/test/Transforms/EarlyCSE/instsimplify-dom.ll b/llvm/test/Transforms/EarlyCSE/instsimplify-dom.ll deleted file mode 100644 index f41ce27a87e..00000000000 --- a/llvm/test/Transforms/EarlyCSE/instsimplify-dom.ll +++ /dev/null @@ -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( diff --git a/llvm/test/Transforms/EarlyCSE/int_sideeffect.ll b/llvm/test/Transforms/EarlyCSE/int_sideeffect.ll deleted file mode 100644 index 1dccaab5e5f..00000000000 --- a/llvm/test/Transforms/EarlyCSE/int_sideeffect.ll +++ /dev/null @@ -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 -} diff --git a/llvm/test/Transforms/EarlyCSE/intrinsics.ll b/llvm/test/Transforms/EarlyCSE/intrinsics.ll deleted file mode 100644 index 0fae469341d..00000000000 --- a/llvm/test/Transforms/EarlyCSE/intrinsics.ll +++ /dev/null @@ -1,36 +0,0 @@ -; RUN: opt < %s -S -mtriple=amdgcn-- -early-cse | FileCheck %s - -; CHECK-LABEL: @no_cse -; CHECK: call i32 @llvm.amdgcn.s.buffer.load.i32(<4 x i32> %in, i32 0, i32 0) -; CHECK: call i32 @llvm.amdgcn.s.buffer.load.i32(<4 x i32> %in, i32 4, i32 0) -define void @no_cse(i32 addrspace(1)* %out, <4 x i32> %in) { - %a = call i32 @llvm.amdgcn.s.buffer.load.i32(<4 x i32> %in, i32 0, i32 0) - %b = call i32 @llvm.amdgcn.s.buffer.load.i32(<4 x i32> %in, i32 4, i32 0) - %c = add i32 %a, %b - store i32 %c, i32 addrspace(1)* %out - ret void -} - -; CHECK-LABEL: @cse_zero_offset -; CHECK: [[CSE:%[a-z0-9A-Z]+]] = call i32 @llvm.amdgcn.s.buffer.load.i32(<4 x i32> %in, i32 0, i32 0) -; CHECK: add i32 [[CSE]], [[CSE]] -define void @cse_zero_offset(i32 addrspace(1)* %out, <4 x i32> %in) { - %a = call i32 @llvm.amdgcn.s.buffer.load.i32(<4 x i32> %in, i32 0, i32 0) - %b = call i32 @llvm.amdgcn.s.buffer.load.i32(<4 x i32> %in, i32 0, i32 0) - %c = add i32 %a, %b - store i32 %c, i32 addrspace(1)* %out - ret void -} - -; CHECK-LABEL: @cse_nonzero_offset -; CHECK: [[CSE:%[a-z0-9A-Z]+]] = call i32 @llvm.amdgcn.s.buffer.load.i32(<4 x i32> %in, i32 4, i32 0) -; CHECK: add i32 [[CSE]], [[CSE]] -define void @cse_nonzero_offset(i32 addrspace(1)* %out, <4 x i32> %in) { - %a = call i32 @llvm.amdgcn.s.buffer.load.i32(<4 x i32> %in, i32 4, i32 0) - %b = call i32 @llvm.amdgcn.s.buffer.load.i32(<4 x i32> %in, i32 4, i32 0) - %c = add i32 %a, %b - store i32 %c, i32 addrspace(1)* %out - ret void -} - -declare i32 @llvm.amdgcn.s.buffer.load.i32(<4 x i32> nocapture, i32, i32) diff --git a/llvm/test/Transforms/EarlyCSE/invariant-loads.ll b/llvm/test/Transforms/EarlyCSE/invariant-loads.ll deleted file mode 100644 index c3fa32d6fad..00000000000 --- a/llvm/test/Transforms/EarlyCSE/invariant-loads.ll +++ /dev/null @@ -1,158 +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 -} - -; By assumption, the call can't change contents of p -; LangRef is a bit unclear about whether the store is reachable, so -; for the moment we chose to be conservative and just assume it's valid -; to restore the same unchanging value. -define void @test_dse1(i32* %p) { -; CHECK-LABEL: @test_dse1 -; CHECK-NOT: store - %v1 = load i32, i32* %p, !invariant.load !{} - call void @clobber_and_use(i32 %v1) - store i32 %v1, i32* %p - ret void -} - -; By assumption, v1 must equal v2 (TODO) -define void @test_false_negative_dse2(i32* %p, i32 %v2) { -; CHECK-LABEL: @test_false_negative_dse2 -; CHECK: store - %v1 = load i32, i32* %p, !invariant.load !{} - call void @clobber_and_use(i32 %v1) - store i32 %v2, i32* %p - ret void -} - -; If we remove the load, we still start an invariant scope since -; it lets us remove later loads not explicitly marked invariant -define void @test_scope_start_without_load(i32* %p) { -; CHECK-LABEL: @test_scope_start_without_load -; CHECK: %v1 = load i32, i32* %p -; CHECK: %add = add i32 %v1, %v1 -; CHECK: call void @clobber_and_use(i32 %add) -; CHECK: call void @clobber_and_use(i32 %v1) -; CHECK: ret void - %v1 = load i32, i32* %p - %v2 = load i32, i32* %p, !invariant.load !{} - %add = add i32 %v1, %v2 - call void @clobber_and_use(i32 %add) - %v3 = load i32, i32* %p - call void @clobber_and_use(i32 %v3) - ret void -} - -; If we already have an invariant scope, don't want to start a new one -; with a potentially greater generation. This hides the earlier invariant -; load -define void @test_scope_restart(i32* %p) { -; CHECK-LABEL: @test_scope_restart -; CHECK: %v1 = load i32, i32* %p -; CHECK: call void @clobber_and_use(i32 %v1) -; CHECK: %add = add i32 %v1, %v1 -; CHECK: call void @clobber_and_use(i32 %add) -; CHECK: call void @clobber_and_use(i32 %v1) -; CHECK: ret void - %v1 = load i32, i32* %p, !invariant.load !{} - call void @clobber_and_use(i32 %v1) - %v2 = load i32, i32* %p, !invariant.load !{} - %add = add i32 %v1, %v2 - call void @clobber_and_use(i32 %add) - %v3 = load i32, i32* %p - call void @clobber_and_use(i32 %v3) - ret void -} diff --git a/llvm/test/Transforms/EarlyCSE/invariant.start.ll b/llvm/test/Transforms/EarlyCSE/invariant.start.ll deleted file mode 100644 index b5dc9a6bff7..00000000000 --- a/llvm/test/Transforms/EarlyCSE/invariant.start.ll +++ /dev/null @@ -1,290 +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 @test_bypass1(i8 *%P) { - ; CHECK-LABEL: @test_bypass1( - ; 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 @test_bypass2(i8 *%P) { - ; CHECK-LABEL: @test_bypass2( - ; 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 @test_bypass3(i8* %P) { -; CHECK-LABEL: @test_bypass3( -; 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 @test_bypass4(i8* %P) { - -; CHECK-LABEL: @test_bypass4( -; 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 -} - - -declare void @clobber() -declare {}* @llvm.invariant.start.p0i32(i64 %size, i32* nocapture %ptr) -declare void @llvm.invariant.end.p0i32({}*, i64, i32* nocapture) nounwind - -define i32 @test_before_load(i32* %p) { -; CHECK-LABEL: @test_before_load -; CHECK: ret i32 0 - call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p) - %v1 = load i32, i32* %p - call void @clobber() - %v2 = load i32, i32* %p - %sub = sub i32 %v1, %v2 - ret i32 %sub -} - -define i32 @test_before_clobber(i32* %p) { -; CHECK-LABEL: @test_before_clobber -; CHECK: ret i32 0 - %v1 = load i32, i32* %p - call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p) - call void @clobber() - %v2 = load i32, i32* %p - %sub = sub i32 %v1, %v2 - ret i32 %sub -} - -define i32 @test_duplicate_scope(i32* %p) { -; CHECK-LABEL: @test_duplicate_scope -; CHECK: ret i32 0 - %v1 = load i32, i32* %p - call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p) - call void @clobber() - call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p) - %v2 = load i32, i32* %p - %sub = sub i32 %v1, %v2 - ret i32 %sub -} - -define i32 @test_unanalzyable_load(i32* %p) { -; CHECK-LABEL: @test_unanalzyable_load -; CHECK: ret i32 0 - call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p) - call void @clobber() - %v1 = load i32, i32* %p - call void @clobber() - %v2 = load i32, i32* %p - %sub = sub i32 %v1, %v2 - ret i32 %sub -} - -define i32 @test_negative_after_clobber(i32* %p) { -; CHECK-LABEL: @test_negative_after_clobber -; CHECK: ret i32 %sub - %v1 = load i32, i32* %p - call void @clobber() - call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p) - %v2 = load i32, i32* %p - %sub = sub i32 %v1, %v2 - ret i32 %sub -} - -define i32 @test_merge(i32* %p, i1 %cnd) { -; CHECK-LABEL: @test_merge -; CHECK: ret i32 0 - %v1 = load i32, i32* %p - call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p) - br i1 %cnd, label %merge, label %taken - -taken: - call void @clobber() - br label %merge -merge: - %v2 = load i32, i32* %p - %sub = sub i32 %v1, %v2 - ret i32 %sub -} - -define i32 @test_negative_after_mergeclobber(i32* %p, i1 %cnd) { -; CHECK-LABEL: @test_negative_after_mergeclobber -; CHECK: ret i32 %sub - %v1 = load i32, i32* %p - br i1 %cnd, label %merge, label %taken - -taken: - call void @clobber() - br label %merge -merge: - call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p) - %v2 = load i32, i32* %p - %sub = sub i32 %v1, %v2 - ret i32 %sub -} - -; In theory, this version could work, but earlycse is incapable of -; merging facts along distinct paths. -define i32 @test_false_negative_merge(i32* %p, i1 %cnd) { -; CHECK-LABEL: @test_false_negative_merge -; CHECK: ret i32 %sub - %v1 = load i32, i32* %p - br i1 %cnd, label %merge, label %taken - -taken: - call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p) - call void @clobber() - br label %merge -merge: - %v2 = load i32, i32* %p - %sub = sub i32 %v1, %v2 - ret i32 %sub -} - -define i32 @test_merge_unanalyzable_load(i32* %p, i1 %cnd) { -; CHECK-LABEL: @test_merge_unanalyzable_load -; CHECK: ret i32 0 - call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p) - call void @clobber() - %v1 = load i32, i32* %p - br i1 %cnd, label %merge, label %taken - -taken: - call void @clobber() - br label %merge -merge: - %v2 = load i32, i32* %p - %sub = sub i32 %v1, %v2 - ret i32 %sub -} - -define void @test_dse_before_load(i32* %p, i1 %cnd) { -; CHECK-LABEL: @test_dse_before_load -; CHECK-NOT: store - call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p) - %v1 = load i32, i32* %p - call void @clobber() - store i32 %v1, i32* %p - ret void -} - -define void @test_dse_after_load(i32* %p, i1 %cnd) { -; CHECK-LABEL: @test_dse_after_load -; CHECK-NOT: store - %v1 = load i32, i32* %p - call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p) - call void @clobber() - store i32 %v1, i32* %p - ret void -} - - -; In this case, we have a false negative since MemoryLocation is implicitly -; typed due to the user of a Value to represent the address. Note that other -; passes will canonicalize away the bitcasts in this example. -define i32 @test_false_negative_types(i32* %p) { -; CHECK-LABEL: @test_false_negative_types -; CHECK: ret i32 %sub - call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p) - %v1 = load i32, i32* %p - call void @clobber() - %pf = bitcast i32* %p to float* - %v2f = load float, float* %pf - %v2 = bitcast float %v2f to i32 - %sub = sub i32 %v1, %v2 - ret i32 %sub -} - -define i32 @test_negative_size1(i32* %p) { -; CHECK-LABEL: @test_negative_size1 -; CHECK: ret i32 %sub - call {}* @llvm.invariant.start.p0i32(i64 3, i32* %p) - %v1 = load i32, i32* %p - call void @clobber() - %v2 = load i32, i32* %p - %sub = sub i32 %v1, %v2 - ret i32 %sub -} - -define i32 @test_negative_size2(i32* %p) { -; CHECK-LABEL: @test_negative_size2 -; CHECK: ret i32 %sub - call {}* @llvm.invariant.start.p0i32(i64 0, i32* %p) - %v1 = load i32, i32* %p - call void @clobber() - %v2 = load i32, i32* %p - %sub = sub i32 %v1, %v2 - ret i32 %sub -} - -define i32 @test_negative_scope(i32* %p) { -; CHECK-LABEL: @test_negative_scope -; CHECK: ret i32 %sub - %scope = call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p) - call void @llvm.invariant.end.p0i32({}* %scope, i64 4, i32* %p) - %v1 = load i32, i32* %p - call void @clobber() - %v2 = load i32, i32* %p - %sub = sub i32 %v1, %v2 - ret i32 %sub -} - -define i32 @test_false_negative_scope(i32* %p) { -; CHECK-LABEL: @test_false_negative_scope -; CHECK: ret i32 %sub - %scope = call {}* @llvm.invariant.start.p0i32(i64 4, i32* %p) - %v1 = load i32, i32* %p - call void @clobber() - %v2 = load i32, i32* %p - call void @llvm.invariant.end.p0i32({}* %scope, i64 4, i32* %p) - %sub = sub i32 %v1, %v2 - ret i32 %sub -} - -; Invariant load defact starts an invariant.start scope of the appropriate size -define i32 @test_invariant_load_scope(i32* %p) { -; CHECK-LABEL: @test_invariant_load_scope -; CHECK: ret i32 0 - %v1 = load i32, i32* %p, !invariant.load !{} - call void @clobber() - %v2 = load i32, i32* %p - %sub = sub i32 %v1, %v2 - ret i32 %sub -} diff --git a/llvm/test/Transforms/EarlyCSE/memoryssa.ll b/llvm/test/Transforms/EarlyCSE/memoryssa.ll deleted file mode 100644 index 41e8d488ab4..00000000000 --- a/llvm/test/Transforms/EarlyCSE/memoryssa.ll +++ /dev/null @@ -1,150 +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 -} - -;; Check that we respect lifetime.start/lifetime.end intrinsics when deleting -;; stores that, without the lifetime calls, would be writebacks. -; CHECK-LABEL: @test_writeback_lifetimes( -; CHECK-NOMEMSSA-LABEL: @test_writeback_lifetimes( -define void @test_writeback_lifetimes(i32* %p) { -entry: - %q = getelementptr i32, i32* %p, i64 1 - %pv = load i32, i32* %p - %qv = load i32, i32* %q - call void @llvm.lifetime.end.p0i8(i64 8, i32* %p) - call void @llvm.lifetime.start.p0i8(i64 8, i32* %p) - ; CHECK: store i32 %pv - ; CHECK-NOMEMSSA-LABEL: store i32 %pv - store i32 %pv, i32* %p - ; CHECK: store i32 %qv, i32* %q - ; CHECK-NOMEMSSA-LABEL: store i32 %qv, i32* %q - store i32 %qv, i32* %q - ret void -} - -;; Check that we respect lifetime.start/lifetime.end intrinsics when deleting -;; stores that, without the lifetime calls, would be writebacks. -; CHECK-LABEL: @test_writeback_lifetimes_multi_arg( -; CHECK-NOMEMSSA-LABEL: @test_writeback_lifetimes_multi_arg( -define void @test_writeback_lifetimes_multi_arg(i32* %p, i32* %q) { -entry: - %pv = load i32, i32* %p - %qv = load i32, i32* %q - call void @llvm.lifetime.end.p0i8(i64 8, i32* %p) - call void @llvm.lifetime.start.p0i8(i64 8, i32* %p) - ; CHECK: store i32 %pv - ; CHECK-NOMEMSSA-LABEL: store i32 %pv - store i32 %pv, i32* %p - ; CHECK: store i32 %qv, i32* %q - ; CHECK-NOMEMSSA-LABEL: store i32 %qv, i32* %q - store i32 %qv, i32* %q - ret void -} - -declare void @llvm.lifetime.end.p0i8(i64, i32*) -declare void @llvm.lifetime.start.p0i8(i64, i32*) diff --git a/llvm/test/Transforms/EarlyCSE/pr33406.ll b/llvm/test/Transforms/EarlyCSE/pr33406.ll deleted file mode 100644 index 4d3312e1f0a..00000000000 --- a/llvm/test/Transforms/EarlyCSE/pr33406.ll +++ /dev/null @@ -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 -} diff --git a/llvm/test/Transforms/EarlyCSE/preserve_memoryssa.ll b/llvm/test/Transforms/EarlyCSE/preserve_memoryssa.ll deleted file mode 100644 index 946293df6ca..00000000000 --- a/llvm/test/Transforms/EarlyCSE/preserve_memoryssa.ll +++ /dev/null @@ -1,137 +0,0 @@ -; RUN: opt < %s -early-cse-memssa -verify-memoryssa -disable-output -; REQUIRES: asserts - -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -; Tests below highlight scenarios where EarlyCSE does not preserve MemorySSA -; optimized accesses. Current MemorySSA verify will accept these. - -; Test 1: -; AA cannot tell here that the last load does not alias the only store. -; The first two loads are a common expression, EarlyCSE removes the second one, -; and then AA can see that the last load is a Use(LoE). Hence not optimized as -; it claims. Note that if we replace the GEP indices 2 and 1, AA sees NoAlias -; for the last load, before CSE-ing the first 2 loads. -%struct.ImageParameters = type { i32, i32, i32 } -@img = external global %struct.ImageParameters*, align 8 -define void @test1_macroblock() { -entry: - ; MemoryUse(LoE) - %0 = load %struct.ImageParameters*, %struct.ImageParameters** @img, align 8 - - %Pos_2 = getelementptr inbounds %struct.ImageParameters, %struct.ImageParameters* %0, i64 0, i32 2 - ; 1 = MemoryDef(LoE) - store i32 undef, i32* %Pos_2, align 8 - - ; MemoryUse(LoE) - %1 = load %struct.ImageParameters*, %struct.ImageParameters** @img, align 8 - - %Pos_1 = getelementptr inbounds %struct.ImageParameters, %struct.ImageParameters* %1, i64 0, i32 1 - ; MemoryUse(1) MayAlias - %2 = load i32, i32* %Pos_1, align 4 - unreachable -} - -; Test 2: -; EarlyCSE simplifies %string to undef. Def and Use used to be MustAlias, with -; undef they are NoAlias. The Use can be optimized further to LoE. We can -; de-optimize uses of replaced instructions, but in general this is not enough -; (see next tests). -%struct.TermS = type { i32, i32, i32, i32, i32, i8* } -define fastcc void @test2_term_string() { -entry: - %string = getelementptr inbounds %struct.TermS, %struct.TermS* undef, i64 0, i32 5 - ; 1 = MemoryDef(LoE) - store i8* undef, i8** %string, align 8 - ; MemoryUse(1) MustAlias - %0 = load i8*, i8** %string, align 8 - unreachable -} - -; Test 3: -; EarlyCSE simplifies %0 to undef. So the second Def now stores to undef. -; We now find the second load (Use(2) can be optimized further to LoE) -; When replacing instructions, we can deoptimize all uses of the replaced -; instruction and all uses of transitive accesses. However this does not stop -; MemorySSA from being tripped by AA (see test4). -%struct.Grammar = type { i8*, i8*, %struct.anon } -%struct.anon = type { i32, i32, %struct.Term**, [3 x %struct.Term*] } -%struct.Term = type { i32 } - -define fastcc void @test3_term_string(%struct.Grammar* %g) { -entry: - ; 1 = MemoryDef(LoE) - store i8* undef, i8** undef, align 8 - ; MemoryUse(LoE) - %0 = load i8*, i8** undef, align 8 - %arrayidx = getelementptr inbounds i8, i8* %0, i64 undef - ; 2 = MemoryDef(1) - store i8 0, i8* %arrayidx, align 1 - %v = getelementptr inbounds %struct.Grammar, %struct.Grammar* %g, i64 0, i32 2, i32 2 - ; MemoryUse(2) MayAlias - %1 = load %struct.Term**, %struct.Term*** %v, align 8 - unreachable -} - -; Test 4: -; Removing dead/unused instructions in if.then274 makes AA smarter. Before -; removal, it finds %4 MayAlias the store above. After removal this can be -; optimized to LoE. Hence after EarlyCSE, there is an access who claims is -; optimized and it can be optimized further. - -; We can't escape such cases in general when relying on Alias Analysis. -; The only fail-safe way to actually preserve MemorySSA when removing or -; replacing instructions (i.e. get the *same* MemorySSA as if it was computed -; for the updated IR) is to recompute it from scratch. What we get now is still -; a correct update, but with accesses that claim to be optimized and can be -; optimized further if we were to re-run MemorySSA on the IR. -%struct.gnode.0.1.3.6.9.18.20.79 = type { i32, i32, i32, i32, i32, i32, i32, %struct.gnode.0.1.3.6.9.18.20.79* } -@gnodeArray = external global %struct.gnode.0.1.3.6.9.18.20.79**, align 8 - -define void @test4_shortest() { -entry: - %exl.i = alloca [5 x i32], align 16 - br i1 undef, label %if.then274, label %for.cond404 - -if.then274: ; preds = %if.end256 - %0 = bitcast [5 x i32]* %exl.i to i8* - %arrayidx.i = getelementptr inbounds [5 x i32], [5 x i32]* %exl.i, i64 0, i64 1 - %arrayidx1.i = getelementptr inbounds [5 x i32], [5 x i32]* %exl.i, i64 0, i64 2 - %arrayidx2.i = getelementptr inbounds [5 x i32], [5 x i32]* %exl.i, i64 0, i64 3 - %arrayidx3.i = getelementptr inbounds [5 x i32], [5 x i32]* %exl.i, i64 0, i64 4 - %1 = bitcast [5 x i32]* %exl.i to i8* - %arrayidx.i1034 = getelementptr inbounds [5 x i32], [5 x i32]* %exl.i, i64 0, i64 1 - %arrayidx1.i1035 = getelementptr inbounds [5 x i32], [5 x i32]* %exl.i, i64 0, i64 2 - %arrayidx2.i1036 = getelementptr inbounds [5 x i32], [5 x i32]* %exl.i, i64 0, i64 3 - %arrayidx3.i1037 = getelementptr inbounds [5 x i32], [5 x i32]* %exl.i, i64 0, i64 4 - unreachable - -for.cond404: ; preds = %if.end256 - %2 = bitcast [5 x i32]* %exl.i to i8* - %arrayidx.i960 = getelementptr inbounds [5 x i32], [5 x i32]* %exl.i, i64 0, i64 1 - %arrayidx1.i961 = getelementptr inbounds [5 x i32], [5 x i32]* %exl.i, i64 0, i64 2 - %arrayidx2.i962 = getelementptr inbounds [5 x i32], [5 x i32]* %exl.i, i64 0, i64 3 - ; 1 = MemoryDef(LoE) - store i32 undef, i32* %arrayidx2.i962, align 4 - %arrayidx3.i963 = getelementptr inbounds [5 x i32], [5 x i32]* %exl.i, i64 0, i64 4 - - ; MemoryUse(LoE) - %3 = load %struct.gnode.0.1.3.6.9.18.20.79**, %struct.gnode.0.1.3.6.9.18.20.79*** @gnodeArray, align 8 - %arrayidx6.i968 = getelementptr inbounds %struct.gnode.0.1.3.6.9.18.20.79*, %struct.gnode.0.1.3.6.9.18.20.79** %3, i64 undef - ; MemoryUse(1) MayAlias - %4 = load %struct.gnode.0.1.3.6.9.18.20.79*, %struct.gnode.0.1.3.6.9.18.20.79** %arrayidx6.i968, align 8 - br i1 undef, label %for.cond26.preheader.i974, label %if.then20.for.body_crit_edge.i999 - -for.cond26.preheader.i974: ; preds = %if.then20.i996 - %5 = bitcast [5 x i32]* %exl.i to i8* - %arrayidx.i924 = getelementptr inbounds [5 x i32], [5 x i32]* %exl.i, i64 0, i64 1 - %arrayidx1.i925 = getelementptr inbounds [5 x i32], [5 x i32]* %exl.i, i64 0, i64 2 - %arrayidx2.i926 = getelementptr inbounds [5 x i32], [5 x i32]* %exl.i, i64 0, i64 3 - %arrayidx3.i927 = getelementptr inbounds [5 x i32], [5 x i32]* %exl.i, i64 0, i64 4 - unreachable - -if.then20.for.body_crit_edge.i999: ; preds = %if.then20.i996 - %arrayidx9.phi.trans.insert.i997 = getelementptr inbounds [5 x i32], [5 x i32]* %exl.i, i64 0, i64 undef - unreachable -} diff --git a/llvm/test/Transforms/EarlyCSE/read-reg.ll b/llvm/test/Transforms/EarlyCSE/read-reg.ll deleted file mode 100644 index 25f5f8019e1..00000000000 --- a/llvm/test/Transforms/EarlyCSE/read-reg.ll +++ /dev/null @@ -1,35 +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-n32:64" -target triple = "powerpc64-unknown-linux-gnu" - -; Function Attrs: nounwind -define i64 @f(i64 %x) #0 { -entry: - %0 = call i64 @llvm.read_register.i64(metadata !0) - call void bitcast (void (...)* @foo to void ()*)() - %1 = call i64 @llvm.read_register.i64(metadata !0) - %add = add nsw i64 %0, %1 - ret i64 %add -} - -; CHECK-LABEL: @f -; CHECK: call i64 @llvm.read_register.i64 -; CHECK: call i64 @llvm.read_register.i64 - -; Function Attrs: nounwind readnone -declare i64 @llvm.read_register.i64(metadata) #1 - -; Function Attrs: nounwind -declare void @llvm.write_register.i64(metadata, i64) #2 - -declare void @foo(...) - -attributes #0 = { nounwind } -attributes #1 = { nounwind readnone } -attributes #2 = { nounwind } - -!llvm.named.register.r1 = !{!0} - -!0 = !{!"r1"} - diff --git a/llvm/test/Transforms/EarlyCSE/readnone-mayunwind.ll b/llvm/test/Transforms/EarlyCSE/readnone-mayunwind.ll deleted file mode 100644 index 47a513f2d6a..00000000000 --- a/llvm/test/Transforms/EarlyCSE/readnone-mayunwind.ll +++ /dev/null @@ -1,15 +0,0 @@ -; RUN: opt -S -early-cse < %s | FileCheck %s - -declare void @readnone_may_unwind() readnone - -define void @f(i32* %ptr) { -; CHECK-LABEL: @f( -; CHECK: store i32 100, i32* %ptr -; CHECK: call void @readnone_may_unwind() -; CHECK: store i32 200, i32* %ptr - - store i32 100, i32* %ptr - call void @readnone_may_unwind() - store i32 200, i32* %ptr - ret void -} |