+/// SelectAddress - Pattern match the maximal addressing mode for this node.
+void X86DAGToDAGISel::SelectAddress(SDOperand N, X86ISelAddressMode &AM) {
+ MatchAddress(N, AM);
+
+ if (AM.BaseType == X86ISelAddressMode::RegBase && !AM.Base.Reg.Val) {
+ AM.Base.Reg = CurDAG->getRegister(0, MVT::i32);
+ } else {
+ AM.Base.Reg = Select(AM.Base.Reg);
+ }
+ if (!AM.IndexReg.Val) {
+ AM.IndexReg = CurDAG->getRegister(0, MVT::i32);
+ } else {
+ AM.IndexReg = Select(AM.IndexReg);
+ }
+}
+
+/// FIXME: copied from X86ISelPattern.cpp
+/// MatchAddress - Add the specified node to the specified addressing mode,
+/// returning true if it cannot be done. This just pattern matches for the
+/// addressing mode
+bool X86DAGToDAGISel::MatchAddress(SDOperand N, X86ISelAddressMode &AM) {
+ switch (N.getOpcode()) {
+ default: break;
+ case ISD::FrameIndex:
+ if (AM.BaseType == X86ISelAddressMode::RegBase && AM.Base.Reg.Val == 0) {
+ AM.BaseType = X86ISelAddressMode::FrameIndexBase;
+ AM.Base.FrameIndex = cast<FrameIndexSDNode>(N)->getIndex();
+ return false;
+ }
+ break;
+ case ISD::GlobalAddress:
+ if (AM.GV == 0) {
+ GlobalValue *GV = cast<GlobalAddressSDNode>(N)->getGlobal();
+ // For Darwin, external and weak symbols are indirect, so we want to load
+ // the value at address GV, not the value of GV itself. This means that
+ // the GlobalAddress must be in the base or index register of the address,
+ // not the GV offset field.
+ if (Subtarget->getIndirectExternAndWeakGlobals() &&
+ (GV->hasWeakLinkage() || GV->isExternal())) {
+ break;
+ } else {
+ AM.GV = GV;
+ return false;
+ }
+ }
+ break;
+ case ISD::Constant:
+ AM.Disp += cast<ConstantSDNode>(N)->getValue();
+ return false;
+ case ISD::SHL:
+ if (AM.IndexReg.Val == 0 && AM.Scale == 1)
+ if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.Val->getOperand(1))) {
+ unsigned Val = CN->getValue();
+ if (Val == 1 || Val == 2 || Val == 3) {
+ AM.Scale = 1 << Val;
+ SDOperand ShVal = N.Val->getOperand(0);
+
+ // Okay, we know that we have a scale by now. However, if the scaled
+ // value is an add of something and a constant, we can fold the
+ // constant into the disp field here.
+ if (ShVal.Val->getOpcode() == ISD::ADD && ShVal.hasOneUse() &&
+ isa<ConstantSDNode>(ShVal.Val->getOperand(1))) {
+ AM.IndexReg = ShVal.Val->getOperand(0);
+ ConstantSDNode *AddVal =
+ cast<ConstantSDNode>(ShVal.Val->getOperand(1));
+ AM.Disp += AddVal->getValue() << Val;
+ } else {
+ AM.IndexReg = ShVal;
+ }
+ return false;
+ }
+ }
+ break;
+ case ISD::MUL:
+ // X*[3,5,9] -> X+X*[2,4,8]
+ if (AM.IndexReg.Val == 0 && AM.BaseType == X86ISelAddressMode::RegBase &&
+ AM.Base.Reg.Val == 0)
+ if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.Val->getOperand(1)))
+ if (CN->getValue() == 3 || CN->getValue() == 5 || CN->getValue() == 9) {
+ AM.Scale = unsigned(CN->getValue())-1;
+
+ SDOperand MulVal = N.Val->getOperand(0);
+ SDOperand Reg;
+
+ // Okay, we know that we have a scale by now. However, if the scaled
+ // value is an add of something and a constant, we can fold the
+ // constant into the disp field here.
+ if (MulVal.Val->getOpcode() == ISD::ADD && MulVal.hasOneUse() &&
+ isa<ConstantSDNode>(MulVal.Val->getOperand(1))) {
+ Reg = MulVal.Val->getOperand(0);
+ ConstantSDNode *AddVal =
+ cast<ConstantSDNode>(MulVal.Val->getOperand(1));
+ AM.Disp += AddVal->getValue() * CN->getValue();
+ } else {
+ Reg = N.Val->getOperand(0);
+ }
+
+ AM.IndexReg = AM.Base.Reg = Reg;
+ return false;
+ }
+ break;
+
+ case ISD::ADD: {
+ X86ISelAddressMode Backup = AM;
+ if (!MatchAddress(N.Val->getOperand(0), AM) &&
+ !MatchAddress(N.Val->getOperand(1), AM))
+ return false;
+ AM = Backup;
+ if (!MatchAddress(N.Val->getOperand(1), AM) &&
+ !MatchAddress(N.Val->getOperand(0), AM))
+ return false;
+ AM = Backup;
+ break;
+ }
+ }
+
+ // Is the base register already occupied?
+ if (AM.BaseType != X86ISelAddressMode::RegBase || AM.Base.Reg.Val) {
+ // If so, check to see if the scale index register is set.
+ if (AM.IndexReg.Val == 0) {
+ AM.IndexReg = N;
+ AM.Scale = 1;
+ return false;
+ }
+
+ // Otherwise, we cannot select it.
+ return true;
+ }
+
+ // Default, generate it as a register.
+ AM.BaseType = X86ISelAddressMode::RegBase;
+ AM.Base.Reg = N;
+ return false;
+}
+