public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/vendors/ARM/heads/morello)] Add builtin align functions
@ 2022-10-21 13:21 Matthew Malcomson
  0 siblings, 0 replies; only message in thread
From: Matthew Malcomson @ 2022-10-21 13:21 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:5e73df0637dbdfa3bf0b3e35f2b406d6841c1979

commit 5e73df0637dbdfa3bf0b3e35f2b406d6841c1979
Author: Matthew Malcomson <matthew.malcomson@arm.com>
Date:   Fri Oct 21 14:18:48 2022 +0100

    Add builtin align functions
    
    This patch is implementing builtins for aligning and checking alignment of
    pointers and integers. Change supports purecap, hybrid and vanilla.
    
    This change introduces three new user-facing builtins (which work on
    both pointers and integers) that can be used instead of common bit-wise
    arithmetic:
    
            __builtin_align_down (x, N)  ->    x & ~(N-1)
            __builtin_align_up (x, N)    ->  ( x +  (N-1) ) & ~(N-1)
            __builtin_is_aligned (x, N)  ->  ( x &  (N-1) ) == 0
    
    These builtins are overloaded over integral parameter types and pointer
    types.
    
    In addition, if both builtins parameters are const integers, this change
    folds these functions and calculates alignment value.
    Since these builtins need to work on capability targets, we need to
    provide two implementations.  One for integral types and one for
    capability typed values.
    
    The integral typed version is encoded with the user-visible
    BUILT_IN_*_INT, and the capability version is encoded with
    BUILT_IN_*_CAP.  These are chosen at builtin resolution time.
    
    In order to implement these builtins in Morello we implement the
    align_address_up and align_address_down optabs for CADImode operands.
    
    ---
    Integral parameter types are implemented by all using the same function
    which acts on an unsigned long long.  This means that trying to use
    these new alignment functions on an __int128 would lose precision.  An
    error is emitted on attempting such a thing.
    
    ---
    We do not implement folding for capability-typed constants.  As it
    stands something like `(__intcap_t)30` actually ends up in the folding
    routines as a `NOP_EXPR` casting an integral type 128 to an
    `INTCAP_TYPE`.  Hence this fold would never trigger.
    
    ---
    To ensure bad constexpr expressions are given an error we must do two
    things.  1) Such expressions must not be fully evaluated when expression
    evaluation is speculatively attempted.  2) We should emit an error when
    the expression is attempted to be evaluated in a context where full
    evaluation is required.
    
    Main Author:
        Przemyslaw Wirkus <przemyslaw.wirkus@arm.com>

Diff:
---
 gcc/builtin-types.def                              |   7 ++
 gcc/builtins.c                                     | 113 ++++++++++++++++++++
 gcc/builtins.def                                   |  14 +++
 gcc/c-family/c-common.c                            | 102 ++++++++++++++++++
 gcc/config/aarch64/aarch64-morello.md              |  42 ++++++++
 gcc/config/aarch64/predicates.md                   |   4 +
 gcc/cp/constexpr.c                                 |  27 +++++
 gcc/expmed.c                                       |  10 ++
 gcc/optabs.c                                       |  21 ++++
 gcc/optabs.h                                       |   1 +
 gcc/testsuite/c-c++-common/builtin_align_intptr.c  |  52 +++++++++
 .../c-c++-common/builtin_alignment_errors-2.c      |  20 ++++
 .../c-c++-common/builtin_alignment_errors-6.c      |  14 +++
 .../c-c++-common/builtin_alignment_errors.c        |  20 ++++
 .../c-c++-common/builtin_alignment_fold.c          |  13 +++
 .../c-c++-common/builtin_alignment_fold_nok.c      |  13 +++
 .../c-c++-common/builtin_alignment_warnings.c      |  20 ++++
 .../align-builtins/builtin_alignment_errors-3.C    | 118 +++++++++++++++++++++
 .../align-builtins/builtin_alignment_errors-4.C    |   5 +
 .../align-builtins/builtin_alignment_errors-5.C    |  17 +++
 .../align-builtins/builtin_alignment_ret_types-1.C |  41 +++++++
 .../align-builtins/builtin_alignment_ret_types.C   |  95 +++++++++++++++++
 .../morello/builtins/builtin_align_down-imm-imm.C  |  20 ++++
 .../morello/builtins/builtin_align_down-imm.C      |  22 ++++
 .../aarch64/morello/builtins/builtin_align_down.C  |  28 +++++
 .../morello/builtins/builtin_align_down_hybrid.C   |  18 ++++
 .../morello/builtins/builtin_align_intcap.C        |  51 +++++++++
 .../morello/builtins/builtin_align_intptr.C        |  52 +++++++++
 .../morello/builtins/builtin_align_up-imm-imm.C    |  21 ++++
 .../morello/builtins/builtin_align_up-imm.C        |  22 ++++
 .../aarch64/morello/builtins/builtin_align_up.C    |  28 +++++
 .../morello/builtins/builtin_align_up_hybrid.C     |  18 ++++
 .../morello/builtins/builtin_alignment_errors-2.C  |  16 +++
 .../morello/builtins/builtin_alignment_errors.C    |  16 +++
 .../morello/builtins/builtin_alignment_fold.C      |  10 ++
 .../morello/builtins/builtin_alignment_fold_nok.C  |   6 ++
 .../builtins/builtin_alignment_ret_types-2.C       |  20 ++++
 .../builtins/builtin_alignment_ret_types-3.C       |  23 ++++
 .../builtins/builtin_alignment_ret_types-4.C       |  24 +++++
 .../builtins/builtin_alignment_ret_types-5.C       |  17 +++
 .../builtin_alignment_ret_types_hybrid-1.C         |  40 +++++++
 .../builtin_alignment_ret_types_hybrid-2.C         |  21 ++++
 .../builtin_alignment_ret_types_hybrid-3.C         |  40 +++++++
 .../builtin_alignment_ret_types_hybrid-4.C         |  24 +++++
 .../builtin_alignment_ret_types_hybrid-5.C         |  17 +++
 .../morello/builtins/builtin_alignment_warnings.C  |  18 ++++
 .../morello/builtins/builtin_is_aligned-imm-imm.C  |  16 +++
 .../builtin_is_aligned-imm-imm_not_aligned.C       |  15 +++
 .../morello/builtins/builtin_is_aligned-imm.C      |  21 ++++
 .../aarch64/morello/builtins/builtin_is_aligned.C  |  28 +++++
 .../morello/builtins/morello-cxx-builtins.exp      |  41 +++++++
 gcc/testsuite/gcc.dg/builtin_alignment_errors-3.c  |  67 ++++++++++++
 gcc/testsuite/gcc.dg/builtin_alignment_errors-4.c  |   6 ++
 gcc/testsuite/gcc.dg/builtin_alignment_errors-5.c  |  17 +++
 .../gcc.target/aarch64/arm_align_max_stack_pwr.c   |   3 +-
 .../morello/builtins/builtin_align_down-imm-imm.c  |  21 ++++
 .../morello/builtins/builtin_align_down-imm.c      |  22 ++++
 .../aarch64/morello/builtins/builtin_align_down.c  |  28 +++++
 .../morello/builtins/builtin_align_down_hybrid-2.c |  24 +++++
 .../morello/builtins/builtin_align_down_hybrid.c   |  18 ++++
 .../morello/builtins/builtin_align_intcap.c        |  51 +++++++++
 .../morello/builtins/builtin_align_intptr.c        |  52 +++++++++
 .../morello/builtins/builtin_align_up-imm-imm.c    |  21 ++++
 .../morello/builtins/builtin_align_up-imm.c        |  22 ++++
 .../aarch64/morello/builtins/builtin_align_up.c    |  28 +++++
 .../morello/builtins/builtin_align_up_hybrid-2.c   |  24 +++++
 .../morello/builtins/builtin_align_up_hybrid.c     |  18 ++++
 .../morello/builtins/builtin_alignment_errors-2.c  |  16 +++
 .../morello/builtins/builtin_alignment_errors.c    |  16 +++
 .../morello/builtins/builtin_alignment_fold.c      |   9 ++
 .../morello/builtins/builtin_alignment_fold_nok.c  |   5 +
 .../morello/builtins/builtin_alignment_warnings.c  |  16 +++
 .../morello/builtins/builtin_is_aligned-imm-imm.c  |  16 +++
 .../builtin_is_aligned-imm-imm_not_aligned.c       |  15 +++
 .../morello/builtins/builtin_is_aligned-imm.c      |  21 ++++
 .../aarch64/morello/builtins/builtin_is_aligned.c  |  28 +++++
 .../aarch64/morello/builtins/morello-builtins.exp  |  36 +++++++
 77 files changed, 2061 insertions(+), 1 deletion(-)

diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def
index c0649f5d987..ff6bc6effd8 100644
--- a/gcc/builtin-types.def
+++ b/gcc/builtin-types.def
@@ -561,6 +561,13 @@ DEF_FUNCTION_TYPE_2 (BT_FN_INT_CONST_FEXCEPT_T_PTR_INT, BT_INT,
 DEF_FUNCTION_TYPE_2 (BT_FN_CAPPTR_CAPPTR_CAPPTR,
 		     BT_CAPPTR, BT_CAPPTR, BT_CAPPTR)
 
+DEF_FUNCTION_TYPE_2 (BT_FN_ULONGLONG_ULONGLONG_SIZE,
+		     BT_ULONGLONG, BT_ULONGLONG, BT_SIZE)
+DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_ULONGLONG_SIZE,
+		     BT_BOOL, BT_ULONGLONG, BT_SIZE)
+DEF_FUNCTION_TYPE_2 (BT_FN_UICAP_UICAP_SIZE, BT_UICAP, BT_UICAP, BT_SIZE)
+DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_UICAP_SIZE, BT_BOOL, BT_UICAP, BT_SIZE)
+
 DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR)
 
 #define DEF_SYNC(DTYPE, BT_DTYPE) \
diff --git a/gcc/builtins.c b/gcc/builtins.c
index aba25bc861a..18721ad5c7a 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -172,6 +172,10 @@ static tree fold_builtin_unordered_cmp (location_t, tree, tree, tree, enum tree_
 					enum tree_code);
 static tree fold_builtin_varargs (location_t, tree, tree*, int);
 
+static tree fold_builtin_align_down (tree, tree);
+static tree fold_builtin_align_up (tree, tree);
+static tree fold_builtin_is_aligned (tree, tree);
+
 static tree fold_builtin_strpbrk (location_t, tree, tree, tree, tree);
 static tree fold_builtin_strspn (location_t, tree, tree, tree);
 static tree fold_builtin_strcspn (location_t, tree, tree, tree);
@@ -195,6 +199,10 @@ static tree do_mpfr_remquo (tree, tree, tree);
 static tree do_mpfr_lgamma_r (tree, tree, tree);
 static void expand_builtin_sync_synchronize (void);
 
+static rtx expand_builtin_align_down (tree exp, rtx target);
+static rtx expand_builtin_align_up (tree exp, rtx target);
+static rtx expand_builtin_is_aligned (tree exp, rtx target);
+
 /* Return true if NAME starts with __builtin_ or __sync_.  */
 
 static bool
@@ -8749,6 +8757,16 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
     case BUILT_IN_ADJUST_DESCRIPTOR:
       return expand_builtin_adjust_descriptor (exp);
 
+    case BUILT_IN_ALIGN_DOWN:
+    case BUILT_IN_ALIGN_DOWN_CAP:
+      return expand_builtin_align_down (exp, target);
+    case BUILT_IN_ALIGN_UP:
+    case BUILT_IN_ALIGN_UP_CAP:
+      return expand_builtin_align_up (exp, target);
+    case BUILT_IN_IS_ALIGNED:
+    case BUILT_IN_IS_ALIGNED_CAP:
+      return expand_builtin_is_aligned (exp, target);
+
     case BUILT_IN_FORK:
     case BUILT_IN_EXECL:
     case BUILT_IN_EXECV:
@@ -10474,6 +10492,15 @@ fold_builtin_2 (location_t loc, tree expr, tree fndecl, tree arg0, tree arg1)
     CASE_FLT_FN (BUILT_IN_MODF):
       return fold_builtin_modf (loc, arg0, arg1, type);
 
+    case BUILT_IN_ALIGN_DOWN:
+      return fold_builtin_align_down (arg0, arg1);
+
+    case BUILT_IN_ALIGN_UP:
+      return fold_builtin_align_up (arg0, arg1);
+
+    case BUILT_IN_IS_ALIGNED:
+      return fold_builtin_is_aligned (arg0, arg1);
+
     case BUILT_IN_STRSPN:
       return fold_builtin_strspn (loc, expr, arg0, arg1);
 
@@ -10956,6 +10983,41 @@ fold_builtin_strpbrk (location_t loc, tree expr, tree s1, tree s2, tree type)
 			      build_int_cst (integer_type_node, p2[0]));
 }
 
+static tree
+fold_builtin_align_down (tree s1, tree s2)
+{
+  if (TREE_CODE (s1) != INTEGER_CST
+      || TREE_CODE (s2) != INTEGER_CST)
+    return NULL_TREE;
+
+  return wide_int_to_tree (long_unsigned_type_node,
+			   wi::to_wide (s1) & -wi::to_wide (s2));
+}
+
+static tree
+fold_builtin_align_up (tree s1, tree s2)
+{
+  if (TREE_CODE (s1) != INTEGER_CST
+      || TREE_CODE (s2) != INTEGER_CST)
+    return NULL_TREE;
+
+  const auto value = wi::to_wide (s1);
+  const auto mask = wi::to_wide (s2) - 1;
+  return wide_int_to_tree (long_unsigned_type_node, (value + mask) & ~mask);
+}
+
+static tree
+fold_builtin_is_aligned (tree s1, tree s2)
+{
+  if (TREE_CODE (s1) != INTEGER_CST
+      || TREE_CODE (s2) != INTEGER_CST)
+    return NULL_TREE;
+
+  const auto value = wi::to_wide (s1);
+  const auto mask = wi::to_wide (s2) - 1;
+  return build_int_cst (boolean_type_node, (value & mask) == 0);
+}
+
 /* Simplify a call to the strspn builtin.  S1 and S2 are the arguments
    to the call.
 
@@ -11314,6 +11376,57 @@ expand_builtin_memory_chk (tree exp, rtx target, machine_mode mode,
     }
 }
 
+static rtx
+expand_builtin_align_down (tree exp, rtx target)
+{
+  tree arg0, arg1;
+  rtx op0, op1;
+
+  arg0 = CALL_EXPR_ARG (exp, 0);
+  op0 = expand_normal (arg0);
+
+  arg1 = CALL_EXPR_ARG (exp, 1);
+  op1 = expand_normal (arg1);
+
+  scalar_addr_mode samode
+    = as_a <scalar_addr_mode> (TYPE_MODE (TREE_TYPE (exp)));
+  return expand_align_down (samode, op0, op1, target, true, OPTAB_DIRECT);
+}
+
+static rtx
+expand_builtin_align_up (tree exp, rtx target)
+{
+  tree arg0, arg1;
+  rtx op0, op1;
+
+  arg0 = CALL_EXPR_ARG (exp, 0);
+  op0 = expand_normal (arg0);
+
+  arg1 = CALL_EXPR_ARG (exp, 1);
+  op1 = expand_normal (arg1);
+
+  scalar_addr_mode samode
+    = as_a <scalar_addr_mode> (TYPE_MODE (TREE_TYPE (exp)));
+  return expand_align_up (samode, op0, op1, target, true, OPTAB_DIRECT);
+}
+
+rtx
+expand_builtin_is_aligned (tree exp, rtx target)
+{
+  tree arg0, arg1;
+  rtx op0, op1;
+
+  arg0 = CALL_EXPR_ARG (exp, 0);
+  op0 = expand_normal (arg0);
+
+  arg1 = CALL_EXPR_ARG (exp, 1);
+  op1 = expand_normal (arg1);
+
+  scalar_addr_mode samode
+    = as_a <scalar_addr_mode> (TYPE_MODE (TREE_TYPE (arg0)));
+  return expand_is_aligned (samode, op0, op1, target, true, OPTAB_DIRECT);
+}
+
 /* Emit warning if a buffer overflow is detected at compile time.  */
 
 static void
diff --git a/gcc/builtins.def b/gcc/builtins.def
index 09d0d15ffbb..caa7371cc8f 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -1075,6 +1075,20 @@ DEF_GCC_BUILTIN (BUILT_IN_LINE, "LINE", BT_FN_INT, ATTR_NOTHROW_LEAF_LIST)
 /* Coroutine builtins.  */
 #include "coroutine-builtins.def"
 
+/* Align builtins.  */
+DEF_GCC_BUILTIN (BUILT_IN_ALIGN_DOWN, "align_down",
+		 BT_FN_ULONGLONG_ULONGLONG_SIZE, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_ALIGN_DOWN_CAP, "align_down_cap",
+		 BT_FN_UICAP_UICAP_SIZE, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_ALIGN_UP, "align_up",
+		 BT_FN_ULONGLONG_ULONGLONG_SIZE, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_ALIGN_UP_CAP, "align_up_cap",
+		 BT_FN_UICAP_UICAP_SIZE, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_IS_ALIGNED, "is_aligned",
+		 BT_FN_BOOL_ULONGLONG_SIZE, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_IS_ALIGNED_CAP, "is_aligned_cap",
+		 BT_FN_BOOL_UICAP_SIZE, ATTR_CONST_NOTHROW_LEAF_LIST)
+
 /* CHERI builtins.  */
 
 DEF_GCC_BUILTIN (BUILT_IN_CHERI_ADDRESS_GET, "cheri_address_get",
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 5fc0a75fd44..719b7e77a67 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -7856,6 +7856,103 @@ resolve_atomic_fncode_n (tree function, vec<tree, va_gc> *params,
   return builtin_decl_explicit (new_code_bt);
 }
 
+/* A subroutine of resolve_overloaded_builtin, with the same arguments.
+   FUNCTION is known to be an overloaded BUILT_IN_ALIGN_{UP|DOWN} or
+   BUILT_IN_IS_ALIGNED function with the following properties:
+
+   - First parameter is a pointer of type T (also const/capability pointer), an
+     integer, or an intcap type.
+
+   If first parameter is a capability we select for
+
+	BUILT_IN_ALIGN_{UP|DOWN} overload BUILT_IN_ALIGN_{UP|DOWN}_CAP and
+	BUILT_IN_IS_ALIGNED      overload BUILT_IN_IS_ALIGNED_CAP.
+
+   Otherwise we simply ensure that the arguments and return values are integers
+   (adding casts if necessary) and use the standard BUILT_IN_ALIGN_{UP|DOWN} or
+   BUILT_IN_IS_ALIGNED.
+
+   Please note that alignment builtins ORIG_CODE is ordered so that:
+
+	BUILT_IN_*     == ORIG_CODE
+	BUILT_IN_*_CAP == ORIG_CODE + 1
+
+   - Second parameter (alignment) is always size_t type.  If second parameter
+     is a constant integer simple checks for its value are made and this can
+     result in a warning or error at LOC depending on alignment value.
+
+   This function will convert return type of a BUILT_IN_ALIGN_{UP,DOWN}{,_CAP}
+   call to its first parameter type if first parameter was a (capability)
+   pointer.
+
+   If both parameters are constant integers alignment builtin is a candidate
+   for folding later on.  */
+
+static tree
+resolve_align_builtin (location_t loc, enum built_in_function const orig_code,
+		       tree function, vec<tree, va_gc> *params)
+{
+  unsigned int num_params = vec_safe_length (params);
+
+  vec<tree, va_gc> *new_params = vec_safe_copy (params);
+  vec<tree, va_gc> *origtypes = vec_safe_copy (params);
+  for (unsigned int i = 0; i < num_params; ++i)
+    (*origtypes)[i] = ((*origtypes)[i] == error_mark_node
+		       ? error_mark_node
+		       : TREE_TYPE ((*origtypes)[i]));
+
+  if (num_params == 0)
+    return NULL_TREE;
+  tree p0 = (*params)[0];    /* Pointer or integer to be aligned. */
+  STRIP_ANY_LOCATION_WRAPPER (p0);
+  tree res = NULL_TREE;
+  tree fndecl = function;
+  if (capability_type_p (TREE_TYPE (p0)))
+    {
+      enum built_in_function new_code
+	= (enum built_in_function)((int)orig_code + 1);
+      fndecl = builtin_decl_explicit (new_code);
+      tree cap_type = uintcap_type_node;
+      (*new_params)[0] = convert (cap_type, (*params)[0]);
+    }
+  else if (TREE_CODE (TREE_TYPE (p0)) == INTEGER_TYPE
+	   || POINTER_TYPE_P (TREE_TYPE (p0)))
+    {
+      tree int_type = long_long_unsigned_type_node;
+      if (TYPE_PRECISION (TREE_TYPE (p0)) > TYPE_PRECISION (int_type))
+	error_at (loc, "%qE does not support %u-bit integers",
+		  function, TYPE_PRECISION (TREE_TYPE (p0)));
+      else
+	(*new_params)[0] = convert (int_type, (*params)[0]);
+    }
+  /* Strange data types just get passed to the integral version directly and
+     we get the corresponding error messages.  */
+  res = build_function_call_vec (loc, vNULL, fndecl, new_params,
+				 origtypes, function);
+
+  if (orig_code != BUILT_IN_IS_ALIGNED)
+    res = convert ((*origtypes)[0], res);
+
+  if (num_params > 1)
+    {
+      tree p1 = (*params)[1];    /* Alignment.  */
+      STRIP_ANY_LOCATION_WRAPPER (p1);
+      if (TREE_CODE (p1) == INTEGER_CST)
+	{
+	  const auto align = wi::to_wide (p1);
+	  if (align == 0)
+	    warning_at (loc, 0, "requested alignment must be nonzero");
+	  else if (align == 1)
+	    warning_at (loc, 0, "the result of checking whether a "
+			"value is aligned to 1 byte is always true");
+	  else if (wi::exact_log2 (align) == -1)
+	    warning_at (loc, 0, "requested alignment is not a power of 2");
+	}
+    }
+
+  return res;
+}
+
 /* A subroutine of resolve_overloaded_builtin, with the same arguments.
    FUNCTION is known to be an overloaded BUILT_IN_CHERI_* function
    with the following properties:
@@ -8012,6 +8109,11 @@ resolve_overloaded_builtin (location_t loc, tree function,
 	  }
       }
 
+    case BUILT_IN_ALIGN_UP:
+    case BUILT_IN_ALIGN_DOWN:
+    case BUILT_IN_IS_ALIGNED:
+      return resolve_align_builtin (loc, orig_code, function, params);
+
     case BUILT_IN_CHERI_ADDRESS_GET:
     case BUILT_IN_CHERI_ADDRESS_SET:
     case BUILT_IN_CHERI_BASE_GET:
diff --git a/gcc/config/aarch64/aarch64-morello.md b/gcc/config/aarch64/aarch64-morello.md
index d3e4c4ac399..50de65fedc5 100644
--- a/gcc/config/aarch64/aarch64-morello.md
+++ b/gcc/config/aarch64/aarch64-morello.md
@@ -562,3 +562,45 @@
     DONE;
   }
 )
+
+;; Alignment functions.
+
+(define_insn "align_down_cadi"
+  [(set (match_operand:CADI 0 "register_operand" "=rk")
+        (align_address_down:CADI
+               (match_operand:CADI 1 "register_operand" "rk")
+               (match_operand:DI 2 "aarch64_pwr_2" "n")))
+  ]
+  "TARGET_MORELLO"
+{
+  operands[2] = GEN_INT (exact_log2 (UINTVAL (operands[2])));
+  return "alignd\\t%0, %1, #%2";
+})
+
+(define_insn "align_address_up_cadi"
+  [(set (match_operand:CADI 0 "register_operand" "=rk")
+        (align_address_down:CADI
+            (pointer_plus:CADI
+                (match_operand:CADI 1 "register_operand" "rk")
+                (match_operand:DI 2 "const_int_operand" "n"))
+        (match_operand:DI 3 "aarch64_pwr_2" "n")))
+  ]
+  "TARGET_MORELLO && ((INTVAL (operands[2]) + 1) == INTVAL (operands[3]))"
+{
+  operands[3] = GEN_INT (exact_log2 (INTVAL (operands[3])));
+  return "alignu\\t%0, %1, #%3";
+})
+
+(define_expand "align_up_cadi"
+  [(set (match_operand:CADI 0 "register_operand")
+       (align_address_down:CADI
+           (pointer_plus:CADI
+                (match_operand:CADI 1 "register_operand" "rk")
+                (match_dup 3))
+           (match_operand:DI 2 "aarch64_pwr_2")))
+  ]
+  "TARGET_MORELLO"
+  {
+    operands[3] = plus_constant (DImode, operands[2], -1);
+  }
+)
diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md
index 50448bd19fc..03bcc73ce9e 100644
--- a/gcc/config/aarch64/predicates.md
+++ b/gcc/config/aarch64/predicates.md
@@ -254,6 +254,10 @@
        (match_test "INTVAL (op) != 0
 		    && (unsigned) exact_log2 (INTVAL (op)) < 64")))
 
+(define_predicate "aarch64_pwr_2"
+   (and (match_code "const_int")
+	(match_test "exact_log2 (INTVAL (op)) != -1")))
+
 (define_predicate "aarch64_alt_base_mem_operand"
   (and (match_code "mem")
        (match_test "aarch64_alt_base_address_p (GET_MODE (op),
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 291be3a998a..6d6fc273830 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1335,6 +1335,7 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
 
   int strops = 0;
   int strret = 0;
+  int alignop  = 0;
   if (fndecl_built_in_p (fun, BUILT_IN_NORMAL))
     switch (DECL_FUNCTION_CODE (fun))
       {
@@ -1355,6 +1356,12 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
       case BUILT_IN_STRSTR:
 	strops = 2;
 	strret = 1;
+	break;
+      case BUILT_IN_ALIGN_UP:
+      case BUILT_IN_ALIGN_DOWN:
+      case BUILT_IN_IS_ALIGNED:
+	alignop = 1;
+	break;
       default:
 	break;
       }
@@ -1404,6 +1411,26 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
 	  else
 	    arg = oarg;
 	}
+      else if (alignop && i == 1)
+	{
+	  if (TREE_CODE (arg) == INTEGER_CST)
+	    {
+	      const auto alignment = wi::to_wide (arg);
+	      location_t loc = EXPR_LOCATION (t);
+	      const char *errmsg = NULL;
+	      if (alignment == 0)
+		errmsg = "alignment must be nonzero";
+	      else if (exact_log2 (alignment) == -1)
+		errmsg = "alignment must be power of 2";
+	      if (errmsg)
+		{
+		  if (!ctx->quiet)
+		    error_at (loc, errmsg);
+		  *non_constant_p = true;
+		  return t;
+		}
+	    }
+	}
 
       args[i] = arg;
     }
diff --git a/gcc/expmed.c b/gcc/expmed.c
index 4d08bd8551e..4e87841ad95 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -6464,6 +6464,14 @@ align_down_optab (void *arg)
 			    ca->arg4, ca->arg5);
 }
 
+static rtx
+is_aligned_optab (void *arg)
+{
+  struct callback_args *ca = (struct callback_args *)arg;
+  return expand_is_aligned (ca->mode, ca->arg1, ca->arg2, ca->arg3,
+			    ca->arg4, ca->arg5);
+}
+
 static void
 test_capability_expand ()
 {
@@ -6503,6 +6511,8 @@ test_capability_expand ()
     = with_recorded_insn_emits (&x3, &ca, &align_up_optab);
   basic_rav
     = with_recorded_insn_emits (&x3, &ca, &align_down_optab);
+  basic_rav
+    = with_recorded_insn_emits (&x3, &ca, &is_aligned_optab);
 }
 
 /*
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 8ba22f2ce36..0a851da53ba 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -6728,6 +6728,27 @@ expand_align_up (scalar_addr_mode mode, rtx x, rtx align, rtx target,
   return expand_align_down (mode, temp, align, target, unsignedp, methods);
 }
 
+rtx
+expand_is_aligned (scalar_addr_mode mode, rtx x, rtx align, rtx target,
+		 int unsignedp, enum optab_methods methods)
+{
+#if STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1
+  int normalizep = STORE_FLAG_VALUE;
+#else
+  int normalizep = 1;
+#endif
+
+  scalar_int_mode omode = offset_mode (mode);
+  rtx oneminus = expand_binop (omode, sub_optab, align,
+			       gen_int_mode (1, omode), NULL_RTX,
+			       unsignedp, methods);
+  rtx ret = expand_binop (omode, and_optab, oneminus,
+			  drop_capability (x), NULL_RTX,
+			  unsignedp, methods);
+  return emit_store_flag_force (target, EQ, ret, const0_rtx, omode,
+				unsignedp, normalizep);
+}
+
 /* Expand the replace_address_value optab:
     Assert that CAPABILITY has no side effects.
     If MODE is a capability mode:
diff --git a/gcc/optabs.h b/gcc/optabs.h
index 218fd7aa7cb..867f3a60dff 100644
--- a/gcc/optabs.h
+++ b/gcc/optabs.h
@@ -346,6 +346,7 @@ rtx expand_pointer_plus (scalar_addr_mode, rtx, rtx, rtx, int, enum optab_method
 rtx expand_pointer_minus (scalar_addr_mode, rtx, rtx, rtx, int, enum optab_methods);
 rtx expand_align_down (scalar_addr_mode, rtx, rtx, rtx, int, enum optab_methods);
 rtx expand_align_up (scalar_addr_mode, rtx, rtx, rtx, int, enum optab_methods);
+rtx expand_is_aligned (scalar_addr_mode, rtx, rtx, rtx, int, enum optab_methods);
 
 extern bool insn_operand_matches (enum insn_code icode, unsigned int opno,
 				  rtx operand);
diff --git a/gcc/testsuite/c-c++-common/builtin_align_intptr.c b/gcc/testsuite/c-c++-common/builtin_align_intptr.c
new file mode 100644
index 00000000000..9549fd2d944
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin_align_intptr.c
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+
+typedef unsigned long size_t;
+typedef __INTPTR_TYPE__ intptr_t;
+#ifndef __cplusplus
+#define bool _Bool
+#endif
+
+intptr_t
+down1 (intptr_t c, size_t alignment) {
+  return __builtin_align_down (c, alignment);
+}
+
+intptr_t
+down2 (size_t alignment) {
+  return __builtin_align_down ((intptr_t)128, alignment);
+}
+
+intptr_t
+down3 (size_t alignment) {
+  return __builtin_align_down ((intptr_t)128, 16);
+}
+
+intptr_t
+up1 (intptr_t c, size_t alignment) {
+  return __builtin_align_up (c, alignment);
+}
+
+intptr_t
+up2 (size_t alignment) {
+  return __builtin_align_up ((intptr_t)128, alignment);
+}
+
+intptr_t
+up3 (size_t alignment) {
+  return __builtin_align_up ((intptr_t)128, 16);
+}
+
+bool
+isa1 (intptr_t c, size_t alignment) {
+  return __builtin_is_aligned (c, alignment);
+}
+
+bool
+isa2 (size_t alignment) {
+  return __builtin_is_aligned ((intptr_t)128, alignment);
+}
+
+bool
+isa3 (size_t alignment) {
+  return __builtin_is_aligned ((intptr_t)128, 16);
+}
diff --git a/gcc/testsuite/c-c++-common/builtin_alignment_errors-2.c b/gcc/testsuite/c-c++-common/builtin_alignment_errors-2.c
new file mode 100644
index 00000000000..dc102301349
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin_alignment_errors-2.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+
+#ifndef __cplusplus
+#define bool _Bool
+#endif
+
+bool
+foo (char *c) {
+  return __builtin_is_aligned (c, 5);       /* { dg-warning "requested alignment is not a power of 2" } */
+}
+
+char *
+bar (char *c) {
+  return __builtin_align_down (c, 17);      /* { dg-warning "requested alignment is not a power of 2" } */
+}
+
+char *
+baz (char *c) {
+  return __builtin_align_up (c, 1021);      /* { dg-warning "requested alignment is not a power of 2" } */
+}
diff --git a/gcc/testsuite/c-c++-common/builtin_alignment_errors-6.c b/gcc/testsuite/c-c++-common/builtin_alignment_errors-6.c
new file mode 100644
index 00000000000..4a6eb814c68
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin_alignment_errors-6.c
@@ -0,0 +1,14 @@
+/* { dg-do compile { target int128 } } */
+typedef unsigned long size_t;
+__int128
+down (__int128 x, size_t alignment) {
+    return __builtin_align_down (x, alignment); /* { dg-error "'__builtin_align_down' does not support 128-bit integers" } */
+}
+__int128
+up (__int128 x, size_t alignment) {
+    return __builtin_align_up (x, alignment); /* { dg-error "'__builtin_align_up' does not support 128-bit integers" } */
+}
+__int128
+aligned (__int128 x, size_t alignment) {
+    return __builtin_is_aligned (x, alignment); /* { dg-error "'__builtin_is_aligned' does not support 128-bit integers" } */
+}
diff --git a/gcc/testsuite/c-c++-common/builtin_alignment_errors.c b/gcc/testsuite/c-c++-common/builtin_alignment_errors.c
new file mode 100644
index 00000000000..562185b6936
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin_alignment_errors.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+
+#ifndef __cplusplus
+#define bool _Bool
+#endif
+
+bool
+foo (char *c) {
+  return __builtin_is_aligned (c, 0);   /* { dg-warning "requested alignment must be nonzero" } */
+}
+
+char *
+bar (char *c) {
+  return __builtin_align_down (c, 0);   /* { dg-warning "requested alignment must be nonzero" } */
+}
+
+char *
+baz (char *c) {
+  return __builtin_align_up (c, 0);     /* { dg-warning "requested alignment must be nonzero" } */
+}
diff --git a/gcc/testsuite/c-c++-common/builtin_alignment_fold.c b/gcc/testsuite/c-c++-common/builtin_alignment_fold.c
new file mode 100644
index 00000000000..80e5a064d75
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin_alignment_fold.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+
+#if defined(__cplusplus) && __cplusplus >= 201103L
+  static_assert (__builtin_align_down (127, 16) == 112, "");
+  static_assert (__builtin_align_up (127, 16) == 128, "");
+  static_assert (__builtin_is_aligned (1024, 512) == 1, "");
+#endif
+
+#ifndef __cplusplus
+  _Static_assert (__builtin_align_down (127, 16) == 112, "");
+  _Static_assert (__builtin_align_up (127, 16) == 128, "");
+  _Static_assert (__builtin_is_aligned (1024, 512) == 1, "");
+#endif
diff --git a/gcc/testsuite/c-c++-common/builtin_alignment_fold_nok.c b/gcc/testsuite/c-c++-common/builtin_alignment_fold_nok.c
new file mode 100644
index 00000000000..67b1c9b29d9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin_alignment_fold_nok.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+
+#if defined(__cplusplus) && __cplusplus >= 201103L
+  static_assert (__builtin_align_down (127, 16) == 128, "112 != 128");   /* { dg-error "static assertion failed" "" { target c++11 }  } */
+  static_assert (__builtin_align_up (129, 16) == 128, "144 != 128");     /* { dg-error "static assertion failed" "" { target c++11 } } */
+  static_assert (__builtin_is_aligned (1023, 512) == 1, "0 != 1");       /* { dg-error "static assertion failed" "" { target c++11 } } */
+#endif
+
+#ifndef __cplusplus
+  _Static_assert (__builtin_align_down (127, 16) == 128, "112 != 128");   /* { dg-error "static assertion failed" "" { target c } } */
+  _Static_assert (__builtin_align_up (129, 16) == 128, "144 != 128");     /* { dg-error "static assertion failed" "" { target c } } */
+  _Static_assert (__builtin_is_aligned (1023, 512) == 1, "0 != 1");       /* { dg-error "static assertion failed" "" { target c } } */
+#endif
diff --git a/gcc/testsuite/c-c++-common/builtin_alignment_warnings.c b/gcc/testsuite/c-c++-common/builtin_alignment_warnings.c
new file mode 100644
index 00000000000..dbcd3c4c9cb
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin_alignment_warnings.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+
+#ifndef __cplusplus
+#define bool _Bool
+#endif
+
+bool
+foo (char *c) {
+  return __builtin_is_aligned (c, 1);   /* { dg-warning "the result of checking whether a value is aligned to 1 byte is always true" } */
+}
+
+char *
+bar (char *c) {
+  return __builtin_align_down (c, 1);   /* { dg-warning "the result of checking whether a value is aligned to 1 byte is always true" } */
+}
+
+char *
+baz (char *c) {
+  return __builtin_align_up (c, 1);    /* { dg-warning "the result of checking whether a value is aligned to 1 byte is always true" } */
+}
diff --git a/gcc/testsuite/g++.dg/align-builtins/builtin_alignment_errors-3.C b/gcc/testsuite/g++.dg/align-builtins/builtin_alignment_errors-3.C
new file mode 100644
index 00000000000..7e9cff8f731
--- /dev/null
+++ b/gcc/testsuite/g++.dg/align-builtins/builtin_alignment_errors-3.C
@@ -0,0 +1,118 @@
+/* { dg-do compile } */
+
+int
+down_bad_type () {
+    return __builtin_align_down ((badtype)128, 16); /* { dg-error ".badtype. was not declared" } */
+}
+
+int
+down_no_alignment () {
+    return __builtin_align_down ((int)128); /* { dg-error "too few arguments" } */
+}
+
+int
+down_bad_alignment () {
+    return __builtin_align_down ((int)128, 13); /* { dg-warning "requested alignment is not a power of 2" } */
+}
+
+int
+down_no_arguments () {
+    return __builtin_align_down(); /* { dg-error "too few arguments to function" } */
+}
+
+int
+up_bad_type () {
+    return __builtin_align_up ((badtype)128, 16); /* { dg-error ".badtype. was not declared" } */
+}
+
+int
+up_no_alignment () {
+    return __builtin_align_up ((int)128); /* { dg-error "too few arguments" } */
+}
+
+int
+up_bad_alignment () {
+    return __builtin_align_up ((int)128, 13); /* { dg-warning "requested alignment is not a power of 2" } */
+}
+
+int
+up_no_arguments () {
+    return __builtin_align_up(); /* { dg-error "too few arguments" } */
+}
+
+int
+check_bad_type () {
+    return __builtin_is_aligned ((badtype)128, 16); /* { dg-error ".badtype. was not declared" } */
+}
+
+int
+check_no_alignment () {
+    return __builtin_is_aligned ((int)128); /* { dg-error "too few arguments" } */
+}
+
+int
+check_bad_alignment () {
+    return __builtin_is_aligned ((int)128, 13); /* { dg-warning "requested alignment is not a power of 2" } */
+}
+
+int
+check_no_arguments () {
+    return __builtin_is_aligned(); /* { dg-error "too few arguments" } */
+}
+
+#if __cplusplus >= 201103L
+constexpr const int aligndown = __builtin_align_down (128, 13);  /* { dg-error "alignment must be power of 2" "" { target c++11 } } */
+/* { dg-warning "requested alignment is not a power of 2" "" { target c++11 } .-1 } */
+constexpr const int alignup = __builtin_align_up (128, 13);  /* { dg-error "alignment must be power of 2" "" { target c++11 } } */
+/* { dg-warning "requested alignment is not a power of 2" "" { target c++11 } .-1 } */
+constexpr const int aligned = __builtin_is_aligned (128, 13);  /* { dg-error "alignment must be power of 2" "" { target c++11 } } */
+/* { dg-warning "requested alignment is not a power of 2" "" { target c++11 } .-1 } */
+constexpr const int aligndown_zero = __builtin_align_down (128, 0);  /* { dg-error "alignment must be nonzero" "" { target c++11 } } */
+/* { dg-warning "requested alignment must be nonzero" "" { target c++11 } .-1 } */
+constexpr const int alignup_zero = __builtin_align_up (128, 0);  /* { dg-error "alignment must be nonzero" "" { target c++11 } } */
+/* { dg-warning "requested alignment must be nonzero" "" { target c++11 } .-1 } */
+constexpr const int aligned_zero = __builtin_is_aligned (128, 0);  /* { dg-error "alignment must be nonzero" "" { target c++11 } } */
+/* { dg-warning "requested alignment must be nonzero" "" { target c++11 } .-1 } */
+
+int
+down_constexpr_bad_alignment () {
+    constexpr int x = __builtin_align_down ((int)128, 13);  /* { dg-error "alignment must be power of 2" "" { target c++11 } } */
+    /* { dg-warning "requested alignment is not a power of 2" "" { target c++11 } .-1 } */
+    return x;
+}
+
+int
+down_constexpr_zero_alignment () {
+    constexpr int x = __builtin_align_down ((int)128, 0);  /* { dg-error "alignment must be nonzero" "" { target c++11 } } */
+    /* { dg-warning "requested alignment must be nonzero" "" { target c++11 } .-1 } */
+    return x;
+}
+
+int
+up_constexpr_bad_alignment () {
+    constexpr int x = __builtin_align_up ((int)128, 13);  /* { dg-error "alignment must be power of 2" "" { target c++11 } } */
+    /* { dg-warning "requested alignment is not a power of 2" "" { target c++11 } .-1 } */
+    return x;
+}
+
+int
+up_constexpr_zero_alignment () {
+    constexpr int x = __builtin_align_up ((int)128, 0);  /* { dg-error "alignment must be nonzero" "" { target c++11 } } */
+    /* { dg-warning "requested alignment must be nonzero" "" { target c++11 } .-1 } */
+    return x;
+}
+
+int
+check_constexpr_bad_alignment () {
+    constexpr int x = __builtin_is_aligned ((int)128, 13);  /* { dg-error "alignment must be power of 2" "" { target c++11 } } */
+    /* { dg-warning "requested alignment is not a power of 2" "" { target c++11 } .-1 } */
+    return x;
+}
+
+int
+check_constexpr_zero_alignment () {
+    constexpr int x = __builtin_is_aligned ((int)128, 0);  /* { dg-error "alignment must be nonzero" "" { target c++11 } } */
+    /* { dg-warning "requested alignment must be nonzero" "" { target c++11 } .-1 } */
+    return x;
+}
+#endif
diff --git a/gcc/testsuite/g++.dg/align-builtins/builtin_alignment_errors-4.C b/gcc/testsuite/g++.dg/align-builtins/builtin_alignment_errors-4.C
new file mode 100644
index 00000000000..babf0969d8b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/align-builtins/builtin_alignment_errors-4.C
@@ -0,0 +1,5 @@
+typedef unsigned long size_t;
+void *
+ham (size_t a) {
+  return __builtin_align_down (1024, a);    /* { dg-error {invalid conversion from 'int' to 'void\*'} } */
+}
diff --git a/gcc/testsuite/g++.dg/align-builtins/builtin_alignment_errors-5.C b/gcc/testsuite/g++.dg/align-builtins/builtin_alignment_errors-5.C
new file mode 100644
index 00000000000..c2170174433
--- /dev/null
+++ b/gcc/testsuite/g++.dg/align-builtins/builtin_alignment_errors-5.C
@@ -0,0 +1,17 @@
+typedef unsigned long size_t;
+struct tempstruct {
+    unsigned short x;
+    unsigned int y;
+};
+unsigned
+down (struct tempstruct x, size_t alignment) {
+    return __builtin_align_down (x, alignment); /* { dg-error "cannot convert 'tempstruct'" } */
+}
+unsigned
+up (struct tempstruct x, size_t alignment) {
+    return __builtin_align_up (x, alignment); /* { dg-error "cannot convert 'tempstruct'" } */
+}
+unsigned
+aligned (struct tempstruct x, size_t alignment) {
+    return __builtin_is_aligned (x, alignment); /* { dg-error "cannot convert 'tempstruct'" } */
+}
diff --git a/gcc/testsuite/g++.dg/align-builtins/builtin_alignment_ret_types-1.C b/gcc/testsuite/g++.dg/align-builtins/builtin_alignment_ret_types-1.C
new file mode 100644
index 00000000000..181cf9bdde4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/align-builtins/builtin_alignment_ret_types-1.C
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+
+#if __cplusplus >= 201103L
+
+typedef unsigned long size_t;
+typedef __INTPTR_TYPE__ intptr_t;
+typedef __UINTPTR_TYPE__ uintptr_t;
+
+void
+check_return_types_for_alignment_builtin_overloads (size_t a, int *i, char *c,  void *v)
+{
+  static_assert (__is_same (decltype (__builtin_align_down (i, a)), int *), "");
+  static_assert (__is_same (decltype (__builtin_align_down (c, a)), char *), "");
+  static_assert (__is_same (decltype (__builtin_align_down (v, a)), void *), "");
+  static_assert (__is_same (decltype (__builtin_align_down (128, a)), int), "");
+  static_assert (__is_same (decltype (__builtin_align_down ((intptr_t)128, a)), intptr_t), "");
+  static_assert (__is_same (decltype (__builtin_align_down ((uintptr_t)128, a)), uintptr_t), "");
+
+  static_assert (__is_same (decltype (__builtin_align_up (i, a)), int *), "");
+  static_assert (__is_same (decltype (__builtin_align_up (c, a)), char *), "");
+  static_assert (__is_same (decltype (__builtin_align_up (v, a)), void *), "");
+  static_assert (__is_same (decltype (__builtin_align_up (128, a)), int), "");
+  static_assert (__is_same (decltype (__builtin_align_up ((intptr_t)128, a)), intptr_t), "");
+  static_assert (__is_same (decltype (__builtin_align_up ((uintptr_t)128, a)), uintptr_t), "");
+
+  static_assert (__is_same (decltype (__builtin_is_aligned (i, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (c, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (v, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (128, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned ((intptr_t)128, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned ((uintptr_t)128, a)), bool), "");
+
+  static_assert (__is_same (decltype (__builtin_align_down (128, 16)), int), "");
+  static_assert (__is_same (decltype (__builtin_align_up (128, 16)), int), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (128, 16)), bool), "");
+
+  static_assert (__is_same (decltype (__builtin_align_down (0, a)), int), "");
+  static_assert (__is_same (decltype (__builtin_align_up (0, a)), int), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (0, a)), bool), "");
+}
+#endif
diff --git a/gcc/testsuite/g++.dg/align-builtins/builtin_alignment_ret_types.C b/gcc/testsuite/g++.dg/align-builtins/builtin_alignment_ret_types.C
new file mode 100644
index 00000000000..fb09af3af5e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/align-builtins/builtin_alignment_ret_types.C
@@ -0,0 +1,95 @@
+#if __cplusplus >= 201103L
+
+typedef unsigned long size_t;
+typedef __INTPTR_TYPE__ intptr_t;
+typedef __UINTPTR_TYPE__ uintptr_t;
+
+void
+check_return_types_for_alignment_builtin_overloads (size_t a, int *i, char *c,  void *v)
+{
+  static_assert (__is_same (decltype (__builtin_align_down (i, a)), int *), "");
+  static_assert (__is_same (decltype (__builtin_align_down (c, a)), char *), "");
+  static_assert (__is_same (decltype (__builtin_align_down (v, a)), void *), "");
+  static_assert (__is_same (decltype (__builtin_align_down (128, a)), int), "");
+  static_assert (__is_same (decltype (__builtin_align_down ((intptr_t)128, a)), intptr_t), "");
+  static_assert (__is_same (decltype (__builtin_align_down ((uintptr_t)128, a)), uintptr_t), "");
+
+  static_assert (__is_same (decltype (__builtin_align_up (i, a)), int *), "");
+  static_assert (__is_same (decltype (__builtin_align_up (c, a)), char *), "");
+  static_assert (__is_same (decltype (__builtin_align_up (v, a)), void *), "");
+  static_assert (__is_same (decltype (__builtin_align_up (128, a)), int), "");
+  static_assert (__is_same (decltype (__builtin_align_up ((intptr_t)128, a)), intptr_t), "");
+  static_assert (__is_same (decltype (__builtin_align_up ((uintptr_t)128, a)), uintptr_t), "");
+
+  static_assert (__is_same (decltype (__builtin_is_aligned (i, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (c, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (v, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (128, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned ((intptr_t)128, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned ((uintptr_t)128, a)), bool), "");
+
+  static_assert (__is_same (decltype (__builtin_align_down (128, 16)), int), "");
+  static_assert (__is_same (decltype (__builtin_align_up (128, 16)), int), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (128, 16)), bool), "");
+
+  static_assert (__is_same (decltype (__builtin_align_down (0, a)), int), "");
+  static_assert (__is_same (decltype (__builtin_align_up (0, a)), int), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (0, a)), bool), "");
+}
+
+void
+check_return_types_for_alignment_builtin_overloads_2 (size_t a, const int *i, const char *c, const void *v)
+{
+  static_assert (__is_same (decltype (__builtin_align_down (i, a)), const int *), "");
+  static_assert (__is_same (decltype (__builtin_align_down (c, a)), const char *), "");
+  static_assert (__is_same (decltype (__builtin_align_down (v, a)), const void *), "");
+
+  static_assert (__is_same (decltype (__builtin_align_up (i, a)), const int *), "");
+  static_assert (__is_same (decltype (__builtin_align_up (c, a)), const char *), "");
+  static_assert (__is_same (decltype (__builtin_align_up (v, a)), const void *), "");
+
+  static_assert (__is_same (decltype (__builtin_is_aligned (i, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (c, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (v, a)), bool), "");
+}
+
+void
+check_return_types_for_alignment_builtin_overloads_3 (size_t a, int i, char c, short s, long l)
+{
+  static_assert (__is_same (decltype (__builtin_align_down (i, a)), int), "");
+  static_assert (__is_same (decltype (__builtin_align_down (c, a)), char), "");
+  static_assert (__is_same (decltype (__builtin_align_down (s, a)), short), "");
+  static_assert (__is_same (decltype (__builtin_align_down (l, a)), long), "");
+
+  static_assert (__is_same (decltype (__builtin_align_up (i, a)), int), "");
+  static_assert (__is_same (decltype (__builtin_align_up (c, a)), char), "");
+  static_assert (__is_same (decltype (__builtin_align_up (s, a)), short), "");
+  static_assert (__is_same (decltype (__builtin_align_up (l, a)), long), "");
+
+  static_assert (__is_same (decltype (__builtin_is_aligned (i, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (c, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (s, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (l, a)), bool), "");
+}
+
+void
+check_return_types_for_alignment_builtin_overloads_3_const (size_t a,
+        const int i, const char c, const short s, const long l)
+{
+  static_assert (__is_same (decltype (__builtin_align_down (i, a)), const int), "");
+  static_assert (__is_same (decltype (__builtin_align_down (c, a)), const char), "");
+  static_assert (__is_same (decltype (__builtin_align_down (s, a)), const short), "");
+  static_assert (__is_same (decltype (__builtin_align_down (l, a)), const long), "");
+
+  static_assert (__is_same (decltype (__builtin_align_up (i, a)), const int), "");
+  static_assert (__is_same (decltype (__builtin_align_up (c, a)), const char), "");
+  static_assert (__is_same (decltype (__builtin_align_up (s, a)), const short), "");
+  static_assert (__is_same (decltype (__builtin_align_up (l, a)), const long), "");
+
+  static_assert (__is_same (decltype (__builtin_is_aligned (i, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (c, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (s, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (l, a)), bool), "");
+}
+
+#endif
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_down-imm-imm.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_down-imm-imm.C
new file mode 100644
index 00000000000..710f614483b
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_down-imm-imm.C
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+
+int
+foo () {
+  return __builtin_align_down (120, 16);
+}
+
+int
+bar () {
+  return __builtin_align_down (127, 32);
+}
+
+int
+baz () {
+  return __builtin_align_down (1023, 512);
+}
+
+/* { dg-final { scan-assembler-times {mov\t[wx][0-9]+, 112} 1 } } */
+/* { dg-final { scan-assembler-times {mov\t[wx][0-9]+, 96} 1 } } */
+/* { dg-final { scan-assembler-times {mov\t[wx][0-9]+, 512} 1 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_down-imm.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_down-imm.C
new file mode 100644
index 00000000000..8e26802299b
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_down-imm.C
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+#define ALIGN_DOWN_IMM(T,N) T* \
+		foo_##N (T* c) \
+		{ return __builtin_align_down (c, N); }
+
+/* Alignment N must be 1 or greater.  */
+/* Aligning value to 1 byte is a no-op.  */
+ALIGN_DOWN_IMM(void, 2)
+ALIGN_DOWN_IMM(void, 4)
+ALIGN_DOWN_IMM(void, 8)
+ALIGN_DOWN_IMM(void, 16)
+ALIGN_DOWN_IMM(void, 32)
+ALIGN_DOWN_IMM(void, 64)
+
+/* { dg-final { scan-assembler-times {alignd\tc[0-9]+, c[0-9]+, #1} 1 } } */
+/* { dg-final { scan-assembler-times {alignd\tc[0-9]+, c[0-9]+, #2} 1 } } */
+/* { dg-final { scan-assembler-times {alignd\tc[0-9]+, c[0-9]+, #3} 1 } } */
+/* { dg-final { scan-assembler-times {alignd\tc[0-9]+, c[0-9]+, #4} 1 } } */
+/* { dg-final { scan-assembler-times {alignd\tc[0-9]+, c[0-9]+, #5} 1 } } */
+/* { dg-final { scan-assembler-times {alignd\tc[0-9]+, c[0-9]+, #6} 1 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_down.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_down.C
new file mode 100644
index 00000000000..5ab423675e4
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_down.C
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+typedef unsigned long size_t;
+
+void *
+foo2 (void *c, size_t alignment) {
+  return __builtin_align_down (c, 16);
+}
+
+int
+foo3 (size_t alignment) {
+  return __builtin_align_down (128, alignment);
+}
+
+void *
+bar (void *c, size_t alignment) {
+  return __builtin_align_down (c, alignment);
+}
+
+void *
+baz (void *c, size_t *alignment) {
+  return __builtin_align_down (c, *alignment);
+}
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
+/* { dg-final { scan-assembler-times {alignd\t} 1 } } */
+/* { dg-final { scan-assembler-times {scvalue\tc[0-9]+, c[0-9]+, x[0-9]+} 2 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_down_hybrid.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_down_hybrid.C
new file mode 100644
index 00000000000..38faa6bfee0
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_down_hybrid.C
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello -mabi=lp64" } */
+
+typedef unsigned long size_t;
+
+void * __capability
+foo1 (void * __capability c, size_t alignment) {
+  return __builtin_align_down (c, alignment);
+}
+
+void * __capability
+foo2 (void * __capability c) {
+  return __builtin_align_down (c, 16);
+}
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
+/* { dg-final { scan-assembler-times {alignd\t} 1 } } */
+/* { dg-final { scan-assembler-times {scvalue\tc[0-9]+, c[0-9]+, x[0-9]+} 1 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_intcap.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_intcap.C
new file mode 100644
index 00000000000..66dbce3d5de
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_intcap.C
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+typedef unsigned long size_t;
+
+__intcap_t
+down1 (__intcap_t c, size_t alignment) {
+  return __builtin_align_down (c, alignment);
+}
+
+__intcap_t
+down2 (size_t alignment) {
+  return __builtin_align_down ((__intcap_t)128, alignment);
+}
+
+__intcap_t
+down3 (size_t alignment) {
+  return __builtin_align_down ((__intcap_t)128, 16);
+}
+
+__intcap_t
+up1 (__intcap_t c, size_t alignment) {
+  return __builtin_align_up (c, alignment);
+}
+
+__intcap_t
+up2 (size_t alignment) {
+  return __builtin_align_up ((__intcap_t)128, alignment);
+}
+
+__intcap_t
+up3 (size_t alignment) {
+  return __builtin_align_up ((__intcap_t)128, 16);
+}
+
+bool
+isa1 (__intcap_t c, size_t alignment) {
+  return __builtin_is_aligned (c, alignment);
+}
+
+bool
+isa2 (size_t alignment) {
+  return __builtin_is_aligned ((__intcap_t)128, alignment);
+}
+
+bool
+isa3 (size_t alignment) {
+  return __builtin_is_aligned ((__intcap_t)128, 16);
+}
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_intptr.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_intptr.C
new file mode 100644
index 00000000000..fb104437a39
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_intptr.C
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+typedef unsigned long size_t;
+typedef __INTPTR_TYPE__ intptr_t;
+
+intptr_t
+down1 (intptr_t c, size_t alignment) {
+  return __builtin_align_down (c, alignment);
+}
+
+intptr_t
+down2 (size_t alignment) {
+  return __builtin_align_down ((intptr_t)128, alignment);
+}
+
+intptr_t
+down3 () {
+  return __builtin_align_down ((intptr_t)128, 16);
+}
+
+intptr_t
+up1 (intptr_t c, size_t alignment) {
+  return __builtin_align_up (c, alignment);
+}
+
+intptr_t
+up2 (size_t alignment) {
+  return __builtin_align_up ((intptr_t)128, alignment);
+}
+
+intptr_t
+up3 () {
+  return __builtin_align_up ((intptr_t)128, 16);
+}
+
+bool
+isa1 (intptr_t c, size_t alignment) {
+  return __builtin_is_aligned (c, alignment);
+}
+
+bool
+isa2 (size_t alignment) {
+  return __builtin_is_aligned ((intptr_t)128, alignment);
+}
+
+bool
+isa3 () {
+  return __builtin_is_aligned ((intptr_t)128, 16);
+}
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_up-imm-imm.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_up-imm-imm.C
new file mode 100644
index 00000000000..71946043596
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_up-imm-imm.C
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+int
+foo () {
+  return __builtin_align_up (120, 16);
+}
+
+int
+bar () {
+  return __builtin_align_up (1, 256);
+}
+
+int
+baz () {
+  return __builtin_align_up (1023, 512);
+}
+
+/* { dg-final { scan-assembler-times {mov\t[wx][0-9]+, 128} 1 } } */
+/* { dg-final { scan-assembler-times {mov\t[wx][0-9]+, 256} 1 } } */
+/* { dg-final { scan-assembler-times {mov\t[wx][0-9]+, 1024} 1 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_up-imm.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_up-imm.C
new file mode 100644
index 00000000000..4290e02e72d
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_up-imm.C
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+#define ALIGN_UP_IMM(T,N) T* \
+		foo_##N (T* c) \
+		{ return __builtin_align_up (c, N); }
+
+/* Alignment N must be 1 or greater.  */
+/* Aligning value to 1 byte is a no-op.  */
+ALIGN_UP_IMM(void, 2)
+ALIGN_UP_IMM(void, 4)
+ALIGN_UP_IMM(void, 8)
+ALIGN_UP_IMM(void, 16)
+ALIGN_UP_IMM(void, 32)
+ALIGN_UP_IMM(void, 64)
+
+/* { dg-final { scan-assembler-times {alignu\tc[0-9]+, c[0-9]+, #1} 1 } } */
+/* { dg-final { scan-assembler-times {alignu\tc[0-9]+, c[0-9]+, #2} 1 } } */
+/* { dg-final { scan-assembler-times {alignu\tc[0-9]+, c[0-9]+, #3} 1 } } */
+/* { dg-final { scan-assembler-times {alignu\tc[0-9]+, c[0-9]+, #4} 1 } } */
+/* { dg-final { scan-assembler-times {alignu\tc[0-9]+, c[0-9]+, #5} 1 } } */
+/* { dg-final { scan-assembler-times {alignu\tc[0-9]+, c[0-9]+, #6} 1 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_up.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_up.C
new file mode 100644
index 00000000000..f3a8036ad4b
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_up.C
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+typedef unsigned long size_t;
+
+void *
+foo2 (void *c, size_t alignment) {
+  return __builtin_align_up (c, 16);
+}
+
+int
+foo3 (size_t alignment) {
+  return __builtin_align_up (128, alignment);
+}
+
+void *
+bar (void *c, size_t alignment) {
+  return __builtin_align_up (c, alignment);
+}
+
+void *
+baz (void *c, size_t *alignment) {
+  return __builtin_align_up (c, *alignment);
+}
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
+/* { dg-final { scan-assembler-times {alignu\t} 1 } } */
+/* { dg-final { scan-assembler-times {scvalue\tc[0-9]+, c[0-9]+, x[0-9]+} 2 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_up_hybrid.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_up_hybrid.C
new file mode 100644
index 00000000000..7afa8f35287
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_align_up_hybrid.C
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello -mabi=lp64" } */
+
+typedef unsigned long size_t;
+
+void * __capability
+foo1 (void * __capability c, size_t alignment) {
+  return __builtin_align_up (c, alignment);
+}
+
+void * __capability
+foo2 (void * __capability c) {
+  return __builtin_align_up (c, 16);
+}
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
+/* { dg-final { scan-assembler-times {alignu\t} 1 } } */
+/* { dg-final { scan-assembler-times {scvalue\tc[0-9]+, c[0-9]+, x[0-9]+} 1 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_errors-2.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_errors-2.C
new file mode 100644
index 00000000000..95708c3e2f4
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_errors-2.C
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+
+bool
+foo (char *c) {
+  return __builtin_is_aligned (c, 5);       /* { dg-warning "requested alignment is not a power of 2" } */
+}
+
+char *
+bar (char *c) {
+  return __builtin_align_down (c, 17);      /* { dg-warning "requested alignment is not a power of 2" } */
+}
+
+char *
+baz (char *c) {
+  return __builtin_align_up (c, 1021);      /* { dg-warning "requested alignment is not a power of 2" } */
+}
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_errors.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_errors.C
new file mode 100644
index 00000000000..4936641da7d
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_errors.C
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+
+bool
+foo (char *c) {
+  return __builtin_is_aligned (c, 0);   /* { dg-warning "requested alignment must be nonzero" } */
+}
+
+char *
+bar (char *c) {
+  return __builtin_align_down (c, 0);   /* { dg-warning "requested alignment must be nonzero" } */
+}
+
+char *
+baz (char *c) {
+  return __builtin_align_up (c, 0);     /* { dg-warning "requested alignment must be nonzero" } */
+}
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_fold.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_fold.C
new file mode 100644
index 00000000000..c80751571db
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_fold.C
@@ -0,0 +1,10 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-O2" } */
+
+int global1 = __builtin_align_down(33, 16);
+int global2 = __builtin_align_up(33, 16);
+bool global3 = __builtin_is_aligned(33, 16);
+
+static_assert (__builtin_align_down (127, 16) == 112, "");
+static_assert (__builtin_align_up (127, 16) == 128, "");
+static_assert (__builtin_is_aligned (1024, 512) == 1, "");
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_fold_nok.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_fold_nok.C
new file mode 100644
index 00000000000..3f159ef6265
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_fold_nok.C
@@ -0,0 +1,6 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-O2" } */
+
+static_assert (__builtin_align_down (127, 16) == 128, "112 != 128");   /* { dg-error "static assertion failed" } */
+static_assert (__builtin_align_up (129, 16) == 128, "144 != 128");     /* { dg-error "static assertion failed" } */
+static_assert (__builtin_is_aligned (1023, 512) == 1, "0 != 1");       /* { dg-error "static assertion failed" } */
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types-2.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types-2.C
new file mode 100644
index 00000000000..95b52acb7a9
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types-2.C
@@ -0,0 +1,20 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+typedef unsigned long size_t;
+
+void
+check_return_types_for_alignment_builtin_overloads_2 (size_t a, const int *i, const char *c, const void *v)
+{
+  static_assert (__is_same (decltype (__builtin_align_down (i, a)), const int *), "");
+  static_assert (__is_same (decltype (__builtin_align_down (c, a)), const char *), "");
+  static_assert (__is_same (decltype (__builtin_align_down (v, a)), const void *), "");
+
+  static_assert (__is_same (decltype (__builtin_align_up (i, a)), const int *), "");
+  static_assert (__is_same (decltype (__builtin_align_up (c, a)), const char *), "");
+  static_assert (__is_same (decltype (__builtin_align_up (v, a)), const void *), "");
+
+  static_assert (__is_same (decltype (__builtin_is_aligned (i, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (c, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (v, a)), bool), "");
+}
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types-3.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types-3.C
new file mode 100644
index 00000000000..53d684f12b0
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types-3.C
@@ -0,0 +1,23 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+typedef unsigned long size_t;
+
+void
+check_return_types_for_alignment_builtin_overloads_3 (size_t a, int i, char c, short s, long l)
+{
+  static_assert (__is_same (decltype (__builtin_align_down (i, a)), int), "");
+  static_assert (__is_same (decltype (__builtin_align_down (c, a)), char), "");
+  static_assert (__is_same (decltype (__builtin_align_down (s, a)), short), "");
+  static_assert (__is_same (decltype (__builtin_align_down (l, a)), long), "");
+
+  static_assert (__is_same (decltype (__builtin_align_up (i, a)), int), "");
+  static_assert (__is_same (decltype (__builtin_align_up (c, a)), char), "");
+  static_assert (__is_same (decltype (__builtin_align_up (s, a)), short), "");
+  static_assert (__is_same (decltype (__builtin_align_up (l, a)), long), "");
+
+  static_assert (__is_same (decltype (__builtin_is_aligned (i, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (c, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (s, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (l, a)), bool), "");
+}
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types-4.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types-4.C
new file mode 100644
index 00000000000..a4cd7eeb563
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types-4.C
@@ -0,0 +1,24 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+typedef unsigned long size_t;
+
+void
+check_return_types_for_alignment_builtin_overloads_3_const (size_t a,
+        const int i, const char c, const short s, const long l)
+{
+  static_assert (__is_same (decltype (__builtin_align_down (i, a)), const int), "");
+  static_assert (__is_same (decltype (__builtin_align_down (c, a)), const char), "");
+  static_assert (__is_same (decltype (__builtin_align_down (s, a)), const short), "");
+  static_assert (__is_same (decltype (__builtin_align_down (l, a)), const long), "");
+
+  static_assert (__is_same (decltype (__builtin_align_up (i, a)), const int), "");
+  static_assert (__is_same (decltype (__builtin_align_up (c, a)), const char), "");
+  static_assert (__is_same (decltype (__builtin_align_up (s, a)), const short), "");
+  static_assert (__is_same (decltype (__builtin_align_up (l, a)), const long), "");
+
+  static_assert (__is_same (decltype (__builtin_is_aligned (i, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (c, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (s, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (l, a)), bool), "");
+}
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types-5.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types-5.C
new file mode 100644
index 00000000000..5543d6a39fd
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types-5.C
@@ -0,0 +1,17 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+typedef unsigned long size_t;
+
+void
+check_return_types_for_alignment_builtin_overloads_4_intcap (size_t a, __intcap_t c)
+{
+  static_assert (__is_same (decltype (__builtin_align_down (c, a)), __intcap_t), "");
+  static_assert (__is_same (decltype (__builtin_align_down ((__intcap_t)128, a)), __intcap_t), "");
+
+  static_assert (__is_same (decltype (__builtin_align_up (c, a)), __intcap_t), "");
+  static_assert (__is_same (decltype (__builtin_align_up ((__intcap_t)64, a)), __intcap_t), "");
+
+  static_assert (__is_same (decltype (__builtin_is_aligned (c, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned ((__intcap_t)32, a)), bool), "");
+}
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-1.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-1.C
new file mode 100644
index 00000000000..8d032d14fbe
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-1.C
@@ -0,0 +1,40 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-O2 -march=morello -mabi=lp64" } */
+
+typedef unsigned long size_t;
+typedef __INTPTR_TYPE__ intptr_t;
+typedef __UINTPTR_TYPE__ uintptr_t;
+
+void
+check_return_types_for_alignment_builtin_overloads (size_t a,
+        int *i, char *c,  void *v)
+{
+  static_assert (__is_same (decltype (__builtin_align_down (i, a)), int *), "");
+  static_assert (__is_same (decltype (__builtin_align_down (c, a)), char *), "");
+  static_assert (__is_same (decltype (__builtin_align_down (v, a)), void *), "");
+  static_assert (__is_same (decltype (__builtin_align_down (128, a)), int), "");
+  static_assert (__is_same (decltype (__builtin_align_down ((intptr_t)128, a)), intptr_t), "");
+  static_assert (__is_same (decltype (__builtin_align_down ((uintptr_t)128, a)), uintptr_t), "");
+
+  static_assert (__is_same (decltype (__builtin_align_up (i, a)), int *), "");
+  static_assert (__is_same (decltype (__builtin_align_up (c, a)), char *), "");
+  static_assert (__is_same (decltype (__builtin_align_up (v, a)), void *), "");
+  static_assert (__is_same (decltype (__builtin_align_up (128, a)), int), "");
+  static_assert (__is_same (decltype (__builtin_align_up ((intptr_t)128, a)), intptr_t), "");
+  static_assert (__is_same (decltype (__builtin_align_up ((uintptr_t)128, a)), uintptr_t), "");
+
+  static_assert (__is_same (decltype (__builtin_is_aligned (i, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (c, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (v, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (128, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned ((intptr_t)128, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned ((uintptr_t)128, a)), bool), "");
+
+  static_assert (__is_same (decltype (__builtin_align_down (128, 16)), int), "");
+  static_assert (__is_same (decltype (__builtin_align_up (128, 16)), int), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (128, 16)), bool), "");
+
+  static_assert (__is_same (decltype (__builtin_align_down (0, a)), int), "");
+  static_assert (__is_same (decltype (__builtin_align_up (0, a)), int), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (0, a)), bool), "");
+}
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-2.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-2.C
new file mode 100644
index 00000000000..0321ff1e7a9
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-2.C
@@ -0,0 +1,21 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-O2 -march=morello -mabi=lp64" } */
+
+typedef unsigned long size_t;
+
+void
+check_return_types_for_alignment_builtin_overloads_2 (size_t a,
+        const int *i, const char *c, const void *v)
+{
+  static_assert (__is_same (decltype (__builtin_align_down (i, a)), const int *), "");
+  static_assert (__is_same (decltype (__builtin_align_down (c, a)), const char *), "");
+  static_assert (__is_same (decltype (__builtin_align_down (v, a)), const void *), "");
+
+  static_assert (__is_same (decltype (__builtin_align_up (i, a)), const int *), "");
+  static_assert (__is_same (decltype (__builtin_align_up (c, a)), const char *), "");
+  static_assert (__is_same (decltype (__builtin_align_up (v, a)), const void *), "");
+
+  static_assert (__is_same (decltype (__builtin_is_aligned (i, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (c, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (v, a)), bool), "");
+}
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-3.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-3.C
new file mode 100644
index 00000000000..4571206f040
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-3.C
@@ -0,0 +1,40 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-O2 -march=morello -mabi=lp64" } */
+
+typedef unsigned long size_t;
+typedef __INTPTR_TYPE__ intptr_t;
+typedef __UINTPTR_TYPE__ uintptr_t;
+
+void
+check_return_types_for_alignment_builtin_overloads_cap (size_t a,
+        int * __capability i, char * __capability c,  void * __capability v)
+{
+  static_assert (__is_same (decltype (__builtin_align_down (i, a)), int __capability*), "");
+  static_assert (__is_same (decltype (__builtin_align_down (c, a)), char __capability*), "");
+  static_assert (__is_same (decltype (__builtin_align_down (v, a)), void __capability*), "");
+  static_assert (__is_same (decltype (__builtin_align_down (128, a)), int), "");
+  static_assert (__is_same (decltype (__builtin_align_down ((intptr_t)128, a)), intptr_t), "");
+  static_assert (__is_same (decltype (__builtin_align_down ((uintptr_t)128, a)), uintptr_t), "");
+
+  static_assert (__is_same (decltype (__builtin_align_up (i, a)), int __capability*), "");
+  static_assert (__is_same (decltype (__builtin_align_up (c, a)), char __capability*), "");
+  static_assert (__is_same (decltype (__builtin_align_up (v, a)), void __capability*), "");
+  static_assert (__is_same (decltype (__builtin_align_up (128, a)), int), "");
+  static_assert (__is_same (decltype (__builtin_align_up ((intptr_t)128, a)), intptr_t), "");
+  static_assert (__is_same (decltype (__builtin_align_up ((uintptr_t)128, a)), uintptr_t), "");
+
+  static_assert (__is_same (decltype (__builtin_is_aligned (i, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (c, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (v, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (128, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned ((intptr_t)128, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned ((uintptr_t)128, a)), bool), "");
+
+  static_assert (__is_same (decltype (__builtin_align_down (128, 16)), int), "");
+  static_assert (__is_same (decltype (__builtin_align_up (128, 16)), int), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (128, 16)), bool), "");
+
+  static_assert (__is_same (decltype (__builtin_align_down (0, a)), int), "");
+  static_assert (__is_same (decltype (__builtin_align_up (0, a)), int), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (0, a)), bool), "");
+}
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-4.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-4.C
new file mode 100644
index 00000000000..6ac30a75385
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-4.C
@@ -0,0 +1,24 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-O2 -march=morello -mabi=lp64" } */
+
+typedef unsigned long size_t;
+
+void
+check_return_types_for_alignment_builtin_overloads_3_const (size_t a,
+        const int i, const char c, const short s, const long l)
+{
+  static_assert (__is_same (decltype (__builtin_align_down (i, a)), const int), "");
+  static_assert (__is_same (decltype (__builtin_align_down (c, a)), const char), "");
+  static_assert (__is_same (decltype (__builtin_align_down (s, a)), const short), "");
+  static_assert (__is_same (decltype (__builtin_align_down (l, a)), const long), "");
+
+  static_assert (__is_same (decltype (__builtin_align_up (i, a)), const int), "");
+  static_assert (__is_same (decltype (__builtin_align_up (c, a)), const char), "");
+  static_assert (__is_same (decltype (__builtin_align_up (s, a)), const short), "");
+  static_assert (__is_same (decltype (__builtin_align_up (l, a)), const long), "");
+
+  static_assert (__is_same (decltype (__builtin_is_aligned (i, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (c, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (s, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned (l, a)), bool), "");
+}
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-5.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-5.C
new file mode 100644
index 00000000000..0bc8139935a
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_ret_types_hybrid-5.C
@@ -0,0 +1,17 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-O2 -march=morello -mabi=lp64" } */
+
+typedef unsigned long size_t;
+
+void
+check_return_types_for_alignment_builtin_overloads_4_intcap (size_t a, __intcap_t c)
+{
+  static_assert (__is_same (decltype (__builtin_align_down (c, a)), __intcap_t), "");
+  static_assert (__is_same (decltype (__builtin_align_down ((__intcap_t)128, a)), __intcap_t), "");
+
+  static_assert (__is_same (decltype (__builtin_align_up (c, a)), __intcap_t), "");
+  static_assert (__is_same (decltype (__builtin_align_up ((__intcap_t)64, a)), __intcap_t), "");
+
+  static_assert (__is_same (decltype (__builtin_is_aligned (c, a)), bool), "");
+  static_assert (__is_same (decltype (__builtin_is_aligned ((__intcap_t)32, a)), bool), "");
+}
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_warnings.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_warnings.C
new file mode 100644
index 00000000000..d09466613a7
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_alignment_warnings.C
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+
+typedef unsigned long size_t;
+
+bool
+foo (char *c) {
+  return __builtin_is_aligned (c, 1);   /* { dg-warning "the result of checking whether a value is aligned to 1 byte is always true" } */
+}
+
+char *
+bar (char *c) {
+  return __builtin_align_down (c, 1);   /* { dg-warning "the result of checking whether a value is aligned to 1 byte is always true" } */
+}
+
+char *
+baz (char *c) {
+  return __builtin_align_up (c, 1);    /* { dg-warning "the result of checking whether a value is aligned to 1 byte is always true" } */
+}
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_is_aligned-imm-imm.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_is_aligned-imm-imm.C
new file mode 100644
index 00000000000..d8fdaf8a9e1
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_is_aligned-imm-imm.C
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+#define IS_ALIGNED_CHECK(X, N) bool foo_##N() \
+    { return __builtin_is_aligned (X, N); }
+
+IS_ALIGNED_CHECK (128, 1)   /* { dg-warning "the result of checking whether a value is aligned to 1 byte is always true" "" { target *-*-* } 5 } */
+IS_ALIGNED_CHECK (128, 2)
+IS_ALIGNED_CHECK (128, 4)
+IS_ALIGNED_CHECK (512, 8)
+IS_ALIGNED_CHECK (1024, 64)
+IS_ALIGNED_CHECK (1024, 256)
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
+/* { dg-final { scan-assembler-not {scvalue\t} } } */
+/* { dg-final { scan-assembler-times {mov\tw[0-9]+, 1} 6 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_is_aligned-imm-imm_not_aligned.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_is_aligned-imm-imm_not_aligned.C
new file mode 100644
index 00000000000..fbe6b979a30
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_is_aligned-imm-imm_not_aligned.C
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+#define IS_ALIGNED_CHECK(X, N) bool foo_##N() \
+    { return __builtin_is_aligned (X, N); }
+
+IS_ALIGNED_CHECK (127, 2)
+IS_ALIGNED_CHECK (127, 4)
+IS_ALIGNED_CHECK (511, 8)
+IS_ALIGNED_CHECK (1023, 64)
+IS_ALIGNED_CHECK (1023, 256)
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
+/* { dg-final { scan-assembler-not {scvalue\t} } } */
+/* { dg-final { scan-assembler-times {mov\tw[0-9]+, 0} 5 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_is_aligned-imm.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_is_aligned-imm.C
new file mode 100644
index 00000000000..b4f6df4b829
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_is_aligned-imm.C
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+bool
+foo_4 (void *c) {
+  return __builtin_is_aligned (c, 4);
+}
+
+bool
+foo_16 (void *c) {
+  return __builtin_is_aligned (c, 16);
+}
+
+bool
+foo_64 (void *c) {
+  return __builtin_is_aligned (c, 64);
+}
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
+/* { dg-final { scan-assembler-not {scvalue\t} } } */
+/* { dg-final { scan-assembler-times {cset\tw[0-9]+, eq} 3 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_is_aligned.C b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_is_aligned.C
new file mode 100644
index 00000000000..31a8f36e215
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/builtin_is_aligned.C
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+typedef unsigned long size_t;
+
+bool
+foo2 (size_t a) {
+  return __builtin_is_aligned (128, a);
+}
+
+bool
+foo3 (void * c) {
+  return __builtin_is_aligned (c, 16);
+}
+
+bool
+bar (void * c, size_t a) {
+  return __builtin_is_aligned (c, a);
+}
+
+bool
+baz (void * c, size_t *a) {
+  return __builtin_is_aligned (c, *a);
+}
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
+/* { dg-final { scan-assembler-not {scvalue\t} } } */
+/* { dg-final { scan-assembler-times {cset\tw[0-9], eq} 4 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/morello/builtins/morello-cxx-builtins.exp b/gcc/testsuite/g++.target/aarch64/morello/builtins/morello-cxx-builtins.exp
new file mode 100644
index 00000000000..d107e9c886c
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/morello/builtins/morello-cxx-builtins.exp
@@ -0,0 +1,41 @@
+#  Specific regression driver for AArch64 Morello.
+#  Copyright (C) 2021 Free Software Foundation, Inc.
+#
+#  This file is part of GCC.
+#
+#  GCC is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 3, or (at your option)
+#  any later version.
+#
+#  GCC is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with GCC; see the file COPYING3.  If not see
+#  <http://www.gnu.org/licenses/>.  */
+
+# Exit immediately if this isn't an AArch64 target.
+if {![istarget aarch64*-*-*] } then {
+  return
+}
+
+# These builtins are tested here for capabilities only
+#if { ![check_effective_target_aarch64_capability_any] } then {
+#  return
+#}
+
+# Load support procs.
+load_lib g++-dg.exp
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cCS\]]] \
+    "" "-ansi"
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/gcc.dg/builtin_alignment_errors-3.c b/gcc/testsuite/gcc.dg/builtin_alignment_errors-3.c
new file mode 100644
index 00000000000..f333f0ff67f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin_alignment_errors-3.c
@@ -0,0 +1,67 @@
+/* { dg-do compile } */
+
+int
+down_bad_type () {
+    return __builtin_align_down ((badtype)128, 16); /* { dg-error ".badtype. undeclared" } */
+    /* { dg-error "before numeric constant" "" { target *-*-* } .-1 } */
+    /* { dg-error "too few arguments" "" { target *-*-* } .-2 } */
+}
+
+int
+down_no_alignment () {
+    return __builtin_align_down ((int)128); /* { dg-error "too few arguments" } */
+}
+
+int
+down_bad_alignment () {
+    return __builtin_align_down ((int)128, 13); /* { dg-warning "requested alignment is not a power of 2" } */
+}
+
+int
+down_no_arguments () {
+    return __builtin_align_down(); /* { dg-error "too few arguments to function" } */
+}
+
+int
+up_bad_type () {
+    return __builtin_align_up ((badtype)128, 16); /* { dg-error ".badtype. undeclared" } */
+    /* { dg-error "before numeric constant" "" { target *-*-* } .-1 } */
+    /* { dg-error "too few arguments" "" { target *-*-* } .-2 } */
+}
+
+int
+up_no_alignment () {
+    return __builtin_align_up ((int)128); /* { dg-error "too few arguments" } */
+}
+
+int
+up_bad_alignment () {
+    return __builtin_align_up ((int)128, 13); /* { dg-warning "requested alignment is not a power of 2" } */
+}
+
+int
+up_no_arguments () {
+    return __builtin_align_up(); /* { dg-error "too few arguments" } */
+}
+
+int
+check_bad_type () {
+    return __builtin_is_aligned ((badtype)128, 16); /* { dg-error ".badtype. undeclared" } */
+    /* { dg-error "before numeric constant" "" { target *-*-* } .-1 } */
+    /* { dg-error "too few arguments" "" { target *-*-* } .-2 } */
+}
+
+int
+check_no_alignment () {
+    return __builtin_is_aligned ((int)128); /* { dg-error "too few arguments" } */
+}
+
+int
+check_bad_alignment () {
+    return __builtin_is_aligned ((int)128, 13); /* { dg-warning "requested alignment is not a power of 2" } */
+}
+
+int
+check_no_arguments () {
+    return __builtin_is_aligned(); /* { dg-error "too few arguments" } */
+}
diff --git a/gcc/testsuite/gcc.dg/builtin_alignment_errors-4.c b/gcc/testsuite/gcc.dg/builtin_alignment_errors-4.c
new file mode 100644
index 00000000000..14a315d2210
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin_alignment_errors-4.c
@@ -0,0 +1,6 @@
+typedef unsigned long size_t;
+void *
+ham (size_t a) {
+  return __builtin_align_down (1024, a);    /* { dg-error {returning 'int' from a function with return type 'void \*' makes pointer from integer without a cast \[-Wint-conversion\]} "" { target { ! cheri_capability_pure } } } */
+  /* { dg-error {returning 'int' from a function with incompatible result type capability 'void \*'} "" { target { cheri_capability_pure } } .-1 } */
+}
diff --git a/gcc/testsuite/gcc.dg/builtin_alignment_errors-5.c b/gcc/testsuite/gcc.dg/builtin_alignment_errors-5.c
new file mode 100644
index 00000000000..4dc23d762b2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin_alignment_errors-5.c
@@ -0,0 +1,17 @@
+typedef unsigned long size_t;
+struct tempstruct {
+    unsigned short x;
+    unsigned int y;
+};
+unsigned
+down (struct tempstruct x, size_t alignment) {
+    return __builtin_align_down (x, alignment); /* { dg-error "incompatible type for argument 1" } */
+}
+unsigned
+up (struct tempstruct x, size_t alignment) {
+    return __builtin_align_up (x, alignment); /* { dg-error "incompatible type for argument 1" } */
+}
+unsigned
+aligned (struct tempstruct x, size_t alignment) {
+    return __builtin_is_aligned (x, alignment); /* { dg-error "incompatible type for argument 1" } */
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/arm_align_max_stack_pwr.c b/gcc/testsuite/gcc.target/aarch64/arm_align_max_stack_pwr.c
index 7f356fe300a..5b33646d4a6 100644
--- a/gcc/testsuite/gcc.target/aarch64/arm_align_max_stack_pwr.c
+++ b/gcc/testsuite/gcc.target/aarch64/arm_align_max_stack_pwr.c
@@ -17,4 +17,5 @@ dummy ()
   return result;
 }
 
-/* { dg-final { scan-assembler "and\tx\[0-9\]+, x\[0-9\]+, -65536" } } */
+/* { dg-final { scan-assembler "and\tx\[0-9\]+, x\[0-9\]+, -65536" { target { ! cheri_capability_pure } } } } */
+/* { dg-final { scan-assembler "alignu\tc\[0-9\]+, c\[0-9\]+, #16" { target cheri_capability_pure } } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_down-imm-imm.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_down-imm-imm.c
new file mode 100644
index 00000000000..8845971d530
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_down-imm-imm.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+int
+foo () {
+  return __builtin_align_down (120, 16);
+}
+
+int
+bar () {
+  return __builtin_align_down (127, 32);
+}
+
+int
+baz () {
+  return __builtin_align_down (1023, 512);
+}
+
+/* { dg-final { scan-assembler-times {mov\t[wx][0-9]+, 112} 1 } } */
+/* { dg-final { scan-assembler-times {mov\t[wx][0-9]+, 96} 1 } } */
+/* { dg-final { scan-assembler-times {mov\t[wx][0-9]+, 512} 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_down-imm.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_down-imm.c
new file mode 100644
index 00000000000..8e26802299b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_down-imm.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+#define ALIGN_DOWN_IMM(T,N) T* \
+		foo_##N (T* c) \
+		{ return __builtin_align_down (c, N); }
+
+/* Alignment N must be 1 or greater.  */
+/* Aligning value to 1 byte is a no-op.  */
+ALIGN_DOWN_IMM(void, 2)
+ALIGN_DOWN_IMM(void, 4)
+ALIGN_DOWN_IMM(void, 8)
+ALIGN_DOWN_IMM(void, 16)
+ALIGN_DOWN_IMM(void, 32)
+ALIGN_DOWN_IMM(void, 64)
+
+/* { dg-final { scan-assembler-times {alignd\tc[0-9]+, c[0-9]+, #1} 1 } } */
+/* { dg-final { scan-assembler-times {alignd\tc[0-9]+, c[0-9]+, #2} 1 } } */
+/* { dg-final { scan-assembler-times {alignd\tc[0-9]+, c[0-9]+, #3} 1 } } */
+/* { dg-final { scan-assembler-times {alignd\tc[0-9]+, c[0-9]+, #4} 1 } } */
+/* { dg-final { scan-assembler-times {alignd\tc[0-9]+, c[0-9]+, #5} 1 } } */
+/* { dg-final { scan-assembler-times {alignd\tc[0-9]+, c[0-9]+, #6} 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_down.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_down.c
new file mode 100644
index 00000000000..5ab423675e4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_down.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+typedef unsigned long size_t;
+
+void *
+foo2 (void *c, size_t alignment) {
+  return __builtin_align_down (c, 16);
+}
+
+int
+foo3 (size_t alignment) {
+  return __builtin_align_down (128, alignment);
+}
+
+void *
+bar (void *c, size_t alignment) {
+  return __builtin_align_down (c, alignment);
+}
+
+void *
+baz (void *c, size_t *alignment) {
+  return __builtin_align_down (c, *alignment);
+}
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
+/* { dg-final { scan-assembler-times {alignd\t} 1 } } */
+/* { dg-final { scan-assembler-times {scvalue\tc[0-9]+, c[0-9]+, x[0-9]+} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_down_hybrid-2.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_down_hybrid-2.c
new file mode 100644
index 00000000000..9ab37d8afd1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_down_hybrid-2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello -mabi=lp64" } */
+
+typedef unsigned long size_t;
+
+void *
+foo2 (void *c) {
+  return __builtin_align_down (c, 16);
+}
+
+void *
+bar (void *c, size_t alignment) {
+  return __builtin_align_down (c, alignment);
+}
+
+int
+baz (size_t alignment) {
+  return __builtin_align_down (1024, alignment);
+}
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
+/* { dg-final { scan-assembler-not {scvalue\t} } } */
+/* { dg-final { scan-assembler-not {alignu\t} } } */
+/* { dg-final { scan-assembler-not {alignd\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_down_hybrid.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_down_hybrid.c
new file mode 100644
index 00000000000..7bf6d90c6cd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_down_hybrid.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello -mabi=lp64" } */
+
+typedef unsigned long size_t;
+
+void * __capability
+foo2 (void * __capability c) {
+  return __builtin_align_down (c, 16);
+}
+
+void * __capability
+bar (void * __capability c, size_t alignment) {
+  return __builtin_align_down (c, alignment);
+}
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
+/* { dg-final { scan-assembler-times {alignd\t} 1 } } */
+/* { dg-final { scan-assembler-times {scvalue\tc[0-9]+, c[0-9]+, x[0-9]+} 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_intcap.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_intcap.c
new file mode 100644
index 00000000000..c6781089527
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_intcap.c
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cheri_capability_any } */
+
+typedef unsigned long size_t;
+
+__intcap_t
+down1 (__intcap_t c, size_t alignment) {
+  return __builtin_align_down (c, alignment);
+}
+
+__intcap_t
+down2 (size_t alignment) {
+  return __builtin_align_down ((__intcap_t)128, alignment);
+}
+
+__intcap_t
+down3 () {
+  return __builtin_align_down ((__intcap_t)128, 16);
+}
+
+__intcap_t
+up1 (__intcap_t c, size_t alignment) {
+  return __builtin_align_up (c, alignment);
+}
+
+__intcap_t
+up2 (size_t alignment) {
+  return __builtin_align_up ((__intcap_t)128, alignment);
+}
+
+__intcap_t
+up3 () {
+  return __builtin_align_up ((__intcap_t)128, 16);
+}
+
+_Bool
+isa1 (__intcap_t c, size_t alignment) {
+  return __builtin_is_aligned (c, alignment);
+}
+
+_Bool
+isa2 (size_t alignment) {
+  return __builtin_is_aligned ((__intcap_t)128, alignment);
+}
+
+_Bool
+isa3 () {
+  return __builtin_is_aligned ((__intcap_t)128, 16);
+}
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_intptr.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_intptr.c
new file mode 100644
index 00000000000..1efd1a61025
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_intptr.c
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+typedef unsigned long size_t;
+typedef __INTPTR_TYPE__ intptr_t;
+
+intptr_t
+down1 (intptr_t c, size_t alignment) {
+  return __builtin_align_down (c, alignment);
+}
+
+intptr_t
+down2 (size_t alignment) {
+  return __builtin_align_down ((intptr_t)128, alignment);
+}
+
+intptr_t
+down3 () {
+  return __builtin_align_down ((intptr_t)128, 16);
+}
+
+intptr_t
+up1 (intptr_t c, size_t alignment) {
+  return __builtin_align_up (c, alignment);
+}
+
+intptr_t
+up2 (size_t alignment) {
+  return __builtin_align_up ((intptr_t)128, alignment);
+}
+
+intptr_t
+up3 () {
+  return __builtin_align_up ((intptr_t)128, 16);
+}
+
+_Bool
+isa1 (intptr_t c, size_t alignment) {
+  return __builtin_is_aligned (c, alignment);
+}
+
+_Bool
+isa2 (size_t alignment) {
+  return __builtin_is_aligned ((intptr_t)128, alignment);
+}
+
+_Bool
+isa3 () {
+  return __builtin_is_aligned ((intptr_t)128, 16);
+}
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_up-imm-imm.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_up-imm-imm.c
new file mode 100644
index 00000000000..71946043596
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_up-imm-imm.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+int
+foo () {
+  return __builtin_align_up (120, 16);
+}
+
+int
+bar () {
+  return __builtin_align_up (1, 256);
+}
+
+int
+baz () {
+  return __builtin_align_up (1023, 512);
+}
+
+/* { dg-final { scan-assembler-times {mov\t[wx][0-9]+, 128} 1 } } */
+/* { dg-final { scan-assembler-times {mov\t[wx][0-9]+, 256} 1 } } */
+/* { dg-final { scan-assembler-times {mov\t[wx][0-9]+, 1024} 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_up-imm.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_up-imm.c
new file mode 100644
index 00000000000..4290e02e72d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_up-imm.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+#define ALIGN_UP_IMM(T,N) T* \
+		foo_##N (T* c) \
+		{ return __builtin_align_up (c, N); }
+
+/* Alignment N must be 1 or greater.  */
+/* Aligning value to 1 byte is a no-op.  */
+ALIGN_UP_IMM(void, 2)
+ALIGN_UP_IMM(void, 4)
+ALIGN_UP_IMM(void, 8)
+ALIGN_UP_IMM(void, 16)
+ALIGN_UP_IMM(void, 32)
+ALIGN_UP_IMM(void, 64)
+
+/* { dg-final { scan-assembler-times {alignu\tc[0-9]+, c[0-9]+, #1} 1 } } */
+/* { dg-final { scan-assembler-times {alignu\tc[0-9]+, c[0-9]+, #2} 1 } } */
+/* { dg-final { scan-assembler-times {alignu\tc[0-9]+, c[0-9]+, #3} 1 } } */
+/* { dg-final { scan-assembler-times {alignu\tc[0-9]+, c[0-9]+, #4} 1 } } */
+/* { dg-final { scan-assembler-times {alignu\tc[0-9]+, c[0-9]+, #5} 1 } } */
+/* { dg-final { scan-assembler-times {alignu\tc[0-9]+, c[0-9]+, #6} 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_up.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_up.c
new file mode 100644
index 00000000000..f3a8036ad4b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_up.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+typedef unsigned long size_t;
+
+void *
+foo2 (void *c, size_t alignment) {
+  return __builtin_align_up (c, 16);
+}
+
+int
+foo3 (size_t alignment) {
+  return __builtin_align_up (128, alignment);
+}
+
+void *
+bar (void *c, size_t alignment) {
+  return __builtin_align_up (c, alignment);
+}
+
+void *
+baz (void *c, size_t *alignment) {
+  return __builtin_align_up (c, *alignment);
+}
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
+/* { dg-final { scan-assembler-times {alignu\t} 1 } } */
+/* { dg-final { scan-assembler-times {scvalue\tc[0-9]+, c[0-9]+, x[0-9]+} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_up_hybrid-2.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_up_hybrid-2.c
new file mode 100644
index 00000000000..2416eb3d706
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_up_hybrid-2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello -mabi=lp64" } */
+
+typedef unsigned long size_t;
+
+void *
+foo (void *c) {
+  return __builtin_align_up (c, 16);
+}
+
+void *
+bar (void *c, size_t alignment) {
+  return __builtin_align_up (c, alignment);
+}
+
+int
+baz (size_t alignment) {
+  return __builtin_align_up (128, alignment);
+}
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
+/* { dg-final { scan-assembler-not {scvalue\t} } } */
+/* { dg-final { scan-assembler-not {alignu\t} } } */
+/* { dg-final { scan-assembler-not {alignd\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_up_hybrid.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_up_hybrid.c
new file mode 100644
index 00000000000..b0dd4550006
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_align_up_hybrid.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello -mabi=lp64" } */
+
+typedef unsigned long size_t;
+
+void * __capability
+foo1 (void * __capability c) {
+  return __builtin_align_up (c, 16);
+}
+
+void * __capability
+foo2 (void * __capability c, size_t alignment) {
+  return __builtin_align_up (c, alignment);
+}
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
+/* { dg-final { scan-assembler-times {alignu\t} 1 } } */
+/* { dg-final { scan-assembler-times {scvalue\tc[0-9]+, c[0-9]+, x[0-9]+} 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_alignment_errors-2.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_alignment_errors-2.c
new file mode 100644
index 00000000000..d3f73e55a5f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_alignment_errors-2.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+
+_Bool
+foo (char *c) {
+  return __builtin_is_aligned (c, 5);       /* { dg-warning "requested alignment is not a power of 2" } */
+}
+
+char *
+bar (char *c) {
+  return __builtin_align_down (c, 17);      /* { dg-warning "requested alignment is not a power of 2" } */
+}
+
+char *
+baz (char *c) {
+  return __builtin_align_up (c, 1021);      /* { dg-warning "requested alignment is not a power of 2" } */
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_alignment_errors.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_alignment_errors.c
new file mode 100644
index 00000000000..4e2f686bb3d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_alignment_errors.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+
+_Bool
+foo (char *c) {
+  return __builtin_is_aligned (c, 0);   /* { dg-warning "requested alignment must be nonzero" } */
+}
+
+char *
+bar (char *c) {
+  return __builtin_align_down (c, 0);   /* { dg-warning "requested alignment must be nonzero" } */
+}
+
+char *
+baz (char *c) {
+  return __builtin_align_up (c, 0);     /* { dg-warning "requested alignment must be nonzero" } */
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_alignment_fold.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_alignment_fold.c
new file mode 100644
index 00000000000..186d970c9eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_alignment_fold.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+
+int global1 = __builtin_align_down(123, 32);
+int global2 = __builtin_align_up(123, 32);
+_Bool global3 = __builtin_is_aligned(123, 32);
+
+_Static_assert (__builtin_align_down (127, 16) == 112, "");
+_Static_assert (__builtin_align_up (127, 16) == 128, "");
+_Static_assert (__builtin_is_aligned (1024, 512) == 1, "");
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_alignment_fold_nok.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_alignment_fold_nok.c
new file mode 100644
index 00000000000..5a20c2d14ff
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_alignment_fold_nok.c
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+
+_Static_assert (__builtin_align_down (127, 16) == 128, "112 != 128");   /* { dg-error "static assertion failed" } */
+_Static_assert (__builtin_align_up (129, 16) == 128, "144 != 128");     /* { dg-error "static assertion failed" } */
+_Static_assert (__builtin_is_aligned (1023, 512) == 1, "0 != 1");       /* { dg-error "static assertion failed" } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_alignment_warnings.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_alignment_warnings.c
new file mode 100644
index 00000000000..f7981bda6fa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_alignment_warnings.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+
+_Bool
+foo (char *c) {
+  return __builtin_is_aligned (c, 1);   /* { dg-warning "the result of checking whether a value is aligned to 1 byte is always true" } */
+}
+
+char *
+bar (char *c) {
+  return __builtin_align_down (c, 1);   /* { dg-warning "the result of checking whether a value is aligned to 1 byte is always true" } */
+}
+
+char *
+baz (char *c) {
+  return __builtin_align_up (c, 1);    /* { dg-warning "the result of checking whether a value is aligned to 1 byte is always true" } */
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_is_aligned-imm-imm.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_is_aligned-imm-imm.c
new file mode 100644
index 00000000000..ec780a3dfc6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_is_aligned-imm-imm.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+#define IS_ALIGNED_CHECK(X, N) _Bool foo_##N() \
+    { return __builtin_is_aligned (X, N); }
+
+IS_ALIGNED_CHECK (128, 1)   /* { dg-warning "the result of checking whether a value is aligned to 1 byte is always true" "" { target *-*-* } 5 } */
+IS_ALIGNED_CHECK (128, 2)
+IS_ALIGNED_CHECK (128, 4)
+IS_ALIGNED_CHECK (512, 8)
+IS_ALIGNED_CHECK (1024, 64)
+IS_ALIGNED_CHECK (1024, 256)
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
+/* { dg-final { scan-assembler-not {scvalue\t} } } */
+/* { dg-final { scan-assembler-times {mov\tw[0-9]+, 1} 6 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_is_aligned-imm-imm_not_aligned.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_is_aligned-imm-imm_not_aligned.c
new file mode 100644
index 00000000000..bba8ff708c1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_is_aligned-imm-imm_not_aligned.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+#define IS_ALIGNED_CHECK(X, N) _Bool foo_##N() \
+    { return __builtin_is_aligned (X, N); }
+
+IS_ALIGNED_CHECK (127, 2)
+IS_ALIGNED_CHECK (127, 4)
+IS_ALIGNED_CHECK (511, 8)
+IS_ALIGNED_CHECK (1023, 64)
+IS_ALIGNED_CHECK (1023, 256)
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
+/* { dg-final { scan-assembler-not {scvalue\t} } } */
+/* { dg-final { scan-assembler-times {mov\tw[0-9]+, 0} 5 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_is_aligned-imm.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_is_aligned-imm.c
new file mode 100644
index 00000000000..e1a4880dde0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_is_aligned-imm.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+_Bool
+foo_4 (void *c) {
+  return __builtin_is_aligned (c, 4);
+}
+
+_Bool
+foo_16 (void *c) {
+  return __builtin_is_aligned (c, 16);
+}
+
+_Bool
+foo_64 (void *c) {
+  return __builtin_is_aligned (c, 64);
+}
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
+/* { dg-final { scan-assembler-not {scvalue\t} } } */
+/* { dg-final { scan-assembler-times {cset\tw[0-9]+, eq} 3 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_is_aligned.c b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_is_aligned.c
new file mode 100644
index 00000000000..72d6300b221
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/builtin_is_aligned.c
@@ -0,0 +1,28 @@
+/* { dg-do compile { target aarch64*-*-* } } */
+/* { dg-options "-O2 -march=morello+c64 -mabi=purecap" } */
+
+typedef unsigned long size_t;
+
+_Bool
+foo2 (size_t a) {
+  return __builtin_is_aligned (128, a);
+}
+
+_Bool
+foo3 (void * c) {
+  return __builtin_is_aligned (c, 16);
+}
+
+_Bool
+bar (void * c, size_t a) {
+  return __builtin_is_aligned (c, a);
+}
+
+_Bool
+baz (void * c, size_t *a) {
+  return __builtin_is_aligned (c, *a);
+}
+
+/* { dg-final { scan-assembler-not {gcvalue\t} } } */
+/* { dg-final { scan-assembler-not {scvalue\t} } } */
+/* { dg-final { scan-assembler-times {cset\tw[0-9], eq} 4 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/builtins/morello-builtins.exp b/gcc/testsuite/gcc.target/aarch64/morello/builtins/morello-builtins.exp
new file mode 100644
index 00000000000..5f856dcd7b5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/builtins/morello-builtins.exp
@@ -0,0 +1,36 @@
+#  Specific regression driver for AArch64 Morello.
+#  Copyright (C) 2021 Free Software Foundation, Inc.
+#
+#  This file is part of GCC.
+#
+#  GCC is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 3, or (at your option)
+#  any later version.
+#
+#  GCC is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with GCC; see the file COPYING3.  If not see
+#  <http://www.gnu.org/licenses/>.  */
+
+# Exit immediately if this isn't an AArch64 target.
+if {![istarget aarch64*-*-*] } then {
+  return
+}
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cCS\]]] \
+    "" "-ansi"
+
+# All done.
+dg-finish

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-10-21 13:21 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-21 13:21 [gcc(refs/vendors/ARM/heads/morello)] Add builtin align functions Matthew Malcomson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).