Created
July 26, 2012 11:46
-
-
Save nicholaslemay/3181611 to your computer and use it in GitHub Desktop.
Holy cyclomatic complexity Batman !
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Check the insns before INSN to see if there is a suitable register | |
6660 containing the same value as GOAL. | |
6661 If OTHER is -1, look for a register in class RCLASS. | |
6662 Otherwise, just see if register number OTHER shares GOAL's value. | |
6663 | |
6664 Return an rtx for the register found, or zero if none is found. | |
6665 | |
6666 If RELOAD_REG_P is (short *)1, | |
6667 we reject any hard reg that appears in reload_reg_rtx | |
6668 because such a hard reg is also needed coming into this insn. | |
6669 | |
6670 If RELOAD_REG_P is any other nonzero value, | |
6671 it is a vector indexed by hard reg number | |
6672 and we reject any hard reg whose element in the vector is nonnegative | |
6673 as well as any that appears in reload_reg_rtx. | |
6674 | |
6675 If GOAL is zero, then GOALREG is a register number; we look | |
6676 for an equivalent for that register. | |
6677 | |
6678 MODE is the machine mode of the value we want an equivalence for. | |
6679 If GOAL is nonzero and not VOIDmode, then it must have mode MODE. | |
6680 | |
6681 This function is used by jump.c as well as in the reload pass. | |
6682 | |
6683 If GOAL is the sum of the stack pointer and a constant, we treat it | |
6684 as if it were a constant except that sp is required to be unchanging. */ | |
6685 | |
6686 rtx | |
6687 find_equiv_reg (rtx goal, rtx insn, enum reg_class rclass, int other, | |
6688 short *reload_reg_p, int goalreg, enum machine_mode mode) | |
6689 { | |
6690 rtx p = insn; | |
6691 rtx goaltry, valtry, value, where; | |
6692 rtx pat; | |
6693 int regno = -1; | |
6694 int valueno; | |
6695 int goal_mem = 0; | |
6696 int goal_const = 0; | |
6697 int goal_mem_addr_varies = 0; | |
6698 int need_stable_sp = 0; | |
6699 int nregs; | |
6700 int valuenregs; | |
6701 int num = 0; | |
6702 | |
6703 if (goal == 0) | |
6704 regno = goalreg; | |
6705 else if (REG_P (goal)) | |
6706 regno = REGNO (goal); | |
6707 else if (MEM_P (goal)) | |
6708 { | |
6709 enum rtx_code code = GET_CODE (XEXP (goal, 0)); | |
6710 if (MEM_VOLATILE_P (goal)) | |
6711 return 0; | |
6712 if (flag_float_store && SCALAR_FLOAT_MODE_P (GET_MODE (goal))) | |
6713 return 0; | |
6714 /* An address with side effects must be reexecuted. */ | |
6715 switch (code) | |
6716 { | |
6717 case POST_INC: | |
6718 case PRE_INC: | |
6719 case POST_DEC: | |
6720 case PRE_DEC: | |
6721 case POST_MODIFY: | |
6722 case PRE_MODIFY: | |
6723 return 0; | |
6724 default: | |
6725 break; | |
6726 } | |
6727 goal_mem = 1; | |
6728 } | |
6729 else if (CONSTANT_P (goal)) | |
6730 goal_const = 1; | |
6731 else if (GET_CODE (goal) == PLUS | |
6732 && XEXP (goal, 0) == stack_pointer_rtx | |
6733 && CONSTANT_P (XEXP (goal, 1))) | |
6734 goal_const = need_stable_sp = 1; | |
6735 else if (GET_CODE (goal) == PLUS | |
6736 && XEXP (goal, 0) == frame_pointer_rtx | |
6737 && CONSTANT_P (XEXP (goal, 1))) | |
6738 goal_const = 1; | |
6739 else | |
6740 return 0; | |
6741 | |
6742 num = 0; | |
6743 /* Scan insns back from INSN, looking for one that copies | |
6744 a value into or out of GOAL. | |
6745 Stop and give up if we reach a label. */ | |
6746 | |
6747 while (1) | |
6748 { | |
6749 p = PREV_INSN (p); | |
6750 if (p && DEBUG_INSN_P (p)) | |
6751 continue; | |
6752 num++; | |
6753 if (p == 0 || LABEL_P (p) | |
6754 || num > PARAM_VALUE (PARAM_MAX_RELOAD_SEARCH_INSNS)) | |
6755 return 0; | |
6756 | |
6757 /* Don't reuse register contents from before a setjmp-type | |
6758 function call; on the second return (from the longjmp) it | |
6759 might have been clobbered by a later reuse. It doesn't | |
6760 seem worthwhile to actually go and see if it is actually | |
6761 reused even if that information would be readily available; | |
6762 just don't reuse it across the setjmp call. */ | |
6763 if (CALL_P (p) && find_reg_note (p, REG_SETJMP, NULL_RTX)) | |
6764 return 0; | |
6765 | |
6766 if (NONJUMP_INSN_P (p) | |
6767 /* If we don't want spill regs ... */ | |
6768 && (! (reload_reg_p != 0 | |
6769 && reload_reg_p != (short *) (HOST_WIDE_INT) 1) | |
6770 /* ... then ignore insns introduced by reload; they aren't | |
6771 useful and can cause results in reload_as_needed to be | |
6772 different from what they were when calculating the need for | |
6773 spills. If we notice an input-reload insn here, we will | |
6774 reject it below, but it might hide a usable equivalent. | |
6775 That makes bad code. It may even fail: perhaps no reg was | |
6776 spilled for this insn because it was assumed we would find | |
6777 that equivalent. */ | |
6778 || INSN_UID (p) < reload_first_uid)) | |
6779 { | |
6780 rtx tem; | |
6781 pat = single_set (p); | |
6782 | |
6783 /* First check for something that sets some reg equal to GOAL. */ | |
6784 if (pat != 0 | |
6785 && ((regno >= 0 | |
6786 && true_regnum (SET_SRC (pat)) == regno | |
6787 && (valueno = true_regnum (valtry = SET_DEST (pat))) >= 0) | |
6788 || | |
6789 (regno >= 0 | |
6790 && true_regnum (SET_DEST (pat)) == regno | |
6791 && (valueno = true_regnum (valtry = SET_SRC (pat))) >= 0) | |
6792 || | |
6793 (goal_const && rtx_equal_p (SET_SRC (pat), goal) | |
6794 /* When looking for stack pointer + const, | |
6795 make sure we don't use a stack adjust. */ | |
6796 && !reg_overlap_mentioned_for_reload_p (SET_DEST (pat), goal) | |
6797 && (valueno = true_regnum (valtry = SET_DEST (pat))) >= 0) | |
6798 || (goal_mem | |
6799 && (valueno = true_regnum (valtry = SET_DEST (pat))) >= 0 | |
6800 && rtx_renumbered_equal_p (goal, SET_SRC (pat))) | |
6801 || (goal_mem | |
6802 && (valueno = true_regnum (valtry = SET_SRC (pat))) >= 0 | |
6803 && rtx_renumbered_equal_p (goal, SET_DEST (pat))) | |
6804 /* If we are looking for a constant, | |
6805 and something equivalent to that constant was copied | |
6806 into a reg, we can use that reg. */ | |
6807 || (goal_const && REG_NOTES (p) != 0 | |
6808 && (tem = find_reg_note (p, REG_EQUIV, NULL_RTX)) | |
6809 && ((rtx_equal_p (XEXP (tem, 0), goal) | |
6810 && (valueno | |
6811 = true_regnum (valtry = SET_DEST (pat))) >= 0) | |
6812 || (REG_P (SET_DEST (pat)) | |
6813 && GET_CODE (XEXP (tem, 0)) == CONST_DOUBLE | |
6814 && SCALAR_FLOAT_MODE_P (GET_MODE (XEXP (tem, 0))) | |
6815 && CONST_INT_P (goal) | |
6816 && 0 != (goaltry | |
6817 = operand_subword (XEXP (tem, 0), 0, 0, | |
6818 VOIDmode)) | |
6819 && rtx_equal_p (goal, goaltry) | |
6820 && (valtry | |
6821 = operand_subword (SET_DEST (pat), 0, 0, | |
6822 VOIDmode)) | |
6823 && (valueno = true_regnum (valtry)) >= 0))) | |
6824 || (goal_const && (tem = find_reg_note (p, REG_EQUIV, | |
6825 NULL_RTX)) | |
6826 && REG_P (SET_DEST (pat)) | |
6827 && GET_CODE (XEXP (tem, 0)) == CONST_DOUBLE | |
6828 && SCALAR_FLOAT_MODE_P (GET_MODE (XEXP (tem, 0))) | |
6829 && CONST_INT_P (goal) | |
6830 && 0 != (goaltry = operand_subword (XEXP (tem, 0), 1, 0, | |
6831 VOIDmode)) | |
6832 && rtx_equal_p (goal, goaltry) | |
6833 && (valtry | |
6834 = operand_subword (SET_DEST (pat), 1, 0, VOIDmode)) | |
6835 && (valueno = true_regnum (valtry)) >= 0))) | |
6836 { | |
6837 if (other >= 0) | |
6838 { | |
6839 if (valueno != other) | |
6840 continue; | |
6841 } | |
6842 else if ((unsigned) valueno >= FIRST_PSEUDO_REGISTER) | |
6843 continue; | |
6844 else if (!in_hard_reg_set_p (reg_class_contents[(int) rclass], | |
6845 mode, valueno)) | |
6846 continue; | |
6847 value = valtry; | |
6848 where = p; | |
6849 break; | |
6850 } | |
6851 } | |
6852 } | |
6853 | |
6854 /* We found a previous insn copying GOAL into a suitable other reg VALUE | |
6855 (or copying VALUE into GOAL, if GOAL is also a register). | |
6856 Now verify that VALUE is really valid. */ | |
6857 | |
6858 /* VALUENO is the register number of VALUE; a hard register. */ | |
6859 | |
6860 /* Don't try to re-use something that is killed in this insn. We want | |
6861 to be able to trust REG_UNUSED notes. */ | |
6862 if (REG_NOTES (where) != 0 && find_reg_note (where, REG_UNUSED, value)) | |
6863 return 0; | |
6864 | |
6865 /* If we propose to get the value from the stack pointer or if GOAL is | |
6866 a MEM based on the stack pointer, we need a stable SP. */ | |
6867 if (valueno == STACK_POINTER_REGNUM || regno == STACK_POINTER_REGNUM | |
6868 || (goal_mem && reg_overlap_mentioned_for_reload_p (stack_pointer_rtx, | |
6869 goal))) | |
6870 need_stable_sp = 1; | |
6871 | |
6872 /* Reject VALUE if the copy-insn moved the wrong sort of datum. */ | |
6873 if (GET_MODE (value) != mode) | |
6874 return 0; | |
6875 | |
6876 /* Reject VALUE if it was loaded from GOAL | |
6877 and is also a register that appears in the address of GOAL. */ | |
6878 | |
6879 if (goal_mem && value == SET_DEST (single_set (where)) | |
6880 && refers_to_regno_for_reload_p (valueno, end_hard_regno (mode, valueno), | |
6881 goal, (rtx*) 0)) | |
6882 return 0; | |
6883 | |
6884 /* Reject registers that overlap GOAL. */ | |
6885 | |
6886 if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER) | |
6887 nregs = hard_regno_nregs[regno][mode]; | |
6888 else | |
6889 nregs = 1; | |
6890 valuenregs = hard_regno_nregs[valueno][mode]; | |
6891 | |
6892 if (!goal_mem && !goal_const | |
6893 && regno + nregs > valueno && regno < valueno + valuenregs) | |
6894 return 0; | |
6895 | |
6896 /* Reject VALUE if it is one of the regs reserved for reloads. | |
6897 Reload1 knows how to reuse them anyway, and it would get | |
6898 confused if we allocated one without its knowledge. | |
6899 (Now that insns introduced by reload are ignored above, | |
6900 this case shouldn't happen, but I'm not positive.) */ | |
6901 | |
6902 if (reload_reg_p != 0 && reload_reg_p != (short *) (HOST_WIDE_INT) 1) | |
6903 { | |
6904 int i; | |
6905 for (i = 0; i < valuenregs; ++i) | |
6906 if (reload_reg_p[valueno + i] >= 0) | |
6907 return 0; | |
6908 } | |
6909 | |
6910 /* Reject VALUE if it is a register being used for an input reload | |
6911 even if it is not one of those reserved. */ | |
6912 | |
6913 if (reload_reg_p != 0) | |
6914 { | |
6915 int i; | |
6916 for (i = 0; i < n_reloads; i++) | |
6917 if (rld[i].reg_rtx != 0 && rld[i].in) | |
6918 { | |
6919 int regno1 = REGNO (rld[i].reg_rtx); | |
6920 int nregs1 = hard_regno_nregs[regno1] | |
6921 [GET_MODE (rld[i].reg_rtx)]; | |
6922 if (regno1 < valueno + valuenregs | |
6923 && regno1 + nregs1 > valueno) | |
6924 return 0; | |
6925 } | |
6926 } | |
6927 | |
6928 if (goal_mem) | |
6929 /* We must treat frame pointer as varying here, | |
6930 since it can vary--in a nonlocal goto as generated by expand_goto. */ | |
6931 goal_mem_addr_varies = !CONSTANT_ADDRESS_P (XEXP (goal, 0)); | |
6932 | |
6933 /* Now verify that the values of GOAL and VALUE remain unaltered | |
6934 until INSN is reached. */ | |
6935 | |
6936 p = insn; | |
6937 while (1) | |
6938 { | |
6939 p = PREV_INSN (p); | |
6940 if (p == where) | |
6941 return value; | |
6942 | |
6943 /* Don't trust the conversion past a function call | |
6944 if either of the two is in a call-clobbered register, or memory. */ | |
6945 if (CALL_P (p)) | |
6946 { | |
6947 int i; | |
6948 | |
6949 if (goal_mem || need_stable_sp) | |
6950 return 0; | |
6951 | |
6952 if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER) | |
6953 for (i = 0; i < nregs; ++i) | |
6954 if (call_used_regs[regno + i] | |
6955 || HARD_REGNO_CALL_PART_CLOBBERED (regno + i, mode)) | |
6956 return 0; | |
6957 | |
6958 if (valueno >= 0 && valueno < FIRST_PSEUDO_REGISTER) | |
6959 for (i = 0; i < valuenregs; ++i) | |
6960 if (call_used_regs[valueno + i] | |
6961 || HARD_REGNO_CALL_PART_CLOBBERED (valueno + i, mode)) | |
6962 return 0; | |
6963 } | |
6964 | |
6965 if (INSN_P (p)) | |
6966 { | |
6967 pat = PATTERN (p); | |
6968 | |
6969 /* Watch out for unspec_volatile, and volatile asms. */ | |
6970 if (volatile_insn_p (pat)) | |
6971 return 0; | |
6972 | |
6973 /* If this insn P stores in either GOAL or VALUE, return 0. | |
6974 If GOAL is a memory ref and this insn writes memory, return 0. | |
6975 If GOAL is a memory ref and its address is not constant, | |
6976 and this insn P changes a register used in GOAL, return 0. */ | |
6977 | |
6978 if (GET_CODE (pat) == COND_EXEC) | |
6979 pat = COND_EXEC_CODE (pat); | |
6980 if (GET_CODE (pat) == SET || GET_CODE (pat) == CLOBBER) | |
6981 { | |
6982 rtx dest = SET_DEST (pat); | |
6983 while (GET_CODE (dest) == SUBREG | |
6984 || GET_CODE (dest) == ZERO_EXTRACT | |
6985 || GET_CODE (dest) == STRICT_LOW_PART) | |
6986 dest = XEXP (dest, 0); | |
6987 if (REG_P (dest)) | |
6988 { | |
6989 int xregno = REGNO (dest); | |
6990 int xnregs; | |
6991 if (REGNO (dest) < FIRST_PSEUDO_REGISTER) | |
6992 xnregs = hard_regno_nregs[xregno][GET_MODE (dest)]; | |
6993 else | |
6994 xnregs = 1; | |
6995 if (xregno < regno + nregs && xregno + xnregs > regno) | |
6996 return 0; | |
6997 if (xregno < valueno + valuenregs | |
6998 && xregno + xnregs > valueno) | |
6999 return 0; | |
7000 if (goal_mem_addr_varies | |
7001 && reg_overlap_mentioned_for_reload_p (dest, goal)) | |
7002 return 0; | |
7003 if (xregno == STACK_POINTER_REGNUM && need_stable_sp) | |
7004 return 0; | |
7005 } | |
7006 else if (goal_mem && MEM_P (dest) | |
7007 && ! push_operand (dest, GET_MODE (dest))) | |
7008 return 0; | |
7009 else if (MEM_P (dest) && regno >= FIRST_PSEUDO_REGISTER | |
7010 && reg_equiv_memory_loc (regno) != 0) | |
7011 return 0; | |
7012 else if (need_stable_sp && push_operand (dest, GET_MODE (dest))) | |
7013 return 0; | |
7014 } | |
7015 else if (GET_CODE (pat) == PARALLEL) | |
7016 { | |
7017 int i; | |
7018 for (i = XVECLEN (pat, 0) - 1; i >= 0; i--) | |
7019 { | |
7020 rtx v1 = XVECEXP (pat, 0, i); | |
7021 if (GET_CODE (v1) == COND_EXEC) | |
7022 v1 = COND_EXEC_CODE (v1); | |
7023 if (GET_CODE (v1) == SET || GET_CODE (v1) == CLOBBER) | |
7024 { | |
7025 rtx dest = SET_DEST (v1); | |
7026 while (GET_CODE (dest) == SUBREG | |
7027 || GET_CODE (dest) == ZERO_EXTRACT | |
7028 || GET_CODE (dest) == STRICT_LOW_PART) | |
7029 dest = XEXP (dest, 0); | |
7030 if (REG_P (dest)) | |
7031 { | |
7032 int xregno = REGNO (dest); | |
7033 int xnregs; | |
7034 if (REGNO (dest) < FIRST_PSEUDO_REGISTER) | |
7035 xnregs = hard_regno_nregs[xregno][GET_MODE (dest)]; | |
7036 else | |
7037 xnregs = 1; | |
7038 if (xregno < regno + nregs | |
7039 && xregno + xnregs > regno) | |
7040 return 0; | |
7041 if (xregno < valueno + valuenregs | |
7042 && xregno + xnregs > valueno) | |
7043 return 0; | |
7044 if (goal_mem_addr_varies | |
7045 && reg_overlap_mentioned_for_reload_p (dest, | |
7046 goal)) | |
7047 return 0; | |
7048 if (xregno == STACK_POINTER_REGNUM && need_stable_sp) | |
7049 return 0; | |
7050 } | |
7051 else if (goal_mem && MEM_P (dest) | |
7052 && ! push_operand (dest, GET_MODE (dest))) | |
7053 return 0; | |
7054 else if (MEM_P (dest) && regno >= FIRST_PSEUDO_REGISTER | |
7055 && reg_equiv_memory_loc (regno) != 0) | |
7056 return 0; | |
7057 else if (need_stable_sp | |
7058 && push_operand (dest, GET_MODE (dest))) | |
7059 return 0; | |
7060 } | |
7061 } | |
7062 } | |
7063 | |
7064 if (CALL_P (p) && CALL_INSN_FUNCTION_USAGE (p)) | |
7065 { | |
7066 rtx link; | |
7067 | |
7068 for (link = CALL_INSN_FUNCTION_USAGE (p); XEXP (link, 1) != 0; | |
7069 link = XEXP (link, 1)) | |
7070 { | |
7071 pat = XEXP (link, 0); | |
7072 if (GET_CODE (pat) == CLOBBER) | |
7073 { | |
7074 rtx dest = SET_DEST (pat); | |
7075 | |
7076 if (REG_P (dest)) | |
7077 { | |
7078 int xregno = REGNO (dest); | |
7079 int xnregs | |
7080 = hard_regno_nregs[xregno][GET_MODE (dest)]; | |
7081 | |
7082 if (xregno < regno + nregs | |
7083 && xregno + xnregs > regno) | |
7084 return 0; | |
7085 else if (xregno < valueno + valuenregs | |
7086 && xregno + xnregs > valueno) | |
7087 return 0; | |
7088 else if (goal_mem_addr_varies | |
7089 && reg_overlap_mentioned_for_reload_p (dest, | |
7090 goal)) | |
7091 return 0; | |
7092 } | |
7093 | |
7094 else if (goal_mem && MEM_P (dest) | |
7095 && ! push_operand (dest, GET_MODE (dest))) | |
7096 return 0; | |
7097 else if (need_stable_sp | |
7098 && push_operand (dest, GET_MODE (dest))) | |
7099 return 0; | |
7100 } | |
7101 } | |
7102 } | |
7103 | |
7104 #ifdef AUTO_INC_DEC | |
7105 /* If this insn auto-increments or auto-decrements | |
7106 either regno or valueno, return 0 now. | |
7107 If GOAL is a memory ref and its address is not constant, | |
7108 and this insn P increments a register used in GOAL, return 0. */ | |
7109 { | |
7110 rtx link; | |
7111 | |
7112 for (link = REG_NOTES (p); link; link = XEXP (link, 1)) | |
7113 if (REG_NOTE_KIND (link) == REG_INC | |
7114 && REG_P (XEXP (link, 0))) | |
7115 { | |
7116 int incno = REGNO (XEXP (link, 0)); | |
7117 if (incno < regno + nregs && incno >= regno) | |
7118 return 0; | |
7119 if (incno < valueno + valuenregs && incno >= valueno) | |
7120 return 0; | |
7121 if (goal_mem_addr_varies | |
7122 && reg_overlap_mentioned_for_reload_p (XEXP (link, 0), | |
7123 goal)) | |
7124 return 0; | |
7125 } | |
7126 } | |
7127 #endif | |
7128 } | |
7129 } | |
7130 } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment