Hi Kyrill,

On 12/11/2019 15:57, Kyrill Tkachov wrote:
> 
> On 11/12/19 3:50 PM, Dennis Zhang wrote:
>> Hi Kyrill,
>>
>> On 12/11/2019 09:40, Kyrill Tkachov wrote:
>>> Hi Dennis,
>>>
>>> On 11/7/19 1:48 PM, Dennis Zhang wrote:
>>>> Hi Kyrill,
>>>>
>>>> I have rebased the patch on top of current truck.
>>>> For resolve_overloaded, I redefined my memtag overloading function to
>>>> fit the latest resolve_overloaded_builtin interface.
>>>>
>>>> Regression tested again and survived for aarch64-none-linux-gnu.
>>> Please reply inline rather than top-posting on gcc-patches.
>>>
>>>
>>>> Cheers
>>>> Dennis
>>>>
>>>> Changelog is updated as following:
>>>>
>>>> gcc/ChangeLog:
>>>>
>>>> 2019-11-07  Dennis Zhang  <dennis.zh...@arm.com>
>>>>
>>>>      * config/aarch64/aarch64-builtins.c (enum aarch64_builtins): Add
>>>>      AARCH64_MEMTAG_BUILTIN_START, AARCH64_MEMTAG_BUILTIN_IRG,
>>>>      AARCH64_MEMTAG_BUILTIN_GMI, AARCH64_MEMTAG_BUILTIN_SUBP,
>>>>      AARCH64_MEMTAG_BUILTIN_INC_TAG, AARCH64_MEMTAG_BUILTIN_SET_TAG,
>>>>      AARCH64_MEMTAG_BUILTIN_GET_TAG, and AARCH64_MEMTAG_BUILTIN_END.
>>>>      (aarch64_init_memtag_builtins): New.
>>>>      (AARCH64_INIT_MEMTAG_BUILTINS_DECL): New macro.
>>>>      (aarch64_general_init_builtins): Call 
>>>> aarch64_init_memtag_builtins.
>>>>      (aarch64_expand_builtin_memtag): New.
>>>>      (aarch64_general_expand_builtin): Call 
>>>> aarch64_expand_builtin_memtag.
>>>>      (AARCH64_BUILTIN_SUBCODE): New macro.
>>>>      (aarch64_resolve_overloaded_memtag): New.
>>>>      (aarch64_resolve_overloaded_builtin_general): New hook. Call
>>>>      aarch64_resolve_overloaded_memtag to handle overloaded MTE 
>>>> builtins.
>>>>      * config/aarch64/aarch64-c.c (aarch64_update_cpp_builtins): Define
>>>>      __ARM_FEATURE_MEMORY_TAGGING when enabled.
>>>>      (aarch64_resolve_overloaded_builtin): Call
>>>>      aarch64_resolve_overloaded_builtin_general.
>>>>      * config/aarch64/aarch64-protos.h
>>>>      (aarch64_resolve_overloaded_builtin_general): New declaration.
>>>>      * config/aarch64/aarch64.h (AARCH64_ISA_MEMTAG): New macro.
>>>>      (TARGET_MEMTAG): Likewise.
>>>>      * config/aarch64/aarch64.md (define_c_enum "unspec"): Add
>>>>      UNSPEC_GEN_TAG, UNSPEC_GEN_TAG_RND, and UNSPEC_TAG_SPACE.
>>>>      (irg, gmi, subp, addg, ldg, stg): New instructions.
>>>>      * config/aarch64/arm_acle.h (__arm_mte_create_random_tag): New 
>>>> macro.
>>>>      (__arm_mte_exclude_tag, __arm_mte_increment_tag): Likewise.
>>>>      (__arm_mte_ptrdiff, __arm_mte_set_tag, __arm_mte_get_tag): 
>>>> Likewise.
>>>>      * config/aarch64/predicates.md (aarch64_memtag_tag_offset): New.
>>>>      (aarch64_granule16_uimm6, aarch64_granule16_simm9): New.
>>>>      * config/arm/types.md (memtag): New.
>>>>      * doc/invoke.texi (-memtag): Update description.
>>>>
>>>> gcc/testsuite/ChangeLog:
>>>>
>>>> 2019-11-07  Dennis Zhang  <dennis.zh...@arm.com>
>>>>
>>>>      * gcc.target/aarch64/acle/memtag_1.c: New test.
>>>>      * gcc.target/aarch64/acle/memtag_2.c: New test.
>>>>      * gcc.target/aarch64/acle/memtag_3.c: New test.
>>>>
>>>>
>>>> On 04/11/2019 16:40, Kyrill Tkachov wrote:
>>>>> Hi Dennis,
>>>>>
>>>>> On 10/17/19 11:03 AM, Dennis Zhang wrote:
>>>>>> Hi,
>>>>>>
>>>>>> Arm Memory Tagging Extension (MTE) is published with Armv8.5-A.
>>>>>> It can be used for spatial and temporal memory safety detection and
>>>>>> lightweight lock and key system.
>>>>>>
>>>>>> This patch enables new intrinsics leveraging MTE instructions to
>>>>>> implement functionalities of creating tags, setting tags, reading 
>>>>>> tags,
>>>>>> and manipulating tags.
>>>>>> The intrinsics are part of Arm ACLE extension:
>>>>>> https://developer.arm.com/docs/101028/latest/memory-tagging-intrinsics 
>>>>>>
>>>>>> The MTE ISA specification can be found at
>>>>>> https://developer.arm.com/docs/ddi0487/latest chapter D6.
>>>>>>
>>>>>> Bootstraped and regtested for aarch64-none-linux-gnu.
>>>>>>
>>>>>> Please help to check if it's OK for trunk.
>>>>>>
>>>>> This looks mostly ok to me but for further review this needs to be
>>>>> rebased on top of current trunk as there are some conflicts with 
>>>>> the SVE
>>>>> ACLE changes that recently went in. Most conflicts looks trivial to
>>>>> resolve but one that needs more attention is the definition of the
>>>>> TARGET_RESOLVE_OVERLOADED_BUILTIN hook.
>>>>>
>>>>> Thanks,
>>>>>
>>>>> Kyrill
>>>>>
>>>>>> Many Thanks
>>>>>> Dennis
>>>>>>
>>>>>> gcc/ChangeLog:
>>>>>>
>>>>>> 2019-10-16  Dennis Zhang  <dennis.zh...@arm.com>
>>>>>>
>>>>>>           * config/aarch64/aarch64-builtins.c (enum
>>>>>> aarch64_builtins): Add
>>>>>>           AARCH64_MEMTAG_BUILTIN_START, AARCH64_MEMTAG_BUILTIN_IRG,
>>>>>>           AARCH64_MEMTAG_BUILTIN_GMI, AARCH64_MEMTAG_BUILTIN_SUBP,
>>>>>>           AARCH64_MEMTAG_BUILTIN_INC_TAG,
>>>>>> AARCH64_MEMTAG_BUILTIN_SET_TAG,
>>>>>>           AARCH64_MEMTAG_BUILTIN_GET_TAG, and
>>>>>> AARCH64_MEMTAG_BUILTIN_END.
>>>>>>           (aarch64_init_memtag_builtins): New.
>>>>>>           (AARCH64_INIT_MEMTAG_BUILTINS_DECL): New macro.
>>>>>>           (aarch64_general_init_builtins): Call
>>>>>> aarch64_init_memtag_builtins.
>>>>>>           (aarch64_expand_builtin_memtag): New.
>>>>>>           (aarch64_general_expand_builtin): Call
>>>>>> aarch64_expand_builtin_memtag.
>>>>>>           (AARCH64_BUILTIN_SUBCODE): New macro.
>>>>>>           (aarch64_resolve_overloaded_memtag): New.
>>>>>>           (aarch64_resolve_overloaded_builtin): New hook. Call
>>>>>>           aarch64_resolve_overloaded_memtag to handle overloaded MTE
>>>>>> builtins.
>>>>>>           * config/aarch64/aarch64-c.c (aarch64_update_cpp_builtins):
>>>>>> Define
>>>>>>           __ARM_FEATURE_MEMORY_TAGGING when enabled.
>>>>>>           * config/aarch64/aarch64-protos.h
>>>>>> (aarch64_resolve_overloaded_builtin):
>>>>>>           Add declaration.
>>>>>>           * config/aarch64/aarch64.c
>>>>>> (TARGET_RESOLVE_OVERLOADED_BUILTIN):
>>>>>>           New hook.
>>>>>>           * config/aarch64/aarch64.h (AARCH64_ISA_MEMTAG): New macro.
>>>>>>           (TARGET_MEMTAG): Likewise.
>>>>>>           * config/aarch64/aarch64.md (define_c_enum "unspec"): Add
>>>>>>           UNSPEC_GEN_TAG, UNSPEC_GEN_TAG_RND, and UNSPEC_TAG_SPACE.
>>>>>>           (irg, gmi, subp, addg, ldg, stg): New instructions.
>>>>>>           * config/aarch64/arm_acle.h 
>>>>>> (__arm_mte_create_random_tag): New
>>>>>> macro.
>>>>>>           (__arm_mte_exclude_tag, __arm_mte_increment_tag): Likewise.
>>>>>>           (__arm_mte_ptrdiff, __arm_mte_set_tag, __arm_mte_get_tag):
>>>>>> Likewise.
>>>>>>           * config/aarch64/predicates.md (aarch64_memtag_tag_offset):
>>>>>> New.
>>>>>>           (aarch64_granule16_uimm6, aarch64_granule16_simm9): New.
>>>>>>           * config/arm/types.md (memtag): New.
>>>>>>           * doc/invoke.texi (-memtag): Update description.
>>>>>>
>>>>>> gcc/testsuite/ChangeLog:
>>>>>>
>>>>>> 2019-10-16  Dennis Zhang  <dennis.zh...@arm.com>
>>>>>>
>>>>>>           * gcc.target/aarch64/acle/memtag_1.c: New test.
>>>>>>           * gcc.target/aarch64/acle/memtag_2.c: New test.
>>>>>>           * gcc.target/aarch64/acle/memtag_3.c: New test.
>>>
>>> +/* Expand an expression EXP that calls a MEMTAG built-in FCODE
>>> +   with result going to TARGET.  */
>>> +static rtx
>>> +aarch64_expand_builtin_memtag (int fcode, tree exp, rtx target)
>>> +{
>>> +  rtx pat = NULL;
>>> +  enum insn_code icode = aarch64_memtag_builtin_data[fcode -
>>> +               AARCH64_MEMTAG_BUILTIN_START - 1].icode;
>>> +
>>> +  rtx op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
>>> +  machine_mode mode0 = GET_MODE (op0);
>>> +  op0 = force_reg (mode0 == VOIDmode ? DImode : mode0, op0);
>>> +  op0 = convert_to_mode (DImode, op0, true);
>>> +
>>> +  switch (fcode)
>>> +    {
>>> +      case AARCH64_MEMTAG_BUILTIN_IRG:
>>> +      case AARCH64_MEMTAG_BUILTIN_GMI:
>>> +      case AARCH64_MEMTAG_BUILTIN_SUBP:
>>> +      case AARCH64_MEMTAG_BUILTIN_INC_TAG:
>>> +    {
>>> +      if (! target
>>> +          || GET_MODE (target) != DImode
>>> +          || ! (*insn_data[icode].operand[0].predicate) (target, 
>>> DImode))
>>> +        target = gen_reg_rtx (DImode);
>>> +
>>> +      if (fcode == AARCH64_MEMTAG_BUILTIN_INC_TAG)
>>> +        {
>>> +          rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1));
>>> +
>>> +          if ((*insn_data[icode].operand[3].predicate) (op1, QImode))
>>> +        {
>>> +          pat = GEN_FCN (icode) (target, op0, const0_rtx, op1);
>>> +          break;
>>> +        }
>>> +          error ("%Kargument %d must be a constant immediate "
>>> +             "in range [0,15]", exp, 2);
>>> +          return target;
>>> +        }
>>> +      else
>>> +        {
>>> +          rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1));
>>> +          machine_mode mode1 = GET_MODE (op1);
>>> +          op1 = force_reg (mode1 == VOIDmode ? DImode : mode1, op1);
>>> +          op1 = convert_to_mode (DImode, op1, true);
>>> +          pat = GEN_FCN (icode) (target, op0, op1);
>>> +        }
>>> +      break;
>>> +    }
>>> +      case AARCH64_MEMTAG_BUILTIN_GET_TAG:
>>> +    target = op0;
>>> +    pat = GEN_FCN (icode) (target, op0, const0_rtx);
>>> +    break;
>>> +      case AARCH64_MEMTAG_BUILTIN_SET_TAG:
>>> +    pat = GEN_FCN (icode) (op0, op0, const0_rtx);
>>> +    break;
>>> +      default:
>>> +    gcc_unreachable();
>>> +    }
>>> +
>>> +  if (!pat)
>>> +    return NULL_RTX;
>>> +
>>> +  emit_insn (pat);
>>> +  return target;
>>> +}
>>> +
>>>
>>> I think we want to error out when using -mabi=ilp32.
>>> Can you please add an error message when they are used with 
>>> TARGET_ILP32.
>> Done. And it's tested in testsuite memtag_3.c.
>>
>>> diff --git a/gcc/testsuite/gcc.target/aarch64/acle/memtag_1.c
>>> b/gcc/testsuite/gcc.target/aarch64/acle/memtag_1.c
>>> new file mode 100644
>>> index 00000000000..a738f7e0b58
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/aarch64/acle/memtag_1.c
>>> @@ -0,0 +1,61 @@
>>> +/* Test the MEMTAG ACLE intrinsic.  */
>>> +
>>> +/* { dg-do compile { target aarch64-*-* } } */
>>> +/* { dg-options "-O2 -march=armv8.5-a+memtag" } */
>>> +
>>>
>>> You shouldn't need the  { target aarch64-*-* } here unless you're trying
>>> to restrict this for big-endian?
>>> Instead we should gate these on lp64 target to prevent these from
>>> running on ILP32 targets.
>> Fixed. And regtested again for aarch64-none-linux-gnu.
>> Thanks a lot for the feedback.
>>
>>> Ok with those two changes.
>>> Thanks for the patch!
>>> Kyrill
>>>
>>>    +#include "arm_acle.h"
>>> +
> 
> +/* Expand an expression EXP that calls a MEMTAG built-in FCODE
> +   with result going to TARGET.  */
> +static rtx
> +aarch64_expand_builtin_memtag (int fcode, tree exp, rtx target)
> +{
> +  if (TARGET_ILP32)
> +    error ("Memory Tagging Extension does not support '-mabi=ilp32'");
> 
> 
> You have to return const0_rtx here (see the other calls to error () in 
> this file) rather than continue with the processing.
> Also, to render the quotes properly use %<-mabi=ilp32%> in the string.
> 

The patch is fixed as attached.

Thanks a lot,
Dennis

> Ok with that change.
> Thanks,
> Kyrill
> 
> +
> +  rtx pat = NULL;
> 
> 
> 
> 
>> Cheers
>> Dennis
diff --git a/gcc/config/aarch64/aarch64-builtins.c b/gcc/config/aarch64/aarch64-builtins.c
index 83d6f75ae07..c35a1b1f029 100644
--- a/gcc/config/aarch64/aarch64-builtins.c
+++ b/gcc/config/aarch64/aarch64-builtins.c
@@ -448,6 +448,15 @@ enum aarch64_builtins
   /* Armv8.5-a RNG instruction builtins.  */
   AARCH64_BUILTIN_RNG_RNDR,
   AARCH64_BUILTIN_RNG_RNDRRS,
+  /* MEMTAG builtins.  */
+  AARCH64_MEMTAG_BUILTIN_START,
+  AARCH64_MEMTAG_BUILTIN_IRG,
+  AARCH64_MEMTAG_BUILTIN_GMI,
+  AARCH64_MEMTAG_BUILTIN_SUBP,
+  AARCH64_MEMTAG_BUILTIN_INC_TAG,
+  AARCH64_MEMTAG_BUILTIN_SET_TAG,
+  AARCH64_MEMTAG_BUILTIN_GET_TAG,
+  AARCH64_MEMTAG_BUILTIN_END,
   AARCH64_BUILTIN_MAX
 };
 
@@ -1130,6 +1139,51 @@ aarch64_init_rng_builtins (void)
 				   AARCH64_BUILTIN_RNG_RNDRRS);
 }
 
+/* Initialize the memory tagging extension (MTE) builtins.  */
+struct
+{
+  tree ftype;
+  enum insn_code icode;
+} aarch64_memtag_builtin_data[AARCH64_MEMTAG_BUILTIN_END -
+			      AARCH64_MEMTAG_BUILTIN_START - 1];
+
+static void
+aarch64_init_memtag_builtins (void)
+{
+  tree fntype = NULL;
+
+#define AARCH64_INIT_MEMTAG_BUILTINS_DECL(F, N, I, T) \
+  aarch64_builtin_decls[AARCH64_MEMTAG_BUILTIN_##F] \
+    = aarch64_general_add_builtin ("__builtin_aarch64_memtag_"#N, \
+				   T, AARCH64_MEMTAG_BUILTIN_##F); \
+  aarch64_memtag_builtin_data[AARCH64_MEMTAG_BUILTIN_##F - \
+			      AARCH64_MEMTAG_BUILTIN_START - 1] = \
+				{T, CODE_FOR_##I};
+
+  fntype = build_function_type_list (ptr_type_node, ptr_type_node,
+				     uint64_type_node, NULL);
+  AARCH64_INIT_MEMTAG_BUILTINS_DECL (IRG, irg, irg, fntype);
+
+  fntype = build_function_type_list (uint64_type_node, ptr_type_node,
+				     uint64_type_node, NULL);
+  AARCH64_INIT_MEMTAG_BUILTINS_DECL (GMI, gmi, gmi, fntype);
+
+  fntype = build_function_type_list (ptrdiff_type_node, ptr_type_node,
+				     ptr_type_node, NULL);
+  AARCH64_INIT_MEMTAG_BUILTINS_DECL (SUBP, subp, subp, fntype);
+
+  fntype = build_function_type_list (ptr_type_node, ptr_type_node,
+				     unsigned_type_node, NULL);
+  AARCH64_INIT_MEMTAG_BUILTINS_DECL (INC_TAG, inc_tag, addg, fntype);
+
+  fntype = build_function_type_list (void_type_node, ptr_type_node, NULL);
+  AARCH64_INIT_MEMTAG_BUILTINS_DECL (SET_TAG, set_tag, stg, fntype);
+
+  fntype = build_function_type_list (ptr_type_node, ptr_type_node, NULL);
+  AARCH64_INIT_MEMTAG_BUILTINS_DECL (GET_TAG, get_tag, ldg, fntype);
+
+#undef AARCH64_INIT_MEMTAG_BUILTINS_DECL
+}
 
 /* Initialize all builtins in the AARCH64_BUILTIN_GENERAL group.  */
 
@@ -1184,6 +1238,9 @@ aarch64_general_init_builtins (void)
 
   if (TARGET_TME)
     aarch64_init_tme_builtins ();
+
+  if (TARGET_MEMTAG)
+    aarch64_init_memtag_builtins ();
 }
 
 /* Implement TARGET_BUILTIN_DECL for the AARCH64_BUILTIN_GENERAL group.  */
@@ -1665,6 +1722,79 @@ aarch64_expand_rng_builtin (tree exp, rtx target, int fcode, int ignore)
   return target;
 }
 
+/* Expand an expression EXP that calls a MEMTAG built-in FCODE
+   with result going to TARGET.  */
+static rtx
+aarch64_expand_builtin_memtag (int fcode, tree exp, rtx target)
+{
+  if (TARGET_ILP32)
+    {
+      error ("Memory Tagging Extension does not support %<-mabi=ilp32%>");
+      return const0_rtx;
+    }
+
+  rtx pat = NULL;
+  enum insn_code icode = aarch64_memtag_builtin_data[fcode -
+			   AARCH64_MEMTAG_BUILTIN_START - 1].icode;
+
+  rtx op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
+  machine_mode mode0 = GET_MODE (op0);
+  op0 = force_reg (mode0 == VOIDmode ? DImode : mode0, op0);
+  op0 = convert_to_mode (DImode, op0, true);
+
+  switch (fcode)
+    {
+      case AARCH64_MEMTAG_BUILTIN_IRG:
+      case AARCH64_MEMTAG_BUILTIN_GMI:
+      case AARCH64_MEMTAG_BUILTIN_SUBP:
+      case AARCH64_MEMTAG_BUILTIN_INC_TAG:
+	{
+	  if (! target
+	      || GET_MODE (target) != DImode
+	      || ! (*insn_data[icode].operand[0].predicate) (target, DImode))
+	    target = gen_reg_rtx (DImode);
+
+	  if (fcode == AARCH64_MEMTAG_BUILTIN_INC_TAG)
+	    {
+	      rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1));
+
+	      if ((*insn_data[icode].operand[3].predicate) (op1, QImode))
+		{
+		  pat = GEN_FCN (icode) (target, op0, const0_rtx, op1);
+		  break;
+		}
+	      error ("%Kargument %d must be a constant immediate "
+		     "in range [0,15]", exp, 2);
+	      return const0_rtx;
+	    }
+	  else
+	    {
+	      rtx op1 = expand_normal (CALL_EXPR_ARG (exp, 1));
+	      machine_mode mode1 = GET_MODE (op1);
+	      op1 = force_reg (mode1 == VOIDmode ? DImode : mode1, op1);
+	      op1 = convert_to_mode (DImode, op1, true);
+	      pat = GEN_FCN (icode) (target, op0, op1);
+	    }
+	  break;
+	}
+      case AARCH64_MEMTAG_BUILTIN_GET_TAG:
+	target = op0;
+	pat = GEN_FCN (icode) (target, op0, const0_rtx);
+	break;
+      case AARCH64_MEMTAG_BUILTIN_SET_TAG:
+	pat = GEN_FCN (icode) (op0, op0, const0_rtx);
+	break;
+      default:
+	gcc_unreachable();
+    }
+
+  if (!pat)
+    return NULL_RTX;
+
+  emit_insn (pat);
+  return target;
+}
+
 /* Expand an expression EXP that calls built-in function FCODE,
    with result going to TARGET if that's convenient.  IGNORE is true
    if the result of the builtin is ignored.  */
@@ -1800,6 +1930,10 @@ aarch64_general_expand_builtin (unsigned int fcode, tree exp, rtx target,
       || fcode == AARCH64_TME_BUILTIN_TCANCEL)
     return aarch64_expand_builtin_tme (fcode, exp, target);
 
+  if (fcode >= AARCH64_MEMTAG_BUILTIN_START
+      && fcode <= AARCH64_MEMTAG_BUILTIN_END)
+    return aarch64_expand_builtin_memtag (fcode, exp, target);
+
   gcc_unreachable ();
 }
 
@@ -2151,6 +2285,106 @@ aarch64_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
 			    reload_fenv, restore_fnenv), update_call);
 }
 
+/* Resolve overloaded MEMTAG build-in functions.  */
+#define AARCH64_BUILTIN_SUBCODE(F) \
+  (DECL_MD_FUNCTION_CODE (F) >> AARCH64_BUILTIN_SHIFT)
+
+static tree
+aarch64_resolve_overloaded_memtag (location_t loc,
+				   tree fndecl, void *pass_params)
+{
+  vec<tree, va_gc> *params = static_cast<vec<tree, va_gc> *> (pass_params);
+  unsigned param_num = params ? params->length() : 0;
+  unsigned int fcode = AARCH64_BUILTIN_SUBCODE (fndecl);
+  tree inittype = aarch64_memtag_builtin_data[
+		    fcode - AARCH64_MEMTAG_BUILTIN_START - 1].ftype;
+  unsigned arg_num = list_length (TYPE_ARG_TYPES (inittype)) - 1;
+
+  if (param_num != arg_num)
+    {
+      TREE_TYPE (fndecl) = inittype;
+      return NULL_TREE;
+    }
+  tree retype = NULL;
+
+  if (fcode == AARCH64_MEMTAG_BUILTIN_SUBP)
+    {
+      tree t0 = TREE_TYPE ((*params)[0]);
+      tree t1 = TREE_TYPE ((*params)[1]);
+
+      if (t0 == error_mark_node || TREE_CODE (t0) != POINTER_TYPE)
+	t0 = ptr_type_node;
+      if (t1 == error_mark_node || TREE_CODE (t1) != POINTER_TYPE)
+	t1 = ptr_type_node;
+
+      if (TYPE_MODE (t0) != DImode)
+	warning_at (loc, 1, "expected 64-bit address but argument 1 is %d-bit",
+	    (int)tree_to_shwi (DECL_SIZE ((*params)[0])));
+
+      if (TYPE_MODE (t1) != DImode)
+	warning_at (loc, 1, "expected 64-bit address but argument 2 is %d-bit",
+	    (int)tree_to_shwi (DECL_SIZE ((*params)[1])));
+
+      retype = build_function_type_list (ptrdiff_type_node, t0, t1, NULL);
+    }
+  else
+    {
+      tree t0 = TREE_TYPE ((*params)[0]);
+
+      if (t0 == error_mark_node || TREE_CODE (t0) != POINTER_TYPE)
+	{
+	  TREE_TYPE (fndecl) = inittype;
+	  return NULL_TREE;
+	}
+
+      if (TYPE_MODE (t0) != DImode)
+	warning_at (loc, 1, "expected 64-bit address but argument 1 is %d-bit",
+	    (int)tree_to_shwi (DECL_SIZE ((*params)[0])));
+
+      switch (fcode)
+	{
+	case AARCH64_MEMTAG_BUILTIN_IRG:
+	  retype = build_function_type_list (t0, t0, uint64_type_node, NULL);
+	  break;
+	case AARCH64_MEMTAG_BUILTIN_GMI:
+	  retype = build_function_type_list (uint64_type_node, t0,
+	      uint64_type_node, NULL);
+	  break;
+	case AARCH64_MEMTAG_BUILTIN_INC_TAG:
+	  retype = build_function_type_list (t0, t0, unsigned_type_node, NULL);
+	  break;
+	case AARCH64_MEMTAG_BUILTIN_SET_TAG:
+	  retype = build_function_type_list (void_type_node, t0, NULL);
+	  break;
+	case AARCH64_MEMTAG_BUILTIN_GET_TAG:
+	  retype = build_function_type_list (t0, t0, NULL);
+	  break;
+	default:
+	  return NULL_TREE;
+	}
+    }
+
+  if (!retype || retype == error_mark_node)
+    TREE_TYPE (fndecl) = inittype;
+  else
+    TREE_TYPE (fndecl) = retype;
+
+  return NULL_TREE;
+}
+
+/* Called at aarch64_resolve_overloaded_builtin in aarch64-c.c.  */
+tree
+aarch64_resolve_overloaded_builtin_general (location_t loc, tree function,
+					    void *pass_params)
+{
+  unsigned int fcode = AARCH64_BUILTIN_SUBCODE (function);
+
+  if (fcode >= AARCH64_MEMTAG_BUILTIN_START
+      && fcode <= AARCH64_MEMTAG_BUILTIN_END)
+    return aarch64_resolve_overloaded_memtag(loc, function, pass_params);
+
+  return NULL_TREE;
+}
 
 #undef AARCH64_CHECK_BUILTIN_MODE
 #undef AARCH64_FIND_FRINT_VARIANT
diff --git a/gcc/config/aarch64/aarch64-c.c b/gcc/config/aarch64/aarch64-c.c
index 7c322ca0813..7ffa4609be4 100644
--- a/gcc/config/aarch64/aarch64-c.c
+++ b/gcc/config/aarch64/aarch64-c.c
@@ -161,6 +161,7 @@ aarch64_update_cpp_builtins (cpp_reader *pfile)
   aarch64_def_or_undef (TARGET_FRINT, "__ARM_FEATURE_FRINT", pfile);
   aarch64_def_or_undef (TARGET_TME, "__ARM_FEATURE_TME", pfile);
   aarch64_def_or_undef (TARGET_RNG, "__ARM_FEATURE_RNG", pfile);
+  aarch64_def_or_undef (TARGET_MEMTAG, "__ARM_FEATURE_MEMORY_TAGGING", pfile);
 
   /* Not for ACLE, but required to keep "float.h" correct if we switch
      target between implementations that do or do not support ARMv8.2-A
@@ -277,8 +278,8 @@ aarch64_resolve_overloaded_builtin (unsigned int uncast_location,
   switch (code & AARCH64_BUILTIN_CLASS)
     {
     case AARCH64_BUILTIN_GENERAL:
-      return NULL_TREE;
-
+      return aarch64_resolve_overloaded_builtin_general (location, fndecl,
+							 uncast_arglist);
     case AARCH64_BUILTIN_SVE:
       new_fndecl = aarch64_sve::resolve_overloaded_builtin (location, subcode,
 							    arglist);
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index 1d4f4fd4888..c60c841c60c 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -772,4 +772,6 @@ extern const atomic_ool_names aarch64_ool_ldset_names;
 extern const atomic_ool_names aarch64_ool_ldclr_names;
 extern const atomic_ool_names aarch64_ool_ldeor_names;
 
+tree aarch64_resolve_overloaded_builtin_general (location_t, tree, void *);
+
 #endif /* GCC_AARCH64_PROTOS_H */
diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
index 425a36332cd..ee01909abb9 100644
--- a/gcc/config/aarch64/aarch64.h
+++ b/gcc/config/aarch64/aarch64.h
@@ -248,6 +248,7 @@ extern unsigned aarch64_architecture_version;
 #define AARCH64_ISA_RNG		   (aarch64_isa_flags & AARCH64_FL_RNG)
 #define AARCH64_ISA_V8_5	   (aarch64_isa_flags & AARCH64_FL_V8_5)
 #define AARCH64_ISA_TME		   (aarch64_isa_flags & AARCH64_FL_TME)
+#define AARCH64_ISA_MEMTAG	   (aarch64_isa_flags & AARCH64_FL_MEMTAG)
 
 /* Crypto is an optional extension to AdvSIMD.  */
 #define TARGET_CRYPTO (TARGET_SIMD && AARCH64_ISA_CRYPTO)
@@ -304,6 +305,9 @@ extern unsigned aarch64_architecture_version;
 /* Random number instructions from Armv8.5-a.  */
 #define TARGET_RNG (AARCH64_ISA_RNG)
 
+/* Memory Tagging instructions optional to Armv8.5 enabled through +memtag.  */
+#define TARGET_MEMTAG (AARCH64_ISA_V8_5 && AARCH64_ISA_MEMTAG)
+
 /* Make sure this is always defined so we don't have to check for ifdefs
    but rather use normal ifs.  */
 #ifndef TARGET_FIX_ERR_A53_835769_DEFAULT
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index f19e2272750..9987fb900b5 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -268,6 +268,9 @@
     UNSPEC_SVE_PREFETCH_GATHER
     UNSPEC_SVE_COMPACT
     UNSPEC_SVE_SPLICE
+    UNSPEC_GEN_TAG		; Generate a 4-bit MTE tag.
+    UNSPEC_GEN_TAG_RND		; Generate a random 4-bit MTE tag.
+    UNSPEC_TAG_SPACE		; Translate address to MTE tag address space.
 ])
 
 (define_c_enum "unspecv" [
@@ -7384,6 +7387,93 @@
   [(set_attr "type" "mrs")]
 )
 
+;; Memory Tagging Extension (MTE) instructions.
+
+(define_insn "irg"
+  [(set (match_operand:DI 0 "register_operand" "=rk")
+	(ior:DI
+	 (and:DI (match_operand:DI 1 "register_operand" "rk")
+		 (const_int -1080863910568919041)) ;; 0xf0ff...
+	 (ashift:DI (unspec:QI [(match_operand:DI 2 "register_operand" "r")]
+		     UNSPEC_GEN_TAG_RND)
+		    (const_int 56))))]
+  "TARGET_MEMTAG"
+  "irg\\t%0, %1, %2"
+  [(set_attr "type" "memtag")]
+)
+
+(define_insn "gmi"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(ior:DI (ashift:DI
+		 (const_int 1)
+		 (and:QI (lshiftrt:DI
+			  (match_operand:DI 1 "register_operand" "rk")
+			  (const_int 56)) (const_int 15)))
+		(match_operand:DI 2 "register_operand" "r")))]
+  "TARGET_MEMTAG"
+  "gmi\\t%0, %1, %2"
+  [(set_attr "type" "memtag")]
+)
+
+(define_insn "addg"
+  [(set (match_operand:DI 0 "register_operand" "=rk")
+	(ior:DI
+	 (and:DI (plus:DI (match_operand:DI 1 "register_operand" "rk")
+			  (match_operand:DI 2 "aarch64_granule16_uimm6" "i"))
+		 (const_int -1080863910568919041)) ;; 0xf0ff...
+	 (ashift:DI
+	  (unspec:QI
+	   [(and:QI (lshiftrt:DI (match_dup 1) (const_int 56)) (const_int 15))
+	    (match_operand:QI 3 "aarch64_memtag_tag_offset" "i")]
+	   UNSPEC_GEN_TAG)
+	  (const_int 56))))]
+  "TARGET_MEMTAG"
+  "addg\\t%0, %1, #%2, #%3"
+  [(set_attr "type" "memtag")]
+)
+
+(define_insn "subp"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(minus:DI
+	  (and:DI (match_operand:DI 1 "register_operand" "rk")
+		  (const_int 72057594037927935)) ;; 0x00ff...
+	  (and:DI (match_operand:DI 2 "register_operand" "rk")
+		  (const_int 72057594037927935))))] ;; 0x00ff...
+  "TARGET_MEMTAG"
+  "subp\\t%0, %1, %2"
+  [(set_attr "type" "memtag")]
+)
+
+;; LDG will use the 16-byte aligned value of the address.
+(define_insn "ldg"
+  [(set (match_operand:DI 0 "register_operand" "+r")
+	(ior:DI
+	 (and:DI (match_dup 0) (const_int -1080863910568919041)) ;; 0xf0ff...
+	 (ashift:DI
+	  (mem:QI (unspec:DI
+	   [(and:DI (plus:DI (match_operand:DI 1 "register_operand" "rk")
+			     (match_operand:DI 2 "aarch64_granule16_simm9" "i"))
+		    (const_int -16))] UNSPEC_TAG_SPACE))
+	  (const_int 56))))]
+  "TARGET_MEMTAG"
+  "ldg\\t%0, [%1, #%2]"
+  [(set_attr "type" "memtag")]
+)
+
+;; STG doesn't align the address but aborts with alignment fault
+;; when the address is not 16-byte aligned.
+(define_insn "stg"
+  [(set (mem:QI (unspec:DI
+	 [(plus:DI (match_operand:DI 1 "register_operand" "rk")
+		   (match_operand:DI 2 "aarch64_granule16_simm9" "i"))]
+	 UNSPEC_TAG_SPACE))
+	(and:QI (lshiftrt:DI (match_operand:DI 0 "register_operand" "rk")
+			     (const_int 56)) (const_int 15)))]
+  "TARGET_MEMTAG"
+  "stg\\t%0, [%1, #%2]"
+  [(set_attr "type" "memtag")]
+)
+
 ;; AdvSIMD Stuff
 (include "aarch64-simd.md")
 
diff --git a/gcc/config/aarch64/arm_acle.h b/gcc/config/aarch64/arm_acle.h
index 2284e71648a..1dfac866e0a 100644
--- a/gcc/config/aarch64/arm_acle.h
+++ b/gcc/config/aarch64/arm_acle.h
@@ -209,6 +209,29 @@ __rndrrs (uint64_t *__res)
 
 #pragma GCC pop_options
 
+#pragma GCC push_options
+#pragma GCC target ("arch=armv8.5-a+memtag")
+
+#define __arm_mte_create_random_tag(__ptr, __u64_mask) \
+  __builtin_aarch64_memtag_irg(__ptr, __u64_mask)
+
+#define __arm_mte_exclude_tag(__ptr, __u64_excluded) \
+  __builtin_aarch64_memtag_gmi(__ptr, __u64_excluded)
+
+#define __arm_mte_ptrdiff(__ptr_a, __ptr_b) \
+  __builtin_aarch64_memtag_subp(__ptr_a, __ptr_b)
+
+#define __arm_mte_increment_tag(__ptr, __u_offset) \
+  __builtin_aarch64_memtag_inc_tag(__ptr, __u_offset)
+
+#define __arm_mte_set_tag(__tagged_address) \
+  __builtin_aarch64_memtag_set_tag(__tagged_address)
+
+#define __arm_mte_get_tag(__address) \
+  __builtin_aarch64_memtag_get_tag(__address)
+
+#pragma GCC pop_options
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md
index 2c5c53c716d..7eb49cfe66a 100644
--- a/gcc/config/aarch64/predicates.md
+++ b/gcc/config/aarch64/predicates.md
@@ -869,3 +869,17 @@
 
 (define_predicate "aarch64_sve_any_binary_operator"
   (match_code "plus,minus,mult,div,udiv,smax,umax,smin,umin,and,ior,xor"))
+
+(define_predicate "aarch64_memtag_tag_offset"
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (INTVAL (op), 0, 15)")))
+
+(define_predicate "aarch64_granule16_uimm6"
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (INTVAL (op), 0, 1008)
+		    && !(INTVAL (op) & 0xf)")))
+
+(define_predicate "aarch64_granule16_simm9"
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (INTVAL (op),  -4096, 4080)
+		    && !(INTVAL (op) & 0xf)")))
diff --git a/gcc/config/arm/types.md b/gcc/config/arm/types.md
index 60faad65979..df39522f2ad 100644
--- a/gcc/config/arm/types.md
+++ b/gcc/config/arm/types.md
@@ -1096,7 +1096,8 @@
   crypto_sm3,\
   crypto_sm4,\
   coproc,\
-  tme"
+  tme,\
+  memtag"
    (const_string "untyped"))
 
 ; Is this an (integer side) multiply with a 32-bit (or smaller) result?
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 00eb7e77808..11e093e3da6 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -16268,9 +16268,8 @@ Enable the Armv8.5-a Random Number instructions.  This option is only to
 enable the extension at the assembler level and does not affect code
 generation.
 @item memtag
-Enable the Armv8.5-a Memory Tagging Extensions.  This option is only to
-enable the extension at the assembler level and does not affect code
-generation.
+Enable the Armv8.5-a Memory Tagging Extensions.
+Use of this option with architectures prior to Armv8.5-A is not supported.
 @item sb
 Enable the Armv8-a Speculation Barrier instruction.  This option is only to
 enable the extension at the assembler level and does not affect code
diff --git a/gcc/testsuite/gcc.target/aarch64/acle/memtag_1.c b/gcc/testsuite/gcc.target/aarch64/acle/memtag_1.c
new file mode 100644
index 00000000000..f8368690032
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/acle/memtag_1.c
@@ -0,0 +1,62 @@
+/* Test the MEMTAG ACLE intrinsic.  */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-options "-O3 -march=armv8.5-a+memtag" } */
+
+#include "arm_acle.h"
+
+/* irg */
+
+void *
+test_memtag_1 (void *p)
+{
+  return __arm_mte_create_random_tag (p, 0);
+}
+
+/* gmi */
+
+uint64_t
+test_memtag_2 (void *p)
+{
+  return __arm_mte_exclude_tag (p, 0);
+}
+
+/* addg */
+
+void *
+test_memtag_3 (void *p)
+{
+  return __arm_mte_increment_tag (p, 1);
+}
+
+/* subp */
+
+int64_t
+test_memtag_4 (void *p, void *q)
+{
+  return __arm_mte_ptrdiff (p, q);
+}
+
+/* ldg */
+
+void *
+test_memtag_5 (void *p)
+{
+  return __arm_mte_get_tag (p);
+}
+
+/* stg */
+
+void
+test_memtag_6 (void *p)
+{
+  __arm_mte_set_tag (p);
+}
+
+/* { dg-final { scan-assembler-times {irg\tx..?, x..?, x..?\n} 1 } } */
+/* { dg-final { scan-assembler-times {gmi\tx..?, x..?, x..?\n} 1 } } */
+/* { dg-final { scan-assembler-times {subp\tx..?, x..?, x..?\n} 1 } } */
+/* { dg-final { scan-assembler-times {addg\tx..?, x..?, #0, #1\n} 1 } } */
+/* { dg-final { scan-assembler-times {ldg\tx..?, \[x..?, #0\]\n} 1 } } */
+/* { dg-final { scan-assembler-times {stg\tx..?, \[x..?, #0\]\n} 1 } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.target/aarch64/acle/memtag_2.c b/gcc/testsuite/gcc.target/aarch64/acle/memtag_2.c
new file mode 100644
index 00000000000..fcab05b7abe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/acle/memtag_2.c
@@ -0,0 +1,70 @@
+/* Test the MEMTAG intrinsic qualifier warnings and argument errors.  */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-options "-O3 -march=armv8.5-a+memtag" } */
+
+#include "arm_acle.h"
+
+void
+test_memtag_warning_return_qualifier (void)
+{
+  const char *c;
+  volatile char *v;
+  char *n;
+  int *i;
+  int64_t d;
+
+  v = __arm_mte_get_tag(c);		  /* { dg-warning {assignment} } */
+  n = __arm_mte_get_tag(c);		  /* { dg-warning {assignment} } */
+  i = __arm_mte_get_tag(c);		  /* { dg-warning {assignment} } */
+  c = __arm_mte_get_tag(v);		  /* { dg-warning {assignment} } */
+  n = __arm_mte_get_tag(v);		  /* { dg-warning {assignment} } */
+
+  i = __arm_mte_create_random_tag (c, 0); /* { dg-warning {assignment} } */
+  i = __arm_mte_increment_tag (c, 0);	  /* { dg-warning {assignment} } */
+
+  c = __arm_mte_get_tag(n);		  /* No warning.  */
+  d = __arm_mte_ptrdiff(c, i);		  /* No warning.  */
+}
+
+void
+test_memtag_warning_argument (void)
+{
+  const char *c;
+  uint64_t i;
+  __arm_mte_exclude_tag(i, 0);		/* { dg-warning {argument} } */
+  __arm_mte_create_random_tag (i, 0);	/* { dg-warning {argument} } */
+  __arm_mte_set_tag(i);			/* { dg-warning {argument} } */
+  __arm_mte_get_tag(i);			/* { dg-warning {argument} } */
+  __arm_mte_increment_tag (i, 15);	/* { dg-warning {argument} } */
+  __arm_mte_ptrdiff(c, i);		/* { dg-warning {argument} } */
+  __arm_mte_ptrdiff(i, c);		/* { dg-warning {argument} } */
+
+  __arm_mte_exclude_tag(1, 0);		/* { dg-warning {argument} } */
+  __arm_mte_create_random_tag (1, 0);	/* { dg-warning {argument} } */
+  __arm_mte_set_tag(1);			/* { dg-warning {argument} } */
+  __arm_mte_get_tag(1);			/* { dg-warning {argument} } */
+  __arm_mte_increment_tag (1, 15);	/* { dg-warning {argument} } */
+  __arm_mte_ptrdiff(c, 1);		/* { dg-warning {argument} } */
+  __arm_mte_ptrdiff(1, c);		/* { dg-warning {argument} } */
+
+  __arm_mte_exclude_tag(0, 0);		/* No warning.  */
+  __arm_mte_create_random_tag (0, 0);	/* No warning.  */
+  __arm_mte_set_tag(0);			/* No warning.  */
+  __arm_mte_get_tag(0);			/* No warning.  */
+  __arm_mte_increment_tag (0, 15);	/* No warning.  */
+  __arm_mte_ptrdiff(c, 0);		/* No warning.  */
+  __arm_mte_ptrdiff(0, c);		/* No warning.  */
+}
+
+void
+test_memtag_error_argument (void)
+{
+  /* Produce errors properly for invalid arguments.  */
+  __arm_mte_exclude_tag(no_decl, 0);	/* { dg-error {} } */
+  __arm_mte_exclude_tag();		/* { dg-error {} } */
+  __arm_mte_ptrdiff(no_decl2, 0);	/* { dg-error {} } */
+  __arm_mte_ptrdiff(0);			/* { dg-error {} } */
+  __arm_mte_ptrdiff();			/* { dg-error {} } */
+}
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.target/aarch64/acle/memtag_3.c b/gcc/testsuite/gcc.target/aarch64/acle/memtag_3.c
new file mode 100644
index 00000000000..109314e5595
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/acle/memtag_3.c
@@ -0,0 +1,16 @@
+/* Test the MEMTAG intrinsic expanding errors.  */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-options "-O3 -march=armv8.5-a+memtag" } */
+
+#include "arm_acle.h"
+
+void
+test_memtag_error_expand (int i)
+{
+  const char *p;
+  p = __arm_mte_increment_tag (p, -1);	/* { dg-error {in range \[0,15\]} } */
+  p = __arm_mte_increment_tag (p, 16);	/* { dg-error {in range \[0,15\]} } */
+  p = __arm_mte_increment_tag (p, i);	/* { dg-error {constant immediate} } */
+}
\ No newline at end of file

Reply via email to