Author: Guillaume Chatelet Date: 2020-02-07T23:55:26+01:00 New Revision: d65bbf81f8be3ff806b86776cf95b001a4cf43ad
URL: https://github.com/llvm/llvm-project/commit/d65bbf81f8be3ff806b86776cf95b001a4cf43ad DIFF: https://github.com/llvm/llvm-project/commit/d65bbf81f8be3ff806b86776cf95b001a4cf43ad.diff LOG: [clang] Add support for __builtin_memcpy_inline Summary: This is a follow up on D61634 and the last step to implement http://lists.llvm.org/pipermail/llvm-dev/2019-April/131973.html Reviewers: efriedma, courbet, tejohnson Subscribers: hiraditya, cfe-commits, llvm-commits, jdoerfert, t.p.northover Tags: #clang, #llvm Differential Revision: https://reviews.llvm.org/D73543 Added: clang/test/CodeGen/builtins-memcpy-inline.c clang/test/Sema/builtins-memcpy-inline.c Modified: clang/docs/LanguageExtensions.rst clang/include/clang/Basic/Builtins.def clang/lib/CodeGen/CGBuilder.h clang/lib/CodeGen/CGBuiltin.cpp clang/lib/Sema/SemaChecking.cpp llvm/include/llvm/IR/IRBuilder.h llvm/lib/IR/IRBuilder.cpp Removed: ################################################################################ diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index f1df9dd93f93..9af49e3a60d7 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -2260,6 +2260,23 @@ is disallowed in general). Support for constant expression evaluation for the above builtins be detected with ``__has_feature(cxx_constexpr_string_builtins)``. +Memory builtins +--------------- + + * ``__builtin_memcpy_inline`` + +.. code-block:: c + + void __builtin_memcpy_inline(void *dst, const void *src, size_t size); + +``__builtin_memcpy_inline(dst, src, size)`` is identical to +``__builtin_memcpy(dst, src, size)`` except that the generated code is +guaranteed not to call any external functions. See [LLVM IR ‘llvm.memcpy.inline’ +Intrinsic](https://llvm.org/docs/LangRef.html#llvm-memcpy-inline-intrinsic) for +more information. + +Note that the `size` argument must be a compile time constant. + Atomic Min/Max builtins with memory ordering -------------------------------------------- diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def index 1a6c85ce2dd3..9a68f72da6d9 100644 --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -480,6 +480,7 @@ BUILTIN(__builtin_fprintf, "iP*cC*.", "Fp:1:") BUILTIN(__builtin_memchr, "v*vC*iz", "nF") BUILTIN(__builtin_memcmp, "ivC*vC*z", "nF") BUILTIN(__builtin_memcpy, "v*v*vC*z", "nF") +BUILTIN(__builtin_memcpy_inline, "vv*vC*Iz", "nt") BUILTIN(__builtin_memmove, "v*v*vC*z", "nF") BUILTIN(__builtin_mempcpy, "v*v*vC*z", "nF") BUILTIN(__builtin_memset, "v*v*iz", "nF") diff --git a/clang/lib/CodeGen/CGBuilder.h b/clang/lib/CodeGen/CGBuilder.h index e736e83a8c66..7687f7990d99 100644 --- a/clang/lib/CodeGen/CGBuilder.h +++ b/clang/lib/CodeGen/CGBuilder.h @@ -280,6 +280,13 @@ class CGBuilderTy : public CGBuilderBaseTy { IsVolatile); } + using CGBuilderBaseTy::CreateMemCpyInline; + llvm::CallInst *CreateMemCpyInline(Address Dest, Address Src, uint64_t Size) { + return CreateMemCpyInline( + Dest.getPointer(), Dest.getAlignment().getAsAlign(), Src.getPointer(), + Src.getAlignment().getAsAlign(), getInt64(Size)); + } + using CGBuilderBaseTy::CreateMemMove; llvm::CallInst *CreateMemMove(Address Dest, Address Src, llvm::Value *Size, bool IsVolatile = false) { diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 7e0c53126914..509400bfc574 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -2518,6 +2518,19 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(Dest.getPointer()); } + case Builtin::BI__builtin_memcpy_inline: { + Address Dest = EmitPointerWithAlignment(E->getArg(0)); + Address Src = EmitPointerWithAlignment(E->getArg(1)); + uint64_t Size = + E->getArg(2)->EvaluateKnownConstInt(getContext()).getZExtValue(); + EmitNonNullArgCheck(RValue::get(Dest.getPointer()), E->getArg(0)->getType(), + E->getArg(0)->getExprLoc(), FD, 0); + EmitNonNullArgCheck(RValue::get(Src.getPointer()), E->getArg(1)->getType(), + E->getArg(1)->getExprLoc(), FD, 1); + Builder.CreateMemCpyInline(Dest, Src, Size); + return RValue::get(nullptr); + } + case Builtin::BI__builtin_char_memchr: BuiltinID = Builtin::BI__builtin_memchr; break; diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index ab63120bf842..a06a82331c9b 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1376,6 +1376,9 @@ CheckBuiltinTargetSupport(Sema &S, unsigned BuiltinID, CallExpr *TheCall, return true; } +static void CheckNonNullArgument(Sema &S, const Expr *ArgExpr, + SourceLocation CallSiteLoc); + ExprResult Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CallExpr *TheCall) { @@ -1645,6 +1648,14 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_nontemporal_load: case Builtin::BI__builtin_nontemporal_store: return SemaBuiltinNontemporalOverloaded(TheCallResult); + case Builtin::BI__builtin_memcpy_inline: { + // __builtin_memcpy_inline size argument is a constant by definition. + if (TheCall->getArg(2)->EvaluateKnownConstInt(Context).isNullValue()) + break; + CheckNonNullArgument(*this, TheCall->getArg(0), TheCall->getExprLoc()); + CheckNonNullArgument(*this, TheCall->getArg(1), TheCall->getExprLoc()); + break; + } #define BUILTIN(ID, TYPE, ATTRS) #define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \ case Builtin::BI##ID: \ diff --git a/clang/test/CodeGen/builtins-memcpy-inline.c b/clang/test/CodeGen/builtins-memcpy-inline.c new file mode 100644 index 000000000000..aa1bf709ae5d --- /dev/null +++ b/clang/test/CodeGen/builtins-memcpy-inline.c @@ -0,0 +1,26 @@ +// REQUIRES: x86-registered-target +// RUN: %clang_cc1 -triple x86_64-unknown-linux -emit-llvm %s -o - | FileCheck %s + +// CHECK-LABEL: define void @test_memcpy_inline_0(i8* %dst, i8* %src) +void test_memcpy_inline_0(void *dst, const void *src) { + // CHECK: call void @llvm.memcpy.inline.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 %1, i64 0, i1 false) + __builtin_memcpy_inline(dst, src, 0); +} + +// CHECK-LABEL: define void @test_memcpy_inline_1(i8* %dst, i8* %src) +void test_memcpy_inline_1(void *dst, const void *src) { + // CHECK: call void @llvm.memcpy.inline.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 %1, i64 1, i1 false) + __builtin_memcpy_inline(dst, src, 1); +} + +// CHECK-LABEL: define void @test_memcpy_inline_4(i8* %dst, i8* %src) +void test_memcpy_inline_4(void *dst, const void *src) { + // CHECK: call void @llvm.memcpy.inline.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 %1, i64 4, i1 false) + __builtin_memcpy_inline(dst, src, 4); +} + +// CHECK-LABEL: define void @test_memcpy_inline_aligned_buffers(i64* %dst, i64* %src) +void test_memcpy_inline_aligned_buffers(unsigned long long *dst, const unsigned long long *src) { + // CHECK: call void @llvm.memcpy.inline.p0i8.p0i8.i64(i8* align 8 %2, i8* align 8 %3, i64 4, i1 false) + __builtin_memcpy_inline(dst, src, 4); +} diff --git a/clang/test/Sema/builtins-memcpy-inline.c b/clang/test/Sema/builtins-memcpy-inline.c new file mode 100644 index 000000000000..6d0edce92a11 --- /dev/null +++ b/clang/test/Sema/builtins-memcpy-inline.c @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +#define NULL ((char *)0) + +#if __has_feature(__builtin_memcpy_inline) +#warning defined as expected +// expected-warning@-1 {{defined as expected}} +#endif + +void test_memcpy_inline_null_src(void *ptr) { + __builtin_memcpy_inline(ptr, NULL, 4); // expected-warning {{null passed to a callee that requires a non-null argument}} +} + +void test_memcpy_inline_null_dst(void *ptr) { + __builtin_memcpy_inline(NULL, ptr, 4); // expected-warning {{null passed to a callee that requires a non-null argument}} +} + +void test_memcpy_inline_null_buffers() { + __builtin_memcpy_inline(NULL, NULL, 4); + // expected-warning@-1 {{null passed to a callee that requires a non-null argument}} + // expected-warning@-2 {{null passed to a callee that requires a non-null argument}} +} + +void test_memcpy_inline_null_buffer_is_ok_if_size_is_zero(void *ptr) { + __builtin_memcpy_inline(ptr, NULL, /*size */ 0); + __builtin_memcpy_inline(NULL, ptr, /*size */ 0); + __builtin_memcpy_inline(NULL, NULL, /*size */ 0); +} + +void test_memcpy_inline_non_constant_size(void *dst, const void *src, unsigned size) { + __builtin_memcpy_inline(dst, src, size); // expected-error {{argument to '__builtin_memcpy_inline' must be a constant integer}} +} diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h index 5a290464739e..82cd0738ac28 100644 --- a/llvm/include/llvm/IR/IRBuilder.h +++ b/llvm/include/llvm/IR/IRBuilder.h @@ -560,6 +560,9 @@ class IRBuilderBase { MDNode *ScopeTag = nullptr, MDNode *NoAliasTag = nullptr); + CallInst *CreateMemCpyInline(Value *Dst, MaybeAlign DstAlign, Value *Src, + MaybeAlign SrcAlign, Value *Size); + /// Create and insert an element unordered-atomic memcpy between the /// specified pointers. /// diff --git a/llvm/lib/IR/IRBuilder.cpp b/llvm/lib/IR/IRBuilder.cpp index f59d68d1db00..0dd78f2f2d4b 100644 --- a/llvm/lib/IR/IRBuilder.cpp +++ b/llvm/lib/IR/IRBuilder.cpp @@ -200,6 +200,30 @@ CallInst *IRBuilderBase::CreateMemCpy(Value *Dst, MaybeAlign DstAlign, return CI; } +CallInst *IRBuilderBase::CreateMemCpyInline(Value *Dst, MaybeAlign DstAlign, + Value *Src, MaybeAlign SrcAlign, + Value *Size) { + Dst = getCastedInt8PtrValue(Dst); + Src = getCastedInt8PtrValue(Src); + Value *IsVolatile = getInt1(false); + + Value *Ops[] = {Dst, Src, Size, IsVolatile}; + Type *Tys[] = {Dst->getType(), Src->getType(), Size->getType()}; + Function *F = BB->getParent(); + Module *M = F->getParent(); + Function *TheFn = Intrinsic::getDeclaration(M, Intrinsic::memcpy_inline, Tys); + + CallInst *CI = createCallHelper(TheFn, Ops, this); + + auto *MCI = cast<MemCpyInlineInst>(CI); + if (DstAlign) + MCI->setDestAlignment(*DstAlign); + if (SrcAlign) + MCI->setSourceAlignment(*SrcAlign); + + return CI; +} + CallInst *IRBuilderBase::CreateElementUnorderedAtomicMemCpy( Value *Dst, Align DstAlign, Value *Src, Align SrcAlign, Value *Size, uint32_t ElementSize, MDNode *TBAATag, MDNode *TBAAStructTag, _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits