⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 s390.c

📁 Mac OS X 10.4.9 for x86 Source Code gcc 实现源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
{  int i;  /* s390_tm_ccmode returns VOIDmode to indicate failure.  */  if (req_mode == VOIDmode)    return 0;  if (GET_CODE (PATTERN (insn)) == SET)    return s390_match_ccmode_set (PATTERN (insn), req_mode);  if (GET_CODE (PATTERN (insn)) == PARALLEL)      for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)        {          rtx set = XVECEXP (PATTERN (insn), 0, i);          if (GET_CODE (set) == SET)            if (!s390_match_ccmode_set (set, req_mode))              return 0;        }  return 1;}/* If a test-under-mask instruction can be used to implement   (compare (and ... OP1) OP2), return the CC mode required   to do that.  Otherwise, return VOIDmode.   MIXED is true if the instruction can distinguish between   CC1 and CC2 for mixed selected bits (TMxx), it is false   if the instruction cannot (TM).  */enum machine_modes390_tm_ccmode (rtx op1, rtx op2, int mixed){  int bit0, bit1;  /* ??? Fixme: should work on CONST_DOUBLE as well.  */  if (GET_CODE (op1) != CONST_INT || GET_CODE (op2) != CONST_INT)    return VOIDmode;  /* Selected bits all zero: CC0.     e.g.: int a; if ((a & (16 + 128)) == 0) */  if (INTVAL (op2) == 0)    return CCTmode;  /* Selected bits all one: CC3.      e.g.: int a; if ((a & (16 + 128)) == 16 + 128) */  if (INTVAL (op2) == INTVAL (op1))    return CCT3mode;  /* Exactly two bits selected, mixed zeroes and ones: CC1 or CC2. e.g.:     int a;     if ((a & (16 + 128)) == 16)         -> CCT1     if ((a & (16 + 128)) == 128)        -> CCT2  */  if (mixed)    {      bit1 = exact_log2 (INTVAL (op2));      bit0 = exact_log2 (INTVAL (op1) ^ INTVAL (op2));      if (bit0 != -1 && bit1 != -1)        return bit0 > bit1 ? CCT1mode : CCT2mode;    }  return VOIDmode;}/* Given a comparison code OP (EQ, NE, etc.) and the operands   OP0 and OP1 of a COMPARE, return the mode to be used for the   comparison.  */enum machine_modes390_select_ccmode (enum rtx_code code, rtx op0, rtx op1){  switch (code)    {      case EQ:      case NE:	if ((GET_CODE (op0) == NEG || GET_CODE (op0) == ABS)	    && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT)	  return CCAPmode;	if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 1)) == CONST_INT	    && CONST_OK_FOR_CONSTRAINT_P (INTVAL (XEXP (op0, 1)), 'K', "K"))	  return CCAPmode;	if ((GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS	     || GET_CODE (op1) == NEG)	    && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT)	  return CCLmode;	if (GET_CODE (op0) == AND)	  {	    /* Check whether we can potentially do it via TM.  */	    enum machine_mode ccmode;	    ccmode = s390_tm_ccmode (XEXP (op0, 1), op1, 1);	    if (ccmode != VOIDmode)	      {		/* Relax CCTmode to CCZmode to allow fall-back to AND		   if that turns out to be beneficial.  */	        return ccmode == CCTmode ? CCZmode : ccmode;	      }	  }	if (register_operand (op0, HImode)	    && GET_CODE (op1) == CONST_INT	    && (INTVAL (op1) == -1 || INTVAL (op1) == 65535))	  return CCT3mode;	if (register_operand (op0, QImode)	    && GET_CODE (op1) == CONST_INT	    && (INTVAL (op1) == -1 || INTVAL (op1) == 255))	  return CCT3mode;	return CCZmode;      case LE:      case LT:      case GE:      case GT:	/* The only overflow condition of NEG and ABS happens when	   -INT_MAX is used as parameter, which stays negative. So	   we have an overflow from a positive value to a negative. 	   Using CCAP mode the resulting cc can be used for comparisons.  */	if ((GET_CODE (op0) == NEG || GET_CODE (op0) == ABS)	    && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT)	  return CCAPmode; 	/* If constants are involved in an add instruction it is possible to use 	   the resulting cc for comparisons with zero. Knowing the sign of the	   constant the overflow behavior gets predictable. e.g.: 	     int a, b; if ((b = a + c) > 0)   	   with c as a constant value: c < 0 -> CCAN and c >= 0 -> CCAP  */	if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 1)) == CONST_INT	    && CONST_OK_FOR_CONSTRAINT_P (INTVAL (XEXP (op0, 1)), 'K', "K"))	  {	    if (INTVAL (XEXP((op0), 1)) < 0)	      return CCANmode;	    else	      return CCAPmode;	  }	/* Fall through.  */      case UNORDERED:      case ORDERED:      case UNEQ:      case UNLE:      case UNLT:      case UNGE:      case UNGT:      case LTGT:	if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op0) == ZERO_EXTEND)	    && GET_CODE (op1) != CONST_INT)	  return CCSRmode;	return CCSmode;      case LTU:      case GEU:	if (GET_CODE (op0) == PLUS	    && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT)	  return CCL1mode;	if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op0) == ZERO_EXTEND)	    && GET_CODE (op1) != CONST_INT)	  return CCURmode;	return CCUmode;      case LEU:      case GTU:	if (GET_CODE (op0) == MINUS	    && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT)	  return CCL2mode;	if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op0) == ZERO_EXTEND)	    && GET_CODE (op1) != CONST_INT)	  return CCURmode;	return CCUmode;      default:	abort ();    }}/* Replace the comparison OP0 CODE OP1 by a semantically equivalent one   that we can implement more efficiently.  */voids390_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1){  /* Convert ZERO_EXTRACT back to AND to enable TM patterns.  */  if ((*code == EQ || *code == NE)      && *op1 == const0_rtx      && GET_CODE (*op0) == ZERO_EXTRACT      && GET_CODE (XEXP (*op0, 1)) == CONST_INT      && GET_CODE (XEXP (*op0, 2)) == CONST_INT      && SCALAR_INT_MODE_P (GET_MODE (XEXP (*op0, 0))))    {      rtx inner = XEXP (*op0, 0);      HOST_WIDE_INT modesize = GET_MODE_BITSIZE (GET_MODE (inner));      HOST_WIDE_INT len = INTVAL (XEXP (*op0, 1));      HOST_WIDE_INT pos = INTVAL (XEXP (*op0, 2));      if (len > 0 && len < modesize	  && pos >= 0 && pos + len <= modesize	  && modesize <= HOST_BITS_PER_WIDE_INT)	{	  unsigned HOST_WIDE_INT block;	  block = ((unsigned HOST_WIDE_INT) 1 << len) - 1;	  block <<= modesize - pos - len;	  *op0 = gen_rtx_AND (GET_MODE (inner), inner,			      gen_int_mode (block, GET_MODE (inner)));	}    }  /* Narrow AND of memory against immediate to enable TM.  */  if ((*code == EQ || *code == NE)      && *op1 == const0_rtx      && GET_CODE (*op0) == AND      && GET_CODE (XEXP (*op0, 1)) == CONST_INT      && SCALAR_INT_MODE_P (GET_MODE (XEXP (*op0, 0))))    {      rtx inner = XEXP (*op0, 0);      rtx mask = XEXP (*op0, 1);      /* Ignore paradoxical SUBREGs if all extra bits are masked out.  */      if (GET_CODE (inner) == SUBREG	  && SCALAR_INT_MODE_P (GET_MODE (SUBREG_REG (inner)))	  && (GET_MODE_SIZE (GET_MODE (inner))	      >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (inner))))	  && ((INTVAL (mask)               & GET_MODE_MASK (GET_MODE (inner))               & ~GET_MODE_MASK (GET_MODE (SUBREG_REG (inner))))	      == 0))	inner = SUBREG_REG (inner);      /* Do not change volatile MEMs.  */      if (MEM_P (inner) && !MEM_VOLATILE_P (inner))	{	  int part = s390_single_part (XEXP (*op0, 1),				       GET_MODE (inner), QImode, 0);	  if (part >= 0)	    {	      mask = gen_int_mode (s390_extract_part (mask, QImode, 0), QImode);	      inner = adjust_address_nv (inner, QImode, part);	      *op0 = gen_rtx_AND (QImode, inner, mask);	    }	}    }  /* Narrow comparisons against 0xffff to HImode if possible.  */  if ((*code == EQ || *code == NE)      && GET_CODE (*op1) == CONST_INT      && INTVAL (*op1) == 0xffff      && SCALAR_INT_MODE_P (GET_MODE (*op0))      && (nonzero_bits (*op0, GET_MODE (*op0)) 	  & ~(unsigned HOST_WIDE_INT) 0xffff) == 0)    {      *op0 = gen_lowpart (HImode, *op0);      *op1 = constm1_rtx;    }  /* Remove redundant UNSPEC_CMPINT conversions if possible.  */  if (GET_CODE (*op0) == UNSPEC      && XINT (*op0, 1) == UNSPEC_CMPINT      && XVECLEN (*op0, 0) == 1      && GET_MODE (XVECEXP (*op0, 0, 0)) == CCUmode      && GET_CODE (XVECEXP (*op0, 0, 0)) == REG      && REGNO (XVECEXP (*op0, 0, 0)) == CC_REGNUM      && *op1 == const0_rtx)    {      enum rtx_code new_code = UNKNOWN;      switch (*code)	{	  case EQ: new_code = EQ;  break;	  case NE: new_code = NE;  break;	  case LT: new_code = GTU; break;	  case GT: new_code = LTU; break;	  case LE: new_code = GEU; break;	  case GE: new_code = LEU; break;	  default: break;	}      if (new_code != UNKNOWN)	{	  *op0 = XVECEXP (*op0, 0, 0);	  *code = new_code;	}    }}/* Emit a compare instruction suitable to implement the comparison   OP0 CODE OP1.  Return the correct condition RTL to be placed in   the IF_THEN_ELSE of the conditional branch testing the result.  */rtxs390_emit_compare (enum rtx_code code, rtx op0, rtx op1){  enum machine_mode mode = s390_select_ccmode (code, op0, op1);  rtx cc = gen_rtx_REG (mode, CC_REGNUM);  emit_insn (gen_rtx_SET (VOIDmode, cc, gen_rtx_COMPARE (mode, op0, op1)));  return gen_rtx_fmt_ee (code, VOIDmode, cc, const0_rtx);}/* Emit a jump instruction to TARGET.  If COND is NULL_RTX, emit an   unconditional jump, else a conditional jump under condition COND.  */voids390_emit_jump (rtx target, rtx cond){  rtx insn;  target = gen_rtx_LABEL_REF (VOIDmode, target);  if (cond)    target = gen_rtx_IF_THEN_ELSE (VOIDmode, cond, target, pc_rtx);  insn = gen_rtx_SET (VOIDmode, pc_rtx, target);  emit_jump_insn (insn);}/* Return nonzero if OP is a valid comparison operator   for a branch condition in mode MODE.  */ints390_comparison (rtx op, enum machine_mode mode){  if (mode != VOIDmode && mode != GET_MODE (op))    return 0;  if (!COMPARISON_P (op))    return 0;  if (GET_CODE (XEXP (op, 0)) != REG      || REGNO (XEXP (op, 0)) != CC_REGNUM      || XEXP (op, 1) != const0_rtx)    return 0;  return s390_branch_condition_mask (op) >= 0;}/* Return nonzero if OP is a valid comparison operator   for an ALC condition in mode MODE.  */ints390_alc_comparison (rtx op, enum machine_mode mode){  if (mode != VOIDmode && mode != GET_MODE (op))    return 0;  while (GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == SIGN_EXTEND)    op = XEXP (op, 0);  if (!COMPARISON_P (op))    return 0;  if (GET_CODE (XEXP (op, 0)) != REG      || REGNO (XEXP (op, 0)) != CC_REGNUM      || XEXP (op, 1) != const0_rtx)    return 0;  switch (GET_MODE (XEXP (op, 0)))    {    case CCL1mode:      return GET_CODE (op) == LTU;    case CCL2mode:      return GET_CODE (op) == LEU;    case CCL3mode:      return GET_CODE (op) == GEU;    case CCUmode:      return GET_CODE (op) == GTU;    case CCURmode:      return GET_CODE (op) == LTU;    case CCSmode:      return GET_CODE (op) == UNGT;    case CCSRmode:      return GET_CODE (op) == UNLT;    default:      return 0;    }}/* Return nonzero if OP is a valid comparison operator   for an SLB condition in mode MODE.  */ints390_slb_comparison (rtx op, enum machine_mode mode){  if (mode != VOIDmode && mode != GET_MODE (op))    return 0;  while (GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == SIGN_EXTEND)    op = XEXP (op, 0);  if (!COMPARISON_P (op))    return 0;  if (GET_CODE (XEXP (op, 0)) != REG      || REGNO (XEXP (op, 0)) != CC_REGNUM      || XEXP (op, 1) != const0_rtx)    return 0;  switch (GET_MODE (XEXP (op, 0)))    {    case CCL1mode:      return GET_CODE (op) == GEU;    case CCL2mode:      return GET_CODE (op) == GTU;    case CCL3mode:      return GET_CODE (op) == LTU;    case CCUmode:      return GET_CODE (op) == LEU;    case CCURmode:      return GET_CODE (op) == GEU;    case CCSmode:      return GET_CODE (op) == LE;    case CCSRmode:      return GET_CODE (op) == GE;    default:      return 0;    }}/* Return branch condition mask to implement a branch   specified by CODE.  Return -1 for invalid comparisons.  */static ints390_branch_condition_mask (rtx code){  const int CC0 = 1 << 3;  const int CC1 = 1 << 2;  const int CC2 = 1 << 1;  const int CC3 = 1 << 0;  if (GET_CODE (XEXP (code, 0)) != REG      || REGNO (XEXP (code, 0)) != CC_REGNUM      || XEXP (code, 1) != const0_rtx)    abort ();  switch (GET_MODE (XEXP (code, 0)))    {    case CCZmode:      switch (GET_CODE (code))        {        case EQ:	return CC0;	case NE:	return CC1 | CC2 | CC3;	default:	return -1;        }      break;    case CCT1mode:      switch (GET_CODE (code))        {        case EQ:	return CC1;	case NE:	return CC0 | CC2 | CC3;	default:	return -1;        }      break;    case CCT2mode:      switch (GET_CODE (code))        {        case EQ:	return CC2;	case NE:	return CC0 | CC1 | CC3;	default:	return -1;        }      break;    case CCT3mode:      switch (GET_CODE (code))        {        case EQ:	return CC3;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -