Add MIPS support to pixelflinger.

See the comment-block at the top of MIPSAssembler.cpp for
implementation overview.

Change-Id: Id492c10610574af8c89c38d19e12fafc3652c28a
diff --git a/libpixelflinger/codeflinger/GGLAssembler.cpp b/libpixelflinger/codeflinger/GGLAssembler.cpp
index f1d81b2..1ddf93d 100644
--- a/libpixelflinger/codeflinger/GGLAssembler.cpp
+++ b/libpixelflinger/codeflinger/GGLAssembler.cpp
@@ -31,7 +31,8 @@
 // ----------------------------------------------------------------------------
 
 GGLAssembler::GGLAssembler(ARMAssemblerInterface* target)
-    : ARMAssemblerProxy(target), RegisterAllocator(), mOptLevel(7)
+    : ARMAssemblerProxy(target),
+      RegisterAllocator(ARMAssemblerProxy::getCodegenArch()), mOptLevel(7)
 {
 }
 
@@ -230,7 +231,9 @@
 
             // texel generation
             build_textures(parts, regs);
-        }        
+            if (registerFile().status())
+                return registerFile().status();
+        }
 
         if ((blending & (FACTOR_DST|BLEND_DST)) || 
                 (mMasking && !mAllMasked) ||
@@ -890,6 +893,15 @@
         return;
     }
     
+    if (getCodegenArch() == CODEGEN_ARCH_MIPS) {
+        // MIPS can do 16-bit imm in 1 instr, 32-bit in 3 instr
+        // the below ' while (mask)' code is buggy on mips
+        // since mips returns true on isValidImmediate()
+        // then we get multiple AND instr (positive logic)
+        AND( AL, 0, d, s, imm(mask) );
+        return;
+    }
+
     int negative_logic = !isValidImmediate(mask);
     if (negative_logic) {
         mask = ~mask & size;
@@ -1002,6 +1014,15 @@
 // cheezy register allocator...
 // ----------------------------------------------------------------------------
 
+// Modified to support MIPS processors, in a very simple way. We retain the
+// (Arm) limit of 16 total registers, but shift the mapping of those registers
+// from 0-15, to 2-17. Register 0 on Mips cannot be used as GP registers, and
+// register 1 has a traditional use as a temp).
+
+RegisterAllocator::RegisterAllocator(int arch) : mRegs(arch)
+{
+}
+
 void RegisterAllocator::reset()
 {
     mRegs.reset();
@@ -1029,16 +1050,22 @@
 
 // ----------------------------------------------------------------------------
 
-RegisterAllocator::RegisterFile::RegisterFile()
-    : mRegs(0), mTouched(0), mStatus(0)
+RegisterAllocator::RegisterFile::RegisterFile(int codegen_arch)
+    : mRegs(0), mTouched(0), mStatus(0), mArch(codegen_arch), mRegisterOffset(0)
 {
+    if (mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS) {
+        mRegisterOffset = 2;    // ARM has regs 0..15, MIPS offset to 2..17
+    }
     reserve(ARMAssemblerInterface::SP);
     reserve(ARMAssemblerInterface::PC);
 }
 
-RegisterAllocator::RegisterFile::RegisterFile(const RegisterFile& rhs)
-    : mRegs(rhs.mRegs), mTouched(rhs.mTouched)
+RegisterAllocator::RegisterFile::RegisterFile(const RegisterFile& rhs, int codegen_arch)
+    : mRegs(rhs.mRegs), mTouched(rhs.mTouched), mArch(codegen_arch), mRegisterOffset(0)
 {
+    if (mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS) {
+        mRegisterOffset = 2;    // ARM has regs 0..15, MIPS offset to 2..17
+    }
 }
 
 RegisterAllocator::RegisterFile::~RegisterFile()
@@ -1057,8 +1084,12 @@
     reserve(ARMAssemblerInterface::PC);
 }
 
+// RegisterFile::reserve() take a register parameter in the
+// range 0-15 (Arm compatible), but on a Mips processor, will
+// return the actual allocated register in the range 2-17.
 int RegisterAllocator::RegisterFile::reserve(int reg)
 {
+    reg += mRegisterOffset;
     LOG_ALWAYS_FATAL_IF(isUsed(reg),
                         "reserving register %d, but already in use",
                         reg);
@@ -1067,6 +1098,7 @@
     return reg;
 }
 
+// This interface uses regMask in range 2-17 on MIPS, no translation.
 void RegisterAllocator::RegisterFile::reserveSeveral(uint32_t regMask)
 {
     mRegs |= regMask;
@@ -1075,7 +1107,7 @@
 
 int RegisterAllocator::RegisterFile::isUsed(int reg) const
 {
-    LOG_ALWAYS_FATAL_IF(reg>=16, "invalid register %d", reg);
+    LOG_ALWAYS_FATAL_IF(reg>=16+(int)mRegisterOffset, "invalid register %d", reg);
     return mRegs & (1<<reg);
 }
 
@@ -1086,10 +1118,10 @@
                                      6,  7, 8, 9,
                                     10, 11 };
     const int nbreg = sizeof(priorityList);
-    int i, r;
+    int i, r, reg;
     for (i=0 ; i<nbreg ; i++) {
         r = priorityList[i];
-        if (!isUsed(r)) {
+        if (!isUsed(r + mRegisterOffset)) {
             break;
         }
     }
@@ -1102,18 +1134,20 @@
         // the code will never be run anyway.
         return ARMAssemblerInterface::SP; 
     }
-    reserve(r);
-    return r;
+    reg = reserve(r);  // Param in Arm range 0-15, returns range 2-17 on Mips.
+    return reg;
 }
 
 bool RegisterAllocator::RegisterFile::hasFreeRegs() const
 {
-    return ((mRegs & 0xFFFF) == 0xFFFF) ? false : true;
+    uint32_t regs = mRegs >> mRegisterOffset;   // MIPS fix.
+    return ((regs & 0xFFFF) == 0xFFFF) ? false : true;
 }
 
 int RegisterAllocator::RegisterFile::countFreeRegs() const
 {
-    int f = ~mRegs & 0xFFFF;
+    uint32_t regs = mRegs >> mRegisterOffset;   // MIPS fix.
+    int f = ~regs & 0xFFFF;
     // now count number of 1
    f = (f & 0x5555) + ((f>>1) & 0x5555);
    f = (f & 0x3333) + ((f>>2) & 0x3333);
@@ -1124,18 +1158,24 @@
 
 void RegisterAllocator::RegisterFile::recycle(int reg)
 {
-    LOG_FATAL_IF(!isUsed(reg),
-            "recycling unallocated register %d",
-            reg);
+    // commented out, since common failure of running out of regs
+    // triggers this assertion. Since the code is not execectued
+    // in that case, it does not matter. No reason to FATAL err.
+    // LOG_FATAL_IF(!isUsed(reg),
+    //         "recycling unallocated register %d",
+    //         reg);
     mRegs &= ~(1<<reg);
 }
 
 void RegisterAllocator::RegisterFile::recycleSeveral(uint32_t regMask)
 {
-    LOG_FATAL_IF((mRegs & regMask)!=regMask,
-            "recycling unallocated registers "
-            "(recycle=%08x, allocated=%08x, unallocated=%08x)",
-            regMask, mRegs, mRegs&regMask);
+    // commented out, since common failure of running out of regs
+    // triggers this assertion. Since the code is not execectued
+    // in that case, it does not matter. No reason to FATAL err.
+    // LOG_FATAL_IF((mRegs & regMask)!=regMask,
+    //         "recycling unallocated registers "
+    //         "(recycle=%08x, allocated=%08x, unallocated=%08x)",
+    //         regMask, mRegs, mRegs&regMask);
     mRegs &= ~regMask;
 }