📄 sparc.c
字号:
* or %reg, %lo(high_bits), %reg * sllx %reg, 32, %reg */ if (low_bits == 0) { sparc_emit_set_const64_quick2 (op0, temp, high_bits, 0, 32); return; } /* We may be able to do something quick when the constant is negated, so try that. */ if (const64_is_2insns ((~high_bits) & 0xffffffff, (~low_bits) & 0xfffffc00)) { /* NOTE: The trailing bits get XOR'd so we need the non-negated bits, not the negated ones. */ unsigned HOST_WIDE_INT trailing_bits = low_bits & 0x3ff; if ((((~high_bits) & 0xffffffff) == 0 && ((~low_bits) & 0x80000000) == 0) || (((~high_bits) & 0xffffffff) == 0xffffffff && ((~low_bits) & 0x80000000) != 0)) { int fast_int = (~low_bits & 0xffffffff); if ((SPARC_SETHI_P (fast_int) && (~high_bits & 0xffffffff) == 0) || SPARC_SIMM13_P (fast_int)) emit_insn (gen_safe_SET64 (temp, fast_int)); else sparc_emit_set_const64 (temp, GEN_INT64 (fast_int)); } else { rtx negated_const;#if HOST_BITS_PER_WIDE_INT == 64 negated_const = GEN_INT (((~low_bits) & 0xfffffc00) | (((HOST_WIDE_INT)((~high_bits) & 0xffffffff))<<32));#else negated_const = gen_rtx_CONST_DOUBLE (DImode, const0_rtx, (~low_bits) & 0xfffffc00, (~high_bits) & 0xffffffff);#endif sparc_emit_set_const64 (temp, negated_const); } /* If we are XOR'ing with -1, then we should emit a one's complement instead. This way the combiner will notice logical operations such as ANDN later on and substitute. */ if (trailing_bits == 0x3ff) { emit_insn (gen_rtx_SET (VOIDmode, op0, gen_rtx_NOT (DImode, temp))); } else { emit_insn (gen_rtx_SET (VOIDmode, op0, gen_safe_XOR64 (temp, (-0x400 | trailing_bits)))); } return; } /* 1) sethi %hi(xxx), %reg * or %reg, %lo(xxx), %reg * sllx %reg, yyy, %reg * * ??? This is just a generalized version of the low_bits==0 * thing above, FIXME... */ if ((highest_bit_set - lowest_bit_set) < 32) { unsigned HOST_WIDE_INT focus_bits = create_simple_focus_bits (high_bits, low_bits, lowest_bit_set, 0); /* We can't get here in this state. */ if (highest_bit_set < 32 || lowest_bit_set >= 32) abort (); /* So what we know is that the set bits straddle the middle of the 64-bit word. */ sparc_emit_set_const64_quick2 (op0, temp, focus_bits, 0, lowest_bit_set); return; } /* 1) sethi %hi(high_bits), %reg * or %reg, %lo(high_bits), %reg * sllx %reg, 32, %reg * or %reg, low_bits, %reg */ if (SPARC_SIMM13_P(low_bits) && ((int)low_bits > 0)) { sparc_emit_set_const64_quick2 (op0, temp, high_bits, low_bits, 32); return; } /* The easiest way when all else fails, is full decomposition. */#if 0 printf ("sparc_emit_set_const64: Hard constant [%08lx%08lx] neg[%08lx%08lx]\n", high_bits, low_bits, ~high_bits, ~low_bits);#endif sparc_emit_set_const64_longway (op0, temp, high_bits, low_bits);}/* X and Y are two things to compare using CODE. Emit the compare insn and return the rtx for the cc reg in the proper mode. */rtxgen_compare_reg (code, x, y) enum rtx_code code; rtx x, y;{ enum machine_mode mode = SELECT_CC_MODE (code, x, y); rtx cc_reg; /* ??? We don't have movcc patterns so we cannot generate pseudo regs for the fcc regs (cse can't tell they're really call clobbered regs and will remove a duplicate comparison even if there is an intervening function call - it will then try to reload the cc reg via an int reg which is why we need the movcc patterns). It is possible to provide the movcc patterns by using the ldxfsr/stxfsr v9 insns. I tried it: you need two registers (say %g1,%g5) and it takes about 6 insns. A better fix would be to tell cse that CCFPE mode registers (even pseudos) are call clobbered. */ /* ??? This is an experiment. Rather than making changes to cse which may or may not be easy/clean, we do our own cse. This is possible because we will generate hard registers. Cse knows they're call clobbered (it doesn't know the same thing about pseudos). If we guess wrong, no big deal, but if we win, great! */ if (TARGET_V9 && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)#if 1 /* experiment */ { int reg; /* We cycle through the registers to ensure they're all exercised. */ static int next_fcc_reg = 0; /* Previous x,y for each fcc reg. */ static rtx prev_args[4][2]; /* Scan prev_args for x,y. */ for (reg = 0; reg < 4; reg++) if (prev_args[reg][0] == x && prev_args[reg][1] == y) break; if (reg == 4) { reg = next_fcc_reg; prev_args[reg][0] = x; prev_args[reg][1] = y; next_fcc_reg = (next_fcc_reg + 1) & 3; } cc_reg = gen_rtx_REG (mode, reg + SPARC_FIRST_V9_FCC_REG); }#else cc_reg = gen_reg_rtx (mode);#endif /* ! experiment */ else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) cc_reg = gen_rtx_REG (mode, SPARC_FCC_REG); else cc_reg = gen_rtx_REG (mode, SPARC_ICC_REG); emit_insn (gen_rtx_SET (VOIDmode, cc_reg, gen_rtx_COMPARE (mode, x, y))); return cc_reg;}/* This function is used for v9 only. CODE is the code for an Scc's comparison. OPERANDS[0] is the target of the Scc insn. OPERANDS[1] is the value we compare against const0_rtx (which hasn't been generated yet). This function is needed to turn (set (reg:SI 110) (gt (reg:CCX 100 %icc) (const_int 0))) into (set (reg:SI 110) (gt:DI (reg:CCX 100 %icc) (const_int 0))) IE: The instruction recognizer needs to see the mode of the comparison to find the right instruction. We could use "gt:DI" right in the define_expand, but leaving it out allows us to handle DI, SI, etc. We refer to the global sparc compare operands sparc_compare_op0 and sparc_compare_op1. */intgen_v9_scc (compare_code, operands) enum rtx_code compare_code; register rtx *operands;{ rtx temp, op0, op1; if (! TARGET_ARCH64 && (GET_MODE (sparc_compare_op0) == DImode || GET_MODE (operands[0]) == DImode)) return 0; /* Handle the case where operands[0] == sparc_compare_op0. We "early clobber" the result. */ if (REGNO (operands[0]) == REGNO (sparc_compare_op0)) { op0 = gen_reg_rtx (GET_MODE (sparc_compare_op0)); emit_move_insn (op0, sparc_compare_op0); } else op0 = sparc_compare_op0; /* For consistency in the following. */ op1 = sparc_compare_op1; /* Try to use the movrCC insns. */ if (TARGET_ARCH64 && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT && op1 == const0_rtx && v9_regcmp_p (compare_code)) { /* Special case for op0 != 0. This can be done with one instruction if operands[0] == sparc_compare_op0. We don't assume they are equal now though. */ if (compare_code == NE && GET_MODE (operands[0]) == DImode && GET_MODE (op0) == DImode) { emit_insn (gen_rtx_SET (VOIDmode, operands[0], op0)); emit_insn (gen_rtx_SET (VOIDmode, operands[0], gen_rtx_IF_THEN_ELSE (DImode, gen_rtx_fmt_ee (compare_code, DImode, op0, const0_rtx), const1_rtx, operands[0]))); return 1; } emit_insn (gen_rtx_SET (VOIDmode, operands[0], const0_rtx)); if (GET_MODE (op0) != DImode) { temp = gen_reg_rtx (DImode); convert_move (temp, op0, 0); } else temp = op0; emit_insn (gen_rtx_SET (VOIDmode, operands[0], gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]), gen_rtx_fmt_ee (compare_code, DImode, temp, const0_rtx), const1_rtx, operands[0]))); return 1; } else { operands[1] = gen_compare_reg (compare_code, op0, op1); switch (GET_MODE (operands[1])) { case CCmode : case CCXmode : case CCFPEmode : case CCFPmode : break; default : abort (); } emit_insn (gen_rtx_SET (VOIDmode, operands[0], const0_rtx)); emit_insn (gen_rtx_SET (VOIDmode, operands[0], gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]), gen_rtx_fmt_ee (compare_code, GET_MODE (operands[1]), operands[1], const0_rtx), const1_rtx, operands[0]))); return 1; }}/* Emit a conditional jump insn for the v9 architecture using comparison code CODE and jump target LABEL. This function exists to take advantage of the v9 brxx insns. */voidemit_v9_brxx_insn (code, op0, label) enum rtx_code code; rtx op0, label;{ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, gen_rtx_IF_THEN_ELSE (VOIDmode, gen_rtx_fmt_ee (code, GET_MODE (op0), op0, const0_rtx), gen_rtx_LABEL_REF (VOIDmode, label), pc_rtx)));}/* Return nonzero if a return peephole merging return with setting of output register is ok. */intleaf_return_peephole_ok (){ return (actual_fsize == 0);}/* Return nonzero if TRIAL can go into the function epilogue's delay slot. SLOT is the slot we are trying to fill. */inteligible_for_epilogue_delay (trial, slot) rtx trial; int slot;{ rtx pat, src; if (slot >= 1) return 0; if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET) return 0; if (get_attr_length (trial) != 1) return 0; /* If %g0 is live, there are lots of things we can't handle. Rather than trying to find them all now, let's punt and only optimize things as necessary. */ if (TARGET_LIVE_G0) return 0; /* In the case of a true leaf function, anything can go into the delay slot. A delay slot only exists however if the frame size is zero, otherwise we will put an insn to adjust the stack after the return. */ if (current_function_uses_only_leaf_regs) { if (leaf_return_peephole_ok ()) return ((get_attr_in_uncond_branch_delay (trial) == IN_BRANCH_DELAY_TRUE)); return 0; } /* If only trivial `restore' insns work, nothing can go in the delay slot. */ else if (TARGET_BROKEN_SAVERESTORE) return 0; pat = PATTERN (trial); /* Otherwise, only operations which can be done in tandem with a `restore' insn can go into the delay slot. */ if (GET_CODE (SET_DEST (pat)) != REG || REGNO (SET_DEST (pat)) >= 32 || REGNO (SET_DEST (pat)) < 24) return 0; /* The set of insns matched here must agree precisely with the set of patterns paired with a RETURN in sparc.md. */ src = SET_SRC (pat); /* This matches "*return_[qhs]i" or even "*return_di" on TARGET_ARCH64. */ if (arith_operand (src, GET_MODE (src))) { if (TARGET_ARCH64) return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode); else return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode); } /* This matches "*return_di". */ else if (arith_double_operand (src, GET_MODE (src))) return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode); /* This matches "*return_sf_no_fpu". */ else if (! TARGET_FPU && restore_operand (SET_DEST (pat), SFmode) && register_operand (src, SFmode)) return 1; /* This matches "*return_addsi". */ else if (GET_CODE (src) == PLUS && arith_operand (XEXP (src, 0), SImode) && arith_operand (XEXP (src, 1), SImode) && (register_operand (XEXP (src, 0), SImode) || register_operand (XEXP (src, 1), SImode))) return 1; /* This matches "*return_adddi". */ else if (GET_CODE (src) == PLUS && arith_double_operand (XEXP (src, 0), DImode) && arith_double_operand (XEXP (src, 1), DImode) && (register_operand (XEXP (src, 0), DImode) || register_operand (XEXP (src, 1), DImode))) return 1; return 0;}static intcheck_return_regs (x) rtx x;{ switch (GET_CODE (x)) { case REG: return IN_OR_GLOBAL_P (x); case CONST_INT: case CONST_DOUBLE: case CONST: case SYMBOL_REF: case LABEL_REF: return 1; case SET: case IOR: case AND: case XOR: case PLUS: case MINUS: if (check_return_regs (XEXP (x, 1)) == 0) return 0; case NOT: case NEG: case MEM: return check_return_regs (XEXP (x, 0)); default: return 0; }}/* Return 1 if TRIAL references only in and global registers. */inteligible_for_return_delay (trial) rtx trial;{ if (GET_CODE (PATTERN (trial)) != SET) return 0; return check_return_regs (PATTERN (trial));}intshort_branch (uid1, uid2) int uid1, uid2;{ unsigned int delta = insn_addresses[uid1] - insn_addresses[uid2]; if (delta + 1024 < 2048) return 1; /* warning ("long branch, distance %d", delta); */ return 0;}/* Return non-zero if REG is not used after INSN. We assume REG is a reload reg, and therefore does not live past labels or calls or jumps. */intreg_unused_after (reg, insn) rtx reg; rtx insn;{ enum rtx_code code, prev_code = UNKNOWN; while ((insn = NEXT_INSN (insn))) { if (prev_code == CALL_INSN && call_used_regs[REGNO (r
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -