diff --git a/include/llvm/Target/TargetInstrItineraries.h b/include/llvm/Target/TargetInstrItineraries.h index 420fa94ce76..3dfa8bc10bf 100644 --- a/include/llvm/Target/TargetInstrItineraries.h +++ b/include/llvm/Target/TargetInstrItineraries.h @@ -47,10 +47,24 @@ namespace llvm { /// indicate that the instruction requires multiple stages at the /// same time. /// +/// FU reservation can be of two different kinds: +/// - FUs which instruction actually requires +/// - FUs which instruction just reserves. Reserved unit is not available for +/// execution of other instruction. However, several instructions can reserve +/// the same unit several times. +/// Such two types of units reservation is used to model instruction domain +/// change stalls, FUs using the same resource (e.g. same register file), etc. + struct InstrStage { + enum ReservationKinds { + Required = 0, + Reserved = 1 + }; + unsigned Cycles_; ///< Length of stage in machine cycles unsigned Units_; ///< Choice of functional units - int NextCycles_; ///< Number of machine cycles to next stage + int NextCycles_; ///< Number of machine cycles to next stage + ReservationKinds Kind_; ///< Kind of the FU reservation /// getCycles - returns the number of cycles the stage is occupied unsigned getCycles() const { @@ -62,6 +76,10 @@ struct InstrStage { return Units_; } + ReservationKinds getReservationKind() const { + return Kind_; + } + /// getNextCycles - returns the number of cycles from the start of /// this stage to the start of the next stage in the itinerary unsigned getNextCycles() const { diff --git a/include/llvm/Target/TargetSchedule.td b/include/llvm/Target/TargetSchedule.td index dcc09921d99..bbf43dec58a 100644 --- a/include/llvm/Target/TargetSchedule.td +++ b/include/llvm/Target/TargetSchedule.td @@ -22,6 +22,13 @@ // class FuncUnit; +class ReservationKind val> { + bits<1> Value = val; +} + +def Required : ReservationKind<0>; +def Reserved : ReservationKind<1>; + //===----------------------------------------------------------------------===// // Instruction stage - These values represent a non-pipelined step in // the execution of an instruction. Cycles represents the number of @@ -36,10 +43,12 @@ class FuncUnit; // InstrStage<1, [FU_x, FU_y]> - TimeInc defaults to Cycles // InstrStage<1, [FU_x, FU_y], 0> - TimeInc explicit // -class InstrStage units, int timeinc = -1> { +class InstrStage units, + int timeinc = -1, ReservationKind kind = Required> { int Cycles = cycles; // length of stage in machine cycles list Units = units; // choice of functional units int TimeInc = timeinc; // cycles till start of next stage + int Kind = kind.Value; // kind of FU reservation } //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/ExactHazardRecognizer.cpp b/lib/CodeGen/ExactHazardRecognizer.cpp index 52908edefc8..af5f2892c2f 100644 --- a/lib/CodeGen/ExactHazardRecognizer.cpp +++ b/lib/CodeGen/ExactHazardRecognizer.cpp @@ -45,14 +45,16 @@ ExactHazardRecognizer(const InstrItineraryData &LItinData) : } } - Scoreboard.reset(ScoreboardDepth); + ReservedScoreboard.reset(ScoreboardDepth); + RequiredScoreboard.reset(ScoreboardDepth); DEBUG(dbgs() << "Using exact hazard recognizer: ScoreboardDepth = " << ScoreboardDepth << '\n'); } void ExactHazardRecognizer::Reset() { - Scoreboard.reset(); + RequiredScoreboard.reset(); + ReservedScoreboard.reset(); } void ExactHazardRecognizer::ScoreBoard::dump() const { @@ -86,10 +88,23 @@ ExactHazardRecognizer::HazardType ExactHazardRecognizer::getHazardType(SUnit *SU // stage is occupied. FIXME it would be more accurate to find the // same unit free in all the cycles. for (unsigned int i = 0; i < IS->getCycles(); ++i) { - assert(((cycle + i) < Scoreboard.getDepth()) && + assert(((cycle + i) < RequiredScoreboard.getDepth()) && "Scoreboard depth exceeded!"); - unsigned freeUnits = IS->getUnits() & ~Scoreboard[cycle + i]; + unsigned freeUnits = IS->getUnits(); + switch (IS->getReservationKind()) { + default: + assert(0 && "Invalid FU reservation"); + case InstrStage::Required: + // Required FUs conflict with both reserved and required ones + freeUnits &= ~ReservedScoreboard[cycle + i]; + // FALLTHROUGH + case InstrStage::Reserved: + // Reserved FUs can conflict only with required ones. + freeUnits &= ~RequiredScoreboard[cycle + i]; + break; + } + if (!freeUnits) { DEBUG(dbgs() << "*** Hazard in cycle " << (cycle + i) << ", "); DEBUG(dbgs() << "SU(" << SU->NodeNum << "): "); @@ -114,16 +129,28 @@ void ExactHazardRecognizer::EmitInstruction(SUnit *SU) { // Use the itinerary for the underlying instruction to reserve FU's // in the scoreboard at the appropriate future cycles. unsigned idx = SU->getInstr()->getDesc().getSchedClass(); - for (const InstrStage *IS = ItinData.beginStage(idx), + for (const InstrStage *IS = ItinData.beginStage(idx), *E = ItinData.endStage(idx); IS != E; ++IS) { // We must reserve one of the stage's units for every cycle the // stage is occupied. FIXME it would be more accurate to reserve // the same unit free in all the cycles. for (unsigned int i = 0; i < IS->getCycles(); ++i) { - assert(((cycle + i) < Scoreboard.getDepth()) && + assert(((cycle + i) < RequiredScoreboard.getDepth()) && "Scoreboard depth exceeded!"); - unsigned freeUnits = IS->getUnits() & ~Scoreboard[cycle + i]; + unsigned freeUnits = IS->getUnits(); + switch (IS->getReservationKind()) { + default: + assert(0 && "Invalid FU reservation"); + case InstrStage::Required: + // Required FUs conflict with both reserved and required ones + freeUnits &= ~ReservedScoreboard[cycle + i]; + // FALLTHROUGH + case InstrStage::Reserved: + // Reserved FUs can conflict only with required ones. + freeUnits &= ~RequiredScoreboard[cycle + i]; + break; + } // reduce to a single unit unsigned freeUnit = 0; @@ -133,17 +160,21 @@ void ExactHazardRecognizer::EmitInstruction(SUnit *SU) { } while (freeUnits); assert(freeUnit && "No function unit available!"); - Scoreboard[cycle + i] |= freeUnit; + if (IS->getReservationKind() == InstrStage::Required) + RequiredScoreboard[cycle + i] |= freeUnit; + else + ReservedScoreboard[cycle + i] |= freeUnit; } // Advance the cycle to the next stage. cycle += IS->getNextCycles(); } - DEBUG(Scoreboard.dump()); + DEBUG(ReservedScoreboard.dump()); + DEBUG(RequiredScoreboard.dump()); } void ExactHazardRecognizer::AdvanceCycle() { - Scoreboard[0] = 0; - Scoreboard.advance(); + ReservedScoreboard[0] = 0; ReservedScoreboard.advance(); + RequiredScoreboard[0] = 0; RequiredScoreboard.advance(); } diff --git a/lib/CodeGen/ExactHazardRecognizer.h b/lib/CodeGen/ExactHazardRecognizer.h index 50fe024d978..91c81a970fa 100644 --- a/lib/CodeGen/ExactHazardRecognizer.h +++ b/lib/CodeGen/ExactHazardRecognizer.h @@ -70,7 +70,8 @@ namespace llvm { // Itinerary data for the target. const InstrItineraryData &ItinData; - ScoreBoard Scoreboard; + ScoreBoard ReservedScoreboard; + ScoreBoard RequiredScoreboard; public: ExactHazardRecognizer(const InstrItineraryData &ItinData); diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp index 9ac652f7993..fb86a704c47 100644 --- a/utils/TableGen/SubtargetEmitter.cpp +++ b/utils/TableGen/SubtargetEmitter.cpp @@ -216,7 +216,7 @@ void SubtargetEmitter::FormItineraryStageString(Record *ItinData, // Next stage const Record *Stage = StageList[i]; - // Form string as ,{ cycles, u1 | u2 | ... | un, timeinc } + // Form string as ,{ cycles, u1 | u2 | ... | un, timeinc, kind } int Cycles = Stage->getValueAsInt("Cycles"); ItinString += " { " + itostr(Cycles) + ", "; @@ -233,6 +233,9 @@ void SubtargetEmitter::FormItineraryStageString(Record *ItinData, int TimeInc = Stage->getValueAsInt("TimeInc"); ItinString += ", " + itostr(TimeInc); + int Kind = Stage->getValueAsInt("Kind"); + ItinString += ", (llvm::InstrStage::ReservationKinds)" + itostr(Kind); + // Close off stage ItinString += " }"; if (++i < N) ItinString += ", "; @@ -278,7 +281,7 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS, // Begin stages table std::string StageTable = "static const llvm::InstrStage Stages[] = {\n"; - StageTable += " { 0, 0, 0 }, // No itinerary\n"; + StageTable += " { 0, 0, 0, llvm::InstrStage::Required }, // No itinerary\n"; // Begin operand cycle table std::string OperandCycleTable = "static const unsigned OperandCycles[] = {\n"; @@ -367,7 +370,7 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS, } // Closing stage - StageTable += " { 0, 0, 0 } // End itinerary\n"; + StageTable += " { 0, 0, 0, llvm::InstrStage::Required } // End itinerary\n"; StageTable += "};\n"; // Closing operand cycles