From 7c9f20a7a158ea30855d41a37e732d7e16c23043 Mon Sep 17 00:00:00 2001 From: Reed Kotler Date: Fri, 10 Oct 2014 17:00:46 +0000 Subject: [PATCH] Implement floating point to integer conversion in mips fast-isel Summary: Add the ability to convert 64 or 32 bit floating point values to integer in mips fast-isel Test Plan: fpintconv.ll ran 4 flavors of test-suite with no errors, misp32 r1/r2 O0/O2 Reviewers: dsanders Reviewed By: dsanders Subscribers: llvm-commits, rfuhler, mcrosier Differential Revision: http://reviews.llvm.org/D5562 llvm-svn: 219511 --- lib/Target/Mips/MipsFastISel.cpp | 70 +++++++++++++++++++++++- test/CodeGen/Mips/Fast-ISel/fpintconv.ll | 35 ++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 test/CodeGen/Mips/Fast-ISel/fpintconv.ll diff --git a/lib/Target/Mips/MipsFastISel.cpp b/lib/Target/Mips/MipsFastISel.cpp index 14cf86f0b77..63299f9b988 100644 --- a/lib/Target/Mips/MipsFastISel.cpp +++ b/lib/Target/Mips/MipsFastISel.cpp @@ -48,6 +48,7 @@ class MipsFastISel final : public FastISel { LLVMContext *Context; bool TargetSupported; + bool UnsupportedFPMode; public: explicit MipsFastISel(FunctionLoweringInfo &funcInfo, @@ -63,6 +64,7 @@ public: TargetSupported = ((Subtarget->getRelocationModel() == Reloc::PIC_) && ((Subtarget->hasMips32r2() || Subtarget->hasMips32()) && (Subtarget->isABI_O32()))); + UnsupportedFPMode = Subtarget->isFP64bit(); } bool fastSelectInstruction(const Instruction *I) override; @@ -82,6 +84,7 @@ private: 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); @@ -191,11 +194,15 @@ bool MipsFastISel::EmitLoad(MVT VT, unsigned &ResultReg, Address &Addr, 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; @@ -218,7 +225,7 @@ unsigned MipsFastISel::fastMaterializeConstant(const Constant *C) { MVT VT = CEVT.getSimpleVT(); if (const ConstantFP *CFP = dyn_cast(C)) - return MaterializeFP(CFP, VT); + return (UnsupportedFPMode) ? 0 : MaterializeFP(CFP, VT); else if (const GlobalValue *GV = dyn_cast(C)) return MaterializeGV(GV, VT); else if (isa(C)) @@ -244,9 +251,13 @@ bool MipsFastISel::EmitStore(MVT VT, unsigned SrcReg, Address &Addr, 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: @@ -388,6 +399,8 @@ bool MipsFastISel::SelectRet(const Instruction *I) { // 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); @@ -409,6 +422,8 @@ bool MipsFastISel::SelectFPExt(const Instruction *I) { // 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); @@ -481,6 +496,53 @@ bool MipsFastISel::SelectTrunc(const Instruction *I) { 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; @@ -502,11 +564,17 @@ bool MipsFastISel::fastSelectInstruction(const Instruction *I) { 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; diff --git a/test/CodeGen/Mips/Fast-ISel/fpintconv.ll b/test/CodeGen/Mips/Fast-ISel/fpintconv.ll new file mode 100644 index 00000000000..846726a868b --- /dev/null +++ b/test/CodeGen/Mips/Fast-ISel/fpintconv.ll @@ -0,0 +1,35 @@ +; 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 +}