Skip to content

Commit 57226ef

Browse files
author
Daniel Neilson
committedJul 12, 2017
Add element atomic memmove intrinsic
Summary: Continuing the work from https://reviews.llvm.org/D33240, this change introduces an element unordered-atomic memmove intrinsic. This intrinsic is essentially memmove with the implementation requirement that all loads/stores used for the copy are done with unordered-atomic loads/stores of a given element size. Reviewers: eli.friedman, reames, mkazantsev, skatkov Reviewed By: reames Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D34884 llvm-svn: 307796
1 parent e092634 commit 57226ef

File tree

9 files changed

+379
-0
lines changed

9 files changed

+379
-0
lines changed
 

‎llvm/docs/LangRef.rst

+79
Original file line numberDiff line numberDiff line change
@@ -10282,6 +10282,8 @@ overlap. It copies "len" bytes of memory over. If the argument is known
1028210282
to be aligned to some boundary, this can be specified as the fourth
1028310283
argument, otherwise it should be set to 0 or 1 (both meaning no alignment).
1028410284

10285+
.. _int_memmove:
10286+
1028510287
'``llvm.memmove``' Intrinsic
1028610288
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1028710289

@@ -14178,4 +14180,81 @@ In the most general case call to the '``llvm.memcpy.element.unordered.atomic.*``
1417814180
lowered to a call to the symbol ``__llvm_memcpy_element_unordered_atomic_*``. Where '*'
1417914181
is replaced with an actual element size.
1418014182

14183+
Optimizer is allowed to inline memory copy when it's profitable to do so.
14184+
14185+
'``llvm.memmove.element.unordered.atomic``' Intrinsic
14186+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14187+
14188+
Syntax:
14189+
"""""""
14190+
14191+
This is an overloaded intrinsic. You can use
14192+
``llvm.memmove.element.unordered.atomic`` on any integer bit width and for
14193+
different address spaces. Not all targets support all bit widths however.
14194+
14195+
::
14196+
14197+
declare void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* <dest>,
14198+
i8* <src>,
14199+
i32 <len>,
14200+
i32 <element_size>)
14201+
declare void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i64(i8* <dest>,
14202+
i8* <src>,
14203+
i64 <len>,
14204+
i32 <element_size>)
14205+
14206+
Overview:
14207+
"""""""""
14208+
14209+
The '``llvm.memmove.element.unordered.atomic.*``' intrinsic is a specialization
14210+
of the '``llvm.memmove.*``' intrinsic. It differs in that the ``dest`` and
14211+
``src`` are treated as arrays with elements that are exactly ``element_size``
14212+
bytes, and the copy between buffers uses a sequence of
14213+
:ref:`unordered atomic <ordering>` load/store operations that are a positive
14214+
integer multiple of the ``element_size`` in size.
14215+
14216+
Arguments:
14217+
""""""""""
14218+
14219+
The first three arguments are the same as they are in the
14220+
:ref:`@llvm.memmove <int_memmove>` intrinsic, with the added constraint that
14221+
``len`` is required to be a positive integer multiple of the ``element_size``.
14222+
If ``len`` is not a positive integer multiple of ``element_size``, then the
14223+
behaviour of the intrinsic is undefined.
14224+
14225+
``element_size`` must be a compile-time constant positive power of two no
14226+
greater than a target-specific atomic access size limit.
14227+
14228+
For each of the input pointers the ``align`` parameter attribute must be
14229+
specified. It must be a power of two no less than the ``element_size``. Caller
14230+
guarantees that both the source and destination pointers are aligned to that
14231+
boundary.
14232+
14233+
Semantics:
14234+
""""""""""
14235+
14236+
The '``llvm.memmove.element.unordered.atomic.*``' intrinsic copies ``len`` bytes
14237+
of memory from the source location to the destination location. These locations
14238+
are allowed to overlap. The memory copy is performed as a sequence of load/store
14239+
operations where each access is guaranteed to be a multiple of ``element_size``
14240+
bytes wide and aligned at an ``element_size`` boundary.
14241+
14242+
The order of the copy is unspecified. The same value may be read from the source
14243+
buffer many times, but only one write is issued to the destination buffer per
14244+
element. It is well defined to have concurrent reads and writes to both source
14245+
and destination provided those reads and writes are unordered atomic when
14246+
specified.
14247+
14248+
This intrinsic does not provide any additional ordering guarantees over those
14249+
provided by a set of unordered loads from the source location and stores to the
14250+
destination.
14251+
14252+
Lowering:
14253+
"""""""""
14254+
14255+
In the most general case call to the
14256+
'``llvm.memmove.element.unordered.atomic.*``' is lowered to a call to the symbol
14257+
``__llvm_memmove_element_unordered_atomic_*``. Where '*' is replaced with an
14258+
actual element size.
14259+
1418114260
The optimizer is allowed to inline the memory copy when it's profitable to do so.

‎llvm/include/llvm/CodeGen/RuntimeLibcalls.h

+11
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,12 @@ namespace RTLIB {
340340
MEMCPY_ELEMENT_UNORDERED_ATOMIC_8,
341341
MEMCPY_ELEMENT_UNORDERED_ATOMIC_16,
342342

343+
MEMMOVE_ELEMENT_UNORDERED_ATOMIC_1,
344+
MEMMOVE_ELEMENT_UNORDERED_ATOMIC_2,
345+
MEMMOVE_ELEMENT_UNORDERED_ATOMIC_4,
346+
MEMMOVE_ELEMENT_UNORDERED_ATOMIC_8,
347+
MEMMOVE_ELEMENT_UNORDERED_ATOMIC_16,
348+
343349
// EXCEPTION HANDLING
344350
UNWIND_RESUME,
345351

@@ -515,6 +521,11 @@ namespace RTLIB {
515521
/// MEMCPY_ELEMENT_UNORDERED_ATOMIC_* value for the given element size or
516522
/// UNKNOW_LIBCALL if there is none.
517523
Libcall getMEMCPY_ELEMENT_UNORDERED_ATOMIC(uint64_t ElementSize);
524+
525+
/// getMEMMOVE_ELEMENT_UNORDERED_ATOMIC - Return
526+
/// MEMMOVE_ELEMENT_UNORDERED_ATOMIC_* value for the given element size or
527+
/// UNKNOW_LIBCALL if there is none.
528+
Libcall getMEMMOVE_ELEMENT_UNORDERED_ATOMIC(uint64_t ElementSize);
518529
}
519530
}
520531

‎llvm/include/llvm/IR/IntrinsicInst.h

+89
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,95 @@ namespace llvm {
296296
}
297297
};
298298

299+
class ElementUnorderedAtomicMemMoveInst : public IntrinsicInst {
300+
private:
301+
enum { ARG_DEST = 0, ARG_SOURCE = 1, ARG_LENGTH = 2, ARG_ELEMENTSIZE = 3 };
302+
303+
public:
304+
Value *getRawDest() const {
305+
return const_cast<Value *>(getArgOperand(ARG_DEST));
306+
}
307+
const Use &getRawDestUse() const { return getArgOperandUse(ARG_DEST); }
308+
Use &getRawDestUse() { return getArgOperandUse(ARG_DEST); }
309+
310+
/// Return the arguments to the instruction.
311+
Value *getRawSource() const {
312+
return const_cast<Value *>(getArgOperand(ARG_SOURCE));
313+
}
314+
const Use &getRawSourceUse() const { return getArgOperandUse(ARG_SOURCE); }
315+
Use &getRawSourceUse() { return getArgOperandUse(ARG_SOURCE); }
316+
317+
Value *getLength() const {
318+
return const_cast<Value *>(getArgOperand(ARG_LENGTH));
319+
}
320+
const Use &getLengthUse() const { return getArgOperandUse(ARG_LENGTH); }
321+
Use &getLengthUse() { return getArgOperandUse(ARG_LENGTH); }
322+
323+
bool isVolatile() const { return false; }
324+
325+
Value *getRawElementSizeInBytes() const {
326+
return const_cast<Value *>(getArgOperand(ARG_ELEMENTSIZE));
327+
}
328+
329+
ConstantInt *getElementSizeInBytesCst() const {
330+
return cast<ConstantInt>(getRawElementSizeInBytes());
331+
}
332+
333+
uint32_t getElementSizeInBytes() const {
334+
return getElementSizeInBytesCst()->getZExtValue();
335+
}
336+
337+
/// This is just like getRawDest, but it strips off any cast
338+
/// instructions that feed it, giving the original input. The returned
339+
/// value is guaranteed to be a pointer.
340+
Value *getDest() const { return getRawDest()->stripPointerCasts(); }
341+
342+
/// This is just like getRawSource, but it strips off any cast
343+
/// instructions that feed it, giving the original input. The returned
344+
/// value is guaranteed to be a pointer.
345+
Value *getSource() const { return getRawSource()->stripPointerCasts(); }
346+
347+
unsigned getDestAddressSpace() const {
348+
return cast<PointerType>(getRawDest()->getType())->getAddressSpace();
349+
}
350+
351+
unsigned getSourceAddressSpace() const {
352+
return cast<PointerType>(getRawSource()->getType())->getAddressSpace();
353+
}
354+
355+
/// Set the specified arguments of the instruction.
356+
void setDest(Value *Ptr) {
357+
assert(getRawDest()->getType() == Ptr->getType() &&
358+
"setDest called with pointer of wrong type!");
359+
setArgOperand(ARG_DEST, Ptr);
360+
}
361+
362+
void setSource(Value *Ptr) {
363+
assert(getRawSource()->getType() == Ptr->getType() &&
364+
"setSource called with pointer of wrong type!");
365+
setArgOperand(ARG_SOURCE, Ptr);
366+
}
367+
368+
void setLength(Value *L) {
369+
assert(getLength()->getType() == L->getType() &&
370+
"setLength called with value of wrong type!");
371+
setArgOperand(ARG_LENGTH, L);
372+
}
373+
374+
void setElementSizeInBytes(Constant *V) {
375+
assert(V->getType() == Type::getInt8Ty(getContext()) &&
376+
"setElementSizeInBytes called with value of wrong type!");
377+
setArgOperand(ARG_ELEMENTSIZE, V);
378+
}
379+
380+
static inline bool classof(const IntrinsicInst *I) {
381+
return I->getIntrinsicID() == Intrinsic::memmove_element_unordered_atomic;
382+
}
383+
static inline bool classof(const Value *V) {
384+
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
385+
}
386+
};
387+
299388
/// This is the common base class for memset/memcpy/memmove.
300389
class MemIntrinsic : public IntrinsicInst {
301390
public:

‎llvm/include/llvm/IR/Intrinsics.td

+12
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,18 @@ def int_memcpy_element_unordered_atomic
873873
ReadOnly<1>
874874
]>;
875875

876+
// @llvm.memmove.element.unordered.atomic.*(dest, src, length, elementsize)
877+
def int_memmove_element_unordered_atomic
878+
: Intrinsic<[],
879+
[
880+
llvm_anyptr_ty, llvm_anyptr_ty, llvm_anyint_ty, llvm_i32_ty
881+
],
882+
[
883+
IntrArgMemOnly, NoCapture<0>, NoCapture<1>, WriteOnly<0>,
884+
ReadOnly<1>
885+
]>;
886+
887+
876888
//===------------------------ Reduction Intrinsics ------------------------===//
877889
//
878890
def int_experimental_vector_reduce_fadd : Intrinsic<[llvm_anyfloat_ty],

‎llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

+38
Original file line numberDiff line numberDiff line change
@@ -4994,6 +4994,44 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
49944994
DAG.setRoot(CallResult.second);
49954995
return nullptr;
49964996
}
4997+
case Intrinsic::memmove_element_unordered_atomic: {
4998+
auto &MI = cast<ElementUnorderedAtomicMemMoveInst>(I);
4999+
SDValue Dst = getValue(MI.getRawDest());
5000+
SDValue Src = getValue(MI.getRawSource());
5001+
SDValue Length = getValue(MI.getLength());
5002+
5003+
// Emit a library call.
5004+
TargetLowering::ArgListTy Args;
5005+
TargetLowering::ArgListEntry Entry;
5006+
Entry.Ty = DAG.getDataLayout().getIntPtrType(*DAG.getContext());
5007+
Entry.Node = Dst;
5008+
Args.push_back(Entry);
5009+
5010+
Entry.Node = Src;
5011+
Args.push_back(Entry);
5012+
5013+
Entry.Ty = MI.getLength()->getType();
5014+
Entry.Node = Length;
5015+
Args.push_back(Entry);
5016+
5017+
uint64_t ElementSizeConstant = MI.getElementSizeInBytes();
5018+
RTLIB::Libcall LibraryCall =
5019+
RTLIB::getMEMMOVE_ELEMENT_UNORDERED_ATOMIC(ElementSizeConstant);
5020+
if (LibraryCall == RTLIB::UNKNOWN_LIBCALL)
5021+
report_fatal_error("Unsupported element size");
5022+
5023+
TargetLowering::CallLoweringInfo CLI(DAG);
5024+
CLI.setDebugLoc(sdl).setChain(getRoot()).setLibCallee(
5025+
TLI.getLibcallCallingConv(LibraryCall),
5026+
Type::getVoidTy(*DAG.getContext()),
5027+
DAG.getExternalSymbol(TLI.getLibcallName(LibraryCall),
5028+
TLI.getPointerTy(DAG.getDataLayout())),
5029+
std::move(Args));
5030+
5031+
std::pair<SDValue, SDValue> CallResult = TLI.LowerCallTo(CLI);
5032+
DAG.setRoot(CallResult.second);
5033+
return nullptr;
5034+
}
49975035
case Intrinsic::dbg_declare: {
49985036
const DbgDeclareInst &DI = cast<DbgDeclareInst>(I);
49995037
DILocalVariable *Variable = DI.getVariable();

‎llvm/lib/CodeGen/TargetLoweringBase.cpp

+27
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,16 @@ static void InitLibcallNames(const char **Names, const Triple &TT) {
384384
"__llvm_memcpy_element_unordered_atomic_8";
385385
Names[RTLIB::MEMCPY_ELEMENT_UNORDERED_ATOMIC_16] =
386386
"__llvm_memcpy_element_unordered_atomic_16";
387+
Names[RTLIB::MEMMOVE_ELEMENT_UNORDERED_ATOMIC_1] =
388+
"__llvm_memmove_element_unordered_atomic_1";
389+
Names[RTLIB::MEMMOVE_ELEMENT_UNORDERED_ATOMIC_2] =
390+
"__llvm_memmove_element_unordered_atomic_2";
391+
Names[RTLIB::MEMMOVE_ELEMENT_UNORDERED_ATOMIC_4] =
392+
"__llvm_memmove_element_unordered_atomic_4";
393+
Names[RTLIB::MEMMOVE_ELEMENT_UNORDERED_ATOMIC_8] =
394+
"__llvm_memmove_element_unordered_atomic_8";
395+
Names[RTLIB::MEMMOVE_ELEMENT_UNORDERED_ATOMIC_16] =
396+
"__llvm_memmove_element_unordered_atomic_16";
387397
Names[RTLIB::UNWIND_RESUME] = "_Unwind_Resume";
388398
Names[RTLIB::SYNC_VAL_COMPARE_AND_SWAP_1] = "__sync_val_compare_and_swap_1";
389399
Names[RTLIB::SYNC_VAL_COMPARE_AND_SWAP_2] = "__sync_val_compare_and_swap_2";
@@ -803,6 +813,23 @@ RTLIB::Libcall RTLIB::getMEMCPY_ELEMENT_UNORDERED_ATOMIC(uint64_t ElementSize) {
803813
}
804814
}
805815

816+
RTLIB::Libcall RTLIB::getMEMMOVE_ELEMENT_UNORDERED_ATOMIC(uint64_t ElementSize) {
817+
switch (ElementSize) {
818+
case 1:
819+
return MEMMOVE_ELEMENT_UNORDERED_ATOMIC_1;
820+
case 2:
821+
return MEMMOVE_ELEMENT_UNORDERED_ATOMIC_2;
822+
case 4:
823+
return MEMMOVE_ELEMENT_UNORDERED_ATOMIC_4;
824+
case 8:
825+
return MEMMOVE_ELEMENT_UNORDERED_ATOMIC_8;
826+
case 16:
827+
return MEMMOVE_ELEMENT_UNORDERED_ATOMIC_16;
828+
default:
829+
return UNKNOWN_LIBCALL;
830+
}
831+
}
832+
806833
/// InitCmpLibcallCCs - Set default comparison libcall CC.
807834
///
808835
static void InitCmpLibcallCCs(ISD::CondCode *CCs) {

‎llvm/lib/IR/Verifier.cpp

+36
Original file line numberDiff line numberDiff line change
@@ -4044,6 +4044,42 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) {
40444044
"incorrect alignment of the source argument", CS);
40454045
break;
40464046
}
4047+
case Intrinsic::memmove_element_unordered_atomic: {
4048+
auto *MI = cast<ElementUnorderedAtomicMemMoveInst>(CS.getInstruction());
4049+
4050+
ConstantInt *ElementSizeCI =
4051+
dyn_cast<ConstantInt>(MI->getRawElementSizeInBytes());
4052+
Assert(ElementSizeCI,
4053+
"element size of the element-wise unordered atomic memory "
4054+
"intrinsic must be a constant int",
4055+
CS);
4056+
const APInt &ElementSizeVal = ElementSizeCI->getValue();
4057+
Assert(ElementSizeVal.isPowerOf2(),
4058+
"element size of the element-wise atomic memory intrinsic "
4059+
"must be a power of 2",
4060+
CS);
4061+
4062+
if (auto *LengthCI = dyn_cast<ConstantInt>(MI->getLength())) {
4063+
uint64_t Length = LengthCI->getZExtValue();
4064+
uint64_t ElementSize = MI->getElementSizeInBytes();
4065+
Assert((Length % ElementSize) == 0,
4066+
"constant length must be a multiple of the element size in the "
4067+
"element-wise atomic memory intrinsic",
4068+
CS);
4069+
}
4070+
4071+
auto IsValidAlignment = [&](uint64_t Alignment) {
4072+
return isPowerOf2_64(Alignment) && ElementSizeVal.ule(Alignment);
4073+
};
4074+
uint64_t DstAlignment = CS.getParamAlignment(0),
4075+
SrcAlignment = CS.getParamAlignment(1);
4076+
Assert(IsValidAlignment(DstAlignment),
4077+
"incorrect alignment of the destination argument", CS);
4078+
Assert(IsValidAlignment(SrcAlignment),
4079+
"incorrect alignment of the source argument", CS);
4080+
4081+
break;
4082+
}
40474083
case Intrinsic::gcroot:
40484084
case Intrinsic::gcwrite:
40494085
case Intrinsic::gcread:

‎llvm/test/CodeGen/X86/element-wise-atomic-memory-intrinsics.ll

+63
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,67 @@ define void @test_memcpy_args(i8** %Storage) {
6262
call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %Dst, i8* align 4 %Src, i32 4, i32 4) ret void
6363
}
6464

65+
define i8* @test_memmove1(i8* %P, i8* %Q) {
66+
; CHECK: test_memmove
67+
call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %P, i8* align 4 %Q, i32 1, i32 1)
68+
ret i8* %P
69+
; 3rd arg (%edx) -- length
70+
; CHECK-DAG: movl $1, %edx
71+
; CHECK: __llvm_memmove_element_unordered_atomic_1
72+
}
73+
74+
define i8* @test_memmove2(i8* %P, i8* %Q) {
75+
; CHECK: test_memmove2
76+
call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %P, i8* align 4 %Q, i32 2, i32 2)
77+
ret i8* %P
78+
; 3rd arg (%edx) -- length
79+
; CHECK-DAG: movl $2, %edx
80+
; CHECK: __llvm_memmove_element_unordered_atomic_2
81+
}
82+
83+
define i8* @test_memmove4(i8* %P, i8* %Q) {
84+
; CHECK: test_memmove4
85+
call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %P, i8* align 4 %Q, i32 4, i32 4)
86+
ret i8* %P
87+
; 3rd arg (%edx) -- length
88+
; CHECK-DAG: movl $4, %edx
89+
; CHECK: __llvm_memmove_element_unordered_atomic_4
90+
}
91+
92+
define i8* @test_memmove8(i8* %P, i8* %Q) {
93+
; CHECK: test_memmove8
94+
call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 8 %P, i8* align 8 %Q, i32 8, i32 8)
95+
ret i8* %P
96+
; 3rd arg (%edx) -- length
97+
; CHECK-DAG: movl $8, %edx
98+
; CHECK: __llvm_memmove_element_unordered_atomic_8
99+
}
100+
101+
define i8* @test_memmove16(i8* %P, i8* %Q) {
102+
; CHECK: test_memmove16
103+
call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 16 %P, i8* align 16 %Q, i32 16, i32 16)
104+
ret i8* %P
105+
; 3rd arg (%edx) -- length
106+
; CHECK-DAG: movl $16, %edx
107+
; CHECK: __llvm_memmove_element_unordered_atomic_16
108+
}
109+
110+
define void @test_memmove_args(i8** %Storage) {
111+
; CHECK: test_memmove_args
112+
%Dst = load i8*, i8** %Storage
113+
%Src.addr = getelementptr i8*, i8** %Storage, i64 1
114+
%Src = load i8*, i8** %Src.addr
115+
116+
; 1st arg (%rdi)
117+
; CHECK-DAG: movq (%rdi), [[REG1:%r.+]]
118+
; CHECK-DAG: movq [[REG1]], %rdi
119+
; 2nd arg (%rsi)
120+
; CHECK-DAG: movq 8(%rdi), %rsi
121+
; 3rd arg (%edx) -- length
122+
; CHECK-DAG: movl $4, %edx
123+
; CHECK: __llvm_memmove_element_unordered_atomic_4
124+
call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %Dst, i8* align 4 %Src, i32 4, i32 4) ret void
125+
}
126+
65127
declare void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i32) nounwind
128+
declare void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i32) nounwind

‎llvm/test/Verifier/element-wise-atomic-memory-intrinsics.ll

+24
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,28 @@ define void @test_memcpy(i8* %P, i8* %Q, i32 %A, i32 %E) {
2222
ret void
2323
}
2424
declare void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i32) nounwind
25+
26+
define void @test_memmove(i8* %P, i8* %Q, i32 %A, i32 %E) {
27+
; CHECK: element size of the element-wise unordered atomic memory intrinsic must be a constant int
28+
call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %P, i8* align 4 %Q, i32 1, i32 %E)
29+
; CHECK: element size of the element-wise atomic memory intrinsic must be a power of 2
30+
call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %P, i8* align 4 %Q, i32 1, i32 3)
31+
32+
; CHECK: constant length must be a multiple of the element size in the element-wise atomic memory intrinsic
33+
call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %P, i8* align 4 %Q, i32 7, i32 4)
34+
35+
; CHECK: incorrect alignment of the destination argument
36+
call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* %P, i8* align 4 %Q, i32 1, i32 1)
37+
; CHECK: incorrect alignment of the destination argument
38+
call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 1 %P, i8* align 4 %Q, i32 4, i32 4)
39+
40+
; CHECK: incorrect alignment of the source argument
41+
call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %P, i8* %Q, i32 1, i32 1)
42+
; CHECK: incorrect alignment of the source argument
43+
call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %P, i8* align 1 %Q, i32 4, i32 4)
44+
45+
ret void
46+
}
47+
declare void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i32) nounwind
48+
2549
; CHECK: input module is broken!

0 commit comments

Comments
 (0)
Please sign in to comment.