Skip to content

Instantly share code, notes, and snippets.

@nicholaslemay
Created July 26, 2012 11:46
Show Gist options
  • Save nicholaslemay/3181611 to your computer and use it in GitHub Desktop.
Save nicholaslemay/3181611 to your computer and use it in GitHub Desktop.
Holy cyclomatic complexity Batman !
/* 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