Ejemplo n.º 1
0
static void
ELSE(State &state, const ControlFlowInst &cf)
{
   insertElse(state);
}
Ejemplo n.º 2
0
/**
 * Unpack instructions within clauses into a linear format.
 *
 * This will also explicitly insert the implied PUSH/POP/ELSE/BREAK/CONTINUE
 * for CF_ALU instructions to ease translation.
 *
 * Also tracks usages of registers for use in code generation.
 */
bool
linearify(Shader &shader)
{
   for (auto &ins : shader.code) {
      if (ins->type == shadir::Instruction::CF) {
         auto cfIns = reinterpret_cast<shadir::CfInstruction *>(ins.get());

         if (cfIns->clause.size()) {
            for (auto &child : cfIns->clause) {
               shader.linear.push_back(child.get());

               // Check for register usage
               if (child->type == shadir::Instruction::TEX) {
                  auto texIns = reinterpret_cast<shadir::TextureFetchInstruction *>(child.get());
                  shader.samplersUsed.emplace(texIns->samplerID);
                  shader.resourcesUsed.emplace(texIns->resourceID);
                  shader.gprsUsed.emplace(texIns->src.id);
                  shader.gprsUsed.emplace(texIns->dst.id);
               } else if (child->type == shadir::Instruction::VTX) {
                  auto vtxIns = reinterpret_cast<shadir::VertexFetchInstruction *>(child.get());
                  shader.gprsUsed.emplace(vtxIns->src.id);
                  shader.gprsUsed.emplace(vtxIns->dst.id);
               }
            }
         } else {
            shader.linear.push_back(cfIns);
         }
      } else if (ins->type == shadir::Instruction::CF_ALU) {
         auto cfAluIns = reinterpret_cast<shadir::CfAluInstruction *>(ins.get());
         auto pushedBefore = false;
         shadir::AluReductionInstruction *reduction = nullptr;

         switch (cfAluIns->id) {
         case SQ_CF_INST_ALU_BREAK:
         case SQ_CF_INST_ALU_CONTINUE:
            // Insert a push before ALU clause
            insertPush(shader, cfAluIns->cfPC);
            break;
         }

         for (auto &child : cfAluIns->clause) {
            auto aluIns = reinterpret_cast<shadir::AluInstruction *>(child.get());
            auto isPredSet = aluIns->flags & SQ_ALU_FLAG_PRED_SET;

            if (isPredSet) {
               switch (cfAluIns->id) {
               case SQ_CF_INST_ALU_PUSH_BEFORE:
                  // Insert a push only before the first PRED_SET_*
                  if (!pushedBefore) {
                     insertPush(shader, aluIns->cfPC);
                     pushedBefore = true;
                  }
                  break;
               case SQ_CF_INST_ALU_ELSE_AFTER:
                  // Insert a push before PRED_SET_*
                  insertPush(shader, aluIns->cfPC);
                  break;
               }
            }

            if (!reduction) {
               if (aluIns->op2 == SQ_OP2_INST_DOT4
                || aluIns->op2 == SQ_OP2_INST_DOT4_IEEE
                || aluIns->op2 == SQ_OP2_INST_CUBE
                || aluIns->op2 == SQ_OP2_INST_MAX4) {
                  // Combine this into reduction instruction
                  reduction = new shadir::AluReductionInstruction {};
                  reduction->op2 = aluIns->op2;
                  reduction->cfPC = aluIns->cfPC;
                  reduction->groupPC = aluIns->groupPC;
                  reduction->name = aluIns->name;
                  reduction->units.fill(nullptr);
                  shader.custom.emplace_back(reduction);
               }
            }

            if (reduction) {
               if (reduction->units[aluIns->unit]) {
                  throw std::logic_error("Reduction instruction unit collision");
               }

               aluIns->isReduction = true;
               reduction->units[aluIns->unit] = aluIns;

               if (std::all_of(reduction->units.begin(), reduction->units.end(), [](auto unit) { return !!unit; })) {
                  shader.linear.push_back(reduction);
                  reduction = nullptr;
               }
            } else {
               shader.linear.push_back(aluIns);
            }

            if (isPredSet) {
               switch (cfAluIns->id) {
               case SQ_CF_INST_ALU_BREAK:
                  // Insert a break after PRED_SET_*
                  insertBreak(shader, aluIns->cfPC);
                  break;
               case SQ_CF_INST_ALU_CONTINUE:
                  // Insert a continue after PRED_SET_*
                  insertContinue(shader, aluIns->cfPC);
                  break;
               case SQ_CF_INST_ALU_ELSE_AFTER:
                  // Insert an else after PRED_SET_*
                  insertElse(shader, aluIns->cfPC);
                  break;
               }
            }

            // Check for register usage
            for (auto i = 0u; i < aluIns->srcCount; ++i) {
               auto &src = aluIns->src[i];

               if ((src.sel >= SQ_ALU_REGISTER_FIRST && src.sel <= SQ_ALU_REGISTER_LAST)
                || (src.sel >= SQ_ALU_TMP_REGISTER_FIRST && src.sel <= SQ_ALU_TMP_REGISTER_LAST)) {
                  shader.gprsUsed.emplace(src.sel - SQ_ALU_REGISTER_FIRST);
               } else if (src.sel >= SQ_ALU_SRC_CONST_FILE_FIRST && src.sel <= SQ_ALU_SRC_CONST_FILE_LAST) {
                  shader.uniformsUsed.emplace(src.sel - SQ_ALU_SRC_CONST_FILE_FIRST);
               } else if (src.sel == SQ_ALU_SRC_PV) {
                  shader.pvUsed.emplace(aluIns->groupPC - 1);
               } else if (src.sel == SQ_ALU_SRC_PS) {
                  shader.psUsed.emplace(aluIns->groupPC - 1);
               }
            }

            if (aluIns->writeMask) {
               shader.gprsUsed.emplace(aluIns->dst.sel);
            }
         }

         switch (cfAluIns->id) {
         case SQ_CF_INST_ALU_BREAK:
         case SQ_CF_INST_ALU_CONTINUE:
         case SQ_CF_INST_ALU_POP_AFTER:
            // Insert a pop after ALU clause
            insertPop(shader, cfAluIns->cfPC);
            break;
         case SQ_CF_INST_ALU_POP2_AFTER:
            // Insert 2 pops after ALU clause
            insertPop(shader, cfAluIns->cfPC);
            insertPop(shader, cfAluIns->cfPC);
            break;
         }
      } else {
         if (ins->type == shadir::Instruction::EXP) {
            auto expIns = reinterpret_cast<shadir::ExportInstruction *>(ins.get());
            shader.gprsUsed.emplace(expIns->rw.id);
         }

         shader.linear.push_back(ins.get());
      }
   }

   return true;
}