📄 alpha.c
字号:
}/* Do what is necessary for `va_start'. The argument is ignored; We look at the current function to determine if stdarg or varargs is used and fill in an initial va_list. A pointer to this constructor is returned. */struct rtx_def *alpha_builtin_saveregs (arglist) tree arglist;{ rtx block, addr, argsize; tree fntype = TREE_TYPE (current_function_decl); int stdarg = (TYPE_ARG_TYPES (fntype) != 0 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node)); int nregs = current_function_args_info; /* If we have a variable-sized argument already, we will have used all the registers, so set up to indicate that. */ if (GET_CODE (current_function_arg_offset_rtx) != CONST_INT) { argsize = plus_constant (current_function_arg_offset_rtx, (6 * UNITS_PER_WORD + UNITS_PER_WORD - 1)); argsize = expand_shift (RSHIFT_EXPR, Pmode, argsize, build_int_2 (3, 0), argsize, 0); } else { /* Compute the number of args in memory and number of arguments already processed. Then adjust the number of registers if this is stdarg. */ int memargs = ((INTVAL (current_function_arg_offset_rtx) + UNITS_PER_WORD - 1) / UNITS_PER_WORD); argsize = GEN_INT (MIN (nregs, 6) + memargs); if (nregs <= 6) nregs -= stdarg; } /* Allocate the va_list constructor */ block = assign_stack_local (BLKmode, 4 * UNITS_PER_WORD, BITS_PER_WORD); RTX_UNCHANGING_P (block) = 1; RTX_UNCHANGING_P (XEXP (block, 0)) = 1; /* Store the argsize as the __va_arg member. */ emit_move_insn (change_address (block, DImode, XEXP (block, 0)), argsize); /* Store the arg pointer in the __va_stack member. */ emit_move_insn (change_address (block, Pmode, plus_constant (XEXP (block, 0), UNITS_PER_WORD)), virtual_incoming_args_rtx); /* Allocate the integer register space, and store it as the __va_ireg member. */ addr = assign_stack_local (BLKmode, 6 * UNITS_PER_WORD, -1); MEM_IN_STRUCT_P (addr) = 1; RTX_UNCHANGING_P (addr) = 1; RTX_UNCHANGING_P (XEXP (addr, 0)) = 1; emit_move_insn (change_address (block, Pmode, plus_constant (XEXP (block, 0), 2 * UNITS_PER_WORD)), copy_to_reg (XEXP (addr, 0))); /* Now store the incoming integer registers. */ if (nregs < 6) move_block_from_reg (16 + nregs, change_address (addr, Pmode, plus_constant (XEXP (addr, 0), nregs * UNITS_PER_WORD)), 6 - nregs); /* Allocate the FP register space, and store it as the __va_freg member. */ addr = assign_stack_local (BLKmode, 6 * UNITS_PER_WORD, -1); MEM_IN_STRUCT_P (addr) = 1; RTX_UNCHANGING_P (addr) = 1; RTX_UNCHANGING_P (XEXP (addr, 0)) = 1; emit_move_insn (change_address (block, Pmode, plus_constant (XEXP (block, 0), 3 * UNITS_PER_WORD)), copy_to_reg (XEXP (addr, 0))); /* Now store the incoming floating-point registers. If we are not to use the floating-point registers, store the integer registers in those locations too. */ if (nregs < 6) move_block_from_reg (16 + 32 * (TARGET_FPREGS != 0) + nregs, change_address (addr, Pmode, plus_constant (XEXP (addr, 0), nregs * UNITS_PER_WORD)), 6 - nregs); /* Return the address of the va_list constructor, but don't put it in a register. This fails when not optimizing and produces worse code when optimizing. */ return XEXP (block, 0);}/* This page contains routines that are used to determine what the function prologue and epilogue code will do and write them out. *//* Compute the size of the save area in the stack. */intalpha_sa_size (){ int size = 0; int i; for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (! fixed_regs[i] && ! call_used_regs[i] && regs_ever_live[i]) size++; return size * 8;}/* Return non-zero if this function needs gp. It does if it has an LDSYM insn. */intalpha_need_gp (){ rtx insn; for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' && GET_CODE (PATTERN (insn)) != USE && GET_CODE (PATTERN (insn)) != CLOBBER && get_attr_type (insn) == TYPE_LDSYM) return 1; return 0;}/* Return 1 if GP is dead at after INSN. */intalpha_gp_dead_after (insn) rtx insn;{ int jump_count = 0; int found = 0; rtx p; /* If we aren't optimizing, don't do this optimization. More importantly, JUMP_LABEL isn't properly set when not optimizing. */ if (optimize == 0) return 0; /* If we are followed by a BARRIER, we don't return. */ if (NEXT_INSN (insn) && GET_CODE (NEXT_INSN (insn)) == BARRIER) return 1; /* Otherwise search for a use of GP before a return. */ for (p = next_active_insn (insn); p; p = next_active_insn (p)) { if (get_attr_type (p) == TYPE_LDSYM || get_attr_type (p) == TYPE_JSR) { found = 1; break; } if (GET_CODE (p) == JUMP_INSN) { if (GET_CODE (PATTERN (p)) == RETURN) break; if (! simplejump_p (p) || jump_count++ > 10) { found = 1; break; } p = JUMP_LABEL (p); } } /* Restore any operands destroyed by the attribute calls above. */ insn_extract (insn); return ! found;}/* Return 1 if this function can directly return via $26. */intdirect_return (){ return (reload_completed && alpha_sa_size () == 0 && get_frame_size () == 0 && current_function_pretend_args_size == 0);}/* Write function prologue. */voidoutput_prolog (file, size) FILE *file; int size;{ HOST_WIDE_INT frame_size = ((size + current_function_outgoing_args_size + current_function_pretend_args_size + alpha_sa_size () + 15) & ~15); int reg_offset = current_function_outgoing_args_size; int start_reg_offset = reg_offset; unsigned reg_mask = 0; int i; /* If we need a GP, load it first. */ alpha_function_needs_gp = alpha_need_gp (); if (alpha_function_needs_gp) { rtx insn; fprintf (file, "\tldgp $29,0($27)\n"); /* If we have a recursive call, put a special label here. */ for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) if (GET_CODE (insn) == CALL_INSN && get_attr_type (insn) != TYPE_JSR) { fprintf (file, "%s..ng:\n", current_function_name); break; } } /* Adjust the stack by the frame size. If the frame size is > 32768 bytes, we have to load it into a register first and then subtract from sp. Note that we are only allowed to adjust sp once in the prologue. */ if (frame_size > 32768) { HOST_WIDE_INT low = (frame_size & 0xffff) - 2 * (frame_size & 0x8000); HOST_WIDE_INT tmp1 = frame_size - low; HOST_WIDE_INT high = ((tmp1 >> 16) & 0xfff) - 2 * ((tmp1 >> 16) & 0x8000); HOST_WIDE_INT tmp2 = frame_size - (high << 16) - low; HOST_WIDE_INT extra = 0; int in_reg = 31; /* We haven't written code to handle frames > 4GB. */#if HOST_BITS_PER_LONG_INT == 64 if ((unsigned HOST_WIDE_INT) frame_size >> 32 != 0) abort ();#endif if (tmp2) { extra = 0x4000; tmp1 -= 0x40000000; high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); } if (low != 0) { fprintf (file, "\tlda $28,%d($%d)\n", low, in_reg); in_reg = 28; } if (extra) { fprintf (file, "\tldah $28,%d($%d)\n", extra, in_reg); in_reg = 28; } fprintf (file, "\tldah $28,%d($%d)\n", high, in_reg); fprintf (file, "\tsubq $30,$28,$30\n"); } else if (frame_size) fprintf (file, "\tlda $30,-%d($30)\n", frame_size); /* Write out the .frame line. If we need a frame pointer, we use an offset of zero. */ if (frame_pointer_needed) fprintf (file, "\t.frame $15,0,$26\n"); else fprintf (file, "\t.frame $30,%d,$26\n", frame_size); /* Save register 26 if it is used. */ if (regs_ever_live[26]) { reg_mask |= 1 << 26; fprintf (file, "\tstq $26,%d($30)\n", reg_offset); reg_offset += 8; } /* Now save any other used register that are required to be saved. */ for (i = 0; i < 32; i++) if (! fixed_regs[i] && ! call_used_regs[i] && regs_ever_live[i] && i != 26) { reg_mask |= 1 << i; fprintf (file, "\tstq $%d,%d($30)\n", i, reg_offset); reg_offset += 8; } /* Print the register mask and do floating-point saves. */ if (reg_mask) fprintf (file, "\t.mask 0x%x,%d\n", reg_mask, start_reg_offset - frame_size); start_reg_offset = reg_offset; reg_mask = 0; for (i = 0; i < 32; i++) if (! fixed_regs[i + 32] && ! call_used_regs[i + 32] && regs_ever_live[i + 32]) { reg_mask |= 1 << i; fprintf (file, "\tstt $f%d,%d($30)\n", i, reg_offset); reg_offset += 8; } /* Print the floating-point mask, if we've saved any fp register. */ if (reg_mask) fprintf (file, "\t.fmask 0x%x,%d\n", reg_mask, start_reg_offset); /* If we need a frame pointer, set it to the value of incoming stack which we compute by adding back the frame size pointer. Because we can subtract one more than we can add, we have to special-case frame sizes of 32K. Note that there is no restriction that the frame pointer be updated in one instruction. */ if (frame_pointer_needed) { if (frame_size == 32768) fprintf (file, "\tlda $15,16384($30)\n\tlda $15,16384($15)\n"); else if (frame_size > 32768) fprintf (file, "\taddq $30,$28,$15\n"); else fprintf (file, "\tlda $15,%d($30)\n", frame_size); }}/* Write function epilogue. */voidoutput_epilog (file, size) FILE *file; int size;{ rtx insn = get_last_insn (); HOST_WIDE_INT frame_size = ((size + current_function_outgoing_args_size + current_function_pretend_args_size + alpha_sa_size () + 15) & ~15); int reg_offset = current_function_outgoing_args_size; int reg_offset_from = STACK_POINTER_REGNUM; int i; /* If the last insn was a BARRIER, we don't have to write anything except the .end pseudo-op. */ if (GET_CODE (insn) == NOTE) insn = prev_nonnote_insn (insn); if (insn == 0 || GET_CODE (insn) != BARRIER) { /* If we have a frame pointer, we restore the registers from an offset from it, assuming that we can reach the offset. If not, we have to compute the address using a scratch register. This is messy, but should not be common. We have to copy the frame pointer elsewhere here since we will be restoring it before we can use it to restore the stack pointer. We use $25. */ if (frame_pointer_needed) { fprintf (file, "\tbis $15,$15,$25\n"); if (frame_size < 32768) reg_offset -= frame_size, reg_offset_from = 25; else { HOST_WIDE_INT low = (frame_size & 0xffff) - 2 * (frame_size & 0x8000); HOST_WIDE_INT tmp1 = frame_size - low; HOST_WIDE_INT high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); HOST_WIDE_INT tmp2 = frame_size - (high << 16) - low; int extra = 0; int in_reg = 31; if (tmp2) { extra = 0x4000; tmp1 -= 0x40000000; high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); } if (low != 0) { fprintf (file, "\tlda $28,%d($%d)\n", low, in_reg); in_reg = 28; } if (extra) { fprintf (file, "\tldah $28,%d($%d)\n", extra, in_reg); in_reg = 28; } fprintf (file, "\tldah $28,%d($%d)\n", high, in_reg); fprintf (file, "\tsubq $25,$28,$28\n"); reg_offset_from = 28; } } /* Restore all the registers, starting with the return address register. */ if (regs_ever_live[26]) { fprintf (file, "\tldq $26,%d($%d)\n", reg_offset, reg_offset_from); reg_offset += 8; } /* Now restore any other used register that that we saved. */ for (i = 0; i < 32; i++) if (! fixed_regs[i] && ! call_used_regs[i] && regs_ever_live[i] && i != 26) { fprintf (file, "\tldq $%d,%d($%d)\n", i, reg_offset, reg_offset_from); reg_offset += 8; } for (i = 0; i < 32; i++) if (! fixed_regs[i + 32] && ! call_used_regs[i + 32] && regs_ever_live[i + 32]) { fprintf (file, "\tldt $f%d,%d($%d)\n", i, reg_offset, reg_offset_from); reg_offset += 8; } /* Restore the stack. If we have a frame pointer, use it. Otherwise, add the size back into the stack, handling the large frame size. */ if (frame_pointer_needed) fprintf (file, "\tbis $25,$25,$30\n"); else if (frame_size > 32767) { HOST_WIDE_INT low = (frame_size & 0xffff) - 2 * (frame_size & 0x8000); HOST_WIDE_INT tmp1 = frame_size - low; HOST_WIDE_INT high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); HOST_WIDE_INT tmp2 = frame_size - (high << 16) - low; HOST_WIDE_INT extra = 0; int in_reg = 31; /* We haven't written code to handle frames > 4GB. */#if HOST_BITS_PER_LONG_INT == 64 if ((unsigned HOST_WIDE_INT) frame_size >> 32 != 0) abort ();#endif if (tmp2) { extra = 0x4000; tmp1 -= 0x40000000; high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); } if (low != 0) { fprintf (file, "\tlda $28,%d($%d)\n", low, in_reg); in_reg = 28; } if (extra) { fprintf (file, "\tldah $28,%d($%d)\n", extra, in_reg); in_reg = 28; } fprintf (file, "\tldah $28,%d($%d)\n", high, in_reg); fprintf (file, "\taddq $30,$28,$30\n"); } else if (frame_size) fprintf (file, "\tlda $30,%d($30)\n", frame_size); /* Now return to the caller. */ fprintf (file, "\tret $31,($26),1\n"); } /* End the function. */ fprintf (file, "\t.end %s\n", alpha_function_name);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -