📄 integrate.c
字号:
FIRST_PARM_INSN (head) = get_insns (); DECL_SAVED_INSNS (fndecl) = head; DECL_FRAME_SIZE (fndecl) = get_frame_size (); TREE_INLINE (fndecl) = 1; parmdecl_map = 0; label_map = 0; reg_map = 0; return_label = 0; set_new_first_and_last_insn (first_insn, last_insn);}/* Copy the rtx ORIG recursively, replacing pseudo-regs and labels according to `reg_map' and `label_map'. All other kinds of rtx are copied except those that can never be changed during compilation. */static rtxcopy_for_inline (orig) rtx orig;{ register rtx x = orig; register int i; register enum rtx_code code; register char *format_ptr; if (x == 0) return x; code = GET_CODE (x); /* These types may be freely shared. */ switch (code) { case QUEUED: case CONST_INT: case CONST_DOUBLE: case SYMBOL_REF: case PC: case CC0: return x; case ASM_OPERANDS: /* If a single asm insn contains multiple output operands then it contains multiple ASM_OPERANDS rtx's that share operand 3. We must make sure that the copied insn continues to share it. */ if (orig_asm_operands_vector == XVEC (orig, 3)) { x = rtx_alloc (ASM_OPERANDS); XSTR (x, 0) = XSTR (orig, 0); XSTR (x, 1) = XSTR (orig, 1); XINT (x, 2) = XINT (orig, 2); XVEC (x, 3) = copy_asm_operands_vector; XVEC (x, 4) = copy_asm_constraints_vector; XSTR (x, 5) = XSTR (orig, 5); XINT (x, 6) = XINT (orig, 6); return x; } break; case MEM: /* A MEM is allowed to be shared if its address is constant or is a constant plus one of the special registers. */ if (CONSTANT_ADDRESS_P (XEXP (x, 0))) return x;#if 0 /* This is turned off because it is possible for unshare_all_rtl to copy the address, into memory that won't be saved. Although the MEM can safely be shared, and won't be copied there, the address itself cannot be shared, and may need to be copied. */ if (GET_CODE (XEXP (x, 0)) == PLUS && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG && (REGNO (XEXP (XEXP (x, 0), 0)) == FRAME_POINTER_REGNUM || REGNO (XEXP (XEXP (x, 0), 0)) == ARG_POINTER_REGNUM) && CONSTANT_ADDRESS_P (XEXP (XEXP (x, 0), 1)))#if 0 /* This statement was accidentally deleted in the remote past. Reinsert it for 1.37. Don't take the risk now. */ return x;#endif if (GET_CODE (XEXP (x, 0)) == REG && (REGNO (XEXP (x, 0)) == FRAME_POINTER_REGNUM || REGNO (XEXP (x, 0)) == ARG_POINTER_REGNUM) && CONSTANT_ADDRESS_P (XEXP (x, 1))) return x;#endif /* 0 */ break; case LABEL_REF: { /* Must point to the new insn. */ return gen_rtx (LABEL_REF, GET_MODE (orig), label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))]); } case REG: if (REGNO (x) >= FIRST_PSEUDO_REGISTER) return reg_map [REGNO (x)]; else return x; /* If a parm that gets modified lives in a pseudo-reg, set its TREE_VOLATILE to prevent certain optimizations. */ case SET: { rtx dest = SET_DEST (x); if (GET_CODE (dest) == REG && REGNO (dest) < max_parm_reg && REGNO (dest) >= FIRST_PSEUDO_REGISTER && parmdecl_map[REGNO (dest)] != 0) TREE_READONLY (parmdecl_map[REGNO (dest)]) = 0; } break; } /* Replace this rtx with a copy of itself. */ x = rtx_alloc (code); bcopy (orig, x, (sizeof (*x) - sizeof (x->fld) + sizeof (x->fld[0]) * GET_RTX_LENGTH (code))); /* Now scan the subexpressions recursively. We can store any replaced subexpressions directly into X since we know X is not shared! Any vectors in X must be copied if X was copied. */ format_ptr = GET_RTX_FORMAT (code); for (i = 0; i < GET_RTX_LENGTH (code); i++) { switch (*format_ptr++) { case 'e': XEXP (x, i) = copy_for_inline (XEXP (x, i)); break; case 'u': /* Change any references to old-insns to point to the corresponding copied insns. */ XEXP (x, i) = insn_map[INSN_UID (XEXP (x, i))]; break; case 'E': if (XVEC (x, i) != NULL && XVECLEN (x, i) != 0) { register int j; XVEC (x, i) = gen_rtvec_v (XVECLEN (x, i), &XVECEXP (x, i, 0)); for (j = 0; j < XVECLEN (x, i); j++) XVECEXP (x, i, j) = copy_for_inline (XVECEXP (x, i, j)); } break; } } if (code == ASM_OPERANDS && orig_asm_operands_vector == 0) { orig_asm_operands_vector = XVEC (orig, 3); copy_asm_operands_vector = XVEC (x, 3); copy_asm_constraints_vector = XVEC (x, 4); } return x;}/* Integrate the procedure defined by FNDECL. Note that this function may wind up calling itself. Since the static variables are not reentrant, we do not assign them until after the possibility or recursion is eliminated. If IGNORE is nonzero, do not produce a value. Otherwise store the value in TARGET if it is nonzero and that is convenient. Value is: (rtx)-1 if we could not substitute the function 0 if we substituted it and it does not produce a value else an rtx for where the value is stored. */rtxexpand_inline_function (fndecl, parms, target, ignore, type, structure_value_addr) tree fndecl, parms; rtx target; int ignore; tree type; rtx structure_value_addr;{ tree formal, actual; rtx header = DECL_SAVED_INSNS (fndecl); rtx insns = FIRST_FUNCTION_INSN (header); rtx parm_insns = FIRST_PARM_INSN (header); rtx insn; int max_regno = MAX_REGNUM (header) + 1; register int i; int min_labelno = FIRST_LABELNO (header); int max_labelno = LAST_LABELNO (header); int nargs; rtx *arg_vec; rtx local_return_label = 0; rtx follows_call = 0; rtx this_struct_value_rtx = 0; /* List of tree_list nodes with parm as purpose and its index as value. */ tree must_load_parms = 0; if (max_regno < FIRST_PSEUDO_REGISTER) abort (); nargs = list_length (DECL_ARGUMENTS (fndecl)); /* We expect PARMS to have the right length; don't crash if not. */ if (list_length (parms) != nargs) return (rtx)-1; /* Also check that the parms type match. Since the appropriate conversions or default promotions have already been applied, the machine modes should match exactly. */ for (formal = DECL_ARGUMENTS (fndecl), actual = parms; formal; formal = TREE_CHAIN (formal), actual = TREE_CHAIN (actual)) { tree arg = TREE_VALUE (actual); enum machine_mode mode = TYPE_MODE (DECL_ARG_TYPE (formal)); if (mode != TYPE_MODE (TREE_TYPE (arg))) return (rtx)-1; /* If they are block mode, the types should match exactly. */ if (mode == BLKmode && TREE_TYPE (arg) != TREE_TYPE (formal)) return (rtx)-1; } /* Make a binding contour to keep inline cleanups called at outer function-scope level from looking like they are shadowing parameter declarations. */ pushlevel (0); /* Make a fresh binding contour that we can easily remove. */ pushlevel (0); expand_start_bindings (0); if (GET_CODE (parm_insns) == NOTE && NOTE_LINE_NUMBER (parm_insns) < 0) emit_note (NOTE_SOURCE_FILE (parm_insns), NOTE_LINE_NUMBER (parm_insns)); /* Get all the actual args as RTL, and store them in ARG_VEC. */ arg_vec = (rtx *)alloca (nargs * sizeof (rtx)); for (formal = DECL_ARGUMENTS (fndecl), actual = parms, i = 0; formal; formal = TREE_CHAIN (formal), actual = TREE_CHAIN (actual), i++) { /* Actual parameter, already converted to DECL_ARG_TYPE (formal). */ tree arg = TREE_VALUE (actual); /* Mode of the value supplied. */ enum machine_mode tmode = TYPE_MODE (DECL_ARG_TYPE (formal)); /* Mode of the variable used within the function. */ enum machine_mode imode = TYPE_MODE (TREE_TYPE (formal)); rtx copy; emit_note (DECL_SOURCE_FILE (formal), DECL_SOURCE_LINE (formal)); /* Make a place to hold the argument value, still in mode TMODE, and put it in COPY. */ if (TREE_ADDRESSABLE (formal)) { int size = int_size_in_bytes (DECL_ARG_TYPE (formal)); copy = assign_stack_local (tmode, size); if (!memory_address_p (DECL_MODE (formal), XEXP (copy, 0))) copy = change_address (copy, VOIDmode, copy_rtx (XEXP (copy, 0))); store_expr (arg, copy, 0); } else if (! TREE_READONLY (formal) || TREE_VOLATILE (formal)) { /* If parm is modified or if it hasn't a pseudo reg, we may not simply substitute the actual value; copy it through a register. */ copy = gen_reg_rtx (tmode); REG_USERVAR_P (copy) = 1; store_expr (arg, copy, 0); } else { copy = expand_expr (arg, 0, tmode, 0); /* We do not use CONSTANT_ADDRESS_P here because the set of cases where that might make a difference are a subset of the cases that arise even when it is a CONSTANT_ADDRESS_P (i.e., fp_delta gets into the act. */ if (GET_CODE (copy) != REG && ! CONSTANT_P (copy)) copy = copy_to_reg (copy); } /* If passed mode != nominal mode, COPY is now the passed mode. Convert it to the nominal mode (i.e. truncate it). */ if (tmode != imode) copy = convert_to_mode (imode, copy, 0); arg_vec[i] = copy; } copy_parm_decls (DECL_ARGUMENTS (fndecl), arg_vec); /* Perform postincrements before actually calling the function. */ emit_queue (); /* clean up stack so that variables might have smaller offsets. */ do_pending_stack_adjust (); /* Pass the function the address in which to return a structure value. */ if (structure_value_addr) { if (GET_CODE (structure_value_addr) == REG && (struct_value_rtx == 0 || GET_CODE (struct_value_rtx) == MEM)) this_struct_value_rtx = structure_value_addr; else this_struct_value_rtx = copy_to_mode_reg (Pmode, structure_value_addr); } /* Now prepare for copying the insns. Set up reg_map, parm_map and label_map saying how to translate the pseudo-registers, stack-parm references and labels when copying. */ reg_map = (rtx *) alloca (max_regno * sizeof (rtx)); bzero (reg_map, max_regno * sizeof (rtx)); parm_map_size = (FUNCTION_ARGS_SIZE (header) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; parm_map = (rtx *)alloca (parm_map_size * sizeof (rtx)); bzero (parm_map, (parm_map_size * sizeof (rtx))); /* Note that expand_expr (called above) can clobber first_parm_offset. */ first_parm_offset = FIRST_PARM_OFFSET (fndecl); parm_map -= first_parm_offset / UNITS_PER_WORD; parm_map_size += first_parm_offset / UNITS_PER_WORD; if (DECL_ARGUMENTS (fndecl)) { tree decl = DECL_ARGUMENTS (fndecl); for (formal = decl, i = 0; formal; formal = TREE_CHAIN (formal), i++) { /* Create an entry in PARM_MAP that says what pseudo register is associated with an address we might compute. */ if (DECL_OFFSET (formal) >= 0) { /* This parameter has a home in the stack. */ parm_map[DECL_OFFSET (formal) / BITS_PER_WORD] = arg_vec[i]; } else { /* Parameter that was passed in a register; does it have a home on the stack (as a local)? */ rtx frtx = DECL_RTL (formal); rtx offset = 0; if (GET_CODE (frtx) == MEM) { frtx = XEXP (frtx, 0); if (GET_CODE (frtx) == PLUS) { if (XEXP (frtx, 0) == frame_pointer_rtx && GET_CODE (XEXP (frtx, 1)) == CONST_INT) offset = XEXP (frtx, 1); else if (XEXP (frtx, 1) == frame_pointer_rtx && GET_CODE (XEXP (frtx, 0)) == CONST_INT) offset = XEXP (frtx, 0);#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM /* If there is a separate arg pointer and REG_PARM_STACK_SPACE is defined, parms passed in regs can be copied to slots reached via the arg pointer. */ if (XEXP (frtx, 0) == arg_pointer_rtx && GET_CODE (XEXP (frtx, 1)) == CONST_INT) offset = XEXP (frtx, 1); else if (XEXP (frtx, 1) == arg_pointer_rtx && GET_CODE (XEXP (frtx, 0)) == CONST_INT) offset = XEXP (frtx, 0);#endif } if (offset && INTVAL (offset) >= first_parm_offset) parm_map[INTVAL (offset) / UNITS_PER_WORD] = arg_vec[i]; else if (offset) must_load_parms = tree_cons (formal, build_int_2 (i, 0), must_load_parms); else if (TREE_TYPE (formal) != error_mark_node) abort (); } else if (GET_CODE (frtx) != REG) abort (); } /* Create an entry in REG_MAP that says what rtx is associated with a pseudo register from the function being inlined. */ if (GET_CODE (DECL_RTL (formal)) == REG) reg_map[REGNO (DECL_RTL (formal))] = arg_vec[i]; } }#if 0 /* This was turned off when it was written, because expand_call was changed not to need it. */ /* Handle the case where our caller offers a register target but the called function wants to return the value in memory. */ if (this_struct_value_rtx == 0 && aggregate_value_p (DECL_RESULT (fndecl))) { enum machine_mode mode1 = GET_MODE (DECL_RTL (DECL_RESULT (fndecl))); this_struct_value_rtx = assign_stack_local (mode1, GET_MODE_SIZE (mode1)); target = 0; }#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -