Basic fast-isel support for instructions with constant int operands.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@55099 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Dan Gohman 2008-08-21 01:41:07 +00:00
parent 2076aa800e
commit d5fe57d2f9
4 changed files with 137 additions and 38 deletions

View File

@ -88,8 +88,15 @@ protected:
/// ///
virtual unsigned FastEmit_ri(MVT::SimpleValueType VT, virtual unsigned FastEmit_ri(MVT::SimpleValueType VT,
ISD::NodeType Opcode, ISD::NodeType Opcode,
unsigned Op0, uint64_t Imm, unsigned Op0, uint64_t Imm);
MVT::SimpleValueType ImmType);
/// 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.
///
virtual unsigned FastEmit_rri(MVT::SimpleValueType VT,
ISD::NodeType Opcode,
unsigned Op0, unsigned Op1, uint64_t Imm);
/// FastEmit_ri_ - This method is a wrapper of FastEmit_ri. It first tries /// FastEmit_ri_ - This method is a wrapper of FastEmit_ri. It first tries
/// to emit an instruction with an immediate operand using FastEmit_ri. /// to emit an instruction with an immediate operand using FastEmit_ri.
@ -106,20 +113,34 @@ protected:
unsigned FastEmitInst_(unsigned MachineInstOpcode, unsigned FastEmitInst_(unsigned MachineInstOpcode,
const TargetRegisterClass *RC); const TargetRegisterClass *RC);
/// FastEmitInst_ - Emit a MachineInstr with one register operand /// FastEmitInst_r - Emit a MachineInstr with one register operand
/// and a result register in the given register class. /// and a result register in the given register class.
/// ///
unsigned FastEmitInst_r(unsigned MachineInstOpcode, unsigned FastEmitInst_r(unsigned MachineInstOpcode,
const TargetRegisterClass *RC, const TargetRegisterClass *RC,
unsigned Op0); unsigned Op0);
/// FastEmitInst_ - Emit a MachineInstr with two register operands /// FastEmitInst_rr - Emit a MachineInstr with two register operands
/// and a result register in the given register class. /// and a result register in the given register class.
/// ///
unsigned FastEmitInst_rr(unsigned MachineInstOpcode, unsigned FastEmitInst_rr(unsigned MachineInstOpcode,
const TargetRegisterClass *RC, const TargetRegisterClass *RC,
unsigned Op0, unsigned Op1); unsigned Op0, unsigned Op1);
/// FastEmitInst_ri - Emit a MachineInstr with two register operands
/// and a result register in the given register class.
///
unsigned FastEmitInst_ri(unsigned MachineInstOpcode,
const TargetRegisterClass *RC,
unsigned Op0, uint64_t Imm);
/// FastEmitInst_rri - Emit a MachineInstr with two register operands,
/// an immediate, and a result register in the given register class.
///
unsigned FastEmitInst_rri(unsigned MachineInstOpcode,
const TargetRegisterClass *RC,
unsigned Op0, unsigned Op1, uint64_t Imm);
private: private:
unsigned createResultReg(const TargetRegisterClass *RC); unsigned createResultReg(const TargetRegisterClass *RC);

View File

@ -26,17 +26,35 @@ using namespace llvm;
/// ///
bool FastISel::SelectBinaryOp(Instruction *I, ISD::NodeType ISDOpcode, bool FastISel::SelectBinaryOp(Instruction *I, ISD::NodeType ISDOpcode,
DenseMap<const Value*, unsigned> &ValueMap) { DenseMap<const Value*, unsigned> &ValueMap) {
unsigned Op0 = ValueMap[I->getOperand(0)];
unsigned Op1 = ValueMap[I->getOperand(1)];
if (Op0 == 0 || Op1 == 0)
// Unhandled operand. Halt "fast" selection and bail.
return false;
MVT VT = MVT::getMVT(I->getType(), /*HandleUnknown=*/true); MVT VT = MVT::getMVT(I->getType(), /*HandleUnknown=*/true);
if (VT == MVT::Other || !VT.isSimple()) if (VT == MVT::Other || !VT.isSimple())
// Unhandled type. Halt "fast" selection and bail. // Unhandled type. Halt "fast" selection and bail.
return false; return false;
unsigned Op0 = ValueMap[I->getOperand(0)];
if (Op0 == 0)
// Unhandled operand. Halt "fast" selection and bail.
return false;
// Check if the second operand is a constant and handle it appropriately.
if (ConstantInt *CI = dyn_cast<ConstantInt>(I->getOperand(1))) {
unsigned ResultReg = FastEmit_ri_(VT.getSimpleVT(), ISDOpcode, Op0,
CI->getZExtValue(), 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.
return false;
unsigned ResultReg = FastEmit_rr(VT.getSimpleVT(), ISDOpcode, Op0, Op1); unsigned ResultReg = FastEmit_rr(VT.getSimpleVT(), ISDOpcode, Op0, Op1);
if (ResultReg == 0) if (ResultReg == 0)
// Target-specific code wasn't able to find a machine opcode for // Target-specific code wasn't able to find a machine opcode for
@ -67,7 +85,7 @@ bool FastISel::SelectGetElementPtr(Instruction *I,
uint64_t Offs = TD.getStructLayout(StTy)->getElementOffset(Field); uint64_t Offs = TD.getStructLayout(StTy)->getElementOffset(Field);
// FIXME: This can be optimized by combining the add with a // FIXME: This can be optimized by combining the add with a
// subsequent one. // subsequent one.
N = FastEmit_ri(VT.getSimpleVT(), ISD::ADD, N, Offs, VT.getSimpleVT()); N = FastEmit_ri_(VT.getSimpleVT(), ISD::ADD, N, Offs, VT.getSimpleVT());
if (N == 0) if (N == 0)
// Unhandled operand. Halt "fast" selection and bail. // Unhandled operand. Halt "fast" selection and bail.
return false; return false;
@ -81,7 +99,7 @@ bool FastISel::SelectGetElementPtr(Instruction *I,
if (CI->getZExtValue() == 0) continue; if (CI->getZExtValue() == 0) continue;
uint64_t Offs = uint64_t Offs =
TD.getABITypeSize(Ty)*cast<ConstantInt>(CI)->getSExtValue(); TD.getABITypeSize(Ty)*cast<ConstantInt>(CI)->getSExtValue();
N = FastEmit_ri(VT.getSimpleVT(), ISD::ADD, N, Offs, VT.getSimpleVT()); N = FastEmit_ri_(VT.getSimpleVT(), ISD::ADD, N, Offs, VT.getSimpleVT());
if (N == 0) if (N == 0)
// Unhandled operand. Halt "fast" selection and bail. // Unhandled operand. Halt "fast" selection and bail.
return false; return false;
@ -108,8 +126,8 @@ bool FastISel::SelectGetElementPtr(Instruction *I,
// FIXME: If multiple is power of two, turn it into a shift. The // FIXME: If multiple is power of two, turn it into a shift. The
// optimization should be in FastEmit_ri? // optimization should be in FastEmit_ri?
IdxN = FastEmit_ri(VT.getSimpleVT(), ISD::MUL, IdxN, IdxN = FastEmit_ri_(VT.getSimpleVT(), ISD::MUL, IdxN,
ElementSize, VT.getSimpleVT()); ElementSize, VT.getSimpleVT());
if (IdxN == 0) if (IdxN == 0)
// Unhandled operand. Halt "fast" selection and bail. // Unhandled operand. Halt "fast" selection and bail.
return false; return false;
@ -226,13 +244,18 @@ unsigned FastISel::FastEmit_rr(MVT::SimpleValueType, ISD::NodeType,
return 0; return 0;
} }
unsigned FastISel::FastEmit_i(MVT::SimpleValueType, uint64_t) { unsigned FastISel::FastEmit_i(MVT::SimpleValueType, uint64_t /*Imm*/) {
return 0; return 0;
} }
unsigned FastISel::FastEmit_ri(MVT::SimpleValueType, ISD::NodeType, unsigned FastISel::FastEmit_ri(MVT::SimpleValueType, ISD::NodeType,
unsigned /*Op0*/, uint64_t Imm, unsigned /*Op0*/, uint64_t /*Imm*/) {
MVT::SimpleValueType ImmType) { return 0;
}
unsigned FastISel::FastEmit_rri(MVT::SimpleValueType, ISD::NodeType,
unsigned /*Op0*/, unsigned /*Op1*/,
uint64_t /*Imm*/) {
return 0; return 0;
} }
@ -241,20 +264,27 @@ unsigned FastISel::FastEmit_ri(MVT::SimpleValueType, ISD::NodeType,
/// If that fails, it materializes the immediate into a register and try /// If that fails, it materializes the immediate into a register and try
/// FastEmit_rr instead. /// FastEmit_rr instead.
unsigned FastISel::FastEmit_ri_(MVT::SimpleValueType VT, ISD::NodeType Opcode, unsigned FastISel::FastEmit_ri_(MVT::SimpleValueType VT, ISD::NodeType Opcode,
unsigned Op0, uint64_t Imm, unsigned Op0, uint64_t Imm,
MVT::SimpleValueType ImmType) { MVT::SimpleValueType ImmType) {
unsigned ResultReg = 0; unsigned ResultReg = 0;
// First check if immediate type is legal. If not, we can't use the ri form. // First check if immediate type is legal. If not, we can't use the ri form.
if (TLI.getOperationAction(ISD::Constant, ImmType) == TargetLowering::Legal) if (TLI.getOperationAction(ISD::Constant, ImmType) == TargetLowering::Legal)
ResultReg = FastEmit_ri(VT, Opcode, Op0, Imm, ImmType); ResultReg = FastEmit_ri(VT, Opcode, Op0, Imm);
if (ResultReg != 0) if (ResultReg != 0)
return ResultReg; return ResultReg;
return FastEmit_rr(VT, Opcode, Op0, FastEmit_i(ImmType, Imm)); unsigned MaterialReg = FastEmit_i(ImmType, Imm);
if (MaterialReg == 0)
return 0;
return FastEmit_rr(VT, Opcode, Op0, MaterialReg);
}
unsigned FastISel::createResultReg(const TargetRegisterClass* RC) {
return MRI.createVirtualRegister(RC);
} }
unsigned FastISel::FastEmitInst_(unsigned MachineInstOpcode, unsigned FastISel::FastEmitInst_(unsigned MachineInstOpcode,
const TargetRegisterClass* RC) { const TargetRegisterClass* RC) {
unsigned ResultReg = MRI.createVirtualRegister(RC); unsigned ResultReg = createResultReg(RC);
const TargetInstrDesc &II = TII.get(MachineInstOpcode); const TargetInstrDesc &II = TII.get(MachineInstOpcode);
BuildMI(MBB, II, ResultReg); BuildMI(MBB, II, ResultReg);
@ -264,7 +294,7 @@ unsigned FastISel::FastEmitInst_(unsigned MachineInstOpcode,
unsigned FastISel::FastEmitInst_r(unsigned MachineInstOpcode, unsigned FastISel::FastEmitInst_r(unsigned MachineInstOpcode,
const TargetRegisterClass *RC, const TargetRegisterClass *RC,
unsigned Op0) { unsigned Op0) {
unsigned ResultReg = MRI.createVirtualRegister(RC); unsigned ResultReg = createResultReg(RC);
const TargetInstrDesc &II = TII.get(MachineInstOpcode); const TargetInstrDesc &II = TII.get(MachineInstOpcode);
BuildMI(MBB, II, ResultReg).addReg(Op0); BuildMI(MBB, II, ResultReg).addReg(Op0);
@ -274,9 +304,29 @@ unsigned FastISel::FastEmitInst_r(unsigned MachineInstOpcode,
unsigned FastISel::FastEmitInst_rr(unsigned MachineInstOpcode, unsigned FastISel::FastEmitInst_rr(unsigned MachineInstOpcode,
const TargetRegisterClass *RC, const TargetRegisterClass *RC,
unsigned Op0, unsigned Op1) { unsigned Op0, unsigned Op1) {
unsigned ResultReg = MRI.createVirtualRegister(RC); unsigned ResultReg = createResultReg(RC);
const TargetInstrDesc &II = TII.get(MachineInstOpcode); const TargetInstrDesc &II = TII.get(MachineInstOpcode);
BuildMI(MBB, II, ResultReg).addReg(Op0).addReg(Op1); BuildMI(MBB, II, ResultReg).addReg(Op0).addReg(Op1);
return ResultReg; return ResultReg;
} }
unsigned FastISel::FastEmitInst_ri(unsigned MachineInstOpcode,
const TargetRegisterClass *RC,
unsigned Op0, uint64_t Imm) {
unsigned ResultReg = createResultReg(RC);
const TargetInstrDesc &II = TII.get(MachineInstOpcode);
BuildMI(MBB, II, ResultReg).addReg(Op0).addImm(Imm);
return ResultReg;
}
unsigned FastISel::FastEmitInst_rri(unsigned MachineInstOpcode,
const TargetRegisterClass *RC,
unsigned Op0, unsigned Op1, uint64_t Imm) {
unsigned ResultReg = createResultReg(RC);
const TargetInstrDesc &II = TII.get(MachineInstOpcode);
BuildMI(MBB, II, ResultReg).addReg(Op0).addReg(Op1).addImm(Imm);
return ResultReg;
}

View File

@ -16,10 +16,11 @@ fast:
%t3 = and i32 %t2, %s %t3 = and i32 %t2, %s
%t4 = or i32 %t3, %s %t4 = or i32 %t3, %s
%t5 = xor i32 %t4, %s %t5 = xor i32 %t4, %s
%t6 = add i32 %t5, 2
br label %exit br label %exit
exit: exit:
ret i32 %t5 ret i32 %t6
} }
define double @bar(double* %p, double* %q) { define double @bar(double* %p, double* %q) {

View File

@ -66,16 +66,31 @@ struct OperandsSignature {
const CodeGenRegisterClass *DstRC) { const CodeGenRegisterClass *DstRC) {
for (unsigned i = 0, e = InstPatNode->getNumChildren(); i != e; ++i) { for (unsigned i = 0, e = InstPatNode->getNumChildren(); i != e; ++i) {
TreePatternNode *Op = InstPatNode->getChild(i); TreePatternNode *Op = InstPatNode->getChild(i);
if (!Op->isLeaf())
return false;
// For now, filter out any operand with a predicate. // For now, filter out any operand with a predicate.
if (!Op->getPredicateFn().empty()) if (!Op->getPredicateFn().empty())
return false; return false;
// For now, filter out any operand with multiple values.
if (Op->getExtTypes().size() != 1)
return false;
// For now, all the operands must have the same type.
if (Op->getTypeNum(0) != VT)
return false;
if (!Op->isLeaf()) {
if (Op->getOperator()->getName() == "imm") {
Operands.push_back("i");
return true;
}
// For now, ignore fpimm and other non-leaf nodes.
return false;
}
DefInit *OpDI = dynamic_cast<DefInit*>(Op->getLeafValue()); DefInit *OpDI = dynamic_cast<DefInit*>(Op->getLeafValue());
if (!OpDI) if (!OpDI)
return false; return false;
Record *OpLeafRec = OpDI->getDef(); Record *OpLeafRec = OpDI->getDef();
// For now, only accept register operands. // TODO: handle instructions which have physreg operands.
if (OpLeafRec->isSubClassOf("Register"))
return false;
// For now, the only other thing we accept is register operands.
if (!OpLeafRec->isSubClassOf("RegisterClass")) if (!OpLeafRec->isSubClassOf("RegisterClass"))
return false; return false;
// For now, require the register operands' register classes to all // For now, require the register operands' register classes to all
@ -86,9 +101,6 @@ struct OperandsSignature {
// For now, all the operands must have the same register class. // For now, all the operands must have the same register class.
if (DstRC != RC) if (DstRC != RC)
return false; return false;
// For now, all the operands must have the same type.
if (Op->getTypeNum(0) != VT)
return false;
Operands.push_back("r"); Operands.push_back("r");
} }
return true; return true;
@ -98,6 +110,8 @@ struct OperandsSignature {
for (unsigned i = 0, e = Operands.size(); i != e; ++i) { for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
if (Operands[i] == "r") { if (Operands[i] == "r") {
OS << "unsigned Op" << i; OS << "unsigned Op" << i;
} else if (Operands[i] == "i") {
OS << "uint64_t imm" << i;
} else { } else {
assert("Unknown operand kind!"); assert("Unknown operand kind!");
abort(); abort();
@ -111,6 +125,8 @@ struct OperandsSignature {
for (unsigned i = 0, e = Operands.size(); i != e; ++i) { for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
if (Operands[i] == "r") { if (Operands[i] == "r") {
OS << "Op" << i; OS << "Op" << i;
} else if (Operands[i] == "i") {
OS << "imm" << i;
} else { } else {
assert("Unknown operand kind!"); assert("Unknown operand kind!");
abort(); abort();
@ -239,13 +255,16 @@ void FastISelEmitter::run(std::ostream &OS) {
MVT::SimpleValueType VT = TI->first; MVT::SimpleValueType VT = TI->first;
OS << " unsigned FastEmit_" << getLegalCName(Opcode) OS << " unsigned FastEmit_" << getLegalCName(Opcode)
<< "_" << getLegalCName(getName(VT)) << "("; << "_" << getLegalCName(getName(VT)) << "_";
Operands.PrintManglingSuffix(OS);
OS << "(";
Operands.PrintParameters(OS); Operands.PrintParameters(OS);
OS << ");\n"; OS << ");\n";
} }
OS << " unsigned FastEmit_" << getLegalCName(Opcode) OS << " unsigned FastEmit_" << getLegalCName(Opcode) << "_";
<< "(MVT::SimpleValueType VT"; Operands.PrintManglingSuffix(OS);
OS << "(MVT::SimpleValueType VT";
if (!Operands.empty()) if (!Operands.empty())
OS << ", "; OS << ", ";
Operands.PrintParameters(OS); Operands.PrintParameters(OS);
@ -293,7 +312,9 @@ void FastISelEmitter::run(std::ostream &OS) {
OS << "unsigned FastISel::FastEmit_" OS << "unsigned FastISel::FastEmit_"
<< getLegalCName(Opcode) << getLegalCName(Opcode)
<< "_" << getLegalCName(getName(VT)) << "("; << "_" << getLegalCName(getName(VT)) << "_";
Operands.PrintManglingSuffix(OS);
OS << "(";
Operands.PrintParameters(OS); Operands.PrintParameters(OS);
OS << ") {\n"; OS << ") {\n";
OS << " return FastEmitInst_"; OS << " return FastEmitInst_";
@ -310,7 +331,9 @@ void FastISelEmitter::run(std::ostream &OS) {
// Emit one function for the opcode that demultiplexes based on the type. // Emit one function for the opcode that demultiplexes based on the type.
OS << "unsigned FastISel::FastEmit_" OS << "unsigned FastISel::FastEmit_"
<< getLegalCName(Opcode) << "(MVT::SimpleValueType VT"; << getLegalCName(Opcode) << "_";
Operands.PrintManglingSuffix(OS);
OS << "(MVT::SimpleValueType VT";
if (!Operands.empty()) if (!Operands.empty())
OS << ", "; OS << ", ";
Operands.PrintParameters(OS); Operands.PrintParameters(OS);
@ -321,7 +344,9 @@ void FastISelEmitter::run(std::ostream &OS) {
MVT::SimpleValueType VT = TI->first; MVT::SimpleValueType VT = TI->first;
std::string TypeName = getName(VT); std::string TypeName = getName(VT);
OS << " case " << TypeName << ": return FastEmit_" OS << " case " << TypeName << ": return FastEmit_"
<< getLegalCName(Opcode) << "_" << getLegalCName(TypeName) << "("; << getLegalCName(Opcode) << "_" << getLegalCName(TypeName) << "_";
Operands.PrintManglingSuffix(OS);
OS << "(";
Operands.PrintArguments(OS); Operands.PrintArguments(OS);
OS << ");\n"; OS << ");\n";
} }
@ -346,7 +371,9 @@ void FastISelEmitter::run(std::ostream &OS) {
const std::string &Opcode = I->first; const std::string &Opcode = I->first;
OS << " case " << Opcode << ": return FastEmit_" OS << " case " << Opcode << ": return FastEmit_"
<< getLegalCName(Opcode) << "(VT"; << getLegalCName(Opcode) << "_";
Operands.PrintManglingSuffix(OS);
OS << "(VT";
if (!Operands.empty()) if (!Operands.empty())
OS << ", "; OS << ", ";
Operands.PrintArguments(OS); Operands.PrintArguments(OS);