@@ -203,5 +203,95 @@ spv::Id SpirvBuilder::IfBuilder::createMergePhi(spv::Id then_variable,
203203 getElsePhiParent ());
204204}
205205
206+ SpirvBuilder::SwitchBuilder::SwitchBuilder (spv::Id selector,
207+ unsigned int selection_control,
208+ SpirvBuilder& builder)
209+ : builder_(builder),
210+ selector_(selector),
211+ selection_control_(selection_control),
212+ function_(builder.getBuildPoint()->getParent()),
213+ header_block_(builder.getBuildPoint()),
214+ default_phi_parent_(builder.getBuildPoint()->getId()) {
215+ merge_block_ = new spv::Block (builder_.getUniqueId (), function_);
216+ }
217+
218+ void SpirvBuilder::SwitchBuilder::makeBeginDefault () {
219+ assert_null (default_block_);
220+
221+ endSegment ();
222+
223+ default_block_ = new spv::Block (builder_.getUniqueId (), function_);
224+ function_.addBlock (default_block_);
225+ default_block_->addPredecessor (header_block_);
226+ builder_.setBuildPoint (default_block_);
227+
228+ current_branch_ = Branch::kDefault ;
229+ }
230+
231+ void SpirvBuilder::SwitchBuilder::makeBeginCase (unsigned int literal) {
232+ endSegment ();
233+
234+ auto case_block = new spv::Block (builder_.getUniqueId (), function_);
235+ function_.addBlock (case_block);
236+ cases_.emplace_back (literal, case_block->getId ());
237+ case_block->addPredecessor (header_block_);
238+ builder_.setBuildPoint (case_block);
239+
240+ current_branch_ = Branch::kCase ;
241+ }
242+
243+ void SpirvBuilder::SwitchBuilder::addCurrentCaseLiteral (unsigned int literal) {
244+ assert_true (current_branch_ == Branch::kCase );
245+
246+ cases_.emplace_back (literal, cases_.back ().second );
247+ }
248+
249+ void SpirvBuilder::SwitchBuilder::makeEndSwitch () {
250+ endSegment ();
251+
252+ builder_.setBuildPoint (header_block_);
253+
254+ builder_.createSelectionMerge (merge_block_, selection_control_);
255+
256+ std::unique_ptr<spv::Instruction> switch_instruction =
257+ std::make_unique<spv::Instruction>(spv::OpSwitch);
258+ switch_instruction->addIdOperand (selector_);
259+ if (default_block_) {
260+ switch_instruction->addIdOperand (default_block_->getId ());
261+ } else {
262+ switch_instruction->addIdOperand (merge_block_->getId ());
263+ merge_block_->addPredecessor (header_block_);
264+ }
265+ for (const std::pair<unsigned int , spv::Id>& case_pair : cases_) {
266+ switch_instruction->addImmediateOperand (case_pair.first );
267+ switch_instruction->addIdOperand (case_pair.second );
268+ }
269+ builder_.getBuildPoint ()->addInstruction (std::move (switch_instruction));
270+
271+ function_.addBlock (merge_block_);
272+ builder_.setBuildPoint (merge_block_);
273+
274+ current_branch_ = Branch::kMerge ;
275+ }
276+
277+ void SpirvBuilder::SwitchBuilder::endSegment () {
278+ assert_true (current_branch_ == Branch::kSelection ||
279+ current_branch_ == Branch::kDefault ||
280+ current_branch_ == Branch::kCase );
281+
282+ if (current_branch_ == Branch::kSelection ) {
283+ return ;
284+ }
285+
286+ if (!builder_.getBuildPoint ()->isTerminated ()) {
287+ builder_.createBranch (merge_block_);
288+ if (current_branch_ == Branch::kDefault ) {
289+ default_phi_parent_ = builder_.getBuildPoint ()->getId ();
290+ }
291+ }
292+
293+ current_branch_ = Branch::kSelection ;
294+ }
295+
206296} // namespace gpu
207297} // namespace xe
0 commit comments