diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2014-11-24 09:08:18 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2014-11-24 09:08:18 +0000 |
| commit | 5ca98fd98791947eba83a1ed3f2c8191ef7afa6c (patch) | |
| tree | f5944309621cee4fe0976be6f9ac619b7ebfc4c2 /test/Analysis | |
| parent | 68bcb7db193e4bc81430063148253d30a791023e (diff) | |
Notes
Diffstat (limited to 'test/Analysis')
64 files changed, 3129 insertions, 215 deletions
diff --git a/test/Analysis/BasicAA/2007-11-05-SizeCrash.ll b/test/Analysis/BasicAA/2007-11-05-SizeCrash.ll index 563d3326367b4..32d9930f42708 100644 --- a/test/Analysis/BasicAA/2007-11-05-SizeCrash.ll +++ b/test/Analysis/BasicAA/2007-11-05-SizeCrash.ll @@ -7,7 +7,7 @@ target triple = "x86_64-unknown-linux-gnu" %struct.pci_device_id = type { i32, i32, i32, i32, i32, i32, i64 } %struct.usb_bus = type { %struct.device* } %struct.usb_hcd = type { %struct.usb_bus, i64, [0 x i64] } -@uhci_pci_ids = external constant [1 x %struct.pci_device_id] ; <[1 x %struct.pci_device_id]*> [#uses=1] +@uhci_pci_ids = constant [1 x %struct.pci_device_id] zeroinitializer @__mod_pci_device_table = alias [1 x %struct.pci_device_id]* @uhci_pci_ids ; <[1 x %struct.pci_device_id]*> [#uses=0] diff --git a/test/Analysis/BasicAA/2007-12-08-OutOfBoundsCrash.ll b/test/Analysis/BasicAA/2007-12-08-OutOfBoundsCrash.ll index 52d0af1b81ce5..cd997ea525133 100644 --- a/test/Analysis/BasicAA/2007-12-08-OutOfBoundsCrash.ll +++ b/test/Analysis/BasicAA/2007-12-08-OutOfBoundsCrash.ll @@ -7,7 +7,7 @@ target triple = "x86_64-unknown-linux-gnu" %struct.pci_device_id = type { i32, i32, i32, i32, i32, i32, i64 } %struct.usb_bus = type { %struct.device* } %struct.usb_hcd = type { %struct.usb_bus, [0 x i64] } -@pci_ids = external constant [1 x %struct.pci_device_id] ; <[1 x %struct.pci_device_id]*> [#uses=1] +@pci_ids = constant [1 x %struct.pci_device_id] zeroinitializer @__mod_pci_device_table = alias [1 x %struct.pci_device_id]* @pci_ids ; <[1 x %struct.pci_device_id]*> [#uses=0] diff --git a/test/Analysis/BasicAA/2014-03-18-Maxlookup-reached.ll b/test/Analysis/BasicAA/2014-03-18-Maxlookup-reached.ll new file mode 100644 index 0000000000000..bc2512eca0c9a --- /dev/null +++ b/test/Analysis/BasicAA/2014-03-18-Maxlookup-reached.ll @@ -0,0 +1,36 @@ +; RUN: opt < %s -basicaa -gvn -S | FileCheck %s + +; PR15967 +; BasicAA claims no alias when there is (due to a problem when the MaxLookup +; limit was reached). + +target datalayout = "e" + +%struct.foo = type { i32, i32 } + +define i32 @main() { + %t = alloca %struct.foo, align 4 + %1 = getelementptr inbounds %struct.foo* %t, i32 0, i32 0 + store i32 1, i32* %1, align 4 + %2 = getelementptr inbounds %struct.foo* %t, i64 1 + %3 = bitcast %struct.foo* %2 to i8* + %4 = getelementptr inbounds i8* %3, i32 -1 + store i8 0, i8* %4 + %5 = getelementptr inbounds i8* %4, i32 -1 + store i8 0, i8* %5 + %6 = getelementptr inbounds i8* %5, i32 -1 + store i8 0, i8* %6 + %7 = getelementptr inbounds i8* %6, i32 -1 + store i8 0, i8* %7 + %8 = getelementptr inbounds i8* %7, i32 -1 + store i8 0, i8* %8 + %9 = getelementptr inbounds i8* %8, i32 -1 + store i8 0, i8* %9 + %10 = getelementptr inbounds i8* %9, i32 -1 + store i8 0, i8* %10 + %11 = getelementptr inbounds i8* %10, i32 -1 + store i8 0, i8* %11 + %12 = load i32* %1, align 4 + ret i32 %12 +; CHECK: ret i32 %12 +} diff --git a/test/Analysis/BasicAA/cs-cs.ll b/test/Analysis/BasicAA/cs-cs.ll new file mode 100644 index 0000000000000..693634c0414d2 --- /dev/null +++ b/test/Analysis/BasicAA/cs-cs.ll @@ -0,0 +1,236 @@ +; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s +target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:64-v128:32:128-a0:0:32-n32" +target triple = "arm-apple-ios" + +declare <8 x i16> @llvm.arm.neon.vld1.v8i16(i8*, i32) nounwind readonly +declare void @llvm.arm.neon.vst1.v8i16(i8*, <8 x i16>, i32) nounwind + +declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) nounwind + +declare void @a_readonly_func(i8 *) noinline nounwind readonly + +define <8 x i16> @test1(i8* %p, <8 x i16> %y) { +entry: + %q = getelementptr i8* %p, i64 16 + %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) nounwind + call void @llvm.arm.neon.vst1.v8i16(i8* %q, <8 x i16> %y, i32 16) + %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) nounwind + %c = add <8 x i16> %a, %b + ret <8 x i16> %c + +; CHECK-LABEL: Function: test1: + +; CHECK: NoAlias: i8* %p, i8* %q +; CHECK: Just Ref: Ptr: i8* %p <-> %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) #1 +; CHECK: NoModRef: Ptr: i8* %q <-> %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) #1 +; CHECK: NoModRef: Ptr: i8* %p <-> call void @llvm.arm.neon.vst1.v8i16(i8* %q, <8 x i16> %y, i32 16) +; CHECK: Both ModRef: Ptr: i8* %q <-> call void @llvm.arm.neon.vst1.v8i16(i8* %q, <8 x i16> %y, i32 16) +; CHECK: Just Ref: Ptr: i8* %p <-> %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) #1 +; CHECK: NoModRef: Ptr: i8* %q <-> %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) #1 +; CHECK: NoModRef: %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) #1 <-> call void @llvm.arm.neon.vst1.v8i16(i8* %q, <8 x i16> %y, i32 16) +; CHECK: NoModRef: %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) #1 <-> %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) #1 +; CHECK: NoModRef: call void @llvm.arm.neon.vst1.v8i16(i8* %q, <8 x i16> %y, i32 16) <-> %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) #1 +; CHECK: NoModRef: call void @llvm.arm.neon.vst1.v8i16(i8* %q, <8 x i16> %y, i32 16) <-> %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) #1 +; CHECK: NoModRef: %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) #1 <-> %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) #1 +; CHECK: NoModRef: %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16(i8* %p, i32 16) #1 <-> call void @llvm.arm.neon.vst1.v8i16(i8* %q, <8 x i16> %y, i32 16) +} + +define void @test2(i8* %P, i8* %Q) nounwind ssp { + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) + ret void + +; CHECK-LABEL: Function: test2: + +; CHECK: MayAlias: i8* %P, i8* %Q +; CHECK: Both ModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Both ModRef: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Both ModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Both ModRef: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Both ModRef: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Both ModRef: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +} + +define void @test2a(i8* noalias %P, i8* noalias %Q) nounwind ssp { + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) + ret void + +; CHECK-LABEL: Function: test2a: + +; CHECK: NoAlias: i8* %P, i8* %Q +; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Mod: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Mod: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +} + +define void @test2b(i8* noalias %P, i8* noalias %Q) nounwind ssp { + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) + %R = getelementptr i8* %P, i64 12 + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) + ret void + +; CHECK-LABEL: Function: test2b: + +; CHECK: NoAlias: i8* %P, i8* %Q +; CHECK: NoAlias: i8* %P, i8* %R +; CHECK: NoAlias: i8* %Q, i8* %R +; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: NoModRef: Ptr: i8* %R <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: NoModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Mod: Ptr: i8* %R <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: NoModRef: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: NoModRef: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +} + +define void @test2c(i8* noalias %P, i8* noalias %Q) nounwind ssp { + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) + %R = getelementptr i8* %P, i64 11 + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) + ret void + +; CHECK-LABEL: Function: test2c: + +; CHECK: NoAlias: i8* %P, i8* %Q +; CHECK: NoAlias: i8* %P, i8* %R +; CHECK: NoAlias: i8* %Q, i8* %R +; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Mod: Ptr: i8* %R <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: NoModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Mod: Ptr: i8* %R <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Mod: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Mod: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +} + +define void @test2d(i8* noalias %P, i8* noalias %Q) nounwind ssp { + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) + %R = getelementptr i8* %P, i64 -12 + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) + ret void + +; CHECK-LABEL: Function: test2d: + +; CHECK: NoAlias: i8* %P, i8* %Q +; CHECK: NoAlias: i8* %P, i8* %R +; CHECK: NoAlias: i8* %Q, i8* %R +; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: NoModRef: Ptr: i8* %R <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: NoModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Mod: Ptr: i8* %R <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: NoModRef: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: NoModRef: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +} + +define void @test2e(i8* noalias %P, i8* noalias %Q) nounwind ssp { + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) + %R = getelementptr i8* %P, i64 -11 + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) + ret void + +; CHECK-LABEL: Function: test2e: + +; CHECK: NoAlias: i8* %P, i8* %Q +; CHECK: NoAlias: i8* %P, i8* %R +; CHECK: NoAlias: i8* %Q, i8* %R +; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: NoModRef: Ptr: i8* %R <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Mod: Ptr: i8* %R <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Mod: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Mod: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %R, i8* %Q, i64 12, i32 1, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +} + +define void @test3(i8* %P, i8* %Q) nounwind ssp { + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 8, i32 1, i1 false) + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) + ret void + +; CHECK-LABEL: Function: test3: + +; CHECK: MayAlias: i8* %P, i8* %Q +; CHECK: Both ModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 8, i32 1, i1 false) +; CHECK: Both ModRef: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 8, i32 1, i1 false) +; CHECK: Both ModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Both ModRef: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Both ModRef: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 8, i32 1, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Both ModRef: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 8, i32 1, i1 false) +} + +define void @test3a(i8* noalias %P, i8* noalias %Q) nounwind ssp { + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 8, i32 1, i1 false) + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) + ret void + +; CHECK-LABEL: Function: test3a: + +; CHECK: NoAlias: i8* %P, i8* %Q +; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 8, i32 1, i1 false) +; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 8, i32 1, i1 false) +; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Mod: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 8, i32 1, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Mod: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 8, i32 1, i1 false) +} + +define void @test4(i8* %P, i8* noalias %Q) nounwind ssp { + tail call void @llvm.memset.p0i8.i64(i8* %P, i8 42, i64 8, i32 1, i1 false) + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) + ret void + +; CHECK-LABEL: Function: test4: + +; CHECK: NoAlias: i8* %P, i8* %Q +; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memset.p0i8.i64(i8* %P, i8 42, i64 8, i32 1, i1 false) +; CHECK: NoModRef: Ptr: i8* %Q <-> tail call void @llvm.memset.p0i8.i64(i8* %P, i8 42, i64 8, i32 1, i1 false) +; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Mod: tail call void @llvm.memset.p0i8.i64(i8* %P, i8 42, i64 8, i32 1, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Just Mod: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) <-> tail call void @llvm.memset.p0i8.i64(i8* %P, i8 42, i64 8, i32 1, i1 false) +} + +define void @test5(i8* %P, i8* %Q, i8* %R) nounwind ssp { + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %R, i64 12, i32 1, i1 false) + ret void + +; CHECK-LABEL: Function: test5: + +; CHECK: MayAlias: i8* %P, i8* %Q +; CHECK: MayAlias: i8* %P, i8* %R +; CHECK: MayAlias: i8* %Q, i8* %R +; CHECK: Both ModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Both ModRef: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Both ModRef: Ptr: i8* %R <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Both ModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %R, i64 12, i32 1, i1 false) +; CHECK: Both ModRef: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %R, i64 12, i32 1, i1 false) +; CHECK: Both ModRef: Ptr: i8* %R <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %R, i64 12, i32 1, i1 false) +; CHECK: Both ModRef: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %R, i64 12, i32 1, i1 false) +; CHECK: Both ModRef: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %R, i64 12, i32 1, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +} + +define void @test6(i8* %P) nounwind ssp { + call void @llvm.memset.p0i8.i64(i8* %P, i8 -51, i64 32, i32 8, i1 false) + call void @a_readonly_func(i8* %P) + ret void + +; CHECK-LABEL: Function: test6: + +; CHECK: Just Mod: Ptr: i8* %P <-> call void @llvm.memset.p0i8.i64(i8* %P, i8 -51, i64 32, i32 8, i1 false) +; CHECK: Just Ref: Ptr: i8* %P <-> call void @a_readonly_func(i8* %P) +; CHECK: Just Mod: call void @llvm.memset.p0i8.i64(i8* %P, i8 -51, i64 32, i32 8, i1 false) <-> call void @a_readonly_func(i8* %P) +; CHECK: Just Ref: call void @a_readonly_func(i8* %P) <-> call void @llvm.memset.p0i8.i64(i8* %P, i8 -51, i64 32, i32 8, i1 false) +} + +attributes #0 = { nounwind } diff --git a/test/Analysis/BasicAA/noalias-bugs.ll b/test/Analysis/BasicAA/noalias-bugs.ll index c02a302c1950f..2bcc14fd9397a 100644 --- a/test/Analysis/BasicAA/noalias-bugs.ll +++ b/test/Analysis/BasicAA/noalias-bugs.ll @@ -1,6 +1,6 @@ ; RUN: opt -S -basicaa -dse < %s | FileCheck %s -target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" ; We incorrectly returned noalias in the example below for "ptr.64" and diff --git a/test/Analysis/BasicAA/pr18573.ll b/test/Analysis/BasicAA/pr18573.ll new file mode 100644 index 0000000000000..1d2a316b6ffef --- /dev/null +++ b/test/Analysis/BasicAA/pr18573.ll @@ -0,0 +1,53 @@ +; RUN: opt %s -O2 -S | FileCheck %s + +; Check that llvm.x86.avx2.gather.d.ps.256 intrinsic is not eliminated as gather and store memory accesses are based on arr.ptr +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: nounwind readonly +declare <8 x float> @llvm.x86.avx2.gather.d.ps.256(<8 x float>, i8*, <8 x i32>, <8 x float>, i8) #0 + +; Function Attrs: nounwind +define <8 x float> @foo1(i8* noalias readonly %arr.ptr, <8 x i32>* noalias readonly %vix.ptr, i8* noalias %t2.ptr) #1 { +allocas: + %vix = load <8 x i32>* %vix.ptr, align 4 + %t1.ptr = getelementptr i8* %arr.ptr, i8 4 + + %v1 = tail call <8 x float> @llvm.x86.avx2.gather.d.ps.256(<8 x float> undef, i8* %arr.ptr, <8 x i32> %vix, <8 x float> <float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000>, i8 1) #2 + store i8 1, i8* %t1.ptr, align 4 + + %v2 = tail call <8 x float> @llvm.x86.avx2.gather.d.ps.256(<8 x float> undef, i8* %arr.ptr, <8 x i32> %vix, <8 x float> <float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000>, i8 1) #2 + %res = fadd <8 x float> %v1, %v2 + + ret <8 x float> %res +} +; CHECK: foo1 +; CHECK: llvm.x86.avx2.gather.d.ps.256 +; CHECK: store +; CHECK: llvm.x86.avx2.gather.d.ps.256 + +; Check that second gather is eliminated as gather and store memory accesses are based on different no-aliasing pointers + +; Function Attrs: nounwind +define <8 x float> @foo2(i8* noalias readonly %arr.ptr, <8 x i32>* noalias readonly %vix.ptr, i8* noalias %t2.ptr) #1 { +allocas: + %vix = load <8 x i32>* %vix.ptr, align 4 + %t1.ptr = getelementptr i8* %arr.ptr, i8 4 + + %v1 = tail call <8 x float> @llvm.x86.avx2.gather.d.ps.256(<8 x float> undef, i8* %arr.ptr, <8 x i32> %vix, <8 x float> <float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000>, i8 1) #2 + store i8 1, i8* %t2.ptr, align 4 + + %v2 = tail call <8 x float> @llvm.x86.avx2.gather.d.ps.256(<8 x float> undef, i8* %arr.ptr, <8 x i32> %vix, <8 x float> <float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000>, i8 1) #2 + %res = fadd <8 x float> %v1, %v2 + + ret <8 x float> %res +} +; CHECK: foo2 +; CHECK: llvm.x86.avx2.gather.d.ps.256 +; CHECK: store +; CHECK-NOT: llvm.x86.avx2.gather.d.ps.256 + +attributes #0 = { nounwind readonly } +attributes #1 = { nounwind "target-cpu"="corei7-avx" "target-features"="+avx2,+popcnt,+cmov,+f16c,+rdrnd,+fma" } +attributes #2 = { nounwind } + diff --git a/test/Analysis/BlockFrequencyInfo/bad_input.ll b/test/Analysis/BlockFrequencyInfo/bad_input.ll new file mode 100644 index 0000000000000..bcdc1e6f0bc0b --- /dev/null +++ b/test/Analysis/BlockFrequencyInfo/bad_input.ll @@ -0,0 +1,50 @@ +; RUN: opt < %s -analyze -block-freq | FileCheck %s + +declare void @g(i32 %x) + +; CHECK-LABEL: Printing analysis {{.*}} for function 'branch_weight_0': +; CHECK-NEXT: block-frequency-info: branch_weight_0 +define void @branch_weight_0(i32 %a) { +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] +entry: + br label %for.body + +; Check that we get 1,4 instead of 0,3. +; CHECK-NEXT: for.body: float = 4.0, +for.body: + %i = phi i32 [ 0, %entry ], [ %inc, %for.body ] + call void @g(i32 %i) + %inc = add i32 %i, 1 + %cmp = icmp ugt i32 %inc, %a + br i1 %cmp, label %for.end, label %for.body, !prof !0 + +; CHECK-NEXT: for.end: float = 1.0, int = [[ENTRY]] +for.end: + ret void +} + +!0 = metadata !{metadata !"branch_weights", i32 0, i32 3} + +; CHECK-LABEL: Printing analysis {{.*}} for function 'infinite_loop' +; CHECK-NEXT: block-frequency-info: infinite_loop +define void @infinite_loop(i1 %x) { +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] +entry: + br i1 %x, label %for.body, label %for.end, !prof !1 + +; Check that the loop scale maxes out at 4096, giving 2048 here. +; CHECK-NEXT: for.body: float = 2048.0, +for.body: + %i = phi i32 [ 0, %entry ], [ %inc, %for.body ] + call void @g(i32 %i) + %inc = add i32 %i, 1 + br label %for.body + +; Check that the exit weight is half of entry, since half is lost in the +; infinite loop above. +; CHECK-NEXT: for.end: float = 0.5, +for.end: + ret void +} + +!1 = metadata !{metadata !"branch_weights", i32 1, i32 1} diff --git a/test/Analysis/BlockFrequencyInfo/basic.ll b/test/Analysis/BlockFrequencyInfo/basic.ll index ce29fb5ce1ba8..006e6ab4d74e5 100644 --- a/test/Analysis/BlockFrequencyInfo/basic.ll +++ b/test/Analysis/BlockFrequencyInfo/basic.ll @@ -1,13 +1,14 @@ ; RUN: opt < %s -analyze -block-freq | FileCheck %s define i32 @test1(i32 %i, i32* %a) { -; CHECK: Printing analysis {{.*}} for function 'test1' -; CHECK: entry = 1.0 +; CHECK-LABEL: Printing analysis {{.*}} for function 'test1': +; CHECK-NEXT: block-frequency-info: test1 +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] entry: br label %body ; Loop backedges are weighted and thus their bodies have a greater frequency. -; CHECK: body = 32.0 +; CHECK-NEXT: body: float = 32.0, body: %iv = phi i32 [ 0, %entry ], [ %next, %body ] %base = phi i32 [ 0, %entry ], [ %sum, %body ] @@ -18,29 +19,29 @@ body: %exitcond = icmp eq i32 %next, %i br i1 %exitcond, label %exit, label %body -; CHECK: exit = 1.0 +; CHECK-NEXT: exit: float = 1.0, int = [[ENTRY]] exit: ret i32 %sum } define i32 @test2(i32 %i, i32 %a, i32 %b) { -; CHECK: Printing analysis {{.*}} for function 'test2' -; CHECK: entry = 1.0 +; CHECK-LABEL: Printing analysis {{.*}} for function 'test2': +; CHECK-NEXT: block-frequency-info: test2 +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] entry: %cond = icmp ult i32 %i, 42 br i1 %cond, label %then, label %else, !prof !0 ; The 'then' branch is predicted more likely via branch weight metadata. -; CHECK: then = 0.94116 +; CHECK-NEXT: then: float = 0.9411{{[0-9]*}}, then: br label %exit -; CHECK: else = 0.05877 +; CHECK-NEXT: else: float = 0.05882{{[0-9]*}}, else: br label %exit -; FIXME: It may be a bug that we don't sum back to 1.0. -; CHECK: exit = 0.99993 +; CHECK-NEXT: exit: float = 1.0, int = [[ENTRY]] exit: %result = phi i32 [ %a, %then ], [ %b, %else ] ret i32 %result @@ -49,37 +50,37 @@ exit: !0 = metadata !{metadata !"branch_weights", i32 64, i32 4} define i32 @test3(i32 %i, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) { -; CHECK: Printing analysis {{.*}} for function 'test3' -; CHECK: entry = 1.0 +; CHECK-LABEL: Printing analysis {{.*}} for function 'test3': +; CHECK-NEXT: block-frequency-info: test3 +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] entry: switch i32 %i, label %case_a [ i32 1, label %case_b i32 2, label %case_c i32 3, label %case_d i32 4, label %case_e ], !prof !1 -; CHECK: case_a = 0.04998 +; CHECK-NEXT: case_a: float = 0.05, case_a: br label %exit -; CHECK: case_b = 0.04998 +; CHECK-NEXT: case_b: float = 0.05, case_b: br label %exit ; The 'case_c' branch is predicted more likely via branch weight metadata. -; CHECK: case_c = 0.79998 +; CHECK-NEXT: case_c: float = 0.8, case_c: br label %exit -; CHECK: case_d = 0.04998 +; CHECK-NEXT: case_d: float = 0.05, case_d: br label %exit -; CHECK: case_e = 0.04998 +; CHECK-NEXT: case_e: float = 0.05, case_e: br label %exit -; FIXME: It may be a bug that we don't sum back to 1.0. -; CHECK: exit = 0.99993 +; CHECK-NEXT: exit: float = 1.0, int = [[ENTRY]] exit: %result = phi i32 [ %a, %case_a ], [ %b, %case_b ], @@ -91,44 +92,50 @@ exit: !1 = metadata !{metadata !"branch_weights", i32 4, i32 4, i32 64, i32 4, i32 4} -; CHECK: Printing analysis {{.*}} for function 'nested_loops' -; CHECK: entry = 1.0 -; This test doesn't seem to be assigning sensible frequencies to nested loops. define void @nested_loops(i32 %a) { +; CHECK-LABEL: Printing analysis {{.*}} for function 'nested_loops': +; CHECK-NEXT: block-frequency-info: nested_loops +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] entry: br label %for.cond1.preheader +; CHECK-NEXT: for.cond1.preheader: float = 4001.0, for.cond1.preheader: %x.024 = phi i32 [ 0, %entry ], [ %inc12, %for.inc11 ] br label %for.cond4.preheader +; CHECK-NEXT: for.cond4.preheader: float = 16008001.0, for.cond4.preheader: %y.023 = phi i32 [ 0, %for.cond1.preheader ], [ %inc9, %for.inc8 ] %add = add i32 %y.023, %x.024 br label %for.body6 +; CHECK-NEXT: for.body6: float = 64048012001.0, for.body6: %z.022 = phi i32 [ 0, %for.cond4.preheader ], [ %inc, %for.body6 ] %add7 = add i32 %add, %z.022 - tail call void @g(i32 %add7) #2 + tail call void @g(i32 %add7) %inc = add i32 %z.022, 1 %cmp5 = icmp ugt i32 %inc, %a br i1 %cmp5, label %for.inc8, label %for.body6, !prof !2 +; CHECK-NEXT: for.inc8: float = 16008001.0, for.inc8: %inc9 = add i32 %y.023, 1 %cmp2 = icmp ugt i32 %inc9, %a br i1 %cmp2, label %for.inc11, label %for.cond4.preheader, !prof !2 +; CHECK-NEXT: for.inc11: float = 4001.0, for.inc11: %inc12 = add i32 %x.024, 1 %cmp = icmp ugt i32 %inc12, %a br i1 %cmp, label %for.end13, label %for.cond1.preheader, !prof !2 +; CHECK-NEXT: for.end13: float = 1.0, int = [[ENTRY]] for.end13: ret void } -declare void @g(i32) #1 +declare void @g(i32) !2 = metadata !{metadata !"branch_weights", i32 1, i32 4000} diff --git a/test/Analysis/BlockFrequencyInfo/double_backedge.ll b/test/Analysis/BlockFrequencyInfo/double_backedge.ll new file mode 100644 index 0000000000000..df8217cfa1b16 --- /dev/null +++ b/test/Analysis/BlockFrequencyInfo/double_backedge.ll @@ -0,0 +1,27 @@ +; RUN: opt < %s -analyze -block-freq | FileCheck %s + +define void @double_backedge(i1 %x) { +; CHECK-LABEL: Printing analysis {{.*}} for function 'double_backedge': +; CHECK-NEXT: block-frequency-info: double_backedge +entry: +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] + br label %loop + +loop: +; CHECK-NEXT: loop: float = 10.0, + br i1 %x, label %exit, label %loop.1, !prof !0 + +loop.1: +; CHECK-NEXT: loop.1: float = 9.0, + br i1 %x, label %loop, label %loop.2, !prof !1 + +loop.2: +; CHECK-NEXT: loop.2: float = 5.0, + br label %loop + +exit: +; CHECK-NEXT: exit: float = 1.0, int = [[ENTRY]] + ret void +} +!0 = metadata !{metadata !"branch_weights", i32 1, i32 9} +!1 = metadata !{metadata !"branch_weights", i32 4, i32 5} diff --git a/test/Analysis/BlockFrequencyInfo/double_exit.ll b/test/Analysis/BlockFrequencyInfo/double_exit.ll new file mode 100644 index 0000000000000..75f664d07ac49 --- /dev/null +++ b/test/Analysis/BlockFrequencyInfo/double_exit.ll @@ -0,0 +1,165 @@ +; RUN: opt < %s -analyze -block-freq | FileCheck %s + +; CHECK-LABEL: Printing analysis {{.*}} for function 'double_exit': +; CHECK-NEXT: block-frequency-info: double_exit +define i32 @double_exit(i32 %N) { +; Mass = 1 +; Frequency = 1 +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] +entry: + br label %outer + +; Mass = 1 +; Backedge mass = 1/3, exit mass = 2/3 +; Loop scale = 3/2 +; Pseudo-edges = exit +; Pseudo-mass = 1 +; Frequency = 1*3/2*1 = 3/2 +; CHECK-NEXT: outer: float = 1.5, +outer: + %I.0 = phi i32 [ 0, %entry ], [ %inc6, %outer.inc ] + %Return.0 = phi i32 [ 0, %entry ], [ %Return.1, %outer.inc ] + %cmp = icmp slt i32 %I.0, %N + br i1 %cmp, label %inner, label %exit, !prof !2 ; 2:1 + +; Mass = 1 +; Backedge mass = 3/5, exit mass = 2/5 +; Loop scale = 5/2 +; Pseudo-edges = outer.inc @ 1/5, exit @ 1/5 +; Pseudo-mass = 2/3 +; Frequency = 3/2*1*5/2*2/3 = 5/2 +; CHECK-NEXT: inner: float = 2.5, +inner: + %Return.1 = phi i32 [ %Return.0, %outer ], [ %call4, %inner.inc ] + %J.0 = phi i32 [ %I.0, %outer ], [ %inc, %inner.inc ] + %cmp2 = icmp slt i32 %J.0, %N + br i1 %cmp2, label %inner.body, label %outer.inc, !prof !1 ; 4:1 + +; Mass = 4/5 +; Frequency = 5/2*4/5 = 2 +; CHECK-NEXT: inner.body: float = 2.0, +inner.body: + %call = call i32 @c2(i32 %I.0, i32 %J.0) + %tobool = icmp ne i32 %call, 0 + br i1 %tobool, label %exit, label %inner.inc, !prof !0 ; 3:1 + +; Mass = 3/5 +; Frequency = 5/2*3/5 = 3/2 +; CHECK-NEXT: inner.inc: float = 1.5, +inner.inc: + %call4 = call i32 @logic2(i32 %Return.1, i32 %I.0, i32 %J.0) + %inc = add nsw i32 %J.0, 1 + br label %inner + +; Mass = 1/3 +; Frequency = 3/2*1/3 = 1/2 +; CHECK-NEXT: outer.inc: float = 0.5, +outer.inc: + %inc6 = add nsw i32 %I.0, 1 + br label %outer + +; Mass = 1 +; Frequency = 1 +; CHECK-NEXT: exit: float = 1.0, int = [[ENTRY]] +exit: + %Return.2 = phi i32 [ %Return.1, %inner.body ], [ %Return.0, %outer ] + ret i32 %Return.2 +} + +!0 = metadata !{metadata !"branch_weights", i32 1, i32 3} +!1 = metadata !{metadata !"branch_weights", i32 4, i32 1} +!2 = metadata !{metadata !"branch_weights", i32 2, i32 1} + +declare i32 @c2(i32, i32) +declare i32 @logic2(i32, i32, i32) + +; CHECK-LABEL: Printing analysis {{.*}} for function 'double_exit_in_loop': +; CHECK-NEXT: block-frequency-info: double_exit_in_loop +define i32 @double_exit_in_loop(i32 %N) { +; Mass = 1 +; Frequency = 1 +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] +entry: + br label %outer + +; Mass = 1 +; Backedge mass = 1/2, exit mass = 1/2 +; Loop scale = 2 +; Pseudo-edges = exit +; Pseudo-mass = 1 +; Frequency = 1*2*1 = 2 +; CHECK-NEXT: outer: float = 2.0, +outer: + %I.0 = phi i32 [ 0, %entry ], [ %inc12, %outer.inc ] + %Return.0 = phi i32 [ 0, %entry ], [ %Return.3, %outer.inc ] + %cmp = icmp slt i32 %I.0, %N + br i1 %cmp, label %middle, label %exit, !prof !3 ; 1:1 + +; Mass = 1 +; Backedge mass = 1/3, exit mass = 2/3 +; Loop scale = 3/2 +; Pseudo-edges = outer.inc +; Pseudo-mass = 1/2 +; Frequency = 2*1*3/2*1/2 = 3/2 +; CHECK-NEXT: middle: float = 1.5, +middle: + %J.0 = phi i32 [ %I.0, %outer ], [ %inc9, %middle.inc ] + %Return.1 = phi i32 [ %Return.0, %outer ], [ %Return.2, %middle.inc ] + %cmp2 = icmp slt i32 %J.0, %N + br i1 %cmp2, label %inner, label %outer.inc, !prof !2 ; 2:1 + +; Mass = 1 +; Backedge mass = 3/5, exit mass = 2/5 +; Loop scale = 5/2 +; Pseudo-edges = middle.inc @ 1/5, outer.inc @ 1/5 +; Pseudo-mass = 2/3 +; Frequency = 3/2*1*5/2*2/3 = 5/2 +; CHECK-NEXT: inner: float = 2.5, +inner: + %Return.2 = phi i32 [ %Return.1, %middle ], [ %call7, %inner.inc ] + %K.0 = phi i32 [ %J.0, %middle ], [ %inc, %inner.inc ] + %cmp5 = icmp slt i32 %K.0, %N + br i1 %cmp5, label %inner.body, label %middle.inc, !prof !1 ; 4:1 + +; Mass = 4/5 +; Frequency = 5/2*4/5 = 2 +; CHECK-NEXT: inner.body: float = 2.0, +inner.body: + %call = call i32 @c3(i32 %I.0, i32 %J.0, i32 %K.0) + %tobool = icmp ne i32 %call, 0 + br i1 %tobool, label %outer.inc, label %inner.inc, !prof !0 ; 3:1 + +; Mass = 3/5 +; Frequency = 5/2*3/5 = 3/2 +; CHECK-NEXT: inner.inc: float = 1.5, +inner.inc: + %call7 = call i32 @logic3(i32 %Return.2, i32 %I.0, i32 %J.0, i32 %K.0) + %inc = add nsw i32 %K.0, 1 + br label %inner + +; Mass = 1/3 +; Frequency = 3/2*1/3 = 1/2 +; CHECK-NEXT: middle.inc: float = 0.5, +middle.inc: + %inc9 = add nsw i32 %J.0, 1 + br label %middle + +; Mass = 1/2 +; Frequency = 2*1/2 = 1 +; CHECK-NEXT: outer.inc: float = 1.0, +outer.inc: + %Return.3 = phi i32 [ %Return.2, %inner.body ], [ %Return.1, %middle ] + %inc12 = add nsw i32 %I.0, 1 + br label %outer + +; Mass = 1 +; Frequency = 1 +; CHECK-NEXT: exit: float = 1.0, int = [[ENTRY]] +exit: + ret i32 %Return.0 +} + +!3 = metadata !{metadata !"branch_weights", i32 1, i32 1} + +declare i32 @c3(i32, i32, i32) +declare i32 @logic3(i32, i32, i32, i32) diff --git a/test/Analysis/BlockFrequencyInfo/irreducible.ll b/test/Analysis/BlockFrequencyInfo/irreducible.ll new file mode 100644 index 0000000000000..af4ad15d9c1d8 --- /dev/null +++ b/test/Analysis/BlockFrequencyInfo/irreducible.ll @@ -0,0 +1,421 @@ +; RUN: opt < %s -analyze -block-freq | FileCheck %s + +; A loop with multiple exits isn't irreducible. It should be handled +; correctly. +; +; CHECK-LABEL: Printing analysis {{.*}} for function 'multiexit': +; CHECK-NEXT: block-frequency-info: multiexit +define void @multiexit(i1 %x) { +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] +entry: + br label %loop.1 + +; CHECK-NEXT: loop.1: float = 2.0, +loop.1: + br i1 %x, label %exit.1, label %loop.2, !prof !0 + +; CHECK-NEXT: loop.2: float = 1.75, +loop.2: + br i1 %x, label %exit.2, label %loop.1, !prof !1 + +; CHECK-NEXT: exit.1: float = 0.25, +exit.1: + br label %return + +; CHECK-NEXT: exit.2: float = 0.75, +exit.2: + br label %return + +; CHECK-NEXT: return: float = 1.0, int = [[ENTRY]] +return: + ret void +} + +!0 = metadata !{metadata !"branch_weights", i32 1, i32 7} +!1 = metadata !{metadata !"branch_weights", i32 3, i32 4} + +; Irreducible control flow +; ======================== +; +; LoopInfo defines a loop as a non-trivial SCC dominated by a single block, +; called the header. A given loop, L, can have sub-loops, which are loops +; within the subgraph of L that excludes the header. +; +; In addition to loops, -block-freq has limited support for irreducible SCCs, +; which are SCCs with multiple entry blocks. Irreducible SCCs are discovered +; on they fly, and modelled as loops with multiple headers. +; +; The headers of irreducible sub-SCCs consist of its entry blocks and all nodes +; that are targets of a backedge within it (excluding backedges within true +; sub-loops). +; +; -block-freq is currently designed to act like a block is inserted that +; intercepts all the edges to the headers. All backedges and entries point to +; this block. Its successors are the headers, which split the frequency +; evenly. +; +; There are a number of testcases below. Only the first two have detailed +; explanations. +; +; Testcase #1 +; =========== +; +; In this case c1 and c2 should have frequencies of 15/7 and 13/7, +; respectively. To calculate this, consider assigning 1.0 to entry, and +; distributing frequency iteratively (to infinity). At the first iteration, +; entry gives 3/4 to c1 and 1/4 to c2. At every step after, c1 and c2 give 3/4 +; of what they have to each other. Somehow, all of it comes out to exit. +; +; c1 = 3/4 + 1/4*3/4 + 3/4*3^2/4^2 + 1/4*3^3/4^3 + 3/4*3^3/4^3 + ... +; c2 = 1/4 + 3/4*3/4 + 1/4*3^2/4^2 + 3/4*3^3/4^3 + 1/4*3^3/4^3 + ... +; +; Simplify by splitting up the odd and even terms of the series and taking out +; factors so that the infite series matches: +; +; c1 = 3/4 *(9^0/16^0 + 9^1/16^1 + 9^2/16^2 + ...) +; + 3/16*(9^0/16^0 + 9^1/16^1 + 9^2/16^2 + ...) +; c2 = 1/4 *(9^0/16^0 + 9^1/16^1 + 9^2/16^2 + ...) +; + 9/16*(9^0/16^0 + 9^1/16^1 + 9^2/16^2 + ...) +; +; c1 = 15/16*(9^0/16^0 + 9^1/16^1 + 9^2/16^2 + ...) +; c2 = 13/16*(9^0/16^0 + 9^1/16^1 + 9^2/16^2 + ...) +; +; Since this geometric series sums to 16/7: +; +; c1 = 15/7 +; c2 = 13/7 +; +; If we treat c1 and c2 as members of the same loop, the exit frequency of the +; loop as a whole is 1/4, so the loop scale should be 4. Summing c1 and c2 +; gives 28/7, or 4.0, which is nice confirmation of the math above. +; +; -block-freq currently treats the two nodes as equals. +define void @multientry(i1 %x) { +; CHECK-LABEL: Printing analysis {{.*}} for function 'multientry': +; CHECK-NEXT: block-frequency-info: multientry +entry: +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] + br i1 %x, label %c1, label %c2, !prof !2 + +c1: +; CHECK-NEXT: c1: float = 2.0, +; The "correct" answer is: float = 2.142857{{[0-9]*}}, + br i1 %x, label %c2, label %exit, !prof !2 + +c2: +; CHECK-NEXT: c2: float = 2.0, +; The "correct" answer is: float = 1.857142{{[0-9]*}}, + br i1 %x, label %c1, label %exit, !prof !2 + +exit: +; CHECK-NEXT: exit: float = 1.0, int = [[ENTRY]] + ret void +} + +!2 = metadata !{metadata !"branch_weights", i32 3, i32 1} + +; Testcase #2 +; =========== +; +; In this case c1 and c2 should be treated as equals in a single loop. The +; exit frequency is 1/3, so the scaling factor for the loop should be 3.0. The +; loop is entered 2/3 of the time, and c1 and c2 split the total loop frequency +; evenly (1/2), so they should each have frequencies of 1.0 (3.0*2/3*1/2). +; Another way of computing this result is by assigning 1.0 to entry and showing +; that c1 and c2 should accumulate frequencies of: +; +; 1/3 + 2/9 + 4/27 + 8/81 + ... +; 2^0/3^1 + 2^1/3^2 + 2^2/3^3 + 2^3/3^4 + ... +; +; At the first step, c1 and c2 each get 1/3 of the entry. At each subsequent +; step, c1 and c2 each get 1/3 of what's left in c1 and c2 combined. This +; infinite series sums to 1. +; +; Since the currently algorithm *always* assumes entry blocks are equal, +; -block-freq gets the right answers here. +define void @crossloops(i2 %x) { +; CHECK-LABEL: Printing analysis {{.*}} for function 'crossloops': +; CHECK-NEXT: block-frequency-info: crossloops +entry: +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] + switch i2 %x, label %exit [ i2 1, label %c1 + i2 2, label %c2 ], !prof !3 + +c1: +; CHECK-NEXT: c1: float = 1.0, + switch i2 %x, label %exit [ i2 1, label %c1 + i2 2, label %c2 ], !prof !3 + +c2: +; CHECK-NEXT: c2: float = 1.0, + switch i2 %x, label %exit [ i2 1, label %c1 + i2 2, label %c2 ], !prof !3 + +exit: +; CHECK-NEXT: exit: float = 1.0, int = [[ENTRY]] + ret void +} + +!3 = metadata !{metadata !"branch_weights", i32 2, i32 2, i32 2} + +; A true loop with irreducible control flow inside. +define void @loop_around_irreducible(i1 %x) { +; CHECK-LABEL: Printing analysis {{.*}} for function 'loop_around_irreducible': +; CHECK-NEXT: block-frequency-info: loop_around_irreducible +entry: +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] + br label %loop + +loop: +; CHECK-NEXT: loop: float = 4.0, int = [[HEAD:[0-9]+]] + br i1 %x, label %left, label %right, !prof !4 + +left: +; CHECK-NEXT: left: float = 8.0, + br i1 %x, label %right, label %loop.end, !prof !5 + +right: +; CHECK-NEXT: right: float = 8.0, + br i1 %x, label %left, label %loop.end, !prof !5 + +loop.end: +; CHECK-NEXT: loop.end: float = 4.0, int = [[HEAD]] + br i1 %x, label %loop, label %exit, !prof !5 + +exit: +; CHECK-NEXT: exit: float = 1.0, int = [[ENTRY]] + ret void +} +!4 = metadata !{metadata !"branch_weights", i32 1, i32 1} +!5 = metadata !{metadata !"branch_weights", i32 3, i32 1} + +; Two unrelated irreducible SCCs. +define void @two_sccs(i1 %x) { +; CHECK-LABEL: Printing analysis {{.*}} for function 'two_sccs': +; CHECK-NEXT: block-frequency-info: two_sccs +entry: +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] + br i1 %x, label %a, label %b, !prof !6 + +a: +; CHECK-NEXT: a: float = 0.75, + br i1 %x, label %a.left, label %a.right, !prof !7 + +a.left: +; CHECK-NEXT: a.left: float = 1.5, + br i1 %x, label %a.right, label %exit, !prof !6 + +a.right: +; CHECK-NEXT: a.right: float = 1.5, + br i1 %x, label %a.left, label %exit, !prof !6 + +b: +; CHECK-NEXT: b: float = 0.25, + br i1 %x, label %b.left, label %b.right, !prof !7 + +b.left: +; CHECK-NEXT: b.left: float = 0.625, + br i1 %x, label %b.right, label %exit, !prof !8 + +b.right: +; CHECK-NEXT: b.right: float = 0.625, + br i1 %x, label %b.left, label %exit, !prof !8 + +exit: +; CHECK-NEXT: exit: float = 1.0, int = [[ENTRY]] + ret void +} +!6 = metadata !{metadata !"branch_weights", i32 3, i32 1} +!7 = metadata !{metadata !"branch_weights", i32 1, i32 1} +!8 = metadata !{metadata !"branch_weights", i32 4, i32 1} + +; A true loop inside irreducible control flow. +define void @loop_inside_irreducible(i1 %x) { +; CHECK-LABEL: Printing analysis {{.*}} for function 'loop_inside_irreducible': +; CHECK-NEXT: block-frequency-info: loop_inside_irreducible +entry: +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] + br i1 %x, label %left, label %right, !prof !9 + +left: +; CHECK-NEXT: left: float = 2.0, + br i1 %x, label %right, label %exit, !prof !10 + +right: +; CHECK-NEXT: right: float = 2.0, int = [[RIGHT:[0-9]+]] + br label %loop + +loop: +; CHECK-NEXT: loop: float = 6.0, + br i1 %x, label %loop, label %right.end, !prof !11 + +right.end: +; CHECK-NEXT: right.end: float = 2.0, int = [[RIGHT]] + br i1 %x, label %left, label %exit, !prof !10 + +exit: +; CHECK-NEXT: exit: float = 1.0, int = [[ENTRY]] + ret void +} +!9 = metadata !{metadata !"branch_weights", i32 1, i32 1} +!10 = metadata !{metadata !"branch_weights", i32 3, i32 1} +!11 = metadata !{metadata !"branch_weights", i32 2, i32 1} + +; Irreducible control flow in a branch that's in a true loop. +define void @loop_around_branch_with_irreducible(i1 %x) { +; CHECK-LABEL: Printing analysis {{.*}} for function 'loop_around_branch_with_irreducible': +; CHECK-NEXT: block-frequency-info: loop_around_branch_with_irreducible +entry: +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] + br label %loop + +loop: +; CHECK-NEXT: loop: float = 2.0, int = [[LOOP:[0-9]+]] + br i1 %x, label %normal, label %irreducible.entry, !prof !12 + +normal: +; CHECK-NEXT: normal: float = 1.5, + br label %loop.end + +irreducible.entry: +; CHECK-NEXT: irreducible.entry: float = 0.5, int = [[IRREDUCIBLE:[0-9]+]] + br i1 %x, label %left, label %right, !prof !13 + +left: +; CHECK-NEXT: left: float = 1.0, + br i1 %x, label %right, label %irreducible.exit, !prof !12 + +right: +; CHECK-NEXT: right: float = 1.0, + br i1 %x, label %left, label %irreducible.exit, !prof !12 + +irreducible.exit: +; CHECK-NEXT: irreducible.exit: float = 0.5, int = [[IRREDUCIBLE]] + br label %loop.end + +loop.end: +; CHECK-NEXT: loop.end: float = 2.0, int = [[LOOP]] + br i1 %x, label %loop, label %exit, !prof !13 + +exit: +; CHECK-NEXT: exit: float = 1.0, int = [[ENTRY]] + ret void +} +!12 = metadata !{metadata !"branch_weights", i32 3, i32 1} +!13 = metadata !{metadata !"branch_weights", i32 1, i32 1} + +; Irreducible control flow between two true loops. +define void @loop_around_branch_with_irreducible_around_loop(i1 %x) { +; CHECK-LABEL: Printing analysis {{.*}} for function 'loop_around_branch_with_irreducible_around_loop': +; CHECK-NEXT: block-frequency-info: loop_around_branch_with_irreducible_around_loop +entry: +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] + br label %loop + +loop: +; CHECK-NEXT: loop: float = 3.0, int = [[LOOP:[0-9]+]] + br i1 %x, label %normal, label %irreducible, !prof !14 + +normal: +; CHECK-NEXT: normal: float = 2.0, + br label %loop.end + +irreducible: +; CHECK-NEXT: irreducible: float = 1.0, + br i1 %x, label %left, label %right, !prof !15 + +left: +; CHECK-NEXT: left: float = 2.0, + br i1 %x, label %right, label %loop.end, !prof !16 + +right: +; CHECK-NEXT: right: float = 2.0, int = [[RIGHT:[0-9]+]] + br label %right.loop + +right.loop: +; CHECK-NEXT: right.loop: float = 10.0, + br i1 %x, label %right.loop, label %right.end, !prof !17 + +right.end: +; CHECK-NEXT: right.end: float = 2.0, int = [[RIGHT]] + br i1 %x, label %left, label %loop.end, !prof !16 + +loop.end: +; CHECK-NEXT: loop.end: float = 3.0, int = [[LOOP]] + br i1 %x, label %loop, label %exit, !prof !14 + +exit: +; CHECK-NEXT: exit: float = 1.0, int = [[ENTRY]] + ret void +} +!14 = metadata !{metadata !"branch_weights", i32 2, i32 1} +!15 = metadata !{metadata !"branch_weights", i32 1, i32 1} +!16 = metadata !{metadata !"branch_weights", i32 3, i32 1} +!17 = metadata !{metadata !"branch_weights", i32 4, i32 1} + +; An irreducible SCC with a non-header. +define void @nonheader(i1 %x) { +; CHECK-LABEL: Printing analysis {{.*}} for function 'nonheader': +; CHECK-NEXT: block-frequency-info: nonheader +entry: +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] + br i1 %x, label %left, label %right, !prof !18 + +left: +; CHECK-NEXT: left: float = 1.0, + br i1 %x, label %bottom, label %exit, !prof !19 + +right: +; CHECK-NEXT: right: float = 1.0, + br i1 %x, label %bottom, label %exit, !prof !20 + +bottom: +; CHECK-NEXT: bottom: float = 1.0, + br i1 %x, label %left, label %right, !prof !18 + +exit: +; CHECK-NEXT: exit: float = 1.0, int = [[ENTRY]] + ret void +} +!18 = metadata !{metadata !"branch_weights", i32 1, i32 1} +!19 = metadata !{metadata !"branch_weights", i32 1, i32 3} +!20 = metadata !{metadata !"branch_weights", i32 3, i32 1} + +; An irreducible SCC with an irreducible sub-SCC. In the current version of +; -block-freq, this means an extra header. +; +; This testcases uses non-trivial branch weights. The CHECK statements here +; will start to fail if we change -block-freq to be more accurate. Currently, +; we expect left, right and top to be treated as equal headers. +define void @nonentry_header(i1 %x, i2 %y) { +; CHECK-LABEL: Printing analysis {{.*}} for function 'nonentry_header': +; CHECK-NEXT: block-frequency-info: nonentry_header +entry: +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] + br i1 %x, label %left, label %right, !prof !21 + +left: +; CHECK-NEXT: left: float = 3.0, + br i1 %x, label %top, label %bottom, !prof !22 + +right: +; CHECK-NEXT: right: float = 3.0, + br i1 %x, label %top, label %bottom, !prof !22 + +top: +; CHECK-NEXT: top: float = 3.0, + switch i2 %y, label %exit [ i2 0, label %left + i2 1, label %right + i2 2, label %bottom ], !prof !23 + +bottom: +; CHECK-NEXT: bottom: float = 4.5, + br label %top + +exit: +; CHECK-NEXT: exit: float = 1.0, int = [[ENTRY]] + ret void +} +!21 = metadata !{metadata !"branch_weights", i32 2, i32 1} +!22 = metadata !{metadata !"branch_weights", i32 1, i32 1} +!23 = metadata !{metadata !"branch_weights", i32 8, i32 1, i32 3, i32 12} diff --git a/test/Analysis/BlockFrequencyInfo/loop_with_branch.ll b/test/Analysis/BlockFrequencyInfo/loop_with_branch.ll new file mode 100644 index 0000000000000..9d27b6bf0f201 --- /dev/null +++ b/test/Analysis/BlockFrequencyInfo/loop_with_branch.ll @@ -0,0 +1,44 @@ +; RUN: opt < %s -analyze -block-freq | FileCheck %s + +; CHECK-LABEL: Printing analysis {{.*}} for function 'loop_with_branch': +; CHECK-NEXT: block-frequency-info: loop_with_branch +define void @loop_with_branch(i32 %a) { +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] +entry: + %skip_loop = call i1 @foo0(i32 %a) + br i1 %skip_loop, label %skip, label %header, !prof !0 + +; CHECK-NEXT: skip: float = 0.25, +skip: + br label %exit + +; CHECK-NEXT: header: float = 4.5, +header: + %i = phi i32 [ 0, %entry ], [ %i.next, %back ] + %i.next = add i32 %i, 1 + %choose = call i2 @foo1(i32 %i) + switch i2 %choose, label %exit [ i2 0, label %left + i2 1, label %right ], !prof !1 + +; CHECK-NEXT: left: float = 1.5, +left: + br label %back + +; CHECK-NEXT: right: float = 2.25, +right: + br label %back + +; CHECK-NEXT: back: float = 3.75, +back: + br label %header + +; CHECK-NEXT: exit: float = 1.0, int = [[ENTRY]] +exit: + ret void +} + +declare i1 @foo0(i32) +declare i2 @foo1(i32) + +!0 = metadata !{metadata !"branch_weights", i32 1, i32 3} +!1 = metadata !{metadata !"branch_weights", i32 1, i32 2, i32 3} diff --git a/test/Analysis/BlockFrequencyInfo/nested_loop_with_branches.ll b/test/Analysis/BlockFrequencyInfo/nested_loop_with_branches.ll new file mode 100644 index 0000000000000..d93ffceb5fabf --- /dev/null +++ b/test/Analysis/BlockFrequencyInfo/nested_loop_with_branches.ll @@ -0,0 +1,59 @@ +; RUN: opt < %s -analyze -block-freq | FileCheck %s + +; CHECK-LABEL: Printing analysis {{.*}} for function 'nested_loop_with_branches' +; CHECK-NEXT: block-frequency-info: nested_loop_with_branches +define void @nested_loop_with_branches(i32 %a) { +; CHECK-NEXT: entry: float = 1.0, int = [[ENTRY:[0-9]+]] +entry: + %v0 = call i1 @foo0(i32 %a) + br i1 %v0, label %exit, label %outer, !prof !0 + +; CHECK-NEXT: outer: float = 12.0, +outer: + %i = phi i32 [ 0, %entry ], [ %i.next, %inner.end ], [ %i.next, %no_inner ] + %i.next = add i32 %i, 1 + %do_inner = call i1 @foo1(i32 %i) + br i1 %do_inner, label %no_inner, label %inner, !prof !0 + +; CHECK-NEXT: inner: float = 36.0, +inner: + %j = phi i32 [ 0, %outer ], [ %j.next, %inner.end ] + %side = call i1 @foo3(i32 %j) + br i1 %side, label %left, label %right, !prof !0 + +; CHECK-NEXT: left: float = 9.0, +left: + %v4 = call i1 @foo4(i32 %j) + br label %inner.end + +; CHECK-NEXT: right: float = 27.0, +right: + %v5 = call i1 @foo5(i32 %j) + br label %inner.end + +; CHECK-NEXT: inner.end: float = 36.0, +inner.end: + %stay_inner = phi i1 [ %v4, %left ], [ %v5, %right ] + %j.next = add i32 %j, 1 + br i1 %stay_inner, label %inner, label %outer, !prof !1 + +; CHECK-NEXT: no_inner: float = 3.0, +no_inner: + %continue = call i1 @foo6(i32 %i) + br i1 %continue, label %outer, label %exit, !prof !1 + +; CHECK-NEXT: exit: float = 1.0, int = [[ENTRY]] +exit: + ret void +} + +declare i1 @foo0(i32) +declare i1 @foo1(i32) +declare i1 @foo2(i32) +declare i1 @foo3(i32) +declare i1 @foo4(i32) +declare i1 @foo5(i32) +declare i1 @foo6(i32) + +!0 = metadata !{metadata !"branch_weights", i32 1, i32 3} +!1 = metadata !{metadata !"branch_weights", i32 3, i32 1} diff --git a/test/Analysis/BranchProbabilityInfo/loop.ll b/test/Analysis/BranchProbabilityInfo/loop.ll index b648cbb16a60d..40f1111c6b03b 100644 --- a/test/Analysis/BranchProbabilityInfo/loop.ll +++ b/test/Analysis/BranchProbabilityInfo/loop.ll @@ -15,7 +15,7 @@ do.body: %i.0 = phi i32 [ 0, %entry ], [ %inc3, %do.end ] call void @g1() br label %do.body1 -; CHECK: edge do.body -> do.body1 probability is 124 / 124 = 100% +; CHECK: edge do.body -> do.body1 probability is 16 / 16 = 100% do.body1: %j.0 = phi i32 [ 0, %do.body ], [ %inc, %do.body1 ] @@ -55,8 +55,8 @@ for.body: %i.010 = phi i32 [ 0, %for.body.lr.ph ], [ %inc5, %for.end ] call void @g1() br i1 %cmp27, label %for.body3, label %for.end -; CHECK: edge for.body -> for.body3 probability is 62 / 124 = 50% -; CHECK: edge for.body -> for.end probability is 62 / 124 = 50% +; CHECK: edge for.body -> for.body3 probability is 20 / 32 = 62.5% +; CHECK: edge for.body -> for.end probability is 12 / 32 = 37.5% for.body3: %j.08 = phi i32 [ %inc, %for.body3 ], [ 0, %for.body ] @@ -91,8 +91,8 @@ do.body: %0 = load i32* %c, align 4 %cmp = icmp slt i32 %0, 42 br i1 %cmp, label %do.body1, label %if.end -; CHECK: edge do.body -> do.body1 probability is 62 / 124 = 50% -; CHECK: edge do.body -> if.end probability is 62 / 124 = 50% +; CHECK: edge do.body -> do.body1 probability is 16 / 32 = 50% +; CHECK: edge do.body -> if.end probability is 16 / 32 = 50% do.body1: %j.0 = phi i32 [ %inc, %do.body1 ], [ 0, %do.body ] @@ -165,7 +165,7 @@ do.body: %i.0 = phi i32 [ 0, %entry ], [ %inc4, %do.end ] call void @g1() br label %do.body1 -; CHECK: edge do.body -> do.body1 probability is 124 / 124 = 100% +; CHECK: edge do.body -> do.body1 probability is 16 / 16 = 100% do.body1: %j.0 = phi i32 [ 0, %do.body ], [ %inc, %if.end ] @@ -209,7 +209,7 @@ do.body: %i.0 = phi i32 [ 0, %entry ], [ %inc4, %do.end ] call void @g1() br label %do.body1 -; CHECK: edge do.body -> do.body1 probability is 124 / 124 = 100% +; CHECK: edge do.body -> do.body1 probability is 16 / 16 = 100% do.body1: %j.0 = phi i32 [ 0, %do.body ], [ %inc, %do.cond ] @@ -261,14 +261,14 @@ for.body: %0 = load i32* %c, align 4 %cmp1 = icmp eq i32 %0, %i.011 br i1 %cmp1, label %for.inc5, label %if.end -; CHECK: edge for.body -> for.inc5 probability is 62 / 124 = 50% -; CHECK: edge for.body -> if.end probability is 62 / 124 = 50% +; CHECK: edge for.body -> for.inc5 probability is 16 / 32 = 50% +; CHECK: edge for.body -> if.end probability is 16 / 32 = 50% if.end: call void @g1() br i1 %cmp38, label %for.body4, label %for.end -; CHECK: edge if.end -> for.body4 probability is 62 / 124 = 50% -; CHECK: edge if.end -> for.end probability is 62 / 124 = 50% +; CHECK: edge if.end -> for.body4 probability is 20 / 32 = 62.5% +; CHECK: edge if.end -> for.end probability is 12 / 32 = 37.5% for.body4: %j.09 = phi i32 [ %inc, %for.body4 ], [ 0, %if.end ] @@ -282,7 +282,7 @@ for.body4: for.end: call void @g3() br label %for.inc5 -; CHECK: edge for.end -> for.inc5 probability is 124 / 124 = 100% +; CHECK: edge for.end -> for.inc5 probability is 16 / 16 = 100% for.inc5: %inc6 = add nsw i32 %i.011, 1 @@ -314,35 +314,35 @@ for.body: %i.019 = phi i32 [ 0, %for.body.lr.ph ], [ %inc14, %for.end ] call void @g1() br i1 %cmp216, label %for.body3, label %for.end -; CHECK: edge for.body -> for.body3 probability is 62 / 124 = 50% -; CHECK: edge for.body -> for.end probability is 62 / 124 = 50% +; CHECK: edge for.body -> for.body3 probability is 20 / 32 = 62.5% +; CHECK: edge for.body -> for.end probability is 12 / 32 = 37.5% for.body3: %j.017 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ] %0 = load i32* %c, align 4 %cmp4 = icmp eq i32 %0, %j.017 br i1 %cmp4, label %for.inc, label %if.end -; CHECK: edge for.body3 -> for.inc probability is 62 / 124 = 50% -; CHECK: edge for.body3 -> if.end probability is 62 / 124 = 50% +; CHECK: edge for.body3 -> for.inc probability is 16 / 32 = 50% +; CHECK: edge for.body3 -> if.end probability is 16 / 32 = 50% if.end: %1 = load i32* %arrayidx5, align 4 %cmp6 = icmp eq i32 %1, %j.017 br i1 %cmp6, label %for.inc, label %if.end8 -; CHECK: edge if.end -> for.inc probability is 62 / 124 = 50% -; CHECK: edge if.end -> if.end8 probability is 62 / 124 = 50% +; CHECK: edge if.end -> for.inc probability is 16 / 32 = 50% +; CHECK: edge if.end -> if.end8 probability is 16 / 32 = 50% if.end8: %2 = load i32* %arrayidx9, align 4 %cmp10 = icmp eq i32 %2, %j.017 br i1 %cmp10, label %for.inc, label %if.end12 -; CHECK: edge if.end8 -> for.inc probability is 62 / 124 = 50% -; CHECK: edge if.end8 -> if.end12 probability is 62 / 124 = 50% +; CHECK: edge if.end8 -> for.inc probability is 16 / 32 = 50% +; CHECK: edge if.end8 -> if.end12 probability is 16 / 32 = 50% if.end12: call void @g2() br label %for.inc -; CHECK: edge if.end12 -> for.inc probability is 124 / 124 = 100% +; CHECK: edge if.end12 -> for.inc probability is 16 / 16 = 100% for.inc: %inc = add nsw i32 %j.017, 1 diff --git a/test/Analysis/BranchProbabilityInfo/pr18705.ll b/test/Analysis/BranchProbabilityInfo/pr18705.ll new file mode 100644 index 0000000000000..9f239b46058d1 --- /dev/null +++ b/test/Analysis/BranchProbabilityInfo/pr18705.ll @@ -0,0 +1,58 @@ +; RUN: opt < %s -analyze -branch-prob | FileCheck %s + +; Since neither of while.body's out-edges is an exit or a back edge, +; calcLoopBranchHeuristics should return early without setting the weights. +; calcFloatingPointHeuristics, which is run later, sets the weights. +; +; CHECK: edge while.body -> if.then probability is 20 / 32 = 62.5% +; CHECK: edge while.body -> if.else probability is 12 / 32 = 37.5% + +define void @foo1(i32 %n, i32* nocapture %b, i32* nocapture %c, i32* nocapture %d, float* nocapture readonly %f0, float* nocapture readonly %f1) { +entry: + %tobool8 = icmp eq i32 %n, 0 + br i1 %tobool8, label %while.end, label %while.body.lr.ph + +while.body.lr.ph: + %0 = sext i32 %n to i64 + br label %while.body + +while.body: + %indvars.iv = phi i64 [ %0, %while.body.lr.ph ], [ %indvars.iv.next, %if.end ] + %b.addr.011 = phi i32* [ %b, %while.body.lr.ph ], [ %b.addr.1, %if.end ] + %d.addr.010 = phi i32* [ %d, %while.body.lr.ph ], [ %incdec.ptr4, %if.end ] + %c.addr.09 = phi i32* [ %c, %while.body.lr.ph ], [ %c.addr.1, %if.end ] + %indvars.iv.next = add nsw i64 %indvars.iv, -1 + %arrayidx = getelementptr inbounds float* %f0, i64 %indvars.iv.next + %1 = load float* %arrayidx, align 4 + %arrayidx2 = getelementptr inbounds float* %f1, i64 %indvars.iv.next + %2 = load float* %arrayidx2, align 4 + %cmp = fcmp une float %1, %2 + br i1 %cmp, label %if.then, label %if.else + +if.then: + %incdec.ptr = getelementptr inbounds i32* %b.addr.011, i64 1 + %3 = load i32* %b.addr.011, align 4 + %add = add nsw i32 %3, 12 + store i32 %add, i32* %b.addr.011, align 4 + br label %if.end + +if.else: + %incdec.ptr3 = getelementptr inbounds i32* %c.addr.09, i64 1 + %4 = load i32* %c.addr.09, align 4 + %sub = add nsw i32 %4, -13 + store i32 %sub, i32* %c.addr.09, align 4 + br label %if.end + +if.end: + %c.addr.1 = phi i32* [ %c.addr.09, %if.then ], [ %incdec.ptr3, %if.else ] + %b.addr.1 = phi i32* [ %incdec.ptr, %if.then ], [ %b.addr.011, %if.else ] + %incdec.ptr4 = getelementptr inbounds i32* %d.addr.010, i64 1 + store i32 14, i32* %d.addr.010, align 4 + %5 = trunc i64 %indvars.iv.next to i32 + %tobool = icmp eq i32 %5, 0 + br i1 %tobool, label %while.end, label %while.body + +while.end: + ret void +} + diff --git a/test/Analysis/CostModel/AArch64/lit.local.cfg b/test/Analysis/CostModel/AArch64/lit.local.cfg new file mode 100644 index 0000000000000..7184443994b69 --- /dev/null +++ b/test/Analysis/CostModel/AArch64/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'AArch64' in config.root.targets: + config.unsupported = True diff --git a/test/Analysis/CostModel/AArch64/select.ll b/test/Analysis/CostModel/AArch64/select.ll new file mode 100644 index 0000000000000..216dc5ddc4888 --- /dev/null +++ b/test/Analysis/CostModel/AArch64/select.ll @@ -0,0 +1,38 @@ +; RUN: opt < %s -cost-model -analyze -mtriple=arm64-apple-ios -mcpu=cyclone | FileCheck %s +target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:32:64-v128:32:128-a0:0:32-n32-S32" + +; CHECK-LABEL: select +define void @select() { + ; Scalar values + ; CHECK: cost of 1 {{.*}} select + %v1 = select i1 undef, i8 undef, i8 undef + ; CHECK: cost of 1 {{.*}} select + %v2 = select i1 undef, i16 undef, i16 undef + ; CHECK: cost of 1 {{.*}} select + %v3 = select i1 undef, i32 undef, i32 undef + ; CHECK: cost of 1 {{.*}} select + %v4 = select i1 undef, i64 undef, i64 undef + ; CHECK: cost of 1 {{.*}} select + %v5 = select i1 undef, float undef, float undef + ; CHECK: cost of 1 {{.*}} select + %v6 = select i1 undef, double undef, double undef + + ; Vector values - check for vectors that have a high cost because they end up + ; scalarized. + ; CHECK: cost of 320 {{.*}} select + %v13b = select <16 x i1> undef, <16 x i16> undef, <16 x i16> undef + + ; CHECK: cost of 160 {{.*}} select + %v15b = select <8 x i1> undef, <8 x i32> undef, <8 x i32> undef + ; CHECK: cost of 320 {{.*}} select + %v15c = select <16 x i1> undef, <16 x i32> undef, <16 x i32> undef + + ; CHECK: cost of 80 {{.*}} select + %v16a = select <4 x i1> undef, <4 x i64> undef, <4 x i64> undef + ; CHECK: cost of 160 {{.*}} select + %v16b = select <8 x i1> undef, <8 x i64> undef, <8 x i64> undef + ; CHECK: cost of 320 {{.*}} select + %v16c = select <16 x i1> undef, <16 x i64> undef, <16 x i64> undef + + ret void +} diff --git a/test/Analysis/CostModel/AArch64/store.ll b/test/Analysis/CostModel/AArch64/store.ll new file mode 100644 index 0000000000000..0c9883cf2a2f7 --- /dev/null +++ b/test/Analysis/CostModel/AArch64/store.ll @@ -0,0 +1,22 @@ +; RUN: opt < %s -cost-model -analyze -mtriple=arm64-apple-ios -mcpu=cyclone | FileCheck %s +target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:32:64-v128:32:128-a0:0:32-n32-S32" +; CHECK-LABEL: store +define void @store() { + ; Stores of <2 x i64> should be expensive because we don't split them and + ; and unaligned 16b stores have bad performance. + ; CHECK: cost of 12 {{.*}} store + store <2 x i64> undef, <2 x i64> * undef + + ; We scalarize the loads/stores because there is no vector register name for + ; these types (they get extended to v.4h/v.2s). + ; CHECK: cost of 16 {{.*}} store + store <2 x i8> undef, <2 x i8> * undef + ; CHECK: cost of 64 {{.*}} store + store <4 x i8> undef, <4 x i8> * undef + ; CHECK: cost of 16 {{.*}} load + load <2 x i8> * undef + ; CHECK: cost of 64 {{.*}} load + load <4 x i8> * undef + + ret void +} diff --git a/test/Analysis/CostModel/ARM/cast.ll b/test/Analysis/CostModel/ARM/cast.ll index 0cdd61cac4f7f..662110f2720d4 100644 --- a/test/Analysis/CostModel/ARM/cast.ll +++ b/test/Analysis/CostModel/ARM/cast.ll @@ -221,9 +221,9 @@ define i32 @casts() { %r96 = fptoui <2 x float> undef to <2 x i32> ; CHECK: cost of 1 {{.*}} fptosi %r97 = fptosi <2 x float> undef to <2 x i32> - ; CHECK: cost of 24 {{.*}} fptoui + ; CHECK: cost of 28 {{.*}} fptoui %r98 = fptoui <2 x float> undef to <2 x i64> - ; CHECK: cost of 24 {{.*}} fptosi + ; CHECK: cost of 28 {{.*}} fptosi %r99 = fptosi <2 x float> undef to <2 x i64> ; CHECK: cost of 8 {{.*}} fptoui @@ -242,9 +242,9 @@ define i32 @casts() { %r106 = fptoui <2 x double> undef to <2 x i32> ; CHECK: cost of 2 {{.*}} fptosi %r107 = fptosi <2 x double> undef to <2 x i32> - ; CHECK: cost of 24 {{.*}} fptoui + ; CHECK: cost of 28 {{.*}} fptoui %r108 = fptoui <2 x double> undef to <2 x i64> - ; CHECK: cost of 24 {{.*}} fptosi + ; CHECK: cost of 28 {{.*}} fptosi %r109 = fptosi <2 x double> undef to <2 x i64> ; CHECK: cost of 16 {{.*}} fptoui @@ -263,9 +263,9 @@ define i32 @casts() { %r116 = fptoui <4 x float> undef to <4 x i32> ; CHECK: cost of 1 {{.*}} fptosi %r117 = fptosi <4 x float> undef to <4 x i32> - ; CHECK: cost of 48 {{.*}} fptoui + ; CHECK: cost of 56 {{.*}} fptoui %r118 = fptoui <4 x float> undef to <4 x i64> - ; CHECK: cost of 48 {{.*}} fptosi + ; CHECK: cost of 56 {{.*}} fptosi %r119 = fptosi <4 x float> undef to <4 x i64> ; CHECK: cost of 16 {{.*}} fptoui @@ -284,9 +284,9 @@ define i32 @casts() { %r126 = fptoui <4 x double> undef to <4 x i32> ; CHECK: cost of 16 {{.*}} fptosi %r127 = fptosi <4 x double> undef to <4 x i32> - ; CHECK: cost of 48 {{.*}} fptoui + ; CHECK: cost of 56 {{.*}} fptoui %r128 = fptoui <4 x double> undef to <4 x i64> - ; CHECK: cost of 48 {{.*}} fptosi + ; CHECK: cost of 56 {{.*}} fptosi %r129 = fptosi <4 x double> undef to <4 x i64> ; CHECK: cost of 32 {{.*}} fptoui @@ -305,9 +305,9 @@ define i32 @casts() { %r136 = fptoui <8 x float> undef to <8 x i32> ; CHECK: cost of 2 {{.*}} fptosi %r137 = fptosi <8 x float> undef to <8 x i32> - ; CHECK: cost of 96 {{.*}} fptoui + ; CHECK: cost of 112 {{.*}} fptoui %r138 = fptoui <8 x float> undef to <8 x i64> - ; CHECK: cost of 96 {{.*}} fptosi + ; CHECK: cost of 112 {{.*}} fptosi %r139 = fptosi <8 x float> undef to <8 x i64> ; CHECK: cost of 32 {{.*}} fptoui @@ -326,9 +326,9 @@ define i32 @casts() { %r146 = fptoui <8 x double> undef to <8 x i32> ; CHECK: cost of 32 {{.*}} fptosi %r147 = fptosi <8 x double> undef to <8 x i32> - ; CHECK: cost of 96 {{.*}} fptoui + ; CHECK: cost of 112 {{.*}} fptoui %r148 = fptoui <8 x double> undef to <8 x i64> - ; CHECK: cost of 96 {{.*}} fptosi + ; CHECK: cost of 112 {{.*}} fptosi %r149 = fptosi <8 x double> undef to <8 x i64> ; CHECK: cost of 64 {{.*}} fptoui @@ -347,9 +347,9 @@ define i32 @casts() { %r156 = fptoui <16 x float> undef to <16 x i32> ; CHECK: cost of 4 {{.*}} fptosi %r157 = fptosi <16 x float> undef to <16 x i32> - ; CHECK: cost of 192 {{.*}} fptoui + ; CHECK: cost of 224 {{.*}} fptoui %r158 = fptoui <16 x float> undef to <16 x i64> - ; CHECK: cost of 192 {{.*}} fptosi + ; CHECK: cost of 224 {{.*}} fptosi %r159 = fptosi <16 x float> undef to <16 x i64> ; CHECK: cost of 64 {{.*}} fptoui @@ -368,9 +368,9 @@ define i32 @casts() { %r166 = fptoui <16 x double> undef to <16 x i32> ; CHECK: cost of 64 {{.*}} fptosi %r167 = fptosi <16 x double> undef to <16 x i32> - ; CHECK: cost of 192 {{.*}} fptoui + ; CHECK: cost of 224 {{.*}} fptoui %r168 = fptoui <16 x double> undef to <16 x i64> - ; CHECK: cost of 192 {{.*}} fptosi + ; CHECK: cost of 224 {{.*}} fptosi %r169 = fptosi <16 x double> undef to <16 x i64> ; CHECK: cost of 8 {{.*}} uitofp @@ -528,7 +528,7 @@ define i32 @casts() { %r242 = uitofp <16 x i8> undef to <16 x double> ; CHECK: cost of 64 {{.*}} sitofp %r243 = sitofp <16 x i8> undef to <16 x double> - ; C4ECK: cost of 64 {{.*}} uitofp + ; CHECK: cost of 64 {{.*}} uitofp %r244 = uitofp <16 x i16> undef to <16 x double> ; CHECK: cost of 64 {{.*}} sitofp %r245 = sitofp <16 x i16> undef to <16 x double> diff --git a/test/Analysis/CostModel/ARM/lit.local.cfg b/test/Analysis/CostModel/ARM/lit.local.cfg index 8a3ba96497e7d..98c6700c209d7 100644 --- a/test/Analysis/CostModel/ARM/lit.local.cfg +++ b/test/Analysis/CostModel/ARM/lit.local.cfg @@ -1,4 +1,3 @@ -targets = set(config.root.targets_to_build.split()) -if not 'ARM' in targets: +if not 'ARM' in config.root.targets: config.unsupported = True diff --git a/test/Analysis/CostModel/PowerPC/ext.ll b/test/Analysis/CostModel/PowerPC/ext.ll new file mode 100644 index 0000000000000..7d6a14e93cdf3 --- /dev/null +++ b/test/Analysis/CostModel/PowerPC/ext.ll @@ -0,0 +1,21 @@ +; RUN: opt < %s -cost-model -analyze -mtriple=powerpc64-unknown-linux-gnu -mcpu=pwr7 -mattr=+vsx | FileCheck %s +target datalayout = "E-m:e-i64:64-n32:64" +target triple = "powerpc64-unknown-linux-gnu" + +define void @exts() { + + ; CHECK: cost of 1 {{.*}} sext + %v1 = sext i16 undef to i32 + + ; CHECK: cost of 1 {{.*}} sext + %v2 = sext <2 x i16> undef to <2 x i32> + + ; CHECK: cost of 1 {{.*}} sext + %v3 = sext <4 x i16> undef to <4 x i32> + + ; CHECK: cost of 112 {{.*}} sext + %v4 = sext <8 x i16> undef to <8 x i32> + + ret void +} + diff --git a/test/Analysis/CostModel/PowerPC/insert_extract.ll b/test/Analysis/CostModel/PowerPC/insert_extract.ll index f51963d56fde3..8dc003153a24a 100644 --- a/test/Analysis/CostModel/PowerPC/insert_extract.ll +++ b/test/Analysis/CostModel/PowerPC/insert_extract.ll @@ -3,13 +3,13 @@ target datalayout = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f3 target triple = "powerpc64-unknown-linux-gnu" define i32 @insert(i32 %arg) { - ; CHECK: cost of 13 {{.*}} insertelement + ; CHECK: cost of 10 {{.*}} insertelement %x = insertelement <4 x i32> undef, i32 %arg, i32 0 ret i32 undef } define i32 @extract(<4 x i32> %arg) { - ; CHECK: cost of 13 {{.*}} extractelement + ; CHECK: cost of 3 {{.*}} extractelement %x = extractelement <4 x i32> %arg, i32 0 ret i32 %x } diff --git a/test/Analysis/CostModel/PowerPC/lit.local.cfg b/test/Analysis/CostModel/PowerPC/lit.local.cfg index 2e463005586fc..5d33887ff0a48 100644 --- a/test/Analysis/CostModel/PowerPC/lit.local.cfg +++ b/test/Analysis/CostModel/PowerPC/lit.local.cfg @@ -1,4 +1,3 @@ -targets = set(config.root.targets_to_build.split()) -if not 'PowerPC' in targets: +if not 'PowerPC' in config.root.targets: config.unsupported = True diff --git a/test/Analysis/CostModel/PowerPC/load_store.ll b/test/Analysis/CostModel/PowerPC/load_store.ll index c77cce955abff..368f0a73489b7 100644 --- a/test/Analysis/CostModel/PowerPC/load_store.ll +++ b/test/Analysis/CostModel/PowerPC/load_store.ll @@ -29,6 +29,17 @@ define i32 @loads(i32 %arg) { ; CHECK: cost of 4 {{.*}} load load i128* undef, align 4 + ; FIXME: There actually are sub-vector Altivec loads, and so we could handle + ; this with a small expense, but we don't currently. + ; CHECK: cost of 48 {{.*}} load + load <4 x i16>* undef, align 2 + + ; CHECK: cost of 1 {{.*}} load + load <4 x i32>* undef, align 4 + + ; CHECK: cost of 46 {{.*}} load + load <3 x float>* undef, align 1 + ret i32 undef } diff --git a/test/Analysis/CostModel/X86/alternate-shuffle-cost.ll b/test/Analysis/CostModel/X86/alternate-shuffle-cost.ll new file mode 100644 index 0000000000000..2e162f0f0005f --- /dev/null +++ b/test/Analysis/CostModel/X86/alternate-shuffle-cost.ll @@ -0,0 +1,347 @@ +; RUN: opt < %s -mtriple=x86_64-unknown-linux-gnu -mattr=+sse2,-ssse3 -cost-model -analyze | FileCheck %s -check-prefix=CHECK -check-prefix=SSE2 +; RUN: opt < %s -mtriple=x86_64-unknown-linux-gnu -mattr=+sse2,+sse3,+ssse3 -cost-model -analyze | FileCheck %s -check-prefix=CHECK -check-prefix=SSSE3 +; RUN: opt < %s -mtriple=x86_64-unknown-linux-gnu -mcpu=corei7 -cost-model -analyze | FileCheck %s -check-prefix=CHECK -check-prefix=SSE41 +; RUN: opt < %s -mtriple=x86_64-unknown-linux-gnu -mcpu=corei7-avx -cost-model -analyze | FileCheck %s -check-prefix=CHECK -check-prefix=AVX +; RUN: opt < %s -mtriple=x86_64-unknown-linux-gnu -mcpu=core-avx2 -cost-model -analyze | FileCheck %s -check-prefix=CHECK -check-prefix=AVX2 + + +; Verify the cost model for alternate shuffles. + +; shufflevector instructions with illegal 64-bit vector types. +; 64-bit packed integer vectors (v2i32) are promoted to type v2i64. +; 64-bit packed float vectors (v2f32) are widened to type v4f32. + +define <2 x i32> @test_v2i32(<2 x i32> %a, <2 x i32> %b) { + %1 = shufflevector <2 x i32> %a, <2 x i32> %b, <2 x i32> <i32 0, i32 3> + ret <2 x i32> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v2i32': +; SSE2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + +define <2 x float> @test_v2f32(<2 x float> %a, <2 x float> %b) { + %1 = shufflevector <2 x float> %a, <2 x float> %b, <2 x i32> <i32 0, i32 3> + ret <2 x float> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v2f32': +; SSE2: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + +define <2 x i32> @test_v2i32_2(<2 x i32> %a, <2 x i32> %b) { + %1 = shufflevector <2 x i32> %a, <2 x i32> %b, <2 x i32> <i32 2, i32 1> + ret <2 x i32> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v2i32_2': +; SSE2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + +define <2 x float> @test_v2f32_2(<2 x float> %a, <2 x float> %b) { + %1 = shufflevector <2 x float> %a, <2 x float> %b, <2 x i32> <i32 2, i32 1> + ret <2 x float> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v2f32_2': +; SSE2: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + + +; Test shuffles on packed vectors of two elements. + +define <2 x i64> @test_v2i64(<2 x i64> %a, <2 x i64> %b) { + %1 = shufflevector <2 x i64> %a, <2 x i64> %b, <2 x i32> <i32 0, i32 3> + ret <2 x i64> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v2i64': +; SSE2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + +define <2 x double> @test_v2f64(<2 x double> %a, <2 x double> %b) { + %1 = shufflevector <2 x double> %a, <2 x double> %b, <2 x i32> <i32 0, i32 3> + ret <2 x double> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v2f64': +; SSE2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + + +define <2 x i64> @test_v2i64_2(<2 x i64> %a, <2 x i64> %b) { + %1 = shufflevector <2 x i64> %a, <2 x i64> %b, <2 x i32> <i32 2, i32 1> + ret <2 x i64> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v2i64_2': +; SSE2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + + +define <2 x double> @test_v2f64_2(<2 x double> %a, <2 x double> %b) { + %1 = shufflevector <2 x double> %a, <2 x double> %b, <2 x i32> <i32 2, i32 1> + ret <2 x double> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v2f64_2': +; SSE2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + +; Test shuffles on packed vectors of four elements. + +define <4 x i32> @test_v4i32(<4 x i32> %a, <4 x i32> %b) { + %1 = shufflevector <4 x i32> %a, <4 x i32> %b, <4 x i32> <i32 0, i32 5, i32 2, i32 7> + ret <4 x i32> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v4i32': +; SSE2: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + + +define <4 x i32> @test_v4i32_2(<4 x i32> %a, <4 x i32> %b) { + %1 = shufflevector <4 x i32> %a, <4 x i32> %b, <4 x i32> <i32 4, i32 1, i32 6, i32 3> + ret <4 x i32> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v4i32_2': +; SSE2: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + + +define <4 x float> @test_v4f32(<4 x float> %a, <4 x float> %b) { + %1 = shufflevector <4 x float> %a, <4 x float> %b, <4 x i32> <i32 0, i32 5, i32 2, i32 7> + ret <4 x float> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v4f32': +; SSE2: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + + +define <4 x float> @test_v4f32_2(<4 x float> %a, <4 x float> %b) { + %1 = shufflevector <4 x float> %a, <4 x float> %b, <4 x i32> <i32 4, i32 1, i32 6, i32 3> + ret <4 x float> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v4f32_2': +; SSE2: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + +define <4 x i64> @test_v4i64(<4 x i64> %a, <4 x i64> %b) { + %1 = shufflevector <4 x i64> %a, <4 x i64> %b, <4 x i32> <i32 0, i32 5, i32 2, i32 7> + ret <4 x i64> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v4i64': +; SSE2: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + + +define <4 x i64> @test_v4i64_2(<4 x i64> %a, <4 x i64> %b) { + %1 = shufflevector <4 x i64> %a, <4 x i64> %b, <4 x i32> <i32 4, i32 1, i32 6, i32 3> + ret <4 x i64> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v4i64_2': +; SSE2: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + + +define <4 x double> @test_v4f64(<4 x double> %a, <4 x double> %b) { + %1 = shufflevector <4 x double> %a, <4 x double> %b, <4 x i32> <i32 0, i32 5, i32 2, i32 7> + ret <4 x double> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v4f64': +; SSE2: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + + +define <4 x double> @test_v4f64_2(<4 x double> %a, <4 x double> %b) { + %1 = shufflevector <4 x double> %a, <4 x double> %b, <4 x i32> <i32 4, i32 1, i32 6, i32 3> + ret <4 x double> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v4f64_2': +; SSE2: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + + +; Test shuffles on packed vectors of eight elements. +define <8 x i16> @test_v8i16(<8 x i16> %a, <8 x i16> %b) { + %1 = shufflevector <8 x i16> %a, <8 x i16> %b, <8 x i32> <i32 0, i32 9, i32 2, i32 11, i32 4, i32 13, i32 6, i32 15> + ret <8 x i16> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v8i16': +; SSE2: Cost Model: {{.*}} 8 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 3 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + + +define <8 x i16> @test_v8i16_2(<8 x i16> %a, <8 x i16> %b) { + %1 = shufflevector <8 x i16> %a, <8 x i16> %b, <8 x i32> <i32 8, i32 1, i32 10, i32 3, i32 12, i32 5, i32 14, i32 7> + ret <8 x i16> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v8i16_2': +; SSE2: Cost Model: {{.*}} 8 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 3 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + + +define <8 x i32> @test_v8i32(<8 x i32> %a, <8 x i32> %b) { + %1 = shufflevector <8 x i32> %a, <8 x i32> %b, <8 x i32> <i32 0, i32 9, i32 2, i32 11, i32 4, i32 13, i32 6, i32 15> + ret <8 x i32> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v8i32': +; SSE2: Cost Model: {{.*}} 4 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 4 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + + +define <8 x i32> @test_v8i32_2(<8 x i32> %a, <8 x i32> %b) { + %1 = shufflevector <8 x i32> %a, <8 x i32> %b, <8 x i32> <i32 8, i32 1, i32 10, i32 3, i32 12, i32 5, i32 14, i32 7> + ret <8 x i32> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v8i32_2': +; SSE2: Cost Model: {{.*}} 4 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 4 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + + +define <8 x float> @test_v8f32(<8 x float> %a, <8 x float> %b) { + %1 = shufflevector <8 x float> %a, <8 x float> %b, <8 x i32> <i32 0, i32 9, i32 2, i32 11, i32 4, i32 13, i32 6, i32 15> + ret <8 x float> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v8f32': +; SSE2: Cost Model: {{.*}} 4 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 4 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + + +define <8 x float> @test_v8f32_2(<8 x float> %a, <8 x float> %b) { + %1 = shufflevector <8 x float> %a, <8 x float> %b, <8 x i32> <i32 8, i32 1, i32 10, i32 3, i32 12, i32 5, i32 14, i32 7> + ret <8 x float> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v8f32_2': +; SSE2: Cost Model: {{.*}} 4 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 4 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + + +; Test shuffles on packed vectors of sixteen elements. +define <16 x i8> @test_v16i8(<16 x i8> %a, <16 x i8> %b) { + %1 = shufflevector <16 x i8> %a, <16 x i8> %b, <16 x i32> <i32 0, i32 17, i32 2, i32 19, i32 4, i32 21, i32 6, i32 23, i32 8, i32 25, i32 10, i32 27, i32 12, i32 29, i32 14, i32 31> + ret <16 x i8> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v16i8': +; SSE2: Cost Model: {{.*}} 48 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 3 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 3 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 3 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 3 for instruction: %1 = shufflevector + + +define <16 x i8> @test_v16i8_2(<16 x i8> %a, <16 x i8> %b) { + %1 = shufflevector <16 x i8> %a, <16 x i8> %b, <16 x i32> <i32 16, i32 1, i32 18, i32 3, i32 20, i32 5, i32 22, i32 7, i32 24, i32 9, i32 26, i32 11, i32 28, i32 13, i32 30, i32 15> + ret <16 x i8> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v16i8_2': +; SSE2: Cost Model: {{.*}} 48 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 3 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 3 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 3 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 3 for instruction: %1 = shufflevector + + +define <16 x i16> @test_v16i16(<16 x i16> %a, <16 x i16> %b) { + %1 = shufflevector <16 x i16> %a, <16 x i16> %b, <16 x i32> <i32 0, i32 17, i32 2, i32 19, i32 4, i32 21, i32 6, i32 23, i32 8, i32 25, i32 10, i32 27, i32 12, i32 29, i32 14, i32 31> + ret <16 x i16> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v16i16': +; SSE2: Cost Model: {{.*}} 16 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 6 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 5 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + + +define <16 x i16> @test_v16i16_2(<16 x i16> %a, <16 x i16> %b) { + %1 = shufflevector <16 x i16> %a, <16 x i16> %b, <16 x i32> <i32 16, i32 1, i32 18, i32 3, i32 20, i32 5, i32 22, i32 7, i32 24, i32 9, i32 26, i32 11, i32 28, i32 13, i32 30, i32 15> + ret <16 x i16> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v16i16_2': +; SSE2: Cost Model: {{.*}} 16 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 6 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 2 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 5 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 1 for instruction: %1 = shufflevector + +define <32 x i8> @test_v32i8(<32 x i8> %a, <32 x i8> %b) { + %1 = shufflevector <32 x i8> %a, <32 x i8> %b, <32 x i32> <i32 0, i32 33, i32 2, i32 35, i32 4, i32 37, i32 6, i32 39, i32 8, i32 41, i32 10, i32 43, i32 12, i32 45, i32 14, i32 47, i32 16, i32 49, i32 18, i32 51, i32 20, i32 53, i32 22, i32 55, i32 24, i32 57, i32 26, i32 59, i32 28, i32 61, i32 30, i32 63> + ret <32 x i8> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v32i8': +; SSE2: Cost Model: {{.*}} 96 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 6 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 6 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 9 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 9 for instruction: %1 = shufflevector + + +define <32 x i8> @test_v32i8_2(<32 x i8> %a, <32 x i8> %b) { + %1 = shufflevector <32 x i8> %a, <32 x i8> %b, <32 x i32> <i32 32, i32 1, i32 34, i32 3, i32 36, i32 5, i32 38, i32 7, i32 40, i32 9, i32 42, i32 11, i32 44, i32 13, i32 46, i32 15, i32 48, i32 17, i32 50, i32 19, i32 52, i32 21, i32 54, i32 23, i32 56, i32 25, i32 58, i32 27, i32 60, i32 29, i32 62, i32 31> + ret <32 x i8> %1 +} +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_v32i8_2': +; SSE2: Cost Model: {{.*}} 96 for instruction: %1 = shufflevector +; SSSE3: Cost Model: {{.*}} 6 for instruction: %1 = shufflevector +; SSE41: Cost Model: {{.*}} 6 for instruction: %1 = shufflevector +; AVX: Cost Model: {{.*}} 9 for instruction: %1 = shufflevector +; AVX2: Cost Model: {{.*}} 9 for instruction: %1 = shufflevector + diff --git a/test/Analysis/CostModel/X86/cast.ll b/test/Analysis/CostModel/X86/cast.ll index f3c1283c7e329..7f97b176f7c17 100644 --- a/test/Analysis/CostModel/X86/cast.ll +++ b/test/Analysis/CostModel/X86/cast.ll @@ -1,10 +1,11 @@ -; RUN: opt < %s -cost-model -analyze -mtriple=x86_64-apple-macosx10.8.0 -mcpu=corei7-avx | FileCheck %s +; RUN: opt < %s -cost-model -analyze -mtriple=x86_64-apple-macosx10.8.0 -mcpu=core-avx2 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-AVX2 +; RUN: opt < %s -cost-model -analyze -mtriple=x86_64-apple-macosx10.8.0 -mcpu=corei7-avx | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-AVX target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.8.0" define i32 @add(i32 %arg) { - +; CHECK-LABEL: for function 'add' ; -- Same size registeres -- ;CHECK: cost of 1 {{.*}} zext %A = zext <4 x i1> undef to <4 x i32> @@ -33,57 +34,106 @@ define i32 @add(i32 %arg) { } define i32 @zext_sext(<8 x i1> %in) { - ;CHECK: cost of 6 {{.*}} zext +; CHECK-AVX2-LABEL: for function 'zext_sext' +; CHECK-AVX-LABEL: for function 'zext_sext' + ;CHECK-AVX2: cost of 3 {{.*}} zext + ;CHECK-AVX: cost of 4 {{.*}} zext %Z = zext <8 x i1> %in to <8 x i32> - ;CHECK: cost of 9 {{.*}} sext + ;CHECK-AVX2: cost of 3 {{.*}} sext + ;CHECK-AVX: cost of 7 {{.*}} sext %S = sext <8 x i1> %in to <8 x i32> - ;CHECK: cost of 1 {{.*}} zext + ;CHECK-AVX2: cost of 1 {{.*}} zext + ;CHECK-AVX: cost of 4 {{.*}} zext %A1 = zext <16 x i8> undef to <16 x i16> - ;CHECK: cost of 1 {{.*}} sext + ;CHECK-AVX2: cost of 1 {{.*}} sext + ;CHECK-AVX: cost of 4 {{.*}} sext %A2 = sext <16 x i8> undef to <16 x i16> - ;CHECK: cost of 1 {{.*}} sext + ;CHECK-AVX2: cost of 1 {{.*}} sext + ;CHECK-AVX: cost of 4 {{.*}} sext %A = sext <8 x i16> undef to <8 x i32> - ;CHECK: cost of 1 {{.*}} zext + ;CHECK-AVX2: cost of 1 {{.*}} zext + ;CHECK-AVX: cost of 4 {{.*}} zext %B = zext <8 x i16> undef to <8 x i32> - ;CHECK: cost of 1 {{.*}} sext + ;CHECK-AVX2: cost of 1 {{.*}} sext + ;CHECK-AVX: cost of 4 {{.*}} sext %C = sext <4 x i32> undef to <4 x i64> - ;CHECK: cost of 6 {{.*}} sext - %C1 = sext <4 x i8> undef to <4 x i64> - ;CHECK: cost of 6 {{.*}} sext - %C2 = sext <4 x i16> undef to <4 x i64> - ;CHECK: cost of 1 {{.*}} zext + ;CHECK-AVX2: cost of 3 {{.*}} zext + ;CHECK-AVX: cost of 4 {{.*}} zext + %C.v8i8.z = zext <8 x i8> undef to <8 x i32> + ;CHECK-AVX2: cost of 3 {{.*}} sext + ;CHECK-AVX: cost of 7 {{.*}} sext + %C.v8i8.s = sext <8 x i8> undef to <8 x i32> + ;CHECK-AVX2: cost of 3 {{.*}} zext + ;CHECK-AVX: cost of 3 {{.*}} zext + %C.v4i16.z = zext <4 x i16> undef to <4 x i64> + ;CHECK-AVX2: cost of 3 {{.*}} sext + ;CHECK-AVX: cost of 6 {{.*}} sext + %C.v4i16.s = sext <4 x i16> undef to <4 x i64> + + ;CHECK-AVX2: cost of 3 {{.*}} zext + ;CHECK-AVX: cost of 4 {{.*}} zext + %C.v4i8.z = zext <4 x i8> undef to <4 x i64> + ;CHECK-AVX2: cost of 3 {{.*}} sext + ;CHECK-AVX: cost of 6 {{.*}} sext + %C.v4i8.s = sext <4 x i8> undef to <4 x i64> + + ;CHECK-AVX2: cost of 1 {{.*}} zext + ;CHECK-AVX: cost of 4 {{.*}} zext %D = zext <4 x i32> undef to <4 x i64> - ;CHECK: cost of 1 {{.*}} trunc + ;CHECK-AVX2: cost of 2 {{.*}} trunc + ;CHECK-AVX: cost of 4 {{.*}} trunc %E = trunc <4 x i64> undef to <4 x i32> - ;CHECK: cost of 1 {{.*}} trunc + ;CHECK-AVX2: cost of 2 {{.*}} trunc + ;CHECK-AVX: cost of 5 {{.*}} trunc %F = trunc <8 x i32> undef to <8 x i16> - ;CHECK: cost of 2 {{.*}} trunc + ;CHECK-AVX2: cost of 4 {{.*}} trunc + ;CHECK-AVX: cost of 4 {{.*}} trunc %F1 = trunc <16 x i16> undef to <16 x i8> + ;CHECK-AVX2: cost of 2 {{.*}} trunc + ;CHECK-AVX: cost of 4 {{.*}} trunc + %F2 = trunc <8 x i32> undef to <8 x i8> + ;CHECK-AVX2: cost of 2 {{.*}} trunc + ;CHECK-AVX: cost of 4 {{.*}} trunc + %F3 = trunc <4 x i64> undef to <4 x i8> - ;CHECK: cost of 3 {{.*}} trunc + ;CHECK-AVX2: cost of 4 {{.*}} trunc + ;CHECK-AVX: cost of 9 {{.*}} trunc %G = trunc <8 x i64> undef to <8 x i32> ret i32 undef } define i32 @masks8(<8 x i1> %in) { - ;CHECK: cost of 6 {{.*}} zext +; CHECK-AVX2-LABEL: for function 'masks8' +; CHECK-AVX-LABEL: for function 'masks8' + + ;CHECK-AVX2: cost of 3 {{.*}} zext + ;CHECK-AVX: cost of 4 {{.*}} zext %Z = zext <8 x i1> %in to <8 x i32> - ;CHECK: cost of 9 {{.*}} sext + ;CHECK-AVX2: cost of 3 {{.*}} sext + ;CHECK-AVX: cost of 7 {{.*}} sext %S = sext <8 x i1> %in to <8 x i32> ret i32 undef } define i32 @masks4(<4 x i1> %in) { - ;CHECK: cost of 8 {{.*}} sext +; CHECK-AVX2-LABEL: for function 'masks4' +; CHECK-AVX-LABEL: for function 'masks4' + + ;CHECK-AVX2: cost of 3 {{.*}} zext + ;CHECK-AVX: cost of 4 {{.*}} zext + %Z = zext <4 x i1> %in to <4 x i64> + ;CHECK-AVX2: cost of 3 {{.*}} sext + ;CHECK-AVX: cost of 6 {{.*}} sext %S = sext <4 x i1> %in to <4 x i64> ret i32 undef } define void @sitofp4(<4 x i1> %a, <4 x i8> %b, <4 x i16> %c, <4 x i32> %d) { +; CHECK-LABEL: for function 'sitofp4' ; CHECK: cost of 3 {{.*}} sitofp %A1 = sitofp <4 x i1> %a to <4 x float> ; CHECK: cost of 3 {{.*}} sitofp @@ -107,6 +157,7 @@ define void @sitofp4(<4 x i1> %a, <4 x i8> %b, <4 x i16> %c, <4 x i32> %d) { } define void @sitofp8(<8 x i1> %a, <8 x i8> %b, <8 x i16> %c, <8 x i32> %d) { +; CHECK-LABEL: for function 'sitofp8' ; CHECK: cost of 8 {{.*}} sitofp %A1 = sitofp <8 x i1> %a to <8 x float> @@ -122,6 +173,7 @@ define void @sitofp8(<8 x i1> %a, <8 x i8> %b, <8 x i16> %c, <8 x i32> %d) { } define void @uitofp4(<4 x i1> %a, <4 x i8> %b, <4 x i16> %c, <4 x i32> %d) { +; CHECK-LABEL: for function 'uitofp4' ; CHECK: cost of 7 {{.*}} uitofp %A1 = uitofp <4 x i1> %a to <4 x float> ; CHECK: cost of 7 {{.*}} uitofp @@ -145,6 +197,7 @@ define void @uitofp4(<4 x i1> %a, <4 x i8> %b, <4 x i16> %c, <4 x i32> %d) { } define void @uitofp8(<8 x i1> %a, <8 x i8> %b, <8 x i16> %c, <8 x i32> %d) { +; CHECK-LABEL: for function 'uitofp8' ; CHECK: cost of 6 {{.*}} uitofp %A1 = uitofp <8 x i1> %a to <8 x float> diff --git a/test/Analysis/CostModel/X86/cmp.ll b/test/Analysis/CostModel/X86/cmp.ll index 713b3742e9209..9f2bdb3c21b75 100644 --- a/test/Analysis/CostModel/X86/cmp.ll +++ b/test/Analysis/CostModel/X86/cmp.ll @@ -1,5 +1,5 @@ -; RUN: opt < %s -cost-model -analyze -mtriple=x86_64-apple-macosx10.8.0 -mcpu=corei7-avx | FileCheck --check-prefix=AVX1 %s -; RUN: opt < %s -cost-model -analyze -mtriple=x86_64-apple-macosx10.8.0 -mcpu=core-avx2 | FileCheck --check-prefix=AVX2 %s +; RUN: opt < %s -cost-model -analyze -mtriple=x86_64-apple-macosx10.8.0 -mcpu=corei7-avx | FileCheck -check-prefix=CHECK -check-prefix=AVX1 %s +; RUN: opt < %s -cost-model -analyze -mtriple=x86_64-apple-macosx10.8.0 -mcpu=core-avx2 | FileCheck -check-prefix=CHECK -check-prefix=AVX2 %s target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.8.0" diff --git a/test/Analysis/CostModel/X86/intrinsic-cost.ll b/test/Analysis/CostModel/X86/intrinsic-cost.ll index 8eeee8124d9ac..3b27b52f76549 100644 --- a/test/Analysis/CostModel/X86/intrinsic-cost.ll +++ b/test/Analysis/CostModel/X86/intrinsic-cost.ll @@ -58,3 +58,31 @@ for.end: ; preds = %vector.body } declare <4 x float> @llvm.nearbyint.v4f32(<4 x float>) nounwind readnone + +define void @test3(float* nocapture %f, <4 x float> %b, <4 x float> %c) nounwind { +vector.ph: + br label %vector.body + +vector.body: ; preds = %vector.body, %vector.ph + %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ] + %0 = getelementptr inbounds float* %f, i64 %index + %1 = bitcast float* %0 to <4 x float>* + %wide.load = load <4 x float>* %1, align 4 + %2 = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> %wide.load, <4 x float> %b, <4 x float> %c) + store <4 x float> %2, <4 x float>* %1, align 4 + %index.next = add i64 %index, 4 + %3 = icmp eq i64 %index.next, 1024 + br i1 %3, label %for.end, label %vector.body + +for.end: ; preds = %vector.body + ret void + +; CORE2: Printing analysis 'Cost Model Analysis' for function 'test3': +; CORE2: Cost Model: Found an estimated cost of 4 for instruction: %2 = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> %wide.load, <4 x float> %b, <4 x float> %c) + +; COREI7: Printing analysis 'Cost Model Analysis' for function 'test3': +; COREI7: Cost Model: Found an estimated cost of 4 for instruction: %2 = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> %wide.load, <4 x float> %b, <4 x float> %c) + +} + +declare <4 x float> @llvm.fmuladd.v4f32(<4 x float>, <4 x float>, <4 x float>) nounwind readnone diff --git a/test/Analysis/CostModel/X86/lit.local.cfg b/test/Analysis/CostModel/X86/lit.local.cfg index ba763cf03ffcc..e71f3cc4c41e7 100644 --- a/test/Analysis/CostModel/X86/lit.local.cfg +++ b/test/Analysis/CostModel/X86/lit.local.cfg @@ -1,4 +1,3 @@ -targets = set(config.root.targets_to_build.split()) -if not 'X86' in targets: +if not 'X86' in config.root.targets: config.unsupported = True diff --git a/test/Analysis/CostModel/X86/scalarize.ll b/test/Analysis/CostModel/X86/scalarize.ll new file mode 100644 index 0000000000000..fc25fcbc563f6 --- /dev/null +++ b/test/Analysis/CostModel/X86/scalarize.ll @@ -0,0 +1,41 @@ +; RUN: opt < %s -cost-model -analyze -mtriple=i386 -mcpu=corei7-avx | FileCheck %s -check-prefix=CHECK32 +; RUN: opt < %s -cost-model -analyze -mtriple=x86_64-apple-macosx10.8.0 -mcpu=corei7-avx | FileCheck %s -check-prefix=CHECK64 + +; Test vector scalarization costs. +; RUN: llc < %s -march=x86 -mcpu=i386 +; RUN: llc < %s -march=x86 -mcpu=yonah + +%i4 = type <4 x i32> +%i8 = type <2 x i64> + +;;; TEST HANDLING OF VARIOUS VECTOR SIZES + +declare %i4 @llvm.bswap.v4i32(%i4) +declare %i8 @llvm.bswap.v2i64(%i8) + +declare %i4 @llvm.ctpop.v4i32(%i4) +declare %i8 @llvm.ctpop.v2i64(%i8) + +; CHECK32-LABEL: test_scalarized_intrinsics +; CHECK64-LABEL: test_scalarized_intrinsics +define void @test_scalarized_intrinsics() { + %r1 = add %i8 undef, undef + +; CHECK32: cost of 12 {{.*}}bswap.v4i32 +; CHECK64: cost of 12 {{.*}}bswap.v4i32 + %r2 = call %i4 @llvm.bswap.v4i32(%i4 undef) +; CHECK32: cost of 10 {{.*}}bswap.v2i64 +; CHECK64: cost of 6 {{.*}}bswap.v2i64 + %r3 = call %i8 @llvm.bswap.v2i64(%i8 undef) + +; CHECK32: cost of 12 {{.*}}ctpop.v4i32 +; CHECK64: cost of 12 {{.*}}ctpop.v4i32 + %r4 = call %i4 @llvm.ctpop.v4i32(%i4 undef) +; CHECK32: cost of 10 {{.*}}ctpop.v2i64 +; CHECK64: cost of 6 {{.*}}ctpop.v2i64 + %r5 = call %i8 @llvm.ctpop.v2i64(%i8 undef) + +; CHECK32: ret +; CHECK64: ret + ret void +} diff --git a/test/Analysis/CostModel/X86/vdiv-cost.ll b/test/Analysis/CostModel/X86/vdiv-cost.ll new file mode 100644 index 0000000000000..c8e4557cbefdc --- /dev/null +++ b/test/Analysis/CostModel/X86/vdiv-cost.ll @@ -0,0 +1,92 @@ +; RUN: opt < %s -mtriple=x86_64-unknown-linux-gnu -mcpu=corei7 -mattr=+sse2,-sse4.1 -cost-model -analyze | FileCheck %s -check-prefix=CHECK -check-prefix=SSE2 +; RUN: opt < %s -mtriple=x86_64-unknown-linux-gnu -mcpu=core-avx2 -cost-model -analyze | FileCheck %s -check-prefix=CHECK -check-prefix=AVX2 + +define <4 x i32> @test1(<4 x i32> %a) { + %div = udiv <4 x i32> %a, <i32 7, i32 7, i32 7, i32 7> + ret <4 x i32> %div + +; CHECK: 'Cost Model Analysis' for function 'test1': +; SSE2: Found an estimated cost of 15 for instruction: %div +; AVX2: Found an estimated cost of 15 for instruction: %div +} + +define <8 x i32> @test2(<8 x i32> %a) { + %div = udiv <8 x i32> %a, <i32 7, i32 7, i32 7, i32 7,i32 7, i32 7, i32 7, i32 7> + ret <8 x i32> %div + +; CHECK: 'Cost Model Analysis' for function 'test2': +; SSE2: Found an estimated cost of 30 for instruction: %div +; AVX2: Found an estimated cost of 15 for instruction: %div +} + +define <8 x i16> @test3(<8 x i16> %a) { + %div = udiv <8 x i16> %a, <i16 7, i16 7, i16 7, i16 7, i16 7, i16 7, i16 7, i16 7> + ret <8 x i16> %div + +; CHECK: 'Cost Model Analysis' for function 'test3': +; SSE2: Found an estimated cost of 6 for instruction: %div +; AVX2: Found an estimated cost of 6 for instruction: %div +} + +define <16 x i16> @test4(<16 x i16> %a) { + %div = udiv <16 x i16> %a, <i16 7, i16 7, i16 7, i16 7,i16 7, i16 7, i16 7, i16 7, i16 7, i16 7, i16 7, i16 7,i16 7, i16 7, i16 7, i16 7> + ret <16 x i16> %div + +; CHECK: 'Cost Model Analysis' for function 'test4': +; SSE2: Found an estimated cost of 12 for instruction: %div +; AVX2: Found an estimated cost of 6 for instruction: %div +} + +define <8 x i16> @test5(<8 x i16> %a) { + %div = sdiv <8 x i16> %a, <i16 7, i16 7, i16 7, i16 7, i16 7, i16 7, i16 7, i16 7> + ret <8 x i16> %div + +; CHECK: 'Cost Model Analysis' for function 'test5': +; SSE2: Found an estimated cost of 6 for instruction: %div +; AVX2: Found an estimated cost of 6 for instruction: %div +} + +define <16 x i16> @test6(<16 x i16> %a) { + %div = sdiv <16 x i16> %a, <i16 7, i16 7, i16 7, i16 7,i16 7, i16 7, i16 7, i16 7, i16 7, i16 7, i16 7, i16 7,i16 7, i16 7, i16 7, i16 7> + ret <16 x i16> %div + +; CHECK: 'Cost Model Analysis' for function 'test6': +; SSE2: Found an estimated cost of 12 for instruction: %div +; AVX2: Found an estimated cost of 6 for instruction: %div +} + +define <16 x i8> @test7(<16 x i8> %a) { + %div = sdiv <16 x i8> %a, <i8 7, i8 7, i8 7, i8 7,i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7,i8 7, i8 7, i8 7, i8 7> + ret <16 x i8> %div + +; CHECK: 'Cost Model Analysis' for function 'test7': +; SSE2: Found an estimated cost of 320 for instruction: %div +; AVX2: Found an estimated cost of 320 for instruction: %div +} + +define <4 x i32> @test8(<4 x i32> %a) { + %div = sdiv <4 x i32> %a, <i32 7, i32 7, i32 7, i32 7> + ret <4 x i32> %div + +; CHECK: 'Cost Model Analysis' for function 'test8': +; SSE2: Found an estimated cost of 19 for instruction: %div +; AVX2: Found an estimated cost of 15 for instruction: %div +} + +define <8 x i32> @test9(<8 x i32> %a) { + %div = sdiv <8 x i32> %a, <i32 7, i32 7, i32 7, i32 7,i32 7, i32 7, i32 7, i32 7> + ret <8 x i32> %div + +; CHECK: 'Cost Model Analysis' for function 'test9': +; SSE2: Found an estimated cost of 38 for instruction: %div +; AVX2: Found an estimated cost of 15 for instruction: %div +} + +define <8 x i32> @test10(<8 x i32> %a) { + %div = sdiv <8 x i32> %a, <i32 8, i32 7, i32 7, i32 7,i32 7, i32 7, i32 7, i32 7> + ret <8 x i32> %div + +; CHECK: 'Cost Model Analysis' for function 'test10': +; SSE2: Found an estimated cost of 160 for instruction: %div +; AVX2: Found an estimated cost of 160 for instruction: %div +} diff --git a/test/Analysis/CostModel/X86/vselect-cost.ll b/test/Analysis/CostModel/X86/vselect-cost.ll new file mode 100644 index 0000000000000..2416777506df8 --- /dev/null +++ b/test/Analysis/CostModel/X86/vselect-cost.ll @@ -0,0 +1,126 @@ +; RUN: opt < %s -mtriple=x86_64-unknown-linux-gnu -mcpu=corei7 -mattr=+sse2,-sse4.1 -cost-model -analyze | FileCheck %s -check-prefix=CHECK -check-prefix=SSE2 +; RUN: opt < %s -mtriple=x86_64-unknown-linux-gnu -mcpu=corei7 -cost-model -analyze | FileCheck %s -check-prefix=CHECK -check-prefix=SSE41 +; RUN: opt < %s -mtriple=x86_64-unknown-linux-gnu -mcpu=corei7-avx -cost-model -analyze | FileCheck %s -check-prefix=CHECK -check-prefix=AVX +; RUN: opt < %s -mtriple=x86_64-unknown-linux-gnu -mcpu=core-avx2 -cost-model -analyze | FileCheck %s -check-prefix=CHECK -check-prefix=AVX2 + + +; Verify the cost of vector select instructions. + +; SSE41 added blend instructions with an immediate for <2 x double> and +; <4 x float>. Integers of the same size should also use those instructions. + +define <2 x i64> @test_2i64(<2 x i64> %a, <2 x i64> %b) { +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_2i64': +; SSE2: Cost Model: {{.*}} 4 for instruction: %sel = select <2 x i1> +; SSE41: Cost Model: {{.*}} 1 for instruction: %sel = select <2 x i1> +; AVX: Cost Model: {{.*}} 1 for instruction: %sel = select <2 x i1> +; AVX2: Cost Model: {{.*}} 1 for instruction: %sel = select <2 x i1> + %sel = select <2 x i1> <i1 true, i1 false>, <2 x i64> %a, <2 x i64> %b + ret <2 x i64> %sel +} + +define <2 x double> @test_2double(<2 x double> %a, <2 x double> %b) { +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_2double': +; SSE2: Cost Model: {{.*}} 3 for instruction: %sel = select <2 x i1> +; SSE41: Cost Model: {{.*}} 1 for instruction: %sel = select <2 x i1> +; AVX: Cost Model: {{.*}} 1 for instruction: %sel = select <2 x i1> +; AVX2: Cost Model: {{.*}} 1 for instruction: %sel = select <2 x i1> + %sel = select <2 x i1> <i1 true, i1 false>, <2 x double> %a, <2 x double> %b + ret <2 x double> %sel +} + +define <4 x i32> @test_4i32(<4 x i32> %a, <4 x i32> %b) { +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_4i32': +; SSE2: Cost Model: {{.*}} 8 for instruction: %sel = select <4 x i1> +; SSE41: Cost Model: {{.*}} 1 for instruction: %sel = select <4 x i1> +; AVX: Cost Model: {{.*}} 1 for instruction: %sel = select <4 x i1> +; AVX2: Cost Model: {{.*}} 1 for instruction: %sel = select <4 x i1> + %sel = select <4 x i1> <i1 true, i1 false, i1 true, i1 false>, <4 x i32> %a, <4 x i32> %b + ret <4 x i32> %sel +} + +define <4 x float> @test_4float(<4 x float> %a, <4 x float> %b) { +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_4float': +; SSE2: Cost Model: {{.*}} 7 for instruction: %sel = select <4 x i1> +; SSE41: Cost Model: {{.*}} 1 for instruction: %sel = select <4 x i1> +; AVX: Cost Model: {{.*}} 1 for instruction: %sel = select <4 x i1> +; AVX2: Cost Model: {{.*}} 1 for instruction: %sel = select <4 x i1> + %sel = select <4 x i1> <i1 true, i1 false, i1 true, i1 true>, <4 x float> %a, <4 x float> %b + ret <4 x float> %sel +} + +define <16 x i8> @test_16i8(<16 x i8> %a, <16 x i8> %b) { +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_16i8': +; SSE2: Cost Model: {{.*}} 32 for instruction: %sel = select <16 x i1> +; SSE41: Cost Model: {{.*}} 1 for instruction: %sel = select <16 x i1> +; AVX: Cost Model: {{.*}} 1 for instruction: %sel = select <16 x i1> +; AVX2: Cost Model: {{.*}} 1 for instruction: %sel = select <16 x i1> + %sel = select <16 x i1> <i1 true, i1 false, i1 true, i1 true, i1 true, i1 false, i1 true, i1 true, i1 true, i1 false, i1 true, i1 true, i1 true, i1 false, i1 true, i1 true>, <16 x i8> %a, <16 x i8> %b + ret <16 x i8> %sel +} + +; AVX added blend instructions with an immediate for <4 x double> and +; <8 x float>. Integers of the same size should also use those instructions. +define <4 x i64> @test_4i64(<4 x i64> %a, <4 x i64> %b) { +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_4i64': +; SSE2: Cost Model: {{.*}} 8 for instruction: %sel = select <4 x i1> +; SSE41: Cost Model: {{.*}} 2 for instruction: %sel = select <4 x i1> +; AVX: Cost Model: {{.*}} 1 for instruction: %sel = select <4 x i1> +; AVX2: Cost Model: {{.*}} 1 for instruction: %sel = select <4 x i1> + %sel = select <4 x i1> <i1 true, i1 false, i1 false, i1 true>, <4 x i64> %a, <4 x i64> %b + ret <4 x i64> %sel +} + +define <4 x double> @test_4double(<4 x double> %a, <4 x double> %b) { +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_4double': +; SSE2: Cost Model: {{.*}} 6 for instruction: %sel = select <4 x i1> +; SSE41: Cost Model: {{.*}} 2 for instruction: %sel = select <4 x i1> +; AVX: Cost Model: {{.*}} 1 for instruction: %sel = select <4 x i1> +; AVX2: Cost Model: {{.*}} 1 for instruction: %sel = select <4 x i1> + %sel = select <4 x i1> <i1 true, i1 false, i1 true, i1 false>, <4 x double> %a, <4 x double> %b + ret <4 x double> %sel +} + +define <8 x i32> @test_8i32(<8 x i32> %a, <8 x i32> %b) { +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_8i32': +; SSE2: Cost Model: {{.*}} 16 for instruction: %sel = select <8 x i1> +; SSE41: Cost Model: {{.*}} 2 for instruction: %sel = select <8 x i1> +; AVX: Cost Model: {{.*}} 1 for instruction: %sel = select <8 x i1> +; AVX2: Cost Model: {{.*}} 1 for instruction: %sel = select <8 x i1> + %sel = select <8 x i1> <i1 true, i1 false, i1 true, i1 true, i1 true, i1 false, i1 true, i1 false>, <8 x i32> %a, <8 x i32> %b + ret <8 x i32> %sel +} + +define <8 x float> @test_8float(<8 x float> %a, <8 x float> %b) { +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_8float': +; SSE2: Cost Model: {{.*}} 14 for instruction: %sel = select <8 x i1> +; SSE41: Cost Model: {{.*}} 2 for instruction: %sel = select <8 x i1> +; AVX: Cost Model: {{.*}} 1 for instruction: %sel = select <8 x i1> +; AVX2: Cost Model: {{.*}} 1 for instruction: %sel = select <8 x i1> + %sel = select <8 x i1> <i1 true, i1 false, i1 false, i1 false, i1 true, i1 false, i1 false, i1 false>, <8 x float> %a, <8 x float> %b + ret <8 x float> %sel +} + +; AVX2 +define <16 x i16> @test_16i16(<16 x i16> %a, <16 x i16> %b) { +; CHECK:Printing analysis 'Cost Model Analysis' for function 'test_16i16': +; SSE2: Cost Model: {{.*}} 32 for instruction: %sel = select <16 x i1> +; SSE41: Cost Model: {{.*}} 2 for instruction: %sel = select <16 x i1> +;;; FIXME: This AVX cost is obviously wrong. We shouldn't be scalarizing. +; AVX: Cost Model: {{.*}} 32 for instruction: %sel = select <16 x i1> +; AVX2: Cost Model: {{.*}} 1 for instruction: %sel = select <16 x i1> + %sel = select <16 x i1> <i1 true, i1 false, i1 false, i1 false, i1 true, i1 false, i1 false, i1 false, i1 true, i1 false, i1 false, i1 false, i1 true, i1 false, i1 false, i1 false>, <16 x i16> %a, <16 x i16> %b + ret <16 x i16> %sel +} + +define <32 x i8> @test_32i8(<32 x i8> %a, <32 x i8> %b) { +; CHECK: Printing analysis 'Cost Model Analysis' for function 'test_32i8': +; SSE2: Cost Model: {{.*}} 64 for instruction: %sel = select <32 x i1> +; SSE41: Cost Model: {{.*}} 2 for instruction: %sel = select <32 x i1> +;;; FIXME: This AVX cost is obviously wrong. We shouldn't be scalarizing. +; AVX: Cost Model: {{.*}} 64 for instruction: %sel = select <32 x i1> +; AVX2: Cost Model: {{.*}} 1 for instruction: %sel = select <32 x i1> + %sel = select <32 x i1> <i1 true, i1 false, i1 true, i1 true, i1 true, i1 false, i1 true, i1 true, i1 true, i1 false, i1 true, i1 true, i1 true, i1 false, i1 true, i1 true, i1 true, i1 false, i1 true, i1 true, i1 true, i1 false, i1 true, i1 true, i1 true, i1 false, i1 true, i1 true, i1 true, i1 false, i1 true, i1 true>, <32 x i8> %a, <32 x i8> %b + ret <32 x i8> %sel +} + diff --git a/test/Analysis/CostModel/X86/vshift-cost.ll b/test/Analysis/CostModel/X86/vshift-cost.ll new file mode 100644 index 0000000000000..84d72463ac0dd --- /dev/null +++ b/test/Analysis/CostModel/X86/vshift-cost.ll @@ -0,0 +1,167 @@ +; RUN: opt < %s -mtriple=x86_64-unknown-linux-gnu -mcpu=corei7 -mattr=+sse2,-sse4.1 -cost-model -analyze | FileCheck %s -check-prefix=CHECK -check-prefix=SSE2 +; RUN: opt < %s -mtriple=x86_64-unknown-linux-gnu -mcpu=corei7 -cost-model -analyze | FileCheck %s -check-prefix=CHECK -check-prefix=SSE41 +; RUN: opt < %s -mtriple=x86_64-unknown-linux-gnu -mcpu=corei7-avx -cost-model -analyze | FileCheck %s -check-prefix=CHECK -check-prefix=AVX +; RUN: opt < %s -mtriple=x86_64-unknown-linux-gnu -mcpu=core-avx2 -cost-model -analyze | FileCheck %s -check-prefix=CHECK -check-prefix=AVX2 + + +; Verify the cost of vector shift left instructions. + +; We always emit a single pmullw in the case of v8i16 vector shifts by +; non-uniform constant. + +define <8 x i16> @test1(<8 x i16> %a) { + %shl = shl <8 x i16> %a, <i16 1, i16 1, i16 2, i16 3, i16 7, i16 0, i16 9, i16 11> + ret <8 x i16> %shl +} +; CHECK: 'Cost Model Analysis' for function 'test1': +; CHECK: Found an estimated cost of 1 for instruction: %shl + + +define <8 x i16> @test2(<8 x i16> %a) { + %shl = shl <8 x i16> %a, <i16 0, i16 undef, i16 0, i16 0, i16 1, i16 undef, i16 -1, i16 1> + ret <8 x i16> %shl +} +; CHECK: 'Cost Model Analysis' for function 'test2': +; CHECK: Found an estimated cost of 1 for instruction: %shl + + +; With SSE4.1, v4i32 shifts can be lowered into a single pmulld instruction. +; Make sure that the estimated cost is always 1 except for the case where +; we only have SSE2 support. With SSE2, we are forced to special lower the +; v4i32 mul as a 2x shuffle, 2x pmuludq, 2x shuffle. + +define <4 x i32> @test3(<4 x i32> %a) { + %shl = shl <4 x i32> %a, <i32 1, i32 -1, i32 2, i32 -3> + ret <4 x i32> %shl +} +; CHECK: 'Cost Model Analysis' for function 'test3': +; SSE2: Found an estimated cost of 6 for instruction: %shl +; SSE41: Found an estimated cost of 1 for instruction: %shl +; AVX: Found an estimated cost of 1 for instruction: %shl +; AVX2: Found an estimated cost of 1 for instruction: %shl + + +define <4 x i32> @test4(<4 x i32> %a) { + %shl = shl <4 x i32> %a, <i32 0, i32 0, i32 1, i32 1> + ret <4 x i32> %shl +} +; CHECK: 'Cost Model Analysis' for function 'test4': +; SSE2: Found an estimated cost of 6 for instruction: %shl +; SSE41: Found an estimated cost of 1 for instruction: %shl +; AVX: Found an estimated cost of 1 for instruction: %shl +; AVX2: Found an estimated cost of 1 for instruction: %shl + + +; On AVX2 we are able to lower the following shift into a single +; vpsllvq. Therefore, the expected cost is only 1. +; In all other cases, this shift is scalarized as the target does not support +; vpsllv instructions. + +define <2 x i64> @test5(<2 x i64> %a) { + %shl = shl <2 x i64> %a, <i64 2, i64 3> + ret <2 x i64> %shl +} +; CHECK: 'Cost Model Analysis' for function 'test5': +; SSE2: Found an estimated cost of 20 for instruction: %shl +; SSE41: Found an estimated cost of 20 for instruction: %shl +; AVX: Found an estimated cost of 20 for instruction: %shl +; AVX2: Found an estimated cost of 1 for instruction: %shl + + +; v16i16 and v8i32 shift left by non-uniform constant are lowered into +; vector multiply instructions. With AVX (but not AVX2), the vector multiply +; is lowered into a sequence of: 1 extract + 2 vpmullw + 1 insert. +; +; With AVX2, instruction vpmullw works with 256bit quantities and +; therefore there is no need to split the resulting vector multiply into +; a sequence of two multiply. +; +; With SSE2 and SSE4.1, the vector shift cost for 'test6' is twice +; the cost computed in the case of 'test1'. That is because the backend +; simply emits 2 pmullw with no extract/insert. + + +define <16 x i16> @test6(<16 x i16> %a) { + %shl = shl <16 x i16> %a, <i16 1, i16 1, i16 2, i16 3, i16 7, i16 0, i16 9, i16 11, i16 1, i16 1, i16 2, i16 3, i16 7, i16 0, i16 9, i16 11> + ret <16 x i16> %shl +} +; CHECK: 'Cost Model Analysis' for function 'test6': +; SSE2: Found an estimated cost of 2 for instruction: %shl +; SSE41: Found an estimated cost of 2 for instruction: %shl +; AVX: Found an estimated cost of 4 for instruction: %shl +; AVX2: Found an estimated cost of 1 for instruction: %shl + + +; With SSE2 and SSE4.1, the vector shift cost for 'test7' is twice +; the cost computed in the case of 'test3'. That is because the multiply +; is type-legalized into two 4i32 vector multiply. + +define <8 x i32> @test7(<8 x i32> %a) { + %shl = shl <8 x i32> %a, <i32 1, i32 1, i32 2, i32 3, i32 1, i32 1, i32 2, i32 3> + ret <8 x i32> %shl +} +; CHECK: 'Cost Model Analysis' for function 'test7': +; SSE2: Found an estimated cost of 12 for instruction: %shl +; SSE41: Found an estimated cost of 2 for instruction: %shl +; AVX: Found an estimated cost of 4 for instruction: %shl +; AVX2: Found an estimated cost of 1 for instruction: %shl + + +; On AVX2 we are able to lower the following shift into a single +; vpsllvq. Therefore, the expected cost is only 1. +; In all other cases, this shift is scalarized as the target does not support +; vpsllv instructions. + +define <4 x i64> @test8(<4 x i64> %a) { + %shl = shl <4 x i64> %a, <i64 1, i64 2, i64 3, i64 4> + ret <4 x i64> %shl +} +; CHECK: 'Cost Model Analysis' for function 'test8': +; SSE2: Found an estimated cost of 40 for instruction: %shl +; SSE41: Found an estimated cost of 40 for instruction: %shl +; AVX: Found an estimated cost of 40 for instruction: %shl +; AVX2: Found an estimated cost of 1 for instruction: %shl + + +; Same as 'test6', with the difference that the cost is double. + +define <32 x i16> @test9(<32 x i16> %a) { + %shl = shl <32 x i16> %a, <i16 1, i16 1, i16 2, i16 3, i16 7, i16 0, i16 9, i16 11, i16 1, i16 1, i16 2, i16 3, i16 7, i16 0, i16 9, i16 11, i16 1, i16 1, i16 2, i16 3, i16 7, i16 0, i16 9, i16 11, i16 1, i16 1, i16 2, i16 3, i16 7, i16 0, i16 9, i16 11> + ret <32 x i16> %shl +} +; CHECK: 'Cost Model Analysis' for function 'test9': +; SSE2: Found an estimated cost of 4 for instruction: %shl +; SSE41: Found an estimated cost of 4 for instruction: %shl +; AVX: Found an estimated cost of 8 for instruction: %shl +; AVX2: Found an estimated cost of 2 for instruction: %shl + + +; Same as 'test7', except that now the cost is double. + +define <16 x i32> @test10(<16 x i32> %a) { + %shl = shl <16 x i32> %a, <i32 1, i32 1, i32 2, i32 3, i32 1, i32 1, i32 2, i32 3, i32 1, i32 1, i32 2, i32 3, i32 1, i32 1, i32 2, i32 3> + ret <16 x i32> %shl +} +; CHECK: 'Cost Model Analysis' for function 'test10': +; SSE2: Found an estimated cost of 24 for instruction: %shl +; SSE41: Found an estimated cost of 4 for instruction: %shl +; AVX: Found an estimated cost of 8 for instruction: %shl +; AVX2: Found an estimated cost of 2 for instruction: %shl + + +; On AVX2 we are able to lower the following shift into a sequence of +; two vpsllvq instructions. Therefore, the expected cost is only 2. +; In all other cases, this shift is scalarized as we don't have vpsllv +; instructions. + +define <8 x i64> @test11(<8 x i64> %a) { + %shl = shl <8 x i64> %a, <i64 1, i64 1, i64 2, i64 3, i64 1, i64 1, i64 2, i64 3> + ret <8 x i64> %shl +} +; CHECK: 'Cost Model Analysis' for function 'test11': +; SSE2: Found an estimated cost of 80 for instruction: %shl +; SSE41: Found an estimated cost of 80 for instruction: %shl +; AVX: Found an estimated cost of 80 for instruction: %shl +; AVX2: Found an estimated cost of 2 for instruction: %shl + + diff --git a/test/Analysis/Delinearization/a.ll b/test/Analysis/Delinearization/a.ll index 9308749b2792e..efebcc42ea276 100644 --- a/test/Analysis/Delinearization/a.ll +++ b/test/Analysis/Delinearization/a.ll @@ -12,17 +12,6 @@ ; CHECK: ArrayDecl[UnknownSize][%m][%o] with elements of sizeof(i32) bytes. ; CHECK: ArrayRef[{3,+,2}<%for.i>][{-4,+,3}<%for.j>][{7,+,5}<%for.k>] -; AddRec: {{(8 + ((4 + (12 * %m)) * %o) + %A),+,(8 * %m * %o)}<%for.i>,+,(12 * %o)}<%for.j> -; CHECK: Base offset: %A -; CHECK: ArrayDecl[UnknownSize][%o] with elements of sizeof(i32) bytes. -; CHECK: ArrayRef[{(1 + (3 * %m)),+,(2 * %m)}<%for.i>][{2,+,(3 * %o)}<%for.j>] - -; AddRec: {(8 + ((-8 + (24 * %m)) * %o) + %A),+,(8 * %m * %o)}<%for.i> -; CHECK: Base offset: %A -; CHECK: ArrayDecl[UnknownSize] with elements of 2 bytes. -; CHECK: ArrayRef[{((1 + ((-1 + (3 * %m)) * %o)) * sizeof(i32)),+,(%m * %o * sizeof(i32))}<%for.i>] - -; Function Attrs: nounwind uwtable define void @foo(i64 %n, i64 %m, i64 %o, i32* nocapture %A) #0 { entry: %cmp32 = icmp sgt i64 %n, 0 diff --git a/test/Analysis/Delinearization/gcd_multiply_expr.ll b/test/Analysis/Delinearization/gcd_multiply_expr.ll new file mode 100644 index 0000000000000..f962f6db7f2b3 --- /dev/null +++ b/test/Analysis/Delinearization/gcd_multiply_expr.ll @@ -0,0 +1,153 @@ +; RUN: opt < %s -basicaa -da -analyze -delinearize +; +; a, b, c, d, g, h; +; char *f; +; static fn1(p1) { +; char *e = p1; +; for (; d;) { +; a = 0; +; for (;; ++a) +; for (; b; ++b) +; c = e[b + a]; +; } +; } +; +; fn2() { +; for (;;) +; fn1(&f[g * h]); +; } + +@g = common global i32 0, align 4 +@h = common global i32 0, align 4 +@f = common global i8* null, align 4 +@a = common global i32 0, align 4 +@b = common global i32 0, align 4 +@c = common global i32 0, align 4 +@d = common global i32 0, align 4 + +define i32 @fn2() { +entry: + %.pr = load i32* @d, align 4 + %phitmp = icmp eq i32 %.pr, 0 + br label %for.cond + +for.cond: + %0 = phi i1 [ true, %for.cond ], [ %phitmp, %entry ] + br i1 %0, label %for.cond, label %for.cond2thread-pre-split.preheader.i + +for.cond2thread-pre-split.preheader.i: + %1 = load i32* @g, align 4 + %2 = load i32* @h, align 4 + %mul = mul nsw i32 %2, %1 + %3 = load i8** @f, align 4 + %.pr.pre.i = load i32* @b, align 4 + br label %for.cond2thread-pre-split.i + +for.cond2thread-pre-split.i: + %.pr.i = phi i32 [ 0, %for.inc5.i ], [ %.pr.pre.i, %for.cond2thread-pre-split.preheader.i ] + %storemerge.i = phi i32 [ %inc6.i, %for.inc5.i ], [ 0, %for.cond2thread-pre-split.preheader.i ] + store i32 %storemerge.i, i32* @a, align 4 + %tobool31.i = icmp eq i32 %.pr.i, 0 + br i1 %tobool31.i, label %for.inc5.i, label %for.body4.preheader.i + +for.body4.preheader.i: + %4 = icmp slt i32 %.pr.i, -7 + %add.i = add i32 %storemerge.i, %mul + br i1 %4, label %for.body4.i.preheader, label %for.body4.ur.i.preheader + +for.body4.i.preheader: + %5 = sub i32 -8, %.pr.i + %6 = lshr i32 %5, 3 + %7 = mul i32 %6, 8 + br label %for.body4.i + +for.body4.i: + %8 = phi i32 [ %inc.7.i, %for.body4.i ], [ %.pr.i, %for.body4.i.preheader ] + %arrayidx.sum1 = add i32 %add.i, %8 + %arrayidx.i = getelementptr inbounds i8* %3, i32 %arrayidx.sum1 + %9 = load i8* %arrayidx.i, align 1 + %conv.i = sext i8 %9 to i32 + store i32 %conv.i, i32* @c, align 4 + %inc.i = add nsw i32 %8, 1 + store i32 %inc.i, i32* @b, align 4 + %arrayidx.sum2 = add i32 %add.i, %inc.i + %arrayidx.1.i = getelementptr inbounds i8* %3, i32 %arrayidx.sum2 + %10 = load i8* %arrayidx.1.i, align 1 + %conv.1.i = sext i8 %10 to i32 + store i32 %conv.1.i, i32* @c, align 4 + %inc.1.i = add nsw i32 %8, 2 + store i32 %inc.1.i, i32* @b, align 4 + %arrayidx.sum3 = add i32 %add.i, %inc.1.i + %arrayidx.2.i = getelementptr inbounds i8* %3, i32 %arrayidx.sum3 + %11 = load i8* %arrayidx.2.i, align 1 + %conv.2.i = sext i8 %11 to i32 + store i32 %conv.2.i, i32* @c, align 4 + %inc.2.i = add nsw i32 %8, 3 + store i32 %inc.2.i, i32* @b, align 4 + %arrayidx.sum4 = add i32 %add.i, %inc.2.i + %arrayidx.3.i = getelementptr inbounds i8* %3, i32 %arrayidx.sum4 + %12 = load i8* %arrayidx.3.i, align 1 + %conv.3.i = sext i8 %12 to i32 + store i32 %conv.3.i, i32* @c, align 4 + %inc.3.i = add nsw i32 %8, 4 + store i32 %inc.3.i, i32* @b, align 4 + %arrayidx.sum5 = add i32 %add.i, %inc.3.i + %arrayidx.4.i = getelementptr inbounds i8* %3, i32 %arrayidx.sum5 + %13 = load i8* %arrayidx.4.i, align 1 + %conv.4.i = sext i8 %13 to i32 + store i32 %conv.4.i, i32* @c, align 4 + %inc.4.i = add nsw i32 %8, 5 + store i32 %inc.4.i, i32* @b, align 4 + %arrayidx.sum6 = add i32 %add.i, %inc.4.i + %arrayidx.5.i = getelementptr inbounds i8* %3, i32 %arrayidx.sum6 + %14 = load i8* %arrayidx.5.i, align 1 + %conv.5.i = sext i8 %14 to i32 + store i32 %conv.5.i, i32* @c, align 4 + %inc.5.i = add nsw i32 %8, 6 + store i32 %inc.5.i, i32* @b, align 4 + %arrayidx.sum7 = add i32 %add.i, %inc.5.i + %arrayidx.6.i = getelementptr inbounds i8* %3, i32 %arrayidx.sum7 + %15 = load i8* %arrayidx.6.i, align 1 + %conv.6.i = sext i8 %15 to i32 + store i32 %conv.6.i, i32* @c, align 4 + %inc.6.i = add nsw i32 %8, 7 + store i32 %inc.6.i, i32* @b, align 4 + %arrayidx.sum8 = add i32 %add.i, %inc.6.i + %arrayidx.7.i = getelementptr inbounds i8* %3, i32 %arrayidx.sum8 + %16 = load i8* %arrayidx.7.i, align 1 + %conv.7.i = sext i8 %16 to i32 + store i32 %conv.7.i, i32* @c, align 4 + %inc.7.i = add nsw i32 %8, 8 + store i32 %inc.7.i, i32* @b, align 4 + %tobool3.7.i = icmp sgt i32 %inc.7.i, -8 + br i1 %tobool3.7.i, label %for.inc5.loopexit.ur-lcssa.i, label %for.body4.i + +for.inc5.loopexit.ur-lcssa.i: + %17 = add i32 %.pr.i, 8 + %18 = add i32 %17, %7 + %19 = icmp eq i32 %18, 0 + br i1 %19, label %for.inc5.i, label %for.body4.ur.i.preheader + +for.body4.ur.i.preheader: + %.ph = phi i32 [ %18, %for.inc5.loopexit.ur-lcssa.i ], [ %.pr.i, %for.body4.preheader.i ] + br label %for.body4.ur.i + +for.body4.ur.i: + %20 = phi i32 [ %inc.ur.i, %for.body4.ur.i ], [ %.ph, %for.body4.ur.i.preheader ] + %arrayidx.sum = add i32 %add.i, %20 + %arrayidx.ur.i = getelementptr inbounds i8* %3, i32 %arrayidx.sum + %21 = load i8* %arrayidx.ur.i, align 1 + %conv.ur.i = sext i8 %21 to i32 + store i32 %conv.ur.i, i32* @c, align 4 + %inc.ur.i = add nsw i32 %20, 1 + store i32 %inc.ur.i, i32* @b, align 4 + %tobool3.ur.i = icmp eq i32 %inc.ur.i, 0 + br i1 %tobool3.ur.i, label %for.inc5.i.loopexit, label %for.body4.ur.i + +for.inc5.i.loopexit: + br label %for.inc5.i + +for.inc5.i: + %inc6.i = add nsw i32 %storemerge.i, 1 + br label %for.cond2thread-pre-split.i +} diff --git a/test/Analysis/Delinearization/himeno_1.ll b/test/Analysis/Delinearization/himeno_1.ll index 9458bd2e52610..c94ca7aff7594 100644 --- a/test/Analysis/Delinearization/himeno_1.ll +++ b/test/Analysis/Delinearization/himeno_1.ll @@ -31,16 +31,6 @@ ; CHECK: ArrayDecl[UnknownSize][(sext i32 %a.cols to i64)][(sext i32 %a.deps to i64)] with elements of sizeof(float) bytes. ; CHECK: ArrayRef[{1,+,1}<nuw><nsw><%for.i>][{1,+,1}<nuw><nsw><%for.j>][{1,+,1}<nuw><nsw><%for.k>] -; AddRec: {{(-4 + (4 * (sext i32 (-1 + %p.deps) to i64)) + (4 * (sext i32 %a.deps to i64) * (1 + (sext i32 %a.cols to i64))) + %a.base),+,(4 * (sext i32 %a.deps to i64) * (sext i32 %a.cols to i64))}<%for.i>,+,(4 * (sext i32 %a.deps to i64))}<%for.j> -; CHECK: Base offset: %a.base -; CHECK: ArrayDecl[UnknownSize][(sext i32 %a.deps to i64)] with elements of sizeof(float) bytes. -; CHECK: ArrayRef[{(1 + (sext i32 %a.cols to i64)),+,(sext i32 %a.cols to i64)}<%for.i>][{(-1 + (sext i32 (-1 + %p.deps) to i64)),+,(sext i32 %a.deps to i64)}<%for.j>] - -; AddRec: {(-4 + (4 * (sext i32 (-1 + %p.deps) to i64)) + ((sext i32 %a.deps to i64) * (-4 + (4 * (sext i32 (-1 + %p.cols) to i64)) + (4 * (sext i32 %a.cols to i64)))) + %a.base),+,(4 * (sext i32 %a.deps to i64) * (sext i32 %a.cols to i64))}<%for.i> -; CHECK: Base offset: %a.base -; CHECK: ArrayDecl[UnknownSize] with elements of sizeof(float) bytes. -; CHECK: ArrayRef[{(-1 + (sext i32 (-1 + %p.deps) to i64) + ((sext i32 %a.deps to i64) * (-1 + (sext i32 (-1 + %p.cols) to i64) + (sext i32 %a.cols to i64)))),+,((sext i32 %a.deps to i64) * (sext i32 %a.cols to i64))}<%for.i>] - %struct.Mat = type { float*, i32, i32, i32, i32 } define void @jacobi(i32 %nn, %struct.Mat* nocapture %a, %struct.Mat* nocapture %p) nounwind uwtable { diff --git a/test/Analysis/Delinearization/himeno_2.ll b/test/Analysis/Delinearization/himeno_2.ll index a29006606fab9..c256384f201ec 100644 --- a/test/Analysis/Delinearization/himeno_2.ll +++ b/test/Analysis/Delinearization/himeno_2.ll @@ -31,16 +31,6 @@ ; CHECK: ArrayDecl[UnknownSize][(sext i32 %a.cols to i64)][(sext i32 %a.deps to i64)] with elements of sizeof(float) bytes. ; CHECK: ArrayRef[{1,+,1}<nuw><nsw><%for.i>][{1,+,1}<nuw><nsw><%for.j>][{1,+,1}<nuw><nsw><%for.k>] -; AddRec: {{(-4 + (4 * (sext i32 (-1 + %p.deps) to i64)) + (4 * (sext i32 %a.deps to i64) * (1 + (sext i32 %a.cols to i64))) + %a.base),+,(4 * (sext i32 %a.deps to i64) * (sext i32 %a.cols to i64))}<%for.i>,+,(4 * (sext i32 %a.deps to i64))}<%for.j> -; CHECK: Base offset: %a.base -; CHECK: ArrayDecl[UnknownSize][(sext i32 %a.deps to i64)] with elements of sizeof(float) bytes. -; CHECK: ArrayRef[{(1 + (sext i32 %a.cols to i64)),+,(sext i32 %a.cols to i64)}<%for.i>][{(-1 + (sext i32 (-1 + %p.deps) to i64)),+,(sext i32 %a.deps to i64)}<%for.j>] - -; AddRec: {(-4 + (4 * (sext i32 (-1 + %p.deps) to i64)) + ((sext i32 %a.deps to i64) * (-4 + (4 * (sext i32 (-1 + %p.cols) to i64)) + (4 * (sext i32 %a.cols to i64)))) + %a.base),+,(4 * (sext i32 %a.deps to i64) * (sext i32 %a.cols to i64))}<%for.i> -; CHECK: Base offset: %a.base -; CHECK: ArrayDecl[UnknownSize] with elements of sizeof(float) bytes. -; CHECK: ArrayRef[{(-1 + (sext i32 (-1 + %p.deps) to i64) + ((sext i32 %a.deps to i64) * (-1 + (sext i32 (-1 + %p.cols) to i64) + (sext i32 %a.cols to i64)))),+,((sext i32 %a.deps to i64) * (sext i32 %a.cols to i64))}<%for.i>] - %struct.Mat = type { float*, i32, i32, i32, i32 } define void @jacobi(i32 %nn, %struct.Mat* nocapture %a, %struct.Mat* nocapture %p) nounwind uwtable { diff --git a/test/Analysis/Delinearization/iv_times_constant_in_subscript.ll b/test/Analysis/Delinearization/iv_times_constant_in_subscript.ll new file mode 100644 index 0000000000000..01a4b96b11a08 --- /dev/null +++ b/test/Analysis/Delinearization/iv_times_constant_in_subscript.ll @@ -0,0 +1,45 @@ +; RUN: opt < %s -analyze -delinearize | FileCheck %s + +; Derived from the following code: +; +; void foo(long n, long m, long b, double A[n][m]) { +; for (long i = 0; i < n; i++) +; for (long j = 0; j < m; j++) +; A[2i+b][2j] = 1.0; +; } + +; AddRec: {{((%m * %b * sizeof(double)) + %A),+,(2 * %m * sizeof(double))}<%for.i>,+,(2 * sizeof(double))}<%for.j> +; CHECK: Base offset: %A +; CHECK: ArrayDecl[UnknownSize][%m] with elements of sizeof(double) bytes. +; CHECK: ArrayRef[{%b,+,2}<%for.i>][{0,+,2}<%for.j>] + + +define void @foo(i64 %n, i64 %m, i64 %b, double* %A) { +entry: + br label %for.i + +for.i: + %i = phi i64 [ 0, %entry ], [ %i.inc, %for.i.inc ] + %outerdim = mul nsw i64 %i, 2 + %outerdim2 = add nsw i64 %outerdim, %b + %tmp = mul nsw i64 %outerdim2, %m + br label %for.j + +for.j: + %j = phi i64 [ 0, %for.i ], [ %j.inc, %for.j ] + %prodj = mul i64 %j, 2 + %vlaarrayidx.sum = add i64 %prodj, %tmp + %arrayidx = getelementptr inbounds double* %A, i64 %vlaarrayidx.sum + store double 1.0, double* %arrayidx + %j.inc = add nsw i64 %j, 1 + %j.exitcond = icmp eq i64 %j.inc, %m + br i1 %j.exitcond, label %for.i.inc, label %for.j + +for.i.inc: + %i.inc = add nsw i64 %i, 1 + %i.exitcond = icmp eq i64 %i.inc, %n + br i1 %i.exitcond, label %end, label %for.i + +end: + ret void +} diff --git a/test/Analysis/Delinearization/lit.local.cfg b/test/Analysis/Delinearization/lit.local.cfg index 19eebc0ac7ac3..c6106e4746f2d 100644 --- a/test/Analysis/Delinearization/lit.local.cfg +++ b/test/Analysis/Delinearization/lit.local.cfg @@ -1 +1 @@ -config.suffixes = ['.ll', '.c', '.cpp'] +config.suffixes = ['.ll'] diff --git a/test/Analysis/Delinearization/multidim_ivs_and_integer_offsets_3d.ll b/test/Analysis/Delinearization/multidim_ivs_and_integer_offsets_3d.ll index 82cab167c74f7..ae80ebc52271f 100644 --- a/test/Analysis/Delinearization/multidim_ivs_and_integer_offsets_3d.ll +++ b/test/Analysis/Delinearization/multidim_ivs_and_integer_offsets_3d.ll @@ -13,16 +13,6 @@ ; CHECK: ArrayDecl[UnknownSize][%m][%o] with elements of sizeof(double) bytes. ; CHECK: ArrayRef[{3,+,1}<nw><%for.i>][{-4,+,1}<nw><%for.j>][{7,+,1}<nw><%for.k>] -; AddRec: {{(48 + ((-24 + (24 * %m)) * %o) + %A),+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j> -; CHECK: Base offset: %A -; CHECK: ArrayDecl[UnknownSize][%o] with elements of sizeof(double) bytes. -; CHECK: ArrayRef[{(-3 + (3 * %m)),+,%m}<%for.i>][{6,+,%o}<%for.j>] - -; AddRec: {(48 + ((-32 + (32 * %m)) * %o) + %A),+,(8 * %m * %o)}<%for.i> -; CHECK: Base offset: %A -; CHECK: ArrayDecl[UnknownSize] with elements of sizeof(double) bytes. -; CHECK: ArrayRef[{(6 + ((-4 + (4 * %m)) * %o)),+,(%m * %o)}<%for.i>] - define void @foo(i64 %n, i64 %m, i64 %o, double* %A) { entry: br label %for.i diff --git a/test/Analysis/Delinearization/multidim_ivs_and_integer_offsets_nts_3d.ll b/test/Analysis/Delinearization/multidim_ivs_and_integer_offsets_nts_3d.ll index a1e779fff6c9f..75080dad3af7a 100644 --- a/test/Analysis/Delinearization/multidim_ivs_and_integer_offsets_nts_3d.ll +++ b/test/Analysis/Delinearization/multidim_ivs_and_integer_offsets_nts_3d.ll @@ -13,16 +13,6 @@ ; CHECK: ArrayDecl[UnknownSize][%m][(%o + %p)] with elements of sizeof(double) bytes. ; CHECK: ArrayRef[{3,+,1}<nw><%for.cond4.preheader.lr.ph.us>][{-4,+,1}<nw><%for.body6.lr.ph.us.us>][{7,+,1}<nw><%for.body6.us.us>] -; AddRec: {{(48 + (8 * %o) + (8 * (-4 + (3 * %m)) * (%o + %p)) + %A),+,(8 * (%o + %p) * %m)}<%for.cond4.preheader.lr.ph.us>,+,(8 * (%o + %p))}<%for.body6.lr.ph.us.us> -; CHECK: Base offset: %A -; CHECK: ArrayDecl[UnknownSize][(%o + %p)] with elements of sizeof(double) bytes. -; CHECK: ArrayRef[{(-4 + (3 * %m)),+,%m}<%for.cond4.preheader.lr.ph.us>][{(6 + %o),+,(%o + %p)}<%for.body6.lr.ph.us.us>] - -; AddRec: {(48 + (8 * %o) + ((-40 + (32 * %m)) * (%o + %p)) + %A),+,(8 * (%o + %p) * %m)}<%for.cond4.preheader.lr.ph.us> -; CHECK: Base offset: %A -; CHECK: ArrayDecl[UnknownSize] with elements of sizeof(double) bytes. -; CHECK: ArrayRef[{(6 + ((-5 + (4 * %m)) * (%o + %p)) + %o),+,((%o + %p) * %m)}<%for.cond4.preheader.lr.ph.us>] - define void @foo(i64 %n, i64 %m, i64 %o, i64 %p, double* nocapture %A) nounwind uwtable { entry: %add = add nsw i64 %p, %o diff --git a/test/Analysis/Delinearization/multidim_ivs_and_parameteric_offsets_3d.ll b/test/Analysis/Delinearization/multidim_ivs_and_parameteric_offsets_3d.ll index a52a4c93ce23f..e921444668d08 100644 --- a/test/Analysis/Delinearization/multidim_ivs_and_parameteric_offsets_3d.ll +++ b/test/Analysis/Delinearization/multidim_ivs_and_parameteric_offsets_3d.ll @@ -13,16 +13,6 @@ ; CHECK: ArrayDecl[UnknownSize][%m][%o] with elements of sizeof(double) bytes. ; CHECK: ArrayRef[{%p,+,1}<nw><%for.i>][{%q,+,1}<nw><%for.j>][{%r,+,1}<nw><%for.k>] -; AddRec: {{(-8 + (8 * ((((%m * %p) + %q) * %o) + %r)) + (8 * %o) + %A),+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j> -; CHECK: Base offset: %A -; CHECK: ArrayDecl[UnknownSize][%o] with elements of sizeof(double) bytes. -; CHECK: ArrayRef[{(1 + (%m * %p) + %q),+,%m}<%for.i>][{(-1 + %r),+,%o}<%for.j>] - -; AddRec: {(-8 + (8 * ((((%m * %p) + %q) * %o) + %r)) + (8 * %m * %o) + %A),+,(8 * %m * %o)}<%for.i> -; CHECK: Base offset: %A -; CHECK: ArrayDecl[UnknownSize] with elements of sizeof(double) bytes. -; CHECK: ArrayRef[{(-1 + ((((1 + %p) * %m) + %q) * %o) + %r),+,(%m * %o)}<%for.i>] - define void @foo(i64 %n, i64 %m, i64 %o, double* %A, i64 %p, i64 %q, i64 %r) { entry: br label %for.i diff --git a/test/Analysis/Delinearization/multidim_only_ivs_2d.ll b/test/Analysis/Delinearization/multidim_only_ivs_2d.ll index d68a15883942e..5a88c4ce4eb1f 100644 --- a/test/Analysis/Delinearization/multidim_only_ivs_2d.ll +++ b/test/Analysis/Delinearization/multidim_only_ivs_2d.ll @@ -8,16 +8,20 @@ ; A[i][j] = 1.0; ; } +; Inst: %val = load double* %arrayidx +; In Loop with Header: for.j +; AddRec: {{0,+,(%m * sizeof(double))}<%for.i>,+,sizeof(double)}<%for.j> +; Base offset: %A +; ArrayDecl[UnknownSize][%m] with elements of sizeof(double) bytes. +; ArrayRef[{0,+,1}<nuw><nsw><%for.i>][{0,+,1}<nuw><nsw><%for.j>] + +; Inst: store double %val, double* %arrayidx +; In Loop with Header: for.j ; AddRec: {{%A,+,(8 * %m)}<%for.i>,+,8}<%for.j> ; CHECK: Base offset: %A ; CHECK: ArrayDecl[UnknownSize][%m] with elements of sizeof(double) bytes. ; CHECK: ArrayRef[{0,+,1}<nuw><nsw><%for.i>][{0,+,1}<nuw><nsw><%for.j>] -; AddRec: {(-8 + (8 * %m) + %A),+,(8 * %m)}<%for.i> -; CHECK: Base offset: %A -; CHECK: ArrayDecl[UnknownSize] with elements of sizeof(double) bytes. -; CHECK: ArrayRef[{(-1 + %m),+,%m}<%for.i>] - define void @foo(i64 %n, i64 %m, double* %A) { entry: br label %for.i @@ -31,7 +35,8 @@ for.j: %j = phi i64 [ 0, %for.i ], [ %j.inc, %for.j ] %vlaarrayidx.sum = add i64 %j, %tmp %arrayidx = getelementptr inbounds double* %A, i64 %vlaarrayidx.sum - store double 1.0, double* %arrayidx + %val = load double* %arrayidx + store double %val, double* %arrayidx %j.inc = add nsw i64 %j, 1 %j.exitcond = icmp eq i64 %j.inc, %m br i1 %j.exitcond, label %for.i.inc, label %for.j diff --git a/test/Analysis/Delinearization/multidim_only_ivs_2d_nested.ll b/test/Analysis/Delinearization/multidim_only_ivs_2d_nested.ll index 7207420205aad..810188f7d552b 100644 --- a/test/Analysis/Delinearization/multidim_only_ivs_2d_nested.ll +++ b/test/Analysis/Delinearization/multidim_only_ivs_2d_nested.ll @@ -1,4 +1,6 @@ ; RUN: opt < %s -analyze -delinearize | FileCheck %s +; XFAIL: * +; We do not recognize anymore variable size arrays. ; extern void bar(long n, long m, double A[n][m]); ; diff --git a/test/Analysis/Delinearization/multidim_only_ivs_3d.ll b/test/Analysis/Delinearization/multidim_only_ivs_3d.ll index 24f95837c8607..aad0f09408400 100644 --- a/test/Analysis/Delinearization/multidim_only_ivs_3d.ll +++ b/test/Analysis/Delinearization/multidim_only_ivs_3d.ll @@ -13,16 +13,6 @@ ; CHECK: ArrayDecl[UnknownSize][%m][%o] with elements of sizeof(double) bytes. ; CHECK: ArrayRef[{0,+,1}<nuw><nsw><%for.i>][{0,+,1}<nuw><nsw><%for.j>][{0,+,1}<nuw><nsw><%for.k>] -; AddRec: {{(-8 + (8 * %o) + %A),+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j> -; CHECK: Base offset: %A -; CHECK: ArrayDecl[UnknownSize][(%m * %o)] with elements of sizeof(double) bytes. -; CHECK: ArrayRef[{0,+,1}<nuw><nsw><%for.i>][{(-1 + %o),+,%o}<%for.j>] - -; AddRec: {(-8 + (8 * %m * %o) + %A),+,(8 * %m * %o)}<%for.i> -; CHECK: Base offset: %A -; CHECK: ArrayDecl[UnknownSize] with elements of sizeof(double) bytes. -; CHECK: ArrayRef[{(-1 + (%m * %o)),+,(%m * %o)}<%for.i>] - define void @foo(i64 %n, i64 %m, i64 %o, double* %A) { entry: br label %for.i diff --git a/test/Analysis/Delinearization/multidim_only_ivs_3d_cast.ll b/test/Analysis/Delinearization/multidim_only_ivs_3d_cast.ll index e1516104ddfcb..9e406d125f44f 100644 --- a/test/Analysis/Delinearization/multidim_only_ivs_3d_cast.ll +++ b/test/Analysis/Delinearization/multidim_only_ivs_3d_cast.ll @@ -12,16 +12,6 @@ ; CHECK: ArrayDecl[UnknownSize][(zext i32 %m to i64)][(zext i32 %o to i64)] with elements of 8 bytes. ; CHECK: ArrayRef[{0,+,1}<%for.i>][{0,+,1}<%for.j>][{0,+,1}<%for.k>] -; AddRec: {{((8 * (zext i32 (-1 + %o) to i64)) + %A),+,(8 * (zext i32 %m to i64) * (zext i32 %o to i64))}<%for.i>,+,(8 * (zext i32 %o to i64))}<%for.j> -; CHECK: Base offset: %A -; CHECK: ArrayDecl[UnknownSize][((zext i32 %m to i64) * (zext i32 %o to i64))] with elements of 8 bytes. -; CHECK: ArrayRef[{0,+,1}<%for.i>][{(zext i32 (-1 + %o) to i64),+,(zext i32 %o to i64)}<%for.j>] - -; AddRec: {((8 * (zext i32 (-1 + %o) to i64)) + (8 * (zext i32 (-1 + %m) to i64) * (zext i32 %o to i64)) + %A),+,(8 * (zext i32 %m to i64) * (zext i32 %o to i64))}<%for.i> -; CHECK: Base offset: %A -; CHECK: ArrayDecl[UnknownSize] with elements of 8 bytes. -; CHECK: ArrayRef[{((zext i32 (-1 + %o) to i64) + ((zext i32 (-1 + %m) to i64) * (zext i32 %o to i64))),+,((zext i32 %m to i64) * (zext i32 %o to i64))}<%for.i>] - target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/test/Analysis/Delinearization/multidim_two_accesses_different_delinearization.ll b/test/Analysis/Delinearization/multidim_two_accesses_different_delinearization.ll new file mode 100644 index 0000000000000..6a98507340acf --- /dev/null +++ b/test/Analysis/Delinearization/multidim_two_accesses_different_delinearization.ll @@ -0,0 +1,43 @@ +; RUN: opt -basicaa -da -analyze -da-delinearize < %s +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Derived from the following code: +; +; void foo(long n, long m, double *A) { +; for (long i = 0; i < n; i++) +; for (long j = 0; j < m; j++) +; *(A + i * n + j) = 1.0; +; *(A + j * m + i) = 2.0; +; } + +define void @foo(i64 %n, i64 %m, double* %A) { +entry: + br label %for.i + +for.i: + %i = phi i64 [ 0, %entry ], [ %i.inc, %for.i.inc ] + br label %for.j + +for.j: + %j = phi i64 [ 0, %for.i ], [ %j.inc, %for.j ] + %tmp = mul nsw i64 %i, %m + %vlaarrayidx.sum = add i64 %j, %tmp + %arrayidx = getelementptr inbounds double* %A, i64 %vlaarrayidx.sum + store double 1.0, double* %arrayidx + %tmp1 = mul nsw i64 %j, %n + %vlaarrayidx.sum1 = add i64 %i, %tmp1 + %arrayidx1 = getelementptr inbounds double* %A, i64 %vlaarrayidx.sum1 + store double 1.0, double* %arrayidx1 + %j.inc = add nsw i64 %j, 1 + %j.exitcond = icmp eq i64 %j.inc, %m + br i1 %j.exitcond, label %for.i.inc, label %for.j + +for.i.inc: + %i.inc = add nsw i64 %i, 1 + %i.exitcond = icmp eq i64 %i.inc, %n + br i1 %i.exitcond, label %end, label %for.i + +end: + ret void +} diff --git a/test/Analysis/Delinearization/undef.ll b/test/Analysis/Delinearization/undef.ll new file mode 100644 index 0000000000000..8ee64e3a2f409 --- /dev/null +++ b/test/Analysis/Delinearization/undef.ll @@ -0,0 +1,38 @@ +; RUN: opt < %s -analyze -delinearize +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @foo(double* %Ey) { +entry: + br i1 undef, label %for.cond55.preheader, label %for.end324 + +for.cond55.preheader: + %iz.069 = phi i64 [ %inc323, %for.inc322 ], [ 0, %entry ] + br i1 undef, label %for.cond58.preheader, label %for.inc322 + +for.cond58.preheader: + %iy.067 = phi i64 [ %inc320, %for.end ], [ 0, %for.cond55.preheader ] + br i1 undef, label %for.body60, label %for.end + +for.body60: + %ix.062 = phi i64 [ %inc, %for.body60 ], [ 0, %for.cond58.preheader ] + %0 = mul i64 %iz.069, undef + %tmp5 = add i64 %iy.067, %0 + %tmp6 = mul i64 %tmp5, undef + %arrayidx69.sum = add i64 undef, %tmp6 + %arrayidx70 = getelementptr inbounds double* %Ey, i64 %arrayidx69.sum + %1 = load double* %arrayidx70, align 8 + %inc = add nsw i64 %ix.062, 1 + br i1 false, label %for.body60, label %for.end + +for.end: + %inc320 = add nsw i64 %iy.067, 1 + br i1 undef, label %for.cond58.preheader, label %for.inc322 + +for.inc322: + %inc323 = add nsw i64 %iz.069, 1 + br i1 undef, label %for.cond55.preheader, label %for.end324 + +for.end324: + ret void +} diff --git a/test/Analysis/DependenceAnalysis/Banerjee.ll b/test/Analysis/DependenceAnalysis/Banerjee.ll index 09e8fd29dcc42..883a06d0bed50 100644 --- a/test/Analysis/DependenceAnalysis/Banerjee.ll +++ b/test/Analysis/DependenceAnalysis/Banerjee.ll @@ -1,4 +1,5 @@ -; RUN: opt < %s -analyze -basicaa -da | FileCheck %s +; RUN: opt < %s -analyze -basicaa -da -da-delinearize=false | FileCheck %s +; RUN: opt < %s -analyze -basicaa -da -da-delinearize | FileCheck %s -check-prefix=DELIN ; ModuleID = 'Banerjee.bc' target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" @@ -21,6 +22,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - none! +; DELIN: 'Dependence Analysis' for function 'banerjee0': +; DELIN: da analyze - none! +; DELIN: da analyze - flow [<= <>]! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! + for.cond1.preheader: ; preds = %entry, %for.inc7 %B.addr.04 = phi i64* [ %B, %entry ], [ %scevgep, %for.inc7 ] %i.03 = phi i64 [ 1, %entry ], [ %inc8, %for.inc7 ] @@ -73,6 +82,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - output [* *]! +; DELIN: 'Dependence Analysis' for function 'banerjee1': +; DELIN: da analyze - output [* *]! +; DELIN: da analyze - flow [* <>]! +; DELIN: da analyze - confused! +; DELIN: da analyze - input [* *]! +; DELIN: da analyze - confused! +; DELIN: da analyze - output [* *]! + for.cond1.preheader.preheader: ; preds = %entry %0 = add i64 %n, 1 br label %for.cond1.preheader @@ -140,6 +157,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - none! +; DELIN: 'Dependence Analysis' for function 'banerjee2': +; DELIN: da analyze - none! +; DELIN: da analyze - none! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! + for.cond1.preheader: ; preds = %entry, %for.inc8 %B.addr.04 = phi i64* [ %B, %entry ], [ %scevgep, %for.inc8 ] %i.03 = phi i64 [ 0, %entry ], [ %inc9, %for.inc8 ] @@ -191,6 +216,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - none! +; DELIN: 'Dependence Analysis' for function 'banerjee3': +; DELIN: da analyze - none! +; DELIN: da analyze - flow [> >]! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! + for.cond1.preheader: ; preds = %entry, %for.inc8 %B.addr.04 = phi i64* [ %B, %entry ], [ %scevgep, %for.inc8 ] %i.03 = phi i64 [ 0, %entry ], [ %inc9, %for.inc8 ] @@ -242,6 +275,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - none! +; DELIN: 'Dependence Analysis' for function 'banerjee4': +; DELIN: da analyze - none! +; DELIN: da analyze - none! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! + for.cond1.preheader: ; preds = %entry, %for.inc7 %B.addr.04 = phi i64* [ %B, %entry ], [ %scevgep, %for.inc7 ] %i.03 = phi i64 [ 0, %entry ], [ %inc8, %for.inc7 ] @@ -293,6 +334,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - none! +; DELIN: 'Dependence Analysis' for function 'banerjee5': +; DELIN: da analyze - none! +; DELIN: da analyze - flow [< <]! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! + for.cond1.preheader: ; preds = %entry, %for.inc7 %B.addr.04 = phi i64* [ %B, %entry ], [ %scevgep, %for.inc7 ] %i.03 = phi i64 [ 0, %entry ], [ %inc8, %for.inc7 ] @@ -344,6 +393,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - none! +; DELIN: 'Dependence Analysis' for function 'banerjee6': +; DELIN: da analyze - none! +; DELIN: da analyze - flow [=> <>]! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! + for.cond1.preheader: ; preds = %entry, %for.inc8 %B.addr.04 = phi i64* [ %B, %entry ], [ %scevgep, %for.inc8 ] %i.03 = phi i64 [ 0, %entry ], [ %inc9, %for.inc8 ] @@ -395,6 +452,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - none! +; DELIN: 'Dependence Analysis' for function 'banerjee7': +; DELIN: da analyze - none! +; DELIN: da analyze - flow [> <=]! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! + for.cond1.preheader: ; preds = %entry, %for.inc8 %B.addr.04 = phi i64* [ %B, %entry ], [ %scevgep, %for.inc8 ] %i.03 = phi i64 [ 0, %entry ], [ %inc9, %for.inc8 ] @@ -446,6 +511,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - none! +; DELIN: 'Dependence Analysis' for function 'banerjee8': +; DELIN: da analyze - none! +; DELIN: da analyze - flow [> <>]! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! + for.cond1.preheader: ; preds = %entry, %for.inc8 %B.addr.04 = phi i64* [ %B, %entry ], [ %scevgep, %for.inc8 ] %i.03 = phi i64 [ 0, %entry ], [ %inc9, %for.inc8 ] @@ -497,6 +570,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - none! +; DELIN: 'Dependence Analysis' for function 'banerjee9': +; DELIN: da analyze - output [* *]! +; DELIN: da analyze - flow [<= =|<]! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! + for.cond1.preheader: ; preds = %entry, %for.inc8 %B.addr.04 = phi i64* [ %B, %entry ], [ %scevgep, %for.inc8 ] %i.03 = phi i64 [ 0, %entry ], [ %inc9, %for.inc8 ] @@ -549,6 +630,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - none! +; DELIN: 'Dependence Analysis' for function 'banerjee10': +; DELIN: da analyze - none! +; DELIN: da analyze - flow [<> =]! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! + for.cond1.preheader: ; preds = %entry, %for.inc7 %B.addr.04 = phi i64* [ %B, %entry ], [ %scevgep, %for.inc7 ] %i.03 = phi i64 [ 0, %entry ], [ %inc8, %for.inc7 ] @@ -600,6 +689,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - none! +; DELIN: 'Dependence Analysis' for function 'banerjee11': +; DELIN: da analyze - none! +; DELIN: da analyze - flow [<= <>]! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! + for.cond1.preheader: ; preds = %entry, %for.inc7 %B.addr.04 = phi i64* [ %B, %entry ], [ %scevgep, %for.inc7 ] %i.03 = phi i64 [ 0, %entry ], [ %inc8, %for.inc7 ] @@ -651,6 +748,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - none! +; DELIN: 'Dependence Analysis' for function 'banerjee12': +; DELIN: da analyze - none! +; DELIN: da analyze - flow [= <>]! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! + for.cond1.preheader: ; preds = %entry, %for.inc7 %B.addr.04 = phi i64* [ %B, %entry ], [ %scevgep, %for.inc7 ] %i.03 = phi i64 [ 0, %entry ], [ %inc8, %for.inc7 ] diff --git a/test/Analysis/DependenceAnalysis/GCD.ll b/test/Analysis/DependenceAnalysis/GCD.ll index bb31d118857d6..7eca18ed262c5 100644 --- a/test/Analysis/DependenceAnalysis/GCD.ll +++ b/test/Analysis/DependenceAnalysis/GCD.ll @@ -1,4 +1,5 @@ -; RUN: opt < %s -analyze -basicaa -da | FileCheck %s +; RUN: opt < %s -analyze -basicaa -da -da-delinearize=false | FileCheck %s +; RUN: opt < %s -analyze -basicaa -da -da-delinearize | FileCheck %s -check-prefix=DELIN ; ModuleID = 'GCD.bc' target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" @@ -22,6 +23,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - none! +; DELIN: 'Dependence Analysis' for function 'gcd0' +; DELIN: da analyze - output [* *]! +; DELIN: da analyze - flow [=> *|<]! +; DELIN: da analyze - confused! +; DELIN: da analyze - input [* *]! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! + for.cond1.preheader: ; preds = %entry, %for.inc8 %B.addr.04 = phi i32* [ %B, %entry ], [ %scevgep, %for.inc8 ] %i.03 = phi i64 [ 0, %entry ], [ %inc9, %for.inc8 ] @@ -75,6 +84,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - none! +; DELIN: 'Dependence Analysis' for function 'gcd1' +; DELIN: da analyze - output [* *]! +; DELIN: da analyze - none! +; DELIN: da analyze - confused! +; DELIN: da analyze - input [* *]! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! + for.cond1.preheader: ; preds = %entry, %for.inc9 %B.addr.04 = phi i32* [ %B, %entry ], [ %scevgep, %for.inc9 ] %i.03 = phi i64 [ 0, %entry ], [ %inc10, %for.inc9 ] @@ -129,6 +146,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - none! +; DELIN: 'Dependence Analysis' for function 'gcd2' +; DELIN: da analyze - output [* *]! +; DELIN: da analyze - none! +; DELIN: da analyze - confused! +; DELIN: da analyze - input [* *]! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! + for.cond1.preheader: ; preds = %entry, %for.inc9 %B.addr.04 = phi i32* [ %B, %entry ], [ %scevgep, %for.inc9 ] %i.03 = phi i64 [ 0, %entry ], [ %inc10, %for.inc9 ] @@ -183,6 +208,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - none! +; DELIN: 'Dependence Analysis' for function 'gcd3' +; DELIN: da analyze - output [* *]! +; DELIN: da analyze - flow [<> *]! +; DELIN: da analyze - confused! +; DELIN: da analyze - input [* *]! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! + for.cond1.preheader: ; preds = %entry, %for.inc7 %B.addr.04 = phi i32* [ %B, %entry ], [ %scevgep, %for.inc7 ] %i.03 = phi i64 [ 0, %entry ], [ %inc8, %for.inc7 ] @@ -235,6 +268,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - none! +; DELIN: 'Dependence Analysis' for function 'gcd4' +; DELIN: da analyze - output [* *]! +; DELIN: da analyze - none! +; DELIN: da analyze - confused! +; DELIN: da analyze - input [* *]! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! + for.cond1.preheader: ; preds = %entry, %for.inc17 %B.addr.04 = phi i32* [ %B, %entry ], [ %scevgep, %for.inc17 ] %i.03 = phi i64 [ 0, %entry ], [ %inc18, %for.inc17 ] @@ -297,6 +338,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - none! +; DELIN: 'Dependence Analysis' for function 'gcd5' +; DELIN: da analyze - output [* *]! +; DELIN: da analyze - flow [<> *]! +; DELIN: da analyze - confused! +; DELIN: da analyze - input [* *]! +; DELIN: da analyze - confused! +; DELIN: da analyze - none! + for.cond1.preheader: ; preds = %entry, %for.inc17 %B.addr.04 = phi i32* [ %B, %entry ], [ %scevgep, %for.inc17 ] %i.03 = phi i64 [ 0, %entry ], [ %inc18, %for.inc17 ] @@ -360,6 +409,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - output [* *]! +; DELIN: 'Dependence Analysis' for function 'gcd6' +; DELIN: da analyze - output [* *]! +; DELIN: da analyze - none! +; DELIN: da analyze - confused! +; DELIN: da analyze - input [* *]! +; DELIN: da analyze - confused! +; DELIN: da analyze - output [* *]! + for.cond1.preheader.preheader: ; preds = %entry br label %for.cond1.preheader @@ -432,6 +489,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - output [* *]! +; DELIN: 'Dependence Analysis' for function 'gcd7' +; DELIN: da analyze - output [* *]! +; DELIN: da analyze - flow [* *|<]! +; DELIN: da analyze - confused! +; DELIN: da analyze - input [* *]! +; DELIN: da analyze - confused! +; DELIN: da analyze - output [* *]! + for.cond1.preheader.preheader: ; preds = %entry br label %for.cond1.preheader @@ -516,6 +581,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - output [* *]! +; DELIN: 'Dependence Analysis' for function 'gcd8' +; DELIN: da analyze - output [* *]! +; DELIN: da analyze - none! +; DELIN: da analyze - confused! +; DELIN: da analyze - input [* *]! +; DELIN: da analyze - confused! +; DELIN: da analyze - output [* *]! + for.cond1.preheader.preheader: ; preds = %entry br label %for.cond1.preheader @@ -595,6 +668,14 @@ entry: ; CHECK: da analyze - confused! ; CHECK: da analyze - output [* *]! +; DELIN: 'Dependence Analysis' for function 'gcd9' +; DELIN: da analyze - output [* *]! +; DELIN: da analyze - flow [* *|<]! +; DELIN: da analyze - confused! +; DELIN: da analyze - input [* *]! +; DELIN: da analyze - confused! +; DELIN: da analyze - output [* *]! + for.cond1.preheader.preheader: ; preds = %entry br label %for.cond1.preheader diff --git a/test/Analysis/LazyCallGraph/basic.ll b/test/Analysis/LazyCallGraph/basic.ll new file mode 100644 index 0000000000000..b8108d99ed6f5 --- /dev/null +++ b/test/Analysis/LazyCallGraph/basic.ll @@ -0,0 +1,176 @@ +; RUN: opt -disable-output -passes=print-cg %s 2>&1 | FileCheck %s +; +; Basic validation of the call graph analysis used in the new pass manager. + +define void @f() { +; CHECK-LABEL: Call edges in function: f +; CHECK-NOT: -> + +entry: + ret void +} + +; A bunch more functions just to make it easier to test several call edges at once. +define void @f1() { + ret void +} +define void @f2() { + ret void +} +define void @f3() { + ret void +} +define void @f4() { + ret void +} +define void @f5() { + ret void +} +define void @f6() { + ret void +} +define void @f7() { + ret void +} +define void @f8() { + ret void +} +define void @f9() { + ret void +} +define void @f10() { + ret void +} +define void @f11() { + ret void +} +define void @f12() { + ret void +} + +declare i32 @__gxx_personality_v0(...) + +define void @test0() { +; CHECK-LABEL: Call edges in function: test0 +; CHECK-NEXT: -> f +; CHECK-NOT: -> + +entry: + call void @f() + call void @f() + call void @f() + call void @f() + ret void +} + +define void ()* @test1(void ()** %x) { +; CHECK-LABEL: Call edges in function: test1 +; CHECK-NEXT: -> f12 +; CHECK-NEXT: -> f11 +; CHECK-NEXT: -> f10 +; CHECK-NEXT: -> f7 +; CHECK-NEXT: -> f9 +; CHECK-NEXT: -> f8 +; CHECK-NEXT: -> f6 +; CHECK-NEXT: -> f5 +; CHECK-NEXT: -> f4 +; CHECK-NEXT: -> f3 +; CHECK-NEXT: -> f2 +; CHECK-NEXT: -> f1 +; CHECK-NOT: -> + +entry: + br label %next + +dead: + br label %next + +next: + phi void ()* [ @f1, %entry ], [ @f2, %dead ] + select i1 true, void ()* @f3, void ()* @f4 + store void ()* @f5, void ()** %x + call void @f6() + call void (void ()*, void ()*)* bitcast (void ()* @f7 to void (void ()*, void ()*)*)(void ()* @f8, void ()* @f9) + invoke void @f10() to label %exit unwind label %unwind + +exit: + ret void ()* @f11 + +unwind: + %res = landingpad { i8*, i32 } personality i32 (...)* @__gxx_personality_v0 + cleanup + resume { i8*, i32 } { i8* bitcast (void ()* @f12 to i8*), i32 42 } +} + +@g = global void ()* @f1 +@g1 = global [4 x void ()*] [void ()* @f2, void ()* @f3, void ()* @f4, void ()* @f5] +@g2 = global {i8, void ()*, i8} {i8 1, void ()* @f6, i8 2} +@h = constant void ()* @f7 + +define void @test2() { +; CHECK-LABEL: Call edges in function: test2 +; CHECK-NEXT: -> f7 +; CHECK-NEXT: -> f6 +; CHECK-NEXT: -> f5 +; CHECK-NEXT: -> f4 +; CHECK-NEXT: -> f3 +; CHECK-NEXT: -> f2 +; CHECK-NEXT: -> f1 +; CHECK-NOT: -> + + load i8** bitcast (void ()** @g to i8**) + load i8** bitcast (void ()** getelementptr ([4 x void ()*]* @g1, i32 0, i32 2) to i8**) + load i8** bitcast (void ()** getelementptr ({i8, void ()*, i8}* @g2, i32 0, i32 1) to i8**) + load i8** bitcast (void ()** @h to i8**) + ret void +} + +; Verify the SCCs formed. +; +; CHECK-LABEL: SCC with 1 functions: +; CHECK-NEXT: f7 +; +; CHECK-LABEL: SCC with 1 functions: +; CHECK-NEXT: f6 +; +; CHECK-LABEL: SCC with 1 functions: +; CHECK-NEXT: f5 +; +; CHECK-LABEL: SCC with 1 functions: +; CHECK-NEXT: f4 +; +; CHECK-LABEL: SCC with 1 functions: +; CHECK-NEXT: f3 +; +; CHECK-LABEL: SCC with 1 functions: +; CHECK-NEXT: f2 +; +; CHECK-LABEL: SCC with 1 functions: +; CHECK-NEXT: f1 +; +; CHECK-LABEL: SCC with 1 functions: +; CHECK-NEXT: test2 +; +; CHECK-LABEL: SCC with 1 functions: +; CHECK-NEXT: f12 +; +; CHECK-LABEL: SCC with 1 functions: +; CHECK-NEXT: f11 +; +; CHECK-LABEL: SCC with 1 functions: +; CHECK-NEXT: f10 +; +; CHECK-LABEL: SCC with 1 functions: +; CHECK-NEXT: f9 +; +; CHECK-LABEL: SCC with 1 functions: +; CHECK-NEXT: f8 +; +; CHECK-LABEL: SCC with 1 functions: +; CHECK-NEXT: test1 +; +; CHECK-LABEL: SCC with 1 functions: +; CHECK-NEXT: f +; +; CHECK-LABEL: SCC with 1 functions: +; CHECK-NEXT: test0 diff --git a/test/Analysis/Lint/address-spaces.ll b/test/Analysis/Lint/address-spaces.ll new file mode 100644 index 0000000000000..46ee1d734baf9 --- /dev/null +++ b/test/Analysis/Lint/address-spaces.ll @@ -0,0 +1,25 @@ +; RUN: opt -lint < %s + +target datalayout = "p32:32:32-p1:16:16:16-n16:32" + +declare void @foo(i64) nounwind + +define i64 @test1(i32 addrspace(1)* %x) nounwind { + %y = ptrtoint i32 addrspace(1)* %x to i64 + ret i64 %y +} + +define <4 x i64> @test1_vector(<4 x i32 addrspace(1)*> %x) nounwind { + %y = ptrtoint <4 x i32 addrspace(1)*> %x to <4 x i64> + ret <4 x i64> %y +} + +define i32 addrspace(1)* @test2(i64 %x) nounwind { + %y = inttoptr i64 %x to i32 addrspace(1)* + ret i32 addrspace(1)* %y +} + +define <4 x i32 addrspace(1)*> @test2_vector(<4 x i64> %x) nounwind { + %y = inttoptr <4 x i64> %x to <4 x i32 addrspace(1)*> + ret <4 x i32 addrspace(1)*> %y +}
\ No newline at end of file diff --git a/test/Analysis/ScalarEvolution/2009-04-22-TruncCast.ll b/test/Analysis/ScalarEvolution/2009-04-22-TruncCast.ll index 3dacfbb0a8d49..a845465a26b51 100644 --- a/test/Analysis/ScalarEvolution/2009-04-22-TruncCast.ll +++ b/test/Analysis/ScalarEvolution/2009-04-22-TruncCast.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -analyze -scalar-evolution | grep "(trunc i" | not grep ext +; RUN: opt < %s -analyze -scalar-evolution | FileCheck %s ; CHECK: Printing analysis 'Scalar Evolution Analysis' for function 'test1' ; CHECK-NOT: (trunc i{{.*}}ext diff --git a/test/Analysis/ScalarEvolution/2012-03-26-LoadConstant.ll b/test/Analysis/ScalarEvolution/2012-03-26-LoadConstant.ll index b88e33f2bb8ad..5746d1c5900c2 100644 --- a/test/Analysis/ScalarEvolution/2012-03-26-LoadConstant.ll +++ b/test/Analysis/ScalarEvolution/2012-03-26-LoadConstant.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -basicaa -globalopt -instcombine -loop-rotate -licm -instcombine -indvars -loop-deletion -constmerge -S +; RUN: opt < %s -basicaa -globalopt -instcombine -loop-rotate -licm -instcombine -indvars -loop-deletion -constmerge -S | FileCheck %s ; PR11882: ComputeLoadConstantCompareExitLimit crash. ; ; for.body is deleted leaving a loop-invariant load. diff --git a/test/Analysis/ScalarEvolution/2012-05-18-LoopPredRecurse.ll b/test/Analysis/ScalarEvolution/2012-05-18-LoopPredRecurse.ll index 52e6683c9f011..66df9d19234fe 100644 --- a/test/Analysis/ScalarEvolution/2012-05-18-LoopPredRecurse.ll +++ b/test/Analysis/ScalarEvolution/2012-05-18-LoopPredRecurse.ll @@ -4,7 +4,7 @@ ; getUDivExpr()->getZeroExtendExpr()->isLoopBackedgeGuardedBy() ; ; We actually want SCEV simplification to fail gracefully in this -; case, so there's no output to check, just the absense of stack overflow. +; case, so there's no output to check, just the absence of stack overflow. @c = common global i8 0, align 1 diff --git a/test/Analysis/ScalarEvolution/and-xor.ll b/test/Analysis/ScalarEvolution/and-xor.ll index 404ab91e269d2..ad636da4d4d79 100644 --- a/test/Analysis/ScalarEvolution/and-xor.ll +++ b/test/Analysis/ScalarEvolution/and-xor.ll @@ -1,11 +1,27 @@ ; RUN: opt < %s -scalar-evolution -analyze | FileCheck %s +; CHECK-LABEL: @test1 ; CHECK: --> (zext ; CHECK: --> (zext ; CHECK-NOT: --> (zext -define i32 @foo(i32 %x) { +define i32 @test1(i32 %x) { %n = and i32 %x, 255 %y = xor i32 %n, 255 ret i32 %y } + +; ScalarEvolution shouldn't try to analyze %z into something like +; --> (zext i4 (-1 + (-1 * (trunc i64 (8 * %x) to i4))) to i64) +; or +; --> (8 * (zext i1 (trunc i64 ((8 * %x) /u 8) to i1) to i64)) + +; CHECK-LABEL: @test2 +; CHECK: --> (8 * (zext i1 (trunc i64 %x to i1) to i64)) + +define i64 @test2(i64 %x) { + %a = shl i64 %x, 3 + %t = and i64 %a, 8 + %z = xor i64 %t, 8 + ret i64 %z +} diff --git a/test/Analysis/ScalarEvolution/fold.ll b/test/Analysis/ScalarEvolution/fold.ll index 57006dd9bb42c..ab5742557b33a 100644 --- a/test/Analysis/ScalarEvolution/fold.ll +++ b/test/Analysis/ScalarEvolution/fold.ll @@ -60,3 +60,29 @@ loop: exit: ret void } + +define void @test5(i32 %i) { +; CHECK-LABEL: @test5 + %A = and i32 %i, 1 +; CHECK: --> (zext i1 (trunc i32 %i to i1) to i32) + %B = and i32 %i, 2 +; CHECK: --> (2 * (zext i1 (trunc i32 (%i /u 2) to i1) to i32)) + %C = and i32 %i, 63 +; CHECK: --> (zext i6 (trunc i32 %i to i6) to i32) + %D = and i32 %i, 126 +; CHECK: --> (2 * (zext i6 (trunc i32 (%i /u 2) to i6) to i32)) + %E = and i32 %i, 64 +; CHECK: --> (64 * (zext i1 (trunc i32 (%i /u 64) to i1) to i32)) + %F = and i32 %i, -2147483648 +; CHECK: --> (-2147483648 * (%i /u -2147483648)) + ret void +} + +define void @test6(i8 %x) { +; CHECK-LABEL: @test6 + %A = zext i8 %x to i16 + %B = shl nuw i16 %A, 8 + %C = and i16 %B, -2048 +; CHECK: --> (2048 * ((zext i8 %x to i16) /u 8)) + ret void +} diff --git a/test/Analysis/ScalarEvolution/max-trip-count.ll b/test/Analysis/ScalarEvolution/max-trip-count.ll index 0cdbdf57a64ca..31f06a46ad00b 100644 --- a/test/Analysis/ScalarEvolution/max-trip-count.ll +++ b/test/Analysis/ScalarEvolution/max-trip-count.ll @@ -98,3 +98,112 @@ for.end: ; preds = %for.cond.for.end_cr ; CHECK: Determining loop execution counts for: @test ; CHECK-NEXT: backedge-taken count is ; CHECK-NEXT: max backedge-taken count is -1 + +; PR19799: Indvars miscompile due to an incorrect max backedge taken count from SCEV. +; CHECK-LABEL: @pr19799 +; CHECK: Loop %for.body.i: <multiple exits> Unpredictable backedge-taken count. +; CHECK: Loop %for.body.i: max backedge-taken count is 1 +@a = common global i32 0, align 4 + +define i32 @pr19799() { +entry: + store i32 -1, i32* @a, align 4 + br label %for.body.i + +for.body.i: ; preds = %for.cond.i, %entry + %storemerge1.i = phi i32 [ -1, %entry ], [ %add.i.i, %for.cond.i ] + %tobool.i = icmp eq i32 %storemerge1.i, 0 + %add.i.i = add nsw i32 %storemerge1.i, 2 + br i1 %tobool.i, label %bar.exit, label %for.cond.i + +for.cond.i: ; preds = %for.body.i + store i32 %add.i.i, i32* @a, align 4 + %cmp.i = icmp slt i32 %storemerge1.i, 0 + br i1 %cmp.i, label %for.body.i, label %bar.exit + +bar.exit: ; preds = %for.cond.i, %for.body.i + ret i32 0 +} + +; PR18886: Indvars miscompile due to an incorrect max backedge taken count from SCEV. +; CHECK-LABEL: @pr18886 +; CHECK: Loop %for.body: <multiple exits> Unpredictable backedge-taken count. +; CHECK: Loop %for.body: max backedge-taken count is 3 +@aa = global i64 0, align 8 + +define i32 @pr18886() { +entry: + store i64 -21, i64* @aa, align 8 + br label %for.body + +for.body: + %storemerge1 = phi i64 [ -21, %entry ], [ %add, %for.cond ] + %tobool = icmp eq i64 %storemerge1, 0 + %add = add nsw i64 %storemerge1, 8 + br i1 %tobool, label %return, label %for.cond + +for.cond: + store i64 %add, i64* @aa, align 8 + %cmp = icmp slt i64 %add, 9 + br i1 %cmp, label %for.body, label %return + +return: + %retval.0 = phi i32 [ 1, %for.body ], [ 0, %for.cond ] + ret i32 %retval.0 +} + +; Here we have a must-exit loop latch that is not computable and a +; may-exit early exit that can only have one non-exiting iteration +; before the check is forever skipped. +; +; CHECK-LABEL: @cannot_compute_mustexit +; CHECK: Loop %for.body.i: <multiple exits> Unpredictable backedge-taken count. +; CHECK: Loop %for.body.i: Unpredictable max backedge-taken count. +@b = common global i32 0, align 4 + +define i32 @cannot_compute_mustexit() { +entry: + store i32 -1, i32* @a, align 4 + br label %for.body.i + +for.body.i: ; preds = %for.cond.i, %entry + %storemerge1.i = phi i32 [ -1, %entry ], [ %add.i.i, %for.cond.i ] + %tobool.i = icmp eq i32 %storemerge1.i, 0 + %add.i.i = add nsw i32 %storemerge1.i, 2 + br i1 %tobool.i, label %bar.exit, label %for.cond.i + +for.cond.i: ; preds = %for.body.i + store i32 %add.i.i, i32* @a, align 4 + %ld = load volatile i32* @b + %cmp.i = icmp ne i32 %ld, 0 + br i1 %cmp.i, label %for.body.i, label %bar.exit + +bar.exit: ; preds = %for.cond.i, %for.body.i + ret i32 0 +} + +; This loop has two must-exits, both of which dominate the latch. The +; MaxBECount should be the minimum of them. +; +; CHECK-LABEL: @two_mustexit +; CHECK: Loop %for.body.i: <multiple exits> Unpredictable backedge-taken count. +; CHECK: Loop %for.body.i: max backedge-taken count is 1 +define i32 @two_mustexit() { +entry: + store i32 -1, i32* @a, align 4 + br label %for.body.i + +for.body.i: ; preds = %for.cond.i, %entry + %storemerge1.i = phi i32 [ -1, %entry ], [ %add.i.i, %for.cond.i ] + %tobool.i = icmp sgt i32 %storemerge1.i, 0 + %add.i.i = add nsw i32 %storemerge1.i, 2 + br i1 %tobool.i, label %bar.exit, label %for.cond.i + +for.cond.i: ; preds = %for.body.i + store i32 %add.i.i, i32* @a, align 4 + %cmp.i = icmp slt i32 %storemerge1.i, 3 + br i1 %cmp.i, label %for.body.i, label %bar.exit + +bar.exit: ; preds = %for.cond.i, %for.body.i + ret i32 0 +} diff --git a/test/Analysis/ScalarEvolution/nsw-offset.ll b/test/Analysis/ScalarEvolution/nsw-offset.ll index 8969a5ad4ceb2..88cdcf23d9ed0 100644 --- a/test/Analysis/ScalarEvolution/nsw-offset.ll +++ b/test/Analysis/ScalarEvolution/nsw-offset.ll @@ -73,5 +73,5 @@ return: ; preds = %bb1.return_crit_edg ret void } -; CHECK: Loop %bb: backedge-taken count is ((-1 + %n) /u 2) +; CHECK: Loop %bb: backedge-taken count is ((-1 + (2 * (%no /u 2))) /u 2) ; CHECK: Loop %bb: max backedge-taken count is 1073741822 diff --git a/test/Analysis/ScalarEvolution/trip-count-pow2.ll b/test/Analysis/ScalarEvolution/trip-count-pow2.ll new file mode 100644 index 0000000000000..2c5b72e49daf4 --- /dev/null +++ b/test/Analysis/ScalarEvolution/trip-count-pow2.ll @@ -0,0 +1,53 @@ +; RUN: opt < %s -scalar-evolution -analyze | FileCheck %s + +define void @test1(i32 %n) { +entry: + %s = mul i32 %n, 96 + br label %loop +loop: + %i = phi i32 [ 0, %entry ], [ %i.next, %loop ] + %i.next = add i32 %i, 32 + %t = icmp ne i32 %i.next, %s + br i1 %t, label %loop, label %exit +exit: + ret void + +; CHECK-LABEL: @test1 +; CHECK: Loop %loop: backedge-taken count is ((-32 + (96 * %n)) /u 32) +; CHECK: Loop %loop: max backedge-taken count is ((-32 + (96 * %n)) /u 32) +} + +; PR19183 +define i32 @test2(i32 %n) { +entry: + %s = and i32 %n, -32 + br label %loop +loop: + %i = phi i32 [ 0, %entry ], [ %i.next, %loop ] + %i.next = add i32 %i, 32 + %t = icmp ne i32 %i.next, %s + br i1 %t, label %loop, label %exit +exit: + ret i32 %i + +; CHECK-LABEL: @test2 +; CHECK: Loop %loop: backedge-taken count is ((-32 + (32 * (%n /u 32))) /u 32) +; CHECK: Loop %loop: max backedge-taken count is ((-32 + (32 * (%n /u 32))) /u 32) +} + +define void @test3(i32 %n) { +entry: + %s = mul i32 %n, 96 + br label %loop +loop: + %i = phi i32 [ 0, %entry ], [ %i.next, %loop ] + %i.next = add i32 %i, 96 + %t = icmp ne i32 %i.next, %s + br i1 %t, label %loop, label %exit +exit: + ret void + +; CHECK-LABEL: @test3 +; CHECK: Loop %loop: Unpredictable backedge-taken count. +; CHECK: Loop %loop: Unpredictable max backedge-taken count. +} diff --git a/test/Analysis/ScalarEvolution/trip-count-switch.ll b/test/Analysis/ScalarEvolution/trip-count-switch.ll new file mode 100644 index 0000000000000..2d2b6b4994089 --- /dev/null +++ b/test/Analysis/ScalarEvolution/trip-count-switch.ll @@ -0,0 +1,30 @@ +; RUN: opt < %s -analyze -scalar-evolution | FileCheck %s + +declare void @foo() + +define void @test1() nounwind { +entry: + br label %for.cond + +for.cond: ; preds = %if.end, %entry + %i.0 = phi i32 [ 2, %entry ], [ %dec, %if.end ] + switch i32 %i.0, label %if.end [ + i32 0, label %for.end + i32 1, label %if.then + ] + +if.then: ; preds = %for.cond + tail call void @foo() + br label %if.end + +if.end: ; preds = %for.cond, %if.then + %dec = add nsw i32 %i.0, -1 + br label %for.cond + +for.end: ; preds = %for.cond + ret void + +; CHECK-LABEL: @test1 +; CHECK: Loop %for.cond: backedge-taken count is 2 +; CHECK: Loop %for.cond: max backedge-taken count is 2 +} diff --git a/test/Analysis/ScalarEvolution/xor-and.ll b/test/Analysis/ScalarEvolution/xor-and.ll deleted file mode 100644 index 2616ea928a494..0000000000000 --- a/test/Analysis/ScalarEvolution/xor-and.ll +++ /dev/null @@ -1,13 +0,0 @@ -; RUN: opt < %s -scalar-evolution -analyze | FileCheck %s - -; ScalarEvolution shouldn't try to analyze %z into something like -; --> (zext i4 (-1 + (-1 * (trunc i64 (8 * %x) to i4))) to i64) - -; CHECK: --> (zext i4 (-8 + (trunc i64 (8 * %x) to i4)) to i64) - -define i64 @foo(i64 %x) { - %a = shl i64 %x, 3 - %t = and i64 %a, 8 - %z = xor i64 %t, 8 - ret i64 %z -} diff --git a/test/Analysis/TypeBasedAliasAnalysis/memcpyopt.ll b/test/Analysis/TypeBasedAliasAnalysis/memcpyopt.ll index 6fd6eaca012e9..cdf72811ce5f6 100644 --- a/test/Analysis/TypeBasedAliasAnalysis/memcpyopt.ll +++ b/test/Analysis/TypeBasedAliasAnalysis/memcpyopt.ll @@ -18,8 +18,8 @@ define void @foo(i8* nocapture %p, i8* nocapture %q, i8* nocapture %s) nounwind declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) nounwind -; CHECK [[TAGA]] = metadata !{metadata [[TYPEA:!.*]], metadata [[TYPEA]], i64 0} -; CHECK [[TYPEA]] = metadata !{metadata !"A", metadata !{{.*}}} +; CHECK: [[TAGA]] = metadata !{metadata [[TYPEA:!.*]], metadata [[TYPEA]], i64 0} +; CHECK: [[TYPEA]] = metadata !{metadata !"A", metadata !{{.*}}} !0 = metadata !{metadata !"tbaa root", null} !1 = metadata !{metadata !3, metadata !3, i64 0} !2 = metadata !{metadata !4, metadata !4, i64 0} diff --git a/test/Analysis/TypeBasedAliasAnalysis/tbaa-path.ll b/test/Analysis/TypeBasedAliasAnalysis/tbaa-path.ll index 0cd5c301842a0..e1c5d4526470b 100644 --- a/test/Analysis/TypeBasedAliasAnalysis/tbaa-path.ll +++ b/test/Analysis/TypeBasedAliasAnalysis/tbaa-path.ll @@ -43,7 +43,7 @@ entry: ; OPT: define ; OPT: store i32 1 ; OPT: store i16 4 -; Remove a load and propogate the value from store. +; Remove a load and propagate the value from store. ; OPT: ret i32 1 %s.addr = alloca i32*, align 8 %A.addr = alloca %struct.StructA*, align 8 @@ -98,7 +98,7 @@ entry: ; OPT: define ; OPT: store i32 1 ; OPT: store i16 4 -; Remove a load and propogate the value from store. +; Remove a load and propagate the value from store. ; OPT: ret i32 1 %A.addr = alloca %struct.StructA*, align 8 %B.addr = alloca %struct.StructB*, align 8 @@ -127,7 +127,7 @@ entry: ; OPT: define ; OPT: store i32 1 ; OPT: store i32 4 -; Remove a load and propogate the value from store. +; Remove a load and propagate the value from store. ; OPT: ret i32 1 %A.addr = alloca %struct.StructA*, align 8 %B.addr = alloca %struct.StructB*, align 8 @@ -155,7 +155,7 @@ entry: ; OPT: define ; OPT: store i32 1 ; OPT: store i32 4 -; Remove a load and propogate the value from store. +; Remove a load and propagate the value from store. ; OPT: ret i32 1 %A.addr = alloca %struct.StructA*, align 8 %B.addr = alloca %struct.StructB*, align 8 @@ -184,7 +184,7 @@ entry: ; OPT: define ; OPT: store i32 1 ; OPT: store i32 4 -; Remove a load and propogate the value from store. +; Remove a load and propagate the value from store. ; OPT: ret i32 1 %A.addr = alloca %struct.StructA*, align 8 %S.addr = alloca %struct.StructS*, align 8 @@ -212,7 +212,7 @@ entry: ; OPT: define ; OPT: store i32 1 ; OPT: store i16 4 -; Remove a load and propogate the value from store. +; Remove a load and propagate the value from store. ; OPT: ret i32 1 %A.addr = alloca %struct.StructA*, align 8 %S.addr = alloca %struct.StructS*, align 8 @@ -240,7 +240,7 @@ entry: ; OPT: define ; OPT: store i32 1 ; OPT: store i32 4 -; Remove a load and propogate the value from store. +; Remove a load and propagate the value from store. ; OPT: ret i32 1 %S.addr = alloca %struct.StructS*, align 8 %S2.addr = alloca %struct.StructS2*, align 8 @@ -268,7 +268,7 @@ entry: ; OPT: define ; OPT: store i32 1 ; OPT: store i16 4 -; Remove a load and propogate the value from store. +; Remove a load and propagate the value from store. ; OPT: ret i32 1 %S.addr = alloca %struct.StructS*, align 8 %S2.addr = alloca %struct.StructS2*, align 8 @@ -296,7 +296,7 @@ entry: ; OPT: define ; OPT: store i32 1 ; OPT: store i32 4 -; Remove a load and propogate the value from store. +; Remove a load and propagate the value from store. ; OPT: ret i32 1 %C.addr = alloca %struct.StructC*, align 8 %D.addr = alloca %struct.StructD*, align 8 |
