diff options
Diffstat (limited to 'llvm/test')
12 files changed, 502 insertions, 0 deletions
diff --git a/llvm/test/Transforms/Util/MemorySSA/atomic-clobber.ll b/llvm/test/Transforms/Util/MemorySSA/atomic-clobber.ll new file mode 100644 index 00000000000..d1a10d90cb2 --- /dev/null +++ b/llvm/test/Transforms/Util/MemorySSA/atomic-clobber.ll @@ -0,0 +1,17 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %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/llvm/test/Transforms/Util/MemorySSA/cyclicphi.ll b/llvm/test/Transforms/Util/MemorySSA/cyclicphi.ll new file mode 100644 index 00000000000..51c2e4cb310 --- /dev/null +++ b/llvm/test/Transforms/Util/MemorySSA/cyclicphi.ll @@ -0,0 +1,33 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %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 +} diff --git a/llvm/test/Transforms/Util/MemorySSA/function-clobber.ll b/llvm/test/Transforms/Util/MemorySSA/function-clobber.ll new file mode 100644 index 00000000000..97e231a4ea2 --- /dev/null +++ b/llvm/test/Transforms/Util/MemorySSA/function-clobber.ll @@ -0,0 +1,26 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %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 +} diff --git a/llvm/test/Transforms/Util/MemorySSA/function-mem-attrs.ll b/llvm/test/Transforms/Util/MemorySSA/function-mem-attrs.ll new file mode 100644 index 00000000000..ab36f039740 --- /dev/null +++ b/llvm/test/Transforms/Util/MemorySSA/function-mem-attrs.ll @@ -0,0 +1,58 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %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/llvm/test/Transforms/Util/MemorySSA/load-invariant.ll b/llvm/test/Transforms/Util/MemorySSA/load-invariant.ll new file mode 100644 index 00000000000..2350346c0a9 --- /dev/null +++ b/llvm/test/Transforms/Util/MemorySSA/load-invariant.ll @@ -0,0 +1,24 @@ +; XFAIL: +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %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/llvm/test/Transforms/Util/MemorySSA/many-dom-backedge.ll b/llvm/test/Transforms/Util/MemorySSA/many-dom-backedge.ll new file mode 100644 index 00000000000..49f9145b9d3 --- /dev/null +++ b/llvm/test/Transforms/Util/MemorySSA/many-dom-backedge.ll @@ -0,0 +1,76 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %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/llvm/test/Transforms/Util/MemorySSA/many-doms.ll b/llvm/test/Transforms/Util/MemorySSA/many-doms.ll new file mode 100644 index 00000000000..733accd3dd1 --- /dev/null +++ b/llvm/test/Transforms/Util/MemorySSA/many-doms.ll @@ -0,0 +1,66 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %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/llvm/test/Transforms/Util/MemorySSA/multi-edges.ll b/llvm/test/Transforms/Util/MemorySSA/multi-edges.ll new file mode 100644 index 00000000000..882a35ddf10 --- /dev/null +++ b/llvm/test/Transforms/Util/MemorySSA/multi-edges.ll @@ -0,0 +1,31 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %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/llvm/test/Transforms/Util/MemorySSA/multiple-backedges-hal.ll b/llvm/test/Transforms/Util/MemorySSA/multiple-backedges-hal.ll new file mode 100644 index 00000000000..7afd7c4940f --- /dev/null +++ b/llvm/test/Transforms/Util/MemorySSA/multiple-backedges-hal.ll @@ -0,0 +1,72 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %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/llvm/test/Transforms/Util/MemorySSA/no-disconnected.ll b/llvm/test/Transforms/Util/MemorySSA/no-disconnected.ll new file mode 100644 index 00000000000..f302f2bffc6 --- /dev/null +++ b/llvm/test/Transforms/Util/MemorySSA/no-disconnected.ll @@ -0,0 +1,42 @@ +; RUN: opt -basicaa -print-memoryssa -analyze -verify-memoryssa < %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/llvm/test/Transforms/Util/MemorySSA/optimize-use.ll b/llvm/test/Transforms/Util/MemorySSA/optimize-use.ll new file mode 100644 index 00000000000..fccdc6450b6 --- /dev/null +++ b/llvm/test/Transforms/Util/MemorySSA/optimize-use.ll @@ -0,0 +1,36 @@ +; RUN: opt -basicaa -print-memoryssa -analyze -verify-memoryssa < %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/llvm/test/Transforms/Util/MemorySSA/volatile-clobber.ll b/llvm/test/Transforms/Util/MemorySSA/volatile-clobber.ll new file mode 100644 index 00000000000..78b6e8fcd6a --- /dev/null +++ b/llvm/test/Transforms/Util/MemorySSA/volatile-clobber.ll @@ -0,0 +1,21 @@ +; RUN: opt -basicaa -print-memoryssa -verify-memoryssa -analyze < %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 +} |

