[Beignet] [Patch V3 2/3] Add Indirect struct argument read support.

Yang Rong rong.r.yang at intel.com
Thu May 14 04:25:36 PDT 2015


The steps to handle Indirect argument read:
1. Find out all indirect loads and its address caculation.
2. Add INDIRECT_MOV IR instruction, replace load to INDIRECT_MOV.
3. Replace the bass address and offset ADD instruction to offset MOV instruction. Could optimize.

V2: use a tmp uw register to calc offset for indirect move.
V3: tmp can't be uniform, because exec width is not 1 when uniform.
Signed-off-by: Yang Rong <rong.r.yang at intel.com>
---
 backend/src/backend/gen_context.cpp        |  32 +++++--
 backend/src/backend/gen_insn_selection.cpp |  47 ++++++----
 backend/src/backend/gen_insn_selection.hpp |   1 +
 backend/src/backend/gen_register.hpp       |  11 ++-
 backend/src/ir/instruction.cpp             |  50 ++++++++++
 backend/src/ir/instruction.hpp             |  10 ++
 backend/src/ir/instruction.hxx             |   1 +
 backend/src/ir/lowering.cpp                | 141 +++++++++++++++++++++++++++--
 8 files changed, 257 insertions(+), 36 deletions(-)

diff --git a/backend/src/backend/gen_context.cpp b/backend/src/backend/gen_context.cpp
index 62fd596..1270564 100644
--- a/backend/src/backend/gen_context.cpp
+++ b/backend/src/backend/gen_context.cpp
@@ -1695,21 +1695,33 @@ namespace gbe
   }
 
   void GenContext::emitIndirectMoveInstruction(const SelectionInstruction &insn) {
-    GenRegister src = ra->genReg(insn.src(0));
-    if(sel->isScalarReg(src.reg()))
-      src = GenRegister::retype(src, GEN_TYPE_UW);
-    else
-      src = GenRegister::unpacked_uw(src.nr, src.subnr / typeSize(GEN_TYPE_UW));
+    GenRegister baseReg = ra->genReg(insn.src(0));
+    GenRegister offset = ra->genReg(insn.src(1));
+    uint32_t immoffset = insn.extra.indirect_offset;
 
     const GenRegister dst = ra->genReg(insn.dst(0));
+    GenRegister tmp = ra->genReg(insn.dst(1));
     const GenRegister a0 = GenRegister::addr8(0);
     uint32_t simdWidth = p->curr.execWidth;
+    GenRegister indirect_src;
+
+    if(sel->isScalarReg(offset.reg()))
+      offset = GenRegister::retype(offset, GEN_TYPE_UW);
+    else
+      offset = GenRegister::unpacked_uw(offset.nr, offset.subnr / typeSize(GEN_TYPE_UW));
+    uint32_t baseRegOffset = GenRegister::grfOffset(baseReg);
+    //There is a restrict that: lower 5 bits indirect reg SubRegNum and
+    //the lower 5 bits of indirect imm SubRegNum cannot exceed 5 bits.
+    //So can't use AddrImm field, need a add.
+    p->ADD(tmp, offset, GenRegister::immuw(baseRegOffset + immoffset));
+    indirect_src = GenRegister::indirect(dst.type, 0, GEN_WIDTH_1,
+                                         GEN_VERTICAL_STRIDE_ONE_DIMENSIONAL, GEN_HORIZONTAL_STRIDE_0);
 
     p->push();
       p->curr.execWidth = 8;
       p->curr.quarterControl = GEN_COMPRESSION_Q1;
-      p->MOV(a0, src);
-      p->MOV(dst, GenRegister::indirect(dst.type, 0, GEN_WIDTH_8));
+      p->MOV(a0, tmp);
+      p->MOV(dst, indirect_src);
     p->pop();
 
     if (simdWidth == 16) {
@@ -1718,9 +1730,9 @@ namespace gbe
         p->curr.quarterControl = GEN_COMPRESSION_Q2;
 
         const GenRegister nextDst = GenRegister::Qn(dst, 1);
-        const GenRegister nextSrc = GenRegister::Qn(src, 1);
-        p->MOV(a0, nextSrc);
-        p->MOV(nextDst, GenRegister::indirect(dst.type, 0, GEN_WIDTH_8));
+        const GenRegister nextOffset = GenRegister::Qn(tmp, 1);
+        p->MOV(a0, nextOffset);
+        p->MOV(nextDst, indirect_src);
       p->pop();
     }
   }
diff --git a/backend/src/backend/gen_insn_selection.cpp b/backend/src/backend/gen_insn_selection.cpp
index 9e15ae0..062b69b 100644
--- a/backend/src/backend/gen_insn_selection.cpp
+++ b/backend/src/backend/gen_insn_selection.cpp
@@ -589,7 +589,7 @@ namespace gbe
     /*! Select instruction with embedded comparison */
     void SEL_CMP(uint32_t conditional, Reg dst, Reg src0, Reg src1);
     /* Constant buffer move instruction */
-    void INDIRECT_MOVE(Reg dst, Reg src);
+    void INDIRECT_MOVE(Reg dst, Reg tmp, Reg base, Reg regOffset, uint32_t immOffset);
     /*! EOT is used to finish GPGPU threads */
     void EOT(void);
     /*! No-op */
@@ -1192,10 +1192,13 @@ namespace gbe
     insn->src(1) = src1;
     insn->extra.function = conditional;
   }
-  void Selection::Opaque::INDIRECT_MOVE(Reg dst, Reg src) {
-    SelectionInstruction *insn = this->appendInsn(SEL_OP_INDIRECT_MOVE, 1, 1);
+  void Selection::Opaque::INDIRECT_MOVE(Reg dst, Reg tmp, Reg base, Reg regOffset, uint32_t immOffset) {
+    SelectionInstruction *insn = this->appendInsn(SEL_OP_INDIRECT_MOVE, 2, 2);
     insn->dst(0) = dst;
-    insn->src(0) = src;
+    insn->dst(1) = tmp;
+    insn->src(0) = base;
+    insn->src(1) = regOffset;
+    insn->extra.indirect_offset = immOffset;
   }
 
   void Selection::Opaque::ATOMIC(Reg dst, uint32_t function,
@@ -3419,18 +3422,6 @@ namespace gbe
       }
     }
 
-    void emitIndirectMove(Selection::Opaque &sel,
-                         const ir::LoadInstruction &insn,
-                         GenRegister address) const
-    {
-      using namespace ir;
-      GBE_ASSERT(insn.getValueNum() == 1);   //todo: handle vec later
-
-      const GenRegister dst = sel.selReg(insn.getValue(0), insn.getValueType());
-      const GenRegister src = address;
-      sel.INDIRECT_MOVE(dst, src);
-    }
-
     INLINE GenRegister getRelativeAddress(Selection::Opaque &sel, GenRegister address, uint8_t bti) const {
       if (bti == 0xfe || bti == BTI_CONSTANT)
         return address;
@@ -4710,6 +4701,29 @@ namespace gbe
     }
   };
 
+  /*! Get a region of a register */
+  class IndirectMovInstructionPattern : public SelectionPattern
+  {
+  public:
+    IndirectMovInstructionPattern(void) : SelectionPattern(1,1) {
+      this->opcodes.push_back(ir::OP_INDIRECT_MOV);
+    }
+    INLINE bool emit(Selection::Opaque &sel, SelectionDAG &dag) const {
+      using namespace ir;
+      const ir::IndirectMovInstruction &insn = cast<ir::IndirectMovInstruction>(dag.insn);
+      GenRegister dst, src0, src1;
+      uint32_t offset = insn.getOffset();
+      dst = sel.selReg(insn.getDst(0), insn.getType());
+      src0 = sel.selReg(insn.getSrc(0), TYPE_U32);
+      src1 = sel.selReg(insn.getSrc(1), TYPE_U32);
+      GenRegister tmp = sel.selReg(sel.reg(FAMILY_WORD), TYPE_U16);
+
+      sel.INDIRECT_MOVE(dst, tmp, src0, src1, offset);
+      markAllChildren(dag);
+      return true;
+    }
+  };
+
   /*! Branch instruction pattern */
   class BranchInstructionPattern : public SelectionPattern
   {
@@ -4936,6 +4950,7 @@ namespace gbe
     this->insert<GetImageInfoInstructionPattern>();
     this->insert<ReadARFInstructionPattern>();
     this->insert<RegionInstructionPattern>();
+    this->insert<IndirectMovInstructionPattern>();
     this->insert<NullaryInstructionPattern>();
 
     // Sort all the patterns with the number of instructions they output
diff --git a/backend/src/backend/gen_insn_selection.hpp b/backend/src/backend/gen_insn_selection.hpp
index dee35bb..2262ef9 100644
--- a/backend/src/backend/gen_insn_selection.hpp
+++ b/backend/src/backend/gen_insn_selection.hpp
@@ -131,6 +131,7 @@ namespace gbe
       };
       uint32_t barrierType;
       bool longjmp;
+      uint32_t indirect_offset;
     } extra;
     /*! Gen opcode */
     uint8_t opcode;
diff --git a/backend/src/backend/gen_register.hpp b/backend/src/backend/gen_register.hpp
index 581f823..80e143e 100644
--- a/backend/src/backend/gen_register.hpp
+++ b/backend/src/backend/gen_register.hpp
@@ -272,6 +272,10 @@ namespace gbe
       return r;
     }
 
+    static INLINE uint32_t grfOffset(GenRegister reg) {
+      return reg.nr * GEN_REG_SIZE + reg.subnr;
+    }
+
     // split a DWORD register into unpacked Byte or Short register
     static INLINE GenRegister splitReg(GenRegister reg, uint32_t count, uint32_t sub_part) {
       GenRegister r = reg;
@@ -826,7 +830,8 @@ namespace gbe
     }
 
     /*! Build an indirectly addressed source */
-    static INLINE GenRegister indirect(uint32_t type, uint32_t subnr, uint32_t width) {
+    static INLINE GenRegister indirect(uint32_t type, uint32_t subnr, uint32_t width,
+                                        uint32_t vstride, uint32_t hstride) {
       GenRegister reg;
       reg.type = type;
       reg.file = GEN_GENERAL_REGISTER_FILE;
@@ -836,8 +841,8 @@ namespace gbe
       reg.nr = 0;
       reg.negation = 0;
       reg.absolute = 0;
-      reg.vstride = 0;
-      reg.hstride = 0;
+      reg.vstride = vstride;
+      reg.hstride = hstride;
       return reg;
     }
 
diff --git a/backend/src/ir/instruction.cpp b/backend/src/ir/instruction.cpp
index 7723b90..8ec8162 100644
--- a/backend/src/ir/instruction.cpp
+++ b/backend/src/ir/instruction.cpp
@@ -729,6 +729,30 @@ namespace ir {
       Register src[1];
     };
 
+    class ALIGNED_INSTRUCTION IndirectMovInstruction :
+      public BasePolicy,
+      public NSrcPolicy<IndirectMovInstruction, 2>,
+      public NDstPolicy<IndirectMovInstruction, 1>
+    {
+    public:
+      INLINE IndirectMovInstruction(Type type, Register dst, Register src0, Register src1, uint32_t offset) {
+        this->type = type;
+        this->offset = offset;
+        this->dst[0] = dst;
+        this->src[0] = src0;
+        this->src[1] = src1;
+        this->opcode = OP_INDIRECT_MOV;
+      }
+      INLINE Type getType(void) const { return this->type; }
+      INLINE uint32_t getOffset(void) const { return this->offset; }
+      INLINE bool wellFormed(const Function &fn, std::string &why) const;
+      INLINE void out(std::ostream &out, const Function &fn) const;
+      Type type;
+      uint32_t offset;
+      Register dst[1];
+      Register src[2];
+    };
+
     class ALIGNED_INSTRUCTION LabelInstruction :
       public BasePolicy,
       public NSrcPolicy<LabelInstruction, 0>,
@@ -1106,6 +1130,16 @@ namespace ir {
       return true;
     }
 
+    INLINE bool IndirectMovInstruction::wellFormed(const Function &fn, std::string &whyNot) const
+    {
+      const RegisterFamily family = getFamily(this->type);
+      if (UNLIKELY(checkSpecialRegForWrite(dst[0], fn, whyNot) == false))
+        return false;
+      if (UNLIKELY(checkRegisterData(family, dst[0], fn, whyNot) == false))
+        return false;
+      return true;
+    }
+
     // Only a label index is required
     INLINE bool LabelInstruction::wellFormed(const Function &fn, std::string &whyNot) const
     {
@@ -1232,6 +1266,12 @@ namespace ir {
       out << " %" << this->getDst(fn, 0) << " %" << this->getSrc(fn, 0) << " offset: " << this->offset;
     }
 
+    INLINE void IndirectMovInstruction::out(std::ostream &out, const Function &fn) const {
+      this->outOpcode(out);
+      out << "." << type << " %" << this->getDst(fn, 0) << " %" << this->getSrc(fn, 0);
+      out << " %" << this->getSrc(fn, 1) << " offset: " << this->offset;
+    }
+
     INLINE void LabelInstruction::out(std::ostream &out, const Function &fn) const {
       this->outOpcode(out);
       out << " $" << labelIndex;
@@ -1393,6 +1433,10 @@ START_INTROSPECTION(RegionInstruction)
 #include "ir/instruction.hxx"
 END_INTROSPECTION(RegionInstruction)
 
+START_INTROSPECTION(IndirectMovInstruction)
+#include "ir/instruction.hxx"
+END_INTROSPECTION(IndirectMovInstruction)
+
 START_INTROSPECTION(LabelInstruction)
 #include "ir/instruction.hxx"
 END_INTROSPECTION(LabelInstruction)
@@ -1581,6 +1625,8 @@ DECL_MEM_FN(SyncInstruction, uint32_t, getParameters(void), getParameters())
 DECL_MEM_FN(ReadARFInstruction, Type, getType(void), getType())
 DECL_MEM_FN(ReadARFInstruction, ARFRegister, getARFRegister(void), getARFRegister())
 DECL_MEM_FN(RegionInstruction, uint32_t, getOffset(void), getOffset())
+DECL_MEM_FN(IndirectMovInstruction, uint32_t, getOffset(void), getOffset())
+DECL_MEM_FN(IndirectMovInstruction, Type, getType(void), getType())
 DECL_MEM_FN(SampleInstruction, Type, getSrcType(void), getSrcType())
 DECL_MEM_FN(SampleInstruction, Type, getDstType(void), getDstType())
 DECL_MEM_FN(SampleInstruction, uint8_t, getSamplerIndex(void), getSamplerIndex())
@@ -1806,6 +1852,10 @@ DECL_MEM_FN(GetImageInfoInstruction, uint8_t, getImageIndex(void), getImageIndex
     return internal::RegionInstruction(dst, src, offset).convert();
   }
 
+  Instruction INDIRECT_MOV(Type type, Register dst, Register src0, Register src1, uint32_t offset) {
+    return internal::IndirectMovInstruction(type, dst, src0, src1, offset).convert();
+  }
+
   // LABEL
   Instruction LABEL(LabelIndex labelIndex) {
     return internal::LabelInstruction(labelIndex).convert();
diff --git a/backend/src/ir/instruction.hpp b/backend/src/ir/instruction.hpp
index 436bfd2..0a6eb80 100644
--- a/backend/src/ir/instruction.hpp
+++ b/backend/src/ir/instruction.hpp
@@ -522,6 +522,15 @@ namespace ir {
     static bool isClassOf(const Instruction &insn);
   };
 
+  /*! Indirect Move instruction */
+  class IndirectMovInstruction : public Instruction {
+  public:
+    Type getType(void) const;
+    uint32_t getOffset(void) const;
+    /*! Return true if the given instruction is an instance of this class */
+    static bool isClassOf(const Instruction &insn);
+  };
+
   /*! Specialize the instruction. Also performs typechecking first based on the
    *  opcode. Crashes if it fails
    */
@@ -723,6 +732,7 @@ namespace ir {
 
   Instruction READ_ARF(Type type, Register dst, ARFRegister arf);
   Instruction REGION(Register dst, Register src, uint32_t offset);
+  Instruction INDIRECT_MOV(Type type, Register dst, Register src0, Register src1, uint32_t offset);
   /*! typed write */
   Instruction TYPED_WRITE(uint8_t imageIndex, Tuple src, uint8_t srcNum, Type srcType, Type coordType);
   /*! sample textures */
diff --git a/backend/src/ir/instruction.hxx b/backend/src/ir/instruction.hxx
index 3f08a92..cf6c6e7 100644
--- a/backend/src/ir/instruction.hxx
+++ b/backend/src/ir/instruction.hxx
@@ -84,6 +84,7 @@ DECL_INSN(SYNC, SyncInstruction)
 DECL_INSN(LABEL, LabelInstruction)
 DECL_INSN(READ_ARF, ReadARFInstruction)
 DECL_INSN(REGION, RegionInstruction)
+DECL_INSN(INDIRECT_MOV, IndirectMovInstruction)
 DECL_INSN(GET_IMAGE_INFO, GetImageInfoInstruction)
 DECL_INSN(MUL_HI, BinaryInstruction)
 DECL_INSN(I64_MUL_HI, BinaryInstruction)
diff --git a/backend/src/ir/lowering.cpp b/backend/src/ir/lowering.cpp
index 0e36907..e17248a 100644
--- a/backend/src/ir/lowering.cpp
+++ b/backend/src/ir/lowering.cpp
@@ -87,9 +87,15 @@ namespace ir {
     uint64_t offset;      //!< Offset where to load in the structure
     uint32_t argID;       //!< Associated function argument
   };
+  struct IndirectLoad {
+    Instruction *load;           //!< Load from the argument
+    vector<Instruction *> adds;  //!< Can be NULL if we only have load(arg)
+    uint32_t argID;              //!< Associated function argument
+  };
 
   /*! List of direct loads */
   typedef vector<LoadAddImm> LoadAddImmSeq;
+  typedef vector<IndirectLoad> IndirectLoadSeq;
 
   /*! Helper class to lower function arguments if required */
   class FunctionArgumentLowerer : public Context
@@ -102,9 +108,13 @@ namespace ir {
     /*! Perform all function arguments substitution if needed */
     void lower(const std::string &name);
     /*! Lower the given function argument accesses */
-    void lower(uint32_t argID);
+    ArgUse lower(uint32_t argID);
     /*! Build the constant push for the function */
     void buildConstantPush(void);
+    /* Lower indirect Read to indirct Mov */
+    void lowerIndirectRead(uint32_t argID);
+    /* Convert indirectLoad to indirect Mov */
+    void ReplaceIndirectLoad(void);
     /*! Inspect the given function argument to see how it is used. If this is
      *  direct loads only, we also output the list of instructions used for each
      *  load
@@ -117,6 +127,7 @@ namespace ir {
     Liveness *liveness; //!< To compute the function graph
     FunctionDAG *dag;   //!< Contains complete dependency information
     LoadAddImmSeq seq;  //!< All the direct loads
+    IndirectLoadSeq indirectSeq;  //!< All the indirect loads
   };
 
   INLINE uint64_t getOffsetFromImm(const Immediate &imm) {
@@ -183,15 +194,21 @@ namespace ir {
     // Process all structure arguments and find all the direct loads we can
     // replace
     const uint32_t argNum = fn->argNum();
+    vector<uint32_t> indirctReadArgs;
     for (uint32_t argID = 0; argID < argNum; ++argID) {
       FunctionArgument &arg = fn->getArg(argID);
       if (arg.type != FunctionArgument::STRUCTURE) continue;
-      this->lower(argID);
+      if(this->lower(argID) == ARG_INDIRECT_READ)
+        indirctReadArgs.push_back(argID);
     }
 
     // Build the constant push description and remove the instruction that
     // therefore become useless
     this->buildConstantPush();
+    for (uint32_t i = 0; i < indirctReadArgs.size(); ++i){
+      lowerIndirectRead(indirctReadArgs[i]);
+    }
+    ReplaceIndirectLoad();
   }
 
 // Remove all the given instructions from the stream (if dead)
@@ -271,6 +288,115 @@ namespace ir {
 
 #undef REMOVE_INSN
 
+  void FunctionArgumentLowerer::lowerIndirectRead(uint32_t argID)
+  {
+    FunctionArgument &arg = fn->getArg(argID);
+
+    vector<Register> derivedRegs;
+    map<Register, vector<Instruction *>> addPtrInsns;
+    derivedRegs.push_back(arg.reg);
+
+    //Collect all load from this argument.
+    for(uint32_t i=0; i<derivedRegs.size(); i++) {
+      const UseSet *useSet = dag->getRegUse(derivedRegs[i]);
+      for (const auto &use : *useSet) {
+        Instruction *insn = const_cast<Instruction*>(use->getInstruction());
+        const Opcode opcode = insn->getOpcode();
+        const uint32_t dstNum = insn->getDstNum();
+        GBE_ASSERT(dstNum == 1 || opcode == OP_LOAD);
+        const Register dst = insn->getDst();
+        auto it = addPtrInsns.find(derivedRegs[i]);
+
+        if((opcode == OP_ADD) && (derivedRegs[i] == arg.reg)) {
+          GBE_ASSERT(it == addPtrInsns.end());
+
+          vector<Instruction *> addInsns;
+          addInsns.push_back(insn);
+          addPtrInsns.insert(std::make_pair(dst, addInsns));
+          derivedRegs.push_back(dst);
+        } else if(opcode == OP_LOAD) {
+          LoadInstruction *load = cast<LoadInstruction>(insn);
+          if (load->getAddressSpace() != MEM_PRIVATE)
+            continue;
+
+          IndirectLoad indirectLoad;
+          Register addr = load->getAddress();
+          indirectLoad.argID = argID;
+          indirectLoad.load = insn;
+
+          auto addrIt = addPtrInsns.find(addr);
+          GBE_ASSERT(addrIt != addPtrInsns.end());
+          indirectLoad.adds = addrIt->second;
+
+          indirectSeq.push_back(indirectLoad);
+        } else {
+          auto dstIt = addPtrInsns.find(dst);
+          if(dstIt == addPtrInsns.end())
+            addPtrInsns.insert(std::make_pair(dst, it->second));
+          else {
+            //Muilt src from both argument, such as select, or phi, merge the vector
+            dstIt->second.insert(dstIt->second.end(), it->second.begin(), it->second.end());
+          }
+          derivedRegs.push_back(dst);
+        }
+      }
+    }
+  }
+
+  void FunctionArgumentLowerer::ReplaceIndirectLoad(void)
+  {
+    if (indirectSeq.size() == 0)
+      return;
+
+    // Track instructions we remove to recursively kill them properly
+    set<const Instruction*> dead;
+
+    set<PushLocation> inserted;
+    for (const auto &indirectLoad : indirectSeq) {
+      const Register arg = fn->getArg(indirectLoad.argID).reg;
+      if(dead.contains(indirectLoad.load)) continue;  //repetitive load in the indirectSeq, skip.
+      LoadInstruction *load = cast<LoadInstruction>(indirectLoad.load);
+      const uint32_t valueNum = load->getValueNum();
+      bool replaced = false;
+      Instruction *ins_after = load; // the instruction to insert after.
+      for (uint32_t valueID = 0; valueID < valueNum; ++valueID) {
+        const Type type = load->getValueType();
+        const RegisterFamily family = getFamily(type);
+        const uint32_t size = getFamilySize(family);
+        const uint32_t offset = valueID * size;
+
+        const Register reg = load->getValue(valueID);
+
+        Instruction mov = ir::INDIRECT_MOV(type, reg, arg, load->getAddress(), offset);
+        mov.insert(ins_after, &ins_after);
+        replaced = true;
+      }
+
+      if (replaced && !dead.contains(load)) {
+        dead.insert(load);
+        load->remove();
+      }
+
+      vector<Instruction *> adds = indirectLoad.adds;
+      for (uint32_t i=0; i<adds.size(); i++) {
+        BinaryInstruction *add = cast<BinaryInstruction>(adds[i]);
+        if (!dead.contains(add)) {
+          Register dst = add->getDst();
+          const Register src0 = add->getSrc(0);
+          const Register src1 = add->getSrc(1);
+
+          GBE_ASSERT(src0 == arg || src1 == arg);
+          Register src = (src0 == arg) ? src1 : src0;
+          Instruction mov = ir::MOV(add->getType(), dst, src);
+
+          //MOV instruction could optimize if the dst don't write later
+          mov.replace(add);
+          dead.insert(add);
+        }
+      }
+    }
+  }
+
   bool FunctionArgumentLowerer::useStore(const ValueDef &def, set<const Instruction*> &visited)
   {
     const UseSet &useSet = dag->getUse(def);
@@ -376,17 +502,18 @@ namespace ir {
     return ARG_INDIRECT_READ;
   }
 
-  void FunctionArgumentLowerer::lower(uint32_t argID) {
-    IF_DEBUG(const ArgUse argUse = )this->getArgUse(argID);
+  ArgUse FunctionArgumentLowerer::lower(uint32_t argID) {
+    const ArgUse argUse = this->getArgUse(argID);
 #if GBE_DEBUG
     GBE_ASSERTM(argUse != ARG_WRITTEN,
                 "TODO A store to a structure argument "
                 "(i.e. not a char/short/int/float argument) has been found. "
                 "This is not supported yet");
-    GBE_ASSERTM(argUse != ARG_INDIRECT_READ,
-                "TODO Only direct loads of structure arguments are "
-                "supported now");
+    //GBE_ASSERTM(argUse != ARG_INDIRECT_READ,
+    //            "TODO Only direct loads of structure arguments are "
+    //            "supported now");
 #endif /* GBE_DEBUG */
+    return argUse;
   }
 
   void lowerFunctionArguments(Unit &unit, const std::string &functionName) {
-- 
1.8.3.2



More information about the Beignet mailing list