📄 rs6000.c
字号:
{ long l; REAL_VALUE_TYPE rv; REAL_VALUE_FROM_CONST_DOUBLE (rv, op); REAL_VALUE_TO_TARGET_SINGLE (rv, l); return num_insns_constant_wide (l) == 1; } else if (mode == DImode) return ((TARGET_POWERPC64 && GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_LOW (op) == 0) || (num_insns_constant (op, DImode) <= 2)); else if (mode == SImode) return 1; else abort ();}/* Return 1 if the operand is a CONST_INT and can be put into a register with one instruction. */static inteasy_vector_constant (op) rtx op;{ rtx elt; int units, i; if (GET_CODE (op) != CONST_VECTOR) return 0; units = CONST_VECTOR_NUNITS (op); /* We can generate 0 easily. Look for that. */ for (i = 0; i < units; ++i) { elt = CONST_VECTOR_ELT (op, i); /* We could probably simplify this by just checking for equality with CONST0_RTX for the current mode, but let's be safe instead. */ switch (GET_CODE (elt)) { case CONST_INT: if (INTVAL (elt) != 0) return 0; break; case CONST_DOUBLE: if (CONST_DOUBLE_LOW (elt) != 0 || CONST_DOUBLE_HIGH (elt) != 0) return 0; break; default: return 0; } } /* We could probably generate a few other constants trivially, but gcc doesn't generate them yet. FIXME later. */ return 1;}/* Return 1 if the operand is the constant 0. This works for scalars as well as vectors. */intzero_constant (op, mode) rtx op; enum machine_mode mode;{ return op == CONST0_RTX (mode);}/* Return 1 if the operand is 0.0. */intzero_fp_constant (op, mode) rtx op; enum machine_mode mode;{ return GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode);}/* Return 1 if the operand is in volatile memory. Note that during the RTL generation phase, memory_operand does not return TRUE for volatile memory references. So this function allows us to recognize volatile references where its safe. */intvolatile_mem_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) != MEM) return 0; if (!MEM_VOLATILE_P (op)) return 0; if (mode != GET_MODE (op)) return 0; if (reload_completed) return memory_operand (op, mode); if (reload_in_progress) return strict_memory_address_p (mode, XEXP (op, 0)); return memory_address_p (mode, XEXP (op, 0));}/* Return 1 if the operand is an offsettable memory operand. */intoffsettable_mem_operand (op, mode) rtx op; enum machine_mode mode;{ return ((GET_CODE (op) == MEM) && offsettable_address_p (reload_completed || reload_in_progress, mode, XEXP (op, 0)));}/* Return 1 if the operand is either an easy FP constant (see above) or memory. */intmem_or_easy_const_operand (op, mode) rtx op; enum machine_mode mode;{ return memory_operand (op, mode) || easy_fp_constant (op, mode);}/* Return 1 if the operand is either a non-special register or an item that can be used as the operand of a `mode' add insn. */intadd_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT) return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'I') || CONST_OK_FOR_LETTER_P (INTVAL (op), 'L')); return gpc_reg_operand (op, mode);}/* Return 1 if OP is a constant but not a valid add_operand. */intnon_add_cint_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return (GET_CODE (op) == CONST_INT && !CONST_OK_FOR_LETTER_P (INTVAL (op), 'I') && !CONST_OK_FOR_LETTER_P (INTVAL (op), 'L'));}/* Return 1 if the operand is a non-special register or a constant that can be used as the operand of an OR or XOR insn on the RS/6000. */intlogical_operand (op, mode) rtx op; enum machine_mode mode;{ HOST_WIDE_INT opl, oph; if (gpc_reg_operand (op, mode)) return 1; if (GET_CODE (op) == CONST_INT) { opl = INTVAL (op) & GET_MODE_MASK (mode);#if HOST_BITS_PER_WIDE_INT <= 32 if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT && opl < 0) return 0;#endif } else if (GET_CODE (op) == CONST_DOUBLE) { if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) abort (); opl = CONST_DOUBLE_LOW (op); oph = CONST_DOUBLE_HIGH (op); if (oph != 0) return 0; } else return 0; return ((opl & ~ (unsigned HOST_WIDE_INT) 0xffff) == 0 || (opl & ~ (unsigned HOST_WIDE_INT) 0xffff0000) == 0);}/* Return 1 if C is a constant that is not a logical operand (as above), but could be split into one. */intnon_logical_cint_operand (op, mode) rtx op; enum machine_mode mode;{ return ((GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE) && ! logical_operand (op, mode) && reg_or_logical_cint_operand (op, mode));}/* Return 1 if C is a constant that can be encoded in a 32-bit mask on the RS/6000. It is if there are no more than two 1->0 or 0->1 transitions. Reject all ones and all zeros, since these should have been optimized away and confuse the making of MB and ME. */intmask_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ HOST_WIDE_INT c, lsb; if (GET_CODE (op) != CONST_INT) return 0; c = INTVAL (op); /* Fail in 64-bit mode if the mask wraps around because the upper 32-bits of the mask will all be 1s, contrary to GCC's internal view. */ if (TARGET_POWERPC64 && (c & 0x80000001) == 0x80000001) return 0; /* We don't change the number of transitions by inverting, so make sure we start with the LS bit zero. */ if (c & 1) c = ~c; /* Reject all zeros or all ones. */ if (c == 0) return 0; /* Find the first transition. */ lsb = c & -c; /* Invert to look for a second transition. */ c = ~c; /* Erase first transition. */ c &= -lsb; /* Find the second transition (if any). */ lsb = c & -c; /* Match if all the bits above are 1's (or c is zero). */ return c == -lsb;}/* Return 1 for the PowerPC64 rlwinm corner case. */intmask_operand_wrap (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ HOST_WIDE_INT c, lsb; if (GET_CODE (op) != CONST_INT) return 0; c = INTVAL (op); if ((c & 0x80000001) != 0x80000001) return 0; c = ~c; if (c == 0) return 0; lsb = c & -c; c = ~c; c &= -lsb; lsb = c & -c; return c == -lsb;}/* Return 1 if the operand is a constant that is a PowerPC64 mask. It is if there are no more than one 1->0 or 0->1 transitions. Reject all zeros, since zero should have been optimized away and confuses the making of MB and ME. */intmask64_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ if (GET_CODE (op) == CONST_INT) { HOST_WIDE_INT c, lsb; c = INTVAL (op); /* Reject all zeros. */ if (c == 0) return 0; /* We don't change the number of transitions by inverting, so make sure we start with the LS bit zero. */ if (c & 1) c = ~c; /* Find the transition, and check that all bits above are 1's. */ lsb = c & -c; return c == -lsb; } return 0;}/* Like mask64_operand, but allow up to three transitions. This predicate is used by insn patterns that generate two rldicl or rldicr machine insns. */intmask64_2_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ if (GET_CODE (op) == CONST_INT) { HOST_WIDE_INT c, lsb; c = INTVAL (op); /* Disallow all zeros. */ if (c == 0) return 0; /* We don't change the number of transitions by inverting, so make sure we start with the LS bit zero. */ if (c & 1) c = ~c; /* Find the first transition. */ lsb = c & -c; /* Invert to look for a second transition. */ c = ~c; /* Erase first transition. */ c &= -lsb; /* Find the second transition. */ lsb = c & -c; /* Invert to look for a third transition. */ c = ~c; /* Erase second transition. */ c &= -lsb; /* Find the third transition (if any). */ lsb = c & -c; /* Match if all the bits above are 1's (or c is zero). */ return c == -lsb; } return 0;}/* Generates shifts and masks for a pair of rldicl or rldicr insns to implement ANDing by the mask IN. */voidbuild_mask64_2_operands (in, out) rtx in; rtx *out;{#if HOST_BITS_PER_WIDE_INT >= 64 unsigned HOST_WIDE_INT c, lsb, m1, m2; int shift; if (GET_CODE (in) != CONST_INT) abort (); c = INTVAL (in); if (c & 1) { /* Assume c initially something like 0x00fff000000fffff. The idea is to rotate the word so that the middle ^^^^^^ group of zeros is at the MS end and can be cleared with an rldicl mask. We then rotate back and clear off the MS ^^ group of zeros with a second rldicl. */ c = ~c; /* c == 0xff000ffffff00000 */ lsb = c & -c; /* lsb == 0x0000000000100000 */ m1 = -lsb; /* m1 == 0xfffffffffff00000 */ c = ~c; /* c == 0x00fff000000fffff */ c &= -lsb; /* c == 0x00fff00000000000 */ lsb = c & -c; /* lsb == 0x0000100000000000 */ c = ~c; /* c == 0xff000fffffffffff */ c &= -lsb; /* c == 0xff00000000000000 */ shift = 0; while ((lsb >>= 1) != 0) shift++; /* shift == 44 on exit from loop */ m1 <<= 64 - shift; /* m1 == 0xffffff0000000000 */ m1 = ~m1; /* m1 == 0x000000ffffffffff */ m2 = ~c; /* m2 == 0x00ffffffffffffff */ } else { /* Assume c initially something like 0xff000f0000000000. The idea is to rotate the word so that the ^^^ middle group of zeros is at the LS end and can be cleared with an rldicr mask. We then rotate back and clear off the LS group of ^^^^^^^^^^ zeros with a second rldicr. */ lsb = c & -c; /* lsb == 0x0000010000000000 */ m2 = -lsb; /* m2 == 0xffffff0000000000 */ c = ~c; /* c == 0x00fff0ffffffffff */ c &= -lsb; /* c == 0x00fff00000000000 */ lsb = c & -c; /* lsb == 0x0000100000000000 */ c = ~c; /* c == 0xff000fffffffffff */ c &= -lsb; /* c == 0xff00000000000000 */ shift = 0; while ((lsb >>= 1) != 0) shift++; /* shift == 44 on exit from loop */ m1 = ~c; /* m1 == 0x00ffffffffffffff */ m1 >>= shift; /* m1 == 0x0000000000000fff */ m1 = ~m1; /* m1 == 0xfffffffffffff000 */ } /* Note that when we only have two 0->1 and 1->0 transitions, one of the masks will be all 1's. We are guaranteed more than one transition. */ out[0] = GEN_INT (64 - shift); out[1] = GEN_INT (m1); out[2] = GEN_INT (shift); out[3] = GEN_INT (m2);#else (void)in; (void)out; abort ();#endif}/* Return 1 if the operand is either a non-special register or a constant that can be used as the operand of a PowerPC64 logical AND insn. */intand64_operand (op, mode) rtx op; enum machine_mode mode;{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -