SDOperand CombineTo(SDNode *N, const std::vector<SDOperand> &To) {
++NodesCombined;
DEBUG(std::cerr << "\nReplacing "; N->dump();
- std::cerr << "\nWith: "; To[0].Val->dump();
+ std::cerr << "\nWith: "; To[0].Val->dump(&DAG);
std::cerr << " and " << To.size()-1 << " other values\n");
std::vector<SDNode*> NowDead;
DAG.ReplaceAllUsesWith(N, To, &NowDead);
// Replace the old value with the new one.
++NodesCombined;
DEBUG(std::cerr << "\nReplacing "; TLO.Old.Val->dump();
- std::cerr << "\nWith: "; TLO.New.Val->dump());
+ std::cerr << "\nWith: "; TLO.New.Val->dump(&DAG));
std::vector<SDNode*> NowDead;
DAG.ReplaceAllUsesOfValueWith(TLO.Old, TLO.New, NowDead);
SDOperand visitSETCC(SDNode *N);
SDOperand visitSIGN_EXTEND(SDNode *N);
SDOperand visitZERO_EXTEND(SDNode *N);
+ SDOperand visitANY_EXTEND(SDNode *N);
SDOperand visitSIGN_EXTEND_INREG(SDNode *N);
SDOperand visitTRUNCATE(SDNode *N);
SDOperand visitBIT_CONVERT(SDNode *N);
SDOperand ReassociateOps(unsigned Opc, SDOperand LHS, SDOperand RHS);
bool SimplifySelectOps(SDNode *SELECT, SDOperand LHS, SDOperand RHS);
+ SDOperand SimplifyBinOpWithSameOpcodeHands(SDNode *N);
SDOperand SimplifySelect(SDOperand N0, SDOperand N1, SDOperand N2);
SDOperand SimplifySelectCC(SDOperand N0, SDOperand N1, SDOperand N2,
SDOperand N3, ISD::CondCode CC);
// mechanics for us, we have no work to do in this case.
if (RV.Val != N) {
DEBUG(std::cerr << "\nReplacing "; N->dump();
- std::cerr << "\nWith: "; RV.Val->dump();
+ std::cerr << "\nWith: "; RV.Val->dump(&DAG);
std::cerr << '\n');
std::vector<SDNode*> NowDead;
DAG.ReplaceAllUsesWith(N, std::vector<SDOperand>(1, RV), &NowDead);
case ISD::SETCC: return visitSETCC(N);
case ISD::SIGN_EXTEND: return visitSIGN_EXTEND(N);
case ISD::ZERO_EXTEND: return visitZERO_EXTEND(N);
+ case ISD::ANY_EXTEND: return visitANY_EXTEND(N);
case ISD::SIGN_EXTEND_INREG: return visitSIGN_EXTEND_INREG(N);
case ISD::TRUNCATE: return visitTRUNCATE(N);
case ISD::BIT_CONVERT: return visitBIT_CONVERT(N);
// If the token factor has two operands and one is the entry token, replace
// the token factor with the other operand.
if (N->getNumOperands() == 2) {
- if (N->getOperand(0).getOpcode() == ISD::EntryToken)
+ if (N->getOperand(0).getOpcode() == ISD::EntryToken ||
+ N->getOperand(0) == N->getOperand(1))
return N->getOperand(1);
if (N->getOperand(1).getOpcode() == ISD::EntryToken)
return N->getOperand(0);
Changed = true;
for (unsigned j = 0, e = Op.getNumOperands(); j != e; ++j)
Ops.push_back(Op.getOperand(j));
- } else {
+ } else if (i == 0 || N->getOperand(i) != N->getOperand(i-1)) {
Ops.push_back(Op);
+ } else {
+ // Deleted an operand that was the same as the last one.
+ Changed = true;
}
}
if (Changed)
return SDOperand();
}
+/// SimplifyBinOpWithSameOpcodeHands - If this is a binary operator with
+/// two operands of the same opcode, try to simplify it.
+SDOperand DAGCombiner::SimplifyBinOpWithSameOpcodeHands(SDNode *N) {
+ SDOperand N0 = N->getOperand(0), N1 = N->getOperand(1);
+ MVT::ValueType VT = N0.getValueType();
+ assert(N0.getOpcode() == N1.getOpcode() && "Bad input!");
+
+ // For each of OP in AND/OR/XOR:
+ // fold (OP (zext x), (zext y)) -> (zext (OP x, y))
+ // fold (OP (sext x), (sext y)) -> (sext (OP x, y))
+ // fold (OP (aext x), (aext y)) -> (aext (OP x, y))
+ // fold (OP (trunc x), (trunc y)) -> (trunc (OP x, y))
+ if ((N0.getOpcode() == ISD::ZERO_EXTEND || N0.getOpcode() == ISD::ANY_EXTEND||
+ N0.getOpcode() == ISD::SIGN_EXTEND || N0.getOpcode() == ISD::TRUNCATE) &&
+ N0.getOperand(0).getValueType() == N1.getOperand(0).getValueType()) {
+ SDOperand ORNode = DAG.getNode(N->getOpcode(),
+ N0.getOperand(0).getValueType(),
+ N0.getOperand(0), N1.getOperand(0));
+ AddToWorkList(ORNode.Val);
+ return DAG.getNode(N0.getOpcode(), VT, ORNode);
+ }
+
+ // For each of OP in SHL/SRL/SRA/AND...
+ // fold (and (OP x, z), (OP y, z)) -> (OP (and x, y), z)
+ // fold (or (OP x, z), (OP y, z)) -> (OP (or x, y), z)
+ // fold (xor (OP x, z), (OP y, z)) -> (OP (xor x, y), z)
+ if ((N0.getOpcode() == ISD::SHL || N0.getOpcode() == ISD::SRL ||
+ N0.getOpcode() == ISD::SRA || N0.getOpcode() == ISD::AND) &&
+ N0.getOperand(1) == N1.getOperand(1)) {
+ SDOperand ORNode = DAG.getNode(N->getOpcode(),
+ N0.getOperand(0).getValueType(),
+ N0.getOperand(0), N1.getOperand(0));
+ AddToWorkList(ORNode.Val);
+ return DAG.getNode(N0.getOpcode(), VT, ORNode, N0.getOperand(1));
+ }
+
+ return SDOperand();
+}
+
SDOperand DAGCombiner::visitAND(SDNode *N) {
SDOperand N0 = N->getOperand(0);
SDOperand N1 = N->getOperand(1);
return DAG.getSetCC(N0.getValueType(), LL, LR, Result);
}
}
- // fold (and (zext x), (zext y)) -> (zext (and x, y))
- if (N0.getOpcode() == ISD::ZERO_EXTEND &&
- N1.getOpcode() == ISD::ZERO_EXTEND &&
- N0.getOperand(0).getValueType() == N1.getOperand(0).getValueType()) {
- SDOperand ANDNode = DAG.getNode(ISD::AND, N0.getOperand(0).getValueType(),
- N0.getOperand(0), N1.getOperand(0));
- AddToWorkList(ANDNode.Val);
- return DAG.getNode(ISD::ZERO_EXTEND, VT, ANDNode);
- }
- // fold (and (shl/srl/sra x), (shl/srl/sra y)) -> (shl/srl/sra (and x, y))
- if (((N0.getOpcode() == ISD::SHL && N1.getOpcode() == ISD::SHL) ||
- (N0.getOpcode() == ISD::SRL && N1.getOpcode() == ISD::SRL) ||
- (N0.getOpcode() == ISD::SRA && N1.getOpcode() == ISD::SRA)) &&
- N0.getOperand(1) == N1.getOperand(1)) {
- SDOperand ANDNode = DAG.getNode(ISD::AND, N0.getOperand(0).getValueType(),
- N0.getOperand(0), N1.getOperand(0));
- AddToWorkList(ANDNode.Val);
- return DAG.getNode(N0.getOpcode(), VT, ANDNode, N0.getOperand(1));
+
+ // Simplify: and (op x...), (op y...) -> (op (and x, y))
+ if (N0.getOpcode() == N1.getOpcode()) {
+ SDOperand Tmp = SimplifyBinOpWithSameOpcodeHands(N);
+ if (Tmp.Val) return Tmp;
}
+
// fold (and (sign_extend_inreg x, i16 to i32), 1) -> (and x, 1)
// fold (and (sra)) -> (and (srl)) when possible.
if (!MVT::isVector(VT) &&
return DAG.getSetCC(N0.getValueType(), LL, LR, Result);
}
}
- // fold (or (zext x), (zext y)) -> (zext (or x, y))
- if (N0.getOpcode() == ISD::ZERO_EXTEND &&
- N1.getOpcode() == ISD::ZERO_EXTEND &&
- N0.getOperand(0).getValueType() == N1.getOperand(0).getValueType()) {
- SDOperand ORNode = DAG.getNode(ISD::OR, N0.getOperand(0).getValueType(),
- N0.getOperand(0), N1.getOperand(0));
- AddToWorkList(ORNode.Val);
- return DAG.getNode(ISD::ZERO_EXTEND, VT, ORNode);
- }
- // fold (or (shl/srl/sra x), (shl/srl/sra y)) -> (shl/srl/sra (or x, y))
- if (((N0.getOpcode() == ISD::SHL && N1.getOpcode() == ISD::SHL) ||
- (N0.getOpcode() == ISD::SRL && N1.getOpcode() == ISD::SRL) ||
- (N0.getOpcode() == ISD::SRA && N1.getOpcode() == ISD::SRA)) &&
- N0.getOperand(1) == N1.getOperand(1)) {
- SDOperand ORNode = DAG.getNode(ISD::OR, N0.getOperand(0).getValueType(),
- N0.getOperand(0), N1.getOperand(0));
- AddToWorkList(ORNode.Val);
- return DAG.getNode(N0.getOpcode(), VT, ORNode, N0.getOperand(1));
+
+ // Simplify: or (op x...), (op y...) -> (op (or x, y))
+ if (N0.getOpcode() == N1.getOpcode()) {
+ SDOperand Tmp = SimplifyBinOpWithSameOpcodeHands(N);
+ if (Tmp.Val) return Tmp;
}
+
// canonicalize shl to left side in a shl/srl pair, to match rotate
if (N0.getOpcode() == ISD::SRL && N1.getOpcode() == ISD::SHL)
std::swap(N0, N1);
return DAG.getNode(ISD::BUILD_VECTOR, VT, Ops);
}
}
- // fold (xor (zext x), (zext y)) -> (zext (xor x, y))
- if (N0.getOpcode() == ISD::ZERO_EXTEND &&
- N1.getOpcode() == ISD::ZERO_EXTEND &&
- N0.getOperand(0).getValueType() == N1.getOperand(0).getValueType()) {
- SDOperand XORNode = DAG.getNode(ISD::XOR, N0.getOperand(0).getValueType(),
- N0.getOperand(0), N1.getOperand(0));
- AddToWorkList(XORNode.Val);
- return DAG.getNode(ISD::ZERO_EXTEND, VT, XORNode);
- }
- // fold (xor (shl/srl/sra x), (shl/srl/sra y)) -> (shl/srl/sra (xor x, y))
- if (((N0.getOpcode() == ISD::SHL && N1.getOpcode() == ISD::SHL) ||
- (N0.getOpcode() == ISD::SRL && N1.getOpcode() == ISD::SRL) ||
- (N0.getOpcode() == ISD::SRA && N1.getOpcode() == ISD::SRA)) &&
- N0.getOperand(1) == N1.getOperand(1)) {
- SDOperand XORNode = DAG.getNode(ISD::XOR, N0.getOperand(0).getValueType(),
- N0.getOperand(0), N1.getOperand(0));
- AddToWorkList(XORNode.Val);
- return DAG.getNode(N0.getOpcode(), VT, XORNode, N0.getOperand(1));
+
+ // Simplify: xor (op x...), (op y...) -> (op (xor x, y))
+ if (N0.getOpcode() == N1.getOpcode()) {
+ SDOperand Tmp = SimplifyBinOpWithSameOpcodeHands(N);
+ if (Tmp.Val) return Tmp;
}
-
+
// Simplify the expression using non-local knowledge.
if (!MVT::isVector(VT) &&
SimplifyDemandedBits(SDOperand(N, 0)))
}
}
+ // Simplify, based on bits shifted out of the LHS.
+ if (N1C && SimplifyDemandedBits(SDOperand(N, 0)))
+ return SDOperand(N, 0);
+
+
// If the sign bit is known to be zero, switch this to a SRL.
if (TLI.MaskedValueIsZero(N0, MVT::getIntVTSignBit(VT)))
return DAG.getNode(ISD::SRL, VT, N0, N1);
DAG.getConstant(c1 + c2, N1.getValueType()));
}
+ // fold (srl (anyextend x), c) -> (anyextend (srl x, c))
+ if (N1C && N0.getOpcode() == ISD::ANY_EXTEND) {
+ // Shifting in all undef bits?
+ MVT::ValueType SmallVT = N0.getOperand(0).getValueType();
+ if (N1C->getValue() >= MVT::getSizeInBits(SmallVT))
+ return DAG.getNode(ISD::UNDEF, VT);
+
+ SDOperand SmallShift = DAG.getNode(ISD::SRL, SmallVT, N0.getOperand(0), N1);
+ AddToWorkList(SmallShift.Val);
+ return DAG.getNode(ISD::ANY_EXTEND, VT, SmallShift);
+ }
+
// fold (srl (ctlz x), "5") -> x iff x has one bit set (the low bit).
if (N1C && N0.getOpcode() == ISD::CTLZ &&
N1C->getValue() == Log2_32(MVT::getSizeInBits(VT))) {
SDOperand DAGCombiner::visitCTLZ(SDNode *N) {
SDOperand N0 = N->getOperand(0);
- ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0);
MVT::ValueType VT = N->getValueType(0);
// fold (ctlz c1) -> c2
- if (N0C)
+ if (isa<ConstantSDNode>(N0))
return DAG.getNode(ISD::CTLZ, VT, N0);
return SDOperand();
}
SDOperand DAGCombiner::visitCTTZ(SDNode *N) {
SDOperand N0 = N->getOperand(0);
- ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0);
MVT::ValueType VT = N->getValueType(0);
// fold (cttz c1) -> c2
- if (N0C)
+ if (isa<ConstantSDNode>(N0))
return DAG.getNode(ISD::CTTZ, VT, N0);
return SDOperand();
}
SDOperand DAGCombiner::visitCTPOP(SDNode *N) {
SDOperand N0 = N->getOperand(0);
- ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0);
MVT::ValueType VT = N->getValueType(0);
// fold (ctpop c1) -> c2
- if (N0C)
+ if (isa<ConstantSDNode>(N0))
return DAG.getNode(ISD::CTPOP, VT, N0);
return SDOperand();
}
SDOperand DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
SDOperand N0 = N->getOperand(0);
- ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0);
MVT::ValueType VT = N->getValueType(0);
// fold (sext c1) -> c1
- if (N0C)
+ if (ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0))
return DAG.getNode(ISD::SIGN_EXTEND, VT, N0);
+
// fold (sext (sext x)) -> (sext x)
- if (N0.getOpcode() == ISD::SIGN_EXTEND)
+ // fold (sext (aext x)) -> (sext x)
+ if (N0.getOpcode() == ISD::SIGN_EXTEND || N0.getOpcode() == ISD::ANY_EXTEND)
return DAG.getNode(ISD::SIGN_EXTEND, VT, N0.getOperand(0));
+
// fold (sext (truncate x)) -> (sextinreg x) iff x size == sext size.
if (N0.getOpcode() == ISD::TRUNCATE && N0.getOperand(0).getValueType() == VT&&
(!AfterLegalize ||
TLI.isOperationLegal(ISD::SIGN_EXTEND_INREG, N0.getValueType())))
return DAG.getNode(ISD::SIGN_EXTEND_INREG, VT, N0.getOperand(0),
DAG.getValueType(N0.getValueType()));
+
// fold (sext (load x)) -> (sext (truncate (sextload x)))
if (N0.getOpcode() == ISD::LOAD && N0.hasOneUse() &&
(!AfterLegalize||TLI.isOperationLegal(ISD::SEXTLOAD, N0.getValueType()))){
// fold (sext ( extload x)) -> (sext (truncate (sextload x)))
if ((N0.getOpcode() == ISD::SEXTLOAD || N0.getOpcode() == ISD::EXTLOAD) &&
N0.hasOneUse()) {
- SDOperand ExtLoad = DAG.getNode(ISD::SEXTLOAD, VT, N0.getOperand(0),
- N0.getOperand(1), N0.getOperand(2),
- N0.getOperand(3));
+ MVT::ValueType EVT = cast<VTSDNode>(N0.getOperand(3))->getVT();
+ SDOperand ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, VT, N0.getOperand(0),
+ N0.getOperand(1), N0.getOperand(2), EVT);
CombineTo(N, ExtLoad);
CombineTo(N0.Val, DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad),
ExtLoad.getValue(1));
SDOperand DAGCombiner::visitZERO_EXTEND(SDNode *N) {
SDOperand N0 = N->getOperand(0);
- ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0);
MVT::ValueType VT = N->getValueType(0);
// fold (zext c1) -> c1
- if (N0C)
+ if (ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0))
return DAG.getNode(ISD::ZERO_EXTEND, VT, N0);
// fold (zext (zext x)) -> (zext x)
- if (N0.getOpcode() == ISD::ZERO_EXTEND)
+ // fold (zext (aext x)) -> (zext x)
+ if (N0.getOpcode() == ISD::ZERO_EXTEND || N0.getOpcode() == ISD::ANY_EXTEND)
return DAG.getNode(ISD::ZERO_EXTEND, VT, N0.getOperand(0));
// fold (zext (truncate x)) -> (zextinreg x) iff x size == zext size.
if (N0.getOpcode() == ISD::TRUNCATE && N0.getOperand(0).getValueType() == VT&&
// fold (zext ( extload x)) -> (zext (truncate (zextload x)))
if ((N0.getOpcode() == ISD::ZEXTLOAD || N0.getOpcode() == ISD::EXTLOAD) &&
N0.hasOneUse()) {
- SDOperand ExtLoad = DAG.getNode(ISD::ZEXTLOAD, VT, N0.getOperand(0),
- N0.getOperand(1), N0.getOperand(2),
- N0.getOperand(3));
+ MVT::ValueType EVT = cast<VTSDNode>(N0.getOperand(3))->getVT();
+ SDOperand ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, VT, N0.getOperand(0),
+ N0.getOperand(1), N0.getOperand(2), EVT);
+ CombineTo(N, ExtLoad);
+ CombineTo(N0.Val, DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad),
+ ExtLoad.getValue(1));
+ return SDOperand(N, 0); // Return N so it doesn't get rechecked!
+ }
+ return SDOperand();
+}
+
+SDOperand DAGCombiner::visitANY_EXTEND(SDNode *N) {
+ SDOperand N0 = N->getOperand(0);
+ MVT::ValueType VT = N->getValueType(0);
+
+ // fold (aext c1) -> c1
+ if (isa<ConstantSDNode>(N0))
+ return DAG.getNode(ISD::ANY_EXTEND, VT, N0);
+ // fold (aext (aext x)) -> (aext x)
+ // fold (aext (zext x)) -> (zext x)
+ // fold (aext (sext x)) -> (sext x)
+ if (N0.getOpcode() == ISD::ANY_EXTEND ||
+ N0.getOpcode() == ISD::ZERO_EXTEND ||
+ N0.getOpcode() == ISD::SIGN_EXTEND)
+ return DAG.getNode(N0.getOpcode(), VT, N0.getOperand(0));
+
+ // fold (aext (truncate x)) -> x iff x size == zext size.
+ if (N0.getOpcode() == ISD::TRUNCATE && N0.getOperand(0).getValueType() == VT)
+ return N0.getOperand(0);
+ // fold (aext (load x)) -> (aext (truncate (extload x)))
+ if (N0.getOpcode() == ISD::LOAD && N0.hasOneUse() &&
+ (!AfterLegalize||TLI.isOperationLegal(ISD::EXTLOAD, N0.getValueType()))) {
+ SDOperand ExtLoad = DAG.getExtLoad(ISD::EXTLOAD, VT, N0.getOperand(0),
+ N0.getOperand(1), N0.getOperand(2),
+ N0.getValueType());
+ CombineTo(N, ExtLoad);
+ CombineTo(N0.Val, DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad),
+ ExtLoad.getValue(1));
+ return SDOperand(N, 0); // Return N so it doesn't get rechecked!
+ }
+
+ // fold (aext (zextload x)) -> (aext (truncate (zextload x)))
+ // fold (aext (sextload x)) -> (aext (truncate (sextload x)))
+ // fold (aext ( extload x)) -> (aext (truncate (extload x)))
+ if ((N0.getOpcode() == ISD::ZEXTLOAD || N0.getOpcode() == ISD::EXTLOAD ||
+ N0.getOpcode() == ISD::SEXTLOAD) &&
+ N0.hasOneUse()) {
+ MVT::ValueType EVT = cast<VTSDNode>(N0.getOperand(3))->getVT();
+ SDOperand ExtLoad = DAG.getExtLoad(N0.getOpcode(), VT, N0.getOperand(0),
+ N0.getOperand(1), N0.getOperand(2), EVT);
CombineTo(N, ExtLoad);
CombineTo(N0.Val, DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad),
ExtLoad.getValue(1));
return SDOperand();
}
+
SDOperand DAGCombiner::visitSIGN_EXTEND_INREG(SDNode *N) {
SDOperand N0 = N->getOperand(0);
SDOperand N1 = N->getOperand(1);
- ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0);
MVT::ValueType VT = N->getValueType(0);
MVT::ValueType EVT = cast<VTSDNode>(N1)->getVT();
unsigned EVTBits = MVT::getSizeInBits(EVT);
// fold (sext_in_reg c1) -> c1
- if (N0C) {
- SDOperand Truncate = DAG.getConstant(N0C->getValue(), EVT);
- return DAG.getNode(ISD::SIGN_EXTEND, VT, Truncate);
- }
- // fold (sext_in_reg (sext_in_reg x, VT2), VT1) -> (sext_in_reg x, minVT) pt1
- if (N0.getOpcode() == ISD::SIGN_EXTEND_INREG &&
- cast<VTSDNode>(N0.getOperand(1))->getVT() <= EVT) {
+ if (isa<ConstantSDNode>(N0) || N0.getOpcode() == ISD::UNDEF)
+ return DAG.getNode(ISD::SIGN_EXTEND_INREG, VT, N0, N1);
+
+ // If the input is already sign extended, just drop the extension.
+ if (TLI.ComputeNumSignBits(N0) >= MVT::getSizeInBits(VT)-EVTBits+1)
return N0;
- }
+
// fold (sext_in_reg (sext_in_reg x, VT2), VT1) -> (sext_in_reg x, minVT) pt2
if (N0.getOpcode() == ISD::SIGN_EXTEND_INREG &&
EVT < cast<VTSDNode>(N0.getOperand(1))->getVT()) {
return DAG.getNode(ISD::SIGN_EXTEND_INREG, VT, N0.getOperand(0), N1);
}
- // fold (sext_in_reg (assert_sext x)) -> (assert_sext x)
- if (N0.getOpcode() == ISD::AssertSext &&
- cast<VTSDNode>(N0.getOperand(1))->getVT() <= EVT) {
- return N0;
- }
- // fold (sext_in_reg (sextload x)) -> (sextload x)
- if (N0.getOpcode() == ISD::SEXTLOAD &&
- cast<VTSDNode>(N0.getOperand(3))->getVT() <= EVT) {
- return N0;
- }
- // fold (sext_in_reg (setcc x)) -> setcc x iff (setcc x) == 0 or -1
- if (N0.getOpcode() == ISD::SETCC &&
- TLI.getSetCCResultContents() ==
- TargetLowering::ZeroOrNegativeOneSetCCResult)
- return N0;
+
// fold (sext_in_reg x) -> (zext_in_reg x) if the sign bit is zero
if (TLI.MaskedValueIsZero(N0, 1ULL << (EVTBits-1)))
return DAG.getZeroExtendInReg(N0, EVT);
+
+ // fold (sext_in_reg (srl X, 24), i8) -> sra X, 24
+ // fold (sext_in_reg (srl X, 23), i8) -> sra X, 23 iff possible.
+ // We already fold "(sext_in_reg (srl X, 25), i8) -> srl X, 25" above.
+ if (N0.getOpcode() == ISD::SRL) {
+ if (ConstantSDNode *ShAmt = dyn_cast<ConstantSDNode>(N0.getOperand(1)))
+ if (ShAmt->getValue()+EVTBits <= MVT::getSizeInBits(VT)) {
+ // We can turn this into an SRA iff the input to the SRL is already sign
+ // extended enough.
+ unsigned InSignBits = TLI.ComputeNumSignBits(N0.getOperand(0));
+ if (MVT::getSizeInBits(VT)-(ShAmt->getValue()+EVTBits) < InSignBits)
+ return DAG.getNode(ISD::SRA, VT, N0.getOperand(0), N0.getOperand(1));
+ }
+ }
+
// fold (sext_inreg (extload x)) -> (sextload x)
if (N0.getOpcode() == ISD::EXTLOAD &&
EVT == cast<VTSDNode>(N0.getOperand(3))->getVT() &&
SDOperand DAGCombiner::visitTRUNCATE(SDNode *N) {
SDOperand N0 = N->getOperand(0);
- ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0);
MVT::ValueType VT = N->getValueType(0);
// noop truncate
if (N0.getValueType() == N->getValueType(0))
return N0;
// fold (truncate c1) -> c1
- if (N0C)
+ if (isa<ConstantSDNode>(N0))
return DAG.getNode(ISD::TRUNCATE, VT, N0);
// fold (truncate (truncate x)) -> (truncate x)
if (N0.getOpcode() == ISD::TRUNCATE)
return DAG.getNode(ISD::TRUNCATE, VT, N0.getOperand(0));
// fold (truncate (ext x)) -> (ext x) or (truncate x) or x
- if (N0.getOpcode() == ISD::ZERO_EXTEND || N0.getOpcode() == ISD::SIGN_EXTEND){
+ if (N0.getOpcode() == ISD::ZERO_EXTEND || N0.getOpcode() == ISD::SIGN_EXTEND||
+ N0.getOpcode() == ISD::ANY_EXTEND) {
if (N0.getValueType() < VT)
// if the source is smaller than the dest, we still need an extend
return DAG.getNode(N0.getOpcode(), VT, N0.getOperand(0));
// fold (fp_extend c1fp) -> c1fp
if (N0CFP)
return DAG.getNode(ISD::FP_EXTEND, VT, N0);
+
+ // fold (fpext (load x)) -> (fpext (fpround (extload x)))
+ if (N0.getOpcode() == ISD::LOAD && N0.hasOneUse() &&
+ (!AfterLegalize||TLI.isOperationLegal(ISD::EXTLOAD, N0.getValueType()))) {
+ SDOperand ExtLoad = DAG.getExtLoad(ISD::EXTLOAD, VT, N0.getOperand(0),
+ N0.getOperand(1), N0.getOperand(2),
+ N0.getValueType());
+ CombineTo(N, ExtLoad);
+ CombineTo(N0.Val, DAG.getNode(ISD::FP_ROUND, N0.getValueType(), ExtLoad),
+ ExtLoad.getValue(1));
+ return SDOperand(N, 0); // Return N so it doesn't get rechecked!
+ }
+
+
return SDOperand();
}