From ff920eec4d449bee560d8d99636ad0eb50cd9d8d Mon Sep 17 00:00:00 2001
From: Tim Northover <Tim.Northover@arm.com>
Date: Sat, 4 May 2013 07:15:13 +0000
Subject: [PATCH] AArch64: teach Clang about __clear_cache intrinsic

libgcc provides a __clear_cache intrinsic on AArch64, much like it
does on 32-bit ARM.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181111 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/clang/Basic/BuiltinsAArch64.def | 18 ++++++++++++++++++
 include/clang/Basic/TargetBuiltins.h    |  9 +++++++++
 lib/Basic/Targets.cpp                   | 14 ++++++++++++--
 lib/CodeGen/CGBuiltin.cpp               | 21 +++++++++++++++++++++
 lib/CodeGen/CodeGenFunction.h           |  1 +
 test/CodeGen/builtins-aarch64.c         |  6 ++++++
 test/Sema/builtins-aarch64.c            | 16 ++++++++++++++++
 7 files changed, 83 insertions(+), 2 deletions(-)
 create mode 100644 include/clang/Basic/BuiltinsAArch64.def
 create mode 100644 test/CodeGen/builtins-aarch64.c
 create mode 100644 test/Sema/builtins-aarch64.c

diff --git a/include/clang/Basic/BuiltinsAArch64.def b/include/clang/Basic/BuiltinsAArch64.def
new file mode 100644
index 00000000000..9e9f6d0875d
--- /dev/null
+++ b/include/clang/Basic/BuiltinsAArch64.def
@@ -0,0 +1,18 @@
+//===-- BuiltinsAArch64.def - AArch64 Builtin function database -*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the AArch64-specific builtin function database.  Users of
+// this file must define the BUILTIN macro to make use of this information.
+//
+//===----------------------------------------------------------------------===//
+
+// The format of this database matches clang/Basic/Builtins.def.
+
+// In libgcc
+BUILTIN(__clear_cache, "vv*v*", "")
diff --git a/include/clang/Basic/TargetBuiltins.h b/include/clang/Basic/TargetBuiltins.h
index 1d5004c3700..66e378fa9b4 100644
--- a/include/clang/Basic/TargetBuiltins.h
+++ b/include/clang/Basic/TargetBuiltins.h
@@ -21,6 +21,15 @@
 
 namespace clang {
 
+  /// \brief AArch64 builtins
+  namespace AArch64 {
+    enum {
+      LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1,
+#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
+#include "clang/Basic/BuiltinsAArch64.def"
+      LastTSBuiltin
+    };
+  }
   /// \brief ARM builtins
   namespace ARM {
     enum {
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 9d78bbebac5..cabdffa68c2 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -3307,6 +3307,8 @@ namespace {
 class AArch64TargetInfo : public TargetInfo {
   static const char * const GCCRegNames[];
   static const TargetInfo::GCCRegAlias GCCRegAliases[];
+
+  static const Builtin::Info BuiltinInfo[];
 public:
   AArch64TargetInfo(const std::string& triple) : TargetInfo(triple) {
     BigEndian = false;
@@ -3375,8 +3377,8 @@ public:
   }
   virtual void getTargetBuiltins(const Builtin::Info *&Records,
                                  unsigned &NumRecords) const {
-    Records = 0;
-    NumRecords = 0;
+    Records = BuiltinInfo;
+    NumRecords = clang::AArch64::LastTSBuiltin-Builtin::FirstTSBuiltin;
   }
   virtual bool hasFeature(StringRef Feature) const {
     return Feature == "aarch64";
@@ -3485,6 +3487,14 @@ void AArch64TargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
   NumAliases = llvm::array_lengthof(GCCRegAliases);
 
 }
+
+const Builtin::Info AArch64TargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\
+                                              ALL_LANGUAGES },
+#include "clang/Basic/BuiltinsAArch64.def"
+};
+
 } // end anonymous namespace
 
 namespace {
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 37bd8fc1f7c..d18767897f3 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -1502,6 +1502,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
 Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID,
                                               const CallExpr *E) {
   switch (getTarget().getTriple().getArch()) {
+  case llvm::Triple::aarch64:
+    return EmitAArch64BuiltinExpr(BuiltinID, E);
   case llvm::Triple::arm:
   case llvm::Triple::thumb:
     return EmitARMBuiltinExpr(BuiltinID, E);
@@ -1621,6 +1623,25 @@ CodeGenFunction::EmitPointerWithAlignment(const Expr *Addr) {
   return std::make_pair(EmitScalarExpr(Addr), Align);
 }
 
+Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
+                                               const CallExpr *E) {
+  if (BuiltinID == AArch64::BI__clear_cache) {
+    assert(E->getNumArgs() == 2 &&
+           "Variadic __clear_cache slipped through on AArch64");
+
+    const FunctionDecl *FD = E->getDirectCallee();
+    SmallVector<Value *, 2> Ops;
+    for (unsigned i = 0; i < E->getNumArgs(); i++)
+      Ops.push_back(EmitScalarExpr(E->getArg(i)));
+    llvm::Type *Ty = CGM.getTypes().ConvertType(FD->getType());
+    llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty);
+    StringRef Name = FD->getName();
+    return EmitNounwindRuntimeCall(CGM.CreateRuntimeFunction(FTy, Name), Ops);
+  }
+
+  return 0;
+}
+
 Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
                                            const CallExpr *E) {
   if (BuiltinID == ARM::BI__clear_cache) {
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 3ea2f34f104..08e60c43ce2 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -2503,6 +2503,7 @@ public:
   /// is unhandled by the current target.
   llvm::Value *EmitTargetBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
 
+  llvm::Value *EmitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
   llvm::Value *EmitARMBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
   llvm::Value *EmitNeonCall(llvm::Function *F,
                             SmallVectorImpl<llvm::Value*> &O,
diff --git a/test/CodeGen/builtins-aarch64.c b/test/CodeGen/builtins-aarch64.c
new file mode 100644
index 00000000000..8a93cb41fa4
--- /dev/null
+++ b/test/CodeGen/builtins-aarch64.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -O3 -emit-llvm -o - %s | FileCheck %s
+
+void f0(char *a, char *b) {
+	__clear_cache(a,b);
+// CHECK: call {{.*}} @__clear_cache
+}
diff --git a/test/Sema/builtins-aarch64.c b/test/Sema/builtins-aarch64.c
new file mode 100644
index 00000000000..03e03343eb9
--- /dev/null
+++ b/test/Sema/builtins-aarch64.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fsyntax-only -verify %s
+
+void test_clear_cache_chars(char *start, char *end) {
+  __clear_cache(start, end);
+}
+
+void test_clear_cache_voids(void *start, void *end) {
+  __clear_cache(start, end);
+}
+
+void test_clear_cache_no_args() {
+  // AArch32 version of this is variadic (at least syntactically).
+  // However, on AArch64 GCC does not permit this call and the
+  // implementation I've seen would go disastrously wrong.
+  __clear_cache(); // expected-error {{too few arguments to function call}}
+}
-- 
GitLab