//
// The LLVM Compiler Infrastructure
//
-// This file was developed by the LLVM research group and is distributed under
-// the University of Illinois Open Source License. See LICENSE.TXT for details.
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
#include "llvm/Assembly/Writer.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineConstantPool.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Target/MRegisterInfo.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include <algorithm>
/// it returns true for things that are clearly not equal, like -0.0 and 0.0.
/// As such, this method can be used to do an exact bit-for-bit comparison of
/// two floating point values.
-bool ConstantFPSDNode::isExactlyValue(double V) const {
- return DoubleToBits(V) == DoubleToBits(Value);
+bool ConstantFPSDNode::isExactlyValue(const APFloat& V) const {
+ return Value.bitwiseIsEqual(V);
+}
+
+bool ConstantFPSDNode::isValueValidForType(MVT::ValueType VT,
+ const APFloat& Val) {
+ // convert modifies in place, so make a copy.
+ APFloat Val2 = APFloat(Val);
+ switch (VT) {
+ default:
+ return false; // These can't be represented as floating point!
+
+ // FIXME rounding mode needs to be more flexible
+ case MVT::f32:
+ return &Val2.getSemantics() == &APFloat::IEEEsingle ||
+ Val2.convert(APFloat::IEEEsingle, APFloat::rmNearestTiesToEven) ==
+ APFloat::opOK;
+ case MVT::f64:
+ return &Val2.getSemantics() == &APFloat::IEEEsingle ||
+ &Val2.getSemantics() == &APFloat::IEEEdouble ||
+ Val2.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven) ==
+ APFloat::opOK;
+ // TODO: Figure out how to test if we can use a shorter type instead!
+ case MVT::f80:
+ case MVT::f128:
+ case MVT::ppcf128:
+ return true;
+ }
}
//===----------------------------------------------------------------------===//
} else if (isa<ConstantFPSDNode>(NotZero)) {
MVT::ValueType VT = NotZero.getValueType();
if (VT== MVT::f64) {
- if (DoubleToBits(cast<ConstantFPSDNode>(NotZero)->getValue()) !=
- (uint64_t)-1)
+ if (((cast<ConstantFPSDNode>(NotZero)->getValueAPF().
+ convertToAPInt().getZExtValue())) != (uint64_t)-1)
return false;
} else {
- if (FloatToBits(cast<ConstantFPSDNode>(NotZero)->getValue()) !=
+ if ((uint32_t)cast<ConstantFPSDNode>(NotZero)->
+ getValueAPF().convertToAPInt().getZExtValue() !=
(uint32_t)-1)
return false;
}
if (!cast<ConstantSDNode>(Zero)->isNullValue())
return false;
} else if (isa<ConstantFPSDNode>(Zero)) {
- if (!cast<ConstantFPSDNode>(Zero)->isExactlyValue(0.0))
+ if (!cast<ConstantFPSDNode>(Zero)->getValueAPF().isPosZero())
return false;
} else
return false;
ID.AddInteger(cast<ConstantSDNode>(N)->getValue());
break;
case ISD::TargetConstantFP:
- case ISD::ConstantFP:
- ID.AddDouble(cast<ConstantFPSDNode>(N)->getValue());
+ case ISD::ConstantFP: {
+ ID.AddAPFloat(cast<ConstantFPSDNode>(N)->getValueAPF());
break;
+ }
case ISD::TargetGlobalAddress:
case ISD::GlobalAddress:
case ISD::TargetGlobalTLSAddress:
LoadSDNode *LD = cast<LoadSDNode>(N);
ID.AddInteger(LD->getAddressingMode());
ID.AddInteger(LD->getExtensionType());
- ID.AddInteger(LD->getLoadedVT());
- ID.AddPointer(LD->getSrcValue());
- ID.AddInteger(LD->getSrcValueOffset());
+ ID.AddInteger((unsigned int)(LD->getLoadedVT()));
ID.AddInteger(LD->getAlignment());
ID.AddInteger(LD->isVolatile());
break;
StoreSDNode *ST = cast<StoreSDNode>(N);
ID.AddInteger(ST->getAddressingMode());
ID.AddInteger(ST->isTruncatingStore());
- ID.AddInteger(ST->getStoredVT());
- ID.AddPointer(ST->getSrcValue());
- ID.AddInteger(ST->getSrcValueOffset());
+ ID.AddInteger((unsigned int)(ST->getStoredVT()));
ID.AddInteger(ST->getAlignment());
ID.AddInteger(ST->isVolatile());
break;
Erased =
TargetExternalSymbols.erase(cast<ExternalSymbolSDNode>(N)->getSymbol());
break;
- case ISD::VALUETYPE:
- Erased = ValueTypeNodes[cast<VTSDNode>(N)->getVT()] != 0;
- ValueTypeNodes[cast<VTSDNode>(N)->getVT()] = 0;
+ case ISD::VALUETYPE: {
+ MVT::ValueType VT = cast<VTSDNode>(N)->getVT();
+ if (MVT::isExtendedVT(VT)) {
+ Erased = ExtendedValueTypeNodes.erase(VT);
+ } else {
+ Erased = ValueTypeNodes[VT] != 0;
+ ValueTypeNodes[VT] = 0;
+ }
break;
+ }
default:
// Remove it from the CSE Map.
Erased = CSEMap.RemoveNode(N);
if (const LoadSDNode *LD = dyn_cast<LoadSDNode>(N)) {
ID.AddInteger(LD->getAddressingMode());
ID.AddInteger(LD->getExtensionType());
- ID.AddInteger(LD->getLoadedVT());
- ID.AddPointer(LD->getSrcValue());
- ID.AddInteger(LD->getSrcValueOffset());
+ ID.AddInteger((unsigned int)(LD->getLoadedVT()));
ID.AddInteger(LD->getAlignment());
ID.AddInteger(LD->isVolatile());
} else if (const StoreSDNode *ST = dyn_cast<StoreSDNode>(N)) {
ID.AddInteger(ST->getAddressingMode());
ID.AddInteger(ST->isTruncatingStore());
- ID.AddInteger(ST->getStoredVT());
- ID.AddPointer(ST->getSrcValue());
- ID.AddInteger(ST->getSrcValueOffset());
+ ID.AddInteger((unsigned int)(ST->getStoredVT()));
ID.AddInteger(ST->getAlignment());
ID.AddInteger(ST->isVolatile());
}
SDOperand SelectionDAG::getConstant(uint64_t Val, MVT::ValueType VT, bool isT) {
assert(MVT::isInteger(VT) && "Cannot create FP integer constant!");
- assert(!MVT::isVector(VT) && "Cannot create Vector ConstantSDNodes!");
+
+ MVT::ValueType EltVT =
+ MVT::isVector(VT) ? MVT::getVectorElementType(VT) : VT;
// Mask out any bits that are not valid for this constant.
- Val &= MVT::getIntVTBitMask(VT);
+ Val &= MVT::getIntVTBitMask(EltVT);
unsigned Opc = isT ? ISD::TargetConstant : ISD::Constant;
FoldingSetNodeID ID;
- AddNodeIDNode(ID, Opc, getVTList(VT), 0, 0);
+ AddNodeIDNode(ID, Opc, getVTList(EltVT), 0, 0);
ID.AddInteger(Val);
void *IP = 0;
- if (SDNode *E = CSEMap.FindNodeOrInsertPos(ID, IP))
- return SDOperand(E, 0);
- SDNode *N = new ConstantSDNode(isT, Val, VT);
- CSEMap.InsertNode(N, IP);
- AllNodes.push_back(N);
- return SDOperand(N, 0);
+ SDNode *N = NULL;
+ if ((N = CSEMap.FindNodeOrInsertPos(ID, IP)))
+ if (!MVT::isVector(VT))
+ return SDOperand(N, 0);
+ if (!N) {
+ N = new ConstantSDNode(isT, Val, EltVT);
+ CSEMap.InsertNode(N, IP);
+ AllNodes.push_back(N);
+ }
+
+ SDOperand Result(N, 0);
+ if (MVT::isVector(VT)) {
+ SmallVector<SDOperand, 8> Ops;
+ Ops.assign(MVT::getVectorNumElements(VT), Result);
+ Result = getNode(ISD::BUILD_VECTOR, VT, &Ops[0], Ops.size());
+ }
+ return Result;
}
+SDOperand SelectionDAG::getIntPtrConstant(uint64_t Val, bool isTarget) {
+ return getConstant(Val, TLI.getPointerTy(), isTarget);
+}
-SDOperand SelectionDAG::getConstantFP(double Val, MVT::ValueType VT,
+
+SDOperand SelectionDAG::getConstantFP(const APFloat& V, MVT::ValueType VT,
bool isTarget) {
assert(MVT::isFloatingPoint(VT) && "Cannot create integer FP constant!");
+
MVT::ValueType EltVT =
MVT::isVector(VT) ? MVT::getVectorElementType(VT) : VT;
- if (EltVT == MVT::f32)
- Val = (float)Val; // Mask out extra precision.
// Do the map lookup using the actual bit pattern for the floating point
// value, so that we don't have problems with 0.0 comparing equal to -0.0, and
unsigned Opc = isTarget ? ISD::TargetConstantFP : ISD::ConstantFP;
FoldingSetNodeID ID;
AddNodeIDNode(ID, Opc, getVTList(EltVT), 0, 0);
- ID.AddDouble(Val);
+ ID.AddAPFloat(V);
void *IP = 0;
- if (SDNode *E = CSEMap.FindNodeOrInsertPos(ID, IP))
- return SDOperand(E, 0);
- SDNode *N = new ConstantFPSDNode(isTarget, Val, EltVT);
- CSEMap.InsertNode(N, IP);
- AllNodes.push_back(N);
+ SDNode *N = NULL;
+ if ((N = CSEMap.FindNodeOrInsertPos(ID, IP)))
+ if (!MVT::isVector(VT))
+ return SDOperand(N, 0);
+ if (!N) {
+ N = new ConstantFPSDNode(isTarget, V, EltVT);
+ CSEMap.InsertNode(N, IP);
+ AllNodes.push_back(N);
+ }
+
SDOperand Result(N, 0);
if (MVT::isVector(VT)) {
SmallVector<SDOperand, 8> Ops;
return Result;
}
+SDOperand SelectionDAG::getConstantFP(double Val, MVT::ValueType VT,
+ bool isTarget) {
+ MVT::ValueType EltVT =
+ MVT::isVector(VT) ? MVT::getVectorElementType(VT) : VT;
+ if (EltVT==MVT::f32)
+ return getConstantFP(APFloat((float)Val), VT, isTarget);
+ else
+ return getConstantFP(APFloat(Val), VT, isTarget);
+}
+
SDOperand SelectionDAG::getGlobalAddress(const GlobalValue *GV,
MVT::ValueType VT, int Offset,
bool isTargetGA) {
}
SDOperand SelectionDAG::getValueType(MVT::ValueType VT) {
- if ((unsigned)VT >= ValueTypeNodes.size())
+ if (!MVT::isExtendedVT(VT) && (unsigned)VT >= ValueTypeNodes.size())
ValueTypeNodes.resize(VT+1);
- if (ValueTypeNodes[VT] == 0) {
- ValueTypeNodes[VT] = new VTSDNode(VT);
- AllNodes.push_back(ValueTypeNodes[VT]);
- }
- return SDOperand(ValueTypeNodes[VT], 0);
+ SDNode *&N = MVT::isExtendedVT(VT) ?
+ ExtendedValueTypeNodes[VT] : ValueTypeNodes[VT];
+
+ if (N) return SDOperand(N, 0);
+ N = new VTSDNode(VT);
+ AllNodes.push_back(N);
+ return SDOperand(N, 0);
}
SDOperand SelectionDAG::getExternalSymbol(const char *Sym, MVT::ValueType VT) {
return SDOperand(N, 0);
}
+/// CreateStackTemporary - Create a stack temporary, suitable for holding the
+/// specified value type.
+SDOperand SelectionDAG::CreateStackTemporary(MVT::ValueType VT) {
+ MachineFrameInfo *FrameInfo = getMachineFunction().getFrameInfo();
+ unsigned ByteSize = MVT::getSizeInBits(VT)/8;
+ const Type *Ty = MVT::getTypeForValueType(VT);
+ unsigned StackAlign = (unsigned)TLI.getTargetData()->getPrefTypeAlignment(Ty);
+ int FrameIdx = FrameInfo->CreateStackObject(ByteSize, StackAlign);
+ return getFrameIndex(FrameIdx, TLI.getPointerTy());
+}
+
+
SDOperand SelectionDAG::FoldSetCC(MVT::ValueType VT, SDOperand N1,
SDOperand N2, ISD::CondCode Cond) {
// These setcc operations always fold.
}
if (ConstantFPSDNode *N1C = dyn_cast<ConstantFPSDNode>(N1.Val))
if (ConstantFPSDNode *N2C = dyn_cast<ConstantFPSDNode>(N2.Val)) {
- double C1 = N1C->getValue(), C2 = N2C->getValue();
-
+ // No compile time operations on this type yet.
+ if (N1C->getValueType(0) == MVT::ppcf128)
+ return SDOperand();
+
+ APFloat::cmpResult R = N1C->getValueAPF().compare(N2C->getValueAPF());
switch (Cond) {
- default: break; // FIXME: Implement the rest of these!
- case ISD::SETEQ: return getConstant(C1 == C2, VT);
- case ISD::SETNE: return getConstant(C1 != C2, VT);
- case ISD::SETLT: return getConstant(C1 < C2, VT);
- case ISD::SETGT: return getConstant(C1 > C2, VT);
- case ISD::SETLE: return getConstant(C1 <= C2, VT);
- case ISD::SETGE: return getConstant(C1 >= C2, VT);
+ default: break;
+ case ISD::SETEQ: if (R==APFloat::cmpUnordered)
+ return getNode(ISD::UNDEF, VT);
+ // fall through
+ case ISD::SETOEQ: return getConstant(R==APFloat::cmpEqual, VT);
+ case ISD::SETNE: if (R==APFloat::cmpUnordered)
+ return getNode(ISD::UNDEF, VT);
+ // fall through
+ case ISD::SETONE: return getConstant(R==APFloat::cmpGreaterThan ||
+ R==APFloat::cmpLessThan, VT);
+ case ISD::SETLT: if (R==APFloat::cmpUnordered)
+ return getNode(ISD::UNDEF, VT);
+ // fall through
+ case ISD::SETOLT: return getConstant(R==APFloat::cmpLessThan, VT);
+ case ISD::SETGT: if (R==APFloat::cmpUnordered)
+ return getNode(ISD::UNDEF, VT);
+ // fall through
+ case ISD::SETOGT: return getConstant(R==APFloat::cmpGreaterThan, VT);
+ case ISD::SETLE: if (R==APFloat::cmpUnordered)
+ return getNode(ISD::UNDEF, VT);
+ // fall through
+ case ISD::SETOLE: return getConstant(R==APFloat::cmpLessThan ||
+ R==APFloat::cmpEqual, VT);
+ case ISD::SETGE: if (R==APFloat::cmpUnordered)
+ return getNode(ISD::UNDEF, VT);
+ // fall through
+ case ISD::SETOGE: return getConstant(R==APFloat::cmpGreaterThan ||
+ R==APFloat::cmpEqual, VT);
+ case ISD::SETO: return getConstant(R!=APFloat::cmpUnordered, VT);
+ case ISD::SETUO: return getConstant(R==APFloat::cmpUnordered, VT);
+ case ISD::SETUEQ: return getConstant(R==APFloat::cmpUnordered ||
+ R==APFloat::cmpEqual, VT);
+ case ISD::SETUNE: return getConstant(R!=APFloat::cmpEqual, VT);
+ case ISD::SETULT: return getConstant(R==APFloat::cmpUnordered ||
+ R==APFloat::cmpLessThan, VT);
+ case ISD::SETUGT: return getConstant(R==APFloat::cmpGreaterThan ||
+ R==APFloat::cmpUnordered, VT);
+ case ISD::SETULE: return getConstant(R!=APFloat::cmpGreaterThan, VT);
+ case ISD::SETUGE: return getConstant(R!=APFloat::cmpLessThan, VT);
}
} else {
// Ensure that the constant occurs on the RHS.
KnownZero |= (~InMask) & Mask;
return;
}
+ case ISD::FGETSIGN:
+ // All bits are zero except the low bit.
+ KnownZero = MVT::getIntVTBitMask(Op.getValueType()) ^ 1;
+ return;
+
case ISD::ADD: {
// If either the LHS or the RHS are Zero, the result is zero.
ComputeMaskedBits(Op.getOperand(1), Mask, KnownZero, KnownOne, Depth+1);
case ISD::ANY_EXTEND:
case ISD::ZERO_EXTEND: return getConstant(Val, VT);
case ISD::TRUNCATE: return getConstant(Val, VT);
- case ISD::SINT_TO_FP: return getConstantFP(C->getSignExtended(), VT);
- case ISD::UINT_TO_FP: return getConstantFP(C->getValue(), VT);
+ case ISD::UINT_TO_FP:
+ case ISD::SINT_TO_FP: {
+ const uint64_t zero[] = {0, 0};
+ // No compile time operations on this type.
+ if (VT==MVT::ppcf128)
+ break;
+ APFloat apf = APFloat(APInt(MVT::getSizeInBits(VT), 2, zero));
+ (void)apf.convertFromZeroExtendedInteger(&Val,
+ MVT::getSizeInBits(Operand.getValueType()),
+ Opcode==ISD::SINT_TO_FP,
+ APFloat::rmNearestTiesToEven);
+ return getConstantFP(apf, VT);
+ }
case ISD::BIT_CONVERT:
if (VT == MVT::f32 && C->getValueType(0) == MVT::i32)
return getConstantFP(BitsToFloat(Val), VT);
}
}
- // Constant fold unary operations with an floating point constant operand.
- if (ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(Operand.Val))
- switch (Opcode) {
- case ISD::FNEG:
- return getConstantFP(-C->getValue(), VT);
- case ISD::FABS:
- return getConstantFP(fabs(C->getValue()), VT);
- case ISD::FP_ROUND:
- case ISD::FP_EXTEND:
- return getConstantFP(C->getValue(), VT);
- case ISD::FP_TO_SINT:
- return getConstant((int64_t)C->getValue(), VT);
- case ISD::FP_TO_UINT:
- return getConstant((uint64_t)C->getValue(), VT);
- case ISD::BIT_CONVERT:
- if (VT == MVT::i32 && C->getValueType(0) == MVT::f32)
- return getConstant(FloatToBits(C->getValue()), VT);
- else if (VT == MVT::i64 && C->getValueType(0) == MVT::f64)
- return getConstant(DoubleToBits(C->getValue()), VT);
- break;
+ // Constant fold unary operations with a floating point constant operand.
+ if (ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(Operand.Val)) {
+ APFloat V = C->getValueAPF(); // make copy
+ if (VT != MVT::ppcf128 && Operand.getValueType() != MVT::ppcf128) {
+ switch (Opcode) {
+ case ISD::FNEG:
+ V.changeSign();
+ return getConstantFP(V, VT);
+ case ISD::FABS:
+ V.clearSign();
+ return getConstantFP(V, VT);
+ case ISD::FP_ROUND:
+ case ISD::FP_EXTEND:
+ // This can return overflow, underflow, or inexact; we don't care.
+ // FIXME need to be more flexible about rounding mode.
+ (void) V.convert(VT==MVT::f32 ? APFloat::IEEEsingle :
+ VT==MVT::f64 ? APFloat::IEEEdouble :
+ VT==MVT::f80 ? APFloat::x87DoubleExtended :
+ VT==MVT::f128 ? APFloat::IEEEquad :
+ APFloat::Bogus,
+ APFloat::rmNearestTiesToEven);
+ return getConstantFP(V, VT);
+ case ISD::FP_TO_SINT:
+ case ISD::FP_TO_UINT: {
+ integerPart x;
+ assert(integerPartWidth >= 64);
+ // FIXME need to be more flexible about rounding mode.
+ APFloat::opStatus s = V.convertToInteger(&x, 64U,
+ Opcode==ISD::FP_TO_SINT,
+ APFloat::rmTowardZero);
+ if (s==APFloat::opInvalidOp) // inexact is OK, in fact usual
+ break;
+ return getConstant(x, VT);
+ }
+ case ISD::BIT_CONVERT:
+ if (VT == MVT::i32 && C->getValueType(0) == MVT::f32)
+ return getConstant((uint32_t)V.convertToAPInt().getZExtValue(), VT);
+ else if (VT == MVT::i64 && C->getValueType(0) == MVT::f64)
+ return getConstant(V.convertToAPInt().getZExtValue(), VT);
+ break;
+ }
}
+ }
unsigned OpOpcode = Operand.Val->getOpcode();
switch (Opcode) {
case ISD::TokenFactor:
return Operand; // Factor of one node? No factor.
- case ISD::FP_ROUND:
+ case ISD::FP_ROUND: assert(0 && "Invalid method to make FP_ROUND node");
case ISD::FP_EXTEND:
assert(MVT::isFloatingPoint(VT) &&
MVT::isFloatingPoint(Operand.getValueType()) && "Invalid FP cast!");
+ if (Operand.getValueType() == VT) return Operand; // noop conversion.
break;
- case ISD::SIGN_EXTEND:
+ case ISD::SIGN_EXTEND:
assert(MVT::isInteger(VT) && MVT::isInteger(Operand.getValueType()) &&
"Invalid SIGN_EXTEND!");
if (Operand.getValueType() == VT) return Operand; // noop extension
- assert(Operand.getValueType() < VT && "Invalid sext node, dst < src!");
+ assert(MVT::getSizeInBits(Operand.getValueType()) < MVT::getSizeInBits(VT)
+ && "Invalid sext node, dst < src!");
if (OpOpcode == ISD::SIGN_EXTEND || OpOpcode == ISD::ZERO_EXTEND)
return getNode(OpOpcode, VT, Operand.Val->getOperand(0));
break;
assert(MVT::isInteger(VT) && MVT::isInteger(Operand.getValueType()) &&
"Invalid ZERO_EXTEND!");
if (Operand.getValueType() == VT) return Operand; // noop extension
- assert(Operand.getValueType() < VT && "Invalid zext node, dst < src!");
+ assert(MVT::getSizeInBits(Operand.getValueType()) < MVT::getSizeInBits(VT)
+ && "Invalid zext node, dst < src!");
if (OpOpcode == ISD::ZERO_EXTEND) // (zext (zext x)) -> (zext x)
return getNode(ISD::ZERO_EXTEND, VT, Operand.Val->getOperand(0));
break;
assert(MVT::isInteger(VT) && MVT::isInteger(Operand.getValueType()) &&
"Invalid ANY_EXTEND!");
if (Operand.getValueType() == VT) return Operand; // noop extension
- assert(Operand.getValueType() < VT && "Invalid anyext node, dst < src!");
+ assert(MVT::getSizeInBits(Operand.getValueType()) < MVT::getSizeInBits(VT)
+ && "Invalid anyext node, dst < src!");
if (OpOpcode == ISD::ZERO_EXTEND || OpOpcode == ISD::SIGN_EXTEND)
// (ext (zext x)) -> (zext x) and (ext (sext x)) -> (sext x)
return getNode(OpOpcode, VT, Operand.Val->getOperand(0));
assert(MVT::isInteger(VT) && MVT::isInteger(Operand.getValueType()) &&
"Invalid TRUNCATE!");
if (Operand.getValueType() == VT) return Operand; // noop truncate
- assert(Operand.getValueType() > VT && "Invalid truncate node, src < dst!");
+ assert(MVT::getSizeInBits(Operand.getValueType()) > MVT::getSizeInBits(VT)
+ && "Invalid truncate node, src < dst!");
if (OpOpcode == ISD::TRUNCATE)
return getNode(ISD::TRUNCATE, VT, Operand.Val->getOperand(0));
else if (OpOpcode == ISD::ZERO_EXTEND || OpOpcode == ISD::SIGN_EXTEND ||
OpOpcode == ISD::ANY_EXTEND) {
// If the source is smaller than the dest, we still need an extend.
- if (Operand.Val->getOperand(0).getValueType() < VT)
+ if (MVT::getSizeInBits(Operand.Val->getOperand(0).getValueType())
+ < MVT::getSizeInBits(VT))
return getNode(OpOpcode, VT, Operand.Val->getOperand(0));
- else if (Operand.Val->getOperand(0).getValueType() > VT)
+ else if (MVT::getSizeInBits(Operand.Val->getOperand(0).getValueType())
+ > MVT::getSizeInBits(VT))
return getNode(ISD::TRUNCATE, VT, Operand.Val->getOperand(0));
else
return Operand.Val->getOperand(0);
SDOperand SelectionDAG::getNode(unsigned Opcode, MVT::ValueType VT,
SDOperand N1, SDOperand N2) {
-#ifndef NDEBUG
+ ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1.Val);
+ ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N2.Val);
switch (Opcode) {
+ default: break;
case ISD::TokenFactor:
assert(VT == MVT::Other && N1.getValueType() == MVT::Other &&
N2.getValueType() == MVT::Other && "Invalid token factor!");
+ // Fold trivial token factors.
+ if (N1.getOpcode() == ISD::EntryToken) return N2;
+ if (N2.getOpcode() == ISD::EntryToken) return N1;
break;
case ISD::AND:
+ assert(MVT::isInteger(VT) && N1.getValueType() == N2.getValueType() &&
+ N1.getValueType() == VT && "Binary operator types must match!");
+ // (X & 0) -> 0. This commonly occurs when legalizing i64 values, so it's
+ // worth handling here.
+ if (N2C && N2C->getValue() == 0)
+ return N2;
+ break;
case ISD::OR:
case ISD::XOR:
+ assert(MVT::isInteger(VT) && N1.getValueType() == N2.getValueType() &&
+ N1.getValueType() == VT && "Binary operator types must match!");
+ // (X ^| 0) -> X. This commonly occurs when legalizing i64 values, so it's
+ // worth handling here.
+ if (N2C && N2C->getValue() == 0)
+ return N1;
+ break;
case ISD::UDIV:
case ISD::UREM:
case ISD::MULHU:
case ISD::MUL:
case ISD::SDIV:
case ISD::SREM:
- assert(MVT::isInteger(N1.getValueType()) && "Should use F* for FP ops");
- // fall through.
case ISD::FADD:
case ISD::FSUB:
case ISD::FMUL:
assert(VT == N1.getValueType() && "Not an inreg round!");
assert(MVT::isFloatingPoint(VT) && MVT::isFloatingPoint(EVT) &&
"Cannot FP_ROUND_INREG integer types");
- assert(EVT <= VT && "Not rounding down!");
+ assert(MVT::getSizeInBits(EVT) <= MVT::getSizeInBits(VT) &&
+ "Not rounding down!");
+ if (cast<VTSDNode>(N2)->getVT() == VT) return N1; // Not actually rounding.
break;
}
+ case ISD::FP_ROUND:
+ assert(MVT::isFloatingPoint(VT) &&
+ MVT::isFloatingPoint(N1.getValueType()) &&
+ MVT::getSizeInBits(VT) <= MVT::getSizeInBits(N1.getValueType()) &&
+ isa<ConstantSDNode>(N2) && "Invalid FP_ROUND!");
+ if (N1.getValueType() == VT) return N1; // noop conversion.
+ break;
case ISD::AssertSext:
- case ISD::AssertZext:
- case ISD::SIGN_EXTEND_INREG: {
+ case ISD::AssertZext: {
MVT::ValueType EVT = cast<VTSDNode>(N2)->getVT();
assert(VT == N1.getValueType() && "Not an inreg extend!");
assert(MVT::isInteger(VT) && MVT::isInteger(EVT) &&
"Cannot *_EXTEND_INREG FP types");
- assert(EVT <= VT && "Not extending!");
- }
-
- default: break;
+ assert(MVT::getSizeInBits(EVT) <= MVT::getSizeInBits(VT) &&
+ "Not extending!");
+ break;
}
-#endif
+ case ISD::SIGN_EXTEND_INREG: {
+ MVT::ValueType EVT = cast<VTSDNode>(N2)->getVT();
+ assert(VT == N1.getValueType() && "Not an inreg extend!");
+ assert(MVT::isInteger(VT) && MVT::isInteger(EVT) &&
+ "Cannot *_EXTEND_INREG FP types");
+ assert(MVT::getSizeInBits(EVT) <= MVT::getSizeInBits(VT) &&
+ "Not extending!");
+ if (EVT == VT) return N1; // Not actually extending
- ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1.Val);
- ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N2.Val);
- if (N1C) {
- if (Opcode == ISD::SIGN_EXTEND_INREG) {
+ if (N1C) {
int64_t Val = N1C->getValue();
unsigned FromBits = MVT::getSizeInBits(cast<VTSDNode>(N2)->getVT());
Val <<= 64-FromBits;
Val >>= 64-FromBits;
return getConstant(Val, VT);
}
+ break;
+ }
+ case ISD::EXTRACT_VECTOR_ELT:
+ assert(N2C && "Bad EXTRACT_VECTOR_ELT!");
+
+ // EXTRACT_VECTOR_ELT of CONCAT_VECTORS is often formed while lowering is
+ // expanding copies of large vectors from registers.
+ if (N1.getOpcode() == ISD::CONCAT_VECTORS &&
+ N1.getNumOperands() > 0) {
+ unsigned Factor =
+ MVT::getVectorNumElements(N1.getOperand(0).getValueType());
+ return getNode(ISD::EXTRACT_VECTOR_ELT, VT,
+ N1.getOperand(N2C->getValue() / Factor),
+ getConstant(N2C->getValue() % Factor, N2.getValueType()));
+ }
+
+ // EXTRACT_VECTOR_ELT of BUILD_VECTOR is often formed while lowering is
+ // expanding large vector constants.
+ if (N1.getOpcode() == ISD::BUILD_VECTOR)
+ return N1.getOperand(N2C->getValue());
+
+ // EXTRACT_VECTOR_ELT of INSERT_VECTOR_ELT is often formed when vector
+ // operations are lowered to scalars.
+ if (N1.getOpcode() == ISD::INSERT_VECTOR_ELT)
+ if (ConstantSDNode *IEC = dyn_cast<ConstantSDNode>(N1.getOperand(2))) {
+ if (IEC == N2C)
+ return N1.getOperand(1);
+ else
+ return getNode(ISD::EXTRACT_VECTOR_ELT, VT, N1.getOperand(0), N2);
+ }
+ break;
+ case ISD::EXTRACT_ELEMENT:
+ assert(N2C && (unsigned)N2C->getValue() < 2 && "Bad EXTRACT_ELEMENT!");
+ // EXTRACT_ELEMENT of BUILD_PAIR is often formed while legalize is expanding
+ // 64-bit integers into 32-bit parts. Instead of building the extract of
+ // the BUILD_PAIR, only to have legalize rip it apart, just do it now.
+ if (N1.getOpcode() == ISD::BUILD_PAIR)
+ return N1.getOperand(N2C->getValue());
+
+ // EXTRACT_ELEMENT of a constant int is also very common.
+ if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N1)) {
+ unsigned Shift = MVT::getSizeInBits(VT) * N2C->getValue();
+ return getConstant(C->getValue() >> Shift, VT);
+ }
+ break;
+ }
+
+ if (N1C) {
if (N2C) {
uint64_t C1 = N1C->getValue(), C2 = N2C->getValue();
switch (Opcode) {
}
}
+ // Constant fold FP operations.
ConstantFPSDNode *N1CFP = dyn_cast<ConstantFPSDNode>(N1.Val);
ConstantFPSDNode *N2CFP = dyn_cast<ConstantFPSDNode>(N2.Val);
if (N1CFP) {
- if (N2CFP) {
- double C1 = N1CFP->getValue(), C2 = N2CFP->getValue();
+ if (!N2CFP && isCommutativeBinOp(Opcode)) {
+ // Cannonicalize constant to RHS if commutative
+ std::swap(N1CFP, N2CFP);
+ std::swap(N1, N2);
+ } else if (N2CFP && VT != MVT::ppcf128) {
+ APFloat V1 = N1CFP->getValueAPF(), V2 = N2CFP->getValueAPF();
+ APFloat::opStatus s;
switch (Opcode) {
- case ISD::FADD: return getConstantFP(C1 + C2, VT);
- case ISD::FSUB: return getConstantFP(C1 - C2, VT);
- case ISD::FMUL: return getConstantFP(C1 * C2, VT);
+ case ISD::FADD:
+ s = V1.add(V2, APFloat::rmNearestTiesToEven);
+ if (s != APFloat::opInvalidOp)
+ return getConstantFP(V1, VT);
+ break;
+ case ISD::FSUB:
+ s = V1.subtract(V2, APFloat::rmNearestTiesToEven);
+ if (s!=APFloat::opInvalidOp)
+ return getConstantFP(V1, VT);
+ break;
+ case ISD::FMUL:
+ s = V1.multiply(V2, APFloat::rmNearestTiesToEven);
+ if (s!=APFloat::opInvalidOp)
+ return getConstantFP(V1, VT);
+ break;
case ISD::FDIV:
- if (C2) return getConstantFP(C1 / C2, VT);
+ s = V1.divide(V2, APFloat::rmNearestTiesToEven);
+ if (s!=APFloat::opInvalidOp && s!=APFloat::opDivByZero)
+ return getConstantFP(V1, VT);
break;
case ISD::FREM :
- if (C2) return getConstantFP(fmod(C1, C2), VT);
+ s = V1.mod(V2, APFloat::rmNearestTiesToEven);
+ if (s!=APFloat::opInvalidOp && s!=APFloat::opDivByZero)
+ return getConstantFP(V1, VT);
break;
- case ISD::FCOPYSIGN: {
- union {
- double F;
- uint64_t I;
- } u1;
- u1.F = C1;
- if (int64_t(DoubleToBits(C2)) < 0) // Sign bit of RHS set?
- u1.I |= 1ULL << 63; // Set the sign bit of the LHS.
- else
- u1.I &= (1ULL << 63)-1; // Clear the sign bit of the LHS.
- return getConstantFP(u1.F, VT);
- }
+ case ISD::FCOPYSIGN:
+ V1.copySign(V2);
+ return getConstantFP(V1, VT);
default: break;
}
- } else { // Cannonicalize constant to RHS if commutative
- if (isCommutativeBinOp(Opcode)) {
- std::swap(N1CFP, N2CFP);
- std::swap(N1, N2);
- }
}
}
}
}
- // Fold operations.
- switch (Opcode) {
- case ISD::TokenFactor:
- // Fold trivial token factors.
- if (N1.getOpcode() == ISD::EntryToken) return N2;
- if (N2.getOpcode() == ISD::EntryToken) return N1;
- break;
-
- case ISD::AND:
- // (X & 0) -> 0. This commonly occurs when legalizing i64 values, so it's
- // worth handling here.
- if (N2C && N2C->getValue() == 0)
- return N2;
- break;
- case ISD::OR:
- case ISD::XOR:
- // (X ^| 0) -> X. This commonly occurs when legalizing i64 values, so it's
- // worth handling here.
- if (N2C && N2C->getValue() == 0)
- return N1;
- break;
- case ISD::FP_ROUND_INREG:
- if (cast<VTSDNode>(N2)->getVT() == VT) return N1; // Not actually rounding.
- break;
- case ISD::SIGN_EXTEND_INREG: {
- MVT::ValueType EVT = cast<VTSDNode>(N2)->getVT();
- if (EVT == VT) return N1; // Not actually extending
- break;
- }
- case ISD::EXTRACT_VECTOR_ELT:
- assert(N2C && "Bad EXTRACT_VECTOR_ELT!");
-
- // EXTRACT_VECTOR_ELT of BUILD_PAIR is often formed while lowering is
- // expanding copies of large vectors from registers.
- if (N1.getOpcode() == ISD::BUILD_PAIR) {
- unsigned NewNumElts = MVT::getVectorNumElements(N1.getValueType()) / 2;
- bool Low = N2C->getValue() < NewNumElts;
- return getNode(ISD::EXTRACT_VECTOR_ELT, VT, N1.getOperand(!Low),
- Low ? N2 : getConstant(N2C->getValue() - NewNumElts,
- N2.getValueType()));
- }
- // EXTRACT_VECTOR_ELT of BUILD_VECTOR is often formed while lowering is
- // expanding large vector constants.
- if (N1.getOpcode() == ISD::BUILD_VECTOR)
- return N1.getOperand(N2C->getValue());
- break;
- case ISD::EXTRACT_ELEMENT:
- assert(N2C && (unsigned)N2C->getValue() < 2 && "Bad EXTRACT_ELEMENT!");
-
- // EXTRACT_ELEMENT of BUILD_PAIR is often formed while legalize is expanding
- // 64-bit integers into 32-bit parts. Instead of building the extract of
- // the BUILD_PAIR, only to have legalize rip it apart, just do it now.
- if (N1.getOpcode() == ISD::BUILD_PAIR)
- return N1.getOperand(N2C->getValue());
-
- // EXTRACT_ELEMENT of a constant int is also very common.
- if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N1)) {
- unsigned Shift = MVT::getSizeInBits(VT) * N2C->getValue();
- return getConstant(C->getValue() >> Shift, VT);
- }
- break;
-
- // FIXME: figure out how to safely handle things like
- // int foo(int x) { return 1 << (x & 255); }
- // int bar() { return foo(256); }
-#if 0
- case ISD::SHL:
- case ISD::SRL:
- case ISD::SRA:
- if (N2.getOpcode() == ISD::SIGN_EXTEND_INREG &&
- cast<VTSDNode>(N2.getOperand(1))->getVT() != MVT::i1)
- return getNode(Opcode, VT, N1, N2.getOperand(0));
- else if (N2.getOpcode() == ISD::AND)
- if (ConstantSDNode *AndRHS = dyn_cast<ConstantSDNode>(N2.getOperand(1))) {
- // If the and is only masking out bits that cannot effect the shift,
- // eliminate the and.
- unsigned NumBits = MVT::getSizeInBits(VT);
- if ((AndRHS->getValue() & (NumBits-1)) == NumBits-1)
- return getNode(Opcode, VT, N1, N2.getOperand(0));
- }
- break;
-#endif
- }
-
// Memoize this node if possible.
SDNode *N;
SDVTList VTs = getVTList(VT);
return getNode(Opcode, VT, Ops, 5);
}
+SDOperand SelectionDAG::getMemcpy(SDOperand Chain, SDOperand Dest,
+ SDOperand Src, SDOperand Size,
+ SDOperand Align,
+ SDOperand AlwaysInline) {
+ SDOperand Ops[] = { Chain, Dest, Src, Size, Align, AlwaysInline };
+ return getNode(ISD::MEMCPY, MVT::Other, Ops, 6);
+}
+
+SDOperand SelectionDAG::getMemmove(SDOperand Chain, SDOperand Dest,
+ SDOperand Src, SDOperand Size,
+ SDOperand Align,
+ SDOperand AlwaysInline) {
+ SDOperand Ops[] = { Chain, Dest, Src, Size, Align, AlwaysInline };
+ return getNode(ISD::MEMMOVE, MVT::Other, Ops, 6);
+}
+
+SDOperand SelectionDAG::getMemset(SDOperand Chain, SDOperand Dest,
+ SDOperand Src, SDOperand Size,
+ SDOperand Align,
+ SDOperand AlwaysInline) {
+ SDOperand Ops[] = { Chain, Dest, Src, Size, Align, AlwaysInline };
+ return getNode(ISD::MEMSET, MVT::Other, Ops, 6);
+}
+
SDOperand SelectionDAG::getLoad(MVT::ValueType VT,
SDOperand Chain, SDOperand Ptr,
const Value *SV, int SVOffset,
AddNodeIDNode(ID, ISD::LOAD, VTs, Ops, 3);
ID.AddInteger(ISD::UNINDEXED);
ID.AddInteger(ISD::NON_EXTLOAD);
- ID.AddInteger(VT);
- ID.AddPointer(SV);
- ID.AddInteger(SVOffset);
+ ID.AddInteger((unsigned int)VT);
ID.AddInteger(Alignment);
ID.AddInteger(isVolatile);
void *IP = 0;
// If they are asking for an extending load from/to the same thing, return a
// normal load.
if (VT == EVT)
- ExtType = ISD::NON_EXTLOAD;
+ return getLoad(VT, Chain, Ptr, SV, SVOffset, isVolatile, Alignment);
if (MVT::isVector(VT))
assert(EVT == MVT::getVectorElementType(VT) && "Invalid vector extload!");
else
- assert(EVT < VT && "Should only be an extending load, not truncating!");
+ assert(MVT::getSizeInBits(EVT) < MVT::getSizeInBits(VT) &&
+ "Should only be an extending load, not truncating!");
assert((ExtType == ISD::EXTLOAD || MVT::isInteger(VT)) &&
"Cannot sign/zero extend a FP/Vector load!");
assert(MVT::isInteger(VT) == MVT::isInteger(EVT) &&
AddNodeIDNode(ID, ISD::LOAD, VTs, Ops, 3);
ID.AddInteger(ISD::UNINDEXED);
ID.AddInteger(ExtType);
- ID.AddInteger(EVT);
- ID.AddPointer(SV);
- ID.AddInteger(SVOffset);
+ ID.AddInteger((unsigned int)EVT);
ID.AddInteger(Alignment);
ID.AddInteger(isVolatile);
void *IP = 0;
AddNodeIDNode(ID, ISD::LOAD, VTs, Ops, 3);
ID.AddInteger(AM);
ID.AddInteger(LD->getExtensionType());
- ID.AddInteger(LD->getLoadedVT());
- ID.AddPointer(LD->getSrcValue());
- ID.AddInteger(LD->getSrcValueOffset());
+ ID.AddInteger((unsigned int)(LD->getLoadedVT()));
ID.AddInteger(LD->getAlignment());
ID.AddInteger(LD->isVolatile());
void *IP = 0;
AddNodeIDNode(ID, ISD::STORE, VTs, Ops, 4);
ID.AddInteger(ISD::UNINDEXED);
ID.AddInteger(false);
- ID.AddInteger(VT);
- ID.AddPointer(SV);
- ID.AddInteger(SVOffset);
+ ID.AddInteger((unsigned int)VT);
ID.AddInteger(Alignment);
ID.AddInteger(isVolatile);
void *IP = 0;
int SVOffset, MVT::ValueType SVT,
bool isVolatile, unsigned Alignment) {
MVT::ValueType VT = Val.getValueType();
- bool isTrunc = VT != SVT;
- assert(VT > SVT && "Not a truncation?");
+ if (VT == SVT)
+ return getStore(Chain, Val, Ptr, SV, SVOffset, isVolatile, Alignment);
+
+ assert(MVT::getSizeInBits(VT) > MVT::getSizeInBits(SVT) &&
+ "Not a truncation?");
assert(MVT::isInteger(VT) == MVT::isInteger(SVT) &&
"Can't do FP-INT conversion!");
FoldingSetNodeID ID;
AddNodeIDNode(ID, ISD::STORE, VTs, Ops, 4);
ID.AddInteger(ISD::UNINDEXED);
- ID.AddInteger(isTrunc);
- ID.AddInteger(SVT);
- ID.AddPointer(SV);
- ID.AddInteger(SVOffset);
+ ID.AddInteger(1);
+ ID.AddInteger((unsigned int)SVT);
ID.AddInteger(Alignment);
ID.AddInteger(isVolatile);
void *IP = 0;
if (SDNode *E = CSEMap.FindNodeOrInsertPos(ID, IP))
return SDOperand(E, 0);
- SDNode *N = new StoreSDNode(Ops, VTs, ISD::UNINDEXED, isTrunc,
+ SDNode *N = new StoreSDNode(Ops, VTs, ISD::UNINDEXED, true,
SVT, SV, SVOffset, Alignment, isVolatile);
CSEMap.InsertNode(N, IP);
AllNodes.push_back(N);
AddNodeIDNode(ID, ISD::STORE, VTs, Ops, 4);
ID.AddInteger(AM);
ID.AddInteger(ST->isTruncatingStore());
- ID.AddInteger(ST->getStoredVT());
- ID.AddPointer(ST->getSrcValue());
- ID.AddInteger(ST->getSrcValueOffset());
+ ID.AddInteger((unsigned int)(ST->getStoredVT()));
ID.AddInteger(ST->getAlignment());
ID.AddInteger(ST->isVolatile());
void *IP = 0;
return SDOperand(N, 0);
}
-SDVTList SelectionDAG::getVTList(MVT::ValueType VT) {
- if (!MVT::isExtendedVT(VT))
- return makeVTList(SDNode::getValueTypeList(VT), 1);
+SDOperand SelectionDAG::getNode(unsigned Opcode, SDVTList VTList) {
+ return getNode(Opcode, VTList, 0, 0);
+}
- for (std::list<std::vector<MVT::ValueType> >::iterator I = VTList.begin(),
- E = VTList.end(); I != E; ++I) {
- if (I->size() == 1 && (*I)[0] == VT)
- return makeVTList(&(*I)[0], 1);
- }
- std::vector<MVT::ValueType> V;
- V.push_back(VT);
- VTList.push_front(V);
- return makeVTList(&(*VTList.begin())[0], 1);
+SDOperand SelectionDAG::getNode(unsigned Opcode, SDVTList VTList,
+ SDOperand N1) {
+ SDOperand Ops[] = { N1 };
+ return getNode(Opcode, VTList, Ops, 1);
+}
+
+SDOperand SelectionDAG::getNode(unsigned Opcode, SDVTList VTList,
+ SDOperand N1, SDOperand N2) {
+ SDOperand Ops[] = { N1, N2 };
+ return getNode(Opcode, VTList, Ops, 2);
+}
+
+SDOperand SelectionDAG::getNode(unsigned Opcode, SDVTList VTList,
+ SDOperand N1, SDOperand N2, SDOperand N3) {
+ SDOperand Ops[] = { N1, N2, N3 };
+ return getNode(Opcode, VTList, Ops, 3);
+}
+
+SDOperand SelectionDAG::getNode(unsigned Opcode, SDVTList VTList,
+ SDOperand N1, SDOperand N2, SDOperand N3,
+ SDOperand N4) {
+ SDOperand Ops[] = { N1, N2, N3, N4 };
+ return getNode(Opcode, VTList, Ops, 4);
+}
+
+SDOperand SelectionDAG::getNode(unsigned Opcode, SDVTList VTList,
+ SDOperand N1, SDOperand N2, SDOperand N3,
+ SDOperand N4, SDOperand N5) {
+ SDOperand Ops[] = { N1, N2, N3, N4, N5 };
+ return getNode(Opcode, VTList, Ops, 5);
+}
+
+SDVTList SelectionDAG::getVTList(MVT::ValueType VT) {
+ return makeVTList(SDNode::getValueTypeList(VT), 1);
}
SDVTList SelectionDAG::getVTList(MVT::ValueType VT1, MVT::ValueType VT2) {
const SDOperand *Ops, unsigned NumOps) {
return getNode(ISD::BUILTIN_OP_END+Opcode, VT, Ops, NumOps).Val;
}
+SDNode *SelectionDAG::getTargetNode(unsigned Opcode, MVT::ValueType VT1,
+ MVT::ValueType VT2) {
+ const MVT::ValueType *VTs = getNodeValueTypes(VT1, VT2);
+ SDOperand Op;
+ return getNode(ISD::BUILTIN_OP_END+Opcode, VTs, 2, &Op, 0).Val;
+}
SDNode *SelectionDAG::getTargetNode(unsigned Opcode, MVT::ValueType VT1,
MVT::ValueType VT2, SDOperand Op1) {
const MVT::ValueType *VTs = getNodeValueTypes(VT1, VT2);
const MVT::ValueType *VTs = getNodeValueTypes(VT1, VT2, VT3);
return getNode(ISD::BUILTIN_OP_END+Opcode, VTs, 3, Ops, NumOps).Val;
}
+SDNode *SelectionDAG::getTargetNode(unsigned Opcode, MVT::ValueType VT1,
+ MVT::ValueType VT2, MVT::ValueType VT3,
+ MVT::ValueType VT4,
+ const SDOperand *Ops, unsigned NumOps) {
+ std::vector<MVT::ValueType> VTList;
+ VTList.push_back(VT1);
+ VTList.push_back(VT2);
+ VTList.push_back(VT3);
+ VTList.push_back(VT4);
+ const MVT::ValueType *VTs = getNodeValueTypes(VTList);
+ return getNode(ISD::BUILTIN_OP_END+Opcode, VTs, 4, Ops, NumOps).Val;
+}
+SDNode *SelectionDAG::getTargetNode(unsigned Opcode,
+ std::vector<MVT::ValueType> &ResultTys,
+ const SDOperand *Ops, unsigned NumOps) {
+ const MVT::ValueType *VTs = getNodeValueTypes(ResultTys);
+ return getNode(ISD::BUILTIN_OP_END+Opcode, VTs, ResultTys.size(),
+ Ops, NumOps).Val;
+}
/// ReplaceAllUsesWith - Modify anything using 'From' to use 'To' instead.
/// This can cause recursive merging of nodes in the DAG.
/// uses of other values produced by From.Val alone. The Deleted vector is
/// handled the same was as for ReplaceAllUsesWith.
void SelectionDAG::ReplaceAllUsesOfValueWith(SDOperand From, SDOperand To,
- std::vector<SDNode*> &Deleted) {
+ std::vector<SDNode*> *Deleted) {
assert(From != To && "Cannot replace a value with itself");
// Handle the simple, trivial, case efficiently.
if (From.Val->getNumValues() == 1 && To.Val->getNumValues() == 1) {
- ReplaceAllUsesWith(From, To, &Deleted);
+ ReplaceAllUsesWith(From, To, Deleted);
return;
}
// deterministically ordered and uniqued set, so we use a SmallSetVector.
SmallSetVector<SDNode*, 16> Users(From.Val->use_begin(), From.Val->use_end());
+ std::vector<SDNode*> LocalDeletionVector;
+
+ // Pick a deletion vector to use. If the user specified one, use theirs,
+ // otherwise use a local one.
+ std::vector<SDNode*> *DeleteVector = Deleted ? Deleted : &LocalDeletionVector;
while (!Users.empty()) {
// We know that this user uses some value of From. If it is the right
// value, update it.
SDNode *User = Users.back();
Users.pop_back();
- for (SDOperand *Op = User->OperandList,
- *E = User->OperandList+User->NumOperands; Op != E; ++Op) {
+ // Scan for an operand that matches From.
+ SDOperand *Op = User->OperandList, *E = User->OperandList+User->NumOperands;
+ for (; Op != E; ++Op)
+ if (*Op == From) break;
+
+ // If there are no matches, the user must use some other result of From.
+ if (Op == E) continue;
+
+ // Okay, we know this user needs to be updated. Remove its old self
+ // from the CSE maps.
+ RemoveNodeFromCSEMaps(User);
+
+ // Update all operands that match "From".
+ for (; Op != E; ++Op) {
if (*Op == From) {
- // Okay, we know this user needs to be updated. Remove its old self
- // from the CSE maps.
- RemoveNodeFromCSEMaps(User);
-
- // Update all operands that match "From".
- for (; Op != E; ++Op) {
- if (*Op == From) {
- From.Val->removeUser(User);
- *Op = To;
- To.Val->addUser(User);
- }
- }
-
- // Now that we have modified User, add it back to the CSE maps. If it
- // already exists there, recursively merge the results together.
- if (SDNode *Existing = AddNonLeafNodeToCSEMaps(User)) {
- unsigned NumDeleted = Deleted.size();
- ReplaceAllUsesWith(User, Existing, &Deleted);
-
- // User is now dead.
- Deleted.push_back(User);
- DeleteNodeNotInCSEMaps(User);
-
- // We have to be careful here, because ReplaceAllUsesWith could have
- // deleted a user of From, which means there may be dangling pointers
- // in the "Users" setvector. Scan over the deleted node pointers and
- // remove them from the setvector.
- for (unsigned i = NumDeleted, e = Deleted.size(); i != e; ++i)
- Users.remove(Deleted[i]);
- }
- break; // Exit the operand scanning loop.
+ From.Val->removeUser(User);
+ *Op = To;
+ To.Val->addUser(User);
}
}
+
+ // Now that we have modified User, add it back to the CSE maps. If it
+ // already exists there, recursively merge the results together.
+ SDNode *Existing = AddNonLeafNodeToCSEMaps(User);
+ if (!Existing) continue; // Continue on to next user.
+
+ // If there was already an existing matching node, use ReplaceAllUsesWith
+ // to replace the dead one with the existing one. However, this can cause
+ // recursive merging of other unrelated nodes down the line. The merging
+ // can cause deletion of nodes that used the old value. In this case,
+ // we have to be certain to remove them from the Users set.
+ unsigned NumDeleted = DeleteVector->size();
+ ReplaceAllUsesWith(User, Existing, DeleteVector);
+
+ // User is now dead.
+ DeleteVector->push_back(User);
+ DeleteNodeNotInCSEMaps(User);
+
+ // We have to be careful here, because ReplaceAllUsesWith could have
+ // deleted a user of From, which means there may be dangling pointers
+ // in the "Users" setvector. Scan over the deleted node pointers and
+ // remove them from the setvector.
+ for (unsigned i = NumDeleted, e = DeleteVector->size(); i != e; ++i)
+ Users.remove((*DeleteVector)[i]);
+
+ // If the user doesn't need the set of deleted elements, don't retain them
+ // to the next loop iteration.
+ if (Deleted == 0)
+ LocalDeletionVector.clear();
}
}
GlobalAddressSDNode::GlobalAddressSDNode(bool isTarget, const GlobalValue *GA,
MVT::ValueType VT, int o)
: SDNode(isa<GlobalVariable>(GA) &&
- dyn_cast<GlobalVariable>(GA)->isThreadLocal() ?
+ cast<GlobalVariable>(GA)->isThreadLocal() ?
// Thread Local
(isTarget ? ISD::TargetGlobalTLSAddress : ISD::GlobalTLSAddress) :
// Non Thread Local
/// getValueTypeList - Return a pointer to the specified value type.
///
MVT::ValueType *SDNode::getValueTypeList(MVT::ValueType VT) {
- static MVT::ValueType VTs[MVT::LAST_VALUETYPE];
- VTs[VT] = VT;
- return &VTs[VT];
+ if (MVT::isExtendedVT(VT)) {
+ static std::set<MVT::ValueType> EVTs;
+ return (MVT::ValueType *)&(*EVTs.insert(VT).first);
+ } else {
+ static MVT::ValueType VTs[MVT::LAST_VALUETYPE];
+ VTs[VT] = VT;
+ return &VTs[VT];
+ }
}
-
+
/// hasNUsesOfValue - Return true if there are exactly NUSES uses of the
/// indicated value. This method ignores uses of other values defined by this
/// operation.
// If there is only one value, this is easy.
if (getNumValues() == 1)
return use_size() == NUses;
- if (Uses.size() < NUses) return false;
+ if (use_size() < NUses) return false;
SDOperand TheValue(const_cast<SDNode *>(this), Value);
}
+/// hasAnyUseOfValue - Return true if there are any use of the indicated
+/// value. This method ignores uses of other values defined by this operation.
+bool SDNode::hasAnyUseOfValue(unsigned Value) const {
+ assert(Value < getNumValues() && "Bad value!");
+
+ if (use_size() == 0) return false;
+
+ SDOperand TheValue(const_cast<SDNode *>(this), Value);
+
+ SmallPtrSet<SDNode*, 32> UsersHandled;
+
+ for (SDNode::use_iterator UI = Uses.begin(), E = Uses.end(); UI != E; ++UI) {
+ SDNode *User = *UI;
+ if (User->getNumOperands() == 1 ||
+ UsersHandled.insert(User)) // First time we've seen this?
+ for (unsigned i = 0, e = User->getNumOperands(); i != e; ++i)
+ if (User->getOperand(i) == TheValue) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
/// isOnlyUse - Return true if this node is the only use of N.
///
bool SDNode::isOnlyUse(SDNode *N) const {
return false;
}
+/// reachesChainWithoutSideEffects - Return true if this operand (which must
+/// be a chain) reaches the specified operand without crossing any
+/// side-effecting instructions. In practice, this looks through token
+/// factors and non-volatile loads. In order to remain efficient, this only
+/// looks a couple of nodes in, it does not do an exhaustive search.
+bool SDOperand::reachesChainWithoutSideEffects(SDOperand Dest,
+ unsigned Depth) const {
+ if (*this == Dest) return true;
+
+ // Don't search too deeply, we just want to be able to see through
+ // TokenFactor's etc.
+ if (Depth == 0) return false;
+
+ // If this is a token factor, all inputs to the TF happen in parallel. If any
+ // of the operands of the TF reach dest, then we can do the xform.
+ if (getOpcode() == ISD::TokenFactor) {
+ for (unsigned i = 0, e = getNumOperands(); i != e; ++i)
+ if (getOperand(i).reachesChainWithoutSideEffects(Dest, Depth-1))
+ return true;
+ return false;
+ }
+
+ // Loads don't have side effects, look through them.
+ if (LoadSDNode *Ld = dyn_cast<LoadSDNode>(*this)) {
+ if (!Ld->isVolatile())
+ return Ld->getChain().reachesChainWithoutSideEffects(Dest, Depth-1);
+ }
+ return false;
+}
+
+
static void findPredecessor(SDNode *N, const SDNode *P, bool &found,
SmallPtrSet<SDNode *, 32> &Visited) {
if (found || !Visited.insert(N))
if (G) {
if (const TargetInstrInfo *TII = G->getTarget().getInstrInfo())
if (getOpcode()-ISD::BUILTIN_OP_END < TII->getNumOpcodes())
- return TII->getName(getOpcode()-ISD::BUILTIN_OP_END);
+ return TII->get(getOpcode()-ISD::BUILTIN_OP_END).getName();
TargetLowering &TLI = G->getTargetLoweringInfo();
const char *Name =
case ISD::GLOBAL_OFFSET_TABLE: return "GLOBAL_OFFSET_TABLE";
case ISD::RETURNADDR: return "RETURNADDR";
case ISD::FRAMEADDR: return "FRAMEADDR";
+ case ISD::FRAME_TO_ARGS_OFFSET: return "FRAME_TO_ARGS_OFFSET";
case ISD::EXCEPTIONADDR: return "EXCEPTIONADDR";
case ISD::EHSELECTION: return "EHSELECTION";
+ case ISD::EH_RETURN: return "EH_RETURN";
case ISD::ConstantPool: return "ConstantPool";
case ISD::ExternalSymbol: return "ExternalSymbol";
case ISD::INTRINSIC_WO_CHAIN: {
case ISD::CopyToReg: return "CopyToReg";
case ISD::CopyFromReg: return "CopyFromReg";
case ISD::UNDEF: return "undef";
- case ISD::MERGE_VALUES: return "mergevalues";
+ case ISD::MERGE_VALUES: return "merge_values";
case ISD::INLINEASM: return "inlineasm";
case ISD::LABEL: return "label";
case ISD::HANDLENODE: return "handlenode";
case ISD::FSIN: return "fsin";
case ISD::FCOS: return "fcos";
case ISD::FPOWI: return "fpowi";
+ case ISD::FPOW: return "fpow";
// Binary operators
case ISD::ADD: return "add";
case ISD::UDIV: return "udiv";
case ISD::SREM: return "srem";
case ISD::UREM: return "urem";
+ case ISD::SMUL_LOHI: return "smul_lohi";
+ case ISD::UMUL_LOHI: return "umul_lohi";
+ case ISD::SDIVREM: return "sdivrem";
+ case ISD::UDIVREM: return "divrem";
case ISD::AND: return "and";
case ISD::OR: return "or";
case ISD::XOR: return "xor";
case ISD::FDIV: return "fdiv";
case ISD::FREM: return "frem";
case ISD::FCOPYSIGN: return "fcopysign";
+ case ISD::FGETSIGN: return "fgetsign";
case ISD::SETCC: return "setcc";
case ISD::SELECT: return "select";
case ISD::SHL_PARTS: return "shl_parts";
case ISD::SRA_PARTS: return "sra_parts";
case ISD::SRL_PARTS: return "srl_parts";
-
+
+ case ISD::EXTRACT_SUBREG: return "extract_subreg";
+ case ISD::INSERT_SUBREG: return "insert_subreg";
+
// Conversion operators.
case ISD::SIGN_EXTEND: return "sign_extend";
case ISD::ZERO_EXTEND: return "zero_extend";
case ISD::SIGN_EXTEND_INREG: return "sign_extend_inreg";
case ISD::TRUNCATE: return "truncate";
case ISD::FP_ROUND: return "fp_round";
+ case ISD::FLT_ROUNDS: return "flt_rounds";
case ISD::FP_ROUND_INREG: return "fp_round_inreg";
case ISD::FP_EXTEND: return "fp_extend";
case ISD::BUILD_PAIR: return "build_pair";
case ISD::STACKSAVE: return "stacksave";
case ISD::STACKRESTORE: return "stackrestore";
-
+ case ISD::TRAP: return "trap";
+
// Block memory operations.
case ISD::MEMSET: return "memset";
case ISD::MEMCPY: return "memcpy";
case ISD::LOCATION: return "location";
case ISD::DEBUG_LOC: return "debug_loc";
+ // Trampolines
+ case ISD::TRAMPOLINE: return "trampoline";
+
case ISD::CONDCODE:
switch (cast<CondCodeSDNode>(this)->get()) {
default: assert(0 && "Unknown setcc condition!");
cerr << ":" << RN;
}
+ if (!isTargetOpcode() && getOpcode() == ISD::VECTOR_SHUFFLE) {
+ SDNode *Mask = getOperand(2).Val;
+ cerr << "<";
+ for (unsigned i = 0, e = Mask->getNumOperands(); i != e; ++i) {
+ if (i) cerr << ",";
+ if (Mask->getOperand(i).getOpcode() == ISD::UNDEF)
+ cerr << "u";
+ else
+ cerr << cast<ConstantSDNode>(Mask->getOperand(i))->getValue();
+ }
+ cerr << ">";
+ }
+
if (const ConstantSDNode *CSDN = dyn_cast<ConstantSDNode>(this)) {
cerr << "<" << CSDN->getValue() << ">";
} else if (const ConstantFPSDNode *CSDN = dyn_cast<ConstantFPSDNode>(this)) {
- cerr << "<" << CSDN->getValue() << ">";
+ if (&CSDN->getValueAPF().getSemantics()==&APFloat::IEEEsingle)
+ cerr << "<" << CSDN->getValueAPF().convertToFloat() << ">";
+ else if (&CSDN->getValueAPF().getSemantics()==&APFloat::IEEEdouble)
+ cerr << "<" << CSDN->getValueAPF().convertToDouble() << ">";
+ else {
+ cerr << "<APFloat(";
+ CSDN->getValueAPF().convertToAPInt().dump();
+ cerr << ")>";
+ }
} else if (const GlobalAddressSDNode *GADN =
dyn_cast<GlobalAddressSDNode>(this)) {
int offset = GADN->getOffset();
} else if (const VTSDNode *N = dyn_cast<VTSDNode>(this)) {
cerr << ":" << MVT::getValueTypeString(N->getVT());
} else if (const LoadSDNode *LD = dyn_cast<LoadSDNode>(this)) {
+ const Value *SrcValue = LD->getSrcValue();
+ int SrcOffset = LD->getSrcValueOffset();
+ cerr << " <";
+ if (SrcValue)
+ cerr << SrcValue;
+ else
+ cerr << "null";
+ cerr << ":" << SrcOffset << ">";
+
bool doExt = true;
switch (LD->getExtensionType()) {
default: doExt = false; break;
cerr << MVT::getValueTypeString(LD->getLoadedVT()) << ">";
const char *AM = getIndexedModeName(LD->getAddressingMode());
- if (AM != "")
+ if (*AM)
cerr << " " << AM;
+ if (LD->isVolatile())
+ cerr << " <volatile>";
+ cerr << " alignment=" << LD->getAlignment();
} else if (const StoreSDNode *ST = dyn_cast<StoreSDNode>(this)) {
+ const Value *SrcValue = ST->getSrcValue();
+ int SrcOffset = ST->getSrcValueOffset();
+ cerr << " <";
+ if (SrcValue)
+ cerr << SrcValue;
+ else
+ cerr << "null";
+ cerr << ":" << SrcOffset << ">";
+
if (ST->isTruncatingStore())
cerr << " <trunc "
<< MVT::getValueTypeString(ST->getStoredVT()) << ">";
const char *AM = getIndexedModeName(ST->getAddressingMode());
- if (AM != "")
+ if (*AM)
cerr << " " << AM;
+ if (ST->isVolatile())
+ cerr << " <volatile>";
+ cerr << " alignment=" << ST->getAlignment();
}
}