diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:41:05 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:41:05 +0000 |
| commit | 01095a5d43bbfde13731688ddcf6048ebb8b7721 (patch) | |
| tree | 4def12e759965de927d963ac65840d663ef9d1ea /test/Transforms/Util | |
| parent | f0f4822ed4b66e3579e92a89f368f8fb860e218e (diff) | |
Vendor import of llvm release_39 branch r276489:vendor/llvm/llvm-release_39-r276489
Diffstat (limited to 'test/Transforms/Util')
20 files changed, 976 insertions, 6 deletions
diff --git a/test/Transforms/Util/MemorySSA/assume.ll b/test/Transforms/Util/MemorySSA/assume.ll new file mode 100644 index 000000000000..d771c78eb1cf --- /dev/null +++ b/test/Transforms/Util/MemorySSA/assume.ll @@ -0,0 +1,19 @@ +; RUN: opt -basicaa -memoryssa -analyze < %s 2>&1 | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='print<memoryssa>,verify<memoryssa>' -disable-output < %s 2>&1 | FileCheck %s +; +; Ensures that assumes are treated as not reading or writing memory. + +declare void @llvm.assume(i1) + +define i32 @foo(i32* %a, i32* %b, i1 %c) { +; CHECK: 1 = MemoryDef(liveOnEntry) +; CHECK-NEXT: store i32 4 + store i32 4, i32* %a, align 4 +; CHECK-NOT: MemoryDef +; CHECK: call void @llvm.assume + call void @llvm.assume(i1 %c) +; CHECK: MemoryUse(1) +; CHECK-NEXT: %1 = load i32 + %1 = load i32, i32* %a, align 4 + ret i32 %1 +} diff --git a/test/Transforms/Util/MemorySSA/atomic-clobber.ll b/test/Transforms/Util/MemorySSA/atomic-clobber.ll new file mode 100644 index 000000000000..217d5f65d787 --- /dev/null +++ b/test/Transforms/Util/MemorySSA/atomic-clobber.ll @@ -0,0 +1,18 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %s 2>&1 | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='print<memoryssa>,verify<memoryssa>' -disable-output < %s 2>&1 | FileCheck %s +; +; Ensures that atomic loads count as MemoryDefs + +define i32 @foo(i32* %a, i32* %b) { +; CHECK: 1 = MemoryDef(liveOnEntry) +; CHECK-NEXT: store i32 4 + store i32 4, i32* %a, align 4 +; CHECK: 2 = MemoryDef(1) +; CHECK-NEXT: %1 = load atomic i32 + %1 = load atomic i32, i32* %b acquire, align 4 +; CHECK: MemoryUse(2) +; CHECK-NEXT: %2 = load i32 + %2 = load i32, i32* %a, align 4 + %3 = add i32 %1, %2 + ret i32 %3 +} diff --git a/test/Transforms/Util/MemorySSA/cyclicphi.ll b/test/Transforms/Util/MemorySSA/cyclicphi.ll new file mode 100644 index 000000000000..c9a5422e0a18 --- /dev/null +++ b/test/Transforms/Util/MemorySSA/cyclicphi.ll @@ -0,0 +1,124 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %s 2>&1 | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='print<memoryssa>,verify<memoryssa>' -disable-output < %s 2>&1 | FileCheck %s + +%struct.hoge = type { i32, %struct.widget } +%struct.widget = type { i64 } + +define hidden void @quux(%struct.hoge *%f) align 2 { + %tmp = getelementptr inbounds %struct.hoge, %struct.hoge* %f, i64 0, i32 1, i32 0 + %tmp24 = getelementptr inbounds %struct.hoge, %struct.hoge* %f, i64 0, i32 1 + %tmp25 = bitcast %struct.widget* %tmp24 to i64** + br label %bb26 + +bb26: ; preds = %bb77, %0 +; CHECK: 3 = MemoryPhi({%0,liveOnEntry},{bb77,2}) +; CHECK-NEXT: br i1 undef, label %bb68, label %bb77 + br i1 undef, label %bb68, label %bb77 + +bb68: ; preds = %bb26 +; CHECK: MemoryUse(liveOnEntry) +; CHECK-NEXT: %tmp69 = load i64, i64* null, align 8 + %tmp69 = load i64, i64* null, align 8 +; CHECK: 1 = MemoryDef(3) +; CHECK-NEXT: store i64 %tmp69, i64* %tmp, align 8 + store i64 %tmp69, i64* %tmp, align 8 + br label %bb77 + +bb77: ; preds = %bb68, %bb26 +; CHECK: 2 = MemoryPhi({bb26,3},{bb68,1}) +; CHECK: MemoryUse(2) +; CHECK-NEXT: %tmp78 = load i64*, i64** %tmp25, align 8 + %tmp78 = load i64*, i64** %tmp25, align 8 + %tmp79 = getelementptr inbounds i64, i64* %tmp78, i64 undef + br label %bb26 +} + +; CHECK-LABEL: define void @quux_skip +define void @quux_skip(%struct.hoge* noalias %f, i64* noalias %g) align 2 { + %tmp = getelementptr inbounds %struct.hoge, %struct.hoge* %f, i64 0, i32 1, i32 0 + %tmp24 = getelementptr inbounds %struct.hoge, %struct.hoge* %f, i64 0, i32 1 + %tmp25 = bitcast %struct.widget* %tmp24 to i64** + br label %bb26 + +bb26: ; preds = %bb77, %0 +; CHECK: 3 = MemoryPhi({%0,liveOnEntry},{bb77,2}) +; CHECK-NEXT: br i1 undef, label %bb68, label %bb77 + br i1 undef, label %bb68, label %bb77 + +bb68: ; preds = %bb26 +; CHECK: MemoryUse(3) +; CHECK-NEXT: %tmp69 = load i64, i64* %g, align 8 + %tmp69 = load i64, i64* %g, align 8 +; CHECK: 1 = MemoryDef(3) +; CHECK-NEXT: store i64 %tmp69, i64* %g, align 8 + store i64 %tmp69, i64* %g, align 8 + br label %bb77 + +bb77: ; preds = %bb68, %bb26 +; CHECK: 2 = MemoryPhi({bb26,3},{bb68,1}) +; FIXME: This should be MemoryUse(liveOnEntry) +; CHECK: MemoryUse(3) +; CHECK-NEXT: %tmp78 = load i64*, i64** %tmp25, align 8 + %tmp78 = load i64*, i64** %tmp25, align 8 + br label %bb26 +} + +; CHECK-LABEL: define void @quux_dominated +define void @quux_dominated(%struct.hoge* noalias %f, i64* noalias %g) align 2 { + %tmp = getelementptr inbounds %struct.hoge, %struct.hoge* %f, i64 0, i32 1, i32 0 + %tmp24 = getelementptr inbounds %struct.hoge, %struct.hoge* %f, i64 0, i32 1 + %tmp25 = bitcast %struct.widget* %tmp24 to i64** + br label %bb26 + +bb26: ; preds = %bb77, %0 +; CHECK: 4 = MemoryPhi({%0,liveOnEntry},{bb77,2}) +; CHECK: MemoryUse(4) +; CHECK-NEXT: load i64*, i64** %tmp25, align 8 + load i64*, i64** %tmp25, align 8 + br i1 undef, label %bb68, label %bb77 + +bb68: ; preds = %bb26 +; CHECK: MemoryUse(4) +; CHECK-NEXT: %tmp69 = load i64, i64* %g, align 8 + %tmp69 = load i64, i64* %g, align 8 +; CHECK: 1 = MemoryDef(4) +; CHECK-NEXT: store i64 %tmp69, i64* %g, align 8 + store i64 %tmp69, i64* %g, align 8 + br label %bb77 + +bb77: ; preds = %bb68, %bb26 +; CHECK: 3 = MemoryPhi({bb26,4},{bb68,1}) +; CHECK: 2 = MemoryDef(3) +; CHECK-NEXT: store i64* null, i64** %tmp25, align 8 + store i64* null, i64** %tmp25, align 8 + br label %bb26 +} + +; CHECK-LABEL: define void @quux_nodominate +define void @quux_nodominate(%struct.hoge* noalias %f, i64* noalias %g) align 2 { + %tmp = getelementptr inbounds %struct.hoge, %struct.hoge* %f, i64 0, i32 1, i32 0 + %tmp24 = getelementptr inbounds %struct.hoge, %struct.hoge* %f, i64 0, i32 1 + %tmp25 = bitcast %struct.widget* %tmp24 to i64** + br label %bb26 + +bb26: ; preds = %bb77, %0 +; CHECK: 3 = MemoryPhi({%0,liveOnEntry},{bb77,2}) +; CHECK: MemoryUse(liveOnEntry) +; CHECK-NEXT: load i64*, i64** %tmp25, align 8 + load i64*, i64** %tmp25, align 8 + br i1 undef, label %bb68, label %bb77 + +bb68: ; preds = %bb26 +; CHECK: MemoryUse(3) +; CHECK-NEXT: %tmp69 = load i64, i64* %g, align 8 + %tmp69 = load i64, i64* %g, align 8 +; CHECK: 1 = MemoryDef(3) +; CHECK-NEXT: store i64 %tmp69, i64* %g, align 8 + store i64 %tmp69, i64* %g, align 8 + br label %bb77 + +bb77: ; preds = %bb68, %bb26 +; CHECK: 2 = MemoryPhi({bb26,3},{bb68,1}) +; CHECK-NEXT: br label %bb26 + br label %bb26 +} diff --git a/test/Transforms/Util/MemorySSA/forward-unreachable.ll b/test/Transforms/Util/MemorySSA/forward-unreachable.ll new file mode 100644 index 000000000000..2bbf399daae4 --- /dev/null +++ b/test/Transforms/Util/MemorySSA/forward-unreachable.ll @@ -0,0 +1,23 @@ +; RUN: opt -aa-pipeline=basic-aa -passes='print<memoryssa>,verify<memoryssa>' -disable-output < %s 2>&1 | FileCheck %s +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" + +define void @test() { +entry: + br i1 undef, label %split1, label %split2 + +split1: + store i16 undef, i16* undef, align 2 + br label %merge +split2: + br label %merge +forwardunreachable: + br label %merge +merge: +; The forwardunreachable block still needs an entry in the phi node, +; because it is reverse reachable, so the CFG still has it as a +; predecessor of the block +; CHECK: 3 = MemoryPhi({split1,1},{split2,liveOnEntry},{forwardunreachable,liveOnEntry}) + store i16 undef, i16* undef, align 2 + ret void +} + diff --git a/test/Transforms/Util/MemorySSA/function-clobber.ll b/test/Transforms/Util/MemorySSA/function-clobber.ll new file mode 100644 index 000000000000..a01893a5b954 --- /dev/null +++ b/test/Transforms/Util/MemorySSA/function-clobber.ll @@ -0,0 +1,54 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %s 2>&1 | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='print<memoryssa>,verify<memoryssa>' -disable-output < %s 2>&1 | FileCheck %s +; +; Ensuring that external functions without attributes are MemoryDefs + +@g = external global i32 +declare void @modifyG() + +define i32 @foo() { +; CHECK: MemoryUse(liveOnEntry) +; CHECK-NEXT: %1 = load i32 + %1 = load i32, i32* @g + +; CHECK: 1 = MemoryDef(liveOnEntry) +; CHECK-NEXT: store i32 4 + store i32 4, i32* @g, align 4 + +; CHECK: 2 = MemoryDef(1) +; CHECK-NEXT: call void @modifyG() + call void @modifyG() + +; CHECK: MemoryUse(2) +; CHECK-NEXT: %2 = load i32 + %2 = load i32, i32* @g + %3 = add i32 %2, %1 + ret i32 %3 +} + +declare void @readEverything() readonly +declare void @clobberEverything() + +; CHECK-LABEL: define void @bar +define void @bar() { +; CHECK: 1 = MemoryDef(liveOnEntry) +; CHECK-NEXT: call void @clobberEverything() + call void @clobberEverything() + br i1 undef, label %if.end, label %if.then + +if.then: +; CHECK: MemoryUse(1) +; CHECK-NEXT: call void @readEverything() + call void @readEverything() +; CHECK: 2 = MemoryDef(1) +; CHECK-NEXT: call void @clobberEverything() + call void @clobberEverything() + br label %if.end + +if.end: +; CHECK: 3 = MemoryPhi({%0,1},{if.then,2}) +; CHECK: MemoryUse(3) +; CHECK-NEXT: call void @readEverything() + call void @readEverything() + ret void +} diff --git a/test/Transforms/Util/MemorySSA/function-mem-attrs.ll b/test/Transforms/Util/MemorySSA/function-mem-attrs.ll new file mode 100644 index 000000000000..11383771a413 --- /dev/null +++ b/test/Transforms/Util/MemorySSA/function-mem-attrs.ll @@ -0,0 +1,59 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %s 2>&1 | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='print<memoryssa>,verify<memoryssa>' -disable-output < %s 2>&1 | FileCheck %s +; +; Test that various function attributes give us sane results. + +@g = external global i32 + +declare void @readonlyFunction() readonly +declare void @noattrsFunction() + +define void @readonlyAttr() { +; CHECK: 1 = MemoryDef(liveOnEntry) +; CHECK-NEXT: store i32 0 + store i32 0, i32* @g, align 4 + + %1 = alloca i32, align 4 +; CHECK: 2 = MemoryDef(1) +; CHECK-NEXT: store i32 0 + store i32 0, i32* %1, align 4 + +; CHECK: MemoryUse(1) +; CHECK-NEXT: call void @readonlyFunction() + call void @readonlyFunction() + +; CHECK: MemoryUse(1) +; CHECK-NEXT: call void @noattrsFunction() # +; Assume that #N is readonly + call void @noattrsFunction() readonly + + ; Sanity check that noattrsFunction is otherwise a MemoryDef +; CHECK: 3 = MemoryDef(2) +; CHECK-NEXT: call void @noattrsFunction() + call void @noattrsFunction() + ret void +} + +declare void @argMemOnly(i32*) argmemonly + +define void @inaccessableOnlyAttr() { + %1 = alloca i32, align 4 +; CHECK: 1 = MemoryDef(liveOnEntry) +; CHECK-NEXT: store i32 0 + store i32 0, i32* %1, align 4 + +; CHECK: 2 = MemoryDef(1) +; CHECK-NEXT: store i32 0 + store i32 0, i32* @g, align 4 + +; CHECK: MemoryUse(1) +; CHECK-NEXT: call void @argMemOnly(i32* %1) # +; Assume that #N is readonly + call void @argMemOnly(i32* %1) readonly + +; CHECK: 3 = MemoryDef(2) +; CHECK-NEXT: call void @argMemOnly(i32* %1) + call void @argMemOnly(i32* %1) + + ret void +} diff --git a/test/Transforms/Util/MemorySSA/livein.ll b/test/Transforms/Util/MemorySSA/livein.ll new file mode 100644 index 000000000000..93072ea97daf --- /dev/null +++ b/test/Transforms/Util/MemorySSA/livein.ll @@ -0,0 +1,53 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %s 2>&1 | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='print<memoryssa>,verify<memoryssa>' -disable-output < %s 2>&1 | FileCheck %s +define void @F(i8*) { + br i1 true, label %left, label %right +left: +; CHECK: 1 = MemoryDef(liveOnEntry) + store i8 16, i8* %0 + br label %merge +right: + br label %merge + +merge: +; CHECK-NOT: 2 = MemoryPhi +ret void +} + +define void @F2(i8*) { + br i1 true, label %left, label %right +left: +; CHECK: 1 = MemoryDef(liveOnEntry) + store i8 16, i8* %0 + br label %merge +right: + br label %merge + +merge: +; CHECK: 2 = MemoryPhi({left,1},{right,liveOnEntry}) +%c = load i8, i8* %0 +ret void +} + +; Ensure we treat def-only blocks as though they have uses for phi placement. +; CHECK-LABEL: define void @F3 +define void @F3() { + %a = alloca i8 +; CHECK: 1 = MemoryDef(liveOnEntry) +; CHECK-NEXT: store i8 0, i8* %a + store i8 0, i8* %a + br i1 undef, label %if.then, label %if.end + +if.then: +; CHECK: 2 = MemoryDef(1) +; CHECK-NEXT: store i8 1, i8* %a + store i8 1, i8* %a + br label %if.end + +if.end: +; CHECK: 4 = MemoryPhi({%0,1},{if.then,2}) +; CHECK: 3 = MemoryDef(4) +; CHECK-NEXT: store i8 2, i8* %a + store i8 2, i8* %a + ret void +} diff --git a/test/Transforms/Util/MemorySSA/load-invariant.ll b/test/Transforms/Util/MemorySSA/load-invariant.ll new file mode 100644 index 000000000000..e387ff4c5302 --- /dev/null +++ b/test/Transforms/Util/MemorySSA/load-invariant.ll @@ -0,0 +1,25 @@ +; XFAIL: * +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %s 2>&1 | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='print<memoryssa>' -verify-memoryssa -disable-output < %s 2>&1 | FileCheck %s +; +; Invariant loads should be considered live on entry, because, once the +; location is known to be dereferenceable, the value can never change. +; +; Currently XFAILed because this optimization was held back from the initial +; commit. + +@g = external global i32 + +declare void @clobberAllTheThings() + +define i32 @foo() { +; CHECK: 1 = MemoryDef(liveOnEntry) +; CHECK-NEXT: call void @clobberAllTheThings() + call void @clobberAllTheThings() +; CHECK: MemoryUse(liveOnEntry) +; CHECK-NEXT: %1 = load i32 + %1 = load i32, i32* @g, align 4, !invariant.load !0 + ret i32 %1 +} + +!0 = !{} diff --git a/test/Transforms/Util/MemorySSA/many-dom-backedge.ll b/test/Transforms/Util/MemorySSA/many-dom-backedge.ll new file mode 100644 index 000000000000..3d76f4af2d61 --- /dev/null +++ b/test/Transforms/Util/MemorySSA/many-dom-backedge.ll @@ -0,0 +1,77 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %s 2>&1 | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='print<memoryssa>,verify<memoryssa>' -disable-output < %s 2>&1 | FileCheck %s +; +; many-dom.ll, with an added back-edge back into the switch. +; Because people love their gotos. + +declare i1 @getBool() readnone + +define i32 @foo(i32* %p) { +entry: + br label %loopbegin + +loopbegin: +; CHECK: 9 = MemoryPhi({entry,liveOnEntry},{sw.epilog,6}) +; CHECK-NEXT: %n = + %n = phi i32 [ 0, %entry ], [ %1, %sw.epilog ] + %m = alloca i32, align 4 + switch i32 %n, label %sw.default [ + i32 0, label %sw.bb + i32 1, label %sw.bb1 + i32 2, label %sw.bb2 + i32 3, label %sw.bb3 + ] + +sw.bb: +; CHECK: 1 = MemoryDef(9) +; CHECK-NEXT: store i32 1 + store i32 1, i32* %m, align 4 + br label %sw.epilog + +sw.bb1: +; CHECK: 2 = MemoryDef(9) +; CHECK-NEXT: store i32 2 + store i32 2, i32* %m, align 4 + br label %sw.epilog + +sw.bb2: +; CHECK: 3 = MemoryDef(9) +; CHECK-NEXT: store i32 3 + store i32 3, i32* %m, align 4 + br label %sw.epilog + +sw.bb3: +; CHECK: 10 = MemoryPhi({loopbegin,9},{sw.almostexit,6}) +; CHECK: 4 = MemoryDef(10) +; CHECK-NEXT: store i32 4 + store i32 4, i32* %m, align 4 + br label %sw.epilog + +sw.default: +; CHECK: 5 = MemoryDef(9) +; CHECK-NEXT: store i32 5 + store i32 5, i32* %m, align 4 + br label %sw.epilog + +sw.epilog: +; CHECK: 8 = MemoryPhi({sw.default,5},{sw.bb3,4},{sw.bb,1},{sw.bb1,2},{sw.bb2,3}) +; CHECK-NEXT: MemoryUse(8) +; CHECK-NEXT: %0 = + %0 = load i32, i32* %m, align 4 +; CHECK: 6 = MemoryDef(8) +; CHECK-NEXT: %1 = + %1 = load volatile i32, i32* %p, align 4 + %2 = icmp eq i32 %0, %1 + br i1 %2, label %sw.almostexit, label %loopbegin + +sw.almostexit: + %3 = icmp eq i32 0, %1 + br i1 %3, label %exit, label %sw.bb3 + +exit: +; CHECK: 7 = MemoryDef(6) +; CHECK-NEXT: %4 = load volatile i32 + %4 = load volatile i32, i32* %p, align 4 + %5 = add i32 %4, %1 + ret i32 %5 +} diff --git a/test/Transforms/Util/MemorySSA/many-doms.ll b/test/Transforms/Util/MemorySSA/many-doms.ll new file mode 100644 index 000000000000..d2e6c6fa1e43 --- /dev/null +++ b/test/Transforms/Util/MemorySSA/many-doms.ll @@ -0,0 +1,67 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %s 2>&1 | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='print<memoryssa>,verify<memoryssa>' -disable-output < %s 2>&1 | FileCheck %s +; +; Testing many dominators, specifically from a switch statement in C. + +declare i1 @getBool() readnone + +define i32 @foo(i32* %p) { +entry: + br label %loopbegin + +loopbegin: +; CHECK: 8 = MemoryPhi({entry,liveOnEntry},{sw.epilog,6}) +; CHECK-NEXT: %n = + %n = phi i32 [ 0, %entry ], [ %1, %sw.epilog ] + %m = alloca i32, align 4 + switch i32 %n, label %sw.default [ + i32 0, label %sw.bb + i32 1, label %sw.bb1 + i32 2, label %sw.bb2 + i32 3, label %sw.bb3 + ] + +sw.bb: +; CHECK: 1 = MemoryDef(8) +; CHECK-NEXT: store i32 1 + store i32 1, i32* %m, align 4 + br label %sw.epilog + +sw.bb1: +; CHECK: 2 = MemoryDef(8) +; CHECK-NEXT: store i32 2 + store i32 2, i32* %m, align 4 + br label %sw.epilog + +sw.bb2: +; CHECK: 3 = MemoryDef(8) +; CHECK-NEXT: store i32 3 + store i32 3, i32* %m, align 4 + br label %sw.epilog + +sw.bb3: +; CHECK: 4 = MemoryDef(8) +; CHECK-NEXT: store i32 4 + store i32 4, i32* %m, align 4 + br label %sw.epilog + +sw.default: +; CHECK: 5 = MemoryDef(8) +; CHECK-NEXT: store i32 5 + store i32 5, i32* %m, align 4 + br label %sw.epilog + +sw.epilog: +; CHECK: 7 = MemoryPhi({sw.default,5},{sw.bb,1},{sw.bb1,2},{sw.bb2,3},{sw.bb3,4}) +; CHECK-NEXT: MemoryUse(7) +; CHECK-NEXT: %0 = + %0 = load i32, i32* %m, align 4 +; CHECK: 6 = MemoryDef(7) +; CHECK-NEXT: %1 = + %1 = load volatile i32, i32* %p, align 4 + %2 = icmp eq i32 %0, %1 + br i1 %2, label %exit, label %loopbegin + +exit: + ret i32 %1 +} diff --git a/test/Transforms/Util/MemorySSA/multi-edges.ll b/test/Transforms/Util/MemorySSA/multi-edges.ll new file mode 100644 index 000000000000..c13fc016b2c7 --- /dev/null +++ b/test/Transforms/Util/MemorySSA/multi-edges.ll @@ -0,0 +1,32 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %s 2>&1 | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='print<memoryssa>,verify<memoryssa>' -disable-output < %s 2>&1 | FileCheck %s +; +; Makes sure we have a sane model if both successors of some block is the same +; block. + +define i32 @foo(i1 %a) { +entry: + %0 = alloca i32, align 4 +; CHECK: 1 = MemoryDef(liveOnEntry) +; CHECK-NEXT: store i32 4 + store i32 4, i32* %0 + br i1 %a, label %Loop.Body, label %Loop.End + +Loop.Body: +; CHECK: 4 = MemoryPhi({entry,1},{Loop.End,3}) +; CHECK-NEXT: 2 = MemoryDef(4) +; CHECK-NEXT: store i32 5 + store i32 5, i32* %0, align 4 + br i1 %a, label %Loop.End, label %Loop.End ; WhyDoWeEvenHaveThatLever.gif + +Loop.End: +; CHECK: 3 = MemoryPhi({entry,1},{Loop.Body,2},{Loop.Body,2}) +; CHECK-NEXT: MemoryUse(3) +; CHECK-NEXT: %1 = load + %1 = load i32, i32* %0, align 4 + %2 = icmp eq i32 5, %1 + br i1 %2, label %Ret, label %Loop.Body + +Ret: + ret i32 %1 +} diff --git a/test/Transforms/Util/MemorySSA/multiple-backedges-hal.ll b/test/Transforms/Util/MemorySSA/multiple-backedges-hal.ll new file mode 100644 index 000000000000..473b3685801c --- /dev/null +++ b/test/Transforms/Util/MemorySSA/multiple-backedges-hal.ll @@ -0,0 +1,73 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %s 2>&1 | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='print<memoryssa>,verify<memoryssa>' -disable-output < %s 2>&1 | FileCheck %s + +; hfinkel's case +; [entry] +; | +; ..... +; (clobbering access - b) +; | +; .... ________________________________ +; \ / | +; (x) | +; ...... | +; | | +; | ______________________ | +; \ / | | +; (starting access) | | +; ... | | +; (clobbering access - a) | | +; ... | | +; | | | | +; | |_______________________| | +; | | +; |_________________________________| +; +; More specifically, one access, with multiple clobbering accesses. One of +; which strictly dominates the access, the other of which has a backedge + +; readnone so we don't have a 1:1 mapping of MemorySSA edges to Instructions. +declare void @doThingWithoutReading() readnone +declare i8 @getValue() readnone +declare i1 @getBool() readnone + +define hidden void @testcase(i8* %Arg) { +Entry: + call void @doThingWithoutReading() + %Val.Entry = call i8 @getValue() +; CHECK: 1 = MemoryDef(liveOnEntry) +; CHECK-NEXT: store i8 %Val.Entry + store i8 %Val.Entry, i8* %Arg + call void @doThingWithoutReading() + br label %OuterLoop + +OuterLoop: +; CHECK: 5 = MemoryPhi({Entry,1},{InnerLoop.Tail,3}) +; CHECK-NEXT: %Val.Outer = + %Val.Outer = call i8 @getValue() +; CHECK: 2 = MemoryDef(5) +; CHECK-NEXT: store i8 %Val.Outer + store i8 %Val.Outer, i8* %Arg + call void @doThingWithoutReading() + br label %InnerLoop + +InnerLoop: +; CHECK: 4 = MemoryPhi({OuterLoop,2},{InnerLoop,3}) +; CHECK-NEXT: ; MemoryUse(4) +; CHECK-NEXT: %StartingAccess = load + %StartingAccess = load i8, i8* %Arg, align 4 + %Val.Inner = call i8 @getValue() +; CHECK: 3 = MemoryDef(4) +; CHECK-NEXT: store i8 %Val.Inner + store i8 %Val.Inner, i8* %Arg + call void @doThingWithoutReading() + %KeepGoing = call i1 @getBool() + br i1 %KeepGoing, label %InnerLoop.Tail, label %InnerLoop + +InnerLoop.Tail: + %KeepGoing.Tail = call i1 @getBool() + br i1 %KeepGoing.Tail, label %End, label %OuterLoop + +End: + ret void +} diff --git a/test/Transforms/Util/MemorySSA/multiple-locations.ll b/test/Transforms/Util/MemorySSA/multiple-locations.ll new file mode 100644 index 000000000000..9a3e87e4ab6d --- /dev/null +++ b/test/Transforms/Util/MemorySSA/multiple-locations.ll @@ -0,0 +1,25 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %s 2>&1 | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='print<memoryssa>,verify<memoryssa>' -disable-output < %s 2>&1 | FileCheck %s +; +; Checks that basicAA is doing some amount of disambiguation for us + +define i32 @foo(i1 %cond) { + %a = alloca i32, align 4 + %b = alloca i32, align 4 +; CHECK: 1 = MemoryDef(liveOnEntry) +; CHECK-NEXT: store i32 0 + store i32 0, i32* %a, align 4 +; CHECK: 2 = MemoryDef(1) +; CHECK-NEXT: store i32 1 + store i32 1, i32* %b, align 4 + +; CHECK: MemoryUse(1) +; CHECK-NEXT: %1 = load i32 + %1 = load i32, i32* %a, align 4 +; CHECK: MemoryUse(2) +; CHECK-NEXT: %2 = load i32 + %2 = load i32, i32* %b, align 4 + + %3 = add i32 %1, %2 + ret i32 %3 +} diff --git a/test/Transforms/Util/MemorySSA/no-disconnected.ll b/test/Transforms/Util/MemorySSA/no-disconnected.ll new file mode 100644 index 000000000000..d1dcb15893ad --- /dev/null +++ b/test/Transforms/Util/MemorySSA/no-disconnected.ll @@ -0,0 +1,43 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %s 2>&1 | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='print<memoryssa>,verify<memoryssa>' -disable-output < %s 2>&1 | FileCheck %s +; +; This test ensures we don't end up with multiple reaching defs for a single +; use/phi edge If we were to optimize defs, we would end up with 2= +; MemoryDef(liveOnEntry) and 4 = MemoryDef(liveOnEntry) Both would mean both +; 1,2, and 3,4 would reach the phi node. Because the phi node can only have one +; entry on each edge, it would choose 2, 4 and disconnect 1 and 3 completely +; from the SSA graph, even though they are not dead + +define void @sink_store(i32 %index, i32* %foo, i32* %bar) { +entry: + %cmp = trunc i32 %index to i1 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry +; CHECK: 1 = MemoryDef(liveOnEntry) +; CHECK-NEXT: store i32 %index, i32* %foo, align 4 + store i32 %index, i32* %foo, align 4 +; CHECK: 2 = MemoryDef(1) +; CHECK-NEXT: store i32 %index, i32* %bar, align 4 + store i32 %index, i32* %bar, align 4 + br label %if.end + +if.else: ; preds = %entry +; CHECK: 3 = MemoryDef(liveOnEntry) +; CHECK-NEXT: store i32 %index, i32* %foo, align 4 + store i32 %index, i32* %foo, align 4 +; CHECK: 4 = MemoryDef(3) +; CHECK-NEXT: store i32 %index, i32* %bar, align 4 + store i32 %index, i32* %bar, align 4 + br label %if.end + +if.end: ; preds = %if.else, %if.then +; CHECK: 5 = MemoryPhi({if.then,2},{if.else,4}) +; CHECK: MemoryUse(5) +; CHECK-NEXT: %c = load i32, i32* %foo + %c = load i32, i32* %foo +; CHECK: MemoryUse(5) +; CHECK-NEXT: %d = load i32, i32* %bar + %d = load i32, i32* %bar + ret void +} diff --git a/test/Transforms/Util/MemorySSA/optimize-use.ll b/test/Transforms/Util/MemorySSA/optimize-use.ll new file mode 100644 index 000000000000..8a8f2dd50959 --- /dev/null +++ b/test/Transforms/Util/MemorySSA/optimize-use.ll @@ -0,0 +1,37 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %s 2>&1 | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='print<memoryssa>,verify<memoryssa>' -disable-output < %s 2>&1 | FileCheck %s + +; Function Attrs: ssp uwtable +define i32 @main() { +entry: +; CHECK: 1 = MemoryDef(liveOnEntry) +; CHECK-NEXT: %call = call noalias i8* @_Znwm(i64 4) + %call = call noalias i8* @_Znwm(i64 4) + %0 = bitcast i8* %call to i32* +; CHECK: 2 = MemoryDef(1) +; CHECK-NEXT: %call1 = call noalias i8* @_Znwm(i64 4) + %call1 = call noalias i8* @_Znwm(i64 4) + %1 = bitcast i8* %call1 to i32* +; CHECK: 3 = MemoryDef(2) +; CHECK-NEXT: store i32 5, i32* %0, align 4 + store i32 5, i32* %0, align 4 +; CHECK: 4 = MemoryDef(3) +; CHECK-NEXT: store i32 7, i32* %1, align 4 + store i32 7, i32* %1, align 4 +; CHECK: MemoryUse(3) +; CHECK-NEXT: %2 = load i32, i32* %0, align 4 + %2 = load i32, i32* %0, align 4 +; CHECK: MemoryUse(4) +; CHECK-NEXT: %3 = load i32, i32* %1, align 4 + %3 = load i32, i32* %1, align 4 +; CHECK: MemoryUse(3) +; CHECK-NEXT: %4 = load i32, i32* %0, align 4 + %4 = load i32, i32* %0, align 4 +; CHECK: MemoryUse(4) +; CHECK-NEXT: %5 = load i32, i32* %1, align 4 + %5 = load i32, i32* %1, align 4 + %add = add nsw i32 %3, %5 + ret i32 %add +} + +declare noalias i8* @_Znwm(i64) diff --git a/test/Transforms/Util/MemorySSA/phi-translation.ll b/test/Transforms/Util/MemorySSA/phi-translation.ll new file mode 100644 index 000000000000..30cd011a119c --- /dev/null +++ b/test/Transforms/Util/MemorySSA/phi-translation.ll @@ -0,0 +1,182 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %s 2>&1 | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='print<memoryssa>,verify<memoryssa>' -disable-output < %s 2>&1 | FileCheck %s + +; %ptr can't alias %local, so we should be able to optimize the use of %local to +; point to the store to %local. +; CHECK-LABEL: define void @check +define void @check(i8* %ptr, i1 %bool) { +entry: + %local = alloca i8, align 1 +; CHECK: 1 = MemoryDef(liveOnEntry) +; CHECK-NEXT: store i8 0, i8* %local, align 1 + store i8 0, i8* %local, align 1 + br i1 %bool, label %if.then, label %if.end + +if.then: + %p2 = getelementptr inbounds i8, i8* %ptr, i32 1 +; CHECK: 2 = MemoryDef(1) +; CHECK-NEXT: store i8 0, i8* %p2, align 1 + store i8 0, i8* %p2, align 1 + br label %if.end + +if.end: +; CHECK: 3 = MemoryPhi({entry,1},{if.then,2}) +; CHECK: MemoryUse(1) +; CHECK-NEXT: load i8, i8* %local, align 1 + load i8, i8* %local, align 1 + ret void +} + +; CHECK-LABEL: define void @check2 +define void @check2(i1 %val1, i1 %val2, i1 %val3) { +entry: + %local = alloca i8, align 1 + %local2 = alloca i8, align 1 + +; CHECK: 1 = MemoryDef(liveOnEntry) +; CHECK-NEXT: store i8 0, i8* %local + store i8 0, i8* %local + br i1 %val1, label %if.then, label %phi.3 + +if.then: +; CHECK: 2 = MemoryDef(1) +; CHECK-NEXT: store i8 2, i8* %local2 + store i8 2, i8* %local2 + br i1 %val2, label %phi.2, label %phi.3 + +phi.3: +; CHECK: 6 = MemoryPhi({entry,1},{if.then,2}) +; CHECK: 3 = MemoryDef(6) +; CHECK-NEXT: store i8 3, i8* %local2 + store i8 3, i8* %local2 + br i1 %val3, label %phi.2, label %phi.1 + +phi.2: +; CHECK: 5 = MemoryPhi({if.then,2},{phi.3,3}) +; CHECK: 4 = MemoryDef(5) +; CHECK-NEXT: store i8 4, i8* %local2 + store i8 4, i8* %local2 + br label %phi.1 + +phi.1: +; Order matters here; phi.2 needs to come before phi.3, because that's the order +; they're visited in. +; CHECK: 7 = MemoryPhi({phi.2,4},{phi.3,3}) +; CHECK: MemoryUse(1) +; CHECK-NEXT: load i8, i8* %local + load i8, i8* %local + ret void +} + +; CHECK-LABEL: define void @cross_phi +define void @cross_phi(i8* noalias %p1, i8* noalias %p2) { +; CHECK: 1 = MemoryDef(liveOnEntry) +; CHECK-NEXT: store i8 0, i8* %p1 + store i8 0, i8* %p1 +; CHECK: MemoryUse(1) +; CHECK-NEXT: load i8, i8* %p1 + load i8, i8* %p1 + br i1 undef, label %a, label %b + +a: +; CHECK: 2 = MemoryDef(1) +; CHECK-NEXT: store i8 0, i8* %p2 + store i8 0, i8* %p2 + br i1 undef, label %c, label %d + +b: +; CHECK: 3 = MemoryDef(1) +; CHECK-NEXT: store i8 1, i8* %p2 + store i8 1, i8* %p2 + br i1 undef, label %c, label %d + +c: +; CHECK: 6 = MemoryPhi({a,2},{b,3}) +; CHECK: 4 = MemoryDef(6) +; CHECK-NEXT: store i8 2, i8* %p2 + store i8 2, i8* %p2 + br label %e + +d: +; CHECK: 7 = MemoryPhi({a,2},{b,3}) +; CHECK: 5 = MemoryDef(7) +; CHECK-NEXT: store i8 3, i8* %p2 + store i8 3, i8* %p2 + br label %e + +e: +; 8 = MemoryPhi({c,4},{d,5}) +; CHECK: MemoryUse(1) +; CHECK-NEXT: load i8, i8* %p1 + load i8, i8* %p1 + ret void +} + +; CHECK-LABEL: define void @looped +define void @looped(i8* noalias %p1, i8* noalias %p2) { +; CHECK: 1 = MemoryDef(liveOnEntry) +; CHECK-NEXT: store i8 0, i8* %p1 + store i8 0, i8* %p1 + br label %loop.1 + +loop.1: +; CHECK: 7 = MemoryPhi({%0,1},{loop.3,4}) +; CHECK: 2 = MemoryDef(7) +; CHECK-NEXT: store i8 0, i8* %p2 + store i8 0, i8* %p2 + br i1 undef, label %loop.2, label %loop.3 + +loop.2: +; CHECK: 6 = MemoryPhi({loop.1,2},{loop.3,4}) +; CHECK: 3 = MemoryDef(6) +; CHECK-NEXT: store i8 1, i8* %p2 + store i8 1, i8* %p2 + br label %loop.3 + +loop.3: +; CHECK: 5 = MemoryPhi({loop.1,2},{loop.2,3}) +; CHECK: 4 = MemoryDef(5) +; CHECK-NEXT: store i8 2, i8* %p2 + store i8 2, i8* %p2 +; FIXME: This should be MemoryUse(1) +; CHECK: MemoryUse(5) +; CHECK-NEXT: load i8, i8* %p1 + load i8, i8* %p1 + br i1 undef, label %loop.2, label %loop.1 +} + +; CHECK-LABEL: define void @looped_visitedonlyonce +define void @looped_visitedonlyonce(i8* noalias %p1, i8* noalias %p2) { + br label %while.cond + +while.cond: +; CHECK: 5 = MemoryPhi({%0,liveOnEntry},{if.end,3}) +; CHECK-NEXT: br i1 undef, label %if.then, label %if.end + br i1 undef, label %if.then, label %if.end + +if.then: +; CHECK: 1 = MemoryDef(5) +; CHECK-NEXT: store i8 0, i8* %p1 + store i8 0, i8* %p1 + br i1 undef, label %if.end, label %if.then2 + +if.then2: +; CHECK: 2 = MemoryDef(1) +; CHECK-NEXT: store i8 1, i8* %p2 + store i8 1, i8* %p2 + br label %if.end + +if.end: +; CHECK: 4 = MemoryPhi({while.cond,5},{if.then,1},{if.then2,2}) +; CHECK: MemoryUse(4) +; CHECK-NEXT: load i8, i8* %p1 + load i8, i8* %p1 +; CHECK: 3 = MemoryDef(4) +; CHECK-NEXT: store i8 2, i8* %p2 + store i8 2, i8* %p2 +; CHECK: MemoryUse(4) +; CHECK-NEXT: load i8, i8* %p1 + load i8, i8* %p1 + br label %while.cond +} + diff --git a/test/Transforms/Util/MemorySSA/volatile-clobber.ll b/test/Transforms/Util/MemorySSA/volatile-clobber.ll new file mode 100644 index 000000000000..baad8d8c2d14 --- /dev/null +++ b/test/Transforms/Util/MemorySSA/volatile-clobber.ll @@ -0,0 +1,22 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %s 2>&1 | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='print<memoryssa>,verify<memoryssa>' -disable-output < %s 2>&1 | FileCheck %s +; +; Ensures that volatile stores/loads count as MemoryDefs + +define i32 @foo() { + %1 = alloca i32, align 4 +; CHECK: 1 = MemoryDef(liveOnEntry) +; CHECK-NEXT: store volatile i32 4 + store volatile i32 4, i32* %1, align 4 +; CHECK: 2 = MemoryDef(1) +; CHECK-NEXT: store volatile i32 8 + store volatile i32 8, i32* %1, align 4 +; CHECK: 3 = MemoryDef(2) +; CHECK-NEXT: %2 = load volatile i32 + %2 = load volatile i32, i32* %1, align 4 +; CHECK: 4 = MemoryDef(3) +; CHECK-NEXT: %3 = load volatile i32 + %3 = load volatile i32, i32* %1, align 4 + %4 = add i32 %3, %2 + ret i32 %4 +} diff --git a/test/Transforms/Util/simplify-dbg-declare-load.ll b/test/Transforms/Util/simplify-dbg-declare-load.ll index 0357a5e6facb..21d305450860 100644 --- a/test/Transforms/Util/simplify-dbg-declare-load.ll +++ b/test/Transforms/Util/simplify-dbg-declare-load.ll @@ -19,9 +19,9 @@ fail: ; preds = %top unreachable idxend: ; preds = %top -; CHECK-NOT call void @llvm.dbg.value(metadata %foo* %cp, i64 0, metadata !1, metadata !16), !dbg !17 +; CHECK-NOT call void @llvm.dbg.value(metadata %foo* %cp, %0 = load volatile %foo, %foo* %cp, align 8 -; CHECK: call void @llvm.dbg.value(metadata %foo %0, i64 0, metadata !1, metadata !16), !dbg !17 +; CHECK: call void @llvm.dbg.value(metadata %foo %0, store volatile %foo %0, %foo* undef, align 8 ret void } @@ -30,11 +30,11 @@ attributes #0 = { nounwind readnone } attributes #1 = { sspreq } !llvm.module.flags = !{!0} -!llvm.dbg.cu = !{} +!llvm.dbg.cu = !{!18} !0 = !{i32 1, !"Debug Info Version", i32 3} !1 = !DILocalVariable(name: "cp", scope: !2, file: !3, line: 106, type: !12) -!2 = distinct !DISubprogram(name: "fastshortest", linkageName: "julia_fastshortest_6256", scope: null, file: !3, type: !4, isLocal: false, isDefinition: true, isOptimized: true, variables: !11) +!2 = distinct !DISubprogram(name: "fastshortest", linkageName: "julia_fastshortest_6256", scope: null, file: !3, type: !4, isLocal: false, isDefinition: true, isOptimized: true, unit: !18, variables: !11) !3 = !DIFile(filename: "grisu/fastshortest.jl", directory: ".") !4 = !DISubroutineType(types: !5) !5 = !{!6, !7} @@ -50,3 +50,4 @@ attributes #1 = { sspreq } !15 = !DIBasicType(name: "Int32", size: 32, align: 32, encoding: DW_ATE_unsigned) !16 = !DIExpression() !17 = !DILocation(line: 106, scope: !2) +!18 = distinct !DICompileUnit(language: DW_LANG_Julia, file: !3) diff --git a/test/Transforms/Util/split-bit-piece.ll b/test/Transforms/Util/split-bit-piece.ll index 6945beca84b1..9343214cd991 100644 --- a/test/Transforms/Util/split-bit-piece.ll +++ b/test/Transforms/Util/split-bit-piece.ll @@ -29,7 +29,7 @@ attributes #0 = { nounwind readnone } !llvm.module.flags = !{!7} !llvm.ident = !{!8} -!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 256979) (llvm/trunk 257107)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, retainedTypes: !2) +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 256979) (llvm/trunk 257107)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: !2) !1 = !DIFile(filename: "tsan_shadow_test.cc", directory: "/tmp") !2 = !{!3, !5} !3 = !DICompositeType(tag: DW_TAG_class_type, name: "FastState", file: !4, line: 91, size: 64, align: 64, identifier: "_ZTSN6__tsan9FastStateE") @@ -40,6 +40,6 @@ attributes #0 = { nounwind readnone } !8 = !{!"clang version 3.8.0 (trunk 256979) (llvm/trunk 257107)"} !9 = !DILocalVariable(name: "v1", scope: !10, file: !4, line: 136, type: !5) !10 = distinct !DILexicalBlock(scope: !11, file: !4, line: 136, column: 5) -!11 = distinct !DISubprogram(name: "SetHistorySize", linkageName: "_ZN6__tsan9FastState14SetHistorySizeEi", scope: !"_ZTSN6__tsan9FastStateE", file: !4, line: 135, isLocal: false, isDefinition: true, scopeLine: 135, flags: DIFlagPrototyped, isOptimized: false) +!11 = distinct !DISubprogram(name: "SetHistorySize", linkageName: "_ZN6__tsan9FastState14SetHistorySizeEi", scope: !3, file: !4, line: 135, isLocal: false, isDefinition: true, scopeLine: 135, flags: DIFlagPrototyped, isOptimized: false, unit: !0) !12 = !DIExpression() !13 = !DILocation(line: 136, column: 5, scope: !10) diff --git a/test/Transforms/Util/store-first-op.ll b/test/Transforms/Util/store-first-op.ll new file mode 100644 index 000000000000..08efbe47ccfe --- /dev/null +++ b/test/Transforms/Util/store-first-op.ll @@ -0,0 +1,36 @@ +; RUN: opt -instcombine -S %s | FileCheck %s + +%foo = type { i8 } + +; Function Attrs: nounwind uwtable +define void @_ZN4llvm13ScaledNumbers10multiply64Emm() { +entry: + %getU = alloca %foo, align 1 +; This is supposed to make sure that the declare conversion, does not accidentally think the store OF +; %getU is a store TO %getU. There are valid reasons to have an llvm.dbg.value here, but if the pass +; is changed to emit such, a more specific check should be added to make sure that any llvm.dbg.value +; is correct. +; CHECK-NOT: @llvm.dbg.value(metadata %foo* %getU + call void @llvm.dbg.declare(metadata %foo* %getU, metadata !3, metadata !6), !dbg !7 + store %foo* %getU, %foo** undef, align 8, !tbaa !8 + unreachable +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (https://github.com/llvm-mirror/clang 89dda3855cda574f355e6defa1d77bdae5053994) (llvm/trunk 257597)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug) +!1 = !DIFile(filename: "none", directory: ".") +!2 = !{i32 2, !"Debug Info Version", i32 3} +!3 = !DILocalVariable(name: "getU", scope: !4, file: !1, line: 25, type: !5) +!4 = distinct !DISubprogram(name: "multiply64", linkageName: "_ZN4llvm13ScaledNumbers10multiply64Emm", scope: null, file: !1, line: 22, isLocal: false, isDefinition: true, scopeLine: 23, flags: DIFlagPrototyped, isOptimized: true, unit: !0) +!5 = !DICompositeType(tag: DW_TAG_class_type, scope: !4, file: !1, line: 25, size: 8, align: 8) +!6 = !DIExpression() +!7 = !DILocation(line: 25, column: 8, scope: !4) +!8 = !{!9, !9, i64 0} +!9 = !{i64 0} |
