📄 integrate.c
字号:
/* Make certain that we can accept struct_value_{incoming_rtx,rtx}, and map it. */ if (this_struct_value_rtx == 0) ; else if (GET_CODE (struct_value_incoming_rtx) == REG) reg_map[REGNO (XEXP (DECL_RTL (DECL_RESULT (fndecl)), 0))] = this_struct_value_rtx; else if (GET_CODE (struct_value_incoming_rtx) == MEM && XEXP (XEXP (struct_value_incoming_rtx, 0), 0) == frame_pointer_rtx && GET_CODE (XEXP (XEXP (struct_value_incoming_rtx, 0), 1)) == CONST_INT) reg_map[REGNO (XEXP (DECL_RTL (DECL_RESULT (fndecl)), 0))] = this_struct_value_rtx;#if 0 parm_map[INTVAL (XEXP (XEXP (struct_value_incoming_rtx, 0), 1)) / UNITS_PER_WORD] = this_struct_value_rtx;#endif else abort (); label_map = (rtx *)alloca ((max_labelno - min_labelno) * sizeof (rtx)); label_map -= min_labelno; for (i = min_labelno; i < max_labelno; i++) label_map[i] = gen_label_rtx (); /* As we copy insns, record the correspondence, so that inter-insn references can be copied into isomorphic structure. */ insn_map = (rtx *) alloca (INSN_UID (header) * sizeof (rtx)); bzero (insn_map, INSN_UID (header) * sizeof (rtx)); /* Set up a target to translate the inline function's value-register. */ if (this_struct_value_rtx != 0 || TYPE_MODE (type) == VOIDmode) inline_target = 0; else { /* Machine mode function was declared to return. */ enum machine_mode departing_mode = TYPE_MODE (type); /* (Possibly wider) machine mode it actually computes (for the sake of callers that fail to declare it right). */ enum machine_mode arriving_mode = TYPE_MODE (DECL_RESULT_TYPE (fndecl)); /* Don't use MEMs as direct targets because on some machines substituting a MEM for a REG makes invalid insns. Let the combiner substitute the MEM if that is valid. */ if (target && GET_CODE (target) == REG && GET_MODE (target) == departing_mode) inline_target = target; else inline_target = target = gen_reg_rtx (departing_mode); /* If function's value was promoted before return, avoid machine mode mismatch when we substitute INLINE_TARGET. But TARGET is what we will return to the caller. */ if (arriving_mode != departing_mode) inline_target = gen_rtx (SUBREG, arriving_mode, target, 0); } /* Make space in current function's stack frame for the stack frame of the inline function. Adjust all frame-pointer references by the difference between the offset to this space and the offset to the equivalent space in the inline function's frame. This difference equals the size of preexisting locals. */ fp_delta = get_frame_size ();#ifdef FRAME_GROWS_DOWNWARD fp_delta = - fp_delta;#endif inline_fp_rtx = copy_to_mode_reg (Pmode, plus_constant (frame_pointer_rtx, fp_delta)); /* Now allocate the space for that to point at. */ assign_stack_local (VOIDmode, DECL_FRAME_SIZE (fndecl)); /* Load any parms represented as locals with the supplied values. We couldn't do this above where the other parms' values are handled because we need fp_delta to do it right. */ while (must_load_parms) { rtx dest = DECL_RTL (TREE_PURPOSE (must_load_parms)); int parm_num = TREE_INT_CST_LOW (TREE_VALUE (must_load_parms)); emit_insn (gen_move_insn (copy_rtx_and_substitute (dest), arg_vec[parm_num])); must_load_parms = TREE_CHAIN (must_load_parms); } /* Now copy the insns one by one. */ for (insn = insns; insn; insn = NEXT_INSN (insn)) { rtx copy, pattern, next = 0; orig_asm_operands_vector = 0; copy_asm_operands_vector = 0; switch (GET_CODE (insn)) { case INSN: pattern = PATTERN (insn); /* Special handling for the insn immediately after a CALL_INSN that returned a value: If it does copy the value, we must avoid the usual translation of the return-register into INLINE_TARGET. If it just USEs the value, the inline function expects it to stay in the return-register and be returned, so copy it into INLINE_TARGET. */ if (follows_call /* Allow a stack-adjust, handled normally, to come in between the call and the value-copying insn. */ && ! (GET_CODE (pattern) == SET && SET_DEST (pattern) == stack_pointer_rtx)) { if (GET_CODE (pattern) == SET && rtx_equal_p (SET_SRC (pattern), follows_call)) /* This insn copies the value: take special care to copy that value to this insn's destination. */ { copy = emit_insn (gen_rtx (SET, VOIDmode, copy_rtx_and_substitute (SET_DEST (pattern)), follows_call)); RTX_INTEGRATED_P (copy) = 1; follows_call = 0; break; } else if (GET_CODE (pattern) == USE && rtx_equal_p (XEXP (pattern, 0), follows_call)) /* This insn does nothing but says the value is expected to flow through to the inline function's return-value. Make that happen, then ignore this insn. */ { copy = emit_insn (gen_rtx (SET, VOIDmode, inline_target, follows_call)); RTX_INTEGRATED_P (copy) = 1; follows_call = 0; break; } /* If it does neither, this value must be ignored. */ follows_call = 0; } /* The (USE (REG n)) at return from the function should be ignored since we are changing (REG n) into inline_target. */ copy = 0; if (GET_CODE (pattern) == USE && GET_CODE (XEXP (pattern, 0)) == REG && REG_FUNCTION_VALUE_P (XEXP (pattern, 0))) break; /* Ignore setting a function value that we don't want to use. */ if (inline_target == 0 && GET_CODE (pattern) == SET && GET_CODE (SET_DEST (pattern)) == REG && REG_FUNCTION_VALUE_P (SET_DEST (pattern))) break; /* Try to do some quick constant folding here. This will save save execution time of the compiler, as well time and space of the program if done here. */ if (GET_CODE (pattern) == SET && SET_DEST (pattern) == cc0_rtx) next = try_fold_cc0 (insn); if (next != 0) { insn = next; } else { rtx note = find_reg_note (insn, REG_EQUIV, 0); copy = emit_insn (copy_rtx_and_substitute (pattern)); RTX_INTEGRATED_P (copy) = 1; /* If we are copying an insn that loads a constant, record the constantness. */ if (note) REG_NOTES (copy) = gen_rtx (EXPR_LIST, REG_EQUIV, /* Copy the expression in the note. This fixes a bug in compiling GCC 2.00 cplus-lex.c which has an inline function calling another inline function, the inner inline function has a switch statement, and the switch expression is constant. */ copy_rtx_and_substitute (XEXP (note, 0)), REG_NOTES (copy)); } break; case JUMP_INSN: follows_call = 0; if (GET_CODE (PATTERN (insn)) == RETURN) { if (local_return_label == 0) local_return_label = gen_label_rtx (); emit_jump (local_return_label); break; } copy = emit_jump_insn (copy_rtx_and_substitute (PATTERN (insn))); RTX_INTEGRATED_P (copy) = 1; break; case CALL_INSN:#if 0 /* This should no longer be necessary now that references to this function's return value are flagged to distinguish them from other references to the same hard register. */ { rtx newbod; /* If the call's body is (set (reg...) (call...)), the register is a function return register, but DON'T translate it into INLINE_TARGET because it describes the called function, not the caller's return value. */ if (GET_CODE (PATTERN (insn)) == SET) newbod = gen_rtx (SET, VOIDmode, SET_DEST (PATTERN (insn)), copy_rtx_and_substitute (SET_SRC (PATTERN (insn)))); else if (GET_CODE (PATTERN (insn)) == PARALLEL && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET) { register int j; rtx newelem; newbod = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (XVECLEN (PATTERN (insn), 0))); newelem = gen_rtx (SET, VOIDmode, SET_DEST (XVECEXP (PATTERN (insn), 0, 0)), copy_rtx_and_substitute (SET_SRC (XVECEXP (PATTERN (insn), 0, 0)))); XVECEXP (newbod, 0, 0) = newelem; for (j = 1; j < XVECLEN (newbod, 0); j++) XVECEXP (newbod, 0, j) = copy_rtx_and_substitute (XVECEXP (PATTERN (insn), 0, j)); } else newbod = copy_rtx_and_substitute (PATTERN (insn)); copy = emit_call_insn (newbod); }#else /* 1 */ copy = emit_call_insn (copy_rtx_and_substitute (PATTERN (insn)));#endif /* 1 */ RTX_INTEGRATED_P (copy) = 1; /* Special handling needed for the following INSN depending on whether it copies the value from the fcn return reg. */ if (GET_CODE (PATTERN (insn)) == SET) follows_call = SET_DEST (PATTERN (insn)); else if (GET_CODE (PATTERN (insn)) == PARALLEL && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET) follows_call = SET_DEST (XVECEXP (PATTERN (insn), 0, 0)); break; case CODE_LABEL: copy = emit_label (label_map[CODE_LABEL_NUMBER (insn)]); follows_call = 0; break; case BARRIER: copy = emit_barrier (); break; case NOTE: if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_BEG) copy = emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn)); else copy = 0; break; default: abort (); break; } insn_map[INSN_UID (insn)] = copy; } if (local_return_label) emit_label (local_return_label); /* Make copies of the decls of the symbols in the inline function, so that the copies of the variables get declared in the current function. */ copy_decl_tree (DECL_INITIAL (fndecl), 0); /* End the scope containing the copied formal parameter variables. */ expand_end_bindings (getdecls (), 1, 1); poplevel (1, 1, 0); poplevel (0, 0, 0); emit_line_note (input_filename, lineno); reg_map = NULL; label_map = NULL; if (ignore || TYPE_MODE (type) == VOIDmode) return 0; if (structure_value_addr) { if (target) return target; return gen_rtx (MEM, TYPE_MODE (type), memory_address (BLKmode, structure_value_addr)); } return target;}/* Given a chain of PARM_DECLs, ARGS, and a vector of RTL homes VEC, copy each decl into a VAR_DECL, push all of those decls and give each one the corresponding home. */static voidcopy_parm_decls (args, vec) tree args; rtx *vec;{ register tree tail; register int i; for (tail = args, i = 0; tail; tail = TREE_CHAIN (tail), i++) { register tree decl = build_decl (VAR_DECL, DECL_NAME (tail), TREE_TYPE (tail)); /* These args would always appear unused, if not for this. */ TREE_USED (decl) = 1; /* Prevent warning for shadowing with these. */ TREE_INLINE (decl) = 1; decl = pushdecl (decl); DECL_RTL (decl) = vec[i]; }}/* Given a LET_STMT node, push decls and levels so as to construct in the current function a tree of contexts isomorphic to the one that is given. */static voidcopy_decl_tree (let, level) tree let; int level;{ tree t, node; pushlevel (0); for (t = STMT_VARS (let); t; t = TREE_CHAIN (t)) { tree d = build_decl (TREE_CODE (t), DECL_NAME (t), TREE_TYPE (t)); DECL_SOURCE_LINE (d) = DECL_SOURCE_LINE (t); DECL_SOURCE_FILE (d) = DECL_SOURCE_FILE (t); if (DECL_RTL (t) != 0) { if (GET_CODE (DECL_RTL (t)) == MEM && CONSTANT_ADDRESS_P (XEXP (DECL_RTL (t), 0))) /* copy_rtx_and_substitute would call memory_address which would copy the address into a register. Then debugging-output wouldn't know how to handle it. */ DECL_RTL (d) = DECL_RTL (t); else DECL_RTL (d) = copy_rtx_and_substitute (DECL_RTL (t)); } TREE_EXTERNAL (d) = TREE_EXTERNAL (t); TREE_STATIC (d) = TREE_STATIC (t); TREE_PUBLIC (d) = TREE_PUBLIC (t); TREE_LITERAL (d) = TREE_LITERAL (t); TREE_ADDRESSABLE (d) = TREE_ADDRESSABLE (t); TREE_READONLY (d) = TREE_READONLY (t); TREE_VOLATILE (d) = TREE_VOLATILE (t); /* These args would always appear unused, if not for this. */ TREE_USED (d) = 1; /* Prevent warning for shadowing with these. */ TREE_INLINE (d) = 1; pushdecl (d); } for (t = STMT_SUBBLOCKS (let); t; t = TREE_CHAIN (t)) copy_decl_tree (t, level + 1); node = poplevel (level > 0, 0, 0); if (node) TREE_USED (node) = TREE_USED (let);}/* Nonzero if X is a sum which has the frame pointer or arg pointers as a term. */static intframe_pointer_sum_p (x) rtx x;{ if (x == frame_pointer_rtx || x == arg_pointer_rtx) return 1; if (GET_CODE (x) == PLUS && (frame_pointer_sum_p (XEXP (x, 0)) || frame_pointer_sum_p (XEXP (x, 1)))) return 1; return 0;}/* Create a new copy of an rtx. Recursively copies the operands of the rtx, except for those few rtx codes that are sharable. */static rtxcopy_rtx_and_substitute (orig) register rtx orig;{ register rtx copy, temp; register int i, j;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -