📄 i386.c
字号:
/* 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 intix86_comp_type_attributes (type1, type2) tree type1; tree type2;{ /* Check for mismatch of non-default calling convention. */ const char *const rtdstr = TARGET_RTD ? "cdecl" : "stdcall"; if (TREE_CODE (type1) != FUNCTION_TYPE) return 1; /* Check for mismatched return types (cdecl vs stdcall). */ if (!lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type1)) != !lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type2))) return 0; return 1;}/* Return the regparm value for a fuctio with the indicated TYPE. */static intix86_fntype_regparm (type) tree type;{ tree attr; attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (type)); if (attr) return TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr))); else return ix86_regparm;}/* Value is the number of bytes of arguments automatically popped when returning from a subroutine call. FUNDECL is the declaration node of the function (as a tree), FUNTYPE is the data type of the function (as a tree), or for a library call it is an identifier node for the subroutine name. SIZE is the number of bytes of arguments passed on the stack. On the 80386, the RTD insn may be used to pop them if the number of args is fixed, but if the number is variable then the caller must pop them all. RTD can't be used for library calls now because the library is compiled with the Unix compiler. Use of RTD is a selectable option, since it is incompatible with standard Unix calling sequences. If the option is not selected, the caller must always pop the args. The attribute stdcall is equivalent to RTD on a per module basis. */intix86_return_pops_args (fundecl, funtype, size) tree fundecl; tree funtype; int size;{ int rtd = TARGET_RTD && (!fundecl || TREE_CODE (fundecl) != IDENTIFIER_NODE); /* Cdecl functions override -mrtd, and never pop the stack. */ if (! lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype))) { /* Stdcall functions will pop the stack if not variable args. */ if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype))) rtd = 1; if (rtd && (TYPE_ARG_TYPES (funtype) == NULL_TREE || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))) return size; } /* Lose any fake structure return argument if it is passed on the stack. */ if (aggregate_value_p (TREE_TYPE (funtype)) && !TARGET_64BIT) { int nregs = ix86_fntype_regparm (funtype); if (!nregs) return GET_MODE_SIZE (Pmode); } return 0;}/* Argument support functions. *//* Return true when register may be used to pass function parameters. */boolix86_function_arg_regno_p (regno) int regno;{ int i; if (!TARGET_64BIT) return (regno < REGPARM_MAX || (TARGET_SSE && SSE_REGNO_P (regno) && !fixed_regs[regno])); if (SSE_REGNO_P (regno) && TARGET_SSE) return true; /* RAX is used as hidden argument to va_arg functions. */ if (!regno) return true; for (i = 0; i < REGPARM_MAX; i++) if (regno == x86_64_int_parameter_registers[i]) return true; return false;}/* 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 0. */voidinit_cumulative_args (cum, fntype, libname) CUMULATIVE_ARGS *cum; /* Argument info to initialize */ tree fntype; /* tree ptr for function decl */ rtx libname; /* SYMBOL_REF of library name or 0 */{ static CUMULATIVE_ARGS zero_cum; tree param, next_param; if (TARGET_DEBUG_ARG) { fprintf (stderr, "\ninit_cumulative_args ("); if (fntype) fprintf (stderr, "fntype code = %s, ret code = %s", tree_code_name[(int) TREE_CODE (fntype)], tree_code_name[(int) TREE_CODE (TREE_TYPE (fntype))]); else fprintf (stderr, "no fntype"); if (libname) fprintf (stderr, ", libname = %s", XSTR (libname, 0)); } *cum = zero_cum; /* Set up the number of registers to use for passing arguments. */ cum->nregs = ix86_regparm; cum->sse_nregs = SSE_REGPARM_MAX; if (fntype && !TARGET_64BIT) { tree attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (fntype)); if (attr) cum->nregs = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr))); } cum->maybe_vaarg = false; /* Determine if this function has variable arguments. This is indicated by the last argument being 'void_type_mode' if there are no variable arguments. If there are variable arguments, then we won't pass anything in registers */ if (cum->nregs) { for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0; param != 0; param = next_param) { next_param = TREE_CHAIN (param); if (next_param == 0 && TREE_VALUE (param) != void_type_node) { if (!TARGET_64BIT) cum->nregs = 0; cum->maybe_vaarg = true; } } } if ((!fntype && !libname) || (fntype && !TYPE_ARG_TYPES (fntype))) cum->maybe_vaarg = 1; if (TARGET_DEBUG_ARG) fprintf (stderr, ", nregs=%d )\n", cum->nregs); return;}/* x86-64 register passing impleemntation. See x86-64 ABI for details. Goal of this code is to classify each 8bytes of incoming argument by the register class and assign registers accordingly. *//* Return the union class of CLASS1 and CLASS2. See the x86-64 PS ABI for details. */static enum x86_64_reg_classmerge_classes (class1, class2) enum x86_64_reg_class class1, class2;{ /* Rule #1: If both classes are equal, this is the resulting class. */ if (class1 == class2) return class1; /* Rule #2: If one of the classes is NO_CLASS, the resulting class is the other class. */ if (class1 == X86_64_NO_CLASS) return class2; if (class2 == X86_64_NO_CLASS) return class1; /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */ if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS) return X86_64_MEMORY_CLASS; /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */ if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS) || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS)) return X86_64_INTEGERSI_CLASS; if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS) return X86_64_INTEGER_CLASS; /* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used. */ if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS) return X86_64_MEMORY_CLASS; /* Rule #6: Otherwise class SSE is used. */ return X86_64_SSE_CLASS;}/* Classify the argument of type TYPE and mode MODE. CLASSES will be filled by the register class used to pass each word of the operand. The number of words is returned. In case the parameter should be passed in memory, 0 is returned. As a special case for zero sized containers, classes[0] will be NO_CLASS and 1 is returned. BIT_OFFSET is used internally for handling records and specifies offset of the offset in bits modulo 256 to avoid overflow cases. See the x86-64 PS ABI for details.*/static intclassify_argument (mode, type, classes, bit_offset) enum machine_mode mode; tree type; enum x86_64_reg_class classes[MAX_CLASSES]; int bit_offset;{ int bytes = (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode); int words = (bytes + (bit_offset % 64) / 8 + UNITS_PER_WORD - 1) / UNITS_PER_WORD; /* Variable sized entities are always passed/returned in memory. */ if (bytes < 0) return 0; if (type && AGGREGATE_TYPE_P (type)) { int i; tree field; enum x86_64_reg_class subclasses[MAX_CLASSES]; /* On x86-64 we pass structures larger than 16 bytes on the stack. */ if (bytes > 16) return 0; for (i = 0; i < words; i++) classes[i] = X86_64_NO_CLASS; /* Zero sized arrays or structures are NO_CLASS. We return 0 to signalize memory class, so handle it as special case. */ if (!words) { classes[0] = X86_64_NO_CLASS; return 1; } /* Classify each field of record and merge classes. */ if (TREE_CODE (type) == RECORD_TYPE) { /* For classes first merge in the field of the subclasses. */ if (TYPE_BINFO (type) != NULL && TYPE_BINFO_BASETYPES (type) != NULL) { tree bases = TYPE_BINFO_BASETYPES (type); int n_bases = TREE_VEC_LENGTH (bases); int i; for (i = 0; i < n_bases; ++i) { tree binfo = TREE_VEC_ELT (bases, i); int num; int offset = tree_low_cst (BINFO_OFFSET (binfo), 0) * 8; tree type = BINFO_TYPE (binfo); num = classify_argument (TYPE_MODE (type), type, subclasses, (offset + bit_offset) % 256); if (!num) return 0; for (i = 0; i < num; i++) { int pos = (offset + (bit_offset % 64)) / 8 / 8; classes[i + pos] = merge_classes (subclasses[i], classes[i + pos]); } } } /* And now merge the fields of structure. */ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) { if (TREE_CODE (field) == FIELD_DECL) { int num; /* Bitfields are always classified as integer. Handle them early, since later code would consider them to be misaligned integers. */ if (DECL_BIT_FIELD (field)) { for (i = int_bit_position (field) / 8 / 8; i < (int_bit_position (field) + tree_low_cst (DECL_SIZE (field), 0) + 63) / 8 / 8; i++) classes[i] = merge_classes (X86_64_INTEGER_CLASS, classes[i]); } else { num = classify_argument (TYPE_MODE (TREE_TYPE (field)), TREE_TYPE (field), subclasses, (int_bit_position (field) + bit_offset) % 256); if (!num) return 0; for (i = 0; i < num; i++) { int pos = (int_bit_position (field) + (bit_offset % 64)) / 8 / 8; classes[i + pos] = merge_classes (subclasses[i], classes[i + pos]); } } } } } /* Arrays are handled as small records. */ else if (TREE_CODE (type) == ARRAY_TYPE) { int num; num = classify_argument (TYPE_MODE (TREE_TYPE (type)), TREE_TYPE (type), subclasses, bit_offset); if (!num) return 0; /* The partial classes are now full classes. */ if (subclasses[0] == X86_64_SSESF_CLASS && bytes != 4) subclasses[0] = X86_64_SSE_CLASS; if (subclasses[0] == X86_64_INTEGERSI_CLASS && bytes != 4) subclasses[0] = X86_64_INTEGER_CLASS; for (i = 0; i < words; i++) classes[i] = subclasses[i % num]; } /* Unions are similar to RECORD_TYPE but offset is always 0. */ else if (TREE_CODE (type) == UNION_TYPE || TREE_CODE (type) == QUAL_UNION_TYPE) { /* For classes first merge in the field of the subclasses. */ if (TYPE_BINFO (type) != NULL && TYPE_BINFO_BASETYPES (type) != NULL) { tree bases = TYPE_BINFO_BASETYPES (type); int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -