[llvm-commits] CVS: llvm/lib/Reoptimizer/Inst/InstManip.cpp InstManip.h Phases.cpp
Joel Stanley
jstanley at cs.uiuc.edu
Fri Apr 11 00:21:01 PDT 2003
Changes in directory llvm/lib/Reoptimizer/Inst:
InstManip.cpp updated: 1.4 -> 1.5
InstManip.h updated: 1.4 -> 1.5
Phases.cpp updated: 1.8 -> 1.9
---
Log message:
Implemented remainder of code generation for phase 3 invocation; added
Phase3Info class for passing information between phase 2 and phase 3.
---
Diffs of the changes:
Index: llvm/lib/Reoptimizer/Inst/InstManip.cpp
diff -u llvm/lib/Reoptimizer/Inst/InstManip.cpp:1.4 llvm/lib/Reoptimizer/Inst/InstManip.cpp:1.5
--- llvm/lib/Reoptimizer/Inst/InstManip.cpp:1.4 Thu Apr 10 18:23:58 2003
+++ llvm/lib/Reoptimizer/Inst/InstManip.cpp Fri Apr 11 00:22:20 2003
@@ -11,6 +11,8 @@
#include "llvm/Reoptimizer/BinInterface/bitmath.h"
#include "InstManip.h"
+const unsigned InstManip::NOP_INST = 0x01000000;
+
void InstManip::printRange(unsigned* start, unsigned* end) const
{
// Dumps contents (and corresponding disassembly) of memory range given by range
@@ -35,12 +37,16 @@
// present) that occurs as the first instruction of the function.
unsigned inst = vm->readInstrFrmVm(addr);
- return RD_FLD(inst, INSTR_OP3) == OP3_SAVE ? addr + 4 : 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 InstManip::generateLoad64(uint64_t value,
- std::vector<unsigned>& snippet,
- TargetRegister reg) const
+void InstManip::generateLoad(uint64_t value,
+ std::vector<unsigned>& snippet,
+ TargetRegister reg) const
{
// When reg == REG_0, load the 64-bit value into %o0, using %o0 and %o1.
// When reg == REG_1, load the 64-bit value into %o1, using %o1 and %o2.
@@ -79,6 +85,42 @@
// add %o0, (lwr 10b of lwr wrd), %o0
snippet.push_back(MK_ADD_R_I(destReg, destReg, LOW10(LOWWORD(value))));
- assert(snippet.size() - initSize == getGenLoad64Size() &&
+ assert(snippet.size() - initSize == getGenLoadSize() &&
"Unexpected number of instructions in code sequence for 64-bit value -> %destReg");
}
+
+void InstManip::generateCall(uint64_t dest,
+ uint64_t slotBase,
+ std::vector<unsigned>& snippet)
+{
+ unsigned initSize = snippet.size();
+
+ // Calculate address of call instruction from slotBase
+ uint64_t callInstAddr = slotBase + getInstWidth() * snippet.size();
+
+ // Add call instruction and nop (for call delay slot) to code snippet.
+ snippet.push_back(getCallInst(dest, callInstAddr));
+ snippet.push_back(NOP_INST);
+
+ assert(snippet.size() - initSize == getGenCallSize() &&
+ "Unexpected number of instructions in code sequence for call");
+}
+
+void InstManip::generateBranchAlways(uint64_t dest,
+ uint64_t slotBase,
+ std::vector<unsigned>& snippet,
+ bool annul)
+{
+ unsigned initSize = snippet.size();
+
+ // Calculate address of branch instruction from slotBase
+ uint64_t branchInstAddr = slotBase + getInstWidth() * snippet.size();
+
+ // Add branch instruction and nop (for branch delay slot) to code snippet.
+ snippet.push_back(getBranchAlways(dest, branchInstAddr, annul));
+ snippet.push_back(NOP_INST);
+
+ assert(snippet.size() - initSize == getGenBranchAlwaysSize() &&
+ "Unexpected number of instruction in code sequence for branch-always");
+}
+
Index: llvm/lib/Reoptimizer/Inst/InstManip.h
diff -u llvm/lib/Reoptimizer/Inst/InstManip.h:1.4 llvm/lib/Reoptimizer/Inst/InstManip.h:1.5
--- llvm/lib/Reoptimizer/Inst/InstManip.h:1.4 Thu Apr 10 18:23:58 2003
+++ llvm/lib/Reoptimizer/Inst/InstManip.h Fri Apr 11 00:22:20 2003
@@ -15,7 +15,8 @@
#include <vector>
#include "llvm/Reoptimizer/BinInterface/sparcdis.h"
-#include "llvm/Reoptimizer/InstrUtils.h"
+#include "llvm/Reoptimizer/InstrUtils.h" // getCallInstr, getUndepJumpInstr, etc.
+
class VirtualMem;
class InstManip
@@ -31,20 +32,36 @@
uint64_t skipFunctionHdr(uint64_t addr, VirtualMem* vm) const;
- void generateLoad64(uint64_t value,
- std::vector<unsigned>& snippet,
- TargetRegister reg = REG_0) const;
-
+ void generateLoad(uint64_t value,
+ std::vector<unsigned>& snippet,
+ TargetRegister reg = REG_0) const;
+
+ void generateCall(uint64_t dest,
+ uint64_t slotBase,
+ std::vector<unsigned>& snippet);
+
+ void generateBranchAlways(uint64_t dest,
+ uint64_t slotBase,
+ std::vector<unsigned>& snippet,
+ bool annul = true);
+
inline unsigned getBranchAlways(uint64_t dest, uint64_t pc, bool annulHigh = true) const;
- inline unsigned getCall(uint64_t dest, uint64_t pc) const;
+ inline unsigned getCallInst(uint64_t dest, uint64_t pc) const;
inline bool isBranch(unsigned inst) const;
- unsigned getNOP() const { return 0x01000000; }
- unsigned getGenLoad64Size() const { return 6; }
+ // These are functions so when InstManip is superclassed, they'd become virtual, etc.
+ // In the short term we could use class constants, but this is more clear.
+
+ unsigned getNOP() const { return 0x01000000; }
+ unsigned getGenLoadSize() const { return 6; }
+ unsigned getGenCallSize() const { return 2; }
+ unsigned getGenBranchAlwaysSize() const { return 2; }
+ unsigned getInstWidth() const { return 4; }
private:
// Branch-always (annul bit high) instruction base (i.e. address not filled in yet)
static const unsigned BRANCH_ALWAYS_BASE = 0x30480000;
+ static const unsigned NOP_INST;
};
void InstManip::printRange(uint64_t start, uint64_t end) const
@@ -74,7 +91,7 @@
return getUndepJumpInstr(BRANCH_ALWAYS_BASE, dest, pc);
}
-unsigned InstManip::getCall(uint64_t dest, uint64_t pc) const
+unsigned InstManip::getCallInst(uint64_t dest, uint64_t pc) const
{
// dest is the destination address to call, pc is the value of the program counter
// when the call instruction is executed (i.e., the address of the branch
@@ -89,6 +106,3 @@
}
#endif // _INCLUDED_INSTMANIP_H
-
-
-
Index: llvm/lib/Reoptimizer/Inst/Phases.cpp
diff -u llvm/lib/Reoptimizer/Inst/Phases.cpp:1.8 llvm/lib/Reoptimizer/Inst/Phases.cpp:1.9
--- llvm/lib/Reoptimizer/Inst/Phases.cpp:1.8 Thu Apr 10 18:40:49 2003
+++ llvm/lib/Reoptimizer/Inst/Phases.cpp Fri Apr 11 00:22:20 2003
@@ -15,15 +15,30 @@
// 2a. Replace the first instruction in F with a branch to a new slot in the
// dummy function.
//
-// 2b. Obtain a heap region to write the phase 3 call into.
-//
-// 2c. At the new slot write the indirect jump to the heap region, followed by
-// the original (replaced) instruction and branch brack to original code.
+// 2b. At the new slot write the call to phase 3, passing it a pointer to an
+// info structure which contains the original (replaced) instruction, the
+// address range of the function, etc.
//
-// 2d. Write code to call phase 3 into the heap region, etc.
+// 2c. At the end of the new slot write the direct branch back to the original
+// code.
//
// PHASE 3:
//
+// 1. Replace the original (replaced) instruction at the proper location in the
+// original code.
+//
+// 2. Delete any slots and/or heap frames which have been marked for deletion by
+// earlier invocations of phase3/4.
+//
+// 3. Analyze the function and determine the load-volatile candidates.
+//
+// 4. For each load-volatile candidate,
+//
+// 4a.
+//
+// 5. Deallocate the parameter structure and mark the phase 2 slot for deletion by a
+// later invocation of phase 3.
+//
// PHASE 4:
//
@@ -31,6 +46,7 @@
#include <iostream>
#include <iomanip>
#include <vector>
+#include <algorithm>
#include "llvm/Reoptimizer/TraceCache.h"
#include "llvm/Reoptimizer/VirtualMem.h"
@@ -43,7 +59,52 @@
using std::cerr;
using std::endl;
-void phase3(uint64_t value);
+typedef std::pair<uint64_t, uint64_t> AddressRange;
+
+class Phase3Info
+{
+ public:
+ Phase3Info(const AddressRange& addressRange,
+ unsigned origInst,
+ uint64_t replaceAddr,
+ uint64_t slotDescriptor,
+ TraceCache* pTraceCache):
+ m_addrRange(addressRange),
+ m_origInst(origInst),
+ m_replaceAddr(replaceAddr),
+ m_slotDescriptor(slotDescriptor),
+ m_pTraceCache(pTraceCache)
+ {
+ }
+
+ 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; }
+ TraceCache* getTraceCache() { return m_pTraceCache; }
+
+ 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
+ TraceCache* m_pTraceCache; // TraceCache instance used by phase 2
+};
+
+void phase3(Phase3Info* p3info);
// 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.
@@ -51,22 +112,29 @@
class Phase2
{
public:
+ Phase2(TraceCache* pTraceCache);
void transform();
- void transformFunction(std::pair<uint64_t, uint64_t>& range);
+ void transformFunction(AddressRange& range);
private:
+ Phase2() {}
inline unsigned getSlotSize() const;
- TraceCache m_traceCache;
- InstManip m_instManip;
+ TraceCache* m_pTraceCache;
+ InstManip m_instManip;
};
extern "C" void phase2()
{
- Phase2 ph;
+ Phase2 ph(new TraceCache());
ph.transform();
}
+Phase2::Phase2(TraceCache* tc):
+ m_pTraceCache(tc)
+{
+}
+
void Phase2::transform()
{
cerr << "============================== Begin Phase 2 ==============================\n";
@@ -77,12 +145,12 @@
ElfReader elfReader(execName);
std::string funcName;
- std::pair<uint64_t, uint64_t> range;
+ AddressRange range;
while(elfReader.GetNextFunction(funcName, range)) {
if(funcName == "l16_fibs") {
//cerr << "Printing information about function " << funcName << endl;
- m_instManip.printRange(range.first, range.second);
+ //m_instManip.printRange(range.first, range.second);
cerr << "Transforming function " << funcName << "..." << endl;
transformFunction(range);
@@ -92,76 +160,104 @@
cerr << "============================== End Phase 2 ==============================\n";
}
-void Phase2::transformFunction(std::pair<uint64_t, uint64_t>& range)
+
+static void copySnippetToSlot(vector<unsigned>& snippet,
+ uint64_t slotBase,
+ VirtualMem* vm,
+ 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();
+ }
+}
+
+void Phase2::transformFunction(AddressRange& range)
{
////////////////
- // 1. Replace the first instruction in F with a branch to a new slot (annulling bit
- // should specify *not* to execute the branch delay slot).
+ // 1. Replace the first (replacable) instruction in F with a branch to a new slot
+ // (annulling bit should specify *not* to execute the branch delay slot) in the dummy
+ // function.
+ //
+ // 2. In the slot, write:
+ //
+ // - The code to load the pointer to the heap-allocated Phase3Info instance.
//
- // 2. At the new slot write first the code to call the phase 3 function with the
- // address of of F as an argument, followed by the (replaced) instruction from the
- // original code.
+ // - The call to phase 3
//
- // 3. At the new slot write a branch back to immediately after the branch-to-slot
- // instruction in the original code.
+ // - The branch back to the location of the replaced instruction (phase 3 will
+ // replace the instruction at runtime).
//
- // Obtain address of first replacable instruction in function
- VirtualMem* vm = m_traceCache.getVM();
+ // 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).
+
+ VirtualMem* vm = m_pTraceCache->getVM();
uint64_t repInstAddr = m_instManip.skipFunctionHdr(range.first, vm);
+ uint64_t slotBase = m_pTraceCache->getMemMgr()->getMemory(getSlotSize());
+ assert(slotBase && "Unable to obtain memory from MemoryManger instance");
- // Obtain new slot's base address, build unconditional-anulled branch to slot base,
- // and write over original instruction (saving it for later use).
-
- MemoryManager* mm = m_traceCache.getMemMgr();
- uint64_t slotBase = mm->getMemory(getSlotSize());
- unsigned origInstr = vm->readInstrFrmVm(repInstAddr);
- assert(!m_instManip.isBranch(origInstr) && "Unhandled case: branch instruction first in function body");
-
- // Replace the instruction at repInstAddr with a branch to the start of the slot
+ // Replace instruction at repInstAddr with a branch to start of slot.
+ unsigned origInst = vm->readInstrFrmVm(repInstAddr);
+ assert(!m_instManip.isBranch(origInst) &&
+ "Unhandled case: branch instruction first in function body");
vm->writeInstToVM(repInstAddr, m_instManip.getBranchAlways(slotBase, repInstAddr));
-
- vector<unsigned> snippet;
- // Pass the starting address of F as the argument to phase3
- // Currently, just some 64-bit value for verification purposes...
- m_instManip.generateLoad64(0xefefefefabababab, snippet);
-
- // Build call to phase 3
- uint64_t callInstAddr = slotBase + 4 * snippet.size();
- snippet.push_back(m_instManip.getCall((uint64_t) &phase3, callInstAddr));
- snippet.push_back(m_instManip.getNOP());
-
- // Instruction from original code (now replaced with branch)
- snippet.push_back(origInstr);
-
- // Build unconditional branch to repInstAddr + 4; this ensures execution of the code
- // is resumed after phase3 is called and performs its transformations.
-
- uint64_t branchInstAddr = slotBase + 4 * snippet.size();
- snippet.push_back(m_instManip.getBranchAlways(repInstAddr + 4, branchInstAddr));
- snippet.push_back(m_instManip.getNOP());
+ // Generate a) code to load the address of the heap-allocated Phase3Info struct into a
+ // register, which will be used as a parameter to the phase3 call, b) the call to
+ // phase 3 itself, and c) the direct branch back to the original code.
- // Copy the snippet code into the slot.
- uint64_t currAddr = slotBase;
- for(vector<unsigned>::iterator i = snippet.begin(), e = snippet.end(); i != e; ++i) {
- vm->writeInstToVM(currAddr, *i);
- currAddr += 4;
- }
+ Phase3Info* p3info = new Phase3Info(range, origInst, repInstAddr, slotBase, m_pTraceCache);
+
+ vector<unsigned> snippet;
+ m_instManip.generateLoad((uint64_t) p3info, snippet);
+ m_instManip.generateCall((uint64_t) &phase3, slotBase, snippet);
+ m_instManip.generateBranchAlways(repInstAddr, slotBase, snippet);
+
+ // Copy the snippet code into the slot
+ assert(snippet.size() == getSlotSize() && "Snippet size does not match slot size");
+ copySnippetToSlot(snippet, slotBase, vm, &m_instManip);
}
unsigned Phase2::getSlotSize() const
{
- // Slot size is [size of code for loading 64-bit value] + call inst + delay slot +
- // instruction from original code + branch (back to original code) inst + delay slot
- // ===> [size of code for loading 64-bit value] + 5
-
- return m_instManip.getGenLoad64Size() + 5;
+ // A slot used by phase 2 looks like:
+ // +------------------------------+
+ // | load parameter for phase 3 |
+ // | call to phase 3 |
+ // | nop |
+ // | branch back to orig code |
+ // | nop |
+ // +------------------------------+
+
+ return m_instManip.getGenLoadSize() +
+ m_instManip.getGenCallSize() +
+ m_instManip.getGenBranchAlwaysSize();
}
-void phase3(uint64_t value)
+void phase3(Phase3Info* p3info)
{
- printf("phase3 called!\n");
- printf("value passed in is: %lx\n", value);
- fflush(stdout);
+ assert(p3info && "phase3 requires valid Phase3Info ptr");
+
+ cerr << "================ Begin Phase 3 [" << std::hex
+ << p3info->getStartAddr() << ", " << p3info->getEndAddr()
+ << "] ================\n";
+
+ // Restore the replaced instruction to its original location (thus effectively
+ // removing the branch to the slot created by phase 2 as well)
+
+ VirtualMem* vm = p3info->getTraceCache()->getVM();
+ vm->writeInstToVM(p3info->getReplaceAddr(), p3info->getOrigInst());
+
+ // TODO: Delete pending slots/heap frames.
+
+ // Deallocate the parameter structure and mark the phase 2 slot that corresponds to this
+ // invocation of phase 3 as deletable.
+
+ // TODO: Mark p3info->getSlot() as deleted
+
+ delete p3info;
+
+ cerr << "============================== End Phase 3 ==============================\n";
}
More information about the llvm-commits
mailing list