[clang] d65bbf8 - [clang] Add support for __builtin_memcpy_inline
Guillaume Chatelet via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 7 15:08:48 PST 2020
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 at -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 at -1 {{null passed to a callee that requires a non-null argument}}
+ // expected-warning at -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,
More information about the cfe-commits
mailing list