GBE: fixed the out-of-range JMPI.
authorZhigang Gong <zhigang.gong@intel.com>
Mon, 27 Jan 2014 01:26:21 +0000 (09:26 +0800)
committerZhigang Gong <zhigang.gong@intel.com>
Tue, 28 Jan 2014 03:09:20 +0000 (11:09 +0800)
For the conditional jump distance out of S15 range [-32768, 32767],
we need to use an inverted jmp followed by a add ip, ip, distance
to implement. A little hacky as we need to change the nop instruction
to add instruction manually.

There is an optimization method which we can insert a
ADD instruction on demand. But that will need some extra analysis
for all the branching instruction. And need to adjust the distance
for those branch instruction's start point and end point contains
this instruction.

After this patch, the luxrender's slg4 could render the scene "alloy"
correctly.

v2:
fix the unconditional branch too.

Signed-off-by: Zhigang Gong <zhigang.gong@intel.com>
Reviewed-by: Yang, Rong R <rong.r.yang@intel.com>
backend/src/backend/gen_context.cpp
backend/src/backend/gen_encoder.cpp

index 9cbe60b..d72b19b 100644 (file)
@@ -880,8 +880,8 @@ namespace gbe
           NOT_IMPLEMENTED;
         p->curr.execWidth = 1;
         p->curr.noMask = 1;
+        jip0 = p->n_instruction();
         p->JMPI(GenRegister::immud(0));
-        jip0 = p->n_instruction() - 1;
       p->pop();
 
       p->curr.predicate = GEN_PREDICATE_NONE;
@@ -905,8 +905,8 @@ namespace gbe
           NOT_IMPLEMENTED;
         p->curr.execWidth = 1;
         p->curr.noMask = 1;
+        jip1 = p->n_instruction();
         p->JMPI(GenRegister::immud(0));
-        jip1 = p->n_instruction() - 1;
       p->pop();
 
       p->curr.predicate = GEN_PREDICATE_NONE;
@@ -1457,7 +1457,7 @@ namespace gbe
       p->curr.noMask = 1;
       int jip = -(int)(p->n_instruction() - loop_start + 1) * 2;
       p->JMPI(zero);
-      p->patchJMPI(p->n_instruction()-1, jip);
+      p->patchJMPI(p->n_instruction()-2, jip);
       p->pop();
       // end of loop
     }
index 61393a3..aaf7dce 100644 (file)
@@ -1050,13 +1050,42 @@ namespace gbe
 
   void GenEncoder::JMPI(GenRegister src) {
     alu2(this, GEN_OPCODE_JMPI, GenRegister::ip(), GenRegister::ip(), src);
+    NOP();
   }
 
   void GenEncoder::patchJMPI(uint32_t insnID, int32_t jumpDistance) {
     GenInstruction &insn = this->store[insnID];
-    assert(insnID < this->store.size());
-    assert(insn.header.opcode == GEN_OPCODE_JMPI);
-    this->setSrc1(&insn, GenRegister::immd(jumpDistance));
+    GBE_ASSERT(insnID < this->store.size());
+    GBE_ASSERT(insn.header.opcode == GEN_OPCODE_JMPI);
+    if ( jumpDistance > -32769 && jumpDistance < 32768 ) {
+        this->setSrc1(&insn, GenRegister::immd(jumpDistance));
+    } else if ( insn.header.predicate_control == GEN_PREDICATE_NONE ) {
+      // For the conditional jump distance out of S15 range, we need to use an
+      // inverted jmp followed by a add ip, ip, distance to implement.
+      // A little hacky as we need to change the nop instruction to add
+      // instruction manually.
+      // If this is a unconditional jump, we just need to add the IP directly.
+      // FIXME there is an optimization method which we can insert a
+      // ADD instruction on demand. But that will need some extra analysis
+      // for all the branching instruction. And need to adjust the distance
+      // for those branch instruction's start point and end point contains
+      // this instruction.
+      insn.header.opcode = GEN_OPCODE_ADD;
+      this->setDst(&insn, GenRegister::ip());
+      this->setSrc0(&insn, GenRegister::ip());
+      this->setSrc1(&insn, GenRegister::immd((jumpDistance + 2) * 8));
+    } else {
+      insn.header.predicate_inverse ^= 1;
+      this->setSrc1(&insn, GenRegister::immd(2));
+      GenInstruction &insn2 = this->store[insnID+1];
+      GBE_ASSERT(insn2.header.opcode == GEN_OPCODE_NOP);
+      GBE_ASSERT(insnID < this->store.size());
+      insn2.header.predicate_control = GEN_PREDICATE_NONE;
+      insn2.header.opcode = GEN_OPCODE_ADD;
+      this->setDst(&insn2, GenRegister::ip());
+      this->setSrc0(&insn2, GenRegister::ip());
+      this->setSrc1(&insn2, GenRegister::immd(jumpDistance * 8));
+    }
   }
 
   void GenEncoder::CMP(uint32_t conditional, GenRegister src0, GenRegister src1) {