📄 function.c
字号:
/* If SIZE is -1 it means that somebody tried to allocate a temporary of a variable size. */ if (size == -1) abort (); /* First try to find an available, already-allocated temporary that is the exact size we require. */ for (p = temp_slots; p; p = p->next) if (p->size == size && GET_MODE (p->slot) == mode && ! p->in_use) break; /* If we didn't find, one, try one that is larger than what we want. We find the smallest such. */ if (p == 0) for (p = temp_slots; p; p = p->next) if (p->size > size && GET_MODE (p->slot) == mode && ! p->in_use && (best_p == 0 || best_p->size > p->size)) best_p = p; /* Make our best, if any, the one to use. */ if (best_p) { /* If there are enough aligned bytes left over, make them into a new temp_slot so that the extra bytes don't get wasted. Do this only for BLKmode slots, so that we can be sure of the alignment. */ if (GET_MODE (best_p->slot) == BLKmode) { int alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT; int rounded_size = CEIL_ROUND (size, alignment); if (best_p->size - rounded_size >= alignment) { p = (struct temp_slot *) oballoc (sizeof (struct temp_slot)); p->in_use = p->addr_taken = 0; p->size = best_p->size - rounded_size; p->base_offset = best_p->base_offset + rounded_size; p->full_size = best_p->full_size - rounded_size; p->slot = gen_rtx (MEM, BLKmode, plus_constant (XEXP (best_p->slot, 0), rounded_size)); p->address = 0; p->rtl_expr = 0; p->next = temp_slots; temp_slots = p; stack_slot_list = gen_rtx (EXPR_LIST, VOIDmode, p->slot, stack_slot_list); best_p->size = rounded_size; best_p->full_size = rounded_size; } } p = best_p; } /* If we still didn't find one, make a new temporary. */ if (p == 0) { int frame_offset_old = frame_offset; p = (struct temp_slot *) oballoc (sizeof (struct temp_slot)); /* If the temp slot mode doesn't indicate the alignment, use the largest possible, so no one will be disappointed. */ p->slot = assign_stack_local (mode, size, mode == BLKmode ? -1 : 0); /* The following slot size computation is necessary because we don't know the actual size of the temporary slot until assign_stack_local has performed all the frame alignment and size rounding for the requested temporary. Note that extra space added for alignment can be either above or below this stack slot depending on which way the frame grows. We include the extra space if and only if it is above this slot. */#ifdef FRAME_GROWS_DOWNWARD p->size = frame_offset_old - frame_offset;#else p->size = size;#endif /* Now define the fields used by combine_temp_slots. */#ifdef FRAME_GROWS_DOWNWARD p->base_offset = frame_offset; p->full_size = frame_offset_old - frame_offset;#else p->base_offset = frame_offset_old; p->full_size = frame_offset - frame_offset_old;#endif p->address = 0; p->next = temp_slots; temp_slots = p; } p->in_use = 1; p->addr_taken = 0; p->rtl_expr = sequence_rtl_expr; if (keep == 2) { p->level = target_temp_slot_level; p->keep = 0; } else { p->level = temp_slot_level; p->keep = keep; } /* We may be reusing an old slot, so clear any MEM flags that may have been set from before. */ RTX_UNCHANGING_P (p->slot) = 0; MEM_IN_STRUCT_P (p->slot) = 0; return p->slot;}/* Assign a temporary of given TYPE. KEEP is as for assign_stack_temp. MEMORY_REQUIRED is 1 if the result must be addressable stack memory; it is 0 if a register is OK. DONT_PROMOTE is 1 if we should not promote values in register to wider modes. */rtxassign_temp (type, keep, memory_required, dont_promote) tree type; int keep; int memory_required; int dont_promote;{ enum machine_mode mode = TYPE_MODE (type); int unsignedp = TREE_UNSIGNED (type); if (mode == BLKmode || memory_required) { int size = int_size_in_bytes (type); rtx tmp; /* Unfortunately, we don't yet know how to allocate variable-sized temporaries. However, sometimes we have a fixed upper limit on the size (which is stored in TYPE_ARRAY_MAX_SIZE) and can use that instead. This is the case for Chill variable-sized strings. */ if (size == -1 && TREE_CODE (type) == ARRAY_TYPE && TYPE_ARRAY_MAX_SIZE (type) != NULL_TREE && TREE_CODE (TYPE_ARRAY_MAX_SIZE (type)) == INTEGER_CST) size = TREE_INT_CST_LOW (TYPE_ARRAY_MAX_SIZE (type)); tmp = assign_stack_temp (mode, size, keep); MEM_IN_STRUCT_P (tmp) = AGGREGATE_TYPE_P (type); return tmp; }#ifndef PROMOTE_FOR_CALL_ONLY if (! dont_promote) mode = promote_mode (type, mode, &unsignedp, 0);#endif return gen_reg_rtx (mode);}/* Combine temporary stack slots which are adjacent on the stack. This allows for better use of already allocated stack space. This is only done for BLKmode slots because we can be sure that we won't have alignment problems in this case. */voidcombine_temp_slots (){ struct temp_slot *p, *q; struct temp_slot *prev_p, *prev_q; /* Determine where to free back to after this function. */ rtx free_pointer = rtx_alloc (CONST_INT); for (p = temp_slots, prev_p = 0; p; p = prev_p ? prev_p->next : temp_slots) { int delete_p = 0; if (! p->in_use && GET_MODE (p->slot) == BLKmode) for (q = p->next, prev_q = p; q; q = prev_q->next) { int delete_q = 0; if (! q->in_use && GET_MODE (q->slot) == BLKmode) { if (p->base_offset + p->full_size == q->base_offset) { /* Q comes after P; combine Q into P. */ p->size += q->size; p->full_size += q->full_size; delete_q = 1; } else if (q->base_offset + q->full_size == p->base_offset) { /* P comes after Q; combine P into Q. */ q->size += p->size; q->full_size += p->full_size; delete_p = 1; break; } } /* Either delete Q or advance past it. */ if (delete_q) prev_q->next = q->next; else prev_q = q; } /* Either delete P or advance past it. */ if (delete_p) { if (prev_p) prev_p->next = p->next; else temp_slots = p->next; } else prev_p = p; } /* Free all the RTL made by plus_constant. */ rtx_free (free_pointer);}/* Find the temp slot corresponding to the object at address X. */static struct temp_slot *find_temp_slot_from_address (x) rtx x;{ struct temp_slot *p; rtx next; for (p = temp_slots; p; p = p->next) { if (! p->in_use) continue; else if (XEXP (p->slot, 0) == x || p->address == x || (GET_CODE (x) == PLUS && XEXP (x, 0) == virtual_stack_vars_rtx && GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= p->base_offset && INTVAL (XEXP (x, 1)) < p->base_offset + p->full_size)) return p; else if (p->address != 0 && GET_CODE (p->address) == EXPR_LIST) for (next = p->address; next; next = XEXP (next, 1)) if (XEXP (next, 0) == x) return p; } return 0;} /* Indicate that NEW is an alternate way of referring to the temp slot that previous was known by OLD. */voidupdate_temp_slot_address (old, new) rtx old, new;{ struct temp_slot *p = find_temp_slot_from_address (old); /* If none, return. Else add NEW as an alias. */ if (p == 0) return; else if (p->address == 0) p->address = new; else { if (GET_CODE (p->address) != EXPR_LIST) p->address = gen_rtx (EXPR_LIST, VOIDmode, p->address, NULL_RTX); p->address = gen_rtx (EXPR_LIST, VOIDmode, new, p->address); }}/* If X could be a reference to a temporary slot, mark the fact that its address was taken. */voidmark_temp_addr_taken (x) rtx x;{ struct temp_slot *p; if (x == 0) return; /* If X is not in memory or is at a constant address, it cannot be in a temporary slot. */ if (GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0))) return; p = find_temp_slot_from_address (XEXP (x, 0)); if (p != 0) p->addr_taken = 1;}/* If X could be a reference to a temporary slot, mark that slot as belonging to the to one level higher than the current level. If X matched one of our slots, just mark that one. Otherwise, we can't easily predict which it is, so upgrade all of them. Kept slots need not be touched. This is called when an ({...}) construct occurs and a statement returns a value in memory. */voidpreserve_temp_slots (x) rtx x;{ struct temp_slot *p = 0; /* If there is no result, we still might have some objects whose address were taken, so we need to make sure they stay around. */ if (x == 0) { for (p = temp_slots; p; p = p->next) if (p->in_use && p->level == temp_slot_level && p->addr_taken) p->level--; return; } /* If X is a register that is being used as a pointer, see if we have a temporary slot we know it points to. To be consistent with the code below, we really should preserve all non-kept slots if we can't find a match, but that seems to be much too costly. */ if (GET_CODE (x) == REG && REGNO_POINTER_FLAG (REGNO (x))) p = find_temp_slot_from_address (x); /* If X is not in memory or is at a constant address, it cannot be in a temporary slot, but it can contain something whose address was taken. */ if (p == 0 && (GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0)))) { for (p = temp_slots; p; p = p->next) if (p->in_use && p->level == temp_slot_level && p->addr_taken) p->level--; return; } /* First see if we can find a match. */ if (p == 0) p = find_temp_slot_from_address (XEXP (x, 0)); if (p != 0) { /* Move everything at our level whose address was taken to our new level in case we used its address. */ struct temp_slot *q; if (p->level == temp_slot_level) { for (q = temp_slots; q; q = q->next) if (q != p && q->addr_taken && q->level == p->level) q->level--; p->level--; p->addr_taken = 0; } return; } /* Otherwise, preserve all non-kept slots at this level. */ for (p = temp_slots; p; p = p->next) if (p->in_use && p->level == temp_slot_level && ! p->keep) p->level--;}/* X is the result of an RTL_EXPR. If it is a temporary slot associated with that RTL_EXPR, promote it into a temporary slot at the present level so it will not be freed when we free slots made in the RTL_EXPR. */voidpreserve_rtl_expr_result (x) rtx x;{ struct temp_slot *p; /* If X is not in memory or is at a constant address, it cannot be in a temporary slot. */ if (x == 0 || GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0))) return; /* If we can find a match, move it to our level unless it is already at an upper level. */ p = find_temp_slot_from_address (XEXP (x, 0)); if (p != 0) { p->level = MIN (p->level, temp_slot_level); p->rtl_expr = 0; } return;}/* Free all temporaries used so far. This is normally called at the end of generating code for a statement. Don't free any temporaries currently in use for an RTL_EXPR that hasn't yet been emitted. We could eventually do better than this since it can be reused while generating the same RTL_EXPR, but this is complex and probably not worthwhile. */voidfree_temp_slots (){ struct temp_slot *p; for (p = temp_slots; p; p = p->next) if (p->in_use && p->level == temp_slot_level && ! p->keep && p->rtl_expr == 0) p->in_use = 0; combine_temp_slots ();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -