⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tree.c

📁 这是完整的gcc源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
  /* If the tree evaluates to a constant, then we don't want to hide that     fact (i.e. this allows further folding, and direct checks for constants).     Since it is no problem to reevaluate literals, we just return the      literal node. */  if (TREE_LITERAL (t) || (TREE_READONLY (t) && !TREE_VOLATILE (t))      || TREE_CODE (t) == SAVE_EXPR)    return t;  return build (SAVE_EXPR, TREE_TYPE (expr), t, NULL);}/* Stabilize a reference so that we can use it any number of times   without causing its operands to be evaluated more than once.   Returns the stabilized reference.   Also allows conversion expressions whose operands are references.   Any other kind of expression is returned unchanged.  */treestabilize_reference (ref)     tree ref;{  register tree result;  register enum tree_code code = TREE_CODE (ref);  switch (code)    {    case VAR_DECL:    case PARM_DECL:    case RESULT_DECL:      result = ref;      break;    case NOP_EXPR:    case CONVERT_EXPR:    case FLOAT_EXPR:    case FIX_TRUNC_EXPR:    case FIX_FLOOR_EXPR:    case FIX_ROUND_EXPR:    case FIX_CEIL_EXPR:      result = build_nt (code, stabilize_reference (TREE_OPERAND (ref, 0)));      break;    case INDIRECT_REF:      result = build_nt (INDIRECT_REF, save_expr (TREE_OPERAND (ref, 0)));      break;    case COMPONENT_REF:      result = build_nt (COMPONENT_REF,			 stabilize_reference (TREE_OPERAND (ref, 0)),			 TREE_OPERAND (ref, 1));      break;    case ARRAY_REF:      result = build_nt (ARRAY_REF, stabilize_reference (TREE_OPERAND (ref, 0)),			 save_expr (TREE_OPERAND (ref, 1)));      break;      /* If arg isn't a kind of lvalue we recognize, make no change.	 Caller should recognize the error for an invalid lvalue.  */    default:      return ref;    case ERROR_MARK:      return error_mark_node;    }  TREE_TYPE (result) = TREE_TYPE (ref);  TREE_READONLY (result) = TREE_READONLY (ref);  TREE_VOLATILE (result) = TREE_VOLATILE (ref);  TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (ref);  return result;}/* Low-level constructors for expressions.  *//* Build an expression of code CODE, data type TYPE,   and operands as specified by the arguments ARG1 and following arguments.   Expressions and reference nodes can be created this way.   Constants, decls, types and misc nodes cannot be.  */treebuild (va_alist)     va_dcl{  register va_list p;  enum tree_code code;  register tree t;  register int length;  register int i;  va_start (p);  code = va_arg (p, enum tree_code);  t = make_node (code);  length = tree_code_length[(int) code];  TREE_TYPE (t) = va_arg (p, tree);  if (length == 2)    {      /* This is equivalent to the loop below, but faster.  */      register tree arg0 = va_arg (p, tree);      register tree arg1 = va_arg (p, tree);      TREE_OPERAND (t, 0) = arg0;      TREE_OPERAND (t, 1) = arg1;      TREE_VOLATILE (t)	= (arg0 && TREE_VOLATILE (arg0)) || (arg1 && TREE_VOLATILE (arg1));    }  else    {      for (i = 0; i < length; i++)	{	  register tree operand = va_arg (p, tree);	  TREE_OPERAND (t, i) = operand;	  if (operand && TREE_VOLATILE (operand))	    TREE_VOLATILE (t) = 1;	}    }  va_end (p);  return t;}/* Similar except don't specify the TREE_TYPE   and leave the TREE_VOLATILE as 0.   It is permissible for arguments to be null,   or even garbage if their values do not matter.  */treebuild_nt (va_alist)     va_dcl{  register va_list p;  register enum tree_code code;  register tree t;  register int length;  register int i;  va_start (p);  code = va_arg (p, enum tree_code);  t = make_node (code);  length = tree_code_length[(int) code];  for (i = 0; i < length; i++)    TREE_OPERAND (t, i) = va_arg (p, tree);  va_end (p);  return t;}treebuild_op_identifier (op1, op2)     tree op1, op2;{  register tree t = make_node (OP_IDENTIFIER);  TREE_PURPOSE (t) = op1;  TREE_VALUE (t) = op2;  return t;}/* Create a DECL_... node of code CODE, name NAME and data type TYPE.   We do NOT enter this node in any sort of symbol table.   layout_decl is used to set up the decl's storage layout.   Other slots are initialized to 0 or null pointers.  */treebuild_decl (code, name, type)     enum tree_code code;     tree name, type;{  register tree t;  t = make_node (code);/*  if (type == error_mark_node)    type = integer_type_node; *//* That is not done, deliberately, so that having error_mark_node   as the type can suppress useless errors in the use of this variable.  */  DECL_NAME (t) = name;  if (name)    {      DECL_PRINT_NAME (t) = IDENTIFIER_POINTER (name);      DECL_ASSEMBLER_NAME (t) = IDENTIFIER_POINTER (name);    }  TREE_TYPE (t) = type;  DECL_ARGUMENTS (t) = NULL_TREE;  DECL_INITIAL (t) = NULL_TREE;  if (code == VAR_DECL || code == PARM_DECL || code == RESULT_DECL)    layout_decl (t, 0);  else if (code == FUNCTION_DECL)    DECL_MODE (t) = FUNCTION_MODE;  return t;}#if 0/* Low-level constructors for statements.   These constructors all expect source file name and line number   as arguments, as well as enough arguments to fill in the data   in the statement node.  */treebuild_goto (filename, line, label)     char *filename;     int line;     tree label;{  register tree t = make_node (GOTO_STMT);  STMT_SOURCE_FILE (t) = filename;  STMT_SOURCE_LINE (t) = line;  STMT_BODY (t) = label;  return t;}treebuild_return (filename, line, arg)     char *filename;     int line;     tree arg;{  register tree t = make_node (RETURN_STMT);  STMT_SOURCE_FILE (t) = filename;  STMT_SOURCE_LINE (t) = line;  STMT_BODY (t) = arg;  return t;}treebuild_expr_stmt (filename, line, expr)     char *filename;     int line;     tree expr;{  register tree t = make_node (EXPR_STMT);  STMT_SOURCE_FILE (t) = filename;  STMT_SOURCE_LINE (t) = line;  STMT_BODY (t) = expr;  return t;}treebuild_if (filename, line, cond, thenclause, elseclause)     char *filename;     int line;     tree cond, thenclause, elseclause;{  register tree t = make_node (IF_STMT);  STMT_SOURCE_FILE (t) = filename;  STMT_SOURCE_LINE (t) = line;  STMT_COND (t) = cond;  STMT_THEN (t) = thenclause;  STMT_ELSE (t) = elseclause;  return t;}treebuild_exit (filename, line, cond)     char *filename;     int line;     tree cond;{  register tree t = make_node (EXIT_STMT);  STMT_SOURCE_FILE (t) = filename;  STMT_SOURCE_LINE (t) = line;  STMT_BODY (t) = cond;  return t;}treebuild_asm_stmt (filename, line, asmcode)     char *filename;     int line;     tree asmcode;{  register tree t = make_node (ASM_STMT);  STMT_SOURCE_FILE (t) = filename;  STMT_SOURCE_LINE (t) = line;  STMT_BODY (t) = asmcode;  return t;}treebuild_case (filename, line, object, cases)     char *filename;     int line;     tree object, cases;{  register tree t = make_node (CASE_STMT);  STMT_SOURCE_FILE (t) = filename;  STMT_SOURCE_LINE (t) = line;  STMT_CASE_INDEX (t) = object;  STMT_CASE_LIST (t) = cases;  return t;}treebuild_loop (filename, line, body)     char *filename;     int line;     tree body;{  register tree t = make_node (LOOP_STMT);  STMT_SOURCE_FILE (t) = filename;  STMT_SOURCE_LINE (t) = line;  STMT_BODY (t) = body;  return t;}treebuild_compound (filename, line, body)     char *filename;     int line;     tree body;{  register tree t = make_node (COMPOUND_STMT);  STMT_SOURCE_FILE (t) = filename;  STMT_SOURCE_LINE (t) = line;  STMT_BODY (t) = body;  return t;}#endif /* 0 *//* LET_STMT nodes are used to represent the structure of binding contours   and declarations, once those contours have been exited and their contents   compiled.  This information is used for outputting debugging info.  */treebuild_let (filename, line, vars, subblocks, supercontext, tags)     char *filename;     int line;     tree vars, subblocks, supercontext, tags;{  register tree t = make_node (LET_STMT);  STMT_SOURCE_FILE (t) = filename;  STMT_SOURCE_LINE (t) = line;  STMT_VARS (t) = vars;  STMT_SUBBLOCKS (t) = subblocks;  STMT_SUPERCONTEXT (t) = supercontext;  STMT_BIND_SIZE (t) = 0;  STMT_TYPE_TAGS (t) = tags;  return t;}/* Return a type like TYPE except that its TREE_READONLY is CONSTP   and its TREE_VOLATILE is VOLATILEP.   Such variant types already made are recorded so that duplicates   are not made.   A variant types should never be used as the type of an expression.   Always copy the variant information into the TREE_READONLY   and TREE_VOLATILE of the expression, and then give the expression   as its type the "main variant", the variant whose TREE_READONLY   and TREE_VOLATILE are zero.  Use TYPE_MAIN_VARIANT to find the   main variant.  */treebuild_type_variant (type, constp, volatilep)     tree type;     int constp, volatilep;{  register tree t, m = TYPE_MAIN_VARIANT (type);  register struct obstack *ambient_obstack = current_obstack;  /* Treat any nonzero argument as 1.  */  constp = !!constp;  volatilep = !!volatilep;  /* First search the chain variants for one that is what we want.  */  for (t = m; t; t = TYPE_NEXT_VARIANT (t))    if (constp == TREE_READONLY (t)	&& volatilep == TREE_VOLATILE (t))      return t;  /* We need a new one.  */  current_obstack    = TREE_PERMANENT (type) ? &permanent_obstack : saveable_obstack;  t = copy_node (type);  TREE_READONLY (t) = constp;  TREE_VOLATILE (t) = volatilep;  TYPE_POINTER_TO (t) = 0;  TYPE_REFERENCE_TO (t) = 0;  /* Add this type to the chain of variants of TYPE.  */  TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m);  TYPE_NEXT_VARIANT (m) = t;  current_obstack = ambient_obstack;  return t;}/* Hashing of types so that we don't make duplicates.   The entry point is `type_hash_canon'.  *//* Each hash table slot is a bucket containing a chain   of these structures.  */struct type_hash{  struct type_hash *next;	/* Next structure in the bucket.  */  int hashcode;			/* Hash code of this type.  */  tree type;			/* The type recorded here.  */};/* Now here is the hash table.  When recording a type, it is added   to the slot whose index is the hash code mod the table size.   Note that the hash table is used for several kinds of types   (function types, array types and array index range types, for now).   While all these live in the same table, they are completely independent,   and the hash code is computed differently for each of these.  */#define TYPE_HASH_SIZE 59struct type_hash *type_hash_table[TYPE_HASH_SIZE];/* Here is how primitive or already-canonicalized types' hash   codes are made.  */#define TYPE_HASH(TYPE) TREE_UID (TYPE)/* Compute a hash code for a list of types (chain of TREE_LIST nodes   with types in the TREE_VALUE slots), by adding the hash codes   of the individual types.  */inttype_hash_list (list)     tree list;{  register int hashcode;  register tree tail;  for (hashcode = 0, tail = list; tail; tail = TREE_CHAIN (tail))    hashcode += TYPE_HASH (TREE_VALUE (tail));  return hashcode;}/* Look in the type hash table for a type isomorphic to TYPE.   If one is found, return it.  Otherwise return 0.  */treetype_hash_lookup (hashcode, type)     int hashcode;     tree type;{  register struct type_hash *h;  for (h = type_hash_table[hashcode % TYPE_HASH_SIZE]; h; h = h->next)    if (h->hashcode == hashcode	&& TREE_CODE (h->type) == TREE_CODE (type)	&& TREE_TYPE (h->type) == TREE_TYPE (type)	&& (TYPE_MAX_VALUE (h->type) == TYPE_MAX_VALUE (type)	    || tree_int_cst_equal (TYPE_MAX_VALUE (h->type),				   TYPE_MAX_VALUE (type)))	&& (TYPE_MIN_VALUE (h->type) == TYPE_MIN_VALUE (type)	    || tree_int_cst_equal (TYPE_MIN_VALUE (h->type),				   TYPE_MIN_VALUE (type)))	&& (TYPE_DOMAIN (h->type) == TYPE_DOMAIN (type)	    || (TREE_CODE (TYPE_DOMAIN (h->type)) == TREE_LIST		&& TREE_CODE (TYPE_DOMAIN (type)) == TREE_LIST		&& type_list_equal (TYPE_DOMAIN (h->type), TYPE_DOMAIN (type)))))      return h->type;  return 0;}/* Add an entry to the type-hash-table   for a type TYPE whose hash code is HASHCODE.  */voidtype_hash_add (hashcode, type)     int hashcode;     tree type;{  register struct type_hash *h;  h = (struct type_hash *) oballoc (sizeof (struct type_hash));  h->hashcode = hashcode;  h->type = type;  h->next = type_hash_table[hashcode % TYPE_HASH_SIZE];  type_hash_table[hashcode % TYPE_HASH_SIZE] = h;}/* Given TYPE, and HASHCODE its hash code, return the canonical   object for an identical type if one already exists.   Otherwise, return TYPE, and record it as the canonical object   if it is a permanent object.   To use this function, first create a type of the sort you want.   Then compute its hash code from the fields of the type that   make it different from other similar types.   Then call this function and use the value.   This function frees the type you pass in if it is a duplicate.  *//* Set to 1 to debug without canonicalization.  Never set by program.  */int debug_no_type_hash = 0;treetype_hash_canon (hashcode, type)     int hashcode;     tree type;{  tree t1;  if (debug_no_type_hash)    return type;  t1 = type_hash_lookup (hashcode, type);  if (t1 != 0)    {      struct obstack *o	= TREE_PERMANENT (type) ? &permanent_obstack : saveable_obstack;      obstack_free (o, type);      return t1;    }  /* If this is a new type, record it for later reuse.  */  if (current_obstack == &permanent_obstack)    type_hash_add (hashcode, type);  return type;}/* Given two lists of types   (chains of TREE_LIST nodes with types in the TREE_VALUE slots)   return 1 if the lists contain the same types in the same order.   Also, the TREE_PURPOSEs must match.  */inttype_list_equal (l1, l2)     tree l1, l2;{  register tree t1, t2;  for (t1 = l1, t2 = l2; t1 && t2; t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))    {      if (TREE_VALUE (t1) != TREE_VALUE (t2))	return 0;      if (TREE_PURPOSE (t1) != TREE_PURPOSE (t2)	  && !simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2)))	return 0;    }  return t1 == t2;}/* Nonzero if integer constants T1 and T2   represent the same constant value.  */inttree_int_cst_equal (t1, t2)     tree t1, t2;{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -