public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] gccrs const folding port: start porting cxx_eval_array_reference()
@ 2022-08-29 15:32 Thomas Schwinge
  0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2022-08-29 15:32 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:7c13a2e5873f5919c00b5f37b6db52af8d0f7300

commit 7c13a2e5873f5919c00b5f37b6db52af8d0f7300
Author: Faisal Abbas <90.abbasfaisal@gmail.com>
Date:   Sat Jul 16 17:01:47 2022 +0100

    gccrs const folding port: start porting cxx_eval_array_reference()
    
    Following functions are ported in this changeset:
     - array_index_cmp
     - unshare_constructor
     - find_array_ctor_elt
     - reduced_constant_expression_p
     - verify_constant
     - diag_array_subscript
     - get_array_or_vector_nelts
     - eval_and_check_array_index
     - extract_string_elt
     - free_constructor
     - cv_unqualified
     - make_tree_vector
     - release_tree_vector
     - vec_safe_push
    
    Following structs, classes and enums are ported in this changeset:
     - releasing_vec
    
    Signed-off-by: Faisal Abbas <90.abbasfaisal@gmail.com>

Diff:
---
 gcc/rust/backend/rust-constexpr.cc | 549 +++++++++++++++++++++++++++++++++++--
 gcc/rust/backend/rust-tree.cc      |  68 +++++
 gcc/rust/backend/rust-tree.h       |  53 ++++
 3 files changed, 653 insertions(+), 17 deletions(-)

diff --git a/gcc/rust/backend/rust-constexpr.cc b/gcc/rust/backend/rust-constexpr.cc
index 53c6ef6a668..8fb378fbda5 100644
--- a/gcc/rust/backend/rust-constexpr.cc
+++ b/gcc/rust/backend/rust-constexpr.cc
@@ -25,10 +25,27 @@
 #include "print-tree.h"
 #include "gimplify.h"
 #include "tree-iterator.h"
+#include "varasm.h"
+
+#define VERIFY_CONSTANT(X)                                                     \
+  do                                                                           \
+    {                                                                          \
+      if (verify_constant ((X), ctx->quiet, non_constant_p, overflow_p))       \
+	return t;                                                              \
+    }                                                                          \
+  while (0)
 
 namespace Rust {
 namespace Compile {
 
+static bool
+verify_constant (tree, bool, bool *, bool *);
+
+static HOST_WIDE_INT
+find_array_ctor_elt (tree ary, tree dindex, bool insert = false);
+static int
+array_index_cmp (tree key, tree index);
+
 struct constexpr_global_ctx
 {
   HOST_WIDE_INT constexpr_ops_count;
@@ -38,7 +55,19 @@ struct constexpr_global_ctx
 
 struct constexpr_ctx
 {
+  /* The part of the context that needs to be unique to the whole
+   cxx_eval_outermost_constant_expr invocation.  */
   constexpr_global_ctx *global;
+
+  /* Whether we should error on a non-constant expression or fail quietly.
+    This flag needs to be here, but some of the others could move to global
+    if they get larger than a word.  */
+  bool quiet;
+  /* The object we're building the CONSTRUCTOR for.  */
+  tree object;
+  /* The CONSTRUCTOR we're currently building up for an aggregate
+     initializer.  */
+  tree ctor;
 };
 
 static tree
@@ -51,19 +80,20 @@ static void
 non_const_var_error (location_t loc, tree r);
 
 static tree
-constexpr_expression (const constexpr_ctx *ctx, tree);
+constexpr_expression (const constexpr_ctx *ctx, tree, bool, bool *, bool *,
+		      tree * = NULL);
 
 static tree
 constexpr_fn_retval (const constexpr_ctx *ctx, tree r);
 
 static tree
-eval_store_expression (const constexpr_ctx *ctx, tree r);
+eval_store_expression (const constexpr_ctx *ctx, tree r, bool, bool *, bool *);
 
 static tree
 eval_call_expression (const constexpr_ctx *ctx, tree r);
 
 static tree
-eval_binary_expression (const constexpr_ctx *ctx, tree r);
+eval_binary_expression (const constexpr_ctx *ctx, tree r, bool, bool *, bool *);
 
 static tree
 get_function_named_in_call (tree t);
@@ -72,15 +102,20 @@ tree
 fold_expr (tree expr)
 {
   constexpr_global_ctx global_ctx;
-  constexpr_ctx ctx = {&global_ctx};
+  constexpr_ctx ctx = {&global_ctx, false};
+  bool non_constant_p = false;
+  bool overflow_p = false;
 
-  tree folded = constexpr_expression (&ctx, expr);
+  tree folded
+    = constexpr_expression (&ctx, expr, false, &non_constant_p, &overflow_p);
   rust_assert (folded != NULL_TREE);
   return folded;
 }
 
 static tree
-constexpr_expression (const constexpr_ctx *ctx, tree t)
+constexpr_expression (const constexpr_ctx *ctx, tree t, bool lval,
+		      bool *non_constant_p, bool *overflow_p,
+		      tree *jump_target /* = NULL */)
 {
   location_t loc = EXPR_LOCATION (t);
 
@@ -165,7 +200,7 @@ constexpr_expression (const constexpr_ctx *ctx, tree t)
     case LTGT_EXPR:
     case RANGE_EXPR:
     case COMPLEX_EXPR:
-      r = eval_binary_expression (ctx, t);
+      r = eval_binary_expression (ctx, t, false, non_constant_p, overflow_p);
       break;
 
     case CALL_EXPR:
@@ -174,11 +209,12 @@ constexpr_expression (const constexpr_ctx *ctx, tree t)
 
     case RETURN_EXPR:
       rust_assert (TREE_OPERAND (t, 0) != NULL_TREE);
-      r = constexpr_expression (ctx, TREE_OPERAND (t, 0));
+      r = constexpr_expression (ctx, TREE_OPERAND (t, 0), false, non_constant_p,
+				overflow_p);
       break;
 
     case MODIFY_EXPR:
-      r = eval_store_expression (ctx, t);
+      r = eval_store_expression (ctx, t, false, non_constant_p, overflow_p);
       break;
 
     default:
@@ -189,7 +225,8 @@ constexpr_expression (const constexpr_ctx *ctx, tree t)
 }
 
 static tree
-eval_store_expression (const constexpr_ctx *ctx, tree t)
+eval_store_expression (const constexpr_ctx *ctx, tree t, bool lval,
+		       bool *non_constant_p, bool *overflow_p)
 {
   tree init = TREE_OPERAND (t, 1);
   if (TREE_CLOBBER_P (init))
@@ -219,7 +256,8 @@ eval_store_expression (const constexpr_ctx *ctx, tree t)
 	    object = probe;
 	  else
 	    {
-	      probe = constexpr_expression (ctx, probe);
+	      probe = constexpr_expression (ctx, probe, lval, non_constant_p,
+					    overflow_p);
 	      evaluated = true;
 	    }
 	  break;
@@ -232,14 +270,15 @@ eval_store_expression (const constexpr_ctx *ctx, tree t)
 /* Subroutine of cxx_eval_constant_expression.
  Like cxx_eval_unary_expression, except for binary expressions.  */
 static tree
-eval_binary_expression (const constexpr_ctx *ctx, tree t)
+eval_binary_expression (const constexpr_ctx *ctx, tree t, bool lval,
+			bool *non_constant_p, bool *overflow_p)
 {
   tree orig_lhs = TREE_OPERAND (t, 0);
   tree orig_rhs = TREE_OPERAND (t, 1);
   tree lhs, rhs;
 
-  lhs = constexpr_expression (ctx, orig_lhs);
-  rhs = constexpr_expression (ctx, orig_rhs);
+  lhs = constexpr_expression (ctx, orig_lhs, lval, non_constant_p, overflow_p);
+  rhs = constexpr_expression (ctx, orig_rhs, lval, non_constant_p, overflow_p);
 
   location_t loc = EXPR_LOCATION (t);
   enum tree_code code = TREE_CODE (t);
@@ -285,9 +324,12 @@ constexpr_fn_retval (const constexpr_ctx *ctx, tree body)
 	return expr;
       }
 
-    case RETURN_EXPR:
-      return constexpr_expression (ctx, body);
-
+      case RETURN_EXPR: {
+	bool non_constant_p = false;
+	bool overflow_p = false;
+	return constexpr_expression (ctx, body, false, &non_constant_p,
+				     &overflow_p);
+      }
       case DECL_EXPR: {
 	tree decl = DECL_EXPR_DECL (body);
 	if (TREE_CODE (decl) == USING_DECL
@@ -437,5 +479,478 @@ var_in_maybe_constexpr_fn (tree t)
   return (DECL_FUNCTION_SCOPE_P (t) && maybe_constexpr_fn (DECL_CONTEXT (t)));
 }
 
+// forked from gcc/cp/constexpr.cc array_index_cmp
+
+/* Returns less than, equal to, or greater than zero if KEY is found to be
+   less than, to match, or to be greater than the constructor_elt's INDEX.  */
+
+static int
+array_index_cmp (tree key, tree index)
+{
+  gcc_assert (TREE_CODE (key) == INTEGER_CST);
+
+  switch (TREE_CODE (index))
+    {
+    case INTEGER_CST:
+      return tree_int_cst_compare (key, index);
+      case RANGE_EXPR: {
+	tree lo = TREE_OPERAND (index, 0);
+	tree hi = TREE_OPERAND (index, 1);
+	if (tree_int_cst_lt (key, lo))
+	  return -1;
+	else if (tree_int_cst_lt (hi, key))
+	  return 1;
+	else
+	  return 0;
+      }
+    default:
+      gcc_unreachable ();
+    }
+}
+
+// forked from gcc/cp/constexpr.cc unshare_constructor
+
+/* If T is a CONSTRUCTOR, return an unshared copy of T and any
+   sub-CONSTRUCTORs.  Otherwise return T.
+
+   We use this whenever we initialize an object as a whole, whether it's a
+   parameter, a local variable, or a subobject, so that subsequent
+   modifications don't affect other places where it was used.  */
+
+tree
+unshare_constructor (tree t MEM_STAT_DECL)
+{
+  if (!t || TREE_CODE (t) != CONSTRUCTOR)
+    return t;
+  auto_vec<tree *, 4> ptrs;
+  ptrs.safe_push (&t);
+  while (!ptrs.is_empty ())
+    {
+      tree *p = ptrs.pop ();
+      tree n = copy_node (*p PASS_MEM_STAT);
+      CONSTRUCTOR_ELTS (n)
+	= vec_safe_copy (CONSTRUCTOR_ELTS (*p) PASS_MEM_STAT);
+      *p = n;
+      vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (n);
+      constructor_elt *ce;
+      for (HOST_WIDE_INT i = 0; vec_safe_iterate (v, i, &ce); ++i)
+	if (ce->value && TREE_CODE (ce->value) == CONSTRUCTOR)
+	  ptrs.safe_push (&ce->value);
+    }
+  return t;
+}
+
+// forked from gcc/cp/constexpr.cc find_array_ctor_elt
+
+/* Returns the index of the constructor_elt of ARY which matches DINDEX, or -1
+   if none.  If INSERT is true, insert a matching element rather than fail.  */
+
+static HOST_WIDE_INT
+find_array_ctor_elt (tree ary, tree dindex, bool insert)
+{
+  if (tree_int_cst_sgn (dindex) < 0)
+    return -1;
+
+  unsigned HOST_WIDE_INT i = tree_to_uhwi (dindex);
+  vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (ary);
+  unsigned HOST_WIDE_INT len = vec_safe_length (elts);
+
+  unsigned HOST_WIDE_INT end = len;
+  unsigned HOST_WIDE_INT begin = 0;
+
+  /* If the last element of the CONSTRUCTOR has its own index, we can assume
+     that the same is true of the other elements and index directly.  */
+  if (end > 0)
+    {
+      tree cindex = (*elts)[end - 1].index;
+      if (cindex == NULL_TREE)
+	{
+	  /* Verify that if the last index is missing, all indexes
+	     are missing.  */
+	  if (flag_checking)
+	    for (unsigned int j = 0; j < len - 1; ++j)
+	      gcc_assert ((*elts)[j].index == NULL_TREE);
+	  if (i < end)
+	    return i;
+	  else
+	    {
+	      begin = end;
+	      if (i == end)
+		/* If the element is to be added right at the end,
+		   make sure it is added with cleared index too.  */
+		dindex = NULL_TREE;
+	      else if (insert)
+		/* Otherwise, in order not to break the assumption
+		   that CONSTRUCTOR either has all indexes or none,
+		   we need to add indexes to all elements.  */
+		for (unsigned int j = 0; j < len; ++j)
+		  (*elts)[j].index = build_int_cst (TREE_TYPE (dindex), j);
+	    }
+	}
+      else if (TREE_CODE (cindex) == INTEGER_CST
+	       && compare_tree_int (cindex, end - 1) == 0)
+	{
+	  if (i < end)
+	    return i;
+	  else
+	    begin = end;
+	}
+    }
+
+  /* Otherwise, find a matching index by means of a binary search.  */
+  while (begin != end)
+    {
+      unsigned HOST_WIDE_INT middle = (begin + end) / 2;
+      constructor_elt &elt = (*elts)[middle];
+      tree idx = elt.index;
+
+      int cmp = array_index_cmp (dindex, idx);
+      if (cmp < 0)
+	end = middle;
+      else if (cmp > 0)
+	begin = middle + 1;
+      else
+	{
+	  if (insert && TREE_CODE (idx) == RANGE_EXPR)
+	    {
+	      /* We need to split the range.  */
+	      constructor_elt e;
+	      tree lo = TREE_OPERAND (idx, 0);
+	      tree hi = TREE_OPERAND (idx, 1);
+	      tree value = elt.value;
+	      dindex = fold_convert (sizetype, dindex);
+	      if (tree_int_cst_lt (lo, dindex))
+		{
+		  /* There are still some lower elts; shorten the range.  */
+		  tree new_hi
+		    = int_const_binop (MINUS_EXPR, dindex, size_one_node);
+		  if (tree_int_cst_equal (lo, new_hi))
+		    /* Only one element left, no longer a range.  */
+		    elt.index = lo;
+		  else
+		    TREE_OPERAND (idx, 1) = new_hi;
+		  /* Append the element we want to insert.  */
+		  ++middle;
+		  e.index = dindex;
+		  e.value = unshare_constructor (value);
+		  vec_safe_insert (CONSTRUCTOR_ELTS (ary), middle, e);
+		}
+	      else
+		/* No lower elts, the range elt is now ours.  */
+		elt.index = dindex;
+
+	      if (tree_int_cst_lt (dindex, hi))
+		{
+		  /* There are still some higher elts; append a range.  */
+		  tree new_lo
+		    = int_const_binop (PLUS_EXPR, dindex, size_one_node);
+		  if (tree_int_cst_equal (new_lo, hi))
+		    e.index = hi;
+		  else
+		    e.index = build2 (RANGE_EXPR, sizetype, new_lo, hi);
+		  e.value = unshare_constructor (value);
+		  vec_safe_insert (CONSTRUCTOR_ELTS (ary), middle + 1, e);
+		}
+	    }
+	  return middle;
+	}
+    }
+
+  if (insert)
+    {
+      constructor_elt e = {dindex, NULL_TREE};
+      vec_safe_insert (CONSTRUCTOR_ELTS (ary), end, e);
+      return end;
+    }
+
+  return -1;
+}
+
+// forked from gcc/cp/constexpr.cc reduced_constant_expression_p
+
+/* Return true if T is a valid constant initializer.  If a CONSTRUCTOR
+   initializes all the members, the CONSTRUCTOR_NO_CLEARING flag will be
+   cleared.
+   FIXME speed this up, it's taking 16% of compile time on sieve testcase.  */
+
+bool
+reduced_constant_expression_p (tree t)
+{
+  if (t == NULL_TREE)
+    return false;
+
+  switch (TREE_CODE (t))
+    {
+    case PTRMEM_CST:
+      /* Even if we can't lower this yet, it's constant.  */
+      return true;
+
+    case CONSTRUCTOR:
+      /* And we need to handle PTRMEM_CST wrapped in a CONSTRUCTOR.  */
+      tree field;
+      if (CONSTRUCTOR_NO_CLEARING (t))
+	{
+	  if (TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
+	    /* An initialized vector would have a VECTOR_CST.  */
+	    return false;
+	  else if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
+	    {
+	      /* There must be a valid constant initializer at every array
+		 index.  */
+	      tree min = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (t)));
+	      tree max = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (t)));
+	      tree cursor = min;
+	      for (auto &e : CONSTRUCTOR_ELTS (t))
+		{
+		  if (!reduced_constant_expression_p (e.value))
+		    return false;
+		  if (array_index_cmp (cursor, e.index) != 0)
+		    return false;
+		  if (TREE_CODE (e.index) == RANGE_EXPR)
+		    cursor = TREE_OPERAND (e.index, 1);
+		  cursor = int_const_binop (PLUS_EXPR, cursor, size_one_node);
+		}
+	      if (find_array_ctor_elt (t, max) == -1)
+		return false;
+	      goto ok;
+	    }
+	  else if (TREE_CODE (TREE_TYPE (t)) == UNION_TYPE)
+	    {
+	      if (CONSTRUCTOR_NELTS (t) == 0)
+		/* An initialized union has a constructor element.  */
+		return false;
+	      /* And it only initializes one member.  */
+	      field = NULL_TREE;
+	    }
+	  else
+	    field = next_initializable_field (TYPE_FIELDS (TREE_TYPE (t)));
+	}
+      else
+	field = NULL_TREE;
+      for (auto &e : CONSTRUCTOR_ELTS (t))
+	{
+	  /* If VAL is null, we're in the middle of initializing this
+	     element.  */
+	  if (!reduced_constant_expression_p (e.value))
+	    return false;
+	  /* Empty class field may or may not have an initializer.  */
+	  for (; field && e.index != field;
+	       field = next_initializable_field (DECL_CHAIN (field)))
+	    if (!is_really_empty_class (TREE_TYPE (field),
+					/*ignore_vptr*/ false))
+	      return false;
+	  if (field)
+	    field = next_initializable_field (DECL_CHAIN (field));
+	}
+      /* There could be a non-empty field at the end.  */
+      for (; field; field = next_initializable_field (DECL_CHAIN (field)))
+	if (!is_really_empty_class (TREE_TYPE (field), /*ignore_vptr*/ false))
+	  return false;
+    ok:
+      if (CONSTRUCTOR_NO_CLEARING (t))
+	/* All the fields are initialized.  */
+	CONSTRUCTOR_NO_CLEARING (t) = false;
+      return true;
+
+    default:
+      /* FIXME are we calling this too much?  */
+      return initializer_constant_valid_p (t, TREE_TYPE (t)) != NULL_TREE;
+    }
+}
+
+// forked from gcc/cp/constexpr.cc verify_constant
+
+/* Some expressions may have constant operands but are not constant
+   themselves, such as 1/0.  Call this function to check for that
+   condition.
+
+   We only call this in places that require an arithmetic constant, not in
+   places where we might have a non-constant expression that can be a
+   component of a constant expression, such as the address of a constexpr
+   variable that might be dereferenced later.  */
+
+static bool
+verify_constant (tree t, bool allow_non_constant, bool *non_constant_p,
+		 bool *overflow_p)
+{
+  if (!*non_constant_p && !reduced_constant_expression_p (t) && t != void_node)
+    {
+      if (!allow_non_constant)
+	error ("%q+E is not a constant expression", t);
+      *non_constant_p = true;
+    }
+  if (TREE_OVERFLOW_P (t))
+    {
+      if (!allow_non_constant)
+	{
+	  permerror (input_location, "overflow in constant expression");
+	  /* If we're being permissive (and are in an enforcing
+	     context), ignore the overflow.  */
+	  if (flag_permissive)
+	    return *non_constant_p;
+	}
+      *overflow_p = true;
+    }
+  return *non_constant_p;
+}
+
+// forked in gcc/cp/constexpr.cc diag_array_subscript
+
+/* Under the control of CTX, issue a detailed diagnostic for
+   an out-of-bounds subscript INDEX into the expression ARRAY.  */
+
+static void
+diag_array_subscript (location_t loc, const constexpr_ctx *ctx, tree array,
+		      tree index)
+{
+  if (!ctx->quiet)
+    {
+      tree arraytype = TREE_TYPE (array);
+
+      /* Convert the unsigned array subscript to a signed integer to avoid
+	 printing huge numbers for small negative values.  */
+      tree sidx = fold_convert (ssizetype, index);
+      STRIP_ANY_LOCATION_WRAPPER (array);
+      if (DECL_P (array))
+	{
+	  if (TYPE_DOMAIN (arraytype))
+	    error_at (loc,
+		      "array subscript value %qE is outside the bounds "
+		      "of array %qD of type %qT",
+		      sidx, array, arraytype);
+	  else
+	    error_at (loc,
+		      "nonzero array subscript %qE is used with array %qD of "
+		      "type %qT with unknown bounds",
+		      sidx, array, arraytype);
+	  inform (DECL_SOURCE_LOCATION (array), "declared here");
+	}
+      else if (TYPE_DOMAIN (arraytype))
+	error_at (loc,
+		  "array subscript value %qE is outside the bounds "
+		  "of array type %qT",
+		  sidx, arraytype);
+      else
+	error_at (loc,
+		  "nonzero array subscript %qE is used with array of type %qT "
+		  "with unknown bounds",
+		  sidx, arraytype);
+    }
+}
+
+// forked from gcc/cp/constexpr.cc get_array_or_vector_nelts
+
+/* Return the number of elements for TYPE (which is an ARRAY_TYPE or
+   a VECTOR_TYPE).  */
+
+static tree
+get_array_or_vector_nelts (const constexpr_ctx *ctx, tree type,
+			   bool *non_constant_p, bool *overflow_p)
+{
+  tree nelts;
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      if (TYPE_DOMAIN (type))
+	nelts = array_type_nelts_top (type);
+      else
+	nelts = size_zero_node;
+    }
+  else if (VECTOR_TYPE_P (type))
+    nelts = size_int (TYPE_VECTOR_SUBPARTS (type));
+  else
+    gcc_unreachable ();
+
+  /* For VLAs, the number of elements won't be an integer constant.  */
+  nelts = constexpr_expression (ctx, nelts, false, non_constant_p, overflow_p);
+  return nelts;
+}
+
+// forked from gcc/cp/constexpr.cc eval_and_check_array_index
+
+/* Subroutine of cxx_eval_array_reference.  T is an ARRAY_REF; evaluate the
+   subscript, diagnose any problems with it, and return the result.  */
+
+static tree
+eval_and_check_array_index (const constexpr_ctx *ctx, tree t,
+			    bool allow_one_past, bool *non_constant_p,
+			    bool *overflow_p)
+{
+  location_t loc = rs_expr_loc_or_input_loc (t);
+  tree ary = TREE_OPERAND (t, 0);
+  t = TREE_OPERAND (t, 1);
+  tree index
+    = constexpr_expression (ctx, t, allow_one_past, non_constant_p, overflow_p);
+  VERIFY_CONSTANT (index);
+
+  if (!tree_fits_shwi_p (index) || tree_int_cst_sgn (index) < 0)
+    {
+      diag_array_subscript (loc, ctx, ary, index);
+      *non_constant_p = true;
+      return t;
+    }
+
+  tree nelts = get_array_or_vector_nelts (ctx, TREE_TYPE (ary), non_constant_p,
+					  overflow_p);
+  VERIFY_CONSTANT (nelts);
+  if (allow_one_past ? !tree_int_cst_le (index, nelts)
+		     : !tree_int_cst_lt (index, nelts))
+    {
+      diag_array_subscript (loc, ctx, ary, index);
+      *non_constant_p = true;
+      return t;
+    }
+
+  return index;
+}
+
+// forked from gcc/cp/constexpr.cc extract_string_elt
+
+/* Extract element INDEX consisting of CHARS_PER_ELT chars from
+   STRING_CST STRING.  */
+
+static tree
+extract_string_elt (tree string, unsigned chars_per_elt, unsigned index)
+{
+  tree type = cv_unqualified (TREE_TYPE (TREE_TYPE (string)));
+  tree r;
+
+  if (chars_per_elt == 1)
+    r = build_int_cst (type, TREE_STRING_POINTER (string)[index]);
+  else
+    {
+      const unsigned char *ptr
+	= ((const unsigned char *) TREE_STRING_POINTER (string)
+	   + index * chars_per_elt);
+      r = native_interpret_expr (type, ptr, chars_per_elt);
+    }
+  return r;
+}
+
+// forked from gcc/cp/constexpr.cc free_constructor
+
+/* If T is a CONSTRUCTOR, ggc_free T and any sub-CONSTRUCTORs.  */
+
+static void
+free_constructor (tree t)
+{
+  if (!t || TREE_CODE (t) != CONSTRUCTOR)
+    return;
+  releasing_vec ctors;
+  vec_safe_push (ctors, t);
+  while (!ctors->is_empty ())
+    {
+      tree c = ctors->pop ();
+      if (vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (c))
+	{
+	  constructor_elt *ce;
+	  for (HOST_WIDE_INT i = 0; vec_safe_iterate (elts, i, &ce); ++i)
+	    if (TREE_CODE (ce->value) == CONSTRUCTOR)
+	      vec_safe_push (ctors, ce->value);
+	  ggc_free (elts);
+	}
+      ggc_free (c);
+    }
+}
+
 } // namespace Compile
 } // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 52dae395973..9221f7bb081 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -3154,4 +3154,72 @@ check_for_uninitialized_const_var (tree decl, bool constexpr_context_p,
 
   return true;
 }
+
+// forked from gcc/cp/tree.cc cv_unqualified
+
+/* Return TYPE with const and volatile removed.  */
+
+tree
+cv_unqualified (tree type)
+{
+  int quals;
+
+  if (type == error_mark_node)
+    return type;
+
+  quals = rs_type_quals (type);
+  quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
+  return rs_build_qualified_type (type, quals);
+}
+
+/* The C and C++ parsers both use vectors to hold function arguments.
+   For efficiency, we keep a cache of unused vectors.  This is the
+   cache.  */
+
+typedef vec<tree, va_gc> *tree_gc_vec;
+static GTY ((deletable)) vec<tree_gc_vec, va_gc> *tree_vector_cache;
+
+// forked from gcc/c-family/c-common.c make_tree_vector
+
+/* Return a new vector from the cache.  If the cache is empty,
+   allocate a new vector.  These vectors are GC'ed, so it is OK if the
+   pointer is not released..  */
+
+vec<tree, va_gc> *
+make_tree_vector (void)
+{
+  if (tree_vector_cache && !tree_vector_cache->is_empty ())
+    return tree_vector_cache->pop ();
+  else
+    {
+      /* Passing 0 to vec::alloc returns NULL, and our callers require
+	 that we always return a non-NULL value.  The vector code uses
+	 4 when growing a NULL vector, so we do too.  */
+      vec<tree, va_gc> *v;
+      vec_alloc (v, 4);
+      return v;
+    }
+}
+
+// forked from gcc/c-family/c-common.c release_tree_vector
+
+/* Release a vector of trees back to the cache.  */
+
+void
+release_tree_vector (vec<tree, va_gc> *vec)
+{
+  if (vec != NULL)
+    {
+      if (vec->allocated () >= 16)
+	/* Don't cache vecs that have expanded more than once.  On a p64
+	   target, vecs double in alloc size with each power of 2 elements, e.g
+	   at 16 elements the alloc increases from 128 to 256 bytes.  */
+	vec_free (vec);
+      else
+	{
+	  vec->truncate (0);
+	  vec_safe_push (tree_vector_cache, vec);
+	}
+    }
+}
 } // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index b838e402c32..b93e9364990 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -2009,6 +2009,59 @@ gnu_vector_type_p (const_tree type)
   return TREE_CODE (type) == VECTOR_TYPE && !TYPE_INDIVISIBLE_P (type);
 }
 
+extern vec<tree, va_gc> *
+make_tree_vector (void);
+
+extern void
+release_tree_vector (vec<tree, va_gc> *);
+
+/* Simplified unique_ptr clone to release a tree vec on exit.  */
+
+class releasing_vec
+{
+public:
+  typedef vec<tree, va_gc> vec_t;
+
+  releasing_vec (vec_t *v) : v (v) {}
+  releasing_vec () : v (make_tree_vector ()) {}
+
+  /* Copy ops are deliberately declared but not defined,
+     copies must always be elided.  */
+  releasing_vec (const releasing_vec &);
+  releasing_vec &operator= (const releasing_vec &);
+
+  vec_t &operator* () const { return *v; }
+  vec_t *operator-> () const { return v; }
+  vec_t *get () const { return v; }
+  operator vec_t * () const { return v; }
+  vec_t **operator& () { return &v; }
+
+  /* Breaks pointer/value consistency for convenience.  This takes ptrdiff_t
+     rather than unsigned to avoid ambiguity with the built-in operator[]
+     (bootstrap/91828).  */
+  tree &operator[] (ptrdiff_t i) const { return (*v)[i]; }
+
+  tree *begin () { return ::begin (v); }
+  tree *end () { return ::end (v); }
+
+  void release ()
+  {
+    release_tree_vector (v);
+    v = NULL;
+  }
+
+  ~releasing_vec () { release_tree_vector (v); }
+
+private:
+  vec_t *v;
+};
+
+inline tree *
+vec_safe_push (releasing_vec &r, const tree &t CXX_MEM_STAT_INFO)
+{
+  return vec_safe_push (*&r, t PASS_MEM_STAT);
+}
+
 } // namespace Rust
 
 #endif // RUST_TREE

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

only message in thread, other threads:[~2022-08-29 15:32 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-29 15:32 [gcc/devel/rust/master] gccrs const folding port: start porting cxx_eval_array_reference() Thomas Schwinge

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).