javed.absar updated this revision to Diff 195112.
javed.absar added a comment.

Tests merged as suggested.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60485/new/

https://reviews.llvm.org/D60485

Files:
  include/clang/Basic/BuiltinsAArch64.def
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Basic/Targets/AArch64.cpp
  lib/Basic/Targets/AArch64.h
  lib/CodeGen/CGBuiltin.cpp
  lib/Headers/arm_acle.h
  lib/Sema/SemaChecking.cpp
  test/CodeGen/arm64-mte.c
  test/Preprocessor/aarch64-target-features.c
  test/Sema/builtins-arm64-mte.c

Index: test/Sema/builtins-arm64-mte.c
===================================================================
--- /dev/null
+++ test/Sema/builtins-arm64-mte.c
@@ -0,0 +1,136 @@
+// RUN: %clang_cc1 -triple arm64-arm-eabi %s -target-feature +mte -fsyntax-only -verify
+// RUN: %clang_cc1 -triple arm64-arm-eabi %s -target-feature +mte -x c++ -fsyntax-only -verify
+#include <stddef.h>
+#include <arm_acle.h>
+
+int  *create_tag1(int a, unsigned b) {
+  // expected-error@+1 {{first argument must be a pointer ('int' invalid)}}
+  return __arm_mte_create_random_tag(a,b);
+}
+
+int  *create_tag2(int *a, unsigned *b) {
+  // expected-error@+1 {{second argument must be an integer type ('unsigned int *' invalid)}}
+  return __arm_mte_create_random_tag(a,b);
+}
+
+int  *create_tag3(const int *a, unsigned b) {
+#ifdef __cplusplus
+  // expected-error@+1 {{cannot initialize return object of type 'int *' with an rvalue of type 'const int *'}}
+  return __arm_mte_create_random_tag(a,b);
+#else
+  // expected-warning@+1 {{returning 'const int *' from a function with result type 'int *' discards qualifiers}}
+  return __arm_mte_create_random_tag(a,b);
+#endif
+}
+
+int  *create_tag4(volatile int *a, unsigned b) {
+#ifdef __cplusplus
+  // expected-error@+1 {{cannot initialize return object of type 'int *' with an rvalue of type 'volatile int *'}}
+  return __arm_mte_create_random_tag(a,b);
+#else
+  // expected-warning@+1 {{returning 'volatile int *' from a function with result type 'int *' discards qualifiers}}
+  return __arm_mte_create_random_tag(a,b);
+#endif
+}
+
+int  *increment_tag1(int *a, unsigned b) {
+  // expected-error@+1 {{argument to '__builtin_arm_addg' must be a constant integer}}
+  return __arm_mte_increment_tag(a,b);
+}
+
+int  *increment_tag2(int *a) {
+  // expected-error@+1 {{argument value 16 is outside the valid range [0, 15]}}
+  return __arm_mte_increment_tag(a,16);
+}
+
+int  *increment_tag3(int *a) {
+  // expected-error@+1 {{argument value -1 is outside the valid range [0, 15]}}
+  return __arm_mte_increment_tag(a,-1);
+}
+
+int  *increment_tag4(const int *a) {
+#ifdef __cplusplus
+  // expected-error@+1 {{cannot initialize return object of type 'int *' with an rvalue of type 'const int *'}}
+  return __arm_mte_increment_tag(a,5);
+#else
+  // expected-warning@+1 {{returning 'const int *' from a function with result type 'int *' discards qualifiers}}
+  return __arm_mte_increment_tag(a,5);
+#endif
+}
+
+int *increment_tag5(const volatile int *a) {
+#ifdef __cplusplus
+  // expected-error@+1 {{cannot initialize return object of type 'int *' with an rvalue of type 'const volatile int *'}}
+  return __arm_mte_increment_tag(a,5);
+#else
+  // expected-warning@+1 {{returning 'const volatile int *' from a function with result type 'int *' discards qualifiers}}
+  return __arm_mte_increment_tag(a,5);
+#endif
+}
+
+unsigned exclude_tag1(int *ptr, unsigned m) {
+   // expected-error@+1 {{first argument must be a pointer ('int' invalid)}}
+   return  __arm_mte_exclude_tag(*ptr, m);
+}
+
+unsigned exclude_tag2(int *ptr, int *m) {
+   // expected-error@+1 {{second argument must be an integer type ('int *' invalid)}}
+   return  __arm_mte_exclude_tag(ptr, m);
+}
+
+void get_tag1() {
+   // expected-error@+1 {{too few arguments to function call, expected 1, have 0}}
+   __arm_mte_get_tag();
+}
+
+int *get_tag2(int ptr) {
+   // expected-error@+1 {{first argument must be a pointer ('int' invalid)}}
+   return __arm_mte_get_tag(ptr);
+}
+
+int *get_tag3(const volatile int *ptr) {
+#ifdef __cplusplus
+  // expected-error@+1 {{cannot initialize return object of type 'int *' with an rvalue of type 'const volatile int *'}}
+  return __arm_mte_get_tag(ptr);
+#else
+  // expected-warning@+1 {{returning 'const volatile int *' from a function with result type 'int *' discards qualifiers}}
+  return __arm_mte_get_tag(ptr);
+#endif
+}
+
+void set_tag1() {
+   // expected-error@+1 {{too few arguments to function call, expected 1, have 0}}
+   __arm_mte_set_tag();
+}
+
+void set_tag2(int ptr) {
+   // expected-error@+1 {{first argument must be a pointer ('int' invalid)}}
+   __arm_mte_set_tag(ptr);
+}
+
+ptrdiff_t subtract_pointers1(int a, int *b) {
+  // expected-error@+1 {{first argument must be a null or a pointer ('int' invalid)}}
+  return __arm_mte_ptrdiff(a, b);
+}
+
+ptrdiff_t subtract_pointers2(int *a, int b) {
+  // expected-error@+1 {{second argument must be a null or a pointer ('int' invalid)}}
+  return __arm_mte_ptrdiff(a, b);
+}
+
+ptrdiff_t subtract_pointers3(char *a, int *b) {
+  // expected-error@+1 {{'char *' and 'int *' are not pointers to compatible types}}
+  return __arm_mte_ptrdiff(a, b);
+}
+
+ptrdiff_t subtract_pointers4(int *a, char *b) {
+  // expected-error@+1 {{'int *' and 'char *' are not pointers to compatible types}}
+  return __arm_mte_ptrdiff(a, b);
+}
+
+#ifdef __cplusplus
+ptrdiff_t subtract_pointers5() {
+  // expected-error@+1 {{at least one argument must be a pointer ('nullptr_t', 'nullptr_t' invalid)}}
+  return __arm_mte_ptrdiff(nullptr, nullptr);
+}
+#endif
Index: test/Preprocessor/aarch64-target-features.c
===================================================================
--- test/Preprocessor/aarch64-target-features.c
+++ test/Preprocessor/aarch64-target-features.c
@@ -316,3 +316,6 @@
 // CHECK-V81A-FEATURE-2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+v8.1a" "-target-feature" "-crypto"
 // CHECK-V81A-FEATURE-3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "-neon"
 
+// ================== Check Memory Tagging Extensions (MTE).
+// RUN: %clang -target arm64-none-linux-gnu -march=armv8.5-a+memtag -x c -E -dM %s -o - 2>&1 | FileCheck -check-prefix=CHECK-MEMTAG %s
+// CHECK-MEMTAG: __ARM_FEATURE_MEMORY_TAGGING 1
Index: test/CodeGen/arm64-mte.c
===================================================================
--- /dev/null
+++ test/CodeGen/arm64-mte.c
@@ -0,0 +1,110 @@
+// Test memory tagging extension intrinsics
+// RUN: %clang_cc1 -triple aarch64-none-linux-eabi -target-feature +mte -O3 -S -emit-llvm -o - %s  | FileCheck %s
+#include <stddef.h>
+#include <arm_acle.h>
+
+// CHECK-LABEL: define i32* @create_tag1
+int *create_tag1(int *a, unsigned b) {
+// CHECK: [[T0:%[0-9]+]] = bitcast i32* %a to i8*
+// CHECK: [[T1:%[0-9]+]] = zext i32 %b to i64
+// CHECK: [[T2:%[0-9]+]] = tail call i8* @llvm.aarch64.irg(i8* [[T0]], i64 [[T1]])
+// CHECK: bitcast i8* [[T2]] to i32*
+        return __arm_mte_create_random_tag(a,b);
+}
+
+// CHECK-LABEL: define i16* @create_tag2
+short *create_tag2(short *a, unsigned b) {
+// CHECK: [[T0:%[0-9]+]] = bitcast i16* %a to i8*
+// CHECK: [[T1:%[0-9]+]] = zext i32 %b to i64
+// CHECK: [[T2:%[0-9]+]] = tail call i8* @llvm.aarch64.irg(i8* [[T0]], i64 [[T1]])
+// CHECK: bitcast i8* [[T2]] to i16*
+        return __arm_mte_create_random_tag(a,b);
+}
+
+// CHECK-LABEL: define i8* @create_tag3
+char *create_tag3(char *a, unsigned b) {
+// CHECK: [[T1:%[0-9]+]] = zext i32 %b to i64
+// CHECK: [[T2:%[0-9]+]] = tail call i8* @llvm.aarch64.irg(i8* %a, i64 [[T1]])
+// CHECK: ret i8* [[T2:%[0-9]+]]
+        return __arm_mte_create_random_tag(a,b);
+}
+
+// CHECK-LABEL: define i8* @increment_tag1
+char *increment_tag1(char *a) {
+// CHECK: call i8* @llvm.aarch64.addg(i8* %a, i64 3)
+        return __arm_mte_increment_tag(a,3);
+}
+
+// CHECK-LABEL: define i16* @increment_tag2
+short *increment_tag2(short *a) {
+// CHECK: [[T0:%[0-9]+]] = bitcast i16* %a to i8*
+// CHECK: [[T1:%[0-9]+]] = tail call i8* @llvm.aarch64.addg(i8* [[T0]], i64 3)
+// CHECK: [[T2:%[0-9]+]]  = bitcast i8* [[T1]] to i16*
+        return __arm_mte_increment_tag(a,3);
+}
+
+// CHECK-LABEL: define i32 @exclude_tag
+unsigned exclude_tag(int *a, unsigned m) {
+// CHECK: [[T0:%[0-9]+]] = zext i32 %m to i64
+// CHECK: [[T1:%[0-9]+]] = bitcast i32* %a to i8*
+// CHECK: [[T2:%[0-9]+]] = tail call i64 @llvm.aarch64.gmi(i8* [[T1]], i64 [[T0]])
+// CHECK: trunc i64 [[T2]] to i32
+  return __arm_mte_exclude_tag(a, m);
+}
+
+// CHECK-LABEL: define i32* @get_tag1
+int *get_tag1(int *a) {
+// CHECK: [[T0:%[0-9]+]] = bitcast i32* %a to i8*
+// CHECK: [[T1:%[0-9]+]] = tail call i8* @llvm.aarch64.ldg(i8* [[T0]], i8* [[T0]])
+// CHECK: [[T2:%[0-9]+]]  = bitcast i8* [[T1]] to i32*
+   return __arm_mte_get_tag(a);
+}
+
+// CHECK-LABEL: define i16* @get_tag2
+short *get_tag2(short *a) {
+// CHECK: [[T0:%[0-9]+]] = bitcast i16* %a to i8*
+// CHECK: [[T1:%[0-9]+]] = tail call i8* @llvm.aarch64.ldg(i8* [[T0]], i8* [[T0]])
+// CHECK: [[T2:%[0-9]+]]  = bitcast i8* [[T1]] to i16*
+   return __arm_mte_get_tag(a);
+}
+
+// CHECK-LABEL: define void @set_tag1
+void set_tag1(int *a) {
+// CHECK: [[T0:%[0-9]+]] = bitcast i32* %a to i8*
+// CHECK: tail call void @llvm.aarch64.stg(i8* [[T0]], i8* [[T0]])
+   __arm_mte_set_tag(a);
+}
+
+// CHECK-LABEL: define i64 @subtract_pointers
+ptrdiff_t subtract_pointers(int *a, int *b) {
+// CHECK: [[T0:%[0-9]+]] = bitcast i32* %a to i8*
+// CHECK: [[T1:%[0-9]+]] = bitcast i32* %b to i8*
+// CHECK: [[T2:%[0-9]+]] = tail call i64 @llvm.aarch64.subp(i8* [[T0]], i8* [[T1]])
+// CHECK: ret i64 [[T2]]
+   return __arm_mte_ptrdiff(a, b);
+}
+
+// CHECK-LABEL: define i64 @subtract_pointers_null_1
+ptrdiff_t subtract_pointers_null_1(int *a) {
+// CHECK: [[T0:%[0-9]+]] = bitcast i32* %a to i8*
+// CHECK: [[T1:%[0-9]+]] = tail call i64 @llvm.aarch64.subp(i8* [[T0]], i8* null)
+// CHECK: ret i64 [[T1]]
+   return __arm_mte_ptrdiff(a, NULL);
+}
+
+// CHECK-LABEL: define i64 @subtract_pointers_null_2
+ptrdiff_t subtract_pointers_null_2(int *a) {
+// CHECK: [[T0:%[0-9]+]] = bitcast i32* %a to i8*
+// CHECK: [[T1:%[0-9]+]] = tail call i64 @llvm.aarch64.subp(i8* null, i8* [[T0]])
+// CHECK: ret i64 [[T1]]
+   return __arm_mte_ptrdiff(NULL, a);
+}
+
+// Check arithmetic promotion on return type
+// CHECK-LABEL: define i32 @subtract_pointers4
+int subtract_pointers4(void* a, void *b) {
+// CHECK: [[T0:%[0-9]+]] = tail call i64 @llvm.aarch64.subp(i8* %a, i8* %b)
+// CHECK-NEXT: %cmp = icmp slt i64 [[T0]], 1
+// CHECK-NEXT:  = zext i1 %cmp to i32
+  return __arm_mte_ptrdiff(a,b) <= 0;
+}
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -1871,6 +1871,16 @@
       BuiltinID == AArch64::BI__builtin_arm_wsr64)
     return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true);
 
+  // Memory Tagging Extensions (MTE) Intrinsics
+  if (BuiltinID == AArch64::BI__builtin_arm_irg ||
+      BuiltinID == AArch64::BI__builtin_arm_addg ||
+      BuiltinID == AArch64::BI__builtin_arm_gmi ||
+      BuiltinID == AArch64::BI__builtin_arm_ldg ||
+      BuiltinID == AArch64::BI__builtin_arm_stg ||
+      BuiltinID == AArch64::BI__builtin_arm_subp) {
+    return SemaBuiltinARMMemoryTaggingCall(BuiltinID, TheCall);
+  }
+
   if (BuiltinID == AArch64::BI__builtin_arm_rsr ||
       BuiltinID == AArch64::BI__builtin_arm_rsrp ||
       BuiltinID == AArch64::BI__builtin_arm_wsr ||
@@ -6098,6 +6108,167 @@
   return false;
 }
 
+/// SemaBuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions
+bool Sema::SemaBuiltinARMMemoryTaggingCall( unsigned BuiltinID, CallExpr *TheCall) {
+  bool IsMTEBuiltin = BuiltinID == AArch64::BI__builtin_arm_irg ||
+                      BuiltinID == AArch64::BI__builtin_arm_addg ||
+                      BuiltinID == AArch64::BI__builtin_arm_gmi ||
+                      BuiltinID == AArch64::BI__builtin_arm_ldg ||
+                      BuiltinID == AArch64::BI__builtin_arm_stg ||
+                      BuiltinID == AArch64::BI__builtin_arm_subp;
+  assert(IsMTEBuiltin  && "Unexpected ARM MTE builtin.");
+
+  if (BuiltinID == AArch64::BI__builtin_arm_irg) {
+    if (checkArgCount(*this, TheCall, 2))
+      return true;
+    Expr *Arg0 = TheCall->getArg(0);
+    Expr *Arg1 = TheCall->getArg(1);
+
+    ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0);
+    if (FirstArg.isInvalid())
+      return true;
+    QualType FirstArgType = FirstArg.get()->getType();
+    if (!FirstArgType->isAnyPointerType())
+      return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
+               << "first" << FirstArgType << Arg0->getSourceRange();
+    TheCall->setArg(0, FirstArg.get());
+
+    ExprResult SecArg = DefaultLvalueConversion(Arg1);
+    if (SecArg.isInvalid())
+      return true;
+    QualType SecArgType = SecArg.get()->getType();
+    if (!SecArgType->isIntegerType())
+      return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer)
+               << "second" << SecArgType << Arg1->getSourceRange();
+
+    // Derive the return type from the pointer argument.
+    TheCall->setType(FirstArgType);
+    return false;
+  }
+
+  if (BuiltinID == AArch64::BI__builtin_arm_addg) {
+    if (checkArgCount(*this, TheCall, 2))
+      return true;
+
+    Expr *Arg0 = TheCall->getArg(0);
+    ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0);
+    if (FirstArg.isInvalid())
+      return true;
+    QualType FirstArgType = FirstArg.get()->getType();
+    if (!FirstArgType->isAnyPointerType())
+      return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
+               << "first" << FirstArgType << Arg0->getSourceRange();
+    TheCall->setArg(0, FirstArg.get());
+
+    // Derive the return type from the pointer argument.
+    TheCall->setType(FirstArgType);
+
+    // Second arg must be an constant in range [0,15]
+    return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15);
+  }
+
+  if (BuiltinID == AArch64::BI__builtin_arm_gmi) {
+    if (checkArgCount(*this, TheCall, 2))
+      return true;
+    Expr *Arg0 = TheCall->getArg(0);
+    Expr *Arg1 = TheCall->getArg(1);
+
+    ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0);
+    if (FirstArg.isInvalid())
+      return true;
+    QualType FirstArgType = FirstArg.get()->getType();
+    if (!FirstArgType->isAnyPointerType())
+      return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
+               << "first" << FirstArgType << Arg0->getSourceRange();
+
+    QualType SecArgType = Arg1->getType();
+    if (!SecArgType->isIntegerType())
+      return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer)
+               << "second" << SecArgType << Arg1->getSourceRange();
+    TheCall->setType(Context.IntTy);
+    return false;
+  }
+
+  if (BuiltinID == AArch64::BI__builtin_arm_ldg ||
+      BuiltinID == AArch64::BI__builtin_arm_stg) {
+    if (checkArgCount(*this, TheCall, 1))
+      return true;
+    Expr *Arg0 = TheCall->getArg(0);
+    ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0);
+    if (FirstArg.isInvalid())
+      return true;
+
+    QualType FirstArgType = FirstArg.get()->getType();
+    if (!FirstArgType->isAnyPointerType())
+      return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
+               << "first" << FirstArgType << Arg0->getSourceRange();
+    TheCall->setArg(0, FirstArg.get());
+
+    // Derive the return type from the pointer argument.
+    if (BuiltinID == AArch64::BI__builtin_arm_ldg)
+      TheCall->setType(FirstArgType);
+    return false;
+  }
+
+  if (BuiltinID == AArch64::BI__builtin_arm_subp) {
+    Expr *ArgA = TheCall->getArg(0);
+    Expr *ArgB = TheCall->getArg(1);
+
+    ExprResult ArgExprA = DefaultFunctionArrayLvalueConversion(ArgA);
+    ExprResult ArgExprB = DefaultFunctionArrayLvalueConversion(ArgB);
+
+    if (ArgExprA.isInvalid() || ArgExprB.isInvalid())
+      return true;
+
+    QualType ArgTypeA = ArgExprA.get()->getType();
+    QualType ArgTypeB = ArgExprB.get()->getType();
+
+    auto isNull = [&] (Expr *E) -> bool {
+      return E->isNullPointerConstant(
+                        Context, Expr::NPC_ValueDependentIsNotNull); };
+
+    // argument should be either a pointer or null
+    if (!ArgTypeA->isAnyPointerType() && !isNull(ArgA))
+      return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer)
+        << "first" << ArgTypeA << ArgA->getSourceRange();
+
+    if (!ArgTypeB->isAnyPointerType() && !isNull(ArgB))
+      return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer)
+        << "second" << ArgTypeB << ArgB->getSourceRange();
+
+    // Ensure Pointee types are compatible
+    if (ArgTypeA->isAnyPointerType() && !isNull(ArgA) &&
+        ArgTypeB->isAnyPointerType() && !isNull(ArgB)) {
+      QualType pointeeA = ArgTypeA->getPointeeType();
+      QualType pointeeB = ArgTypeB->getPointeeType();
+      if (!Context.typesAreCompatible(
+             Context.getCanonicalType(pointeeA).getUnqualifiedType(),
+             Context.getCanonicalType(pointeeB).getUnqualifiedType())) {
+        return Diag(TheCall->getBeginLoc(), diag::err_typecheck_sub_ptr_compatible)
+          << ArgTypeA <<  ArgTypeB << ArgA->getSourceRange()
+          << ArgB->getSourceRange();
+      }
+    }
+
+    // at least one argument should be pointer type
+    if (!ArgTypeA->isAnyPointerType() && !ArgTypeB->isAnyPointerType())
+      return Diag(TheCall->getBeginLoc(), diag::err_memtag_any2arg_pointer)
+        <<  ArgTypeA << ArgTypeB << ArgA->getSourceRange();
+
+    if (isNull(ArgA)) // adopt type of the other pointer
+      ArgExprA = ImpCastExprToType(ArgExprA.get(), ArgTypeB, CK_NullToPointer);
+
+    if (isNull(ArgB))
+      ArgExprB = ImpCastExprToType(ArgExprB.get(), ArgTypeA, CK_NullToPointer);
+
+    TheCall->setArg(0, ArgExprA.get());
+    TheCall->setArg(1, ArgExprB.get());
+    TheCall->setType(Context.LongLongTy);
+    return false;
+  }
+  return true;
+}
+
 /// SemaBuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr
 /// TheCall is an ARM/AArch64 special register string literal.
 bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall,
Index: lib/Headers/arm_acle.h
===================================================================
--- lib/Headers/arm_acle.h
+++ lib/Headers/arm_acle.h
@@ -605,6 +605,16 @@
 #define __arm_wsr64(sysreg, v) __builtin_arm_wsr64(sysreg, v)
 #define __arm_wsrp(sysreg, v) __builtin_arm_wsrp(sysreg, v)
 
+// Memory Tagging Extensions (MTE) Intrinsics
+#if __ARM_FEATURE_MEMORY_TAGGING
+#define __arm_mte_create_random_tag(__ptr, __mask)  __builtin_arm_irg(__ptr, __mask)
+#define __arm_mte_increment_tag(__ptr, __tag_offset)  __builtin_arm_addg(__ptr, __tag_offset)
+#define __arm_mte_exclude_tag(__ptr, __excluded)  __builtin_arm_gmi(__ptr, __excluded)
+#define __arm_mte_get_tag(__ptr) __builtin_arm_ldg(__ptr)
+#define __arm_mte_set_tag(__ptr) __builtin_arm_stg(__ptr)
+#define __arm_mte_ptrdiff(__ptra, __ptrb) __builtin_arm_subp(__ptra, __ptrb)
+#endif
+
 #if defined(__cplusplus)
 }
 #endif
Index: lib/CodeGen/CGBuiltin.cpp
===================================================================
--- lib/CodeGen/CGBuiltin.cpp
+++ lib/CodeGen/CGBuiltin.cpp
@@ -7040,6 +7040,84 @@
     return Builder.CreateCall(F, {Arg0, Arg1});
   }
 
+  // Memory Tagging Extensions (MTE) Intrinsics
+  Intrinsic::ID MTEIntrinsicID = Intrinsic::not_intrinsic;
+  switch (BuiltinID) {
+  case AArch64::BI__builtin_arm_irg:
+    MTEIntrinsicID = Intrinsic::aarch64_irg; break;
+  case  AArch64::BI__builtin_arm_addg:
+    MTEIntrinsicID = Intrinsic::aarch64_addg; break;
+  case  AArch64::BI__builtin_arm_gmi:
+    MTEIntrinsicID = Intrinsic::aarch64_gmi; break;
+  case  AArch64::BI__builtin_arm_ldg:
+    MTEIntrinsicID = Intrinsic::aarch64_ldg; break;
+  case AArch64::BI__builtin_arm_stg:
+    MTEIntrinsicID = Intrinsic::aarch64_stg; break;
+  case AArch64::BI__builtin_arm_subp:
+    MTEIntrinsicID = Intrinsic::aarch64_subp; break;
+  }
+
+  if (MTEIntrinsicID != Intrinsic::not_intrinsic) {
+    llvm::Type *T = ConvertType(E->getType());
+
+    if (MTEIntrinsicID == Intrinsic::aarch64_irg) {
+      Value *Pointer = EmitScalarExpr(E->getArg(0));
+      Value *Mask = EmitScalarExpr(E->getArg(1));
+
+      Pointer = Builder.CreatePointerCast(Pointer, Int8PtrTy);
+      Mask = Builder.CreateZExt(Mask, Int64Ty);
+      Value *RV = Builder.CreateCall(
+                       CGM.getIntrinsic(MTEIntrinsicID), {Pointer, Mask});
+       return Builder.CreatePointerCast(RV, T);
+    }
+    if (MTEIntrinsicID == Intrinsic::aarch64_addg) {
+      Value *Pointer = EmitScalarExpr(E->getArg(0));
+      Value *TagOffset = EmitScalarExpr(E->getArg(1));
+
+      Pointer = Builder.CreatePointerCast(Pointer, Int8PtrTy);
+      TagOffset = Builder.CreateZExt(TagOffset, Int64Ty);
+      Value *RV = Builder.CreateCall(
+                       CGM.getIntrinsic(MTEIntrinsicID), {Pointer, TagOffset});
+      return Builder.CreatePointerCast(RV, T);
+    }
+    if (MTEIntrinsicID == Intrinsic::aarch64_gmi) {
+      Value *Pointer = EmitScalarExpr(E->getArg(0));
+      Value *ExcludedMask = EmitScalarExpr(E->getArg(1));
+
+      ExcludedMask = Builder.CreateZExt(ExcludedMask, Int64Ty);
+      Pointer = Builder.CreatePointerCast(Pointer, Int8PtrTy);
+      return Builder.CreateCall(
+                       CGM.getIntrinsic(MTEIntrinsicID), {Pointer, ExcludedMask});
+    }
+    // Although it is possible to supply a different return
+    // address (first arg) to this intrinsic, for now we set
+    // return address same as input address.
+    if (MTEIntrinsicID == Intrinsic::aarch64_ldg) {
+      Value *TagAddress = EmitScalarExpr(E->getArg(0));
+      TagAddress = Builder.CreatePointerCast(TagAddress, Int8PtrTy);
+      Value *RV = Builder.CreateCall(
+                    CGM.getIntrinsic(MTEIntrinsicID), {TagAddress, TagAddress});
+      return Builder.CreatePointerCast(RV, T);
+    }
+    // Although it is possible to supply a different tag (to set)
+    // to this intrinsic (as first arg), for now we supply
+    // the tag that is in input address arg (common use case).
+    if (MTEIntrinsicID == Intrinsic::aarch64_stg) {
+        Value *TagAddress = EmitScalarExpr(E->getArg(0));
+        TagAddress = Builder.CreatePointerCast(TagAddress, Int8PtrTy);
+        return Builder.CreateCall(
+                 CGM.getIntrinsic(MTEIntrinsicID), {TagAddress, TagAddress});
+    }
+    if (MTEIntrinsicID == Intrinsic::aarch64_subp) {
+      Value *PointerA = EmitScalarExpr(E->getArg(0));
+      Value *PointerB = EmitScalarExpr(E->getArg(1));
+      PointerA = Builder.CreatePointerCast(PointerA, Int8PtrTy);
+      PointerB = Builder.CreatePointerCast(PointerB, Int8PtrTy);
+      return Builder.CreateCall(
+                       CGM.getIntrinsic(MTEIntrinsicID), {PointerA, PointerB});
+    }
+  }
+
   if (BuiltinID == AArch64::BI__builtin_arm_rsr ||
       BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
       BuiltinID == AArch64::BI__builtin_arm_rsrp ||
Index: lib/Basic/Targets/AArch64.h
===================================================================
--- lib/Basic/Targets/AArch64.h
+++ lib/Basic/Targets/AArch64.h
@@ -34,6 +34,7 @@
   unsigned HasFullFP16;
   unsigned HasDotProd;
   unsigned HasFP16FML;
+  unsigned HasMTE;
   llvm::AArch64::ArchKind ArchKind;
 
   static const Builtin::Info BuiltinInfo[];
Index: lib/Basic/Targets/AArch64.cpp
===================================================================
--- lib/Basic/Targets/AArch64.cpp
+++ lib/Basic/Targets/AArch64.cpp
@@ -194,6 +194,9 @@
   if (HasDotProd)
     Builder.defineMacro("__ARM_FEATURE_DOTPROD", "1");
 
+  if (HasMTE)
+    Builder.defineMacro("__ARM_FEATURE_MEMORY_TAGGING", "1");
+
   if ((FPU & NeonMode) && HasFP16FML)
     Builder.defineMacro("__ARM_FEATURE_FP16FML", "1");
 
@@ -258,6 +261,8 @@
       HasDotProd = 1;
     if (Feature == "+fp16fml")
       HasFP16FML = 1;
+    if (Feature == "+mte")
+      HasMTE = 1;
   }
 
   setDataLayout();
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -10726,6 +10726,7 @@
   bool SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall,
                                 int ArgNum, unsigned ExpectedFieldNum,
                                 bool AllowName);
+ bool SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall);
 public:
   enum FormatStringType {
     FST_Scanf,
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -9561,6 +9561,21 @@
    "the type is not trivially copyable|"
    "the type does not have the expected form}1">;
 
+// Memory Tagging Extensions (MTE) diagnostics
+def err_memtag_arg_null_or_pointer : Error<
+  "%0 argument must be a null or a pointer (%1 invalid)">;
+def err_memtag_any2arg_pointer : Error<
+  "at least one argument must be a pointer (%0, %1 invalid)">;
+def err_memtag_arg_must_be_pointer : Error<
+  "%0 argument must be a pointer (%1 invalid)">;
+def err_memtag_arg_must_be_integer : Error<
+  "%0 argument must be an integer type (%1 invalid)">;
+def err_memtag_arg_must_be_unsigned : Error<
+  "%0 argument must be an unsigned integer type (%1 invalid)">;
+def err_memtag_ptr_compatible : Error<
+  "%diff{$ and $ are not pointers to compatible types|"
+  "pointers to incompatible types}0,1">;
+
 def warn_dereference_of_noderef_type : Warning<
   "dereferencing %0; was declared with a 'noderef' type">, InGroup<NoDeref>;
 def warn_dereference_of_noderef_type_no_decl : Warning<
Index: include/clang/Basic/BuiltinsAArch64.def
===================================================================
--- include/clang/Basic/BuiltinsAArch64.def
+++ include/clang/Basic/BuiltinsAArch64.def
@@ -52,6 +52,14 @@
 BUILTIN(__builtin_arm_crc32d, "UiUiWUi", "nc")
 BUILTIN(__builtin_arm_crc32cd, "UiUiWUi", "nc")
 
+// Memory Tagging Extensions (MTE)
+BUILTIN(__builtin_arm_irg, "v*v*Ui", "t")
+BUILTIN(__builtin_arm_addg, "v*v*Ui", "t")
+BUILTIN(__builtin_arm_gmi, "Uiv*Ui", "t")
+BUILTIN(__builtin_arm_ldg, "v*v*", "t")
+BUILTIN(__builtin_arm_stg, "vv*", "t")
+BUILTIN(__builtin_arm_subp, "Uiv*v*", "t")
+
 // Memory barrier
 BUILTIN(__builtin_arm_dmb, "vUi", "nc")
 BUILTIN(__builtin_arm_dsb, "vUi", "nc")
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to