| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016 |
- // Copyright (c) 2017 Google Inc.
- //
- // 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/ir_context.h"
- #include <cstring>
- #include "OpenCLDebugInfo100.h"
- #include "source/latest_version_glsl_std_450_header.h"
- #include "source/opt/log.h"
- #include "source/opt/mem_pass.h"
- #include "source/opt/reflect.h"
- namespace {
- static const int kSpvDecorateTargetIdInIdx = 0;
- static const int kSpvDecorateDecorationInIdx = 1;
- static const int kSpvDecorateBuiltinInIdx = 2;
- static const int kEntryPointInterfaceInIdx = 3;
- static const int kEntryPointFunctionIdInIdx = 1;
- // Constants for OpenCL.DebugInfo.100 extension instructions.
- static const uint32_t kDebugFunctionOperandFunctionIndex = 13;
- static const uint32_t kDebugGlobalVariableOperandVariableIndex = 11;
- } // anonymous namespace
- namespace spvtools {
- namespace opt {
- void IRContext::BuildInvalidAnalyses(IRContext::Analysis set) {
- if (set & kAnalysisDefUse) {
- BuildDefUseManager();
- }
- if (set & kAnalysisInstrToBlockMapping) {
- BuildInstrToBlockMapping();
- }
- if (set & kAnalysisDecorations) {
- BuildDecorationManager();
- }
- if (set & kAnalysisCFG) {
- BuildCFG();
- }
- if (set & kAnalysisDominatorAnalysis) {
- ResetDominatorAnalysis();
- }
- if (set & kAnalysisLoopAnalysis) {
- ResetLoopAnalysis();
- }
- if (set & kAnalysisBuiltinVarId) {
- ResetBuiltinAnalysis();
- }
- if (set & kAnalysisNameMap) {
- BuildIdToNameMap();
- }
- if (set & kAnalysisScalarEvolution) {
- BuildScalarEvolutionAnalysis();
- }
- if (set & kAnalysisRegisterPressure) {
- BuildRegPressureAnalysis();
- }
- if (set & kAnalysisValueNumberTable) {
- BuildValueNumberTable();
- }
- if (set & kAnalysisStructuredCFG) {
- BuildStructuredCFGAnalysis();
- }
- if (set & kAnalysisIdToFuncMapping) {
- BuildIdToFuncMapping();
- }
- if (set & kAnalysisConstants) {
- BuildConstantManager();
- }
- if (set & kAnalysisTypes) {
- BuildTypeManager();
- }
- }
- void IRContext::InvalidateAnalysesExceptFor(
- IRContext::Analysis preserved_analyses) {
- uint32_t analyses_to_invalidate = valid_analyses_ & (~preserved_analyses);
- InvalidateAnalyses(static_cast<IRContext::Analysis>(analyses_to_invalidate));
- }
- void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) {
- // The ConstantManager contains Type pointers. If the TypeManager goes
- // away, the ConstantManager has to go away.
- if (analyses_to_invalidate & kAnalysisTypes) {
- analyses_to_invalidate |= kAnalysisConstants;
- }
- // The dominator analysis hold the psuedo entry and exit nodes from the CFG.
- // Also if the CFG change the dominators many changed as well, so the
- // dominator analysis should be invalidated as well.
- if (analyses_to_invalidate & kAnalysisCFG) {
- analyses_to_invalidate |= kAnalysisDominatorAnalysis;
- }
- if (analyses_to_invalidate & kAnalysisDefUse) {
- def_use_mgr_.reset(nullptr);
- }
- if (analyses_to_invalidate & kAnalysisInstrToBlockMapping) {
- instr_to_block_.clear();
- }
- if (analyses_to_invalidate & kAnalysisDecorations) {
- decoration_mgr_.reset(nullptr);
- }
- if (analyses_to_invalidate & kAnalysisCombinators) {
- combinator_ops_.clear();
- }
- if (analyses_to_invalidate & kAnalysisBuiltinVarId) {
- builtin_var_id_map_.clear();
- }
- if (analyses_to_invalidate & kAnalysisCFG) {
- cfg_.reset(nullptr);
- }
- if (analyses_to_invalidate & kAnalysisDominatorAnalysis) {
- dominator_trees_.clear();
- post_dominator_trees_.clear();
- }
- if (analyses_to_invalidate & kAnalysisNameMap) {
- id_to_name_.reset(nullptr);
- }
- if (analyses_to_invalidate & kAnalysisValueNumberTable) {
- vn_table_.reset(nullptr);
- }
- if (analyses_to_invalidate & kAnalysisStructuredCFG) {
- struct_cfg_analysis_.reset(nullptr);
- }
- if (analyses_to_invalidate & kAnalysisIdToFuncMapping) {
- id_to_func_.clear();
- }
- if (analyses_to_invalidate & kAnalysisConstants) {
- constant_mgr_.reset(nullptr);
- }
- if (analyses_to_invalidate & kAnalysisTypes) {
- type_mgr_.reset(nullptr);
- }
- valid_analyses_ = Analysis(valid_analyses_ & ~analyses_to_invalidate);
- }
- Instruction* IRContext::KillInst(Instruction* inst) {
- if (!inst) {
- return nullptr;
- }
- KillNamesAndDecorates(inst);
- KillOperandFromDebugInstructions(inst);
- if (AreAnalysesValid(kAnalysisDefUse)) {
- get_def_use_mgr()->ClearInst(inst);
- }
- if (AreAnalysesValid(kAnalysisInstrToBlockMapping)) {
- instr_to_block_.erase(inst);
- }
- if (AreAnalysesValid(kAnalysisDecorations)) {
- if (inst->IsDecoration()) {
- decoration_mgr_->RemoveDecoration(inst);
- }
- }
- if (type_mgr_ && IsTypeInst(inst->opcode())) {
- type_mgr_->RemoveId(inst->result_id());
- }
- if (constant_mgr_ && IsConstantInst(inst->opcode())) {
- constant_mgr_->RemoveId(inst->result_id());
- }
- if (inst->opcode() == SpvOpCapability || inst->opcode() == SpvOpExtension) {
- // We reset the feature manager, instead of updating it, because it is just
- // as much work. We would have to remove all capabilities implied by this
- // capability that are not also implied by the remaining OpCapability
- // instructions. We could update extensions, but we will see if it is
- // needed.
- ResetFeatureManager();
- }
- RemoveFromIdToName(inst);
- Instruction* next_instruction = nullptr;
- if (inst->IsInAList()) {
- next_instruction = inst->NextNode();
- inst->RemoveFromList();
- delete inst;
- } else {
- // Needed for instructions that are not part of a list like OpLabels,
- // OpFunction, OpFunctionEnd, etc..
- inst->ToNop();
- }
- return next_instruction;
- }
- bool IRContext::KillDef(uint32_t id) {
- Instruction* def = get_def_use_mgr()->GetDef(id);
- if (def != nullptr) {
- KillInst(def);
- return true;
- }
- return false;
- }
- bool IRContext::ReplaceAllUsesWith(uint32_t before, uint32_t after) {
- return ReplaceAllUsesWithPredicate(
- before, after, [](Instruction*, uint32_t) { return true; });
- }
- bool IRContext::ReplaceAllUsesWithPredicate(
- uint32_t before, uint32_t after,
- const std::function<bool(Instruction*, uint32_t)>& predicate) {
- if (before == after) return false;
- // Ensure that |after| has been registered as def.
- assert(get_def_use_mgr()->GetDef(after) &&
- "'after' is not a registered def.");
- std::vector<std::pair<Instruction*, uint32_t>> uses_to_update;
- get_def_use_mgr()->ForEachUse(
- before, [&predicate, &uses_to_update](Instruction* user, uint32_t index) {
- if (predicate(user, index)) {
- uses_to_update.emplace_back(user, index);
- }
- });
- Instruction* prev = nullptr;
- for (auto p : uses_to_update) {
- Instruction* user = p.first;
- uint32_t index = p.second;
- if (prev == nullptr || prev != user) {
- ForgetUses(user);
- prev = user;
- }
- const uint32_t type_result_id_count =
- (user->result_id() != 0) + (user->type_id() != 0);
- if (index < type_result_id_count) {
- // Update the type_id. Note that result id is immutable so it should
- // never be updated.
- if (user->type_id() != 0 && index == 0) {
- user->SetResultType(after);
- } else if (user->type_id() == 0) {
- SPIRV_ASSERT(consumer_, false,
- "Result type id considered as use while the instruction "
- "doesn't have a result type id.");
- (void)consumer_; // Makes the compiler happy for release build.
- } else {
- SPIRV_ASSERT(consumer_, false,
- "Trying setting the immutable result id.");
- }
- } else {
- // Update an in-operand.
- uint32_t in_operand_pos = index - type_result_id_count;
- // Make the modification in the instruction.
- user->SetInOperand(in_operand_pos, {after});
- }
- AnalyzeUses(user);
- }
- return true;
- }
- bool IRContext::IsConsistent() {
- #ifndef SPIRV_CHECK_CONTEXT
- return true;
- #else
- if (AreAnalysesValid(kAnalysisDefUse)) {
- analysis::DefUseManager new_def_use(module());
- if (*get_def_use_mgr() != new_def_use) {
- return false;
- }
- }
- if (AreAnalysesValid(kAnalysisIdToFuncMapping)) {
- for (auto& fn : *module_) {
- if (id_to_func_[fn.result_id()] != &fn) {
- return false;
- }
- }
- }
- if (AreAnalysesValid(kAnalysisInstrToBlockMapping)) {
- for (auto& func : *module()) {
- for (auto& block : func) {
- if (!block.WhileEachInst([this, &block](Instruction* inst) {
- if (get_instr_block(inst) != &block) {
- return false;
- }
- return true;
- }))
- return false;
- }
- }
- }
- if (!CheckCFG()) {
- return false;
- }
- if (AreAnalysesValid(kAnalysisDecorations)) {
- analysis::DecorationManager* dec_mgr = get_decoration_mgr();
- analysis::DecorationManager current(module());
- if (*dec_mgr != current) {
- return false;
- }
- }
- if (feature_mgr_ != nullptr) {
- FeatureManager current(grammar_);
- current.Analyze(module());
- if (current != *feature_mgr_) {
- return false;
- }
- }
- return true;
- #endif
- }
- void IRContext::ForgetUses(Instruction* inst) {
- if (AreAnalysesValid(kAnalysisDefUse)) {
- get_def_use_mgr()->EraseUseRecordsOfOperandIds(inst);
- }
- if (AreAnalysesValid(kAnalysisDecorations)) {
- if (inst->IsDecoration()) {
- get_decoration_mgr()->RemoveDecoration(inst);
- }
- }
- RemoveFromIdToName(inst);
- }
- void IRContext::AnalyzeUses(Instruction* inst) {
- if (AreAnalysesValid(kAnalysisDefUse)) {
- get_def_use_mgr()->AnalyzeInstUse(inst);
- }
- if (AreAnalysesValid(kAnalysisDecorations)) {
- if (inst->IsDecoration()) {
- get_decoration_mgr()->AddDecoration(inst);
- }
- }
- if (id_to_name_ &&
- (inst->opcode() == SpvOpName || inst->opcode() == SpvOpMemberName)) {
- id_to_name_->insert({inst->GetSingleWordInOperand(0), inst});
- }
- }
- void IRContext::KillNamesAndDecorates(uint32_t id) {
- analysis::DecorationManager* dec_mgr = get_decoration_mgr();
- dec_mgr->RemoveDecorationsFrom(id);
- std::vector<Instruction*> name_to_kill;
- for (auto name : GetNames(id)) {
- name_to_kill.push_back(name.second);
- }
- for (Instruction* name_inst : name_to_kill) {
- KillInst(name_inst);
- }
- }
- void IRContext::KillNamesAndDecorates(Instruction* inst) {
- const uint32_t rId = inst->result_id();
- if (rId == 0) return;
- KillNamesAndDecorates(rId);
- }
- Instruction* IRContext::GetOpenCL100DebugInfoNone() {
- if (debug_info_none_inst_) return debug_info_none_inst_;
- assert(get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo() &&
- "Module does not include debug info extension instruction.");
- // Create a new DebugInfoNone.
- std::unique_ptr<Instruction> dbg_info_none(new Instruction(
- this, SpvOpExtInst, get_type_mgr()->GetVoidTypeId(), TakeNextId(),
- {
- {SPV_OPERAND_TYPE_RESULT_ID,
- {get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()}},
- {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
- {static_cast<uint32_t>(OpenCLDebugInfo100DebugInfoNone)}},
- }));
- // Add to the front of |ext_inst_debuginfo_|.
- debug_info_none_inst_ = module()->ext_inst_debuginfo_begin()->InsertBefore(
- std::move(dbg_info_none));
- return debug_info_none_inst_;
- }
- void IRContext::KillOperandFromDebugInstructions(Instruction* inst) {
- const auto opcode = inst->opcode();
- const uint32_t id = inst->result_id();
- // Kill id of OpFunction from DebugFunction.
- if (opcode == SpvOpFunction) {
- for (auto it = module()->ext_inst_debuginfo_begin();
- it != module()->ext_inst_debuginfo_end(); ++it) {
- if (it->GetOpenCL100DebugOpcode() != OpenCLDebugInfo100DebugFunction)
- continue;
- auto& operand = it->GetOperand(kDebugFunctionOperandFunctionIndex);
- if (operand.words[0] == id) {
- operand.words[0] = GetOpenCL100DebugInfoNone()->result_id();
- }
- }
- }
- // Kill id of OpVariable for global variable from DebugGlobalVariable.
- if (opcode == SpvOpVariable || IsConstantInst(opcode)) {
- for (auto it = module()->ext_inst_debuginfo_begin();
- it != module()->ext_inst_debuginfo_end(); ++it) {
- if (it->GetOpenCL100DebugOpcode() !=
- OpenCLDebugInfo100DebugGlobalVariable)
- continue;
- auto& operand = it->GetOperand(kDebugGlobalVariableOperandVariableIndex);
- if (operand.words[0] == id) {
- operand.words[0] = GetOpenCL100DebugInfoNone()->result_id();
- }
- }
- }
- // Notice that we do not need anythings to do for local variables.
- // DebugLocalVariable does not have an OpVariable operand. Instead,
- // DebugDeclare/DebugValue has an OpVariable operand for a local
- // variable. The function inlining pass handles it properly.
- }
- void IRContext::AddCombinatorsForCapability(uint32_t capability) {
- if (capability == SpvCapabilityShader) {
- combinator_ops_[0].insert({SpvOpNop,
- SpvOpUndef,
- SpvOpConstant,
- SpvOpConstantTrue,
- SpvOpConstantFalse,
- SpvOpConstantComposite,
- SpvOpConstantSampler,
- SpvOpConstantNull,
- SpvOpTypeVoid,
- SpvOpTypeBool,
- SpvOpTypeInt,
- SpvOpTypeFloat,
- SpvOpTypeVector,
- SpvOpTypeMatrix,
- SpvOpTypeImage,
- SpvOpTypeSampler,
- SpvOpTypeSampledImage,
- SpvOpTypeAccelerationStructureNV,
- SpvOpTypeAccelerationStructureKHR,
- SpvOpTypeRayQueryProvisionalKHR,
- SpvOpTypeArray,
- SpvOpTypeRuntimeArray,
- SpvOpTypeStruct,
- SpvOpTypeOpaque,
- SpvOpTypePointer,
- SpvOpTypeFunction,
- SpvOpTypeEvent,
- SpvOpTypeDeviceEvent,
- SpvOpTypeReserveId,
- SpvOpTypeQueue,
- SpvOpTypePipe,
- SpvOpTypeForwardPointer,
- SpvOpVariable,
- SpvOpImageTexelPointer,
- SpvOpLoad,
- SpvOpAccessChain,
- SpvOpInBoundsAccessChain,
- SpvOpArrayLength,
- SpvOpVectorExtractDynamic,
- SpvOpVectorInsertDynamic,
- SpvOpVectorShuffle,
- SpvOpCompositeConstruct,
- SpvOpCompositeExtract,
- SpvOpCompositeInsert,
- SpvOpCopyObject,
- SpvOpTranspose,
- SpvOpSampledImage,
- SpvOpImageSampleImplicitLod,
- SpvOpImageSampleExplicitLod,
- SpvOpImageSampleDrefImplicitLod,
- SpvOpImageSampleDrefExplicitLod,
- SpvOpImageSampleProjImplicitLod,
- SpvOpImageSampleProjExplicitLod,
- SpvOpImageSampleProjDrefImplicitLod,
- SpvOpImageSampleProjDrefExplicitLod,
- SpvOpImageFetch,
- SpvOpImageGather,
- SpvOpImageDrefGather,
- SpvOpImageRead,
- SpvOpImage,
- SpvOpImageQueryFormat,
- SpvOpImageQueryOrder,
- SpvOpImageQuerySizeLod,
- SpvOpImageQuerySize,
- SpvOpImageQueryLevels,
- SpvOpImageQuerySamples,
- SpvOpConvertFToU,
- SpvOpConvertFToS,
- SpvOpConvertSToF,
- SpvOpConvertUToF,
- SpvOpUConvert,
- SpvOpSConvert,
- SpvOpFConvert,
- SpvOpQuantizeToF16,
- SpvOpBitcast,
- SpvOpSNegate,
- SpvOpFNegate,
- SpvOpIAdd,
- SpvOpFAdd,
- SpvOpISub,
- SpvOpFSub,
- SpvOpIMul,
- SpvOpFMul,
- SpvOpUDiv,
- SpvOpSDiv,
- SpvOpFDiv,
- SpvOpUMod,
- SpvOpSRem,
- SpvOpSMod,
- SpvOpFRem,
- SpvOpFMod,
- SpvOpVectorTimesScalar,
- SpvOpMatrixTimesScalar,
- SpvOpVectorTimesMatrix,
- SpvOpMatrixTimesVector,
- SpvOpMatrixTimesMatrix,
- SpvOpOuterProduct,
- SpvOpDot,
- SpvOpIAddCarry,
- SpvOpISubBorrow,
- SpvOpUMulExtended,
- SpvOpSMulExtended,
- SpvOpAny,
- SpvOpAll,
- SpvOpIsNan,
- SpvOpIsInf,
- SpvOpLogicalEqual,
- SpvOpLogicalNotEqual,
- SpvOpLogicalOr,
- SpvOpLogicalAnd,
- SpvOpLogicalNot,
- SpvOpSelect,
- SpvOpIEqual,
- SpvOpINotEqual,
- SpvOpUGreaterThan,
- SpvOpSGreaterThan,
- SpvOpUGreaterThanEqual,
- SpvOpSGreaterThanEqual,
- SpvOpULessThan,
- SpvOpSLessThan,
- SpvOpULessThanEqual,
- SpvOpSLessThanEqual,
- SpvOpFOrdEqual,
- SpvOpFUnordEqual,
- SpvOpFOrdNotEqual,
- SpvOpFUnordNotEqual,
- SpvOpFOrdLessThan,
- SpvOpFUnordLessThan,
- SpvOpFOrdGreaterThan,
- SpvOpFUnordGreaterThan,
- SpvOpFOrdLessThanEqual,
- SpvOpFUnordLessThanEqual,
- SpvOpFOrdGreaterThanEqual,
- SpvOpFUnordGreaterThanEqual,
- SpvOpShiftRightLogical,
- SpvOpShiftRightArithmetic,
- SpvOpShiftLeftLogical,
- SpvOpBitwiseOr,
- SpvOpBitwiseXor,
- SpvOpBitwiseAnd,
- SpvOpNot,
- SpvOpBitFieldInsert,
- SpvOpBitFieldSExtract,
- SpvOpBitFieldUExtract,
- SpvOpBitReverse,
- SpvOpBitCount,
- SpvOpPhi,
- SpvOpImageSparseSampleImplicitLod,
- SpvOpImageSparseSampleExplicitLod,
- SpvOpImageSparseSampleDrefImplicitLod,
- SpvOpImageSparseSampleDrefExplicitLod,
- SpvOpImageSparseSampleProjImplicitLod,
- SpvOpImageSparseSampleProjExplicitLod,
- SpvOpImageSparseSampleProjDrefImplicitLod,
- SpvOpImageSparseSampleProjDrefExplicitLod,
- SpvOpImageSparseFetch,
- SpvOpImageSparseGather,
- SpvOpImageSparseDrefGather,
- SpvOpImageSparseTexelsResident,
- SpvOpImageSparseRead,
- SpvOpSizeOf});
- }
- }
- void IRContext::AddCombinatorsForExtension(Instruction* extension) {
- assert(extension->opcode() == SpvOpExtInstImport &&
- "Expecting an import of an extension's instruction set.");
- const char* extension_name =
- reinterpret_cast<const char*>(&extension->GetInOperand(0).words[0]);
- if (!strcmp(extension_name, "GLSL.std.450")) {
- combinator_ops_[extension->result_id()] = {GLSLstd450Round,
- GLSLstd450RoundEven,
- GLSLstd450Trunc,
- GLSLstd450FAbs,
- GLSLstd450SAbs,
- GLSLstd450FSign,
- GLSLstd450SSign,
- GLSLstd450Floor,
- GLSLstd450Ceil,
- GLSLstd450Fract,
- GLSLstd450Radians,
- GLSLstd450Degrees,
- GLSLstd450Sin,
- GLSLstd450Cos,
- GLSLstd450Tan,
- GLSLstd450Asin,
- GLSLstd450Acos,
- GLSLstd450Atan,
- GLSLstd450Sinh,
- GLSLstd450Cosh,
- GLSLstd450Tanh,
- GLSLstd450Asinh,
- GLSLstd450Acosh,
- GLSLstd450Atanh,
- GLSLstd450Atan2,
- GLSLstd450Pow,
- GLSLstd450Exp,
- GLSLstd450Log,
- GLSLstd450Exp2,
- GLSLstd450Log2,
- GLSLstd450Sqrt,
- GLSLstd450InverseSqrt,
- GLSLstd450Determinant,
- GLSLstd450MatrixInverse,
- GLSLstd450ModfStruct,
- GLSLstd450FMin,
- GLSLstd450UMin,
- GLSLstd450SMin,
- GLSLstd450FMax,
- GLSLstd450UMax,
- GLSLstd450SMax,
- GLSLstd450FClamp,
- GLSLstd450UClamp,
- GLSLstd450SClamp,
- GLSLstd450FMix,
- GLSLstd450IMix,
- GLSLstd450Step,
- GLSLstd450SmoothStep,
- GLSLstd450Fma,
- GLSLstd450FrexpStruct,
- GLSLstd450Ldexp,
- GLSLstd450PackSnorm4x8,
- GLSLstd450PackUnorm4x8,
- GLSLstd450PackSnorm2x16,
- GLSLstd450PackUnorm2x16,
- GLSLstd450PackHalf2x16,
- GLSLstd450PackDouble2x32,
- GLSLstd450UnpackSnorm2x16,
- GLSLstd450UnpackUnorm2x16,
- GLSLstd450UnpackHalf2x16,
- GLSLstd450UnpackSnorm4x8,
- GLSLstd450UnpackUnorm4x8,
- GLSLstd450UnpackDouble2x32,
- GLSLstd450Length,
- GLSLstd450Distance,
- GLSLstd450Cross,
- GLSLstd450Normalize,
- GLSLstd450FaceForward,
- GLSLstd450Reflect,
- GLSLstd450Refract,
- GLSLstd450FindILsb,
- GLSLstd450FindSMsb,
- GLSLstd450FindUMsb,
- GLSLstd450InterpolateAtCentroid,
- GLSLstd450InterpolateAtSample,
- GLSLstd450InterpolateAtOffset,
- GLSLstd450NMin,
- GLSLstd450NMax,
- GLSLstd450NClamp};
- } else {
- // Map the result id to the empty set.
- combinator_ops_[extension->result_id()];
- }
- }
- void IRContext::InitializeCombinators() {
- get_feature_mgr()->GetCapabilities()->ForEach(
- [this](SpvCapability cap) { AddCombinatorsForCapability(cap); });
- for (auto& extension : module()->ext_inst_imports()) {
- AddCombinatorsForExtension(&extension);
- }
- valid_analyses_ |= kAnalysisCombinators;
- }
- void IRContext::RemoveFromIdToName(const Instruction* inst) {
- if (id_to_name_ &&
- (inst->opcode() == SpvOpName || inst->opcode() == SpvOpMemberName)) {
- auto range = id_to_name_->equal_range(inst->GetSingleWordInOperand(0));
- for (auto it = range.first; it != range.second; ++it) {
- if (it->second == inst) {
- id_to_name_->erase(it);
- break;
- }
- }
- }
- }
- LoopDescriptor* IRContext::GetLoopDescriptor(const Function* f) {
- if (!AreAnalysesValid(kAnalysisLoopAnalysis)) {
- ResetLoopAnalysis();
- }
- std::unordered_map<const Function*, LoopDescriptor>::iterator it =
- loop_descriptors_.find(f);
- if (it == loop_descriptors_.end()) {
- return &loop_descriptors_
- .emplace(std::make_pair(f, LoopDescriptor(this, f)))
- .first->second;
- }
- return &it->second;
- }
- uint32_t IRContext::FindBuiltinInputVar(uint32_t builtin) {
- for (auto& a : module_->annotations()) {
- if (a.opcode() != SpvOpDecorate) continue;
- if (a.GetSingleWordInOperand(kSpvDecorateDecorationInIdx) !=
- SpvDecorationBuiltIn)
- continue;
- if (a.GetSingleWordInOperand(kSpvDecorateBuiltinInIdx) != builtin) continue;
- uint32_t target_id = a.GetSingleWordInOperand(kSpvDecorateTargetIdInIdx);
- Instruction* b_var = get_def_use_mgr()->GetDef(target_id);
- if (b_var->opcode() != SpvOpVariable) continue;
- if (b_var->GetSingleWordInOperand(0) != SpvStorageClassInput) continue;
- return target_id;
- }
- return 0;
- }
- void IRContext::AddVarToEntryPoints(uint32_t var_id) {
- uint32_t ocnt = 0;
- for (auto& e : module()->entry_points()) {
- bool found = false;
- e.ForEachInOperand([&ocnt, &found, &var_id](const uint32_t* idp) {
- if (ocnt >= kEntryPointInterfaceInIdx) {
- if (*idp == var_id) found = true;
- }
- ++ocnt;
- });
- if (!found) {
- e.AddOperand({SPV_OPERAND_TYPE_ID, {var_id}});
- get_def_use_mgr()->AnalyzeInstDefUse(&e);
- }
- }
- }
- uint32_t IRContext::GetBuiltinInputVarId(uint32_t builtin) {
- if (!AreAnalysesValid(kAnalysisBuiltinVarId)) ResetBuiltinAnalysis();
- // If cached, return it.
- std::unordered_map<uint32_t, uint32_t>::iterator it =
- builtin_var_id_map_.find(builtin);
- if (it != builtin_var_id_map_.end()) return it->second;
- // Look for one in shader
- uint32_t var_id = FindBuiltinInputVar(builtin);
- if (var_id == 0) {
- // If not found, create it
- // TODO(greg-lunarg): Add support for all builtins
- analysis::TypeManager* type_mgr = get_type_mgr();
- analysis::Type* reg_type;
- switch (builtin) {
- case SpvBuiltInFragCoord: {
- analysis::Float float_ty(32);
- analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty);
- analysis::Vector v4float_ty(reg_float_ty, 4);
- reg_type = type_mgr->GetRegisteredType(&v4float_ty);
- break;
- }
- case SpvBuiltInVertexIndex:
- case SpvBuiltInInstanceIndex:
- case SpvBuiltInPrimitiveId:
- case SpvBuiltInInvocationId:
- case SpvBuiltInSubgroupLocalInvocationId: {
- analysis::Integer uint_ty(32, false);
- reg_type = type_mgr->GetRegisteredType(&uint_ty);
- break;
- }
- case SpvBuiltInGlobalInvocationId:
- case SpvBuiltInLaunchIdNV: {
- analysis::Integer uint_ty(32, false);
- analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
- analysis::Vector v3uint_ty(reg_uint_ty, 3);
- reg_type = type_mgr->GetRegisteredType(&v3uint_ty);
- break;
- }
- case SpvBuiltInTessCoord: {
- analysis::Float float_ty(32);
- analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty);
- analysis::Vector v3float_ty(reg_float_ty, 3);
- reg_type = type_mgr->GetRegisteredType(&v3float_ty);
- break;
- }
- case SpvBuiltInSubgroupLtMask: {
- analysis::Integer uint_ty(32, false);
- analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
- analysis::Vector v4uint_ty(reg_uint_ty, 4);
- reg_type = type_mgr->GetRegisteredType(&v4uint_ty);
- break;
- }
- default: {
- assert(false && "unhandled builtin");
- return 0;
- }
- }
- uint32_t type_id = type_mgr->GetTypeInstruction(reg_type);
- uint32_t varTyPtrId =
- type_mgr->FindPointerToType(type_id, SpvStorageClassInput);
- // TODO(1841): Handle id overflow.
- var_id = TakeNextId();
- std::unique_ptr<Instruction> newVarOp(
- new Instruction(this, SpvOpVariable, varTyPtrId, var_id,
- {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
- {SpvStorageClassInput}}}));
- get_def_use_mgr()->AnalyzeInstDefUse(&*newVarOp);
- module()->AddGlobalValue(std::move(newVarOp));
- get_decoration_mgr()->AddDecorationVal(var_id, SpvDecorationBuiltIn,
- builtin);
- AddVarToEntryPoints(var_id);
- }
- builtin_var_id_map_[builtin] = var_id;
- return var_id;
- }
- void IRContext::AddCalls(const Function* func, std::queue<uint32_t>* todo) {
- for (auto bi = func->begin(); bi != func->end(); ++bi)
- for (auto ii = bi->begin(); ii != bi->end(); ++ii)
- if (ii->opcode() == SpvOpFunctionCall)
- todo->push(ii->GetSingleWordInOperand(0));
- }
- bool IRContext::ProcessEntryPointCallTree(ProcessFunction& pfn) {
- // Collect all of the entry points as the roots.
- std::queue<uint32_t> roots;
- for (auto& e : module()->entry_points()) {
- roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx));
- }
- return ProcessCallTreeFromRoots(pfn, &roots);
- }
- bool IRContext::ProcessReachableCallTree(ProcessFunction& pfn) {
- std::queue<uint32_t> roots;
- // Add all entry points since they can be reached from outside the module.
- for (auto& e : module()->entry_points())
- roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx));
- // Add all exported functions since they can be reached from outside the
- // module.
- for (auto& a : annotations()) {
- // TODO: Handle group decorations as well. Currently not generate by any
- // front-end, but could be coming.
- if (a.opcode() == SpvOp::SpvOpDecorate) {
- if (a.GetSingleWordOperand(1) ==
- SpvDecoration::SpvDecorationLinkageAttributes) {
- uint32_t lastOperand = a.NumOperands() - 1;
- if (a.GetSingleWordOperand(lastOperand) ==
- SpvLinkageType::SpvLinkageTypeExport) {
- uint32_t id = a.GetSingleWordOperand(0);
- if (GetFunction(id)) {
- roots.push(id);
- }
- }
- }
- }
- }
- return ProcessCallTreeFromRoots(pfn, &roots);
- }
- bool IRContext::ProcessCallTreeFromRoots(ProcessFunction& pfn,
- std::queue<uint32_t>* roots) {
- // Process call tree
- bool modified = false;
- std::unordered_set<uint32_t> done;
- while (!roots->empty()) {
- const uint32_t fi = roots->front();
- roots->pop();
- if (done.insert(fi).second) {
- Function* fn = GetFunction(fi);
- assert(fn && "Trying to process a function that does not exist.");
- modified = pfn(fn) || modified;
- AddCalls(fn, roots);
- }
- }
- return modified;
- }
- void IRContext::EmitErrorMessage(std::string message, Instruction* inst) {
- if (!consumer()) {
- return;
- }
- Instruction* line_inst = inst;
- while (line_inst != nullptr) { // Stop at the beginning of the basic block.
- if (!line_inst->dbg_line_insts().empty()) {
- line_inst = &line_inst->dbg_line_insts().back();
- if (line_inst->opcode() == SpvOpNoLine) {
- line_inst = nullptr;
- }
- break;
- }
- line_inst = line_inst->PreviousNode();
- }
- uint32_t line_number = 0;
- uint32_t col_number = 0;
- char* source = nullptr;
- if (line_inst != nullptr) {
- Instruction* file_name =
- get_def_use_mgr()->GetDef(line_inst->GetSingleWordInOperand(0));
- source = reinterpret_cast<char*>(&file_name->GetInOperand(0).words[0]);
- // Get the line number and column number.
- line_number = line_inst->GetSingleWordInOperand(1);
- col_number = line_inst->GetSingleWordInOperand(2);
- }
- message +=
- "\n " + inst->PrettyPrint(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
- consumer()(SPV_MSG_ERROR, source, {line_number, col_number, 0},
- message.c_str());
- }
- // Gets the dominator analysis for function |f|.
- DominatorAnalysis* IRContext::GetDominatorAnalysis(const Function* f) {
- if (!AreAnalysesValid(kAnalysisDominatorAnalysis)) {
- ResetDominatorAnalysis();
- }
- if (dominator_trees_.find(f) == dominator_trees_.end()) {
- dominator_trees_[f].InitializeTree(*cfg(), f);
- }
- return &dominator_trees_[f];
- }
- // Gets the postdominator analysis for function |f|.
- PostDominatorAnalysis* IRContext::GetPostDominatorAnalysis(const Function* f) {
- if (!AreAnalysesValid(kAnalysisDominatorAnalysis)) {
- ResetDominatorAnalysis();
- }
- if (post_dominator_trees_.find(f) == post_dominator_trees_.end()) {
- post_dominator_trees_[f].InitializeTree(*cfg(), f);
- }
- return &post_dominator_trees_[f];
- }
- bool IRContext::CheckCFG() {
- std::unordered_map<uint32_t, std::vector<uint32_t>> real_preds;
- if (!AreAnalysesValid(kAnalysisCFG)) {
- return true;
- }
- for (Function& function : *module()) {
- for (const auto& bb : function) {
- bb.ForEachSuccessorLabel([&bb, &real_preds](const uint32_t lab_id) {
- real_preds[lab_id].push_back(bb.id());
- });
- }
- for (auto& bb : function) {
- std::vector<uint32_t> preds = cfg()->preds(bb.id());
- std::vector<uint32_t> real = real_preds[bb.id()];
- std::sort(preds.begin(), preds.end());
- std::sort(real.begin(), real.end());
- bool same = true;
- if (preds.size() != real.size()) {
- same = false;
- }
- for (size_t i = 0; i < real.size() && same; i++) {
- if (preds[i] != real[i]) {
- same = false;
- }
- }
- if (!same) {
- std::cerr << "Predecessors for " << bb.id() << " are different:\n";
- std::cerr << "Real:";
- for (uint32_t i : real) {
- std::cerr << ' ' << i;
- }
- std::cerr << std::endl;
- std::cerr << "Recorded:";
- for (uint32_t i : preds) {
- std::cerr << ' ' << i;
- }
- std::cerr << std::endl;
- }
- if (!same) return false;
- }
- }
- return true;
- }
- } // namespace opt
- } // namespace spvtools
|