X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FMips%2FMipsISelDAGToDAG.cpp;h=f1d4a67c81a259f23baa5b93c3c07cf5bd219ecc;hb=518bb53485df640d7b7e3f6b0544099020c42aa7;hp=810dce1f28422df9da384c57f56125fcd3611e6e;hpb=f5a86f45e75ec744c203270ffa03659eb0a220c1;p=oota-llvm.git diff --git a/lib/Target/Mips/MipsISelDAGToDAG.cpp b/lib/Target/Mips/MipsISelDAGToDAG.cpp index 810dce1f284..f1d4a67c81a 100644 --- a/lib/Target/Mips/MipsISelDAGToDAG.cpp +++ b/lib/Target/Mips/MipsISelDAGToDAG.cpp @@ -84,12 +84,14 @@ private: } SDNode *getGlobalBaseReg(); - SDNode *Select(SDValue N); + SDNode *Select(SDNode *N); // Complex Pattern. - bool SelectAddr(SDValue Op, SDValue N, + bool SelectAddr(SDNode *Op, SDValue N, SDValue &Base, SDValue &Offset); + SDNode *SelectLoadFp64(SDNode *N); + SDNode *SelectStoreFp64(SDNode *N); // getI32Imm - Return a target constant with the specified // value, of type i32. @@ -108,7 +110,6 @@ private: /// InstructionSelect - This callback is invoked by /// SelectionDAGISel when it has created a SelectionDAG for us to codegen. void MipsDAGToDAGISel::InstructionSelect() { - DEBUG(BB->dump()); // Codegen the basic block. DEBUG(errs() << "===== Instruction selection begins:\n"); DEBUG(Indent = 0); @@ -131,7 +132,7 @@ SDNode *MipsDAGToDAGISel::getGlobalBaseReg() { /// ComplexPattern used on MipsInstrInfo /// Used on Mips Load/Store instructions bool MipsDAGToDAGISel:: -SelectAddr(SDValue Op, SDValue Addr, SDValue &Offset, SDValue &Base) +SelectAddr(SDNode *Op, SDValue Addr, SDValue &Offset, SDValue &Base) { // if Address is FI, get the TargetFrameIndex. if (FrameIndexSDNode *FIN = dyn_cast(Addr)) { @@ -143,6 +144,7 @@ SelectAddr(SDValue Op, SDValue Addr, SDValue &Offset, SDValue &Base) // on PIC code Load GA if (TM.getRelocationModel() == Reloc::PIC_) { if ((Addr.getOpcode() == ISD::TargetGlobalAddress) || + (Addr.getOpcode() == ISD::TargetConstantPool) || (Addr.getOpcode() == ISD::TargetJumpTable)){ Base = CurDAG->getRegister(Mips::GP, MVT::i32); Offset = Addr; @@ -171,6 +173,25 @@ SelectAddr(SDValue Op, SDValue Addr, SDValue &Offset, SDValue &Base) return true; } } + + // When loading from constant pools, load the lower address part in + // the instruction itself. Example, instead of: + // lui $2, %hi($CPI1_0) + // addiu $2, $2, %lo($CPI1_0) + // lwc1 $f0, 0($2) + // Generate: + // lui $2, %hi($CPI1_0) + // lwc1 $f0, %lo($CPI1_0)($2) + if ((Addr.getOperand(0).getOpcode() == MipsISD::Hi || + Addr.getOperand(0).getOpcode() == ISD::LOAD) && + Addr.getOperand(1).getOpcode() == MipsISD::Lo) { + SDValue LoVal = Addr.getOperand(1); + if (dyn_cast(LoVal.getOperand(0))) { + Base = Addr.getOperand(0); + Offset = LoVal.getOperand(0); + return true; + } + } } Base = Addr; @@ -178,10 +199,132 @@ SelectAddr(SDValue Op, SDValue Addr, SDValue &Offset, SDValue &Base) return true; } +SDNode *MipsDAGToDAGISel::SelectLoadFp64(SDNode *N) { + MVT::SimpleValueType NVT = + N->getValueType(0).getSimpleVT().SimpleTy; + + if (!Subtarget.isMips1() || NVT != MVT::f64) + return NULL; + + if (!Predicate_unindexedload(N) || + !Predicate_load(N)) + return NULL; + + SDValue Chain = N->getOperand(0); + SDValue N1 = N->getOperand(1); + SDValue Offset0, Offset1, Base; + + if (!SelectAddr(N, N1, Offset0, Base) || + N1.getValueType() != MVT::i32) + return NULL; + + MachineSDNode::mmo_iterator MemRefs0 = MF->allocateMemRefsArray(1); + MemRefs0[0] = cast(N)->getMemOperand(); + DebugLoc dl = N->getDebugLoc(); + + // The second load should start after for 4 bytes. + if (ConstantSDNode *C = dyn_cast(Offset0)) + Offset1 = CurDAG->getTargetConstant(C->getSExtValue()+4, MVT::i32); + else if (ConstantPoolSDNode *CP = dyn_cast(Offset0)) + Offset1 = CurDAG->getTargetConstantPool(CP->getConstVal(), + MVT::i32, + CP->getAlignment(), + CP->getOffset()+4, + CP->getTargetFlags()); + else + return NULL; + + // Choose the offsets depending on the endianess + if (TM.getTargetData()->isBigEndian()) + std::swap(Offset0, Offset1); + + // Instead of: + // ldc $f0, X($3) + // Generate: + // lwc $f0, X($3) + // lwc $f1, X+4($3) + SDNode *LD0 = CurDAG->getMachineNode(Mips::LWC1, dl, MVT::f32, + MVT::Other, Offset0, Base, Chain); + SDValue Undef = SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, + dl, NVT), 0); + SDValue I0 = CurDAG->getTargetInsertSubreg(Mips::SUBREG_FPEVEN, dl, + MVT::f64, Undef, SDValue(LD0, 0)); + + SDNode *LD1 = CurDAG->getMachineNode(Mips::LWC1, dl, MVT::f32, + MVT::Other, Offset1, Base, SDValue(LD0, 1)); + SDValue I1 = CurDAG->getTargetInsertSubreg(Mips::SUBREG_FPODD, dl, + MVT::f64, I0, SDValue(LD1, 0)); + + ReplaceUses(SDValue(N, 0), I1); + ReplaceUses(SDValue(N, 1), Chain); + cast(LD0)->setMemRefs(MemRefs0, MemRefs0 + 1); + cast(LD1)->setMemRefs(MemRefs0, MemRefs0 + 1); + return I1.getNode(); +} + +SDNode *MipsDAGToDAGISel::SelectStoreFp64(SDNode *N) { + + if (!Subtarget.isMips1() || + N->getOperand(1).getValueType() != MVT::f64) + return NULL; + + SDValue Chain = N->getOperand(0); + + if (!Predicate_unindexedstore(N) || + !Predicate_store(N)) + return NULL; + + SDValue N1 = N->getOperand(1); + SDValue N2 = N->getOperand(2); + SDValue Offset0, Offset1, Base; + + if (!SelectAddr(N, N2, Offset0, Base) || + N1.getValueType() != MVT::f64 || + N2.getValueType() != MVT::i32) + return NULL; + + MachineSDNode::mmo_iterator MemRefs0 = MF->allocateMemRefsArray(1); + MemRefs0[0] = cast(N)->getMemOperand(); + DebugLoc dl = N->getDebugLoc(); + + // Get the even and odd part from the f64 register + SDValue FPOdd = CurDAG->getTargetExtractSubreg(Mips::SUBREG_FPODD, + dl, MVT::f32, N1); + SDValue FPEven = CurDAG->getTargetExtractSubreg(Mips::SUBREG_FPEVEN, + dl, MVT::f32, N1); + + // The second store should start after for 4 bytes. + if (ConstantSDNode *C = dyn_cast(Offset0)) + Offset1 = CurDAG->getTargetConstant(C->getSExtValue()+4, MVT::i32); + else + return NULL; + + // Choose the offsets depending on the endianess + if (TM.getTargetData()->isBigEndian()) + std::swap(Offset0, Offset1); + + // Instead of: + // sdc $f0, X($3) + // Generate: + // swc $f0, X($3) + // swc $f1, X+4($3) + SDValue Ops0[] = { FPEven, Offset0, Base, Chain }; + Chain = SDValue(CurDAG->getMachineNode(Mips::SWC1, dl, + MVT::Other, Ops0, 4), 0); + cast(Chain.getNode())->setMemRefs(MemRefs0, MemRefs0 + 1); + + SDValue Ops1[] = { FPOdd, Offset1, Base, Chain }; + Chain = SDValue(CurDAG->getMachineNode(Mips::SWC1, dl, + MVT::Other, Ops1, 4), 0); + cast(Chain.getNode())->setMemRefs(MemRefs0, MemRefs0 + 1); + + ReplaceUses(SDValue(N, 0), Chain); + return Chain.getNode(); +} + /// Select instructions not customized! Used for /// expanded, promoted and normal instructions -SDNode* MipsDAGToDAGISel::Select(SDValue N) { - SDNode *Node = N.getNode(); +SDNode* MipsDAGToDAGISel::Select(SDNode *Node) { unsigned Opcode = Node->getOpcode(); DebugLoc dl = Node->getDebugLoc(); @@ -235,7 +378,7 @@ SDNode* MipsDAGToDAGISel::Select(SDValue N) { SDNode *AddCarry = CurDAG->getMachineNode(Mips::ADDu, dl, VT, SDValue(Carry,0), RHS); - return CurDAG->SelectNodeTo(N.getNode(), MOp, VT, MVT::Flag, + return CurDAG->SelectNodeTo(Node, MOp, VT, MVT::Flag, LHS, SDValue(AddCarry,0)); } @@ -253,19 +396,19 @@ SDNode* MipsDAGToDAGISel::Select(SDValue N) { else Op = (Opcode == ISD::UDIVREM ? Mips::DIVu : Mips::DIV); - SDNode *Node = CurDAG->getMachineNode(Op, dl, MVT::Flag, Op1, Op2); + SDNode *MulDiv = CurDAG->getMachineNode(Op, dl, MVT::Flag, Op1, Op2); - SDValue InFlag = SDValue(Node, 0); + SDValue InFlag = SDValue(MulDiv, 0); SDNode *Lo = CurDAG->getMachineNode(Mips::MFLO, dl, MVT::i32, MVT::Flag, InFlag); InFlag = SDValue(Lo,1); SDNode *Hi = CurDAG->getMachineNode(Mips::MFHI, dl, MVT::i32, InFlag); - if (!N.getValue(0).use_empty()) - ReplaceUses(N.getValue(0), SDValue(Lo,0)); + if (!SDValue(Node, 0).use_empty()) + ReplaceUses(SDValue(Node, 0), SDValue(Lo,0)); - if (!N.getValue(1).use_empty()) - ReplaceUses(N.getValue(1), SDValue(Hi,0)); + if (!SDValue(Node, 1).use_empty()) + ReplaceUses(SDValue(Node, 1), SDValue(Hi,0)); return NULL; } @@ -283,7 +426,7 @@ SDNode* MipsDAGToDAGISel::Select(SDValue N) { SDValue InFlag = SDValue(MulNode, 0); - if (MulOp == ISD::MUL) + if (Opcode == ISD::MUL) return CurDAG->getMachineNode(Mips::MFLO, dl, MVT::i32, InFlag); else return CurDAG->getMachineNode(Mips::MFHI, dl, MVT::i32, InFlag); @@ -315,16 +458,51 @@ SDNode* MipsDAGToDAGISel::Select(SDValue N) { case ISD::GLOBAL_OFFSET_TABLE: return getGlobalBaseReg(); + case ISD::ConstantFP: { + ConstantFPSDNode *CN = dyn_cast(Node); + if (Node->getValueType(0) == MVT::f64 && CN->isExactlyValue(+0.0)) { + SDValue Zero = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl, + Mips::ZERO, MVT::i32); + SDValue Undef = SDValue( + CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, MVT::f64), 0); + SDNode *MTC = CurDAG->getMachineNode(Mips::MTC1, dl, MVT::f32, Zero); + SDValue I0 = CurDAG->getTargetInsertSubreg(Mips::SUBREG_FPEVEN, dl, + MVT::f64, Undef, SDValue(MTC, 0)); + SDValue I1 = CurDAG->getTargetInsertSubreg(Mips::SUBREG_FPODD, dl, + MVT::f64, I0, SDValue(MTC, 0)); + ReplaceUses(SDValue(Node, 0), I1); + return I1.getNode(); + } + break; + } + + case ISD::LOAD: + if (SDNode *ResNode = SelectLoadFp64(Node)) + return ResNode; + // Other cases are autogenerated. + break; + + case ISD::STORE: + if (SDNode *ResNode = SelectStoreFp64(Node)) + return ResNode; + // Other cases are autogenerated. + break; + /// Handle direct and indirect calls when using PIC. On PIC, when /// GOT is smaller than about 64k (small code) the GA target is /// loaded with only one instruction. Otherwise GA's target must /// be loaded with 3 instructions. case MipsISD::JmpLink: { if (TM.getRelocationModel() == Reloc::PIC_) { + unsigned LastOpNum = Node->getNumOperands()-1; + SDValue Chain = Node->getOperand(0); SDValue Callee = Node->getOperand(1); - SDValue T9Reg = CurDAG->getRegister(Mips::T9, MVT::i32); - SDValue InFlag(0, 0); + SDValue InFlag; + + // Skip the incomming flag if present + if (Node->getOperand(LastOpNum).getValueType() == MVT::Flag) + LastOpNum--; if ( (isa(Callee)) || (isa(Callee)) ) @@ -339,29 +517,39 @@ SDNode* MipsDAGToDAGISel::Select(SDValue N) { Chain = Load.getValue(1); // Call target must be on T9 - Chain = CurDAG->getCopyToReg(Chain, dl, T9Reg, Load, InFlag); + Chain = CurDAG->getCopyToReg(Chain, dl, Mips::T9, Load, InFlag); } else /// Indirect call - Chain = CurDAG->getCopyToReg(Chain, dl, T9Reg, Callee, InFlag); + Chain = CurDAG->getCopyToReg(Chain, dl, Mips::T9, Callee, InFlag); + + // Map the JmpLink operands to JALR + SDVTList NodeTys = CurDAG->getVTList(MVT::Other, MVT::Flag); + SmallVector Ops; + Ops.push_back(CurDAG->getRegister(Mips::T9, MVT::i32)); + + for (unsigned i = 2, e = LastOpNum+1; i != e; ++i) + Ops.push_back(Node->getOperand(i)); + Ops.push_back(Chain); + Ops.push_back(Chain.getValue(1)); // Emit Jump and Link Register - SDNode *ResNode = CurDAG->getMachineNode(Mips::JALR, dl, MVT::Other, - MVT::Flag, T9Reg, Chain); - Chain = SDValue(ResNode, 0); - InFlag = SDValue(ResNode, 1); - ReplaceUses(SDValue(Node, 0), Chain); - ReplaceUses(SDValue(Node, 1), InFlag); + SDNode *ResNode = CurDAG->getMachineNode(Mips::JALR, dl, NodeTys, + &Ops[0], Ops.size()); + + // Replace Chain and InFlag + ReplaceUses(SDValue(Node, 0), SDValue(ResNode, 0)); + ReplaceUses(SDValue(Node, 1), SDValue(ResNode, 1)); return ResNode; } } } // Select the default instruction - SDNode *ResNode = SelectCode(N); + SDNode *ResNode = SelectCode(Node); DEBUG(errs().indent(Indent-2) << "=> "); - if (ResNode == NULL || ResNode == N.getNode()) - DEBUG(N.getNode()->dump(CurDAG)); + if (ResNode == NULL || ResNode == Node) + DEBUG(Node->dump(CurDAG)); else DEBUG(ResNode->dump(CurDAG)); DEBUG(errs() << "\n");