[llvm-commits] CVS: llvm/lib/Reoptimizer/Inst/InstManip.cpp InstManip.h Phases.cpp SparcInstManip.cpp SparcInstManip.h design.txt
Joel Stanley
jstanley at cs.uiuc.edu
Wed Apr 30 11:30:01 PDT 2003
Changes in directory llvm/lib/Reoptimizer/Inst:
InstManip.cpp updated: 1.10 -> 1.11
InstManip.h updated: 1.11 -> 1.12
Phases.cpp updated: 1.16 -> 1.17
SparcInstManip.cpp updated: 1.1 -> 1.2
SparcInstManip.h updated: 1.1 -> 1.2
design.txt updated: 1.11 -> 1.12
---
Log message:
Another intermediary refactoring point -- in particular, most of the platform-dependent
behavior has been moved into the SparcInstManip class, etc.
---
Diffs of the changes:
Index: llvm/lib/Reoptimizer/Inst/InstManip.cpp
diff -u llvm/lib/Reoptimizer/Inst/InstManip.cpp:1.10 llvm/lib/Reoptimizer/Inst/InstManip.cpp:1.11
--- llvm/lib/Reoptimizer/Inst/InstManip.cpp:1.10 Tue Apr 29 22:08:03 2003
+++ llvm/lib/Reoptimizer/Inst/InstManip.cpp Wed Apr 30 11:36:09 2003
@@ -7,6 +7,7 @@
#include <iostream>
#include <iomanip>
+#include "llvm/Reoptimizer/TraceCache.h"
#include "llvm/Reoptimizer/VirtualMem.h"
#include "InstManip.h"
@@ -40,12 +41,38 @@
ostr << "}";
}
-InstManip::InstManip(VirtualMem* vm):
- m_pVM(vm)
+InstManip::InstManip(TraceCache* tc, unsigned sharedSize, unsigned instWidth):
+ m_pTC(tc),
+ m_pPhase3SpillRegion(0),
+ m_pCurrSpill(0),
+ m_sharedSize(sharedSize),
+ m_instWidth(instWidth)
{
- assert(vm && "InstManip requires valid VirtualMem instance");
+ assert(tc && "InstManip requires valid TraceCache instance");
}
InstManip::~InstManip()
{
+ if(m_pPhase3SpillRegion)
+ delete [] m_pPhase3SpillRegion;
+}
+
+void InstManip::makePhase3SpillRegion(unsigned numFuncs)
+{
+ // Heap-allocate a region of memory in which to spill shared registers before phase3
+ // invocations. We allocate one unit of space (given by getSharedSize()) for each
+ // function that must be transformed.
+
+ m_pPhase3SpillRegion = new uint64_t[getSharedSize() * numFuncs];
+ m_pCurrSpill = m_pPhase3SpillRegion;
+}
+
+void InstManip::copySnippetToSlot(std::vector<unsigned>& snippet, uint64_t slotBase)
+{
+ uint64_t currAddr = slotBase;
+ for(std::vector<unsigned>::iterator i = snippet.begin(),
+ e = snippet.end(); i != e; ++i) {
+ m_pTC->getVM()->writeInstToVM(currAddr, *i);
+ currAddr += getInstWidth();
+ }
}
Index: llvm/lib/Reoptimizer/Inst/InstManip.h
diff -u llvm/lib/Reoptimizer/Inst/InstManip.h:1.11 llvm/lib/Reoptimizer/Inst/InstManip.h:1.12
--- llvm/lib/Reoptimizer/Inst/InstManip.h:1.11 Tue Apr 29 22:08:03 2003
+++ llvm/lib/Reoptimizer/Inst/InstManip.h Wed Apr 30 11:36:09 2003
@@ -4,7 +4,11 @@
// fileid: InstManip.h
// purpose: InstManip is a (pure virtual) class that hdies platform-specific
// instruction manipulation behind a common interface, and provides clients with
-// various instruction manipulation utilities. Only two relevant assumptions are made:
+// various instruction manipulation utilities. Since the structure of the TraceCache
+// "slots" for the various phases of the binary editing for performance
+// instrumentation have structure and content that is platform-dependent, this class
+// also hides the platform-specific details of the slot construction as well. Only
+// two relevant assumptions are made:
//
// * The TraceCache objects (TraceCache, MemoryManager, VirtualMem, etc) from the
// Reoptimizer library work in an appropriate manner on the given platform.
@@ -21,14 +25,21 @@
#include <vector>
#include <algorithm>
-class VirtualMem;
+class TraceCache;
+class Phase2;
+class Phase3;
+class InstCandidate;
+class Phase3Info;
+class Phase4Info;
class InstManip
{
public:
- InstManip(VirtualMem* vm);
+ InstManip(TraceCache* vm, unsigned sharedSize, unsigned instWidth);
virtual ~InstManip();
+ typedef std::pair<uint64_t, uint64_t> AddressRange;
+
// Logical registers used by clients of this class, mapped to machine-specific IDs
// by the logical -> actual register map.
enum LogicalRegister {
@@ -37,19 +48,56 @@
REG_2
};
+ // buildSlot - Fill the provided vector with the instructions that go into the slot
+ // given by the Phase{3,4}Info instance. The proper function is distinguished by type
+ // in this manner because there are not really enough phases to warrant building the
+ // slot-building behavior into the Phase{3,4}Info classes themselves.
+
+ virtual void buildSlot(Phase3Info* p3info,
+ std::vector<unsigned>& snippet) = 0;
+
+ virtual void buildSlot(Phase4Info* p4info,
+ std::vector<unsigned>& snippet) = 0;
+
+ virtual unsigned getSlotSize(Phase2* p2) const = 0;
+ virtual unsigned getSlotSize(Phase3* p3, InstCandidate& cand) const = 0;
+
+ // getStartAddr - return the desired starting position in the function body. This is
+ // useful for skipping standard prologue code that occurs at the start of the function
+ // body.
+
+ virtual uint64_t getStartAddr(uint64_t funcStartAddr) const = 0;
+
+ virtual unsigned getBranchAlways(uint64_t dest, uint64_t pc, bool annulHigh = true) const = 0;
+ virtual bool isBranch(unsigned inst) const = 0;
virtual void printRange(unsigned* start, unsigned* end) const = 0;
virtual void printInst(unsigned inst) const = 0;
- virtual unsigned getInstWidth() const = 0;
+
+ ////
+
+ void makePhase3SpillRegion(unsigned numFuncs);
+ uint64_t* getCurrentSpill() { return m_pCurrSpill; }
+ void advanceSpill() { m_pCurrSpill += getSharedSize(); }
+ void copySnippetToSlot(std::vector<unsigned>& snippet, uint64_t slotBase);
inline void printRange(uint64_t start, uint64_t end) const;
+ unsigned getSharedSize() const { return m_sharedSize; }
+ unsigned getInstWidth() const { return m_instWidth; }
+
protected:
InstManip() {}
typedef std::map<LogicalRegister, unsigned> LogicalToActualRegMap;
LogicalToActualRegMap m_logicalToActualReg; // Maps logical -> actual register
- VirtualMem* m_pVM;
+ TraceCache* m_pTC;
+
+ uint64_t* m_pPhase3SpillRegion; // Base pointer to spill region for phase 3 invocations
+ uint64_t* m_pCurrSpill; // Current location in the phase 3 spill region
+
+ unsigned m_sharedSize; // # of shared registers that must be spilled
+ unsigned m_instWidth; // instruction width, in bytes
};
void InstManip::printRange(uint64_t start, uint64_t end) const
Index: llvm/lib/Reoptimizer/Inst/Phases.cpp
diff -u llvm/lib/Reoptimizer/Inst/Phases.cpp:1.16 llvm/lib/Reoptimizer/Inst/Phases.cpp:1.17
--- llvm/lib/Reoptimizer/Inst/Phases.cpp:1.16 Tue Apr 29 22:08:03 2003
+++ llvm/lib/Reoptimizer/Inst/Phases.cpp Wed Apr 30 11:36:09 2003
@@ -81,6 +81,7 @@
#include "ElfReader.h"
//#include "InstManip.h"
#include "SparcInstManip.h"
+#include "PhaseInfo.h"
using std::vector;
using std::cerr;
@@ -101,92 +102,6 @@
typedef std::pair<uint64_t, uint64_t> AddressRange;
-class Phase3Info
-{
- public:
- Phase3Info(const AddressRange& addressRange,
- unsigned origInst,
- uint64_t replaceAddr,
- uint64_t slotDescriptor,
- unsigned slotSize,
- TraceCache* pTraceCache,
- SparcInstManip* pInstManip):
- m_addrRange(addressRange),
- m_origInst(origInst),
- m_replaceAddr(replaceAddr),
- m_slotDescriptor(slotDescriptor),
- m_slotSize(slotSize),
- m_pTraceCache(pTraceCache),
- m_pInstManip(pInstManip)
- {
- }
-
- void print(std::ostream& ostr)
- {
- ostr << std::hex << "Phase3Info instance: {" << endl
- << " Function address range: [" << m_addrRange.first << ", "
- << m_addrRange.second << "]" << endl
- << " To replace: [" << m_origInst << " @ "
- << m_replaceAddr << "]" << endl
- << "}" << endl;
- }
-
- uint64_t getStartAddr() const { return m_addrRange.first; }
- uint64_t getEndAddr() const { return m_addrRange.second; }
- uint64_t getOrigInst() const { return m_origInst; }
- uint64_t getReplaceAddr() const { return m_replaceAddr; }
- uint64_t getSlot() const { return m_slotDescriptor; }
- uint64_t getSlotSize() const { return m_slotSize; }
- TraceCache* getTraceCache() { return m_pTraceCache; }
- SparcInstManip* getIM() { return m_pInstManip; }
-
- private:
- Phase3Info() {}
-
- AddressRange m_addrRange; // Range of function for phase 3 to examine
- unsigned m_origInst; // Instruction replaced by phase 2
- uint64_t m_replaceAddr; // Address at which to restore original inst
- uint64_t m_slotDescriptor; // Slot created by phase 2
- unsigned m_slotSize; // Size of slot created by phase 2
- TraceCache* m_pTraceCache; // TraceCache instance used by phase 2
- SparcInstManip* m_pInstManip; // The InstManip instance to pass to the next phase
-};
-
-class Phase4Info
-{
- public:
- Phase4Info(const InstCandidate& candidate,
- uint64_t slotDescriptor,
- uint64_t slotSize,
- TraceCache* pTraceCache,
- SparcInstManip* pInstManip):
- m_candidate(candidate),
- m_slotDescriptor(slotDescriptor),
- m_slotSize(slotSize),
- m_pTraceCache(pTraceCache),
- m_pInstManip(pInstManip)
- {
- }
-
- const InstCandidate& getCandidate() const { return m_candidate; }
- uint64_t getSlot() const { return m_slotDescriptor; }
- uint64_t getSlotSize() const { return m_slotSize; }
- TraceCache* getTraceCache() { return m_pTraceCache; }
- SparcInstManip* getIM() { return m_pInstManip; }
-
- private:
- Phase4Info() {}
-
- InstCandidate m_candidate; // Candidate responsible for this instance's creation
- uint64_t m_slotDescriptor; // Slot created by phase 3
- unsigned m_slotSize; // Size of slot created by phase 3
- TraceCache* m_pTraceCache; // TraceCache instance used by phases 2 and 3
- SparcInstManip* m_pInstManip; // The InstManip instance to pass to the next phase
-};
-
-void phase3(Phase3Info* p3info);
-void phase4(uint64_t tag, Phase4Info* p4info);
-
// Phase2 is the class that is responsible for effecting the core of the phase 2
// transformation; the global function phase2() is simply an C-linkage interface.
@@ -199,17 +114,16 @@
private:
Phase2() {}
- inline unsigned getSlotSize() const;
TraceCache* m_pTraceCache;
SparcInstManip* m_pInstManip;
- static uint64_t* sm_pSpillRegion; // Base pointer to the spill region for phase 3 invocations
- static uint64_t* sm_pCurrSpill; // Pointer to current location in the spill region
+ //static uint64_t* sm_pSpillRegion; // Base pointer to the spill region for phase 3 invocations
+ //static uint64_t* sm_pCurrSpill; // Pointer to current location in the spill region
};
-uint64_t* Phase2::sm_pSpillRegion = 0;
-uint64_t* Phase2::sm_pCurrSpill = 0;
+//uint64_t* Phase2::sm_pSpillRegion = 0;
+//uint64_t* Phase2::sm_pCurrSpill = 0;
// Phase3 is the class that is responsible for making the "phase 3" transformation; the
// global function phase3() is responsible for constructing one Phase3 instance per
@@ -227,7 +141,6 @@
Phase3() {}
void processCandidates(vector<InstCandidate>& candidates);
- inline unsigned getSlotSize(InstCandidate&) const;
Phase3Info* m_pPhase3Info;
TraceCache* m_pTraceCache;
@@ -249,8 +162,6 @@
private:
Phase4() {}
- inline unsigned getSlotSize() const;
-
Phase4Info* m_pPhase4Info;
TraceCache* m_pTraceCache;
SparcInstManip* m_pInstManip;
@@ -262,7 +173,7 @@
extern "C" void phase2()
{
TraceCache* pTC = new TraceCache();
- SparcInstManip* pIM = new SparcInstManip(pTC->getVM());
+ SparcInstManip* pIM = new SparcInstManip(pTC);
Phase2 ph(pTC, pIM);
ph.transform();
}
@@ -295,12 +206,10 @@
cerr << "There are " << funcs.size() << " functions to process." << endl << endl;
- // Heap-allocate a region of memory in which to spill shared registers before phase3
- // invocations. We allocate one unit of space (given by InstManip::getSharedSize())
- // for each function that we transform.
-
- sm_pSpillRegion = new uint64_t[m_pInstManip->getSharedSize() * funcs.size()];
- sm_pCurrSpill = sm_pSpillRegion;
+ m_pInstManip->makePhase3SpillRegion(funcs.size());
+
+ //sm_pSpillRegion = new uint64_t[m_pInstManip->getSharedSize() * funcs.size()];
+ //sm_pCurrSpill = sm_pSpillRegion;
for(vector<std::pair<std::string, AddressRange> >::iterator i = funcs.begin(),
e = funcs.end(); i != e; ++i) {
@@ -317,17 +226,68 @@
static void copySnippetToSlot(vector<unsigned>& snippet,
uint64_t slotBase,
VirtualMem* vm,
- InstManip& im)
+ InstManip* im)
{
uint64_t currAddr = slotBase;
for(vector<unsigned>::iterator i = snippet.begin(), e = snippet.end(); i != e; ++i) {
vm->writeInstToVM(currAddr, *i);
- currAddr += im.getInstWidth();
+ currAddr += im->getInstWidth();
}
}
+static uint64_t replaceInstWithBrToSlot(uint64_t srcAddr,
+ unsigned slotSize,
+ TraceCache* tc,
+ InstManip* im)
+{
+ // Obtain a new slot of the given size
+ uint64_t slotBase = tc->getMemMgr()->getMemory(slotSize);
+ assert(slotBase && "Unable to obtain memory from MemoryManager instance");
+
+ // Replace instruction at srcAddr with branch to start of new slot
+ tc->getVM()->writeInstToVM(srcAddr, im->getBranchAlways(slotBase, srcAddr));
+
+ return slotBase;
+}
+
void Phase2::transformFunction(AddressRange& range)
{
+ // Obtain address of first replacable instruction in function and obtain a new slot
+ // from the TraceCache memory manager (i.e., a new slot in the dummy function). Hold
+ // onto the replaced instruction for later restoration.
+
+ VirtualMem* vm = m_pTraceCache->getVM();
+ uint64_t repInstAddr = m_pInstManip->getStartAddr(range.first);
+ unsigned origInst = vm->readInstrFrmVm(repInstAddr);
+
+ assert(!m_pInstManip->isBranch(origInst) &&
+ "Unhandled case: branch instruction first in function body");
+
+ unsigned slotSize = m_pInstManip->getSlotSize(this);
+
+ // Replace instruction at repInstAddr with a branch to start of a new slot.
+ uint64_t slotBase = replaceInstWithBrToSlot(repInstAddr, slotSize, m_pTraceCache, m_pInstManip);
+
+ // Build the Phase3Info structure and generate the phase 3 slot.
+
+ Phase3Info* p3info = new Phase3Info(range, origInst, repInstAddr,
+ slotBase, slotSize, m_pTraceCache, m_pInstManip);
+
+ vector<unsigned> snippet;
+ m_pInstManip->buildSlot(p3info, snippet);
+
+ // Dump snippet instructions:
+ cerr << "phase3 slot instructions:" << endl;
+ for(vector<unsigned>::iterator j = snippet.begin(), k = snippet.end(); j != k; ++j) {
+ m_pInstManip->printInst(*j);
+ cerr << endl;
+ }
+
+ // Copy the snippet code into the slot
+ copySnippetToSlot(snippet, slotBase, vm, m_pInstManip);
+
+ // {{{ Old version of this function
+#if 0
// Obtain address of first replacable instruction in function and obtain a new slot from
// the TraceCache memory manager (i.e., a new slot in the dummy function).
@@ -350,11 +310,13 @@
vector<unsigned> snippet;
m_pInstManip->startCode(snippet);
+ uint64_t* pCurrSpill = m_pInstManip->getCurrentSpill();
+
m_pInstManip->generateSave();
- m_pInstManip->generateSpillShared((uint64_t) sm_pCurrSpill);
+ m_pInstManip->generateSpillShared((uint64_t) pCurrSpill);
m_pInstManip->generateLoad((uint64_t) p3info, InstManip::REG_0, InstManip::REG_1);
m_pInstManip->generateCall((uint64_t) &phase3, slotBase);
- m_pInstManip->generateRestoreShared((uint64_t) sm_pCurrSpill);
+ m_pInstManip->generateRestoreShared((uint64_t) pCurrSpill);
m_pInstManip->generateBranchAlways(repInstAddr, slotBase, m_pInstManip->getRestoreInst());
m_pInstManip->endCode();
@@ -369,13 +331,17 @@
// Bump the current spill pointer to the next "spill slot" in the spill region used
// before/after phase3() invocations.
- sm_pCurrSpill += m_pInstManip->getSharedSize();
+ m_pInstManip->advanceSpill();
+ //sm_pCurrSpill += m_pInstManip->getSharedSize();
// Copy the snippet code into the slot
assert(snippet.size() == getSlotSize() && "Snippet size does not match slot size");
- copySnippetToSlot(snippet, slotBase, vm, *m_pInstManip);
+ copySnippetToSlot(snippet, slotBase, vm, m_pInstManip);
+#endif
+ // }}}
}
+#if 0
unsigned Phase2::getSlotSize() const
{
// The following sum corresponds to the sizes consumed by the various regions of the
@@ -388,6 +354,7 @@
m_pInstManip->getGenRestoreSharedSize() +
m_pInstManip->getGenBranchAlwaysSize();
}
+#endif
//////////////// Phase3 implementation ////////////////
@@ -431,23 +398,43 @@
delete m_pPhase3Info;
}
-static uint64_t replaceInstWithBrToSlot(uint64_t srcAddr,
- unsigned slotSize,
- TraceCache* tc,
- SparcInstManip& im)
+void Phase3::processCandidates(vector<InstCandidate>& candidates)
{
- // Obtain a new slot of the given size
- uint64_t slotBase = tc->getMemMgr()->getMemory(slotSize);
- assert(slotBase && "Unable to obtain memory from MemoryManager instance");
+ // For each load candidate, obtain a new slot and write the phase 4 slot region
+ // contents into it.
- // Replace instruction at srcAddr with branch to start of new slot
- tc->getVM()->writeInstToVM(srcAddr, im.getBranchAlways(slotBase, srcAddr));
+ for(vector<InstCandidate>::iterator i = candidates.begin(), e = candidates.end(); i != e; ++i) {
+ cerr << "Transforming " << *i << endl;
+ unsigned slotSize = m_pInstManip->getSlotSize(this, *i);
- return slotBase;
-}
+ // Replace load candidate instruction with a branch to the start of a new slot.
+ uint64_t slotBase = replaceInstWithBrToSlot(i->front().first, slotSize,
+ m_pTraceCache, m_pInstManip);
-void Phase3::processCandidates(vector<InstCandidate>& candidates)
-{
+ // Build the Phase4Info structure and generate the phase 4 slot.
+
+ Phase4Info* p4info = new Phase4Info(*i, slotBase, slotSize, m_pTraceCache, m_pInstManip);
+
+ vector<unsigned> snippet;
+ m_pInstManip->buildSlot(p4info, snippet);
+
+ // Dump snippet instructions:
+ cerr << "phase4 slot instructions:" << endl;
+ for(vector<unsigned>::iterator j = snippet.begin(), k = snippet.end(); j != k; ++j) {
+ m_pInstManip->printInst(*j);
+ cerr << endl;
+ }
+
+ // Copy the snippet code into the slot
+ copySnippetToSlot(snippet, slotBase, m_pTraceCache->getVM(), m_pInstManip);
+
+ // just one candidate for now
+ break;
+ }
+
+ // {{{ Old version of this function
+
+#if 0
// For each load candidate, obtain a new slot and write the phase 3 slot region
// contents into it. See diagram in comments at top of file for more info.
@@ -496,13 +483,17 @@
// Copy the snippet code into the slot
assert(snippet.size() == getSlotSize(*i) && "Snippet size does not match slot size");
- copySnippetToSlot(snippet, slotBase, m_pTraceCache->getVM(), *m_pInstManip);
+ copySnippetToSlot(snippet, slotBase, m_pTraceCache->getVM(), m_pInstManip);
// just one candidate for now
break;
}
+#endif
+
+ // }}}
}
+#if 0
unsigned Phase3::getSlotSize(InstCandidate& cand) const
{
// The following sum corresponds to the sizes consumed by the various regions of the
@@ -518,6 +509,7 @@
m_pInstManip->getGenRestoreSharedSize() +
m_pInstManip->getGenBranchAlwaysSize();
}
+#endif
void Phase3::transform()
{
Index: llvm/lib/Reoptimizer/Inst/SparcInstManip.cpp
diff -u llvm/lib/Reoptimizer/Inst/SparcInstManip.cpp:1.1 llvm/lib/Reoptimizer/Inst/SparcInstManip.cpp:1.2
--- llvm/lib/Reoptimizer/Inst/SparcInstManip.cpp:1.1 Tue Apr 29 22:08:03 2003
+++ llvm/lib/Reoptimizer/Inst/SparcInstManip.cpp Wed Apr 30 11:36:09 2003
@@ -7,27 +7,34 @@
#include <iostream>
#include <iomanip>
+#include "llvm/Reoptimizer/TraceCache.h"
#include "llvm/Reoptimizer/VirtualMem.h"
+#include "llvm/Reoptimizer/MemoryManager.h"
#include "llvm/Reoptimizer/BinInterface/sparc9.h"
#include "llvm/Reoptimizer/BinInterface/bitmath.h"
#include "SparcInstManip.h"
+#include "PhaseInfo.h"
const unsigned SparcInstManip::NOP_INST = 0x01000000;
const unsigned SparcInstManip::BRANCH_ALWAYS_BASE = 0x10480000;
const unsigned SparcInstManip::BRANCH_ALWAYS_BASE_ANNUL = 0x30480000;
const unsigned SparcInstManip::BIAS = 2047;
-uint64_t SparcInstManip::sm_phase3SpillRegion[SparcInstManip::SHARED_SIZE];
+uint64_t SparcInstManip::sm_phase4SpillRegion[SparcInstManip::SHARED_SIZE];
using std::cout;
using std::cerr;
using std::endl;
+using std::vector;
-SparcInstManip::SparcInstManip(VirtualMem* vm):
- InstManip(vm),
+void phase3(Phase3Info* p3info);
+void phase4(uint64_t tag, Phase4Info* p4info);
+
+SparcInstManip::SparcInstManip(TraceCache* tc):
+ InstManip(tc, SHARED_SIZE, INST_WIDTH),
m_pCurrSnippet(0)
{
- assert(vm && "SparcInstManip requires valid VirtualMem instance");
+ assert(tc && "SparcInstManip requires valid TraceCache instance");
// Populate logical->actual register map. Since this SparcInstManip class is
// SparcV9-specific, we map to the values used by the BinInterface library and macros.
@@ -55,6 +62,110 @@
m_outputToInputReg[i] = i;
}
+void SparcInstManip::buildSlot(Phase3Info* p3info,
+ std::vector<unsigned>& snippet)
+{
+ // Build phase 3 slot. See ASCII diagram of phase 3 slot contents for details.
+
+ assert(p3info && "buildSlot requires valid p3info ptr");
+
+ uint64_t slotBase = p3info->getSlot();
+ uint64_t spillAddr = (uint64_t) getCurrentSpill();
+
+ startCode(snippet);
+
+ generateSave();
+ generateSpillShared(spillAddr);
+ generateLoad((uint64_t) p3info, REG_0, REG_1);
+ generateCall((uint64_t) &phase3, slotBase);
+ generateRestoreShared(spillAddr);
+ generateBranchAlways(p3info->getReplaceAddr(), slotBase, getRestoreInst());
+
+ endCode();
+ advanceSpill();
+ assert(snippet.size() == p3info->getSlotSize() &&
+ "Snippet size does not match expected slot size");
+}
+
+
+void SparcInstManip::buildSlot(Phase4Info* p4info,
+ std::vector<unsigned>& snippet)
+{
+ // Build phase 4 slot. See ASCII diagram of phase 4 slot contents for details.
+
+ uint64_t slotBase = p4info->getSlot();
+ uint64_t spillAddr = (uint64_t) getPhase4SpillAddr();
+ const InstCandidate& cand = p4info->getCandidate();
+
+ // NB: We pass parameters to the phase4 function in REG_0 and REG_1 on the assumption
+ // that the input parameters will be looked for there. However, it is possible that
+ // the input parameters will be taken from the parameter array at fixed offsets from
+ // the stack pointer. Hence, we store the parameters there as well.
+
+ startCode(snippet);
+
+ generateSave();
+ generateAddressCopy(cand.front().second, REG_0, true); // REG_0 live to call
+ generateParamStore(REG_0, PARAM_0);
+ generateSpillShared(spillAddr, REG_1, REG_2);
+ generateLoad((uint64_t) p4info, REG_1, REG_2); // REG_1 live to call
+ generateParamStore(REG_1, PARAM_1);
+ generateCall((uint64_t) &phase4, slotBase);
+ generateRestoreShared(spillAddr);
+ generateBranchAlways(cand.front().first, slotBase, getRestoreInst());
+
+ endCode();
+ assert(snippet.size() == p4info->getSlotSize() &&
+ "Snippet size does not match expected slot size");
+}
+
+unsigned SparcInstManip::getSlotSize(Phase2* p2) const
+{
+ // The following sum corresponds to the sizes consumed by the various regions of the
+ // the slot constructed by phase 2, called the phase 3 slot. See ASCII diagram of
+ // phase 3 slot contents for details.
+
+ (void) p2;
+
+ return getGenSaveSize() +
+ getGenSpillSharedSize() +
+ getGenLoadSize() +
+ getGenCallSize() +
+ getGenRestoreSharedSize() +
+ getGenBranchAlwaysSize();
+}
+
+unsigned SparcInstManip::getSlotSize(Phase3* p3, InstCandidate& cand) const
+{
+ // The following sum corresponds to the sizes consumed by the various regions of the
+ // the slot constructed by phase 3, called the phase 4 slot. See ASCII diagram of
+ // phase 4 slot contents for details.
+
+ (void) p3;
+
+ return getGenSaveSize() +
+ getGenAddressCopySize(cand.front().second) +
+ getGenParamStoreSize() +
+ getGenSpillSharedSize() +
+ getGenLoadSize() +
+ getGenParamStoreSize() +
+ getGenCallSize() +
+ getGenRestoreSharedSize() +
+ getGenBranchAlwaysSize();
+}
+
+uint64_t SparcInstManip::getStartAddr(uint64_t addr) const
+{
+ // For SparcV9, skip the save instruction, if present.
+
+ unsigned inst = m_pTC->getVM()->readInstrFrmVm(addr);
+ assert(RD_FLD(inst, INSTR_OP) == OP_2 &&
+ RD_FLD(inst, INSTR_OP3) == OP3_SAVE &&
+ "Unhandled case: non-save instruction in function header");
+
+ return addr + getInstWidth();
+}
+
void SparcInstManip::printRange(unsigned* start,
unsigned* end) const
{
@@ -80,19 +191,6 @@
fflush(stdout);
}
-uint64_t SparcInstManip::skipFunctionHdr(uint64_t addr) const
-{
- // For SparcV9, what we're calling the "function header" is the save instruction (if
- // present) that occurs as the first instruction of the function.
-
- unsigned inst = m_pVM->readInstrFrmVm(addr);
- assert(RD_FLD(inst, INSTR_OP) == OP_2 &&
- RD_FLD(inst, INSTR_OP3) == OP3_SAVE &&
- "Unhandled case: non-save instruction in function header");
-
- return addr + getInstWidth();
-}
-
void SparcInstManip::generateLoad(uint64_t value,
LogicalRegister dest,
LogicalRegister tmp)
@@ -103,7 +201,7 @@
assert(m_pCurrSnippet && "Invalid snippet for code generation");
assert(dest != tmp && "Distinct logical registers required");
- std::vector<unsigned>& snippet = *m_pCurrSnippet;
+ vector<unsigned>& snippet = *m_pCurrSnippet;
unsigned initSize = snippet.size();
unsigned destReg = m_logicalToActualReg[dest];
@@ -139,7 +237,7 @@
// input registers.
assert(m_pCurrSnippet && "Invalid snippet for code generation");
- std::vector<unsigned>& snippet = *m_pCurrSnippet;
+ vector<unsigned>& snippet = *m_pCurrSnippet;
unsigned initSize = snippet.size();
unsigned destReg = m_logicalToActualReg[dest];
@@ -171,7 +269,7 @@
StackOffset off)
{
assert(m_pCurrSnippet && "Invalid snippet for code generation");
- std::vector<unsigned>& snippet = *m_pCurrSnippet;
+ vector<unsigned>& snippet = *m_pCurrSnippet;
unsigned initSize = snippet.size();
unsigned srcReg = m_logicalToActualReg[src];
@@ -186,7 +284,7 @@
uint64_t slotBase)
{
assert(m_pCurrSnippet && "Invalid snippet for code generation");
- std::vector<unsigned>& snippet = *m_pCurrSnippet;
+ vector<unsigned>& snippet = *m_pCurrSnippet;
unsigned initSize = snippet.size();
@@ -210,7 +308,7 @@
void SparcInstManip::generateRestore()
{
assert(m_pCurrSnippet && "Invalid snippet for code generation");
- std::vector<unsigned>& snippet = *m_pCurrSnippet;
+ vector<unsigned>& snippet = *m_pCurrSnippet;
unsigned initSize = snippet.size();
@@ -223,7 +321,7 @@
void SparcInstManip::generateSave()
{
assert(m_pCurrSnippet && "Invalid snippet for code generation");
- std::vector<unsigned>& snippet = *m_pCurrSnippet;
+ vector<unsigned>& snippet = *m_pCurrSnippet;
unsigned initSize = snippet.size();
@@ -244,7 +342,7 @@
assert(m_pCurrSnippet && "Invalid snippet for code generation");
assert(tmp1 != tmp2 && "Distinct logical registers required");
- std::vector<unsigned>& snippet = *m_pCurrSnippet;
+ vector<unsigned>& snippet = *m_pCurrSnippet;
unsigned initSize = snippet.size();
unsigned tmpReg = m_logicalToActualReg[tmp1];
@@ -268,7 +366,7 @@
assert(m_pCurrSnippet && "Invalid snippet for code generation");
assert(tmp1 != tmp2 && "Distinct logical registers required");
- std::vector<unsigned>& snippet = *m_pCurrSnippet;
+ vector<unsigned>& snippet = *m_pCurrSnippet;
unsigned initSize = snippet.size();
unsigned tmpReg = m_logicalToActualReg[tmp1];
@@ -290,7 +388,7 @@
unsigned delaySlotInstr)
{
assert(m_pCurrSnippet && "Invalid snippet for code generation");
- std::vector<unsigned>& snippet = *m_pCurrSnippet;
+ vector<unsigned>& snippet = *m_pCurrSnippet;
unsigned initSize = snippet.size();
@@ -306,8 +404,8 @@
}
void SparcInstManip::findCandidates(uint64_t start,
- uint64_t end,
- std::vector<InstCandidate>& candidates)
+ uint64_t end,
+ vector<InstCandidate>& candidates)
{
for(uint64_t currAddr = start; currAddr <= end; currAddr += getInstWidth()) {
InstCandidate cand(this);
@@ -404,11 +502,11 @@
// Last schema-2 search: find the STB instruction that stores from the
// LDUB's destination register.
- unsigned ldubInst = m_pVM->readInstrFrmVm(stkLoadAddr);
+ unsigned ldubInst = m_pTC->getVM()->readInstrFrmVm(stkLoadAddr);
uint64_t stbAddr = findNextStore(stkLoadAddr, end, getLoadDest(ldubInst));
unsigned stbInst;
- if(stbAddr && isSTB((stbInst = m_pVM->readInstrFrmVm(stbAddr)))) {
+ if(stbAddr && isSTB((stbInst = m_pTC->getVM()->readInstrFrmVm(stbAddr)))) {
// All of the criteria have been met for Schema 2, the "stack transfer"
// pattern.
@@ -467,7 +565,7 @@
// Address of potential candidate load is given by 'addr', maximum search address is
// given by 'end'
- unsigned inst = m_pVM->readInstrFrmVm(addr);
+ unsigned inst = m_pTC->getVM()->readInstrFrmVm(addr);
if(isLoadHalfWord(inst)) {
// Search forward until a sth/stb from inst's target register is encountered
@@ -475,7 +573,7 @@
// If STB, take actions for schema 1, otherwise check for schema 2 conditions.
- unsigned storeInst = m_pVM->readInstrFrmVm(storeAddr);
+ unsigned storeInst = m_pTC->getVM()->readInstrFrmVm(storeAddr);
std::pair<uint64_t, unsigned> inst1(addr, inst);
std::pair<uint64_t, unsigned> inst2(storeAddr, storeInst);
@@ -495,7 +593,7 @@
// an instance cannot be found.
for(uint64_t currAddr = addr; currAddr <= end; currAddr += getInstWidth()) {
- unsigned inst = m_pVM->readInstrFrmVm(currAddr);
+ unsigned inst = m_pTC->getVM()->readInstrFrmVm(currAddr);
if(isLoadByte(inst) && isFPRelative(inst) && getFPOffset(inst) == fpOffset)
return currAddr;
@@ -513,7 +611,7 @@
// 0 if such an instance cannot be found.
for(uint64_t currAddr = addr; currAddr <= end; currAddr += getInstWidth()) {
- unsigned inst = m_pVM->readInstrFrmVm(currAddr);
+ unsigned inst = m_pTC->getVM()->readInstrFrmVm(currAddr);
if(isSTH(inst) || isSTB(inst) && getStoreSrc(inst) == srcReg)
return currAddr;
}
Index: llvm/lib/Reoptimizer/Inst/SparcInstManip.h
diff -u llvm/lib/Reoptimizer/Inst/SparcInstManip.h:1.1 llvm/lib/Reoptimizer/Inst/SparcInstManip.h:1.2
--- llvm/lib/Reoptimizer/Inst/SparcInstManip.h:1.1 Tue Apr 29 22:08:03 2003
+++ llvm/lib/Reoptimizer/Inst/SparcInstManip.h Wed Apr 30 11:36:09 2003
@@ -17,7 +17,7 @@
class SparcInstManip : public InstManip
{
public:
- SparcInstManip(VirtualMem* vm);
+ SparcInstManip(TraceCache* vm);
// Offsets in stack frame for function parameters
enum StackOffset {
@@ -25,12 +25,23 @@
PARAM_1 = 136
};
+ // Overloaded functions
+
+ virtual void buildSlot(Phase3Info* p3info,
+ std::vector<unsigned>& snippet);
+
+ virtual void buildSlot(Phase4Info* p3info,
+ std::vector<unsigned>& snippet);
+
+ virtual unsigned getSlotSize(Phase2* p2) const;
+ virtual unsigned getSlotSize(Phase3* p3, InstCandidate& cand) const;
+ virtual uint64_t getStartAddr(uint64_t funcStartAddr) const;
+ inline unsigned getBranchAlways(uint64_t dest, uint64_t pc, bool annulHigh = true) const;
+ inline bool isBranch(unsigned inst) const;
virtual void printRange(unsigned* start, unsigned* end) const;
virtual void printInst(unsigned inst) const;
////
-
- uint64_t skipFunctionHdr(uint64_t addr) const;
void startCode(std::vector<unsigned>& snippet) { m_pCurrSnippet = &snippet; }
void endCode() { m_pCurrSnippet = 0; }
@@ -67,9 +78,7 @@
std::vector<InstCandidate>& candidates);
unsigned getRestoreInst() const;
- inline unsigned getBranchAlways(uint64_t dest, uint64_t pc, bool annulHigh = true) const;
inline unsigned getCallInst(uint64_t dest, uint64_t pc) const;
- inline bool isBranch(unsigned inst) const;
// These are functions so when SparcInstManip is superclassed, they'd become virtual, etc.
// In the short term we could use class constants, but this is more clear.
@@ -80,15 +89,13 @@
unsigned getGenBranchAlwaysSize() const { return 2; }
unsigned getGenSaveSize() const { return 1; }
unsigned getGenParamStoreSize() const { return 1; }
- unsigned getGenSpillSharedSize() const { return getGenLoadSize() + SHARED_SIZE; }
- unsigned getGenRestoreSharedSize() const { return getGenLoadSize() + SHARED_SIZE; }
+ unsigned getGenSpillSharedSize() const { return getGenLoadSize() + getSharedSize(); }
+ unsigned getGenRestoreSharedSize() const { return getGenLoadSize() + getSharedSize(); }
unsigned getGenRestoreSize() const { return 1; }
- virtual unsigned getInstWidth() const { return 4; }
- unsigned getSharedSize() const { return SHARED_SIZE; }
inline unsigned getGenAddressCopySize(unsigned loadInst) const;
- uint64_t getPhase3SpillAddr() { return (uint64_t) sm_phase3SpillRegion; }
+ uint64_t getPhase4SpillAddr() { return (uint64_t) sm_phase4SpillRegion; }
private:
SparcInstManip() {}
@@ -126,6 +133,9 @@
// Size (in number of 64-bit words) required for storing shared registers
static const unsigned SHARED_SIZE = 7;
+ // Instruction width (in bytes)
+ static const unsigned INST_WIDTH = 4;
+
// Sparc-specific constant used in SP manipulations
static const unsigned BIAS;
@@ -135,7 +145,7 @@
// because only one activation of a phase 4 slot ever occurs at a given time (assuming
// single-threaded execution).
- static uint64_t sm_phase3SpillRegion[SHARED_SIZE];
+ static uint64_t sm_phase4SpillRegion[SHARED_SIZE];
};
unsigned SparcInstManip::getBranchAlways(uint64_t dest, uint64_t pc, bool annul) const
Index: llvm/lib/Reoptimizer/Inst/design.txt
diff -u llvm/lib/Reoptimizer/Inst/design.txt:1.11 llvm/lib/Reoptimizer/Inst/design.txt:1.12
--- llvm/lib/Reoptimizer/Inst/design.txt:1.11 Tue Apr 29 21:08:42 2003
+++ llvm/lib/Reoptimizer/Inst/design.txt Wed Apr 30 11:36:09 2003
@@ -886,11 +886,8 @@
{{{ TODO
- - Get phase 2 allocation of spill space working, write spill code (to spill space) for
- phase 3 invocation. (Currently NO spilling is being done, which is not safe)
-
- - Ensure phase 3 writes proper spill code for phase 4 invocation. (One spill space
- should be sufficient)
+ - Refactor for platform independence, or at least approximate closely a good refactoring.
+ - Suggest making a slot builder class as well -- pull out slot creation from InstManip.
- Start table-of-stacks implementation for phase4 authorship of phase 5 slots.
More information about the llvm-commits
mailing list