Revert "[Intrinsics][PreISelInstrinsicLowering] llvm.memcpy.inline length no …"
This reverts commit 522fd53838d577add8c19b5eccccae756fd27899.
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 40c8b7f..a04b576 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -15026,7 +15026,7 @@
""""""""""
The first argument is a pointer to the destination, the second is a
-pointer to the source. The third argument is an integer argument
+pointer to the source. The third argument is a constant integer argument
specifying the number of bytes to copy, and the fourth is a
boolean indicating a volatile access.
diff --git a/llvm/include/llvm/IR/IntrinsicInst.h b/llvm/include/llvm/IR/IntrinsicInst.h
index fe3f92d..a2ecf62 100644
--- a/llvm/include/llvm/IR/IntrinsicInst.h
+++ b/llvm/include/llvm/IR/IntrinsicInst.h
@@ -1296,6 +1296,9 @@
/// This class wraps the llvm.memcpy.inline intrinsic.
class MemCpyInlineInst : public MemCpyInst {
public:
+ ConstantInt *getLength() const {
+ return cast<ConstantInt>(MemCpyInst::getLength());
+ }
// Methods for support type inquiry through isa, cast, and dyn_cast:
static bool classof(const IntrinsicInst *I) {
return I->getIntrinsicID() == Intrinsic::memcpy_inline;
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index 9d04256..01e379d 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -966,6 +966,7 @@
// Memcpy semantic that is guaranteed to be inlined.
// In particular this means that the generated code is not allowed to call any
// external function.
+// The third argument (specifying the size) must be a constant.
def int_memcpy_inline
: Intrinsic<[],
[llvm_anyptr_ty, llvm_anyptr_ty, llvm_anyint_ty, llvm_i1_ty],
@@ -973,7 +974,7 @@
NoCapture<ArgIndex<0>>, NoCapture<ArgIndex<1>>,
NoAlias<ArgIndex<0>>, NoAlias<ArgIndex<1>>,
WriteOnly<ArgIndex<0>>, ReadOnly<ArgIndex<1>>,
- ImmArg<ArgIndex<3>>]>;
+ ImmArg<ArgIndex<2>>, ImmArg<ArgIndex<3>>]>;
def int_memmove : Intrinsic<[],
[llvm_anyptr_ty, llvm_anyptr_ty, llvm_anyint_ty,
diff --git a/llvm/lib/Analysis/Lint.cpp b/llvm/lib/Analysis/Lint.cpp
index a44d5a3..496308a 100644
--- a/llvm/lib/Analysis/Lint.cpp
+++ b/llvm/lib/Analysis/Lint.cpp
@@ -290,8 +290,7 @@
// TODO: Check more intrinsics
- case Intrinsic::memcpy:
- case Intrinsic::memcpy_inline: {
+ case Intrinsic::memcpy: {
MemCpyInst *MCI = cast<MemCpyInst>(&I);
visitMemoryReference(I, MemoryLocation::getForDest(MCI),
MCI->getDestAlign(), nullptr, MemRef::Write);
@@ -312,6 +311,23 @@
"Undefined behavior: memcpy source and destination overlap", &I);
break;
}
+ case Intrinsic::memcpy_inline: {
+ MemCpyInlineInst *MCII = cast<MemCpyInlineInst>(&I);
+ const uint64_t Size = MCII->getLength()->getValue().getLimitedValue();
+ visitMemoryReference(I, MemoryLocation::getForDest(MCII),
+ MCII->getDestAlign(), nullptr, MemRef::Write);
+ visitMemoryReference(I, MemoryLocation::getForSource(MCII),
+ MCII->getSourceAlign(), nullptr, MemRef::Read);
+
+ // Check that the memcpy arguments don't overlap. The AliasAnalysis API
+ // isn't expressive enough for what we really want to do. Known partial
+ // overlap is not distinguished from the case where nothing is known.
+ const LocationSize LS = LocationSize::precise(Size);
+ Check(AA->alias(MCII->getSource(), LS, MCII->getDest(), LS) !=
+ AliasResult::MustAlias,
+ "Undefined behavior: memcpy source and destination overlap", &I);
+ break;
+ }
case Intrinsic::memmove: {
MemMoveInst *MMI = cast<MemMoveInst>(&I);
visitMemoryReference(I, MemoryLocation::getForDest(MMI),
diff --git a/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp b/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp
index 19950f3..8572cdc 100644
--- a/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp
+++ b/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp
@@ -230,21 +230,6 @@
break;
}
- case Intrinsic::memcpy_inline: {
- // Only expand llvm.memcpy.inline with non-constant length in this
- // codepath, leaving the current SelectionDAG expansion for constant
- // length memcpy intrinsics undisturbed.
- auto *Memcpy = cast<MemCpyInlineInst>(Inst);
- if (isa<ConstantInt>(Memcpy->getLength()))
- break;
-
- Function *ParentFunc = Memcpy->getFunction();
- const TargetTransformInfo &TTI = LookupTTI(*ParentFunc);
- expandMemCpyAsLoop(Memcpy, TTI);
- Changed = true;
- Memcpy->eraseFromParent();
- break;
- }
case Intrinsic::memmove: {
auto *Memmove = cast<MemMoveInst>(Inst);
Function *ParentFunc = Memmove->getFunction();
@@ -306,7 +291,6 @@
default:
break;
case Intrinsic::memcpy:
- case Intrinsic::memcpy_inline:
case Intrinsic::memmove:
case Intrinsic::memset:
case Intrinsic::memset_inline:
diff --git a/llvm/test/Transforms/PreISelIntrinsicLowering/X86/memcpy-inline-non-constant-len.ll b/llvm/test/Transforms/PreISelIntrinsicLowering/X86/memcpy-inline-non-constant-len.ll
deleted file mode 100644
index a4e0499..0000000
--- a/llvm/test/Transforms/PreISelIntrinsicLowering/X86/memcpy-inline-non-constant-len.ll
+++ /dev/null
@@ -1,49 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
-; RUN: opt -mtriple=x86_64-pc-linux-gnu -passes=pre-isel-intrinsic-lowering -S -o - %s | FileCheck %s
-
-; Constant length memcpy.inline should be left unmodified.
-define void @memcpy_32(ptr %dst, ptr %src) nounwind {
-; CHECK-LABEL: define void @memcpy_32(
-; CHECK-SAME: ptr [[DST:%.*]], ptr [[SRC:%.*]]) #[[ATTR0:[0-9]+]] {
-; CHECK-NEXT: call void @llvm.memcpy.inline.p0.p0.i64(ptr [[DST]], ptr [[SRC]], i64 32, i1 false)
-; CHECK-NEXT: tail call void @llvm.memcpy.inline.p0.p0.i64(ptr [[DST]], ptr [[SRC]], i64 32, i1 true)
-; CHECK-NEXT: ret void
-;
- call void @llvm.memcpy.inline.p0.p0.i64(ptr %dst, ptr %src, i64 32, i1 0)
- tail call void @llvm.memcpy.inline.p0.p0.i64(ptr %dst, ptr %src, i64 32, i1 1)
- ret void
-}
-
-define void @memcpy_x(ptr %dst, ptr %src, i64 %x) nounwind {
-; CHECK-LABEL: define void @memcpy_x(
-; CHECK-SAME: ptr [[DST:%.*]], ptr [[SRC:%.*]], i64 [[X:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[X]], 0
-; CHECK-NEXT: br i1 [[TMP1]], label %[[LOOP_MEMCPY_EXPANSION:.*]], label %[[POST_LOOP_MEMCPY_EXPANSION:.*]]
-; CHECK: [[LOOP_MEMCPY_EXPANSION]]:
-; CHECK-NEXT: [[LOOP_INDEX:%.*]] = phi i64 [ 0, [[TMP0:%.*]] ], [ [[TMP5:%.*]], %[[LOOP_MEMCPY_EXPANSION]] ]
-; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 [[LOOP_INDEX]]
-; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[TMP2]], align 1
-; CHECK-NEXT: [[TMP4:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 [[LOOP_INDEX]]
-; CHECK-NEXT: store i8 [[TMP3]], ptr [[TMP4]], align 1
-; CHECK-NEXT: [[TMP5]] = add i64 [[LOOP_INDEX]], 1
-; CHECK-NEXT: [[TMP6:%.*]] = icmp ult i64 [[TMP5]], [[X]]
-; CHECK-NEXT: br i1 [[TMP6]], label %[[LOOP_MEMCPY_EXPANSION]], label %[[POST_LOOP_MEMCPY_EXPANSION]]
-; CHECK: [[POST_LOOP_MEMCPY_EXPANSION]]:
-; CHECK-NEXT: [[TMP7:%.*]] = icmp ne i64 [[X]], 0
-; CHECK-NEXT: br i1 [[TMP7]], label %[[LOOP_MEMCPY_EXPANSION2:.*]], label %[[POST_LOOP_MEMCPY_EXPANSION1:.*]]
-; CHECK: [[LOOP_MEMCPY_EXPANSION2]]:
-; CHECK-NEXT: [[LOOP_INDEX3:%.*]] = phi i64 [ 0, %[[POST_LOOP_MEMCPY_EXPANSION]] ], [ [[TMP11:%.*]], %[[LOOP_MEMCPY_EXPANSION2]] ]
-; CHECK-NEXT: [[TMP8:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 [[LOOP_INDEX3]]
-; CHECK-NEXT: [[TMP9:%.*]] = load volatile i8, ptr [[TMP8]], align 1
-; CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 [[LOOP_INDEX3]]
-; CHECK-NEXT: store volatile i8 [[TMP9]], ptr [[TMP10]], align 1
-; CHECK-NEXT: [[TMP11]] = add i64 [[LOOP_INDEX3]], 1
-; CHECK-NEXT: [[TMP12:%.*]] = icmp ult i64 [[TMP11]], [[X]]
-; CHECK-NEXT: br i1 [[TMP12]], label %[[LOOP_MEMCPY_EXPANSION2]], label %[[POST_LOOP_MEMCPY_EXPANSION1]]
-; CHECK: [[POST_LOOP_MEMCPY_EXPANSION1]]:
-; CHECK-NEXT: ret void
-;
- call void @llvm.memcpy.inline.p0.p0.i64(ptr %dst, ptr %src, i64 %x, i1 0)
- tail call void @llvm.memcpy.inline.p0.p0.i64(ptr %dst, ptr %src, i64 %x, i1 1)
- ret void
-}
diff --git a/llvm/test/Verifier/intrinsic-immarg.ll b/llvm/test/Verifier/intrinsic-immarg.ll
index ad70b17..b1b9f7e 100644
--- a/llvm/test/Verifier/intrinsic-immarg.ll
+++ b/llvm/test/Verifier/intrinsic-immarg.ll
@@ -36,6 +36,14 @@
ret void
}
+define void @memcpy_inline_variable_size(ptr %dest, ptr %src, i32 %size) {
+ ; CHECK: immarg operand has non-immediate parameter
+ ; CHECK-NEXT: i32 %size
+ ; CHECK-NEXT: call void @llvm.memcpy.inline.p0.p0.i32(ptr %dest, ptr %src, i32 %size, i1 true)
+ call void @llvm.memcpy.inline.p0.p0.i32(ptr %dest, ptr %src, i32 %size, i1 true)
+ ret void
+}
+
declare void @llvm.memmove.p0.p0.i32(ptr nocapture, ptr nocapture, i32, i1)
define void @memmove(ptr %dest, ptr %src, i1 %is.volatile) {
; CHECK: immarg operand has non-immediate parameter