};
} // 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<ConstantInt>(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<GlobalVariable>(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<Function>(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<ConstantFP>(C))
+ return (UnsupportedFPMode) ? 0 : materializeFP(CFP, VT);
+ else if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
+ return materializeGV(GV, VT);
+ else if (isa<ConstantInt>(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<Instruction>(Obj))
+ return false;
+ else if (isa<ConstantExpr>(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.
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<Instruction>(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<ConstantExpr>(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:
+ llvm_unreachable("Only switching of a subset of CCs.");
+ }
+ 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<ConstantFP>(C))
- return (UnsupportedFPMode) ? 0 : materializeFP(CFP, VT);
- else if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
- return materializeGV(GV, VT);
- else if (isa<ConstantInt>(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<BranchInst>(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<CmpInst>(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) {
return true;
}
-bool MipsFastISel::selectRet(const Instruction *I) {
- const ReturnInst *Ret = cast<ReturnInst>(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<BranchInst>(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<CmpInst>(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<CmpInst>(I);
+ unsigned ResultReg = createResultReg(&Mips::GPR32RegClass);
+ if (!emitCmp(ResultReg, CI))
return false;
- }
- emitInst(Mips::RetRA);
+ updateValueMap(I, ResultReg);
return true;
}
return true;
}
-bool MipsFastISel::selectIntExt(const Instruction *I) {
- Type *DestTy = I->getType();
- Value *Src = I->getOperand(0);
- Type *SrcTy = Src->getType();
-
- bool isZExt = isa<ZExtInst>(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)
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<ReturnInst>(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<ZExtInst>(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);
- 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);
- 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);
+ case MVT::i8:
+ ShiftAmt = 24;
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);
+ case MVT::i16:
+ ShiftAmt = 16;
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);
+ 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::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:
- llvm_unreachable("Only switching of a subset of CCs.");
- }
- 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::SEH, DestReg).addReg(SrcReg);
break;
}
- }
return true;
}
-bool MipsFastISel::selectCmp(const Instruction *I) {
- const CmpInst *CI = cast<CmpInst>(I);
- unsigned ResultReg = createResultReg(&Mips::GPR32RegClass);
- if (!emitCmp(ResultReg, CI))
+bool MipsFastISel::emitIntSExt(MVT SrcVT, unsigned SrcReg, MVT DestVT,
+ unsigned DestReg) {
+ if ((DestVT != MVT::i32) && (DestVT != MVT::i16))
return false;
- updateValueMap(I, ResultReg);
+ 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);
+ }
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;
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<GlobalVariable>(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<Function>(GV)))) {
- unsigned TempReg = createResultReg(RC);
- emitInst(Mips::ADDiu, TempReg)
- .addReg(DestReg)
- .addGlobalAddress(GV, 0, MipsII::MO_ABS_LO);
- DestReg = TempReg;
- }
- return DestReg;
-}
-
-unsigned MipsFastISel::materializeInt(const Constant *C, MVT VT) {
- if (VT != MVT::i32 && VT != MVT::i16 && VT != MVT::i8 && VT != MVT::i1)
+unsigned MipsFastISel::getRegEnsuringSimpleIntegerWidening(const Value *V,
+ bool IsUnsigned) {
+ unsigned VReg = getRegForValue(V);
+ if (VReg == 0)
return 0;
- const TargetRegisterClass *RC = &Mips::GPR32RegClass;
- const ConstantInt *CI = cast<ConstantInt>(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);
+ 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 ResultReg;
+ return VReg;
}
namespace llvm {