[llvm-commits] CVS: llvm/lib/Reoptimizer/Inst/ElfReader.cpp ElfReader.h Phase2.cpp
Joel Stanley
jstanley at cs.uiuc.edu
Tue Apr 8 22:35:01 PDT 2003
Changes in directory llvm/lib/Reoptimizer/Inst:
ElfReader.cpp updated: 1.2 -> 1.3
ElfReader.h updated: 1.2 -> 1.3
Phase2.cpp updated: 1.1 -> 1.2
---
Log message:
Significant functionality added to InstManip wrapper class.
As of this version, phase2 works (on a particular
example). Furthermore:
- Slot created in dummy function via TraceCache utils.
- Writes call to phase3, passing 64-bit value (will later be
function address), branch back to original code, etc.
- phase3 doesn't exist yet, and is just a dummy function.
---
Diffs of the changes:
Index: llvm/lib/Reoptimizer/Inst/ElfReader.cpp
diff -u llvm/lib/Reoptimizer/Inst/ElfReader.cpp:1.2 llvm/lib/Reoptimizer/Inst/ElfReader.cpp:1.3
--- llvm/lib/Reoptimizer/Inst/ElfReader.cpp:1.2 Thu Apr 3 15:00:51 2003
+++ llvm/lib/Reoptimizer/Inst/ElfReader.cpp Tue Apr 8 22:35:57 2003
@@ -57,7 +57,6 @@
m_entrySize = m_symTab->sh_entsize;
m_numEntries = m_symTab->sh_size / m_entrySize;
assert(m_symTab->sh_size % m_entrySize == 0 && "Symtable size must be multiple of entry size");
- cerr << "Symbol table contains " << m_numEntries << " entries" << endl;
// Seek to the start of the symbol table in the file
if(lseek(m_execFD, m_symTab->sh_offset, SEEK_SET) < 0)
@@ -67,8 +66,15 @@
}
bool ElfReader::GetNextFunction(std::string& fname,
- AddressRange& addressRange)
+ std::pair<uint64_t, uint64_t>& range)
{
+ // Locate next function (skipping non-function entries) in the symbol table if
+ // possible. If found, return true, yielding name & extents by reference. Return
+ // false otherwise.
+ //
+ // NB: Address range contains the (closed) memory interval [start,end] of the memory
+ // addresses corresponding to the function with function fname.
+
while(m_entriesProcessed < m_numEntries) {
m_entriesProcessed++;
@@ -79,11 +85,11 @@
rdcnt = read(m_execFD, &sym + rdcnt, m_entrySize);
} while(rdcnt < m_entrySize);
- // If it is a function, extract the information and return
+ // If it is a function, extract name, extents, and return
if(STT_FUNC == (sym.st_info & 0xf)) { // Symbol type is lower 4 bits
fname = m_strTab + sym.st_name;
- addressRange.first = sym.st_value;
- addressRange.second = sym.st_value + sym.st_size - 4;
+ range.first = sym.st_value;
+ range.second = sym.st_value + sym.st_size - 4;
return true;
}
}
@@ -103,7 +109,6 @@
if(SHT_SYMTAB == secHdr->sh_type) {
// Found section marked as a symbol table
- cerr << "Found symbol table!" << endl;
assert(!m_symTab && "Should only be one symbol table in the image");
m_symTab = secHdr;
}
Index: llvm/lib/Reoptimizer/Inst/ElfReader.h
diff -u llvm/lib/Reoptimizer/Inst/ElfReader.h:1.2 llvm/lib/Reoptimizer/Inst/ElfReader.h:1.3
--- llvm/lib/Reoptimizer/Inst/ElfReader.h:1.2 Thu Apr 3 15:00:51 2003
+++ llvm/lib/Reoptimizer/Inst/ElfReader.h Tue Apr 8 22:35:57 2003
@@ -16,9 +16,8 @@
ElfReader(const char* execName);
~ElfReader();
- typedef std::pair<uint64_t, uint64_t> AddressRange;
-
- bool GetNextFunction(std::string& string, AddressRange& range);
+ bool GetNextFunction(std::string& string,
+ std::pair<uint64_t, uint64_t>& range);
private:
ElfReader() {}
Index: llvm/lib/Reoptimizer/Inst/Phase2.cpp
diff -u llvm/lib/Reoptimizer/Inst/Phase2.cpp:1.1 llvm/lib/Reoptimizer/Inst/Phase2.cpp:1.2
--- llvm/lib/Reoptimizer/Inst/Phase2.cpp:1.1 Fri Apr 4 17:08:56 2003
+++ llvm/lib/Reoptimizer/Inst/Phase2.cpp Tue Apr 8 22:35:57 2003
@@ -30,56 +30,368 @@
#include <stdlib.h>
#include <iostream>
+#include <iomanip>
#include <vector>
#include "ElfReader.h"
-#include "../BinInterface/sparcdis.h"
+#include "llvm/Reoptimizer/TraceCache.h"
+#include "llvm/Reoptimizer/VirtualMem.h"
+#include "llvm/Reoptimizer/InstrUtils.h"
+#include "../BinInterface/sparcdis.h" // TODO: Move to proper include directory
+#include "../BinInterface/sparc9.h" // TODO: Move to proper include directory
+#include "../BinInterface/bitmath.h" // TODO: Move to proper include directory
+#include "../TraceCache/MemoryManager.h" // TODO: Move to proper include directory
using std::vector;
using std::cerr;
using std::endl;
+typedef std::pair<uint64_t, uint64_t> AddressRange;
+
+// InstManip is a wrapper class around any BinInterface macros/mechanisms, as well as the
+// TraceCache "instruction utilities, all which are SparcV9-specific; this class exists
+// both for conceptual clarity and to facilitate hiding the Sparc-specificity from the
+// Phase2 actions (and thus making it easier to use the phase2 transformations on other
+// platforms in the future; we should be able to change which instruction manipulator
+// object is instantiated, after making the appropriate superclass, etc).
+
+class InstManip
+{
+ public:
+ void printRange(unsigned* start, unsigned* end);
+ inline void printRange(AddressRange& range);
+ inline void printRange(uint64_t start, uint64_t end);
+
+ inline void printInst(unsigned inst);
+ inline void printInst(unsigned* instAddr);
+
+ uint64_t skipFunctionHdr(uint64_t addr, VirtualMem* vm);
+
+ void generateLoad64(uint64_t value, vector<unsigned>& snippet);
+
+ unsigned getBranchAlways(uint64_t dest, uint64_t pc, bool annulHigh = true);
+ inline unsigned getCall(uint64_t dest, uint64_t pc);
+
+ unsigned getNOP() const { return 0x01000000; }
+ unsigned getGenLoad64Size() const { return 6; }
+
+ private:
+ ////////////////
+ // Instruction constants and field-extraction "macros", etc.
+
+ // Branch-always (annul bit high) instruction base (i.e. address not filled in yet)
+ static const int wtf = 19;
+
+ static const unsigned BRANCH_ALWAYS_BASE = 0x30480000;
+
+ unsigned low10(unsigned value) { return value & 0x000003ff; }
+ unsigned high22(unsigned value) { return value >> 10; }
+ unsigned highWord(uint64_t value) { return (unsigned) (value >> 32); }
+ unsigned lowWord(uint64_t value) { return (unsigned) value; }
+};
+
+// 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.
+
+class Phase2
+{
+ public:
+ void transform();
+ void transformFunction(AddressRange& range);
+
+ private:
+ inline unsigned getSlotSize() const;
+
+ TraceCache m_traceCache;
+ InstManip m_instManip;
+};
+
extern "C" void phase2()
{
+ Phase2 ph;
+ ph.transform();
+}
+
+void Phase2::transform()
+{
cerr << "============================== Begin Phase 2 ==============================\n";
const char* execName = getexecname();
cerr << "Executable name is: " << execName << endl;
ElfReader elfReader(execName);
-
+
std::string funcName;
- ElfReader::AddressRange range;
+ AddressRange range;
while(elfReader.GetNextFunction(funcName, range)) {
- if(funcName == "l16_fibs" || funcName == "l16_floogle") {
- cerr << "Function name is: " << funcName << endl;
- cerr << "\tAddress range is [";
- fprintf(stderr, "%lx, %lx]", range.first, range.second);
- cerr << endl;
-
- cerr << "Dumping BinInterface-generated disasm:" << endl;
-
- for(unsigned* inst = (unsigned*) range.first,
- *end = (unsigned*) range.second; inst <= end; ++inst){
- printf("%lx:\t%8x\t", (uint64_t) inst, *inst);
- sparc_print(*inst);
- printf("\n");
- fflush(stdout);
- }
-
#if 0
- cerr << "First instruction in function: " << endl;
- void* ptr = (void*) range.first;
- unsigned inst = *((uint32_t*)((void*) range.first));
- fprintf(stderr, "%x\n", inst);
- cerr << "Disassembly is: ";
- sparc_print(inst);
- fflush(stdout);
+ if(funcName == "l16_floogle") {
+ cerr << "Printing information about function " << funcName << endl;
+ m_instManip.printRange(range);
+ }
#endif
+ if(funcName == "l16_fibs") {
+ //cerr << "Printing information about function " << funcName << endl;
+ //m_instManip.printRange(range);
+
+ cerr << "Transforming function " << funcName << "..." << endl;
+ transformFunction(range);
}
}
cerr << "============================== End Phase 2 ==============================\n";
+}
+
+void phase3(uint64_t value)
+{
+ printf("phase3 called!\n");
+ printf("value passed in is: %lx\n", value);
+ fflush(stdout);
+}
+
+#if 0
+static void generateLoad64(uint64_t value, vector<unsigned>& snippet)
+{
+ // Use %o0 and %o1 to load the 64-bit value 'value' into %o0.
+ // Place the generated instructions into instruction-vector 'snippet'.
+
+ unsigned high32 = (unsigned) (value >> 32);
+ unsigned low32 = (unsigned) value;
+ unsigned low10 = high32 & 0x000003ff;
+
+ snippet.push_back(0x11000000 | (high32 >> 10)); // sethi (upper 22b of upper wrd), %o0
+ snippet.push_back(0x90122000 | low10); // or %o0, (lower 10b of upper wrd), %o0
+ snippet.push_back(0x912a3020); // sllx %o0, 32, %o0
+ low10 = low32 & 0x000003ff;
+ snippet.push_back(0x13000000 | (low32 >> 10)); // sethi (upper 22b of lwr wrd), %o1
+ snippet.push_back(0x90120009); // or %o0, %o1, %o0
+ snippet.push_back(0x90022000 | low10); // add %o0, (lwr 10b of lwr wrd), %o0
+}
+
+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).
+ //
+ // 2. At the new slot write first the replaced instruction followed by code to call
+ // the phase 3 function with the address of of F as an argument.
+ //
+ // 3. At the new slot write a branch back to immediately after the branch-to-slot
+ // instruction in the original code.
+ //
+
+ // Obtain address of first replacable instruction in function
+ VirtualMem* vm = m_traceCache.getVM();
+ uint64_t repInstAddr = m_instManip.skipFunctionHdr(range.first, vm);
+
+ // 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(11);
+
+ // 0x30480000 is branch-always-annul-high instruction (without imm offset)
+ unsigned branchToSlot = getUndepJumpInstr(0x30480000, slotBase, repInstAddr);
+ unsigned origInstr = vm->readInstrFrmVm(repInstAddr);
+
+ if(isBranchInstr(origInstr))
+ assert(0 && "Unhandled case: branch instruction first in function body");
+
+ vm->writeInstToVM(repInstAddr, branchToSlot);
+
+ // Build instructions into snippet vector for later insertion.
+ vector<unsigned> snippet;
+
+ // Pass the starting address of F as the argument to phase3
+ m_instManip.generateLoad64(0xefefefefabababab, snippet);
+
+ // Build call to phase3
+ uint64_t phase3Addr = (uint64_t)(&phase3);
+ unsigned call = getCallInstr(phase3Addr, slotBase + 4 * snippet.size());
+ snippet.push_back(call); // call phase3
+ snippet.push_back(0x01000000); // nop
+
+ // Insert the instruction from the original code which has now
+ // been replaced with a branch.
+ snippet.push_back(origInstr); // Inst from orig code (now replaced with branch)
+
+ // Build unconditional branch to repInstAddr + 4; this ensures execution of the code
+ // is resumed after phase3 is called and performs its transformations.
+ unsigned branchBack =
+ getUndepJumpInstr(0x30480000, repInstAddr + 4, slotBase + 4 * snippet.size());
+ snippet.push_back(branchBack); // branch to original code
+ snippet.push_back(0x01000000); // nop
+
+ // 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;
+ }
+
+#if 0
+ cerr << "Dumping inserted snippet..." << endl;
+ m_instManip.printRange(slotBase, currAddr - 4);
+ fflush(stdout);
+ cerr << "Done w/ transformFunction" << endl;
+#endif
+}
+#endif
+
+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).
+ //
+ // 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.
+ //
+ // 3. At the new slot write a branch back to immediately after the branch-to-slot
+ // instruction in the original code.
+ //
+
+ // Obtain address of first replacable instruction in function
+ VirtualMem* vm = m_traceCache.getVM();
+ uint64_t repInstAddr = m_instManip.skipFunctionHdr(range.first, vm);
+
+ // 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);
+
+ if(isBranchInstr(origInstr))
+ assert(0 && "Unhandled case: branch instruction first in function body");
+
+ // Replace the instruction at repInstAddr with a branch to the start of the slot
+ vm->writeInstToVM(repInstAddr, m_instManip.getBranchAlways(slotBase, repInstAddr));
+
+ vector<unsigned> snippet;
+
+ // Pass the starting address of F as the argument to phase3
+ 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());
+
+ // 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;
+ }
+}
+
+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;
+}
+
+//////////////// InstManip implementation ////////////////
+
+void InstManip::printRange(unsigned* start, unsigned* end)
+{
+ // Dumps contents (and corresponding disassembly) of memory range given by range
+ // to stdout. TODO: Parameterize by an ostream instance; cannot do this yet
+ // because BinInterface is hard-coded to use printf and must be changed.
+
+ std::cout << "Sparc dissassembly of range ["
+ << start << ", " << end << "]:" << endl;
+
+ for(; start <= end; ++start) {
+ std::cout << start << " | "
+ << std::hex << std::setw(8) << std::setfill('0')
+ << *start << " | ";
+ sparc_print(*start);
+ std::cout << endl;
+ }
+}
+
+void InstManip::printRange(AddressRange& range)
+{
+ printRange((unsigned*) range.first, (unsigned*) range.second);
+}
+
+void InstManip::printRange(uint64_t start, uint64_t end)
+{
+ printRange((unsigned*) start, (unsigned*) end);
+}
+
+void InstManip::printInst(unsigned inst)
+{
+ sparc_print(inst);
+ fflush(stdout);
+}
+
+void InstManip::printInst(unsigned* instAddr)
+{
+ sparc_print(*instAddr);
+ fflush(stdout);
+}
+
+uint64_t InstManip::skipFunctionHdr(uint64_t addr, VirtualMem* vm)
+{
+ // 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 = vm->readInstrFrmVm(addr);
+ return RD_FLD(inst, INSTR_OP3) == OP3_SAVE ? addr + 4 : addr;
+}
+
+void InstManip::generateLoad64(uint64_t value, vector<unsigned>& snippet)
+{
+ // Using %o0 and %o1, load the 64-bit value 'value' into %o0. The sequence of
+ // instructions to do this is placed in the provided instruction vector 'snippet'.
+
+ unsigned initSize = snippet.size();
+ snippet.push_back(0x11000000 | high22(highWord(value))); // sethi (upper 22b of upper wrd), %o0
+ snippet.push_back(0x90122000 | low10(highWord(value))); // or %o0, (lower 10b of upper wrd), %o0
+ snippet.push_back(0x912a3020); // sllx %o0, 32, %o0
+ snippet.push_back(0x13000000 | high22(lowWord(value))); // sethi (upper 22b of lwr wrd), %o1
+ snippet.push_back(0x90120009); // or %o0, %o1, %o0
+ snippet.push_back(0x90022000 | low10(lowWord(value))); // add %o0, (lwr 10b of lwr wrd), %o0
+
+ assert(snippet.size() - initSize == getGenLoad64Size() &&
+ "Unexpected number of instructions in code sequence for 64-bit value -> %o0");
+}
+
+unsigned InstManip::getBranchAlways(uint64_t dest, uint64_t pc, bool annul)
+{
+ // dest is the destination address, pc is the value of the program counter when the
+ // branch instruction is executed (i.e., the address of the branch instruction). NB:
+ // Only handles branch-always-annul-high at the moment
+
+ assert(annul && "Unhandled case: annul bit low");
+ return getUndepJumpInstr(BRANCH_ALWAYS_BASE, dest, pc);
+}
+
+unsigned InstManip::getCall(uint64_t dest, uint64_t pc)
+{
+ // 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
+ // instruction).
+
+ return getCallInstr(dest, pc);
}
More information about the llvm-commits
mailing list