| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980 |
- // Copyright (c) 2019 Google LLC.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- #include "source/opt/amd_ext_to_khr.h"
- #include <set>
- #include <string>
- #include "ir_builder.h"
- #include "source/opt/ir_context.h"
- #include "spv-amd-shader-ballot.insts.inc"
- #include "type_manager.h"
- namespace spvtools {
- namespace opt {
- namespace {
- enum AmdShaderBallotExtOpcodes {
- AmdShaderBallotSwizzleInvocationsAMD = 1,
- AmdShaderBallotSwizzleInvocationsMaskedAMD = 2,
- AmdShaderBallotWriteInvocationAMD = 3,
- AmdShaderBallotMbcntAMD = 4
- };
- enum AmdShaderTrinaryMinMaxExtOpCodes {
- FMin3AMD = 1,
- UMin3AMD = 2,
- SMin3AMD = 3,
- FMax3AMD = 4,
- UMax3AMD = 5,
- SMax3AMD = 6,
- FMid3AMD = 7,
- UMid3AMD = 8,
- SMid3AMD = 9
- };
- enum AmdGcnShader { CubeFaceCoordAMD = 2, CubeFaceIndexAMD = 1, TimeAMD = 3 };
- analysis::Type* GetUIntType(IRContext* ctx) {
- analysis::Integer int_type(32, false);
- return ctx->get_type_mgr()->GetRegisteredType(&int_type);
- }
- // Returns a folding rule that replaces |op(a,b,c)| by |op(op(a,b),c)|, where
- // |op| is either min or max. |opcode| is the binary opcode in the GLSLstd450
- // extended instruction set that corresponds to the trinary instruction being
- // replaced.
- template <GLSLstd450 opcode>
- bool ReplaceTrinaryMinMax(IRContext* ctx, Instruction* inst,
- const std::vector<const analysis::Constant*>&) {
- uint32_t glsl405_ext_inst_id =
- ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
- if (glsl405_ext_inst_id == 0) {
- ctx->AddExtInstImport("GLSL.std.450");
- glsl405_ext_inst_id =
- ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
- }
- InstructionBuilder ir_builder(
- ctx, inst,
- IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
- uint32_t op1 = inst->GetSingleWordInOperand(2);
- uint32_t op2 = inst->GetSingleWordInOperand(3);
- uint32_t op3 = inst->GetSingleWordInOperand(4);
- Instruction* temp = ir_builder.AddNaryExtendedInstruction(
- inst->type_id(), glsl405_ext_inst_id, opcode, {op1, op2});
- Instruction::OperandList new_operands;
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {glsl405_ext_inst_id}});
- new_operands.push_back({SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
- {static_cast<uint32_t>(opcode)}});
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {temp->result_id()}});
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {op3}});
- inst->SetInOperands(std::move(new_operands));
- ctx->UpdateDefUse(inst);
- return true;
- }
- // Returns a folding rule that replaces |mid(a,b,c)| by |clamp(a, min(b,c),
- // max(b,c)|. The three parameters are the opcode that correspond to the min,
- // max, and clamp operations for the type of the instruction being replaced.
- template <GLSLstd450 min_opcode, GLSLstd450 max_opcode, GLSLstd450 clamp_opcode>
- bool ReplaceTrinaryMid(IRContext* ctx, Instruction* inst,
- const std::vector<const analysis::Constant*>&) {
- uint32_t glsl405_ext_inst_id =
- ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
- if (glsl405_ext_inst_id == 0) {
- ctx->AddExtInstImport("GLSL.std.450");
- glsl405_ext_inst_id =
- ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
- }
- InstructionBuilder ir_builder(
- ctx, inst,
- IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
- uint32_t op1 = inst->GetSingleWordInOperand(2);
- uint32_t op2 = inst->GetSingleWordInOperand(3);
- uint32_t op3 = inst->GetSingleWordInOperand(4);
- Instruction* min = ir_builder.AddNaryExtendedInstruction(
- inst->type_id(), glsl405_ext_inst_id, static_cast<uint32_t>(min_opcode),
- {op2, op3});
- Instruction* max = ir_builder.AddNaryExtendedInstruction(
- inst->type_id(), glsl405_ext_inst_id, static_cast<uint32_t>(max_opcode),
- {op2, op3});
- Instruction::OperandList new_operands;
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {glsl405_ext_inst_id}});
- new_operands.push_back({SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
- {static_cast<uint32_t>(clamp_opcode)}});
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {op1}});
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {min->result_id()}});
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {max->result_id()}});
- inst->SetInOperands(std::move(new_operands));
- ctx->UpdateDefUse(inst);
- return true;
- }
- // Returns a folding rule that will replace the opcode with |opcode| and add
- // the capabilities required. The folding rule assumes it is folding an
- // OpGroup*NonUniformAMD instruction from the SPV_AMD_shader_ballot extension.
- template <spv::Op new_opcode>
- bool ReplaceGroupNonuniformOperationOpCode(
- IRContext* ctx, Instruction* inst,
- const std::vector<const analysis::Constant*>&) {
- switch (new_opcode) {
- case spv::Op::OpGroupNonUniformIAdd:
- case spv::Op::OpGroupNonUniformFAdd:
- case spv::Op::OpGroupNonUniformUMin:
- case spv::Op::OpGroupNonUniformSMin:
- case spv::Op::OpGroupNonUniformFMin:
- case spv::Op::OpGroupNonUniformUMax:
- case spv::Op::OpGroupNonUniformSMax:
- case spv::Op::OpGroupNonUniformFMax:
- break;
- default:
- assert(
- false &&
- "Should be replacing with a group non uniform arithmetic operation.");
- }
- switch (inst->opcode()) {
- case spv::Op::OpGroupIAddNonUniformAMD:
- case spv::Op::OpGroupFAddNonUniformAMD:
- case spv::Op::OpGroupUMinNonUniformAMD:
- case spv::Op::OpGroupSMinNonUniformAMD:
- case spv::Op::OpGroupFMinNonUniformAMD:
- case spv::Op::OpGroupUMaxNonUniformAMD:
- case spv::Op::OpGroupSMaxNonUniformAMD:
- case spv::Op::OpGroupFMaxNonUniformAMD:
- break;
- default:
- assert(false &&
- "Should be replacing a group non uniform arithmetic operation.");
- }
- ctx->AddCapability(spv::Capability::GroupNonUniformArithmetic);
- inst->SetOpcode(new_opcode);
- return true;
- }
- // Returns a folding rule that will replace the SwizzleInvocationsAMD extended
- // instruction in the SPV_AMD_shader_ballot extension.
- //
- // The instruction
- //
- // %offset = OpConstantComposite %v3uint %x %y %z %w
- // %result = OpExtInst %type %1 SwizzleInvocationsAMD %data %offset
- //
- // is replaced with
- //
- // potentially new constants and types
- //
- // clang-format off
- // %uint_max = OpConstant %uint 0xFFFFFFFF
- // %v4uint = OpTypeVector %uint 4
- // %ballot_value = OpConstantComposite %v4uint %uint_max %uint_max %uint_max %uint_max
- // %null = OpConstantNull %type
- // clang-format on
- //
- // and the following code in the function body
- //
- // clang-format off
- // %id = OpLoad %uint %SubgroupLocalInvocationId
- // %quad_idx = OpBitwiseAnd %uint %id %uint_3
- // %quad_ldr = OpBitwiseXor %uint %id %quad_idx
- // %my_offset = OpVectorExtractDynamic %uint %offset %quad_idx
- // %target_inv = OpIAdd %uint %quad_ldr %my_offset
- // %is_active = OpGroupNonUniformBallotBitExtract %bool %uint_3 %ballot_value %target_inv
- // %shuffle = OpGroupNonUniformShuffle %type %uint_3 %data %target_inv
- // %result = OpSelect %type %is_active %shuffle %null
- // clang-format on
- //
- // Also adding the capabilities and builtins that are needed.
- bool ReplaceSwizzleInvocations(IRContext* ctx, Instruction* inst,
- const std::vector<const analysis::Constant*>&) {
- analysis::TypeManager* type_mgr = ctx->get_type_mgr();
- analysis::ConstantManager* const_mgr = ctx->get_constant_mgr();
- ctx->AddExtension("SPV_KHR_shader_ballot");
- ctx->AddCapability(spv::Capability::GroupNonUniformBallot);
- ctx->AddCapability(spv::Capability::GroupNonUniformShuffle);
- InstructionBuilder ir_builder(
- ctx, inst,
- IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
- uint32_t data_id = inst->GetSingleWordInOperand(2);
- uint32_t offset_id = inst->GetSingleWordInOperand(3);
- // Get the subgroup invocation id.
- uint32_t var_id = ctx->GetBuiltinInputVarId(
- uint32_t(spv::BuiltIn::SubgroupLocalInvocationId));
- assert(var_id != 0 && "Could not get SubgroupLocalInvocationId variable.");
- Instruction* var_inst = ctx->get_def_use_mgr()->GetDef(var_id);
- Instruction* var_ptr_type =
- ctx->get_def_use_mgr()->GetDef(var_inst->type_id());
- uint32_t uint_type_id = var_ptr_type->GetSingleWordInOperand(1);
- Instruction* id = ir_builder.AddLoad(uint_type_id, var_id);
- uint32_t quad_mask = ir_builder.GetUintConstantId(3);
- // This gives the offset in the group of 4 of this invocation.
- Instruction* quad_idx = ir_builder.AddBinaryOp(
- uint_type_id, spv::Op::OpBitwiseAnd, id->result_id(), quad_mask);
- // Get the invocation id of the first invocation in the group of 4.
- Instruction* quad_ldr =
- ir_builder.AddBinaryOp(uint_type_id, spv::Op::OpBitwiseXor,
- id->result_id(), quad_idx->result_id());
- // Get the offset of the target invocation from the offset vector.
- Instruction* my_offset =
- ir_builder.AddBinaryOp(uint_type_id, spv::Op::OpVectorExtractDynamic,
- offset_id, quad_idx->result_id());
- // Determine the index of the invocation to read from.
- Instruction* target_inv =
- ir_builder.AddBinaryOp(uint_type_id, spv::Op::OpIAdd,
- quad_ldr->result_id(), my_offset->result_id());
- // Do the group operations
- uint32_t uint_max_id = ir_builder.GetUintConstantId(0xFFFFFFFF);
- uint32_t subgroup_scope =
- ir_builder.GetUintConstantId(uint32_t(spv::Scope::Subgroup));
- const auto* ballot_value_const = const_mgr->GetConstant(
- type_mgr->GetUIntVectorType(4),
- {uint_max_id, uint_max_id, uint_max_id, uint_max_id});
- Instruction* ballot_value =
- const_mgr->GetDefiningInstruction(ballot_value_const);
- Instruction* is_active = ir_builder.AddNaryOp(
- type_mgr->GetBoolTypeId(), spv::Op::OpGroupNonUniformBallotBitExtract,
- {subgroup_scope, ballot_value->result_id(), target_inv->result_id()});
- Instruction* shuffle =
- ir_builder.AddNaryOp(inst->type_id(), spv::Op::OpGroupNonUniformShuffle,
- {subgroup_scope, data_id, target_inv->result_id()});
- // Create the null constant to use in the select.
- const auto* null = const_mgr->GetConstant(type_mgr->GetType(inst->type_id()),
- std::vector<uint32_t>());
- Instruction* null_inst = const_mgr->GetDefiningInstruction(null);
- // Build the select.
- inst->SetOpcode(spv::Op::OpSelect);
- Instruction::OperandList new_operands;
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {is_active->result_id()}});
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {shuffle->result_id()}});
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {null_inst->result_id()}});
- inst->SetInOperands(std::move(new_operands));
- ctx->UpdateDefUse(inst);
- return true;
- }
- // Returns a folding rule that will replace the SwizzleInvocationsMaskedAMD
- // extended instruction in the SPV_AMD_shader_ballot extension.
- //
- // The instruction
- //
- // %mask = OpConstantComposite %v3uint %uint_x %uint_y %uint_z
- // %result = OpExtInst %uint %1 SwizzleInvocationsMaskedAMD %data %mask
- //
- // is replaced with
- //
- // potentially new constants and types
- //
- // clang-format off
- // %uint_mask_extend = OpConstant %uint 0xFFFFFFE0
- // %uint_max = OpConstant %uint 0xFFFFFFFF
- // %v4uint = OpTypeVector %uint 4
- // %ballot_value = OpConstantComposite %v4uint %uint_max %uint_max %uint_max %uint_max
- // clang-format on
- //
- // and the following code in the function body
- //
- // clang-format off
- // %id = OpLoad %uint %SubgroupLocalInvocationId
- // %and_mask = OpBitwiseOr %uint %uint_x %uint_mask_extend
- // %and = OpBitwiseAnd %uint %id %and_mask
- // %or = OpBitwiseOr %uint %and %uint_y
- // %target_inv = OpBitwiseXor %uint %or %uint_z
- // %is_active = OpGroupNonUniformBallotBitExtract %bool %uint_3 %ballot_value %target_inv
- // %shuffle = OpGroupNonUniformShuffle %type %uint_3 %data %target_inv
- // %result = OpSelect %type %is_active %shuffle %uint_0
- // clang-format on
- //
- // Also adding the capabilities and builtins that are needed.
- bool ReplaceSwizzleInvocationsMasked(
- IRContext* ctx, Instruction* inst,
- const std::vector<const analysis::Constant*>&) {
- analysis::TypeManager* type_mgr = ctx->get_type_mgr();
- analysis::DefUseManager* def_use_mgr = ctx->get_def_use_mgr();
- analysis::ConstantManager* const_mgr = ctx->get_constant_mgr();
- ctx->AddCapability(spv::Capability::GroupNonUniformBallot);
- ctx->AddCapability(spv::Capability::GroupNonUniformShuffle);
- InstructionBuilder ir_builder(
- ctx, inst,
- IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
- // Get the operands to inst, and the components of the mask
- uint32_t data_id = inst->GetSingleWordInOperand(2);
- Instruction* mask_inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(3));
- assert(mask_inst->opcode() == spv::Op::OpConstantComposite &&
- "The mask is suppose to be a vector constant.");
- assert(mask_inst->NumInOperands() == 3 &&
- "The mask is suppose to have 3 components.");
- uint32_t uint_x = mask_inst->GetSingleWordInOperand(0);
- uint32_t uint_y = mask_inst->GetSingleWordInOperand(1);
- uint32_t uint_z = mask_inst->GetSingleWordInOperand(2);
- // Get the subgroup invocation id.
- uint32_t var_id = ctx->GetBuiltinInputVarId(
- uint32_t(spv::BuiltIn::SubgroupLocalInvocationId));
- ctx->AddExtension("SPV_KHR_shader_ballot");
- assert(var_id != 0 && "Could not get SubgroupLocalInvocationId variable.");
- Instruction* var_inst = ctx->get_def_use_mgr()->GetDef(var_id);
- Instruction* var_ptr_type =
- ctx->get_def_use_mgr()->GetDef(var_inst->type_id());
- uint32_t uint_type_id = var_ptr_type->GetSingleWordInOperand(1);
- Instruction* id = ir_builder.AddLoad(uint_type_id, var_id);
- // Do the bitwise operations.
- uint32_t mask_extended = ir_builder.GetUintConstantId(0xFFFFFFE0);
- Instruction* and_mask = ir_builder.AddBinaryOp(
- uint_type_id, spv::Op::OpBitwiseOr, uint_x, mask_extended);
- Instruction* and_result =
- ir_builder.AddBinaryOp(uint_type_id, spv::Op::OpBitwiseAnd,
- id->result_id(), and_mask->result_id());
- Instruction* or_result = ir_builder.AddBinaryOp(
- uint_type_id, spv::Op::OpBitwiseOr, and_result->result_id(), uint_y);
- Instruction* target_inv = ir_builder.AddBinaryOp(
- uint_type_id, spv::Op::OpBitwiseXor, or_result->result_id(), uint_z);
- // Do the group operations
- uint32_t uint_max_id = ir_builder.GetUintConstantId(0xFFFFFFFF);
- uint32_t subgroup_scope =
- ir_builder.GetUintConstantId(uint32_t(spv::Scope::Subgroup));
- const auto* ballot_value_const = const_mgr->GetConstant(
- type_mgr->GetUIntVectorType(4),
- {uint_max_id, uint_max_id, uint_max_id, uint_max_id});
- Instruction* ballot_value =
- const_mgr->GetDefiningInstruction(ballot_value_const);
- Instruction* is_active = ir_builder.AddNaryOp(
- type_mgr->GetBoolTypeId(), spv::Op::OpGroupNonUniformBallotBitExtract,
- {subgroup_scope, ballot_value->result_id(), target_inv->result_id()});
- Instruction* shuffle =
- ir_builder.AddNaryOp(inst->type_id(), spv::Op::OpGroupNonUniformShuffle,
- {subgroup_scope, data_id, target_inv->result_id()});
- // Create the null constant to use in the select.
- const auto* null = const_mgr->GetConstant(type_mgr->GetType(inst->type_id()),
- std::vector<uint32_t>());
- Instruction* null_inst = const_mgr->GetDefiningInstruction(null);
- // Build the select.
- inst->SetOpcode(spv::Op::OpSelect);
- Instruction::OperandList new_operands;
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {is_active->result_id()}});
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {shuffle->result_id()}});
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {null_inst->result_id()}});
- inst->SetInOperands(std::move(new_operands));
- ctx->UpdateDefUse(inst);
- return true;
- }
- // Returns a folding rule that will replace the WriteInvocationAMD extended
- // instruction in the SPV_AMD_shader_ballot extension.
- //
- // The instruction
- //
- // clang-format off
- // %result = OpExtInst %type %1 WriteInvocationAMD %input_value %write_value %invocation_index
- // clang-format on
- //
- // with
- //
- // %id = OpLoad %uint %SubgroupLocalInvocationId
- // %cmp = OpIEqual %bool %id %invocation_index
- // %result = OpSelect %type %cmp %write_value %input_value
- //
- // Also adding the capabilities and builtins that are needed.
- bool ReplaceWriteInvocation(IRContext* ctx, Instruction* inst,
- const std::vector<const analysis::Constant*>&) {
- uint32_t var_id = ctx->GetBuiltinInputVarId(
- uint32_t(spv::BuiltIn::SubgroupLocalInvocationId));
- ctx->AddCapability(spv::Capability::SubgroupBallotKHR);
- ctx->AddExtension("SPV_KHR_shader_ballot");
- assert(var_id != 0 && "Could not get SubgroupLocalInvocationId variable.");
- Instruction* var_inst = ctx->get_def_use_mgr()->GetDef(var_id);
- Instruction* var_ptr_type =
- ctx->get_def_use_mgr()->GetDef(var_inst->type_id());
- InstructionBuilder ir_builder(
- ctx, inst,
- IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
- Instruction* t =
- ir_builder.AddLoad(var_ptr_type->GetSingleWordInOperand(1), var_id);
- analysis::Bool bool_type;
- uint32_t bool_type_id = ctx->get_type_mgr()->GetTypeInstruction(&bool_type);
- Instruction* cmp =
- ir_builder.AddBinaryOp(bool_type_id, spv::Op::OpIEqual, t->result_id(),
- inst->GetSingleWordInOperand(4));
- // Build a select.
- inst->SetOpcode(spv::Op::OpSelect);
- Instruction::OperandList new_operands;
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {cmp->result_id()}});
- new_operands.push_back(inst->GetInOperand(3));
- new_operands.push_back(inst->GetInOperand(2));
- inst->SetInOperands(std::move(new_operands));
- ctx->UpdateDefUse(inst);
- return true;
- }
- // Returns a folding rule that will replace the MbcntAMD extended instruction in
- // the SPV_AMD_shader_ballot extension.
- //
- // The instruction
- //
- // %result = OpExtInst %uint %1 MbcntAMD %mask
- //
- // with
- //
- // Get SubgroupLtMask and convert the first 64-bits into a uint64_t because
- // AMD's shader compiler expects a 64-bit integer mask.
- //
- // %var = OpLoad %v4uint %SubgroupLtMaskKHR
- // %shuffle = OpVectorShuffle %v2uint %var %var 0 1
- // %cast = OpBitcast %ulong %shuffle
- //
- // Perform the mask and count the bits.
- //
- // %and = OpBitwiseAnd %ulong %cast %mask
- // %result = OpBitCount %uint %and
- //
- // Also adding the capabilities and builtins that are needed.
- bool ReplaceMbcnt(IRContext* context, Instruction* inst,
- const std::vector<const analysis::Constant*>&) {
- analysis::TypeManager* type_mgr = context->get_type_mgr();
- analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
- uint32_t var_id =
- context->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::SubgroupLtMask));
- assert(var_id != 0 && "Could not get SubgroupLtMask variable.");
- context->AddCapability(spv::Capability::GroupNonUniformBallot);
- Instruction* var_inst = def_use_mgr->GetDef(var_id);
- Instruction* var_ptr_type = def_use_mgr->GetDef(var_inst->type_id());
- Instruction* var_type =
- def_use_mgr->GetDef(var_ptr_type->GetSingleWordInOperand(1));
- assert(var_type->opcode() == spv::Op::OpTypeVector &&
- "Variable is suppose to be a vector of 4 ints");
- // Get the type for the shuffle.
- analysis::Vector temp_type(GetUIntType(context), 2);
- const analysis::Type* shuffle_type =
- context->get_type_mgr()->GetRegisteredType(&temp_type);
- uint32_t shuffle_type_id = type_mgr->GetTypeInstruction(shuffle_type);
- uint32_t mask_id = inst->GetSingleWordInOperand(2);
- Instruction* mask_inst = def_use_mgr->GetDef(mask_id);
- // Testing with amd's shader compiler shows that a 64-bit mask is expected.
- assert(type_mgr->GetType(mask_inst->type_id())->AsInteger() != nullptr);
- assert(type_mgr->GetType(mask_inst->type_id())->AsInteger()->width() == 64);
- InstructionBuilder ir_builder(
- context, inst,
- IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
- Instruction* load = ir_builder.AddLoad(var_type->result_id(), var_id);
- Instruction* shuffle = ir_builder.AddVectorShuffle(
- shuffle_type_id, load->result_id(), load->result_id(), {0, 1});
- Instruction* bitcast = ir_builder.AddUnaryOp(
- mask_inst->type_id(), spv::Op::OpBitcast, shuffle->result_id());
- Instruction* t =
- ir_builder.AddBinaryOp(mask_inst->type_id(), spv::Op::OpBitwiseAnd,
- bitcast->result_id(), mask_id);
- inst->SetOpcode(spv::Op::OpBitCount);
- inst->SetInOperands({{SPV_OPERAND_TYPE_ID, {t->result_id()}}});
- context->UpdateDefUse(inst);
- return true;
- }
- // A folding rule that will replace the CubeFaceCoordAMD extended
- // instruction in the SPV_AMD_gcn_shader_ballot. Returns true if the folding is
- // successful.
- //
- // The instruction
- //
- // %result = OpExtInst %v2float %1 CubeFaceCoordAMD %input
- //
- // with
- //
- // %x = OpCompositeExtract %float %input 0
- // %y = OpCompositeExtract %float %input 1
- // %z = OpCompositeExtract %float %input 2
- // %nx = OpFNegate %float %x
- // %ny = OpFNegate %float %y
- // %nz = OpFNegate %float %z
- // %ax = OpExtInst %float %n_1 FAbs %x
- // %ay = OpExtInst %float %n_1 FAbs %y
- // %az = OpExtInst %float %n_1 FAbs %z
- // %amax_x_y = OpExtInst %float %n_1 FMax %ay %ax
- // %amax = OpExtInst %float %n_1 FMax %az %amax_x_y
- // %cubema = OpFMul %float %float_2 %amax
- // %is_z_max = OpFOrdGreaterThanEqual %bool %az %amax_x_y
- // %not_is_z_max = OpLogicalNot %bool %is_z_max
- // %y_gt_x = OpFOrdGreaterThanEqual %bool %ay %ax
- // %is_y_max = OpLogicalAnd %bool %not_is_z_max %y_gt_x
- // %is_z_neg = OpFOrdLessThan %bool %z %float_0
- // %cubesc_case_1 = OpSelect %float %is_z_neg %nx %x
- // %is_x_neg = OpFOrdLessThan %bool %x %float_0
- // %cubesc_case_2 = OpSelect %float %is_x_neg %z %nz
- // %sel = OpSelect %float %is_y_max %x %cubesc_case_2
- // %cubesc = OpSelect %float %is_z_max %cubesc_case_1 %sel
- // %is_y_neg = OpFOrdLessThan %bool %y %float_0
- // %cubetc_case_1 = OpSelect %float %is_y_neg %nz %z
- // %cubetc = OpSelect %float %is_y_max %cubetc_case_1 %ny
- // %cube = OpCompositeConstruct %v2float %cubesc %cubetc
- // %denom = OpCompositeConstruct %v2float %cubema %cubema
- // %div = OpFDiv %v2float %cube %denom
- // %result = OpFAdd %v2float %div %const
- //
- // Also adding the capabilities and builtins that are needed.
- bool ReplaceCubeFaceCoord(IRContext* ctx, Instruction* inst,
- const std::vector<const analysis::Constant*>&) {
- analysis::TypeManager* type_mgr = ctx->get_type_mgr();
- analysis::ConstantManager* const_mgr = ctx->get_constant_mgr();
- uint32_t float_type_id = type_mgr->GetFloatTypeId();
- const analysis::Type* v2_float_type = type_mgr->GetFloatVectorType(2);
- uint32_t v2_float_type_id = type_mgr->GetId(v2_float_type);
- uint32_t bool_id = type_mgr->GetBoolTypeId();
- InstructionBuilder ir_builder(
- ctx, inst,
- IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
- uint32_t input_id = inst->GetSingleWordInOperand(2);
- uint32_t glsl405_ext_inst_id =
- ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
- if (glsl405_ext_inst_id == 0) {
- ctx->AddExtInstImport("GLSL.std.450");
- glsl405_ext_inst_id =
- ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
- }
- // Get the constants that will be used.
- uint32_t f0_const_id = const_mgr->GetFloatConstId(0.0);
- uint32_t f2_const_id = const_mgr->GetFloatConstId(2.0);
- uint32_t f0_5_const_id = const_mgr->GetFloatConstId(0.5);
- const analysis::Constant* vec_const =
- const_mgr->GetConstant(v2_float_type, {f0_5_const_id, f0_5_const_id});
- uint32_t vec_const_id =
- const_mgr->GetDefiningInstruction(vec_const)->result_id();
- // Extract the input values.
- Instruction* x = ir_builder.AddCompositeExtract(float_type_id, input_id, {0});
- Instruction* y = ir_builder.AddCompositeExtract(float_type_id, input_id, {1});
- Instruction* z = ir_builder.AddCompositeExtract(float_type_id, input_id, {2});
- // Negate the input values.
- Instruction* nx =
- ir_builder.AddUnaryOp(float_type_id, spv::Op::OpFNegate, x->result_id());
- Instruction* ny =
- ir_builder.AddUnaryOp(float_type_id, spv::Op::OpFNegate, y->result_id());
- Instruction* nz =
- ir_builder.AddUnaryOp(float_type_id, spv::Op::OpFNegate, z->result_id());
- // Get the abolsute values of the inputs.
- Instruction* ax = ir_builder.AddNaryExtendedInstruction(
- float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {x->result_id()});
- Instruction* ay = ir_builder.AddNaryExtendedInstruction(
- float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {y->result_id()});
- Instruction* az = ir_builder.AddNaryExtendedInstruction(
- float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {z->result_id()});
- // Find which values are negative. Used in later computations.
- Instruction* is_z_neg = ir_builder.AddBinaryOp(
- bool_id, spv::Op::OpFOrdLessThan, z->result_id(), f0_const_id);
- Instruction* is_y_neg = ir_builder.AddBinaryOp(
- bool_id, spv::Op::OpFOrdLessThan, y->result_id(), f0_const_id);
- Instruction* is_x_neg = ir_builder.AddBinaryOp(
- bool_id, spv::Op::OpFOrdLessThan, x->result_id(), f0_const_id);
- // Compute cubema
- Instruction* amax_x_y = ir_builder.AddNaryExtendedInstruction(
- float_type_id, glsl405_ext_inst_id, GLSLstd450FMax,
- {ax->result_id(), ay->result_id()});
- Instruction* amax = ir_builder.AddNaryExtendedInstruction(
- float_type_id, glsl405_ext_inst_id, GLSLstd450FMax,
- {az->result_id(), amax_x_y->result_id()});
- Instruction* cubema = ir_builder.AddBinaryOp(float_type_id, spv::Op::OpFMul,
- f2_const_id, amax->result_id());
- // Do the comparisons needed for computing cubesc and cubetc.
- Instruction* is_z_max =
- ir_builder.AddBinaryOp(bool_id, spv::Op::OpFOrdGreaterThanEqual,
- az->result_id(), amax_x_y->result_id());
- Instruction* not_is_z_max = ir_builder.AddUnaryOp(
- bool_id, spv::Op::OpLogicalNot, is_z_max->result_id());
- Instruction* y_gr_x =
- ir_builder.AddBinaryOp(bool_id, spv::Op::OpFOrdGreaterThanEqual,
- ay->result_id(), ax->result_id());
- Instruction* is_y_max =
- ir_builder.AddBinaryOp(bool_id, spv::Op::OpLogicalAnd,
- not_is_z_max->result_id(), y_gr_x->result_id());
- // Select the correct value for cubesc.
- Instruction* cubesc_case_1 = ir_builder.AddSelect(
- float_type_id, is_z_neg->result_id(), nx->result_id(), x->result_id());
- Instruction* cubesc_case_2 = ir_builder.AddSelect(
- float_type_id, is_x_neg->result_id(), z->result_id(), nz->result_id());
- Instruction* sel =
- ir_builder.AddSelect(float_type_id, is_y_max->result_id(), x->result_id(),
- cubesc_case_2->result_id());
- Instruction* cubesc =
- ir_builder.AddSelect(float_type_id, is_z_max->result_id(),
- cubesc_case_1->result_id(), sel->result_id());
- // Select the correct value for cubetc.
- Instruction* cubetc_case_1 = ir_builder.AddSelect(
- float_type_id, is_y_neg->result_id(), nz->result_id(), z->result_id());
- Instruction* cubetc =
- ir_builder.AddSelect(float_type_id, is_y_max->result_id(),
- cubetc_case_1->result_id(), ny->result_id());
- // Do the division
- Instruction* cube = ir_builder.AddCompositeConstruct(
- v2_float_type_id, {cubesc->result_id(), cubetc->result_id()});
- Instruction* denom = ir_builder.AddCompositeConstruct(
- v2_float_type_id, {cubema->result_id(), cubema->result_id()});
- Instruction* div = ir_builder.AddBinaryOp(
- v2_float_type_id, spv::Op::OpFDiv, cube->result_id(), denom->result_id());
- // Get the final result by adding 0.5 to |div|.
- inst->SetOpcode(spv::Op::OpFAdd);
- Instruction::OperandList new_operands;
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {div->result_id()}});
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {vec_const_id}});
- inst->SetInOperands(std::move(new_operands));
- ctx->UpdateDefUse(inst);
- return true;
- }
- // A folding rule that will replace the CubeFaceIndexAMD extended
- // instruction in the SPV_AMD_gcn_shader_ballot. Returns true if the folding
- // is successful.
- //
- // The instruction
- //
- // %result = OpExtInst %float %1 CubeFaceIndexAMD %input
- //
- // with
- //
- // %x = OpCompositeExtract %float %input 0
- // %y = OpCompositeExtract %float %input 1
- // %z = OpCompositeExtract %float %input 2
- // %ax = OpExtInst %float %n_1 FAbs %x
- // %ay = OpExtInst %float %n_1 FAbs %y
- // %az = OpExtInst %float %n_1 FAbs %z
- // %is_z_neg = OpFOrdLessThan %bool %z %float_0
- // %is_y_neg = OpFOrdLessThan %bool %y %float_0
- // %is_x_neg = OpFOrdLessThan %bool %x %float_0
- // %amax_x_y = OpExtInst %float %n_1 FMax %ax %ay
- // %is_z_max = OpFOrdGreaterThanEqual %bool %az %amax_x_y
- // %y_gt_x = OpFOrdGreaterThanEqual %bool %ay %ax
- // %case_z = OpSelect %float %is_z_neg %float_5 %float4
- // %case_y = OpSelect %float %is_y_neg %float_3 %float2
- // %case_x = OpSelect %float %is_x_neg %float_1 %float0
- // %sel = OpSelect %float %y_gt_x %case_y %case_x
- // %result = OpSelect %float %is_z_max %case_z %sel
- //
- // Also adding the capabilities and builtins that are needed.
- bool ReplaceCubeFaceIndex(IRContext* ctx, Instruction* inst,
- const std::vector<const analysis::Constant*>&) {
- analysis::TypeManager* type_mgr = ctx->get_type_mgr();
- analysis::ConstantManager* const_mgr = ctx->get_constant_mgr();
- uint32_t float_type_id = type_mgr->GetFloatTypeId();
- uint32_t bool_id = type_mgr->GetBoolTypeId();
- InstructionBuilder ir_builder(
- ctx, inst,
- IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
- uint32_t input_id = inst->GetSingleWordInOperand(2);
- uint32_t glsl405_ext_inst_id =
- ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
- if (glsl405_ext_inst_id == 0) {
- ctx->AddExtInstImport("GLSL.std.450");
- glsl405_ext_inst_id =
- ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
- }
- // Get the constants that will be used.
- uint32_t f0_const_id = const_mgr->GetFloatConstId(0.0);
- uint32_t f1_const_id = const_mgr->GetFloatConstId(1.0);
- uint32_t f2_const_id = const_mgr->GetFloatConstId(2.0);
- uint32_t f3_const_id = const_mgr->GetFloatConstId(3.0);
- uint32_t f4_const_id = const_mgr->GetFloatConstId(4.0);
- uint32_t f5_const_id = const_mgr->GetFloatConstId(5.0);
- // Extract the input values.
- Instruction* x = ir_builder.AddCompositeExtract(float_type_id, input_id, {0});
- Instruction* y = ir_builder.AddCompositeExtract(float_type_id, input_id, {1});
- Instruction* z = ir_builder.AddCompositeExtract(float_type_id, input_id, {2});
- // Get the absolute values of the inputs.
- Instruction* ax = ir_builder.AddNaryExtendedInstruction(
- float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {x->result_id()});
- Instruction* ay = ir_builder.AddNaryExtendedInstruction(
- float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {y->result_id()});
- Instruction* az = ir_builder.AddNaryExtendedInstruction(
- float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {z->result_id()});
- // Find which values are negative. Used in later computations.
- Instruction* is_z_neg = ir_builder.AddBinaryOp(
- bool_id, spv::Op::OpFOrdLessThan, z->result_id(), f0_const_id);
- Instruction* is_y_neg = ir_builder.AddBinaryOp(
- bool_id, spv::Op::OpFOrdLessThan, y->result_id(), f0_const_id);
- Instruction* is_x_neg = ir_builder.AddBinaryOp(
- bool_id, spv::Op::OpFOrdLessThan, x->result_id(), f0_const_id);
- // Find the max value.
- Instruction* amax_x_y = ir_builder.AddNaryExtendedInstruction(
- float_type_id, glsl405_ext_inst_id, GLSLstd450FMax,
- {ax->result_id(), ay->result_id()});
- Instruction* is_z_max =
- ir_builder.AddBinaryOp(bool_id, spv::Op::OpFOrdGreaterThanEqual,
- az->result_id(), amax_x_y->result_id());
- Instruction* y_gr_x =
- ir_builder.AddBinaryOp(bool_id, spv::Op::OpFOrdGreaterThanEqual,
- ay->result_id(), ax->result_id());
- // Get the value for each case.
- Instruction* case_z = ir_builder.AddSelect(
- float_type_id, is_z_neg->result_id(), f5_const_id, f4_const_id);
- Instruction* case_y = ir_builder.AddSelect(
- float_type_id, is_y_neg->result_id(), f3_const_id, f2_const_id);
- Instruction* case_x = ir_builder.AddSelect(
- float_type_id, is_x_neg->result_id(), f1_const_id, f0_const_id);
- // Select the correct case.
- Instruction* sel =
- ir_builder.AddSelect(float_type_id, y_gr_x->result_id(),
- case_y->result_id(), case_x->result_id());
- // Get the final result by adding 0.5 to |div|.
- inst->SetOpcode(spv::Op::OpSelect);
- Instruction::OperandList new_operands;
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {is_z_max->result_id()}});
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {case_z->result_id()}});
- new_operands.push_back({SPV_OPERAND_TYPE_ID, {sel->result_id()}});
- inst->SetInOperands(std::move(new_operands));
- ctx->UpdateDefUse(inst);
- return true;
- }
- // A folding rule that will replace the TimeAMD extended instruction in the
- // SPV_AMD_gcn_shader_ballot. It returns true if the folding is successful.
- // It returns False, otherwise.
- //
- // The instruction
- //
- // %result = OpExtInst %uint64 %1 TimeAMD
- //
- // with
- //
- // %result = OpReadClockKHR %uint64 %uint_3
- //
- // NOTE: TimeAMD uses subgroup scope (it is not a real time clock).
- bool ReplaceTimeAMD(IRContext* ctx, Instruction* inst,
- const std::vector<const analysis::Constant*>&) {
- InstructionBuilder ir_builder(
- ctx, inst,
- IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
- ctx->AddExtension("SPV_KHR_shader_clock");
- ctx->AddCapability(spv::Capability::ShaderClockKHR);
- inst->SetOpcode(spv::Op::OpReadClockKHR);
- Instruction::OperandList args;
- uint32_t subgroup_scope_id =
- ir_builder.GetUintConstantId(uint32_t(spv::Scope::Subgroup));
- args.push_back({SPV_OPERAND_TYPE_ID, {subgroup_scope_id}});
- inst->SetInOperands(std::move(args));
- ctx->UpdateDefUse(inst);
- return true;
- }
- class AmdExtFoldingRules : public FoldingRules {
- public:
- explicit AmdExtFoldingRules(IRContext* ctx) : FoldingRules(ctx) {}
- protected:
- virtual void AddFoldingRules() override {
- rules_[spv::Op::OpGroupIAddNonUniformAMD].push_back(
- ReplaceGroupNonuniformOperationOpCode<spv::Op::OpGroupNonUniformIAdd>);
- rules_[spv::Op::OpGroupFAddNonUniformAMD].push_back(
- ReplaceGroupNonuniformOperationOpCode<spv::Op::OpGroupNonUniformFAdd>);
- rules_[spv::Op::OpGroupUMinNonUniformAMD].push_back(
- ReplaceGroupNonuniformOperationOpCode<spv::Op::OpGroupNonUniformUMin>);
- rules_[spv::Op::OpGroupSMinNonUniformAMD].push_back(
- ReplaceGroupNonuniformOperationOpCode<spv::Op::OpGroupNonUniformSMin>);
- rules_[spv::Op::OpGroupFMinNonUniformAMD].push_back(
- ReplaceGroupNonuniformOperationOpCode<spv::Op::OpGroupNonUniformFMin>);
- rules_[spv::Op::OpGroupUMaxNonUniformAMD].push_back(
- ReplaceGroupNonuniformOperationOpCode<spv::Op::OpGroupNonUniformUMax>);
- rules_[spv::Op::OpGroupSMaxNonUniformAMD].push_back(
- ReplaceGroupNonuniformOperationOpCode<spv::Op::OpGroupNonUniformSMax>);
- rules_[spv::Op::OpGroupFMaxNonUniformAMD].push_back(
- ReplaceGroupNonuniformOperationOpCode<spv::Op::OpGroupNonUniformFMax>);
- uint32_t extension_id =
- context()->module()->GetExtInstImportId("SPV_AMD_shader_ballot");
- if (extension_id != 0) {
- ext_rules_[{extension_id, AmdShaderBallotSwizzleInvocationsAMD}]
- .push_back(ReplaceSwizzleInvocations);
- ext_rules_[{extension_id, AmdShaderBallotSwizzleInvocationsMaskedAMD}]
- .push_back(ReplaceSwizzleInvocationsMasked);
- ext_rules_[{extension_id, AmdShaderBallotWriteInvocationAMD}].push_back(
- ReplaceWriteInvocation);
- ext_rules_[{extension_id, AmdShaderBallotMbcntAMD}].push_back(
- ReplaceMbcnt);
- }
- extension_id = context()->module()->GetExtInstImportId(
- "SPV_AMD_shader_trinary_minmax");
- if (extension_id != 0) {
- ext_rules_[{extension_id, FMin3AMD}].push_back(
- ReplaceTrinaryMinMax<GLSLstd450FMin>);
- ext_rules_[{extension_id, UMin3AMD}].push_back(
- ReplaceTrinaryMinMax<GLSLstd450UMin>);
- ext_rules_[{extension_id, SMin3AMD}].push_back(
- ReplaceTrinaryMinMax<GLSLstd450SMin>);
- ext_rules_[{extension_id, FMax3AMD}].push_back(
- ReplaceTrinaryMinMax<GLSLstd450FMax>);
- ext_rules_[{extension_id, UMax3AMD}].push_back(
- ReplaceTrinaryMinMax<GLSLstd450UMax>);
- ext_rules_[{extension_id, SMax3AMD}].push_back(
- ReplaceTrinaryMinMax<GLSLstd450SMax>);
- ext_rules_[{extension_id, FMid3AMD}].push_back(
- ReplaceTrinaryMid<GLSLstd450FMin, GLSLstd450FMax, GLSLstd450FClamp>);
- ext_rules_[{extension_id, UMid3AMD}].push_back(
- ReplaceTrinaryMid<GLSLstd450UMin, GLSLstd450UMax, GLSLstd450UClamp>);
- ext_rules_[{extension_id, SMid3AMD}].push_back(
- ReplaceTrinaryMid<GLSLstd450SMin, GLSLstd450SMax, GLSLstd450SClamp>);
- }
- extension_id =
- context()->module()->GetExtInstImportId("SPV_AMD_gcn_shader");
- if (extension_id != 0) {
- ext_rules_[{extension_id, CubeFaceCoordAMD}].push_back(
- ReplaceCubeFaceCoord);
- ext_rules_[{extension_id, CubeFaceIndexAMD}].push_back(
- ReplaceCubeFaceIndex);
- ext_rules_[{extension_id, TimeAMD}].push_back(ReplaceTimeAMD);
- }
- }
- };
- class AmdExtConstFoldingRules : public ConstantFoldingRules {
- public:
- AmdExtConstFoldingRules(IRContext* ctx) : ConstantFoldingRules(ctx) {}
- protected:
- virtual void AddFoldingRules() override {}
- };
- } // namespace
- Pass::Status AmdExtensionToKhrPass::Process() {
- bool changed = false;
- // Traverse the body of the functions to replace instructions that require
- // the extensions.
- InstructionFolder folder(
- context(),
- std::unique_ptr<AmdExtFoldingRules>(new AmdExtFoldingRules(context())),
- MakeUnique<AmdExtConstFoldingRules>(context()));
- for (Function& func : *get_module()) {
- func.ForEachInst([&changed, &folder](Instruction* inst) {
- if (folder.FoldInstruction(inst)) {
- changed = true;
- }
- });
- }
- // Now that instruction that require the extensions have been removed, we can
- // remove the extension instructions.
- std::set<std::string> ext_to_remove = {"SPV_AMD_shader_ballot",
- "SPV_AMD_shader_trinary_minmax",
- "SPV_AMD_gcn_shader"};
- std::vector<Instruction*> to_be_killed;
- for (Instruction& inst : context()->module()->extensions()) {
- if (inst.opcode() == spv::Op::OpExtension) {
- if (ext_to_remove.count(inst.GetInOperand(0).AsString()) != 0) {
- to_be_killed.push_back(&inst);
- }
- }
- }
- for (Instruction& inst : context()->ext_inst_imports()) {
- if (inst.opcode() == spv::Op::OpExtInstImport) {
- if (ext_to_remove.count(inst.GetInOperand(0).AsString()) != 0) {
- to_be_killed.push_back(&inst);
- }
- }
- }
- for (Instruction* inst : to_be_killed) {
- context()->KillInst(inst);
- changed = true;
- }
- // The replacements that take place use instructions that are missing before
- // SPIR-V 1.3. If we changed something, we will have to make sure the version
- // is at least SPIR-V 1.3 to make sure those instruction can be used.
- if (changed) {
- uint32_t version = get_module()->version();
- if (version < 0x00010300 /*1.3*/) {
- get_module()->set_version(0x00010300);
- }
- }
- return changed ? Status::SuccessWithChange : Status::SuccessWithoutChange;
- }
- } // namespace opt
- } // namespace spvtools
|