The read_latency.patch is incomplete. I forgot to deal with spill live intervals.
Lauro 2007/2/6, Lauro Ramos Venancio <[EMAIL PROTECTED]>:
READ_LATENCY patch for review. Sample of use: class RegConstraint<string C> { string Constraints = C; } // AI_orr - Defines a (op r, r) pattern. class AI_orr<string opc, SDNode opnode> : AI<(ops GPR:$dst, GPR:$a, GPR:$b), !strconcat(opc, " $dst, $a, $b"), [(set GPR:$dst, (opnode GPR:$a, GPR:$b))]>, RegConstraint<"$a lat 2">; Lauro 2007/1/26, Evan Cheng <[EMAIL PROTECTED]>: > > On Jan 26, 2007, at 1:07 PM, Lauro Ramos Venancio wrote: > > >> The facility does that have to be that general. There are 4 cycles > >> between every two instructions. See LiveIntervalAnalysis: > >> > >> struct InstrSlots { > >> enum { > >> LOAD = 0, > >> USE = 1, > >> DEF = 2, > >> STORE = 3, > >> NUM = 4 > >> }; > >> }; > >> > >> We can restrict the constraint range to 1 - 3. This ensures the last > >> use is always the kill while retaining its flexibility. > >> > >> Evan > > > > I will try to implement this. Do you have any suggestion for > > constraint name and syntax? > > I don't have any great ideas. Perhaps READ_LATENCY for constraint and > something like > > $src +lat 2 > > for syntax? > > Feel free to choose something else if you have better ideas. > > Thanks, > > Evan > > > > > Lauro > >
Index: include/llvm/Target/TargetInstrInfo.h =================================================================== RCS file: /var/cvs/llvm/llvm/include/llvm/Target/TargetInstrInfo.h,v retrieving revision 1.111 diff -u -r1.111 TargetInstrInfo.h --- include/llvm/Target/TargetInstrInfo.h 26 Jan 2007 14:34:51 -0000 1.111 +++ include/llvm/Target/TargetInstrInfo.h 6 Feb 2007 21:09:44 -0000 @@ -94,9 +94,10 @@ const unsigned M_PREDICATE_OPERAND = 1 << 1; namespace TOI { - // Operand constraints: only "tied_to" for now. + // Operand constraints: only "tied_to" and read_latency for now. enum OperandConstraint { - TIED_TO = 0 // Must be allocated the same register as. + TIED_TO = 0, // Must be allocated the same register as. + READ_LATENCY // Number of cycles needed for read operand. }; } Index: lib/CodeGen/LiveIntervalAnalysis.cpp =================================================================== RCS file: /var/cvs/llvm/llvm/lib/CodeGen/LiveIntervalAnalysis.cpp,v retrieving revision 1.204 diff -u -r1.204 LiveIntervalAnalysis.cpp --- lib/CodeGen/LiveIntervalAnalysis.cpp 19 Dec 2006 22:41:21 -0000 1.204 +++ lib/CodeGen/LiveIntervalAnalysis.cpp 6 Feb 2007 21:09:44 -0000 @@ -354,15 +354,26 @@ // // Keep track of whether we replace a use and/or def so that we can // create the spill interval with the appropriate range. - mop.setReg(NewVReg); - - bool HasUse = mop.isUse(); - bool HasDef = mop.isDef(); - for (unsigned j = i+1, e = MI->getNumOperands(); j != e; ++j) { + + bool HasUse = false; + bool HasDef = false; + int ReadLatency = InstrSlots::USE; //default read latency + for (unsigned j = i, e = MI->getNumOperands(); j != e; ++j) { if (MI->getOperand(j).isReg() && MI->getOperand(j).getReg() == li.reg) { MI->getOperand(j).setReg(NewVReg); - HasUse |= MI->getOperand(j).isUse(); + + if (MI->getOperand(j).isUse()) { + HasUse = true; + //get the greatest read latency + if (!MI->getOperand(j).isImplicit()){ + int read_latency = MI->getInstrDescriptor()-> + getOperandConstraint(j,TOI::READ_LATENCY); + if (read_latency != -1 && read_latency > ReadLatency) + ReadLatency = read_latency; + } + } + HasDef |= MI->getOperand(j).isDef(); } } @@ -376,16 +387,16 @@ // the spill weight is now infinity as it // cannot be spilled again nI.weight = HUGE_VALF; - + unsigned ValNum = nI.getNextValue(~0U, 0); if (HasUse) { - LiveRange LR(getLoadIndex(index), getUseIndex(index), - nI.getNextValue(~0U, 0)); + LiveRange LR(getLoadIndex(index), + getBaseIndex(index) + ReadLatency + 1, ValNum); DOUT << " +" << LR; nI.addRange(LR); } if (HasDef) { LiveRange LR(getDefIndex(index), getStoreIndex(index), - nI.getNextValue(~0U, 0)); + ValNum); DOUT << " +" << LR; nI.addRange(LR); } @@ -441,6 +452,24 @@ DOUT << "\t\tregister: "; DEBUG(printRegName(interval.reg)); LiveVariables::VarInfo& vi = lv_->getVarInfo(interval.reg); + // For each kill, get the greatest read latency of the virtual register. + std::vector<char> ReadLatency(vi.Kills.size()); + for (unsigned i = 0, e = vi.Kills.size(); i != e; ++i){ + const TargetInstrDescriptor *instrDescriptor = + vi.Kills[i]->getInstrDescriptor(); + ReadLatency[i] = InstrSlots::USE; //default read latency + //find the operands that use the virtual register + for (unsigned j = 0, f = vi.Kills[i]->getNumOperands(); j != f; ++j){ + MachineOperand op = vi.Kills[i]->getOperand(j); + if (op.isRegister() && op.isUse() && (op.getReg() == interval.reg)) { + int read_latency = + instrDescriptor->getOperandConstraint(j, TOI::READ_LATENCY); + if (read_latency != -1 && read_latency > ReadLatency[i]) + ReadLatency[i] = (char) read_latency; + } + } + } + // Virtual registers may be defined multiple times (due to phi // elimination and 2-addr elimination). Much of what we do only has to be // done once for the vreg. We use an empty interval to detect the first @@ -467,7 +496,7 @@ // FIXME: what about dead vars? unsigned killIdx; if (vi.Kills[0] != mi) - killIdx = getUseIndex(getInstructionIndex(vi.Kills[0]))+1; + killIdx = getInstructionIndex(vi.Kills[0]) + ReadLatency[0] + 1; else killIdx = defIndex+1; @@ -514,7 +543,7 @@ for (unsigned i = 0, e = vi.Kills.size(); i != e; ++i) { MachineInstr *Kill = vi.Kills[i]; LiveRange LR(getMBBStartIdx(Kill->getParent()), - getUseIndex(getInstructionIndex(Kill))+1, + getInstructionIndex(Kill)+ ReadLatency[i] + 1, ValNum); interval.addRange(LR); DOUT << " +" << LR; @@ -574,7 +603,7 @@ // Remove the old range that we now know has an incorrect number. MachineInstr *Killer = vi.Kills[0]; unsigned Start = getMBBStartIdx(Killer->getParent()); - unsigned End = getUseIndex(getInstructionIndex(Killer))+1; + unsigned End = getInstructionIndex(Killer) + ReadLatency[0] + 1; DOUT << "Removing [" << Start << "," << End << "] from: "; interval.print(DOUT, mri_); DOUT << "\n"; interval.removeRange(Start, End); Index: lib/CodeGen/RegAllocLocal.cpp =================================================================== RCS file: /var/cvs/llvm/llvm/lib/CodeGen/RegAllocLocal.cpp,v retrieving revision 1.100 diff -u -r1.100 RegAllocLocal.cpp --- lib/CodeGen/RegAllocLocal.cpp 1 Feb 2007 05:31:50 -0000 1.100 +++ lib/CodeGen/RegAllocLocal.cpp 6 Feb 2007 21:09:45 -0000 @@ -567,10 +567,20 @@ } SmallVector<unsigned, 8> Kills; + SmallVector<char, 8> ReadLatency; for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { MachineOperand& MO = MI->getOperand(i); - if (MO.isRegister() && MO.isKill()) + if (MO.isRegister() && MO.isKill()){ Kills.push_back(MO.getReg()); + int read_latency = 1; + //we can't call getOperandConstraint on a implicit MO + if (!MO.isImplicit()) { + read_latency = TID.getOperandConstraint(i,TOI::READ_LATENCY); + if (read_latency == -1) + read_latency = 1; + } + ReadLatency.push_back((char)read_latency); + } } // Get the used operands into registers. This has the potential to spill @@ -591,6 +601,7 @@ // value, freeing the register being used, so it doesn't need to be // spilled to memory. // + SmallVector<unsigned, 8> PostponedRegRemove; for (unsigned i = 0, e = Kills.size(); i != e; ++i) { unsigned VirtReg = Kills[i]; unsigned PhysReg = VirtReg; @@ -606,16 +617,21 @@ } if (PhysReg) { - DOUT << " Last use of " << RegInfo->getName(PhysReg) - << "[%reg" << VirtReg <<"], removing it from live set\n"; - removePhysReg(PhysReg); - for (const unsigned *AliasSet = RegInfo->getAliasSet(PhysReg); - *AliasSet; ++AliasSet) { - if (PhysRegsUsed[*AliasSet] != -2) { - DOUT << " Last use of " - << RegInfo->getName(*AliasSet) - << "[%reg" << VirtReg <<"], removing it from live set\n"; - removePhysReg(*AliasSet); + if (ReadLatency[i] > 1) { + //postpone the reg remove from live set. + PostponedRegRemove.push_back(PhysReg); + } else { + DOUT << " Last use of " << RegInfo->getName(PhysReg) + << "[%reg" << VirtReg <<"], removing it from live set\n"; + removePhysReg(PhysReg); + for (const unsigned *AliasSet = RegInfo->getAliasSet(PhysReg); + *AliasSet; ++AliasSet) { + if (PhysRegsUsed[*AliasSet] != -2) { + DOUT << " Last use of " + << RegInfo->getName(*AliasSet) + << "[%reg" << VirtReg <<"], removing it from live set\n"; + removePhysReg(*AliasSet); + } } } } @@ -731,7 +747,24 @@ } } } - + + //Do postponed reg removes from live set + for (unsigned i = 0, e = PostponedRegRemove.size(); i != e; ++i) { + DOUT << " Last use of " << RegInfo->getName(PostponedRegRemove[i]) + <<", removing it from live set (postponed)\n"; + removePhysReg(PostponedRegRemove[i]); + for (const unsigned *AliasSet = + RegInfo->getAliasSet(PostponedRegRemove[i]); + *AliasSet; ++AliasSet) { + if (PhysRegsUsed[*AliasSet] != -2) { + DOUT << " Last use of " + << RegInfo->getName(*AliasSet) + <<", removing it from live set (postponed)\n"; + removePhysReg(*AliasSet); + } + } + } + // Finally, if this is a noop copy instruction, zap it. unsigned SrcReg, DstReg; if (TII.isMoveInstr(*MI, SrcReg, DstReg) && SrcReg == DstReg) { Index: utils/TableGen/CodeGenTarget.cpp =================================================================== RCS file: /var/cvs/llvm/llvm/utils/TableGen/CodeGenTarget.cpp,v retrieving revision 1.82 diff -u -r1.82 CodeGenTarget.cpp --- utils/TableGen/CodeGenTarget.cpp 26 Jan 2007 17:29:20 -0000 1.82 +++ utils/TableGen/CodeGenTarget.cpp 6 Feb 2007 21:09:46 -0000 @@ -20,6 +20,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Streams.h" +#include "llvm/Target/TargetInstrInfo.h" #include <set> #include <algorithm> using namespace llvm; @@ -284,38 +285,61 @@ static void ParseConstraint(const std::string &CStr, CodeGenInstruction *I) { - // FIXME: Only supports TIED_TO for now. - std::string::size_type pos = CStr.find_first_of('='); - assert(pos != std::string::npos && "Unrecognized constraint"); - std::string Name = CStr.substr(0, pos); - - // TIED_TO: $src1 = $dst - std::string::size_type wpos = Name.find_first_of(" \t"); - if (wpos == std::string::npos) - throw "Illegal format for tied-to constraint: '" + CStr + "'"; - std::string DestOpName = Name.substr(0, wpos); - std::pair<unsigned,unsigned> DestOp = I->ParseOperandName(DestOpName, false); - - Name = CStr.substr(pos+1); - wpos = Name.find_first_not_of(" \t"); - if (wpos == std::string::npos) - throw "Illegal format for tied-to constraint: '" + CStr + "'"; - - std::pair<unsigned,unsigned> SrcOp = - I->ParseOperandName(Name.substr(wpos), false); - if (SrcOp > DestOp) - throw "Illegal tied-to operand constraint '" + CStr + "'"; - - - unsigned FlatOpNo = I->getFlattenedOperandNumber(SrcOp); + std::pair<unsigned,unsigned> Operand; + unsigned ConstraintValue; + TOI::OperandConstraint Constraint; + std::string::size_type pos; + + if ((pos = CStr.find_first_of('=')) != std::string::npos) { + //TIED_TO Constraint + Constraint = TOI::TIED_TO; + std::string Name = CStr.substr(0, pos); + // TIED_TO: $src1 = $dst + std::string::size_type wpos = Name.find_first_of(" \t"); + if (wpos == std::string::npos) + throw "Illegal format for tied-to constraint: '" + CStr + "'"; + std::string DestOpName = Name.substr(0, wpos); + Operand = I->ParseOperandName(DestOpName, false); + + Name = CStr.substr(pos+1); + wpos = Name.find_first_not_of(" \t"); + if (wpos == std::string::npos) + throw "Illegal format for tied-to constraint: '" + CStr + "'"; + + std::pair<unsigned,unsigned> SrcOp = + I->ParseOperandName(Name.substr(wpos), false); + if (SrcOp > Operand) + throw "Illegal tied-to operand constraint '" + CStr + "'"; + ConstraintValue = I->getFlattenedOperandNumber(SrcOp); + + } else if ((pos = CStr.find("lat")) != std::string::npos) { + //READ_LATENCY Constraint + Constraint = TOI::READ_LATENCY; + + //get read latency operand + std::string Name = CStr.substr(0, pos); + std::string::size_type wpos = Name.find_first_of(" \t"); + if (wpos == std::string::npos) + throw "Illegal format for read-latency constraint: '" + CStr + "'"; + std::string OpName = Name.substr(0, wpos); + Operand = I->ParseOperandName(OpName, false); + + //get read latancy value + Name = CStr.substr(pos+3); + sscanf(Name.c_str(),"%u",&ConstraintValue); + if (ConstraintValue <= 0 || ConstraintValue > 3) + throw "Invalid read latency value: '" + CStr + "'"; + } else { + throw "Unrecognized constraint"; + } + // Build the string for the operand. - std::string OpConstraint = - "((" + utostr(FlatOpNo) + " << 16) | (1 << TOI::TIED_TO))"; + std::string OpConstraint ="((" + utostr(ConstraintValue) + " << " + + utostr(16 + Constraint * 4) + ") | (1 << " + utostr(Constraint) +"))"; - - if (!I->OperandList[DestOp.first].Constraints[DestOp.second].empty()) - throw "Operand '" + DestOpName + "' cannot have multiple constraints!"; - I->OperandList[DestOp.first].Constraints[DestOp.second] = OpConstraint; + if (!I->OperandList[Operand.first].Constraints[Operand.second].empty()) + throw "Operands cannot have multiple constraints."; + I->OperandList[Operand.first].Constraints[Operand.second] = OpConstraint; } static void ParseConstraints(const std::string &CStr, CodeGenInstruction *I) {
_______________________________________________ llvm-commits mailing list llvm-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits