[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