| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 = !{} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } |