[llvm] r307796 - Add element atomic memmove intrinsic

David Blaikie via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 12 11:26:01 PDT 2017


This seems to be breaking internal buildbots on WebAssembly tests
(test/CodeGen/WebAssembli/{byval,f16,f32,f64,frem,global,i128,legalize,mem-intrinsics}.ll

I've not reproduced this myself, but working on that now to get more info,
including stack traces, etc.

On Wed, Jul 12, 2017 at 8:25 AM Daniel Neilson via llvm-commits <
llvm-commits at lists.llvm.org> wrote:

> Author: dneilson
> Date: Wed Jul 12 08:25:26 2017
> New Revision: 307796
>
> URL: http://llvm.org/viewvc/llvm-project?rev=307796&view=rev
> Log:
> 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
>
> Modified:
>     llvm/trunk/docs/LangRef.rst
>     llvm/trunk/include/llvm/CodeGen/RuntimeLibcalls.h
>     llvm/trunk/include/llvm/IR/IntrinsicInst.h
>     llvm/trunk/include/llvm/IR/Intrinsics.td
>     llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
>     llvm/trunk/lib/CodeGen/TargetLoweringBase.cpp
>     llvm/trunk/lib/IR/Verifier.cpp
>     llvm/trunk/test/CodeGen/X86/element-wise-atomic-memory-intrinsics.ll
>     llvm/trunk/test/Verifier/element-wise-atomic-memory-intrinsics.ll
>
> Modified: llvm/trunk/docs/LangRef.rst
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/LangRef.rst?rev=307796&r1=307795&r2=307796&view=diff
>
> ==============================================================================
> --- llvm/trunk/docs/LangRef.rst (original)
> +++ llvm/trunk/docs/LangRef.rst Wed Jul 12 08:25:26 2017
> @@ -10282,6 +10282,8 @@ overlap. It copies "len" bytes of memory
>  to be aligned to some boundary, this can be specified as the fourth
>  argument, otherwise it should be set to 0 or 1 (both meaning no
> alignment).
>
> +.. _int_memmove:
> +
>  '``llvm.memmove``' Intrinsic
>  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> @@ -14178,4 +14180,81 @@ In the most general case call to the '``
>  lowered to a call to the symbol
> ``__llvm_memcpy_element_unordered_atomic_*``. Where '*'
>  is replaced with an actual element size.
>
> +Optimizer is allowed to inline memory copy when it's profitable to do so.
> +
> +'``llvm.memmove.element.unordered.atomic``' Intrinsic
> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> +
> +Syntax:
> +"""""""
> +
> +This is an overloaded intrinsic. You can use
> +``llvm.memmove.element.unordered.atomic`` on any integer bit width and for
> +different address spaces. Not all targets support all bit widths however.
> +
> +::
> +
> +      declare void
> @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* <dest>,
> +
> i8* <src>,
> +
> i32 <len>,
> +
> i32 <element_size>)
> +      declare void
> @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i64(i8* <dest>,
> +
> i8* <src>,
> +
> i64 <len>,
> +
> i32 <element_size>)
> +
> +Overview:
> +"""""""""
> +
> +The '``llvm.memmove.element.unordered.atomic.*``' intrinsic is a
> specialization
> +of the '``llvm.memmove.*``' intrinsic. It differs in that the ``dest`` and
> +``src`` are treated as arrays with elements that are exactly
> ``element_size``
> +bytes, and the copy between buffers uses a sequence of
> +:ref:`unordered atomic <ordering>` load/store operations that are a
> positive
> +integer multiple of the ``element_size`` in size.
> +
> +Arguments:
> +""""""""""
> +
> +The first three arguments are the same as they are in the
> +:ref:`@llvm.memmove <int_memmove>` intrinsic, with the added constraint
> that
> +``len`` is required to be a positive integer multiple of the
> ``element_size``.
> +If ``len`` is not a positive integer multiple of ``element_size``, then
> the
> +behaviour of the intrinsic is undefined.
> +
> +``element_size`` must be a compile-time constant positive power of two no
> +greater than a target-specific atomic access size limit.
> +
> +For each of the input pointers the ``align`` parameter attribute must be
> +specified. It must be a power of two no less than the ``element_size``.
> Caller
> +guarantees that both the source and destination pointers are aligned to
> that
> +boundary.
> +
> +Semantics:
> +""""""""""
> +
> +The '``llvm.memmove.element.unordered.atomic.*``' intrinsic copies
> ``len`` bytes
> +of memory from the source location to the destination location. These
> locations
> +are allowed to overlap. The memory copy is performed as a sequence of
> load/store
> +operations where each access is guaranteed to be a multiple of
> ``element_size``
> +bytes wide and aligned at an ``element_size`` boundary.
> +
> +The order of the copy is unspecified. The same value may be read from the
> source
> +buffer many times, but only one write is issued to the destination buffer
> per
> +element. It is well defined to have concurrent reads and writes to both
> source
> +and destination provided those reads and writes are unordered atomic when
> +specified.
> +
> +This intrinsic does not provide any additional ordering guarantees over
> those
> +provided by a set of unordered loads from the source location and stores
> to the
> +destination.
> +
> +Lowering:
> +"""""""""
> +
> +In the most general case call to the
> +'``llvm.memmove.element.unordered.atomic.*``' is lowered to a call to the
> symbol
> +``__llvm_memmove_element_unordered_atomic_*``. Where '*' is replaced with
> an
> +actual element size.
> +
>  The optimizer is allowed to inline the memory copy when it's profitable
> to do so.
>
> Modified: llvm/trunk/include/llvm/CodeGen/RuntimeLibcalls.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/RuntimeLibcalls.h?rev=307796&r1=307795&r2=307796&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/CodeGen/RuntimeLibcalls.h (original)
> +++ llvm/trunk/include/llvm/CodeGen/RuntimeLibcalls.h Wed Jul 12 08:25:26
> 2017
> @@ -340,6 +340,12 @@ namespace RTLIB {
>      MEMCPY_ELEMENT_UNORDERED_ATOMIC_8,
>      MEMCPY_ELEMENT_UNORDERED_ATOMIC_16,
>
> +    MEMMOVE_ELEMENT_UNORDERED_ATOMIC_1,
> +    MEMMOVE_ELEMENT_UNORDERED_ATOMIC_2,
> +    MEMMOVE_ELEMENT_UNORDERED_ATOMIC_4,
> +    MEMMOVE_ELEMENT_UNORDERED_ATOMIC_8,
> +    MEMMOVE_ELEMENT_UNORDERED_ATOMIC_16,
> +
>      // EXCEPTION HANDLING
>      UNWIND_RESUME,
>
> @@ -515,6 +521,11 @@ namespace RTLIB {
>    /// MEMCPY_ELEMENT_UNORDERED_ATOMIC_* value for the given element size
> or
>    /// UNKNOW_LIBCALL if there is none.
>    Libcall getMEMCPY_ELEMENT_UNORDERED_ATOMIC(uint64_t ElementSize);
> +
> +  /// getMEMMOVE_ELEMENT_UNORDERED_ATOMIC - Return
> +  /// MEMMOVE_ELEMENT_UNORDERED_ATOMIC_* value for the given element size
> or
> +  /// UNKNOW_LIBCALL if there is none.
> +  Libcall getMEMMOVE_ELEMENT_UNORDERED_ATOMIC(uint64_t ElementSize);
>  }
>  }
>
>
> Modified: llvm/trunk/include/llvm/IR/IntrinsicInst.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/IntrinsicInst.h?rev=307796&r1=307795&r2=307796&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/IR/IntrinsicInst.h (original)
> +++ llvm/trunk/include/llvm/IR/IntrinsicInst.h Wed Jul 12 08:25:26 2017
> @@ -296,6 +296,95 @@ namespace llvm {
>      }
>    };
>
> +  class ElementUnorderedAtomicMemMoveInst : public IntrinsicInst {
> +  private:
> +    enum { ARG_DEST = 0, ARG_SOURCE = 1, ARG_LENGTH = 2, ARG_ELEMENTSIZE
> = 3 };
> +
> +  public:
> +    Value *getRawDest() const {
> +      return const_cast<Value *>(getArgOperand(ARG_DEST));
> +    }
> +    const Use &getRawDestUse() const { return getArgOperandUse(ARG_DEST);
> }
> +    Use &getRawDestUse() { return getArgOperandUse(ARG_DEST); }
> +
> +    /// Return the arguments to the instruction.
> +    Value *getRawSource() const {
> +      return const_cast<Value *>(getArgOperand(ARG_SOURCE));
> +    }
> +    const Use &getRawSourceUse() const { return
> getArgOperandUse(ARG_SOURCE); }
> +    Use &getRawSourceUse() { return getArgOperandUse(ARG_SOURCE); }
> +
> +    Value *getLength() const {
> +      return const_cast<Value *>(getArgOperand(ARG_LENGTH));
> +    }
> +    const Use &getLengthUse() const { return
> getArgOperandUse(ARG_LENGTH); }
> +    Use &getLengthUse() { return getArgOperandUse(ARG_LENGTH); }
> +
> +    bool isVolatile() const { return false; }
> +
> +    Value *getRawElementSizeInBytes() const {
> +      return const_cast<Value *>(getArgOperand(ARG_ELEMENTSIZE));
> +    }
> +
> +    ConstantInt *getElementSizeInBytesCst() const {
> +      return cast<ConstantInt>(getRawElementSizeInBytes());
> +    }
> +
> +    uint32_t getElementSizeInBytes() const {
> +      return getElementSizeInBytesCst()->getZExtValue();
> +    }
> +
> +    /// This is just like getRawDest, but it strips off any cast
> +    /// instructions that feed it, giving the original input.  The
> returned
> +    /// value is guaranteed to be a pointer.
> +    Value *getDest() const { return getRawDest()->stripPointerCasts(); }
> +
> +    /// This is just like getRawSource, but it strips off any cast
> +    /// instructions that feed it, giving the original input.  The
> returned
> +    /// value is guaranteed to be a pointer.
> +    Value *getSource() const { return
> getRawSource()->stripPointerCasts(); }
> +
> +    unsigned getDestAddressSpace() const {
> +      return
> cast<PointerType>(getRawDest()->getType())->getAddressSpace();
> +    }
> +
> +    unsigned getSourceAddressSpace() const {
> +      return
> cast<PointerType>(getRawSource()->getType())->getAddressSpace();
> +    }
> +
> +    /// Set the specified arguments of the instruction.
> +    void setDest(Value *Ptr) {
> +      assert(getRawDest()->getType() == Ptr->getType() &&
> +             "setDest called with pointer of wrong type!");
> +      setArgOperand(ARG_DEST, Ptr);
> +    }
> +
> +    void setSource(Value *Ptr) {
> +      assert(getRawSource()->getType() == Ptr->getType() &&
> +             "setSource called with pointer of wrong type!");
> +      setArgOperand(ARG_SOURCE, Ptr);
> +    }
> +
> +    void setLength(Value *L) {
> +      assert(getLength()->getType() == L->getType() &&
> +             "setLength called with value of wrong type!");
> +      setArgOperand(ARG_LENGTH, L);
> +    }
> +
> +    void setElementSizeInBytes(Constant *V) {
> +      assert(V->getType() == Type::getInt8Ty(getContext()) &&
> +             "setElementSizeInBytes called with value of wrong type!");
> +      setArgOperand(ARG_ELEMENTSIZE, V);
> +    }
> +
> +    static inline bool classof(const IntrinsicInst *I) {
> +      return I->getIntrinsicID() ==
> Intrinsic::memmove_element_unordered_atomic;
> +    }
> +    static inline bool classof(const Value *V) {
> +      return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
> +    }
> +  };
> +
>    /// This is the common base class for memset/memcpy/memmove.
>    class MemIntrinsic : public IntrinsicInst {
>    public:
>
> Modified: llvm/trunk/include/llvm/IR/Intrinsics.td
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Intrinsics.td?rev=307796&r1=307795&r2=307796&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/IR/Intrinsics.td (original)
> +++ llvm/trunk/include/llvm/IR/Intrinsics.td Wed Jul 12 08:25:26 2017
> @@ -873,6 +873,18 @@ def int_memcpy_element_unordered_atomic
>                    ReadOnly<1>
>                  ]>;
>
> +// @llvm.memmove.element.unordered.atomic.*(dest, src, length,
> elementsize)
> +def int_memmove_element_unordered_atomic
> +    : Intrinsic<[],
> +                [
> +                  llvm_anyptr_ty, llvm_anyptr_ty, llvm_anyint_ty,
> llvm_i32_ty
> +                ],
> +                [
> +                  IntrArgMemOnly, NoCapture<0>, NoCapture<1>,
> WriteOnly<0>,
> +                  ReadOnly<1>
> +                ]>;
> +
> +
>  //===------------------------ Reduction Intrinsics
> ------------------------===//
>  //
>  def int_experimental_vector_reduce_fadd : Intrinsic<[llvm_anyfloat_ty],
>
> Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp?rev=307796&r1=307795&r2=307796&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (original)
> +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Wed Jul 12
> 08:25:26 2017
> @@ -4994,6 +4994,44 @@ SelectionDAGBuilder::visitIntrinsicCall(
>      DAG.setRoot(CallResult.second);
>      return nullptr;
>    }
> +  case Intrinsic::memmove_element_unordered_atomic: {
> +    auto &MI = cast<ElementUnorderedAtomicMemMoveInst>(I);
> +    SDValue Dst = getValue(MI.getRawDest());
> +    SDValue Src = getValue(MI.getRawSource());
> +    SDValue Length = getValue(MI.getLength());
> +
> +    // Emit a library call.
> +    TargetLowering::ArgListTy Args;
> +    TargetLowering::ArgListEntry Entry;
> +    Entry.Ty = DAG.getDataLayout().getIntPtrType(*DAG.getContext());
> +    Entry.Node = Dst;
> +    Args.push_back(Entry);
> +
> +    Entry.Node = Src;
> +    Args.push_back(Entry);
> +
> +    Entry.Ty = MI.getLength()->getType();
> +    Entry.Node = Length;
> +    Args.push_back(Entry);
> +
> +    uint64_t ElementSizeConstant = MI.getElementSizeInBytes();
> +    RTLIB::Libcall LibraryCall =
> +        RTLIB::getMEMMOVE_ELEMENT_UNORDERED_ATOMIC(ElementSizeConstant);
> +    if (LibraryCall == RTLIB::UNKNOWN_LIBCALL)
> +      report_fatal_error("Unsupported element size");
> +
> +    TargetLowering::CallLoweringInfo CLI(DAG);
> +    CLI.setDebugLoc(sdl).setChain(getRoot()).setLibCallee(
> +        TLI.getLibcallCallingConv(LibraryCall),
> +        Type::getVoidTy(*DAG.getContext()),
> +        DAG.getExternalSymbol(TLI.getLibcallName(LibraryCall),
> +                              TLI.getPointerTy(DAG.getDataLayout())),
> +        std::move(Args));
> +
> +    std::pair<SDValue, SDValue> CallResult = TLI.LowerCallTo(CLI);
> +    DAG.setRoot(CallResult.second);
> +    return nullptr;
> +  }
>    case Intrinsic::dbg_declare: {
>      const DbgDeclareInst &DI = cast<DbgDeclareInst>(I);
>      DILocalVariable *Variable = DI.getVariable();
>
> Modified: llvm/trunk/lib/CodeGen/TargetLoweringBase.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/TargetLoweringBase.cpp?rev=307796&r1=307795&r2=307796&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/TargetLoweringBase.cpp (original)
> +++ llvm/trunk/lib/CodeGen/TargetLoweringBase.cpp Wed Jul 12 08:25:26 2017
> @@ -384,6 +384,16 @@ static void InitLibcallNames(const char
>        "__llvm_memcpy_element_unordered_atomic_8";
>    Names[RTLIB::MEMCPY_ELEMENT_UNORDERED_ATOMIC_16] =
>        "__llvm_memcpy_element_unordered_atomic_16";
> +  Names[RTLIB::MEMMOVE_ELEMENT_UNORDERED_ATOMIC_1] =
> +      "__llvm_memmove_element_unordered_atomic_1";
> +  Names[RTLIB::MEMMOVE_ELEMENT_UNORDERED_ATOMIC_2] =
> +      "__llvm_memmove_element_unordered_atomic_2";
> +  Names[RTLIB::MEMMOVE_ELEMENT_UNORDERED_ATOMIC_4] =
> +      "__llvm_memmove_element_unordered_atomic_4";
> +  Names[RTLIB::MEMMOVE_ELEMENT_UNORDERED_ATOMIC_8] =
> +      "__llvm_memmove_element_unordered_atomic_8";
> +  Names[RTLIB::MEMMOVE_ELEMENT_UNORDERED_ATOMIC_16] =
> +      "__llvm_memmove_element_unordered_atomic_16";
>    Names[RTLIB::UNWIND_RESUME] = "_Unwind_Resume";
>    Names[RTLIB::SYNC_VAL_COMPARE_AND_SWAP_1] =
> "__sync_val_compare_and_swap_1";
>    Names[RTLIB::SYNC_VAL_COMPARE_AND_SWAP_2] =
> "__sync_val_compare_and_swap_2";
> @@ -801,6 +811,23 @@ RTLIB::Libcall RTLIB::getMEMCPY_ELEMENT_
>    default:
>      return UNKNOWN_LIBCALL;
>    }
> +}
> +
> +RTLIB::Libcall RTLIB::getMEMMOVE_ELEMENT_UNORDERED_ATOMIC(uint64_t
> ElementSize) {
> +  switch (ElementSize) {
> +  case 1:
> +    return MEMMOVE_ELEMENT_UNORDERED_ATOMIC_1;
> +  case 2:
> +    return MEMMOVE_ELEMENT_UNORDERED_ATOMIC_2;
> +  case 4:
> +    return MEMMOVE_ELEMENT_UNORDERED_ATOMIC_4;
> +  case 8:
> +    return MEMMOVE_ELEMENT_UNORDERED_ATOMIC_8;
> +  case 16:
> +    return MEMMOVE_ELEMENT_UNORDERED_ATOMIC_16;
> +  default:
> +    return UNKNOWN_LIBCALL;
> +  }
>  }
>
>  /// InitCmpLibcallCCs - Set default comparison libcall CC.
>
> Modified: llvm/trunk/lib/IR/Verifier.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Verifier.cpp?rev=307796&r1=307795&r2=307796&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/IR/Verifier.cpp (original)
> +++ llvm/trunk/lib/IR/Verifier.cpp Wed Jul 12 08:25:26 2017
> @@ -4044,6 +4044,42 @@ void Verifier::visitIntrinsicCallSite(In
>             "incorrect alignment of the source argument", CS);
>      break;
>    }
> +  case Intrinsic::memmove_element_unordered_atomic: {
> +    auto *MI =
> cast<ElementUnorderedAtomicMemMoveInst>(CS.getInstruction());
> +
> +    ConstantInt *ElementSizeCI =
> +        dyn_cast<ConstantInt>(MI->getRawElementSizeInBytes());
> +    Assert(ElementSizeCI,
> +           "element size of the element-wise unordered atomic memory "
> +           "intrinsic must be a constant int",
> +           CS);
> +    const APInt &ElementSizeVal = ElementSizeCI->getValue();
> +    Assert(ElementSizeVal.isPowerOf2(),
> +           "element size of the element-wise atomic memory intrinsic "
> +           "must be a power of 2",
> +           CS);
> +
> +    if (auto *LengthCI = dyn_cast<ConstantInt>(MI->getLength())) {
> +      uint64_t Length = LengthCI->getZExtValue();
> +      uint64_t ElementSize = MI->getElementSizeInBytes();
> +      Assert((Length % ElementSize) == 0,
> +             "constant length must be a multiple of the element size in
> the "
> +             "element-wise atomic memory intrinsic",
> +             CS);
> +    }
> +
> +    auto IsValidAlignment = [&](uint64_t Alignment) {
> +      return isPowerOf2_64(Alignment) && ElementSizeVal.ule(Alignment);
> +    };
> +    uint64_t DstAlignment = CS.getParamAlignment(0),
> +             SrcAlignment = CS.getParamAlignment(1);
> +    Assert(IsValidAlignment(DstAlignment),
> +           "incorrect alignment of the destination argument", CS);
> +    Assert(IsValidAlignment(SrcAlignment),
> +           "incorrect alignment of the source argument", CS);
> +
> +    break;
> +  }
>    case Intrinsic::gcroot:
>    case Intrinsic::gcwrite:
>    case Intrinsic::gcread:
>
> Modified:
> llvm/trunk/test/CodeGen/X86/element-wise-atomic-memory-intrinsics.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/element-wise-atomic-memory-intrinsics.ll?rev=307796&r1=307795&r2=307796&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/CodeGen/X86/element-wise-atomic-memory-intrinsics.ll
> (original)
> +++ llvm/trunk/test/CodeGen/X86/element-wise-atomic-memory-intrinsics.ll
> Wed Jul 12 08:25:26 2017
> @@ -62,4 +62,67 @@ define void @test_memcpy_args(i8** %Stor
>    call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align
> 4 %Dst, i8* align 4 %Src, i32 4, i32 4)  ret void
>  }
>
> +define i8* @test_memmove1(i8* %P, i8* %Q) {
> +  ; CHECK: test_memmove
> +  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8*
> align 4 %P, i8* align 4 %Q, i32 1, i32 1)
> +  ret i8* %P
> +  ; 3rd arg (%edx) -- length
> +  ; CHECK-DAG: movl $1, %edx
> +  ; CHECK: __llvm_memmove_element_unordered_atomic_1
> +}
> +
> +define i8* @test_memmove2(i8* %P, i8* %Q) {
> +  ; CHECK: test_memmove2
> +  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8*
> align 4 %P, i8* align 4 %Q, i32 2, i32 2)
> +  ret i8* %P
> +  ; 3rd arg (%edx) -- length
> +  ; CHECK-DAG: movl $2, %edx
> +  ; CHECK: __llvm_memmove_element_unordered_atomic_2
> +}
> +
> +define i8* @test_memmove4(i8* %P, i8* %Q) {
> +  ; CHECK: test_memmove4
> +  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8*
> align 4 %P, i8* align 4 %Q, i32 4, i32 4)
> +  ret i8* %P
> +  ; 3rd arg (%edx) -- length
> +  ; CHECK-DAG: movl $4, %edx
> +  ; CHECK: __llvm_memmove_element_unordered_atomic_4
> +}
> +
> +define i8* @test_memmove8(i8* %P, i8* %Q) {
> +  ; CHECK: test_memmove8
> +  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8*
> align 8 %P, i8* align 8 %Q, i32 8, i32 8)
> +  ret i8* %P
> +  ; 3rd arg (%edx) -- length
> +  ; CHECK-DAG: movl $8, %edx
> +  ; CHECK: __llvm_memmove_element_unordered_atomic_8
> +}
> +
> +define i8* @test_memmove16(i8* %P, i8* %Q) {
> +  ; CHECK: test_memmove16
> +  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8*
> align 16 %P, i8* align 16 %Q, i32 16, i32 16)
> +  ret i8* %P
> +  ; 3rd arg (%edx) -- length
> +  ; CHECK-DAG: movl $16, %edx
> +  ; CHECK: __llvm_memmove_element_unordered_atomic_16
> +}
> +
> +define void @test_memmove_args(i8** %Storage) {
> +  ; CHECK: test_memmove_args
> +  %Dst = load i8*, i8** %Storage
> +  %Src.addr = getelementptr i8*, i8** %Storage, i64 1
> +  %Src = load i8*, i8** %Src.addr
> +
> +  ; 1st arg (%rdi)
> +  ; CHECK-DAG: movq (%rdi), [[REG1:%r.+]]
> +  ; CHECK-DAG: movq [[REG1]], %rdi
> +  ; 2nd arg (%rsi)
> +  ; CHECK-DAG: movq 8(%rdi), %rsi
> +  ; 3rd arg (%edx) -- length
> +  ; CHECK-DAG: movl $4, %edx
> +  ; CHECK: __llvm_memmove_element_unordered_atomic_4
> +  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8*
> align 4 %Dst, i8* align 4 %Src, i32 4, i32 4)  ret void
> +}
> +
>  declare void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8*
> nocapture, i8* nocapture, i32, i32) nounwind
> +declare void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8*
> nocapture, i8* nocapture, i32, i32) nounwind
>
> Modified: llvm/trunk/test/Verifier/element-wise-atomic-memory-intrinsics.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Verifier/element-wise-atomic-memory-intrinsics.ll?rev=307796&r1=307795&r2=307796&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/Verifier/element-wise-atomic-memory-intrinsics.ll
> (original)
> +++ llvm/trunk/test/Verifier/element-wise-atomic-memory-intrinsics.ll Wed
> Jul 12 08:25:26 2017
> @@ -22,4 +22,28 @@ define void @test_memcpy(i8* %P, i8* %Q,
>    ret void
>  }
>  declare void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8*
> nocapture, i8* nocapture, i32, i32) nounwind
> +
> +define void @test_memmove(i8* %P, i8* %Q, i32 %A, i32 %E) {
> +  ; CHECK: element size of the element-wise unordered atomic memory
> intrinsic must be a constant int
> +  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8*
> align 4 %P, i8* align 4 %Q, i32 1, i32 %E)
> +  ; CHECK: element size of the element-wise atomic memory intrinsic must
> be a power of 2
> +  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8*
> align 4 %P, i8* align 4 %Q, i32 1, i32 3)
> +
> +  ; CHECK: constant length must be a multiple of the element size in the
> element-wise atomic memory intrinsic
> +  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8*
> align 4 %P, i8* align 4 %Q, i32 7, i32 4)
> +
> +  ; CHECK: incorrect alignment of the destination argument
> +  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* %P,
> i8* align 4 %Q, i32 1, i32 1)
> +  ; CHECK: incorrect alignment of the destination argument
> +  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8*
> align 1 %P, i8* align 4 %Q, i32 4, i32 4)
> +
> +  ; CHECK: incorrect alignment of the source argument
> +  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8*
> align 4 %P, i8* %Q, i32 1, i32 1)
> +  ; CHECK: incorrect alignment of the source argument
> +  call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8*
> align 4 %P, i8* align 1 %Q, i32 4, i32 4)
> +
> +  ret void
> +}
> +declare void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8*
> nocapture, i8* nocapture, i32, i32) nounwind
> +
>  ; CHECK: input module is broken!
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20170712/0978d43b/attachment.html>


More information about the llvm-commits mailing list