LLVMContext *Context;
bool TargetSupported;
+ bool UnsupportedFPMode;
public:
explicit MipsFastISel(FunctionLoweringInfo &funcInfo,
TargetSupported = ((Subtarget->getRelocationModel() == Reloc::PIC_) &&
((Subtarget->hasMips32r2() || Subtarget->hasMips32()) &&
(Subtarget->isABI_O32())));
+ UnsupportedFPMode = Subtarget->isFP64bit();
}
bool fastSelectInstruction(const Instruction *I) override;
bool SelectTrunc(const Instruction *I);
bool SelectFPExt(const Instruction *I);
bool SelectFPTrunc(const Instruction *I);
+ bool SelectFPToI(const Instruction *I, bool IsSigned);
bool isTypeLegal(Type *Ty, MVT &VT);
bool isLoadTypeLegal(Type *Ty, MVT &VT);
break;
}
case MVT::f32: {
+ if (UnsupportedFPMode)
+ return false;
ResultReg = createResultReg(&Mips::FGR32RegClass);
Opc = Mips::LWC1;
break;
}
case MVT::f64: {
+ if (UnsupportedFPMode)
+ return false;
ResultReg = createResultReg(&Mips::AFGR64RegClass);
Opc = Mips::LDC1;
break;
MVT VT = CEVT.getSimpleVT();
if (const ConstantFP *CFP = dyn_cast<ConstantFP>(C))
- return MaterializeFP(CFP, VT);
+ return (UnsupportedFPMode) ? 0 : MaterializeFP(CFP, VT);
else if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
return MaterializeGV(GV, VT);
else if (isa<ConstantInt>(C))
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;
break;
default:
// Attempt to fast-select a floating-point extend instruction.
bool MipsFastISel::SelectFPExt(const Instruction *I) {
+ if (UnsupportedFPMode)
+ return false;
Value *Src = I->getOperand(0);
EVT SrcVT = TLI.getValueType(Src->getType(), true);
EVT DestVT = TLI.getValueType(I->getType(), true);
// Attempt to fast-select a floating-point truncate instruction.
bool MipsFastISel::SelectFPTrunc(const Instruction *I) {
+ if (UnsupportedFPMode)
+ return false;
Value *Src = I->getOperand(0);
EVT SrcVT = TLI.getValueType(Src->getType(), true);
EVT DestVT = TLI.getValueType(I->getType(), true);
return true;
}
+// Attempt to fast-select a floating-point-to-integer conversion.
+bool MipsFastISel::SelectFPToI(const Instruction *I, bool IsSigned) {
+ if (UnsupportedFPMode)
+ return false;
+ MVT DstVT, SrcVT;
+ if (!IsSigned)
+ return false; // We don't handle this case yet. There is no native
+ // instruction for this but it can be synthesized.
+ Type *DstTy = I->getType();
+ if (!isTypeLegal(DstTy, DstVT))
+ return false;
+
+ if (DstVT != MVT::i32)
+ return false;
+
+ Value *Src = I->getOperand(0);
+ Type *SrcTy = Src->getType();
+ if (!isTypeLegal(SrcTy, SrcVT))
+ return false;
+
+ if (SrcVT != MVT::f32 && SrcVT != MVT::f64)
+ return false;
+
+ unsigned SrcReg = getRegForValue(Src);
+ if (SrcReg == 0)
+ return false;
+
+ // Determine the opcode for the conversion, which takes place
+ // entirely within FPRs.
+ unsigned DestReg = createResultReg(&Mips::GPR32RegClass);
+ unsigned TempReg = createResultReg(&Mips::FGR32RegClass);
+ unsigned Opc;
+
+ if (SrcVT == MVT::f32)
+ Opc = Mips::TRUNC_W_S;
+ else
+ Opc = Mips::TRUNC_W_D32;
+
+ // Generate the convert.
+ EmitInst(Opc, TempReg).addReg(SrcReg);
+
+ EmitInst(Mips::MFC1, DestReg).addReg(TempReg);
+
+ updateValueMap(I, DestReg);
+ return true;
+}
+
bool MipsFastISel::fastSelectInstruction(const Instruction *I) {
if (!TargetSupported)
return false;
return SelectFPTrunc(I);
case Instruction::FPExt:
return SelectFPExt(I);
+ case Instruction::FPToSI:
+ return SelectFPToI(I, /*isSigned*/ true);
+ case Instruction::FPToUI:
+ return SelectFPToI(I, /*isSigned*/ 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;
--- /dev/null
+; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32r2 \
+; RUN: < %s | FileCheck %s
+; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32 \
+; RUN: < %s | FileCheck %s
+
+
+@f = global float 0x40D6E83280000000, align 4
+@d = global double 0x4132D68780000000, align 8
+@i_f = common global i32 0, align 4
+@i_d = common global i32 0, align 4
+@.str = private unnamed_addr constant [5 x i8] c"%i \0A\00", align 1
+
+; Function Attrs: nounwind
+define void @ifv() {
+entry:
+; CHECK-LABEL: .ent ifv
+ %0 = load float* @f, align 4
+ %conv = fptosi float %0 to i32
+; CHECK: trunc.w.s $f[[REG:[0-9]+]], $f{{[0-9]+}}
+; CHECK: mfc1 ${{[0-9]+}}, $f[[REG]]
+ store i32 %conv, i32* @i_f, align 4
+ ret void
+}
+
+; Function Attrs: nounwind
+define void @idv() {
+entry:
+; CHECK-LABEL: .ent idv
+ %0 = load double* @d, align 8
+ %conv = fptosi double %0 to i32
+; CHECK: trunc.w.d $f[[REG:[0-9]+]], $f{{[0-9]+}}
+; CHECK: mfc1 ${{[0-9]+}}, $f[[REG]]
+ store i32 %conv, i32* @i_d, align 4
+ ret void
+}