diff options
-rw-r--r-- | include/llvm/CodeGen/FastISel.h | 34 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/FastISel.cpp | 74 | ||||
-rw-r--r-- | test/CodeGen/X86/fast-isel.ll | 3 | ||||
-rw-r--r-- | utils/TableGen/FastISelEmitter.cpp | 13 |
4 files changed, 123 insertions, 1 deletions
diff --git a/include/llvm/CodeGen/FastISel.h b/include/llvm/CodeGen/FastISel.h index 9ed66f1..51c6bc2 100644 --- a/include/llvm/CodeGen/FastISel.h +++ b/include/llvm/CodeGen/FastISel.h @@ -20,6 +20,7 @@ namespace llvm { +class ConstantFP; class MachineBasicBlock; class MachineFunction; class MachineRegisterInfo; @@ -93,6 +94,15 @@ protected: ISD::NodeType Opcode, unsigned Op0, uint64_t Imm); + /// FastEmit_rf - This method is called by target-independent code + /// to request that an instruction with the given type, opcode, and + /// register and floating-point immediate operands be emitted. + /// + virtual unsigned FastEmit_rf(MVT::SimpleValueType VT, + MVT::SimpleValueType RetVT, + ISD::NodeType Opcode, + unsigned Op0, ConstantFP *FPImm); + /// FastEmit_rri - This method is called by target-independent code /// to request that an instruction with the given type, opcode, and /// register and immediate operands be emitted. @@ -111,6 +121,15 @@ protected: unsigned Op0, uint64_t Imm, MVT::SimpleValueType ImmType); + /// FastEmit_rf_ - This method is a wrapper of FastEmit_rf. It first tries + /// to emit an instruction with an immediate operand using FastEmit_rf. + /// If that fails, it materializes the immediate into a register and try + /// FastEmit_rr instead. + unsigned FastEmit_rf_(MVT::SimpleValueType VT, + ISD::NodeType Opcode, + unsigned Op0, ConstantFP *FPImm, + MVT::SimpleValueType ImmType); + /// FastEmit_i - This method is called by target-independent code /// to request that an instruction with the given type, opcode, and /// immediate operand be emitted. @@ -119,6 +138,14 @@ protected: ISD::NodeType Opcode, uint64_t Imm); + /// FastEmit_f - This method is called by target-independent code + /// to request that an instruction with the given type, opcode, and + /// floating-point immediate operand be emitted. + virtual unsigned FastEmit_f(MVT::SimpleValueType VT, + MVT::SimpleValueType RetVT, + ISD::NodeType Opcode, + ConstantFP *FPImm); + /// FastEmitInst_ - Emit a MachineInstr with no operands and a /// result register in the given register class. /// @@ -146,6 +173,13 @@ protected: const TargetRegisterClass *RC, unsigned Op0, uint64_t Imm); + /// FastEmitInst_rf - Emit a MachineInstr with two register operands + /// and a result register in the given register class. + /// + unsigned FastEmitInst_rf(unsigned MachineInstOpcode, + const TargetRegisterClass *RC, + unsigned Op0, ConstantFP *FPImm); + /// FastEmitInst_rri - Emit a MachineInstr with two register operands, /// an immediate, and a result register in the given register class. /// diff --git a/lib/CodeGen/SelectionDAG/FastISel.cpp b/lib/CodeGen/SelectionDAG/FastISel.cpp index a956f01..ac35c43 100644 --- a/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -56,6 +56,20 @@ bool FastISel::SelectBinaryOp(Instruction *I, ISD::NodeType ISDOpcode, return true; } + // Check if the second operand is a constant float. + if (ConstantFP *CF = dyn_cast<ConstantFP>(I->getOperand(1))) { + unsigned ResultReg = FastEmit_rf_(VT.getSimpleVT(), ISDOpcode, Op0, + CF, VT.getSimpleVT()); + if (ResultReg == 0) + // Target-specific code wasn't able to find a machine opcode for + // the given ISD opcode and type. Halt "fast" selection and bail. + return false; + + // We successfully emitted code for the given LLVM Instruction. + ValueMap[I] = ResultReg; + return true; + } + unsigned Op1 = ValueMap[I->getOperand(1)]; if (Op1 == 0) // Unhandled operand. Halt "fast" selection and bail. @@ -451,12 +465,23 @@ unsigned FastISel::FastEmit_i(MVT::SimpleValueType, MVT::SimpleValueType, return 0; } +unsigned FastISel::FastEmit_f(MVT::SimpleValueType, MVT::SimpleValueType, + ISD::NodeType, ConstantFP * /*FPImm*/) { + return 0; +} + unsigned FastISel::FastEmit_ri(MVT::SimpleValueType, MVT::SimpleValueType, ISD::NodeType, unsigned /*Op0*/, uint64_t /*Imm*/) { return 0; } +unsigned FastISel::FastEmit_rf(MVT::SimpleValueType, MVT::SimpleValueType, + ISD::NodeType, unsigned /*Op0*/, + ConstantFP * /*FPImm*/) { + return 0; +} + unsigned FastISel::FastEmit_rri(MVT::SimpleValueType, MVT::SimpleValueType, ISD::NodeType, unsigned /*Op0*/, unsigned /*Op1*/, @@ -483,6 +508,45 @@ unsigned FastISel::FastEmit_ri_(MVT::SimpleValueType VT, ISD::NodeType Opcode, return FastEmit_rr(VT, VT, Opcode, Op0, MaterialReg); } +/// FastEmit_rf_ - This method is a wrapper of FastEmit_ri. It first tries +/// to emit an instruction with a floating-point immediate operand using +/// FastEmit_rf. If that fails, it materializes the immediate into a register +/// and try FastEmit_rr instead. +unsigned FastISel::FastEmit_rf_(MVT::SimpleValueType VT, ISD::NodeType Opcode, + unsigned Op0, ConstantFP *FPImm, + MVT::SimpleValueType ImmType) { + unsigned ResultReg = 0; + // First check if immediate type is legal. If not, we can't use the rf form. + if (TLI.getOperationAction(ISD::Constant, ImmType) == TargetLowering::Legal) + ResultReg = FastEmit_rf(VT, VT, Opcode, Op0, FPImm); + if (ResultReg != 0) + return ResultReg; + + // Materialize the constant in a register. + unsigned MaterialReg = FastEmit_f(ImmType, ImmType, ISD::ConstantFP, FPImm); + if (MaterialReg == 0) { + const APFloat &Flt = FPImm->getValueAPF(); + MVT IntVT = TLI.getPointerTy(); + + uint64_t x[2]; + uint32_t IntBitWidth = IntVT.getSizeInBits(); + if (Flt.convertToInteger(x, IntBitWidth, /*isSigned=*/true, + APFloat::rmTowardZero) != APFloat::opOK) + return 0; + APInt IntVal(IntBitWidth, 2, x); + + unsigned IntegerReg = FastEmit_i(IntVT.getSimpleVT(), IntVT.getSimpleVT(), + ISD::Constant, IntVal.getZExtValue()); + if (IntegerReg == 0) + return 0; + MaterialReg = FastEmit_r(IntVT.getSimpleVT(), VT, + ISD::SINT_TO_FP, IntegerReg); + if (MaterialReg == 0) + return 0; + } + return FastEmit_rr(VT, VT, Opcode, Op0, MaterialReg); +} + unsigned FastISel::createResultReg(const TargetRegisterClass* RC) { return MRI.createVirtualRegister(RC); } @@ -526,6 +590,16 @@ unsigned FastISel::FastEmitInst_ri(unsigned MachineInstOpcode, return ResultReg; } +unsigned FastISel::FastEmitInst_rf(unsigned MachineInstOpcode, + const TargetRegisterClass *RC, + unsigned Op0, ConstantFP *FPImm) { + unsigned ResultReg = createResultReg(RC); + const TargetInstrDesc &II = TII.get(MachineInstOpcode); + + BuildMI(MBB, II, ResultReg).addReg(Op0).addFPImm(FPImm); + return ResultReg; +} + unsigned FastISel::FastEmitInst_rri(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0, unsigned Op1, uint64_t Imm) { diff --git a/test/CodeGen/X86/fast-isel.ll b/test/CodeGen/X86/fast-isel.ll index 9c10a7b..b96406e 100644 --- a/test/CodeGen/X86/fast-isel.ll +++ b/test/CodeGen/X86/fast-isel.ll @@ -35,10 +35,11 @@ fast: %t0 = add double %r, %s %t1 = mul double %t0, %s %t2 = sub double %t1, %s + %t3 = add double %t2, 707.0 br label %exit exit: - ret double %t2 + ret double %t3 } define i32 @cast(){ diff --git a/utils/TableGen/FastISelEmitter.cpp b/utils/TableGen/FastISelEmitter.cpp index 219b8f3..290676a 100644 --- a/utils/TableGen/FastISelEmitter.cpp +++ b/utils/TableGen/FastISelEmitter.cpp @@ -68,6 +68,11 @@ struct OperandsSignature { Operands.push_back("i"); return true; } + if (!InstPatNode->isLeaf() && + InstPatNode->getOperator()->getName() == "fpimm") { + Operands.push_back("f"); + return true; + } const CodeGenRegisterClass *DstRC = 0; @@ -87,6 +92,10 @@ struct OperandsSignature { Operands.push_back("i"); return true; } + if (Op->getOperator()->getName() == "fpimm") { + Operands.push_back("f"); + return true; + } // For now, ignore fpimm and other non-leaf nodes. return false; } @@ -122,6 +131,8 @@ struct OperandsSignature { OS << "unsigned Op" << i; } else if (Operands[i] == "i") { OS << "uint64_t imm" << i; + } else if (Operands[i] == "f") { + OS << "ConstantFP *f" << i; } else { assert("Unknown operand kind!"); abort(); @@ -137,6 +148,8 @@ struct OperandsSignature { OS << "Op" << i; } else if (Operands[i] == "i") { OS << "imm" << i; + } else if (Operands[i] == "f") { + OS << "f" << i; } else { assert("Unknown operand kind!"); abort(); |