summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/CodeGen/FastISel.h34
-rw-r--r--lib/CodeGen/SelectionDAG/FastISel.cpp74
-rw-r--r--test/CodeGen/X86/fast-isel.ll3
-rw-r--r--utils/TableGen/FastISelEmitter.cpp13
4 files changed, 123 insertions, 1 deletions
diff --git a/include/llvm/CodeGen/FastISel.h b/include/llvm/CodeGen/FastISel.h
index 9ed66f10e4..51c6bc249c 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 a956f0190b..ac35c43e78 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 9c10a7b828..b96406e2c8 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 219b8f3973..290676ae7a 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();