[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