mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
[LangRef] Adjust guarantee for llvm.memcpy to also allow equal arguments.
This adjusts the description of `llvm.memcpy` to also allow operands to be equal. This is in line with what Clang currently expects. This change is intended to be temporary and followed by re-introduce a variant with the non-overlapping guarantee for cases where we can actually ensure that property in the front-end. See the links below for more details: http://lists.llvm.org/pipermail/cfe-dev/2020-August/066614.html and PR11763. Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D86815
This commit is contained in:
parent
39d0c7029b
commit
6276196b86
@ -12479,11 +12479,11 @@ very cleanly specified and it is unwise to depend on it.
|
||||
Semantics:
|
||||
""""""""""
|
||||
|
||||
The '``llvm.memcpy.*``' intrinsics copy a block of memory from the
|
||||
source location to the destination location, which are not allowed to
|
||||
overlap. It copies "len" bytes of memory over. If the argument is known
|
||||
to be aligned to some boundary, this can be specified as an attribute on
|
||||
the argument.
|
||||
The '``llvm.memcpy.*``' intrinsics copy a block of memory from the source
|
||||
location to the destination location, which must either be equal or
|
||||
non-overlapping. It copies "len" bytes of memory over. If the argument is known
|
||||
to be aligned to some boundary, this can be specified as an attribute on the
|
||||
argument.
|
||||
|
||||
If "len" is 0, the pointers may be NULL, dangling, ``undef``, or ``poison``
|
||||
pointers. However, they must still be appropriately aligned.
|
||||
|
@ -975,22 +975,14 @@ ModRefInfo BasicAAResult::getModRefInfo(const CallBase *Call,
|
||||
return ModRefInfo::NoModRef;
|
||||
}
|
||||
|
||||
// The semantics of memcpy intrinsics forbid overlap between their respective
|
||||
// operands, i.e., source and destination of any given memcpy must no-alias.
|
||||
// If Loc must-aliases either one of these two locations, then it necessarily
|
||||
// no-aliases the other.
|
||||
// The semantics of memcpy intrinsics either exactly overlap or do not
|
||||
// overlap, i.e., source and destination of any given memcpy are either
|
||||
// no-alias or must-alias.
|
||||
if (auto *Inst = dyn_cast<AnyMemCpyInst>(Call)) {
|
||||
AliasResult SrcAA, DestAA;
|
||||
|
||||
if ((SrcAA = getBestAAResults().alias(MemoryLocation::getForSource(Inst),
|
||||
Loc, AAQI)) == MustAlias)
|
||||
// Loc is exactly the memcpy source thus disjoint from memcpy dest.
|
||||
return ModRefInfo::Ref;
|
||||
if ((DestAA = getBestAAResults().alias(MemoryLocation::getForDest(Inst),
|
||||
Loc, AAQI)) == MustAlias)
|
||||
// The converse case.
|
||||
return ModRefInfo::Mod;
|
||||
|
||||
AliasResult SrcAA =
|
||||
getBestAAResults().alias(MemoryLocation::getForSource(Inst), Loc, AAQI);
|
||||
AliasResult DestAA =
|
||||
getBestAAResults().alias(MemoryLocation::getForDest(Inst), Loc, AAQI);
|
||||
// It's also possible for Loc to alias both src and dest, or neither.
|
||||
ModRefInfo rv = ModRefInfo::NoModRef;
|
||||
if (SrcAA != NoAlias)
|
||||
|
@ -14,8 +14,8 @@ define void @test1(i8* %P, i8* %Q) nounwind ssp {
|
||||
; CHECK: MayAlias: i8* %P, i8* %Q
|
||||
; CHECK: NoModRef: Ptr: i8* %P <-> tail call void @llvm.assume(i1 true)
|
||||
; CHECK: NoModRef: Ptr: i8* %Q <-> tail call void @llvm.assume(i1 true)
|
||||
; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: NoModRef: tail call void @llvm.assume(i1 true) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: NoModRef: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false) <-> tail call void @llvm.assume(i1 true)
|
||||
}
|
||||
|
@ -17,12 +17,12 @@ define void @test2(i8* %P, i8* %Q) #3 {
|
||||
; CHECK-LABEL: Function: test2:
|
||||
|
||||
; CHECK: MayAlias: i8* %P, i8* %Q
|
||||
; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Just Mod: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Just Mod: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
}
|
||||
|
||||
define void @test2_atomic(i8* %P, i8* %Q) #3 {
|
||||
@ -33,12 +33,12 @@ define void @test2_atomic(i8* %P, i8* %Q) #3 {
|
||||
; CHECK-LABEL: Function: test2_atomic:
|
||||
|
||||
; CHECK: MayAlias: i8* %P, i8* %Q
|
||||
; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %P, i8* align 1 %Q, i64 12, i32 1)
|
||||
; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %P, i8* align 1 %Q, i64 12, i32 1)
|
||||
; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %P, i8* align 1 %Q, i64 12, i32 1)
|
||||
; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %P, i8* align 1 %Q, i64 12, i32 1)
|
||||
; CHECK: Just Mod: tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %P, i8* align 1 %Q, i64 12, i32 1) <-> tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %P, i8* align 1 %Q, i64 12, i32 1)
|
||||
; CHECK: Just Mod: tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %P, i8* align 1 %Q, i64 12, i32 1) <-> tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %P, i8* align 1 %Q, i64 12, i32 1)
|
||||
; CHECK: Both ModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %P, i8* align 1 %Q, i64 12, i32 1)
|
||||
; CHECK: Both ModRef: Ptr: i8* %Q <-> tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %P, i8* align 1 %Q, i64 12, i32 1)
|
||||
; CHECK: Both ModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %P, i8* align 1 %Q, i64 12, i32 1)
|
||||
; CHECK: Both ModRef: Ptr: i8* %Q <-> tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %P, i8* align 1 %Q, i64 12, i32 1)
|
||||
; CHECK: Both ModRef: tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %P, i8* align 1 %Q, i64 12, i32 1) <-> tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %P, i8* align 1 %Q, i64 12, i32 1)
|
||||
; CHECK: Both ModRef: tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %P, i8* align 1 %Q, i64 12, i32 1) <-> tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %P, i8* align 1 %Q, i64 12, i32 1)
|
||||
}
|
||||
|
||||
define void @test2a(i8* noalias %P, i8* noalias %Q) #3 {
|
||||
@ -149,12 +149,12 @@ define void @test3(i8* %P, i8* %Q) #3 {
|
||||
; CHECK-LABEL: Function: test3:
|
||||
|
||||
; CHECK: MayAlias: i8* %P, i8* %Q
|
||||
; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 8, i1 false)
|
||||
; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 8, i1 false)
|
||||
; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Just Mod: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 8, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Just Mod: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 8, i1 false)
|
||||
; CHECK: Both ModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 8, i1 false)
|
||||
; CHECK: Both ModRef: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 8, i1 false)
|
||||
; CHECK: Both ModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 8, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 8, i1 false)
|
||||
}
|
||||
|
||||
define void @test3a(i8* noalias %P, i8* noalias %Q) #3 {
|
||||
@ -199,14 +199,14 @@ define void @test5(i8* %P, i8* %Q, i8* %R) #3 {
|
||||
; CHECK: MayAlias: i8* %P, i8* %Q
|
||||
; CHECK: MayAlias: i8* %P, i8* %R
|
||||
; CHECK: MayAlias: i8* %Q, i8* %R
|
||||
; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: Ptr: i8* %R <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %R, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %R, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %R, i64 12, i1 false)
|
||||
; CHECK: Just Ref: Ptr: i8* %R <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %R, i64 12, i1 false)
|
||||
; CHECK: Just Mod: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %R, i64 12, i1 false)
|
||||
; CHECK: Just Mod: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %R, i64 12, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: Ptr: i8* %R <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %R, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %R, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %R, i64 12, i1 false) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
}
|
||||
|
||||
define void @test5a(i8* noalias %P, i8* noalias %Q, i8* noalias %R) nounwind ssp {
|
||||
|
@ -14,8 +14,8 @@ define void @test1(i8* %P, i8* %Q) {
|
||||
|
||||
; CHECK: Just Ref: Ptr: i8* %P <-> tail call void (i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
|
||||
; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void (i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
|
||||
; CHECK: Just Mod: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Both ModRef: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Just Ref: tail call void (i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ] <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
; CHECK: Just Mod: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false) <-> tail call void (i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ define void @source_clobber(i8* %a, i8* %b) {
|
||||
; CHECK-LABEL: @source_clobber(
|
||||
; CHECK-NEXT: ; 1 = MemoryDef(liveOnEntry)
|
||||
; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a, i8* %b, i64 128, i1 false)
|
||||
; CHECK-NEXT: ; MemoryUse(liveOnEntry)
|
||||
; CHECK-NEXT: ; MemoryUse(1) MayAlias
|
||||
; CHECK-NEXT: [[X:%.*]] = load i8, i8* %b
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
|
@ -68,13 +68,12 @@ define void @test17v(i8* %P, i8* %Q) nounwind ssp {
|
||||
ret void
|
||||
}
|
||||
|
||||
; According to the current LangRef, memcpy's source and destination cannot
|
||||
; overlap, hence the first memcpy is dead.
|
||||
;
|
||||
; Previously this was not allowed (PR8728), also discussed in PR11763.
|
||||
; See PR11763 - LLVM allows memcpy's source and destination to be equal (but not
|
||||
; inequal and overlapping).
|
||||
define void @test18(i8* %P, i8* %Q, i8* %R) nounwind ssp {
|
||||
; CHECK-LABEL: @test18(
|
||||
; CHECK-NEXT: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[P:%.*]], i8* [[R:%.*]], i64 12, i1 false)
|
||||
; CHECK-NEXT: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[P:%.*]], i8* [[Q:%.*]], i64 12, i1 false)
|
||||
; CHECK-NEXT: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[P]], i8* [[R:%.*]], i64 12, i1 false)
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false)
|
||||
@ -84,7 +83,8 @@ define void @test18(i8* %P, i8* %Q, i8* %R) nounwind ssp {
|
||||
|
||||
define void @test18_atomic(i8* %P, i8* %Q, i8* %R) nounwind ssp {
|
||||
; CHECK-LABEL: @test18_atomic(
|
||||
; CHECK-NEXT: tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 [[P:%.*]], i8* align 1 [[R:%.*]], i64 12, i32 1)
|
||||
; CHECK-NEXT: tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 [[P:%.*]], i8* align 1 [[Q:%.*]], i64 12, i32 1)
|
||||
; CHECK-NEXT: tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 [[P]], i8* align 1 [[R:%.*]], i64 12, i32 1)
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %P, i8* align 1 %Q, i64 12, i32 1)
|
||||
|
@ -554,10 +554,12 @@ define void @test37_atomic(i8* %P, i8* %Q, i8* %R) {
|
||||
ret void
|
||||
}
|
||||
|
||||
; The memmove is dead, because memcpy arguments cannot overlap.
|
||||
; See PR11763 - LLVM allows memcpy's source and destination to be equal (but not
|
||||
; inequal and overlapping).
|
||||
define void @test38(i8* %P, i8* %Q, i8* %R) {
|
||||
; CHECK-LABEL: @test38(
|
||||
; CHECK-NEXT: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[P:%.*]], i8* [[R:%.*]], i64 12, i1 false)
|
||||
; CHECK-NEXT: tail call void @llvm.memmove.p0i8.p0i8.i64(i8* [[P:%.*]], i8* [[Q:%.*]], i64 12, i1 false)
|
||||
; CHECK-NEXT: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[P]], i8* [[R:%.*]], i64 12, i1 false)
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
|
||||
@ -566,10 +568,12 @@ define void @test38(i8* %P, i8* %Q, i8* %R) {
|
||||
ret void
|
||||
}
|
||||
|
||||
; The memmove is dead, because memcpy arguments cannot overlap.
|
||||
; See PR11763 - LLVM allows memcpy's source and destination to be equal (but not
|
||||
; inequal and overlapping).
|
||||
define void @test38_atomic(i8* %P, i8* %Q, i8* %R) {
|
||||
; CHECK-LABEL: @test38_atomic(
|
||||
; CHECK-NEXT: tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 [[P:%.*]], i8* align 1 [[R:%.*]], i64 12, i32 1)
|
||||
; CHECK-NEXT: tail call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 [[P:%.*]], i8* align 1 [[Q:%.*]], i64 12, i32 1)
|
||||
; CHECK-NEXT: tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 [[P]], i8* align 1 [[R:%.*]], i64 12, i32 1)
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user