Index: lib/Target/Mips/MipsFastISel.cpp =================================================================== --- lib/Target/Mips/MipsFastISel.cpp +++ lib/Target/Mips/MipsFastISel.cpp @@ -166,6 +166,124 @@ }; } // end anonymous namespace. +unsigned MipsFastISel::materializeInt(const Constant *C, MVT VT) { + if (VT != MVT::i32 && VT != MVT::i16 && VT != MVT::i8 && VT != MVT::i1) + return 0; + const TargetRegisterClass *RC = &Mips::GPR32RegClass; + const ConstantInt *CI = cast(C); + int64_t Imm; + if ((VT != MVT::i1) && CI->isNegative()) + Imm = CI->getSExtValue(); + else + Imm = CI->getZExtValue(); + return materialize32BitInt(Imm, RC); +} + +unsigned MipsFastISel::materialize32BitInt(int64_t Imm, + const TargetRegisterClass *RC) { + unsigned ResultReg = createResultReg(RC); + + if (isInt<16>(Imm)) { + unsigned Opc = Mips::ADDiu; + emitInst(Opc, ResultReg).addReg(Mips::ZERO).addImm(Imm); + return ResultReg; + } else if (isUInt<16>(Imm)) { + emitInst(Mips::ORi, ResultReg).addReg(Mips::ZERO).addImm(Imm); + return ResultReg; + } + unsigned Lo = Imm & 0xFFFF; + unsigned Hi = (Imm >> 16) & 0xFFFF; + if (Lo) { + // Both Lo and Hi have nonzero bits. + unsigned TmpReg = createResultReg(RC); + emitInst(Mips::LUi, TmpReg).addImm(Hi); + emitInst(Mips::ORi, ResultReg).addReg(TmpReg).addImm(Lo); + } else { + emitInst(Mips::LUi, ResultReg).addImm(Hi); + } + return ResultReg; +} + +unsigned MipsFastISel::materializeFP(const ConstantFP *CFP, MVT VT) { + if (UnsupportedFPMode) + return 0; + int64_t Imm = CFP->getValueAPF().bitcastToAPInt().getZExtValue(); + if (VT == MVT::f32) { + const TargetRegisterClass *RC = &Mips::FGR32RegClass; + unsigned DestReg = createResultReg(RC); + unsigned TempReg = materialize32BitInt(Imm, &Mips::GPR32RegClass); + emitInst(Mips::MTC1, DestReg).addReg(TempReg); + return DestReg; + } else if (VT == MVT::f64) { + const TargetRegisterClass *RC = &Mips::AFGR64RegClass; + unsigned DestReg = createResultReg(RC); + unsigned TempReg1 = materialize32BitInt(Imm >> 32, &Mips::GPR32RegClass); + unsigned TempReg2 = + materialize32BitInt(Imm & 0xFFFFFFFF, &Mips::GPR32RegClass); + emitInst(Mips::BuildPairF64, DestReg).addReg(TempReg2).addReg(TempReg1); + return DestReg; + } + return 0; +} + +unsigned MipsFastISel::materializeGV(const GlobalValue *GV, MVT VT) { + // For now 32-bit only. + if (VT != MVT::i32) + return 0; + const TargetRegisterClass *RC = &Mips::GPR32RegClass; + unsigned DestReg = createResultReg(RC); + const GlobalVariable *GVar = dyn_cast(GV); + bool IsThreadLocal = GVar && GVar->isThreadLocal(); + // TLS not supported at this time. + if (IsThreadLocal) + return 0; + emitInst(Mips::LW, DestReg) + .addReg(MFI->getGlobalBaseReg()) + .addGlobalAddress(GV, 0, MipsII::MO_GOT); + if ((GV->hasInternalLinkage() || + (GV->hasLocalLinkage() && !isa(GV)))) { + unsigned TempReg = createResultReg(RC); + emitInst(Mips::ADDiu, TempReg) + .addReg(DestReg) + .addGlobalAddress(GV, 0, MipsII::MO_ABS_LO); + DestReg = TempReg; + } + return DestReg; +} + +// Materialize a constant into a register, and return the register +// number (or zero if we failed to handle it). +unsigned MipsFastISel::fastMaterializeConstant(const Constant *C) { + EVT CEVT = TLI.getValueType(C->getType(), true); + + // Only handle simple types. + if (!CEVT.isSimple()) + return 0; + MVT VT = CEVT.getSimpleVT(); + + if (const ConstantFP *CFP = dyn_cast(C)) + return (UnsupportedFPMode) ? 0 : materializeFP(CFP, VT); + else if (const GlobalValue *GV = dyn_cast(C)) + return materializeGV(GV, VT); + else if (isa(C)) + return materializeInt(C, VT); + + return 0; +} + +bool MipsFastISel::computeAddress(const Value *Obj, Address &Addr) { + // This construct looks a big awkward but it is how other ports handle this + // and as this function is more fully completed, these cases which + // return false will have additional code in them. + // + if (isa(Obj)) + return false; + else if (isa(Obj)) + return false; + Addr.setReg(getRegForValue(Obj)); + return Addr.getReg() != 0; +} + bool MipsFastISel::isTypeLegal(Type *Ty, MVT &VT) { EVT evt = TLI.getValueType(Ty, true); // Only handle simple types. @@ -188,229 +306,207 @@ return true; return false; } - -bool MipsFastISel::computeAddress(const Value *Obj, Address &Addr) { - // This construct looks a big awkward but it is how other ports handle this - // and as this function is more fully completed, these cases which - // return false will have additional code in them. - // - if (isa(Obj)) +// Because of how EmitCmp is called with fast-isel, you can +// end up with redundant "andi" instructions after the sequences emitted below. +// We should try and solve this issue in the future. +// +bool MipsFastISel::emitCmp(unsigned ResultReg, const CmpInst *CI) { + const Value *Left = CI->getOperand(0), *Right = CI->getOperand(1); + bool IsUnsigned = CI->isUnsigned(); + unsigned LeftReg = getRegEnsuringSimpleIntegerWidening(Left, IsUnsigned); + if (LeftReg == 0) return false; - else if (isa(Obj)) + unsigned RightReg = getRegEnsuringSimpleIntegerWidening(Right, IsUnsigned); + if (RightReg == 0) return false; - Addr.setReg(getRegForValue(Obj)); - return Addr.getReg() != 0; -} + CmpInst::Predicate P = CI->getPredicate(); -unsigned MipsFastISel::getRegEnsuringSimpleIntegerWidening(const Value *V, - bool IsUnsigned) { - unsigned VReg = getRegForValue(V); - if (VReg == 0) - return 0; - MVT VMVT = TLI.getValueType(V->getType(), true).getSimpleVT(); - if ((VMVT == MVT::i8) || (VMVT == MVT::i16)) { + switch (P) { + default: + return false; + case CmpInst::ICMP_EQ: { unsigned TempReg = createResultReg(&Mips::GPR32RegClass); - if (!emitIntExt(VMVT, VReg, MVT::i32, TempReg, IsUnsigned)) - return 0; - VReg = TempReg; + emitInst(Mips::XOR, TempReg).addReg(LeftReg).addReg(RightReg); + emitInst(Mips::SLTiu, ResultReg).addReg(TempReg).addImm(1); + break; } - return VReg; -} - -bool MipsFastISel::emitLoad(MVT VT, unsigned &ResultReg, Address &Addr, - unsigned Alignment) { - // - // more cases will be handled here in following patches. - // - unsigned Opc; - switch (VT.SimpleTy) { - case MVT::i32: { - ResultReg = createResultReg(&Mips::GPR32RegClass); - Opc = Mips::LW; + case CmpInst::ICMP_NE: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + emitInst(Mips::XOR, TempReg).addReg(LeftReg).addReg(RightReg); + emitInst(Mips::SLTu, ResultReg).addReg(Mips::ZERO).addReg(TempReg); break; } - case MVT::i16: { - ResultReg = createResultReg(&Mips::GPR32RegClass); - Opc = Mips::LHu; + case CmpInst::ICMP_UGT: { + emitInst(Mips::SLTu, ResultReg).addReg(RightReg).addReg(LeftReg); break; } - case MVT::i8: { - ResultReg = createResultReg(&Mips::GPR32RegClass); - Opc = Mips::LBu; + case CmpInst::ICMP_ULT: { + emitInst(Mips::SLTu, ResultReg).addReg(LeftReg).addReg(RightReg); break; } - case MVT::f32: { - if (UnsupportedFPMode) - return false; - ResultReg = createResultReg(&Mips::FGR32RegClass); - Opc = Mips::LWC1; + case CmpInst::ICMP_UGE: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + emitInst(Mips::SLTu, TempReg).addReg(LeftReg).addReg(RightReg); + emitInst(Mips::XORi, ResultReg).addReg(TempReg).addImm(1); break; } - case MVT::f64: { + case CmpInst::ICMP_ULE: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + emitInst(Mips::SLTu, TempReg).addReg(RightReg).addReg(LeftReg); + emitInst(Mips::XORi, ResultReg).addReg(TempReg).addImm(1); + break; + } + case CmpInst::ICMP_SGT: { + emitInst(Mips::SLT, ResultReg).addReg(RightReg).addReg(LeftReg); + break; + } + case CmpInst::ICMP_SLT: { + emitInst(Mips::SLT, ResultReg).addReg(LeftReg).addReg(RightReg); + break; + } + case CmpInst::ICMP_SGE: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + emitInst(Mips::SLT, TempReg).addReg(LeftReg).addReg(RightReg); + emitInst(Mips::XORi, ResultReg).addReg(TempReg).addImm(1); + break; + } + case CmpInst::ICMP_SLE: { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + emitInst(Mips::SLT, TempReg).addReg(RightReg).addReg(LeftReg); + emitInst(Mips::XORi, ResultReg).addReg(TempReg).addImm(1); + break; + } + case CmpInst::FCMP_OEQ: + case CmpInst::FCMP_UNE: + case CmpInst::FCMP_OLT: + case CmpInst::FCMP_OLE: + case CmpInst::FCMP_OGT: + case CmpInst::FCMP_OGE: { if (UnsupportedFPMode) return false; - ResultReg = createResultReg(&Mips::AFGR64RegClass); - Opc = Mips::LDC1; + bool IsFloat = Left->getType()->isFloatTy(); + bool IsDouble = Left->getType()->isDoubleTy(); + if (!IsFloat && !IsDouble) + return false; + unsigned Opc, CondMovOpc; + switch (P) { + case CmpInst::FCMP_OEQ: + Opc = IsFloat ? Mips::C_EQ_S : Mips::C_EQ_D32; + CondMovOpc = Mips::MOVT_I; + break; + case CmpInst::FCMP_UNE: + Opc = IsFloat ? Mips::C_EQ_S : Mips::C_EQ_D32; + CondMovOpc = Mips::MOVF_I; + break; + case CmpInst::FCMP_OLT: + Opc = IsFloat ? Mips::C_OLT_S : Mips::C_OLT_D32; + CondMovOpc = Mips::MOVT_I; + break; + case CmpInst::FCMP_OLE: + Opc = IsFloat ? Mips::C_OLE_S : Mips::C_OLE_D32; + CondMovOpc = Mips::MOVT_I; + break; + case CmpInst::FCMP_OGT: + Opc = IsFloat ? Mips::C_ULE_S : Mips::C_ULE_D32; + CondMovOpc = Mips::MOVF_I; + break; + case CmpInst::FCMP_OGE: + Opc = IsFloat ? Mips::C_ULT_S : Mips::C_ULT_D32; + CondMovOpc = Mips::MOVF_I; + break; + default: + break; + } + unsigned RegWithZero = createResultReg(&Mips::GPR32RegClass); + unsigned RegWithOne = createResultReg(&Mips::GPR32RegClass); + emitInst(Mips::ADDiu, RegWithZero).addReg(Mips::ZERO).addImm(0); + emitInst(Mips::ADDiu, RegWithOne).addReg(Mips::ZERO).addImm(1); + emitInst(Opc).addReg(LeftReg).addReg(RightReg).addReg( + Mips::FCC0, RegState::ImplicitDefine); + MachineInstrBuilder MI = emitInst(CondMovOpc, ResultReg) + .addReg(RegWithOne) + .addReg(Mips::FCC0) + .addReg(RegWithZero, RegState::Implicit); + MI->tieOperands(0, 3); break; } - default: - return false; } - emitInstLoad(Opc, ResultReg, Addr.getReg(), Addr.getOffset()); return true; } - -// Materialize a constant into a register, and return the register -// number (or zero if we failed to handle it). -unsigned MipsFastISel::fastMaterializeConstant(const Constant *C) { - EVT CEVT = TLI.getValueType(C->getType(), true); - - // Only handle simple types. - if (!CEVT.isSimple()) - return 0; - MVT VT = CEVT.getSimpleVT(); - - if (const ConstantFP *CFP = dyn_cast(C)) - return (UnsupportedFPMode) ? 0 : materializeFP(CFP, VT); - else if (const GlobalValue *GV = dyn_cast(C)) - return materializeGV(GV, VT); - else if (isa(C)) - return materializeInt(C, VT); - - return 0; -} - -bool MipsFastISel::emitStore(MVT VT, unsigned SrcReg, Address &Addr, - unsigned Alignment) { +bool MipsFastISel::emitLoad(MVT VT, unsigned &ResultReg, Address &Addr, + unsigned Alignment) { // // more cases will be handled here in following patches. // unsigned Opc; switch (VT.SimpleTy) { - case MVT::i8: - Opc = Mips::SB; - break; - case MVT::i16: - Opc = Mips::SH; - break; - case MVT::i32: - Opc = Mips::SW; - break; - case MVT::f32: - if (UnsupportedFPMode) - return false; - Opc = Mips::SWC1; - break; - case MVT::f64: - if (UnsupportedFPMode) - return false; - Opc = Mips::SDC1; + case MVT::i32: { + ResultReg = createResultReg(&Mips::GPR32RegClass); + Opc = Mips::LW; break; - default: - return false; } - emitInstStore(Opc, SrcReg, Addr.getReg(), Addr.getOffset()); - return true; -} - -bool MipsFastISel::emitIntSExt32r1(MVT SrcVT, unsigned SrcReg, MVT DestVT, - unsigned DestReg) { - unsigned ShiftAmt; - switch (SrcVT.SimpleTy) { - default: - return false; - case MVT::i8: - ShiftAmt = 24; + case MVT::i16: { + ResultReg = createResultReg(&Mips::GPR32RegClass); + Opc = Mips::LHu; break; - case MVT::i16: - ShiftAmt = 16; + } + case MVT::i8: { + ResultReg = createResultReg(&Mips::GPR32RegClass); + Opc = Mips::LBu; break; } - unsigned TempReg = createResultReg(&Mips::GPR32RegClass); - emitInst(Mips::SLL, TempReg).addReg(SrcReg).addImm(ShiftAmt); - emitInst(Mips::SRA, DestReg).addReg(TempReg).addImm(ShiftAmt); - return true; -} - -bool MipsFastISel::emitIntSExt32r2(MVT SrcVT, unsigned SrcReg, MVT DestVT, - unsigned DestReg) { - switch (SrcVT.SimpleTy) { - default: - return false; - case MVT::i8: - emitInst(Mips::SEB, DestReg).addReg(SrcReg); + case MVT::f32: { + if (UnsupportedFPMode) + return false; + ResultReg = createResultReg(&Mips::FGR32RegClass); + Opc = Mips::LWC1; break; - case MVT::i16: - emitInst(Mips::SEH, DestReg).addReg(SrcReg); + } + case MVT::f64: { + if (UnsupportedFPMode) + return false; + ResultReg = createResultReg(&Mips::AFGR64RegClass); + Opc = Mips::LDC1; break; } - return true; -} - -bool MipsFastISel::emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, - unsigned DestReg, bool IsZExt) { - if (IsZExt) - return emitIntZExt(SrcVT, SrcReg, DestVT, DestReg); - return emitIntSExt(SrcVT, SrcReg, DestVT, DestReg); -} - -bool MipsFastISel::emitIntSExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, - unsigned DestReg) { - if ((DestVT != MVT::i32) && (DestVT != MVT::i16)) - return false; - if (Subtarget->hasMips32r2()) - return emitIntSExt32r2(SrcVT, SrcReg, DestVT, DestReg); - return emitIntSExt32r1(SrcVT, SrcReg, DestVT, DestReg); -} - -bool MipsFastISel::emitIntZExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, - unsigned DestReg) { - switch (SrcVT.SimpleTy) { default: return false; - case MVT::i1: - emitInst(Mips::ANDi, DestReg).addReg(SrcReg).addImm(1); - break; - case MVT::i8: - emitInst(Mips::ANDi, DestReg).addReg(SrcReg).addImm(0xff); - break; - case MVT::i16: - emitInst(Mips::ANDi, DestReg).addReg(SrcReg).addImm(0xffff); - break; } + emitInstLoad(Opc, ResultReg, Addr.getReg(), Addr.getOffset()); return true; } -// -// This can cause a redundant sltiu to be generated. -// FIXME: try and eliminate this in a future patch. -// -bool MipsFastISel::selectBranch(const Instruction *I) { - const BranchInst *BI = cast(I); - MachineBasicBlock *BrBB = FuncInfo.MBB; +bool MipsFastISel::emitStore(MVT VT, unsigned SrcReg, Address &Addr, + unsigned Alignment) { // - // TBB is the basic block for the case where the comparison is true. - // FBB is the basic block for the case where the comparison is false. - // if (cond) goto TBB - // goto FBB - // TBB: + // more cases will be handled here in following patches. // - MachineBasicBlock *TBB = FuncInfo.MBBMap[BI->getSuccessor(0)]; - MachineBasicBlock *FBB = FuncInfo.MBBMap[BI->getSuccessor(1)]; - BI->getCondition(); - // For now, just try the simplest case where it's fed by a compare. - if (const CmpInst *CI = dyn_cast(BI->getCondition())) { - unsigned CondReg = createResultReg(&Mips::GPR32RegClass); - if (!emitCmp(CondReg, CI)) + unsigned Opc; + switch (VT.SimpleTy) { + case MVT::i8: + Opc = Mips::SB; + break; + case MVT::i16: + Opc = Mips::SH; + break; + case MVT::i32: + Opc = Mips::SW; + break; + case MVT::f32: + if (UnsupportedFPMode) return false; - BuildMI(*BrBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::BGTZ)) - .addReg(CondReg) - .addMBB(TBB); - fastEmitBranch(FBB, DbgLoc); - FuncInfo.MBB->addSuccessor(TBB); - return true; + Opc = Mips::SWC1; + break; + case MVT::f64: + if (UnsupportedFPMode) + return false; + Opc = Mips::SDC1; + break; + default: + return false; } - return false; + emitInstStore(Opc, SrcReg, Addr.getReg(), Addr.getOffset()); + return true; } bool MipsFastISel::selectLoad(const Instruction *I) { @@ -463,15 +559,44 @@ return true; } -bool MipsFastISel::selectRet(const Instruction *I) { - const ReturnInst *Ret = cast(I); +// +// This can cause a redundant sltiu to be generated. +// FIXME: try and eliminate this in a future patch. +// +bool MipsFastISel::selectBranch(const Instruction *I) { + const BranchInst *BI = cast(I); + MachineBasicBlock *BrBB = FuncInfo.MBB; + // + // TBB is the basic block for the case where the comparison is true. + // FBB is the basic block for the case where the comparison is false. + // if (cond) goto TBB + // goto FBB + // TBB: + // + MachineBasicBlock *TBB = FuncInfo.MBBMap[BI->getSuccessor(0)]; + MachineBasicBlock *FBB = FuncInfo.MBBMap[BI->getSuccessor(1)]; + BI->getCondition(); + // For now, just try the simplest case where it's fed by a compare. + if (const CmpInst *CI = dyn_cast(BI->getCondition())) { + unsigned CondReg = createResultReg(&Mips::GPR32RegClass); + if (!emitCmp(CondReg, CI)) + return false; + BuildMI(*BrBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::BGTZ)) + .addReg(CondReg) + .addMBB(TBB); + fastEmitBranch(FBB, DbgLoc); + FuncInfo.MBB->addSuccessor(TBB); + return true; + } + return false; +} - if (!FuncInfo.CanLowerReturn) - return false; - if (Ret->getNumOperands() > 0) { +bool MipsFastISel::selectCmp(const Instruction *I) { + const CmpInst *CI = cast(I); + unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); + if (!emitCmp(ResultReg, CI)) return false; - } - emitInst(Mips::RetRA); + updateValueMap(I, ResultReg); return true; } @@ -522,58 +647,6 @@ return true; } -bool MipsFastISel::selectIntExt(const Instruction *I) { - Type *DestTy = I->getType(); - Value *Src = I->getOperand(0); - Type *SrcTy = Src->getType(); - - bool isZExt = isa(I); - unsigned SrcReg = getRegForValue(Src); - if (!SrcReg) - return false; - - EVT SrcEVT, DestEVT; - SrcEVT = TLI.getValueType(SrcTy, true); - DestEVT = TLI.getValueType(DestTy, true); - if (!SrcEVT.isSimple()) - return false; - if (!DestEVT.isSimple()) - return false; - - MVT SrcVT = SrcEVT.getSimpleVT(); - MVT DestVT = DestEVT.getSimpleVT(); - unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); - - if (!emitIntExt(SrcVT, SrcReg, DestVT, ResultReg, isZExt)) - return false; - updateValueMap(I, ResultReg); - return true; -} - -bool MipsFastISel::selectTrunc(const Instruction *I) { - // The high bits for a type smaller than the register size are assumed to be - // undefined. - Value *Op = I->getOperand(0); - - EVT SrcVT, DestVT; - SrcVT = TLI.getValueType(Op->getType(), true); - DestVT = TLI.getValueType(I->getType(), true); - - if (SrcVT != MVT::i32 && SrcVT != MVT::i16 && SrcVT != MVT::i8) - return false; - if (DestVT != MVT::i16 && DestVT != MVT::i8 && DestVT != MVT::i1) - return false; - - unsigned SrcReg = getRegForValue(Op); - if (!SrcReg) - return false; - - // Because the high bits are undefined, a truncate doesn't generate - // any code. - updateValueMap(I, SrcReg); - return true; -} - // Attempt to fast-select a floating-point-to-integer conversion. bool MipsFastISel::selectFPToInt(const Instruction *I, bool IsSigned) { if (UnsupportedFPMode) @@ -621,143 +694,135 @@ return true; } // -// Because of how EmitCmp is called with fast-isel, you can -// end up with redundant "andi" instructions after the sequences emitted below. -// We should try and solve this issue in the future. -// -bool MipsFastISel::emitCmp(unsigned ResultReg, const CmpInst *CI) { - const Value *Left = CI->getOperand(0), *Right = CI->getOperand(1); - bool IsUnsigned = CI->isUnsigned(); - unsigned LeftReg = getRegEnsuringSimpleIntegerWidening(Left, IsUnsigned); - if (LeftReg == 0) +bool MipsFastISel::selectRet(const Instruction *I) { + const ReturnInst *Ret = cast(I); + + if (!FuncInfo.CanLowerReturn) return false; - unsigned RightReg = getRegEnsuringSimpleIntegerWidening(Right, IsUnsigned); - if (RightReg == 0) + if (Ret->getNumOperands() > 0) { return false; - CmpInst::Predicate P = CI->getPredicate(); + } + emitInst(Mips::RetRA); + return true; +} + +bool MipsFastISel::selectTrunc(const Instruction *I) { + // The high bits for a type smaller than the register size are assumed to be + // undefined. + Value *Op = I->getOperand(0); + + EVT SrcVT, DestVT; + SrcVT = TLI.getValueType(Op->getType(), true); + DestVT = TLI.getValueType(I->getType(), true); + + if (SrcVT != MVT::i32 && SrcVT != MVT::i16 && SrcVT != MVT::i8) + return false; + if (DestVT != MVT::i16 && DestVT != MVT::i8 && DestVT != MVT::i1) + return false; + + unsigned SrcReg = getRegForValue(Op); + if (!SrcReg) + return false; + + // Because the high bits are undefined, a truncate doesn't generate + // any code. + updateValueMap(I, SrcReg); + return true; +} +bool MipsFastISel::selectIntExt(const Instruction *I) { + Type *DestTy = I->getType(); + Value *Src = I->getOperand(0); + Type *SrcTy = Src->getType(); + + bool isZExt = isa(I); + unsigned SrcReg = getRegForValue(Src); + if (!SrcReg) + return false; + + EVT SrcEVT, DestEVT; + SrcEVT = TLI.getValueType(SrcTy, true); + DestEVT = TLI.getValueType(DestTy, true); + if (!SrcEVT.isSimple()) + return false; + if (!DestEVT.isSimple()) + return false; + + MVT SrcVT = SrcEVT.getSimpleVT(); + MVT DestVT = DestEVT.getSimpleVT(); + unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); - switch (P) { + if (!emitIntExt(SrcVT, SrcReg, DestVT, ResultReg, isZExt)) + return false; + updateValueMap(I, ResultReg); + return true; +} +bool MipsFastISel::emitIntSExt32r1(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg) { + unsigned ShiftAmt; + switch (SrcVT.SimpleTy) { default: return false; - case CmpInst::ICMP_EQ: { - unsigned TempReg = createResultReg(&Mips::GPR32RegClass); - emitInst(Mips::XOR, TempReg).addReg(LeftReg).addReg(RightReg); - emitInst(Mips::SLTiu, ResultReg).addReg(TempReg).addImm(1); - break; - } - case CmpInst::ICMP_NE: { - unsigned TempReg = createResultReg(&Mips::GPR32RegClass); - emitInst(Mips::XOR, TempReg).addReg(LeftReg).addReg(RightReg); - emitInst(Mips::SLTu, ResultReg).addReg(Mips::ZERO).addReg(TempReg); - break; - } - case CmpInst::ICMP_UGT: { - emitInst(Mips::SLTu, ResultReg).addReg(RightReg).addReg(LeftReg); - break; - } - case CmpInst::ICMP_ULT: { - emitInst(Mips::SLTu, ResultReg).addReg(LeftReg).addReg(RightReg); - break; - } - case CmpInst::ICMP_UGE: { - unsigned TempReg = createResultReg(&Mips::GPR32RegClass); - emitInst(Mips::SLTu, TempReg).addReg(LeftReg).addReg(RightReg); - emitInst(Mips::XORi, ResultReg).addReg(TempReg).addImm(1); + case MVT::i8: + ShiftAmt = 24; break; - } - case CmpInst::ICMP_ULE: { - unsigned TempReg = createResultReg(&Mips::GPR32RegClass); - emitInst(Mips::SLTu, TempReg).addReg(RightReg).addReg(LeftReg); - emitInst(Mips::XORi, ResultReg).addReg(TempReg).addImm(1); + case MVT::i16: + ShiftAmt = 16; break; } - case CmpInst::ICMP_SGT: { - emitInst(Mips::SLT, ResultReg).addReg(RightReg).addReg(LeftReg); + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + emitInst(Mips::SLL, TempReg).addReg(SrcReg).addImm(ShiftAmt); + emitInst(Mips::SRA, DestReg).addReg(TempReg).addImm(ShiftAmt); + return true; +} + +bool MipsFastISel::emitIntSExt32r2(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg) { + switch (SrcVT.SimpleTy) { + default: + return false; + case MVT::i8: + emitInst(Mips::SEB, DestReg).addReg(SrcReg); break; - } - case CmpInst::ICMP_SLT: { - emitInst(Mips::SLT, ResultReg).addReg(LeftReg).addReg(RightReg); + case MVT::i16: + emitInst(Mips::SEH, DestReg).addReg(SrcReg); break; } - case CmpInst::ICMP_SGE: { - unsigned TempReg = createResultReg(&Mips::GPR32RegClass); - emitInst(Mips::SLT, TempReg).addReg(LeftReg).addReg(RightReg); - emitInst(Mips::XORi, ResultReg).addReg(TempReg).addImm(1); + return true; +} + +bool MipsFastISel::emitIntSExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg) { + if ((DestVT != MVT::i32) && (DestVT != MVT::i16)) + return false; + if (Subtarget->hasMips32r2()) + return emitIntSExt32r2(SrcVT, SrcReg, DestVT, DestReg); + return emitIntSExt32r1(SrcVT, SrcReg, DestVT, DestReg); +} + +bool MipsFastISel::emitIntZExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg) { + switch (SrcVT.SimpleTy) { + default: + return false; + case MVT::i1: + emitInst(Mips::ANDi, DestReg).addReg(SrcReg).addImm(1); break; - } - case CmpInst::ICMP_SLE: { - unsigned TempReg = createResultReg(&Mips::GPR32RegClass); - emitInst(Mips::SLT, TempReg).addReg(RightReg).addReg(LeftReg); - emitInst(Mips::XORi, ResultReg).addReg(TempReg).addImm(1); + case MVT::i8: + emitInst(Mips::ANDi, DestReg).addReg(SrcReg).addImm(0xff); break; - } - case CmpInst::FCMP_OEQ: - case CmpInst::FCMP_UNE: - case CmpInst::FCMP_OLT: - case CmpInst::FCMP_OLE: - case CmpInst::FCMP_OGT: - case CmpInst::FCMP_OGE: { - if (UnsupportedFPMode) - return false; - bool IsFloat = Left->getType()->isFloatTy(); - bool IsDouble = Left->getType()->isDoubleTy(); - if (!IsFloat && !IsDouble) - return false; - unsigned Opc, CondMovOpc; - switch (P) { - case CmpInst::FCMP_OEQ: - Opc = IsFloat ? Mips::C_EQ_S : Mips::C_EQ_D32; - CondMovOpc = Mips::MOVT_I; - break; - case CmpInst::FCMP_UNE: - Opc = IsFloat ? Mips::C_EQ_S : Mips::C_EQ_D32; - CondMovOpc = Mips::MOVF_I; - break; - case CmpInst::FCMP_OLT: - Opc = IsFloat ? Mips::C_OLT_S : Mips::C_OLT_D32; - CondMovOpc = Mips::MOVT_I; - break; - case CmpInst::FCMP_OLE: - Opc = IsFloat ? Mips::C_OLE_S : Mips::C_OLE_D32; - CondMovOpc = Mips::MOVT_I; - break; - case CmpInst::FCMP_OGT: - Opc = IsFloat ? Mips::C_ULE_S : Mips::C_ULE_D32; - CondMovOpc = Mips::MOVF_I; - break; - case CmpInst::FCMP_OGE: - Opc = IsFloat ? Mips::C_ULT_S : Mips::C_ULT_D32; - CondMovOpc = Mips::MOVF_I; - break; - default: - break; - } - unsigned RegWithZero = createResultReg(&Mips::GPR32RegClass); - unsigned RegWithOne = createResultReg(&Mips::GPR32RegClass); - emitInst(Mips::ADDiu, RegWithZero).addReg(Mips::ZERO).addImm(0); - emitInst(Mips::ADDiu, RegWithOne).addReg(Mips::ZERO).addImm(1); - emitInst(Opc).addReg(LeftReg).addReg(RightReg).addReg( - Mips::FCC0, RegState::ImplicitDefine); - MachineInstrBuilder MI = emitInst(CondMovOpc, ResultReg) - .addReg(RegWithOne) - .addReg(Mips::FCC0) - .addReg(RegWithZero, RegState::Implicit); - MI->tieOperands(0, 3); + case MVT::i16: + emitInst(Mips::ANDi, DestReg).addReg(SrcReg).addImm(0xffff); break; } - } return true; } -bool MipsFastISel::selectCmp(const Instruction *I) { - const CmpInst *CI = cast(I); - unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); - if (!emitCmp(ResultReg, CI)) - return false; - updateValueMap(I, ResultReg); - return true; +bool MipsFastISel::emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg, bool IsZExt) { + if (IsZExt) + return emitIntZExt(SrcVT, SrcReg, DestVT, DestReg); + return emitIntSExt(SrcVT, SrcReg, DestVT, DestReg); } - bool MipsFastISel::fastSelectInstruction(const Instruction *I) { if (!TargetSupported) return false; @@ -792,90 +857,21 @@ return false; } -unsigned MipsFastISel::materializeFP(const ConstantFP *CFP, MVT VT) { - if (UnsupportedFPMode) - return 0; - int64_t Imm = CFP->getValueAPF().bitcastToAPInt().getZExtValue(); - if (VT == MVT::f32) { - const TargetRegisterClass *RC = &Mips::FGR32RegClass; - unsigned DestReg = createResultReg(RC); - unsigned TempReg = materialize32BitInt(Imm, &Mips::GPR32RegClass); - emitInst(Mips::MTC1, DestReg).addReg(TempReg); - return DestReg; - } else if (VT == MVT::f64) { - const TargetRegisterClass *RC = &Mips::AFGR64RegClass; - unsigned DestReg = createResultReg(RC); - unsigned TempReg1 = materialize32BitInt(Imm >> 32, &Mips::GPR32RegClass); - unsigned TempReg2 = - materialize32BitInt(Imm & 0xFFFFFFFF, &Mips::GPR32RegClass); - emitInst(Mips::BuildPairF64, DestReg).addReg(TempReg2).addReg(TempReg1); - return DestReg; - } - return 0; -} - -unsigned MipsFastISel::materializeGV(const GlobalValue *GV, MVT VT) { - // For now 32-bit only. - if (VT != MVT::i32) - return 0; - const TargetRegisterClass *RC = &Mips::GPR32RegClass; - unsigned DestReg = createResultReg(RC); - const GlobalVariable *GVar = dyn_cast(GV); - bool IsThreadLocal = GVar && GVar->isThreadLocal(); - // TLS not supported at this time. - if (IsThreadLocal) +unsigned MipsFastISel::getRegEnsuringSimpleIntegerWidening(const Value *V, + bool IsUnsigned) { + unsigned VReg = getRegForValue(V); + if (VReg == 0) return 0; - emitInst(Mips::LW, DestReg) - .addReg(MFI->getGlobalBaseReg()) - .addGlobalAddress(GV, 0, MipsII::MO_GOT); - if ((GV->hasInternalLinkage() || - (GV->hasLocalLinkage() && !isa(GV)))) { - unsigned TempReg = createResultReg(RC); - emitInst(Mips::ADDiu, TempReg) - .addReg(DestReg) - .addGlobalAddress(GV, 0, MipsII::MO_ABS_LO); - DestReg = TempReg; + MVT VMVT = TLI.getValueType(V->getType(), true).getSimpleVT(); + if ((VMVT == MVT::i8) || (VMVT == MVT::i16)) { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + if (!emitIntExt(VMVT, VReg, MVT::i32, TempReg, IsUnsigned)) + return 0; + VReg = TempReg; } - return DestReg; -} - -unsigned MipsFastISel::materializeInt(const Constant *C, MVT VT) { - if (VT != MVT::i32 && VT != MVT::i16 && VT != MVT::i8 && VT != MVT::i1) - return 0; - const TargetRegisterClass *RC = &Mips::GPR32RegClass; - const ConstantInt *CI = cast(C); - int64_t Imm; - if ((VT != MVT::i1) && CI->isNegative()) - Imm = CI->getSExtValue(); - else - Imm = CI->getZExtValue(); - return materialize32BitInt(Imm, RC); + return VReg; } -unsigned MipsFastISel::materialize32BitInt(int64_t Imm, - const TargetRegisterClass *RC) { - unsigned ResultReg = createResultReg(RC); - - if (isInt<16>(Imm)) { - unsigned Opc = Mips::ADDiu; - emitInst(Opc, ResultReg).addReg(Mips::ZERO).addImm(Imm); - return ResultReg; - } else if (isUInt<16>(Imm)) { - emitInst(Mips::ORi, ResultReg).addReg(Mips::ZERO).addImm(Imm); - return ResultReg; - } - unsigned Lo = Imm & 0xFFFF; - unsigned Hi = (Imm >> 16) & 0xFFFF; - if (Lo) { - // Both Lo and Hi have nonzero bits. - unsigned TmpReg = createResultReg(RC); - emitInst(Mips::LUi, TmpReg).addImm(Hi); - emitInst(Mips::ORi, ResultReg).addReg(TmpReg).addImm(Lo); - } else { - emitInst(Mips::LUi, ResultReg).addImm(Hi); - } - return ResultReg; -} namespace llvm { FastISel *Mips::createFastISel(FunctionLoweringInfo &funcInfo,