summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/docs/LangRef.rst30
-rw-r--r--llvm/include/llvm/Analysis/TargetTransformInfoImpl.h1
-rw-r--r--llvm/include/llvm/CodeGen/BasicTTIImpl.h1
-rw-r--r--llvm/include/llvm/IR/Intrinsics.td6
-rw-r--r--llvm/lib/Analysis/AliasSetTracker.cpp1
-rw-r--r--llvm/lib/Analysis/ValueTracking.cpp4
-rw-r--r--llvm/lib/Analysis/VectorUtils.cpp3
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/FastISel.cpp2
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp3
-rw-r--r--llvm/lib/Transforms/Scalar/EarlyCSE.cpp6
-rw-r--r--llvm/lib/Transforms/Scalar/GVNHoist.cpp3
-rw-r--r--llvm/lib/Transforms/Utils/Evaluator.cpp4
-rw-r--r--llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp5
-rw-r--r--llvm/lib/Transforms/Vectorize/LoopVectorize.cpp2
-rw-r--r--llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp4
-rw-r--r--llvm/test/CodeGen/Generic/intrinsics.ll9
-rw-r--r--llvm/test/Transforms/DCE/int_sideeffect.ll12
-rw-r--r--llvm/test/Transforms/DeadStoreElimination/int_sideeffect.ll15
-rw-r--r--llvm/test/Transforms/EarlyCSE/int_sideeffect.ll27
-rw-r--r--llvm/test/Transforms/FunctionAttrs/int_sideeffect.ll21
-rw-r--r--llvm/test/Transforms/GVN/int_sideeffect.ll51
-rw-r--r--llvm/test/Transforms/GVNHoist/int_sideeffect.ll30
-rw-r--r--llvm/test/Transforms/GVNSink/int_sideeffect.ll30
-rw-r--r--llvm/test/Transforms/GlobalOpt/int_sideeffect.ll16
-rw-r--r--llvm/test/Transforms/InstCombine/int_sideeffect.ll14
-rw-r--r--llvm/test/Transforms/LICM/int_sideeffect.ll27
-rw-r--r--llvm/test/Transforms/LoadStoreVectorizer/int_sideeffect.ll26
-rw-r--r--llvm/test/Transforms/LoopIdiom/int_sideeffect.ll23
-rw-r--r--llvm/test/Transforms/LoopVectorize/int_sideeffect.ll24
-rw-r--r--llvm/test/Transforms/NewGVN/int_sideeffect.ll27
-rw-r--r--llvm/test/Transforms/SLPVectorizer/int_sideeffect.ll25
31 files changed, 446 insertions, 6 deletions
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 8cbed7d87d1..b097230591f 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -14267,6 +14267,36 @@ not overflow at link time under the medium code model if ``x`` is an
a constant initializer folded into a function body. This intrinsic can be
used to avoid the possibility of overflows when loading from such a constant.
+'``llvm.sideeffect``' Intrinsic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+::
+
+ declare void @llvm.sideeffect() inaccessiblememonly nounwind
+
+Overview:
+"""""""""
+
+The ``llvm.sideeffect`` intrinsic doesn't perform any operation. Optimizers
+treat it as having side effects, so it can be inserted into a loop to
+indicate that the loop shouldn't be assumed to terminate (which could
+potentially lead to the loop being optimized away entirely), even if it's
+an infinite loop with no other side effects.
+
+Arguments:
+""""""""""
+
+None.
+
+Semantics:
+""""""""""
+
+This intrinsic actually does nothing, but optimizers must assume that it
+has externally observable side effects.
+
Stack Map Intrinsics
--------------------
diff --git a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
index ada8fc0facb..4f27f6a1410 100644
--- a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
+++ b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
@@ -152,6 +152,7 @@ public:
case Intrinsic::annotation:
case Intrinsic::assume:
+ case Intrinsic::sideeffect:
case Intrinsic::dbg_declare:
case Intrinsic::dbg_value:
case Intrinsic::invariant_start:
diff --git a/llvm/include/llvm/CodeGen/BasicTTIImpl.h b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
index 0334ed9eacb..aa16f86c307 100644
--- a/llvm/include/llvm/CodeGen/BasicTTIImpl.h
+++ b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
@@ -1023,6 +1023,7 @@ public:
// FIXME: We should return 0 whenever getIntrinsicCost == TCC_Free.
case Intrinsic::lifetime_start:
case Intrinsic::lifetime_end:
+ case Intrinsic::sideeffect:
return 0;
case Intrinsic::masked_store:
return static_cast<T *>(this)
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index cb16c3d4849..9560ae642dd 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -810,6 +810,12 @@ def int_experimental_guard : Intrinsic<[], [llvm_i1_ty, llvm_vararg_ty],
// NOP: calls/invokes to this intrinsic are removed by codegen
def int_donothing : Intrinsic<[], [], [IntrNoMem]>;
+// This instruction has no actual effect, though it is treated by the optimizer
+// has having opaque side effects. This may be inserted into loops to ensure
+// that they are not removed even if they turn out to be empty, for languages
+// which specify that infinite loops must be preserved.
+def int_sideeffect : Intrinsic<[], [], [IntrInaccessibleMemOnly]>;
+
// Intrisics to support half precision floating point format
let IntrProperties = [IntrNoMem] in {
def int_convert_to_fp16 : Intrinsic<[llvm_i16_ty], [llvm_anyfloat_ty]>;
diff --git a/llvm/lib/Analysis/AliasSetTracker.cpp b/llvm/lib/Analysis/AliasSetTracker.cpp
index 025e8119deb..b575944092a 100644
--- a/llvm/lib/Analysis/AliasSetTracker.cpp
+++ b/llvm/lib/Analysis/AliasSetTracker.cpp
@@ -436,6 +436,7 @@ void AliasSetTracker::addUnknown(Instruction *Inst) {
break;
// FIXME: Add lifetime/invariant intrinsics (See: PR30807).
case Intrinsic::assume:
+ case Intrinsic::sideeffect:
return;
}
}
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 2010858139a..9a0df74fd57 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -433,6 +433,7 @@ static bool isAssumeLikeIntrinsic(const Instruction *I) {
default: break;
// FIXME: This list is repeated from NoTTI::getIntrinsicCost.
case Intrinsic::assume:
+ case Intrinsic::sideeffect:
case Intrinsic::dbg_declare:
case Intrinsic::dbg_value:
case Intrinsic::invariant_start:
@@ -3857,7 +3858,8 @@ bool llvm::isGuaranteedToTransferExecutionToSuccessor(const Instruction *I) {
// FIXME: This isn't aggressive enough; a call which only writes to a global
// is guaranteed to return.
return CS.onlyReadsMemory() || CS.onlyAccessesArgMemory() ||
- match(I, m_Intrinsic<Intrinsic::assume>());
+ match(I, m_Intrinsic<Intrinsic::assume>()) ||
+ match(I, m_Intrinsic<Intrinsic::sideeffect>());
}
// Other instructions return normally.
diff --git a/llvm/lib/Analysis/VectorUtils.cpp b/llvm/lib/Analysis/VectorUtils.cpp
index 554d132c2ab..2becfbfe8a8 100644
--- a/llvm/lib/Analysis/VectorUtils.cpp
+++ b/llvm/lib/Analysis/VectorUtils.cpp
@@ -91,7 +91,8 @@ Intrinsic::ID llvm::getVectorIntrinsicIDForCall(const CallInst *CI,
return Intrinsic::not_intrinsic;
if (isTriviallyVectorizable(ID) || ID == Intrinsic::lifetime_start ||
- ID == Intrinsic::lifetime_end || ID == Intrinsic::assume)
+ ID == Intrinsic::lifetime_end || ID == Intrinsic::assume ||
+ ID == Intrinsic::sideeffect)
return ID;
return Intrinsic::not_intrinsic;
}
diff --git a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp
index 6e245feb735..acc67b827ed 100644
--- a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp
@@ -1132,6 +1132,8 @@ bool FastISel::selectIntrinsicCall(const IntrinsicInst *II) {
case Intrinsic::lifetime_end:
// The donothing intrinsic does, well, nothing.
case Intrinsic::donothing:
+ // Neither does the sideeffect intrinsic.
+ case Intrinsic::sideeffect:
// Neither does the assume intrinsic; it's also OK not to codegen its operand.
case Intrinsic::assume:
return true;
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index f4f8879b5d8..4a1e71583eb 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -5702,7 +5702,8 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
return nullptr;
case Intrinsic::assume:
case Intrinsic::var_annotation:
- // Discard annotate attributes and assumptions
+ case Intrinsic::sideeffect:
+ // Discard annotate attributes, assumptions, and artificial side-effects.
return nullptr;
case Intrinsic::codeview_annotation: {
diff --git a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
index 6d1362a6a28..1066dc33007 100644
--- a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
+++ b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
@@ -709,6 +709,12 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
continue;
}
+ // Skip sideeffect intrinsics, for the same reason as assume intrinsics.
+ if (match(Inst, m_Intrinsic<Intrinsic::sideeffect>())) {
+ DEBUG(dbgs() << "EarlyCSE skipping sideeffect: " << *Inst << '\n');
+ continue;
+ }
+
// Skip invariant.start intrinsics since they only read memory, and we can
// forward values across it. Also, we dont need to consume the last store
// since the semantics of invariant.start allow us to perform DSE of the
diff --git a/llvm/lib/Transforms/Scalar/GVNHoist.cpp b/llvm/lib/Transforms/Scalar/GVNHoist.cpp
index d77ebdcd975..e90c89c2e3a 100644
--- a/llvm/lib/Transforms/Scalar/GVNHoist.cpp
+++ b/llvm/lib/Transforms/Scalar/GVNHoist.cpp
@@ -1110,7 +1110,8 @@ private:
else if (auto *Call = dyn_cast<CallInst>(&I1)) {
if (auto *Intr = dyn_cast<IntrinsicInst>(Call)) {
if (isa<DbgInfoIntrinsic>(Intr) ||
- Intr->getIntrinsicID() == Intrinsic::assume)
+ Intr->getIntrinsicID() == Intrinsic::assume ||
+ Intr->getIntrinsicID() == Intrinsic::sideeffect)
continue;
}
if (Call->mayHaveSideEffects())
diff --git a/llvm/lib/Transforms/Utils/Evaluator.cpp b/llvm/lib/Transforms/Utils/Evaluator.cpp
index a65c3bac5e5..3c5e299fae9 100644
--- a/llvm/lib/Transforms/Utils/Evaluator.cpp
+++ b/llvm/lib/Transforms/Utils/Evaluator.cpp
@@ -433,6 +433,10 @@ bool Evaluator::EvaluateBlock(BasicBlock::iterator CurInst,
DEBUG(dbgs() << "Skipping assume intrinsic.\n");
++CurInst;
continue;
+ } else if (II->getIntrinsicID() == Intrinsic::sideeffect) {
+ DEBUG(dbgs() << "Skipping sideeffect intrinsic.\n");
+ ++CurInst;
+ continue;
}
DEBUG(dbgs() << "Unknown intrinsic. Can not evaluate.\n");
diff --git a/llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp b/llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp
index 5d355c52021..dc83b6d4d29 100644
--- a/llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp
@@ -34,6 +34,7 @@
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/User.h"
@@ -500,6 +501,10 @@ Vectorizer::getVectorizablePrefix(ArrayRef<Instruction *> Chain) {
MemoryInstrs.push_back(&I);
else
ChainInstrs.push_back(&I);
+ } else if (isa<IntrinsicInst>(&I) &&
+ cast<IntrinsicInst>(&I)->getIntrinsicID() ==
+ Intrinsic::sideeffect) {
+ // Ignore llvm.sideeffect calls.
} else if (IsLoadChain && (I.mayWriteToMemory() || I.mayThrow())) {
DEBUG(dbgs() << "LSV: Found may-write/throw operation: " << I << '\n');
break;
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index ed29ca0b573..673c47f4730 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -8117,7 +8117,7 @@ bool LoopVectorizationPlanner::tryToWiden(Instruction *I, VPBasicBlock *VPBB,
if (CallInst *CI = dyn_cast<CallInst>(I)) {
Intrinsic::ID ID = getVectorIntrinsicIDForCall(CI, TLI);
if (ID && (ID == Intrinsic::assume || ID == Intrinsic::lifetime_end ||
- ID == Intrinsic::lifetime_start))
+ ID == Intrinsic::lifetime_start || ID == Intrinsic::sideeffect))
return false;
}
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 4232252af36..6c607062f25 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -3612,7 +3612,9 @@ void BoUpSLP::BlockScheduling::initScheduleData(Instruction *FromI,
"new ScheduleData already in scheduling region");
SD->init(SchedulingRegionID, I);
- if (I->mayReadOrWriteMemory()) {
+ if (I->mayReadOrWriteMemory() &&
+ (!isa<IntrinsicInst>(I) ||
+ cast<IntrinsicInst>(I)->getIntrinsicID() != Intrinsic::sideeffect)) {
// Update the linked list of memory accessing instructions.
if (CurrentLoadStore) {
CurrentLoadStore->NextLoadStore = SD;
diff --git a/llvm/test/CodeGen/Generic/intrinsics.ll b/llvm/test/CodeGen/Generic/intrinsics.ll
index 4d04786a58d..6a51d2d371b 100644
--- a/llvm/test/CodeGen/Generic/intrinsics.ll
+++ b/llvm/test/CodeGen/Generic/intrinsics.ll
@@ -45,3 +45,12 @@ define i8* @barrier(i8* %p) {
%q = call i8* @llvm.invariant.group.barrier(i8* %p)
ret i8* %q
}
+
+; sideeffect
+
+declare void @llvm.sideeffect()
+
+define void @test_sideeffect() {
+ call void @llvm.sideeffect()
+ ret void
+}
diff --git a/llvm/test/Transforms/DCE/int_sideeffect.ll b/llvm/test/Transforms/DCE/int_sideeffect.ll
new file mode 100644
index 00000000000..af06303fa86
--- /dev/null
+++ b/llvm/test/Transforms/DCE/int_sideeffect.ll
@@ -0,0 +1,12 @@
+; RUN: opt -S < %s -instcombine | FileCheck %s
+
+declare void @llvm.sideeffect()
+
+; Don't DCE llvm.sideeffect calls.
+
+; CHECK-LABEL: dce
+; CHECK: call void @llvm.sideeffect()
+define void @dce() {
+ call void @llvm.sideeffect()
+ ret void
+}
diff --git a/llvm/test/Transforms/DeadStoreElimination/int_sideeffect.ll b/llvm/test/Transforms/DeadStoreElimination/int_sideeffect.ll
new file mode 100644
index 00000000000..035e787f6bd
--- /dev/null
+++ b/llvm/test/Transforms/DeadStoreElimination/int_sideeffect.ll
@@ -0,0 +1,15 @@
+; RUN: opt -S < %s -dse | FileCheck %s
+
+declare void @llvm.sideeffect()
+
+; Dead store elimination across a @llvm.sideeffect.
+
+; CHECK-LABEL: dse
+; CHECK: store
+; CHECK-NOT: store
+define void @dse(float* %p) {
+ store float 0.0, float* %p
+ call void @llvm.sideeffect()
+ store float 0.0, float* %p
+ ret void
+}
diff --git a/llvm/test/Transforms/EarlyCSE/int_sideeffect.ll b/llvm/test/Transforms/EarlyCSE/int_sideeffect.ll
new file mode 100644
index 00000000000..1dccaab5e5f
--- /dev/null
+++ b/llvm/test/Transforms/EarlyCSE/int_sideeffect.ll
@@ -0,0 +1,27 @@
+; RUN: opt -S < %s -early-cse | FileCheck %s
+
+declare void @llvm.sideeffect()
+
+; Store-to-load forwarding across a @llvm.sideeffect.
+
+; CHECK-LABEL: s2l
+; CHECK-NOT: load
+define float @s2l(float* %p) {
+ store float 0.0, float* %p
+ call void @llvm.sideeffect()
+ %t = load float, float* %p
+ ret float %t
+}
+
+; Redundant load elimination across a @llvm.sideeffect.
+
+; CHECK-LABEL: rle
+; CHECK: load
+; CHECK-NOT: load
+define float @rle(float* %p) {
+ %r = load float, float* %p
+ call void @llvm.sideeffect()
+ %s = load float, float* %p
+ %t = fadd float %r, %s
+ ret float %t
+}
diff --git a/llvm/test/Transforms/FunctionAttrs/int_sideeffect.ll b/llvm/test/Transforms/FunctionAttrs/int_sideeffect.ll
new file mode 100644
index 00000000000..13091e3e8cb
--- /dev/null
+++ b/llvm/test/Transforms/FunctionAttrs/int_sideeffect.ll
@@ -0,0 +1,21 @@
+; RUN: opt -S < %s -functionattrs | FileCheck %s
+
+declare void @llvm.sideeffect()
+
+; Don't add readnone or similar attributes when an @llvm.sideeffect() intrinsic
+; is present.
+
+; CHECK: define void @test() {
+define void @test() {
+ call void @llvm.sideeffect()
+ ret void
+}
+
+; CHECK: define void @loop() {
+define void @loop() {
+ br label %loop
+
+loop:
+ call void @llvm.sideeffect()
+ br label %loop
+}
diff --git a/llvm/test/Transforms/GVN/int_sideeffect.ll b/llvm/test/Transforms/GVN/int_sideeffect.ll
new file mode 100644
index 00000000000..02ee2fcbdb0
--- /dev/null
+++ b/llvm/test/Transforms/GVN/int_sideeffect.ll
@@ -0,0 +1,51 @@
+; RUN: opt -S < %s -gvn | FileCheck %s
+
+declare void @llvm.sideeffect()
+
+; Store-to-load forwarding across a @llvm.sideeffect.
+
+; CHECK-LABEL: s2l
+; CHECK-NOT: load
+define float @s2l(float* %p) {
+ store float 0.0, float* %p
+ call void @llvm.sideeffect()
+ %t = load float, float* %p
+ ret float %t
+}
+
+; Redundant load elimination across a @llvm.sideeffect.
+
+; CHECK-LABEL: rle
+; CHECK: load
+; CHECK-NOT: load
+define float @rle(float* %p) {
+ %r = load float, float* %p
+ call void @llvm.sideeffect()
+ %s = load float, float* %p
+ %t = fadd float %r, %s
+ ret float %t
+}
+
+; LICM across a @llvm.sideeffect.
+
+; CHECK-LABEL: licm
+; CHECK: load
+; CHECK: loop:
+; CHECK-NOT: load
+define float @licm(i64 %n, float* nocapture readonly %p) #0 {
+bb0:
+ br label %loop
+
+loop:
+ %i = phi i64 [ 0, %bb0 ], [ %t5, %loop ]
+ %sum = phi float [ 0.000000e+00, %bb0 ], [ %t4, %loop ]
+ call void @llvm.sideeffect()
+ %t3 = load float, float* %p
+ %t4 = fadd float %sum, %t3
+ %t5 = add i64 %i, 1
+ %t6 = icmp ult i64 %t5, %n
+ br i1 %t6, label %loop, label %bb2
+
+bb2:
+ ret float %t4
+}
diff --git a/llvm/test/Transforms/GVNHoist/int_sideeffect.ll b/llvm/test/Transforms/GVNHoist/int_sideeffect.ll
new file mode 100644
index 00000000000..26029fe52ce
--- /dev/null
+++ b/llvm/test/Transforms/GVNHoist/int_sideeffect.ll
@@ -0,0 +1,30 @@
+; RUN: opt -S < %s -gvn-hoist | FileCheck %s
+
+declare void @llvm.sideeffect()
+
+; GVN hoisting across a @llvm.sideeffect.
+
+; CHECK-LABEL: scalarsHoisting
+; CHECK: = fsub
+; CHECK: br i1 %cmp,
+; CHECK-NOT: fsub
+define float @scalarsHoisting(float %d, float %m, float %a, i1 %cmp) {
+entry:
+ br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+ call void @llvm.sideeffect()
+ %sub0 = fsub float %m, %a
+ %mul = fmul float %sub0, %d
+ br label %if.end
+
+if.else:
+ %sub1 = fsub float %m, %a
+ %div = fdiv float %sub1, %d
+ br label %if.end
+
+if.end:
+ %phi = phi float [ %mul, %if.then ], [ %div, %if.else ]
+ ret float %phi
+}
+
diff --git a/llvm/test/Transforms/GVNSink/int_sideeffect.ll b/llvm/test/Transforms/GVNSink/int_sideeffect.ll
new file mode 100644
index 00000000000..0ea773654c4
--- /dev/null
+++ b/llvm/test/Transforms/GVNSink/int_sideeffect.ll
@@ -0,0 +1,30 @@
+; RUN: opt -S < %s -gvn-sink | FileCheck %s
+
+declare void @llvm.sideeffect()
+
+; GVN sinking across a @llvm.sideeffect.
+
+; CHECK-LABEL: scalarsSinking
+; CHECK-NOT: fmul
+; CHECK: = phi
+; CHECK: = fmul
+define float @scalarsSinking(float %d, float %m, float %a, i1 %cmp) {
+entry:
+ br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+ call void @llvm.sideeffect()
+ %sub = fsub float %m, %a
+ %mul0 = fmul float %sub, %d
+ br label %if.end
+
+if.else:
+ %add = fadd float %m, %a
+ %mul1 = fmul float %add, %d
+ br label %if.end
+
+if.end:
+ %phi = phi float [ %mul0, %if.then ], [ %mul1, %if.else ]
+ ret float %phi
+}
+
diff --git a/llvm/test/Transforms/GlobalOpt/int_sideeffect.ll b/llvm/test/Transforms/GlobalOpt/int_sideeffect.ll
new file mode 100644
index 00000000000..59c3a8aa4ba
--- /dev/null
+++ b/llvm/test/Transforms/GlobalOpt/int_sideeffect.ll
@@ -0,0 +1,16 @@
+; RUN: opt -S < %s -globalopt | FileCheck %s
+
+; Static evaluation across a @llvm.sideeffect.
+
+; CHECK-NOT: store
+
+declare void @llvm.sideeffect()
+
+@llvm.global_ctors = appending global [1 x { i32, void ()* }] [ { i32, void ()* } { i32 65535, void ()* @ctor } ]
+@G = global i32 0
+
+define internal void @ctor() {
+ store i32 1, i32* @G
+ call void @llvm.sideeffect()
+ ret void
+}
diff --git a/llvm/test/Transforms/InstCombine/int_sideeffect.ll b/llvm/test/Transforms/InstCombine/int_sideeffect.ll
new file mode 100644
index 00000000000..6355c4557ef
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/int_sideeffect.ll
@@ -0,0 +1,14 @@
+; RUN: opt -S < %s -instcombine | FileCheck %s
+
+declare void @llvm.sideeffect()
+
+; Store-to-load forwarding across a @llvm.sideeffect.
+
+; CHECK-LABEL: s2l
+; CHECK-NOT: load
+define float @s2l(float* %p) {
+ store float 0.0, float* %p
+ call void @llvm.sideeffect()
+ %t = load float, float* %p
+ ret float %t
+}
diff --git a/llvm/test/Transforms/LICM/int_sideeffect.ll b/llvm/test/Transforms/LICM/int_sideeffect.ll
new file mode 100644
index 00000000000..842efe56585
--- /dev/null
+++ b/llvm/test/Transforms/LICM/int_sideeffect.ll
@@ -0,0 +1,27 @@
+; RUN: opt -S < %s -licm | FileCheck %s
+
+declare void @llvm.sideeffect()
+
+; LICM across a @llvm.sideeffect.
+
+; CHECK-LABEL: licm
+; CHECK: load
+; CHECK: loop:
+; CHECK-NOT: load
+define float @licm(i64 %n, float* nocapture readonly %p) #0 {
+bb0:
+ br label %loop
+
+loop:
+ %i = phi i64 [ 0, %bb0 ], [ %t5, %loop ]
+ %sum = phi float [ 0.000000e+00, %bb0 ], [ %t4, %loop ]
+ call void @llvm.sideeffect()
+ %t3 = load float, float* %p
+ %t4 = fadd float %sum, %t3
+ %t5 = add i64 %i, 1
+ %t6 = icmp ult i64 %t5, %n
+ br i1 %t6, label %loop, label %bb2
+
+bb2:
+ ret float %t4
+}
diff --git a/llvm/test/Transforms/LoadStoreVectorizer/int_sideeffect.ll b/llvm/test/Transforms/LoadStoreVectorizer/int_sideeffect.ll
new file mode 100644
index 00000000000..07bdc9123f9
--- /dev/null
+++ b/llvm/test/Transforms/LoadStoreVectorizer/int_sideeffect.ll
@@ -0,0 +1,26 @@
+; RUN: opt -S < %s -load-store-vectorizer | FileCheck %s
+
+declare void @llvm.sideeffect()
+
+; load-store vectorization across a @llvm.sideeffect.
+
+; CHECK-LABEL: test
+; CHECK: load <4 x float>
+; CHECK: store <4 x float>
+define void @test(float* %p) {
+ %p0 = getelementptr float, float* %p, i64 0
+ %p1 = getelementptr float, float* %p, i64 1
+ %p2 = getelementptr float, float* %p, i64 2
+ %p3 = getelementptr float, float* %p, i64 3
+ %l0 = load float, float* %p0, align 16
+ %l1 = load float, float* %p1
+ %l2 = load float, float* %p2
+ call void @llvm.sideeffect()
+ %l3 = load float, float* %p3
+ store float %l0, float* %p0, align 16
+ call void @llvm.sideeffect()
+ store float %l1, float* %p1
+ store float %l2, float* %p2
+ store float %l3, float* %p3
+ ret void
+}
diff --git a/llvm/test/Transforms/LoopIdiom/int_sideeffect.ll b/llvm/test/Transforms/LoopIdiom/int_sideeffect.ll
new file mode 100644
index 00000000000..40acf3cbe2a
--- /dev/null
+++ b/llvm/test/Transforms/LoopIdiom/int_sideeffect.ll
@@ -0,0 +1,23 @@
+; RUN: opt -S < %s -loop-idiom | FileCheck %s
+
+declare void @llvm.sideeffect()
+
+; Loop idiom recognition across a @llvm.sideeffect.
+
+; CHECK-LABEL: zero
+; CHECK: llvm.memset
+define void @zero(float* %p, i64 %n) nounwind {
+bb7.lr.ph:
+ br label %bb7
+
+bb7:
+ %i.02 = phi i64 [ 0, %bb7.lr.ph ], [ %tmp13, %bb7 ]
+ %tmp10 = getelementptr inbounds float, float* %p, i64 %i.02
+ store float 0.000000e+00, float* %tmp10, align 4
+ %tmp13 = add i64 %i.02, 1
+ %tmp6 = icmp ult i64 %tmp13, %n
+ br i1 %tmp6, label %bb7, label %bb14
+
+bb14:
+ ret void
+}
diff --git a/llvm/test/Transforms/LoopVectorize/int_sideeffect.ll b/llvm/test/Transforms/LoopVectorize/int_sideeffect.ll
new file mode 100644
index 00000000000..ec72bed7c7b
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/int_sideeffect.ll
@@ -0,0 +1,24 @@
+; RUN: opt -S < %s -loop-vectorize -force-vector-width=4 | FileCheck %s
+
+declare void @llvm.sideeffect()
+
+; Vectorization across a @llvm.sideeffect.
+
+; CHECK-LABEL: store_ones
+; CHECK: store <4 x float>
+define void @store_ones(float* %p, i64 %n) nounwind {
+bb7.lr.ph:
+ br label %bb7
+
+bb7:
+ %i.02 = phi i64 [ 0, %bb7.lr.ph ], [ %tmp13, %bb7 ]
+ call void @llvm.sideeffect()
+ %tmp10 = getelementptr inbounds float, float* %p, i64 %i.02
+ store float 1.0, float* %tmp10, align 4
+ %tmp13 = add i64 %i.02, 1
+ %tmp6 = icmp ult i64 %tmp13, %n
+ br i1 %tmp6, label %bb7, label %bb14
+
+bb14:
+ ret void
+}
diff --git a/llvm/test/Transforms/NewGVN/int_sideeffect.ll b/llvm/test/Transforms/NewGVN/int_sideeffect.ll
new file mode 100644
index 00000000000..75a798d6f0a
--- /dev/null
+++ b/llvm/test/Transforms/NewGVN/int_sideeffect.ll
@@ -0,0 +1,27 @@
+; RUN: opt -S < %s -newgvn | FileCheck %s
+
+declare void @llvm.sideeffect()
+
+; Store-to-load forwarding across a @llvm.sideeffect.
+
+; CHECK-LABEL: s2l
+; CHECK-NOT: load
+define float @s2l(float* %p) {
+ store float 0.0, float* %p
+ call void @llvm.sideeffect()
+ %t = load float, float* %p
+ ret float %t
+}
+
+; Redundant load elimination across a @llvm.sideeffect.
+
+; CHECK-LABEL: rle
+; CHECK: load
+; CHECK-NOT: load
+define float @rle(float* %p) {
+ %r = load float, float* %p
+ call void @llvm.sideeffect()
+ %s = load float, float* %p
+ %t = fadd float %r, %s
+ ret float %t
+}
diff --git a/llvm/test/Transforms/SLPVectorizer/int_sideeffect.ll b/llvm/test/Transforms/SLPVectorizer/int_sideeffect.ll
new file mode 100644
index 00000000000..a6123c11d92
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/int_sideeffect.ll
@@ -0,0 +1,25 @@
+; RUN: opt -S < %s -slp-vectorizer -slp-max-reg-size=128 -slp-min-reg-size=128 | FileCheck %s
+
+declare void @llvm.sideeffect()
+
+; SLP vectorization across a @llvm.sideeffect.
+
+; CHECK-LABEL: test
+; CHECK: store <4 x float>
+define void @test(float* %p) {
+ %p0 = getelementptr float, float* %p, i64 0
+ %p1 = getelementptr float, float* %p, i64 1
+ %p2 = getelementptr float, float* %p, i64 2
+ %p3 = getelementptr float, float* %p, i64 3
+ %l0 = load float, float* %p0
+ %l1 = load float, float* %p1
+ %l2 = load float, float* %p2
+ call void @llvm.sideeffect()
+ %l3 = load float, float* %p3
+ store float %l0, float* %p0
+ call void @llvm.sideeffect()
+ store float %l1, float* %p1
+ store float %l2, float* %p2
+ store float %l3, float* %p3
+ ret void
+}
OpenPOWER on IntegriCloud