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

📄 arm.c

📁 linux下的gcc编译器
💻 C
📖 第 1 页 / 共 5 页
字号:
	  *op1 = GEN_INT (i + 1);	  return code == GT ? GE : LT;	}      break;    case GE:    case LT:      if (i != (((unsigned HOST_WIDE_INT) 1) << (HOST_BITS_PER_WIDE_INT - 1))	  && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))	{	  *op1 = GEN_INT (i - 1);	  return code == GE ? GT : LE;	}      break;    case GTU:    case LEU:      if (i != ~((unsigned HOST_WIDE_INT) 0)	  && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))	{	  *op1 = GEN_INT (i + 1);	  return code == GTU ? GEU : LTU;	}      break;    case GEU:    case LTU:      if (i != 0	  && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))	{	  *op1 = GEN_INT (i - 1);	  return code == GEU ? GTU : LEU;	}      break;    default:      abort ();    }  return code;}/* Decide whether a type should be returned in memory (true)   or in a register (false).  This is called by the macro   RETURN_IN_MEMORY.  */intarm_return_in_memory (type)     tree type;{  HOST_WIDE_INT size;  if (!AGGREGATE_TYPE_P (type))    /* All simple types are returned in registers.  */    return 0;  size = int_size_in_bytes (type);  if (TARGET_ATPCS)    {      /* ATPCS returns aggregate types in memory only if they are	 larger than a word (or are variable size).  */      return (size < 0 || size > UNITS_PER_WORD);    }    /* For the arm-wince targets we choose to be compitable with Microsoft's     ARM and Thumb compilers, which always return aggregates in memory.  */#ifndef ARM_WINCE  /* All structures/unions bigger than one word are returned in memory.     Also catch the case where int_size_in_bytes returns -1.  In this case     the aggregate is either huge or of varaible size, and in either case     we will want to return it via memory and not in a register.  */  if (size < 0 || size > UNITS_PER_WORD)    return 1;    if (TREE_CODE (type) == RECORD_TYPE)    {      tree field;      /* For a struct the APCS says that we only return in a register	 if the type is 'integer like' and every addressable element	 has an offset of zero.  For practical purposes this means	 that the structure can have at most one non bit-field element	 and that this element must be the first one in the structure.  */            /* Find the first field, ignoring non FIELD_DECL things which will	 have been created by C++.  */      for (field = TYPE_FIELDS (type);	   field && TREE_CODE (field) != FIELD_DECL;	   field = TREE_CHAIN (field))	continue;            if (field == NULL)	return 0; /* An empty structure.  Allowed by an extension to ANSI C.  */      /* Check that the first field is valid for returning in a register.  */      /* ... Floats are not allowed */      if (FLOAT_TYPE_P (TREE_TYPE (field)))	return 1;      /* ... Aggregates that are not themselves valid for returning in	 a register are not allowed.  */      if (RETURN_IN_MEMORY (TREE_TYPE (field)))	return 1;      /* Now check the remaining fields, if any.  Only bitfields are allowed,	 since they are not addressable.  */      for (field = TREE_CHAIN (field);	   field;	   field = TREE_CHAIN (field))	{	  if (TREE_CODE (field) != FIELD_DECL)	    continue;	  	  if (!DECL_BIT_FIELD_TYPE (field))	    return 1;	}      return 0;    }    if (TREE_CODE (type) == UNION_TYPE)    {      tree field;      /* Unions can be returned in registers if every element is	 integral, or can be returned in an integer register.  */      for (field = TYPE_FIELDS (type);	   field;	   field = TREE_CHAIN (field))	{	  if (TREE_CODE (field) != FIELD_DECL)	    continue;	  if (FLOAT_TYPE_P (TREE_TYPE (field)))	    return 1;	  	  if (RETURN_IN_MEMORY (TREE_TYPE (field)))	    return 1;	}            return 0;    }#endif /* not ARM_WINCE */      /* Return all other types in memory.  */  return 1;}/* Indicate whether or not words of a double are in big-endian order. */intarm_float_words_big_endian (){  /* For FPA, float words are always big-endian.  For VFP, floats words     follow the memory system mode.  */  if (TARGET_HARD_FLOAT)    {      /* FIXME: TARGET_HARD_FLOAT currently implies FPA.  */      return 1;    }  if (TARGET_VFP)    return (TARGET_BIG_END ? 1 : 0);  return 1;}/* Initialize a variable CUM of type CUMULATIVE_ARGS   for a call to a function whose data type is FNTYPE.   For a library call, FNTYPE is NULL.  */voidarm_init_cumulative_args (pcum, fntype, libname, indirect)     CUMULATIVE_ARGS * pcum;     tree fntype;     rtx libname  ATTRIBUTE_UNUSED;     int indirect ATTRIBUTE_UNUSED;{  /* On the ARM, the offset starts at 0.  */  pcum->nregs = ((fntype && aggregate_value_p (TREE_TYPE (fntype))) ? 1 : 0);    pcum->call_cookie = CALL_NORMAL;  if (TARGET_LONG_CALLS)    pcum->call_cookie = CALL_LONG;      /* Check for long call/short call attributes.  The attributes     override any command line option.  */  if (fntype)    {      if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (fntype)))	pcum->call_cookie = CALL_SHORT;      else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (fntype)))	pcum->call_cookie = CALL_LONG;    }}/* Determine where to put an argument to a function.   Value is zero to push the argument on the stack,   or a hard register in which to store the argument.   MODE is the argument's machine mode.   TYPE is the data type of the argument (as a tree).    This is null for libcalls where that information may    not be available.   CUM is a variable of type CUMULATIVE_ARGS which gives info about    the preceding args and about the function being called.   NAMED is nonzero if this argument is a named parameter    (otherwise it is an extra parameter matching an ellipsis).  */rtxarm_function_arg (pcum, mode, type, named)     CUMULATIVE_ARGS * pcum;     enum machine_mode mode;     tree type ATTRIBUTE_UNUSED;     int named;{  if (mode == VOIDmode)    /* Compute operand 2 of the call insn.  */    return GEN_INT (pcum->call_cookie);    if (!named || pcum->nregs >= NUM_ARG_REGS)    return NULL_RTX;    return gen_rtx_REG (mode, pcum->nregs);}/* Variable sized types are passed by reference.  This is a GCC   extension to the ARM ABI.  */intarm_function_arg_pass_by_reference (cum, mode, type, named)     CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;     enum machine_mode mode ATTRIBUTE_UNUSED;     tree type;     int named ATTRIBUTE_UNUSED;{  return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;}/* Implement va_arg.  */rtxarm_va_arg (valist, type)     tree valist, type;{  /* Variable sized types are passed by reference.  */  if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)    {      rtx addr = std_expand_builtin_va_arg (valist, build_pointer_type (type));      return gen_rtx_MEM (ptr_mode, force_reg (Pmode, addr));    }  return std_expand_builtin_va_arg (valist, type);}/* Encode the current state of the #pragma [no_]long_calls.  */typedef enum{  OFF,		/* No #pramgma [no_]long_calls is in effect.  */  LONG,		/* #pragma long_calls is in effect.  */  SHORT		/* #pragma no_long_calls is in effect.  */} arm_pragma_enum;static arm_pragma_enum arm_pragma_long_calls = OFF;voidarm_pr_long_calls (pfile)     cpp_reader * pfile ATTRIBUTE_UNUSED;{  arm_pragma_long_calls = LONG;}voidarm_pr_no_long_calls (pfile)     cpp_reader * pfile ATTRIBUTE_UNUSED;{  arm_pragma_long_calls = SHORT;}voidarm_pr_long_calls_off (pfile)     cpp_reader * pfile ATTRIBUTE_UNUSED;{  arm_pragma_long_calls = OFF;}/* Table of machine attributes.  */const struct attribute_spec arm_attribute_table[] ={  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */  /* Function calls made to this symbol must be done indirectly, because     it may lie outside of the 26 bit addressing range of a normal function     call.  */  { "long_call",    0, 0, false, true,  true,  NULL },  /* Whereas these functions are always known to reside within the 26 bit     addressing range.  */  { "short_call",   0, 0, false, true,  true,  NULL },  /* Interrupt Service Routines have special prologue and epilogue requirements.  */   { "isr",          0, 1, false, false, false, arm_handle_isr_attribute },  { "interrupt",    0, 1, false, false, false, arm_handle_isr_attribute },  { "naked",        0, 0, true,  false, false, arm_handle_fndecl_attribute },#ifdef ARM_PE  /* ARM/PE has three new attributes:     interfacearm - ?     dllexport - for exporting a function/variable that will live in a dll     dllimport - for importing a function/variable from a dll     Microsoft allows multiple declspecs in one __declspec, separating     them with spaces.  We do NOT support this.  Instead, use __declspec     multiple times.  */  { "dllimport",    0, 0, true,  false, false, NULL },  { "dllexport",    0, 0, true,  false, false, NULL },  { "interfacearm", 0, 0, true,  false, false, arm_handle_fndecl_attribute },#endif  { NULL,           0, 0, false, false, false, NULL }};/* Handle an attribute requiring a FUNCTION_DECL;   arguments as in struct attribute_spec.handler.  */static treearm_handle_fndecl_attribute (node, name, args, flags, no_add_attrs)     tree * node;     tree   name;     tree   args ATTRIBUTE_UNUSED;     int    flags ATTRIBUTE_UNUSED;     bool * no_add_attrs;{  if (TREE_CODE (*node) != FUNCTION_DECL)    {      warning ("`%s' attribute only applies to functions",	       IDENTIFIER_POINTER (name));      *no_add_attrs = true;    }  return NULL_TREE;}/* Handle an "interrupt" or "isr" attribute;   arguments as in struct attribute_spec.handler.  */static treearm_handle_isr_attribute (node, name, args, flags, no_add_attrs)     tree * node;     tree   name;     tree   args;     int    flags;     bool * no_add_attrs;{  if (DECL_P (*node))    {      if (TREE_CODE (*node) != FUNCTION_DECL)	{	  warning ("`%s' attribute only applies to functions",		   IDENTIFIER_POINTER (name));	  *no_add_attrs = true;	}      /* FIXME: the argument if any is checked for type attributes;	 should it be checked for decl ones?  */    }  else    {      if (TREE_CODE (*node) == FUNCTION_TYPE	  || TREE_CODE (*node) == METHOD_TYPE)	{	  if (arm_isr_value (args) == ARM_FT_UNKNOWN)	    {	      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));	      *no_add_attrs = true;	    }	}      else if (TREE_CODE (*node) == POINTER_TYPE	       && (TREE_CODE (TREE_TYPE (*node)) == FUNCTION_TYPE		   || TREE_CODE (TREE_TYPE (*node)) == METHOD_TYPE)	       && arm_isr_value (args) != ARM_FT_UNKNOWN)	{	  *node = build_type_copy (*node);	  TREE_TYPE (*node) = build_type_attribute_variant	    (TREE_TYPE (*node),	     tree_cons (name, args, TYPE_ATTRIBUTES (TREE_TYPE (*node))));	  *no_add_attrs = true;	}      else	{	  /* Possibly pass this attribute on from the type to a decl.  */	  if (flags & ((int) ATTR_FLAG_DECL_NEXT		       | (int) ATTR_FLAG_FUNCTION_NEXT		       | (int) ATTR_FLAG_ARRAY_NEXT))	    {	      *no_add_attrs = true;	      return tree_cons (name, args, NULL_TREE);	    }	  else	    {	      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));	    }	}    }  return NULL_TREE;}/* Return 0 if the attributes for two types are incompatible, 1 if they   are compatible, and 2 if they are nearly compatible (which causes a   warning to be generated).  */static intarm_comp_type_attributes (type1, type2)     tree type1;     tree type2;{  int l1, l2, s1, s2;    /* Check for mismatch of non-default calling convention.  */  if (TREE_CODE (type1) != FUNCTION_TYPE)    return 1;  /* Check for mismatched call attributes.  */  l1 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type1)) != NULL;  l2 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type2)) != NULL;  s1 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type1)) != NULL;  s2 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type2)) != NULL;  /* Only bother to check if an attribute is defined.  */  if (l1 | l2 | s1 | s2)    {      /* If one type 

⌨️ 快捷键说明

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