[Beignet] [PATCH] GBE: fix a uniform analysis bug.

Zhigang Gong zhigang.gong at intel.com
Thu May 22 18:40:10 PDT 2014


From: Zhigang Gong <zhigang.gong at gmail.com>

If a value is defined in a loop and is used out-of the
loop. That value could not be a uniform(scalar) value.
The reason is that value may be assigned different
scalar value on different lanes when it reenters with
different lanes actived.
Thanks for yang rong reporting this bug.

Signed-off-by: Zhigang Gong <zhigang.gong at gmail.com>
---
 backend/src/ir/liveness.cpp | 63 +++++++++++++++++++++++++++++++--------------
 backend/src/ir/liveness.hpp |  3 ++-
 2 files changed, 46 insertions(+), 20 deletions(-)

diff --git a/backend/src/ir/liveness.cpp b/backend/src/ir/liveness.cpp
index c3d6fe4..afed476 100644
--- a/backend/src/ir/liveness.cpp
+++ b/backend/src/ir/liveness.cpp
@@ -43,13 +43,52 @@ namespace ir {
     // Now with iterative analysis, we compute liveout and livein sets
     this->computeLiveInOut();
     // extend register (def in loop, use out-of-loop) liveness to the whole loop
-    this->computeExtraLiveInOut();
+    set<Register> extentRegs;
+    this->computeExtraLiveInOut(extentRegs);
+    // analyze uniform values. The extentRegs contains all the values which is
+    // defined in a loop and use out-of-loop which could not be a uniform. The reason
+    // is that when it reenter the second time, it may active different lanes. So
+    // reenter many times may cause it has different values in different lanes.
+    this->analyzeUniform(&extentRegs);
   }
 
   Liveness::~Liveness(void) {
     for (auto &pair : liveness) GBE_SAFE_DELETE(pair.second);
   }
 
+  void Liveness::analyzeUniform(set<Register> *extentRegs) {
+    fn.foreachBlock([this, extentRegs](const BasicBlock &bb) {
+      const_cast<BasicBlock&>(bb).foreach([this, extentRegs](const Instruction &insn) {
+        const uint32_t srcNum = insn.getSrcNum();
+        const uint32_t dstNum = insn.getDstNum();
+        bool uniform = true;
+        for (uint32_t srcID = 0; srcID < srcNum; ++srcID) {
+          const Register reg = insn.getSrc(srcID);
+          if (!fn.isUniformRegister(reg))
+            uniform = false;
+        }
+        // A destination is a killed value
+        for (uint32_t dstID = 0; dstID < dstNum; ++dstID) {
+          const Register reg = insn.getDst(dstID);
+          int opCode = insn.getOpcode();
+          // FIXME, ADDSAT and uniform vector should be supported.
+          if (uniform &&
+              fn.getRegisterFamily(reg) != ir::FAMILY_QWORD &&
+              !insn.getParent()->definedPhiRegs.contains(reg) &&
+              opCode != ir::OP_ATOMIC &&
+              opCode != ir::OP_MUL_HI &&
+              opCode != ir::OP_HADD &&
+              opCode != ir::OP_RHADD &&
+              opCode != ir::OP_ADDSAT &&
+              (dstNum == 1 || insn.getOpcode() != ir::OP_LOAD) &&
+              !extentRegs->contains(reg)
+             )
+            fn.setRegisterUniform(reg, true);
+        }
+      });
+    });
+  }
+
   void Liveness::initBlock(const BasicBlock &bb) {
     GBE_ASSERT(liveness.contains(&bb) == false);
     BlockInfo *info = GBE_NEW(BlockInfo, bb);
@@ -64,11 +103,8 @@ namespace ir {
     const uint32_t srcNum = insn.getSrcNum();
     const uint32_t dstNum = insn.getDstNum();
     // First look for used before killed
-    bool uniform = true;
     for (uint32_t srcID = 0; srcID < srcNum; ++srcID) {
       const Register reg = insn.getSrc(srcID);
-      if (!fn.isUniformRegister(reg))
-        uniform = false;
       // Not killed -> it is really an upward use
       if (info.varKill.contains(reg) == false)
         info.upwardUsed.insert(reg);
@@ -76,19 +112,6 @@ namespace ir {
     // A destination is a killed value
     for (uint32_t dstID = 0; dstID < dstNum; ++dstID) {
       const Register reg = insn.getDst(dstID);
-      int opCode = insn.getOpcode();
-      // FIXME, ADDSAT and uniform vector should be supported.
-      if (uniform &&
-          fn.getRegisterFamily(reg) != ir::FAMILY_QWORD &&
-          !info.bb.definedPhiRegs.contains(reg) &&
-          opCode != ir::OP_ATOMIC &&
-          opCode != ir::OP_MUL_HI &&
-          opCode != ir::OP_HADD &&
-          opCode != ir::OP_RHADD &&
-          opCode != ir::OP_ADDSAT &&
-          (dstNum == 1 || insn.getOpcode() != ir::OP_LOAD)
-         )
-        fn.setRegisterUniform(reg, true);
       info.varKill.insert(reg);
     }
   }
@@ -144,8 +167,9 @@ namespace ir {
   killed period, and the instructions before kill point were re-executed with different prediction,
   the inactive lanes of vreg maybe over-written. Then the out-of-loop use will got wrong data.
 */
-  void Liveness::computeExtraLiveInOut(void) {
+  void Liveness::computeExtraLiveInOut(set<Register> &extentRegs) {
     const vector<Loop *> &loops = fn.getLoops();
+    extentRegs.clear();
     if(loops.size() == 0) return;
 
     for (auto l : loops) {
@@ -163,7 +187,8 @@ namespace ir {
           std::set_intersection(exiting->liveOut.begin(), exiting->liveOut.end(), exit->upwardUsed.begin(), exit->upwardUsed.end(), std::back_inserter(toExtend));
         }
         if (toExtend.size() == 0) continue;
-
+        for(auto r : toExtend)
+          extentRegs.insert(r);
         for (auto bb : l->bbs) {
           BlockInfo * bI = liveness[&fn.getBlock(bb)];
           for(auto r : toExtend) {
diff --git a/backend/src/ir/liveness.hpp b/backend/src/ir/liveness.hpp
index 11f1fdc..d55e00d 100644
--- a/backend/src/ir/liveness.hpp
+++ b/backend/src/ir/liveness.hpp
@@ -127,7 +127,8 @@ namespace ir {
     void initInstruction(BlockInfo &info, const Instruction &insn);
     /*! Now really compute LiveOut based on UEVar and VarKill */
     void computeLiveInOut(void);
-    void computeExtraLiveInOut(void);
+    void computeExtraLiveInOut(set<Register> &extentRegs);
+    void analyzeUniform(set<Register> *extentRegs);
     /*! Set of work list block which has exit(return) instruction */
     typedef set <struct BlockInfo*> WorkSet;
     WorkSet workSet;
-- 
1.8.3.2



More information about the Beignet mailing list