1 // Copyright (c) 2017 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "source/opt/ir_context.h"
16
17 #include <cstring>
18
19 #include "OpenCLDebugInfo100.h"
20 #include "source/latest_version_glsl_std_450_header.h"
21 #include "source/opt/log.h"
22 #include "source/opt/mem_pass.h"
23 #include "source/opt/reflect.h"
24
25 namespace {
26
27 static const int kSpvDecorateTargetIdInIdx = 0;
28 static const int kSpvDecorateDecorationInIdx = 1;
29 static const int kSpvDecorateBuiltinInIdx = 2;
30 static const int kEntryPointInterfaceInIdx = 3;
31 static const int kEntryPointFunctionIdInIdx = 1;
32
33 // Constants for OpenCL.DebugInfo.100 / NonSemantic.Shader.DebugInfo.100
34 // extension instructions.
35 static const uint32_t kDebugFunctionOperandFunctionIndex = 13;
36 static const uint32_t kDebugGlobalVariableOperandVariableIndex = 11;
37
38 } // anonymous namespace
39
40 namespace spvtools {
41 namespace opt {
42
BuildInvalidAnalyses(IRContext::Analysis set)43 void IRContext::BuildInvalidAnalyses(IRContext::Analysis set) {
44 if (set & kAnalysisDefUse) {
45 BuildDefUseManager();
46 }
47 if (set & kAnalysisInstrToBlockMapping) {
48 BuildInstrToBlockMapping();
49 }
50 if (set & kAnalysisDecorations) {
51 BuildDecorationManager();
52 }
53 if (set & kAnalysisCFG) {
54 BuildCFG();
55 }
56 if (set & kAnalysisDominatorAnalysis) {
57 ResetDominatorAnalysis();
58 }
59 if (set & kAnalysisLoopAnalysis) {
60 ResetLoopAnalysis();
61 }
62 if (set & kAnalysisBuiltinVarId) {
63 ResetBuiltinAnalysis();
64 }
65 if (set & kAnalysisNameMap) {
66 BuildIdToNameMap();
67 }
68 if (set & kAnalysisScalarEvolution) {
69 BuildScalarEvolutionAnalysis();
70 }
71 if (set & kAnalysisRegisterPressure) {
72 BuildRegPressureAnalysis();
73 }
74 if (set & kAnalysisValueNumberTable) {
75 BuildValueNumberTable();
76 }
77 if (set & kAnalysisStructuredCFG) {
78 BuildStructuredCFGAnalysis();
79 }
80 if (set & kAnalysisIdToFuncMapping) {
81 BuildIdToFuncMapping();
82 }
83 if (set & kAnalysisConstants) {
84 BuildConstantManager();
85 }
86 if (set & kAnalysisTypes) {
87 BuildTypeManager();
88 }
89 if (set & kAnalysisDebugInfo) {
90 BuildDebugInfoManager();
91 }
92 }
93
InvalidateAnalysesExceptFor(IRContext::Analysis preserved_analyses)94 void IRContext::InvalidateAnalysesExceptFor(
95 IRContext::Analysis preserved_analyses) {
96 uint32_t analyses_to_invalidate = valid_analyses_ & (~preserved_analyses);
97 InvalidateAnalyses(static_cast<IRContext::Analysis>(analyses_to_invalidate));
98 }
99
InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate)100 void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) {
101 // The ConstantManager and DebugInfoManager contain Type pointers. If the
102 // TypeManager goes away, the ConstantManager and DebugInfoManager have to
103 // go away.
104 if (analyses_to_invalidate & kAnalysisTypes) {
105 analyses_to_invalidate |= kAnalysisConstants;
106 analyses_to_invalidate |= kAnalysisDebugInfo;
107 }
108
109 // The dominator analysis hold the psuedo entry and exit nodes from the CFG.
110 // Also if the CFG change the dominators many changed as well, so the
111 // dominator analysis should be invalidated as well.
112 if (analyses_to_invalidate & kAnalysisCFG) {
113 analyses_to_invalidate |= kAnalysisDominatorAnalysis;
114 }
115
116 if (analyses_to_invalidate & kAnalysisDefUse) {
117 def_use_mgr_.reset(nullptr);
118 }
119 if (analyses_to_invalidate & kAnalysisInstrToBlockMapping) {
120 instr_to_block_.clear();
121 }
122 if (analyses_to_invalidate & kAnalysisDecorations) {
123 decoration_mgr_.reset(nullptr);
124 }
125 if (analyses_to_invalidate & kAnalysisCombinators) {
126 combinator_ops_.clear();
127 }
128 if (analyses_to_invalidate & kAnalysisBuiltinVarId) {
129 builtin_var_id_map_.clear();
130 }
131 if (analyses_to_invalidate & kAnalysisCFG) {
132 cfg_.reset(nullptr);
133 }
134 if (analyses_to_invalidate & kAnalysisDominatorAnalysis) {
135 dominator_trees_.clear();
136 post_dominator_trees_.clear();
137 }
138 if (analyses_to_invalidate & kAnalysisNameMap) {
139 id_to_name_.reset(nullptr);
140 }
141 if (analyses_to_invalidate & kAnalysisValueNumberTable) {
142 vn_table_.reset(nullptr);
143 }
144 if (analyses_to_invalidate & kAnalysisStructuredCFG) {
145 struct_cfg_analysis_.reset(nullptr);
146 }
147 if (analyses_to_invalidate & kAnalysisIdToFuncMapping) {
148 id_to_func_.clear();
149 }
150 if (analyses_to_invalidate & kAnalysisConstants) {
151 constant_mgr_.reset(nullptr);
152 }
153 if (analyses_to_invalidate & kAnalysisTypes) {
154 type_mgr_.reset(nullptr);
155 }
156
157 if (analyses_to_invalidate & kAnalysisDebugInfo) {
158 debug_info_mgr_.reset(nullptr);
159 }
160
161 valid_analyses_ = Analysis(valid_analyses_ & ~analyses_to_invalidate);
162 }
163
KillInst(Instruction * inst)164 Instruction* IRContext::KillInst(Instruction* inst) {
165 if (!inst) {
166 return nullptr;
167 }
168
169 KillNamesAndDecorates(inst);
170
171 KillOperandFromDebugInstructions(inst);
172
173 if (AreAnalysesValid(kAnalysisDefUse)) {
174 analysis::DefUseManager* def_use_mgr = get_def_use_mgr();
175 def_use_mgr->ClearInst(inst);
176 for (auto& l_inst : inst->dbg_line_insts()) def_use_mgr->ClearInst(&l_inst);
177 }
178 if (AreAnalysesValid(kAnalysisInstrToBlockMapping)) {
179 instr_to_block_.erase(inst);
180 }
181 if (AreAnalysesValid(kAnalysisDecorations)) {
182 if (inst->IsDecoration()) {
183 decoration_mgr_->RemoveDecoration(inst);
184 }
185 }
186 if (AreAnalysesValid(kAnalysisDebugInfo)) {
187 get_debug_info_mgr()->ClearDebugScopeAndInlinedAtUses(inst);
188 get_debug_info_mgr()->ClearDebugInfo(inst);
189 }
190 if (type_mgr_ && IsTypeInst(inst->opcode())) {
191 type_mgr_->RemoveId(inst->result_id());
192 }
193 if (constant_mgr_ && IsConstantInst(inst->opcode())) {
194 constant_mgr_->RemoveId(inst->result_id());
195 }
196 if (inst->opcode() == SpvOpCapability || inst->opcode() == SpvOpExtension) {
197 // We reset the feature manager, instead of updating it, because it is just
198 // as much work. We would have to remove all capabilities implied by this
199 // capability that are not also implied by the remaining OpCapability
200 // instructions. We could update extensions, but we will see if it is
201 // needed.
202 ResetFeatureManager();
203 }
204
205 RemoveFromIdToName(inst);
206
207 Instruction* next_instruction = nullptr;
208 if (inst->IsInAList()) {
209 next_instruction = inst->NextNode();
210 inst->RemoveFromList();
211 delete inst;
212 } else {
213 // Needed for instructions that are not part of a list like OpLabels,
214 // OpFunction, OpFunctionEnd, etc..
215 inst->ToNop();
216 }
217 return next_instruction;
218 }
219
CollectNonSemanticTree(Instruction * inst,std::unordered_set<Instruction * > * to_kill)220 void IRContext::CollectNonSemanticTree(
221 Instruction* inst, std::unordered_set<Instruction*>* to_kill) {
222 if (!inst->HasResultId()) return;
223 // Debug[No]Line result id is not used, so we are done
224 if (inst->IsDebugLineInst()) return;
225 std::vector<Instruction*> work_list;
226 std::unordered_set<Instruction*> seen;
227 work_list.push_back(inst);
228
229 while (!work_list.empty()) {
230 auto* i = work_list.back();
231 work_list.pop_back();
232 get_def_use_mgr()->ForEachUser(
233 i, [&work_list, to_kill, &seen](Instruction* user) {
234 if (user->IsNonSemanticInstruction() && seen.insert(user).second) {
235 work_list.push_back(user);
236 to_kill->insert(user);
237 }
238 });
239 }
240 }
241
KillDef(uint32_t id)242 bool IRContext::KillDef(uint32_t id) {
243 Instruction* def = get_def_use_mgr()->GetDef(id);
244 if (def != nullptr) {
245 KillInst(def);
246 return true;
247 }
248 return false;
249 }
250
ReplaceAllUsesWith(uint32_t before,uint32_t after)251 bool IRContext::ReplaceAllUsesWith(uint32_t before, uint32_t after) {
252 return ReplaceAllUsesWithPredicate(before, after,
253 [](Instruction*) { return true; });
254 }
255
ReplaceAllUsesWithPredicate(uint32_t before,uint32_t after,const std::function<bool (Instruction *)> & predicate)256 bool IRContext::ReplaceAllUsesWithPredicate(
257 uint32_t before, uint32_t after,
258 const std::function<bool(Instruction*)>& predicate) {
259 if (before == after) return false;
260
261 if (AreAnalysesValid(kAnalysisDebugInfo)) {
262 get_debug_info_mgr()->ReplaceAllUsesInDebugScopeWithPredicate(before, after,
263 predicate);
264 }
265
266 // Ensure that |after| has been registered as def.
267 assert(get_def_use_mgr()->GetDef(after) &&
268 "'after' is not a registered def.");
269
270 std::vector<std::pair<Instruction*, uint32_t>> uses_to_update;
271 get_def_use_mgr()->ForEachUse(
272 before, [&predicate, &uses_to_update](Instruction* user, uint32_t index) {
273 if (predicate(user)) {
274 uses_to_update.emplace_back(user, index);
275 }
276 });
277
278 Instruction* prev = nullptr;
279 for (auto p : uses_to_update) {
280 Instruction* user = p.first;
281 uint32_t index = p.second;
282 if (prev == nullptr || prev != user) {
283 ForgetUses(user);
284 prev = user;
285 }
286 const uint32_t type_result_id_count =
287 (user->result_id() != 0) + (user->type_id() != 0);
288
289 if (index < type_result_id_count) {
290 // Update the type_id. Note that result id is immutable so it should
291 // never be updated.
292 if (user->type_id() != 0 && index == 0) {
293 user->SetResultType(after);
294 } else if (user->type_id() == 0) {
295 SPIRV_ASSERT(consumer_, false,
296 "Result type id considered as use while the instruction "
297 "doesn't have a result type id.");
298 (void)consumer_; // Makes the compiler happy for release build.
299 } else {
300 SPIRV_ASSERT(consumer_, false,
301 "Trying setting the immutable result id.");
302 }
303 } else {
304 // Update an in-operand.
305 uint32_t in_operand_pos = index - type_result_id_count;
306 // Make the modification in the instruction.
307 user->SetInOperand(in_operand_pos, {after});
308 }
309 AnalyzeUses(user);
310 }
311 return true;
312 }
313
IsConsistent()314 bool IRContext::IsConsistent() {
315 #ifndef SPIRV_CHECK_CONTEXT
316 return true;
317 #else
318 if (AreAnalysesValid(kAnalysisDefUse)) {
319 analysis::DefUseManager new_def_use(module());
320 if (*get_def_use_mgr() != new_def_use) {
321 return false;
322 }
323 }
324
325 if (AreAnalysesValid(kAnalysisIdToFuncMapping)) {
326 for (auto& fn : *module_) {
327 if (id_to_func_[fn.result_id()] != &fn) {
328 return false;
329 }
330 }
331 }
332
333 if (AreAnalysesValid(kAnalysisInstrToBlockMapping)) {
334 for (auto& func : *module()) {
335 for (auto& block : func) {
336 if (!block.WhileEachInst([this, &block](Instruction* inst) {
337 if (get_instr_block(inst) != &block) {
338 return false;
339 }
340 return true;
341 }))
342 return false;
343 }
344 }
345 }
346
347 if (!CheckCFG()) {
348 return false;
349 }
350
351 if (AreAnalysesValid(kAnalysisDecorations)) {
352 analysis::DecorationManager* dec_mgr = get_decoration_mgr();
353 analysis::DecorationManager current(module());
354
355 if (*dec_mgr != current) {
356 return false;
357 }
358 }
359
360 if (feature_mgr_ != nullptr) {
361 FeatureManager current(grammar_);
362 current.Analyze(module());
363
364 if (current != *feature_mgr_) {
365 return false;
366 }
367 }
368 return true;
369 #endif
370 }
371
ForgetUses(Instruction * inst)372 void IRContext::ForgetUses(Instruction* inst) {
373 if (AreAnalysesValid(kAnalysisDefUse)) {
374 get_def_use_mgr()->EraseUseRecordsOfOperandIds(inst);
375 }
376 if (AreAnalysesValid(kAnalysisDecorations)) {
377 if (inst->IsDecoration()) {
378 get_decoration_mgr()->RemoveDecoration(inst);
379 }
380 }
381 if (AreAnalysesValid(kAnalysisDebugInfo)) {
382 get_debug_info_mgr()->ClearDebugInfo(inst);
383 }
384 RemoveFromIdToName(inst);
385 }
386
AnalyzeUses(Instruction * inst)387 void IRContext::AnalyzeUses(Instruction* inst) {
388 if (AreAnalysesValid(kAnalysisDefUse)) {
389 get_def_use_mgr()->AnalyzeInstUse(inst);
390 }
391 if (AreAnalysesValid(kAnalysisDecorations)) {
392 if (inst->IsDecoration()) {
393 get_decoration_mgr()->AddDecoration(inst);
394 }
395 }
396 if (AreAnalysesValid(kAnalysisDebugInfo)) {
397 get_debug_info_mgr()->AnalyzeDebugInst(inst);
398 }
399 if (id_to_name_ &&
400 (inst->opcode() == SpvOpName || inst->opcode() == SpvOpMemberName)) {
401 id_to_name_->insert({inst->GetSingleWordInOperand(0), inst});
402 }
403 }
404
KillNamesAndDecorates(uint32_t id)405 void IRContext::KillNamesAndDecorates(uint32_t id) {
406 analysis::DecorationManager* dec_mgr = get_decoration_mgr();
407 dec_mgr->RemoveDecorationsFrom(id);
408
409 std::vector<Instruction*> name_to_kill;
410 for (auto name : GetNames(id)) {
411 name_to_kill.push_back(name.second);
412 }
413 for (Instruction* name_inst : name_to_kill) {
414 KillInst(name_inst);
415 }
416 }
417
KillNamesAndDecorates(Instruction * inst)418 void IRContext::KillNamesAndDecorates(Instruction* inst) {
419 const uint32_t rId = inst->result_id();
420 if (rId == 0) return;
421 KillNamesAndDecorates(rId);
422 }
423
KillOperandFromDebugInstructions(Instruction * inst)424 void IRContext::KillOperandFromDebugInstructions(Instruction* inst) {
425 const auto opcode = inst->opcode();
426 const uint32_t id = inst->result_id();
427 // Kill id of OpFunction from DebugFunction.
428 if (opcode == SpvOpFunction) {
429 for (auto it = module()->ext_inst_debuginfo_begin();
430 it != module()->ext_inst_debuginfo_end(); ++it) {
431 if (it->GetOpenCL100DebugOpcode() != OpenCLDebugInfo100DebugFunction)
432 continue;
433 auto& operand = it->GetOperand(kDebugFunctionOperandFunctionIndex);
434 if (operand.words[0] == id) {
435 operand.words[0] =
436 get_debug_info_mgr()->GetDebugInfoNone()->result_id();
437 get_def_use_mgr()->AnalyzeInstUse(&*it);
438 }
439 }
440 }
441 // Kill id of OpVariable for global variable from DebugGlobalVariable.
442 if (opcode == SpvOpVariable || IsConstantInst(opcode)) {
443 for (auto it = module()->ext_inst_debuginfo_begin();
444 it != module()->ext_inst_debuginfo_end(); ++it) {
445 if (it->GetCommonDebugOpcode() != CommonDebugInfoDebugGlobalVariable)
446 continue;
447 auto& operand = it->GetOperand(kDebugGlobalVariableOperandVariableIndex);
448 if (operand.words[0] == id) {
449 operand.words[0] =
450 get_debug_info_mgr()->GetDebugInfoNone()->result_id();
451 get_def_use_mgr()->AnalyzeInstUse(&*it);
452 }
453 }
454 }
455 }
456
AddCombinatorsForCapability(uint32_t capability)457 void IRContext::AddCombinatorsForCapability(uint32_t capability) {
458 if (capability == SpvCapabilityShader) {
459 combinator_ops_[0].insert({SpvOpNop,
460 SpvOpUndef,
461 SpvOpConstant,
462 SpvOpConstantTrue,
463 SpvOpConstantFalse,
464 SpvOpConstantComposite,
465 SpvOpConstantSampler,
466 SpvOpConstantNull,
467 SpvOpTypeVoid,
468 SpvOpTypeBool,
469 SpvOpTypeInt,
470 SpvOpTypeFloat,
471 SpvOpTypeVector,
472 SpvOpTypeMatrix,
473 SpvOpTypeImage,
474 SpvOpTypeSampler,
475 SpvOpTypeSampledImage,
476 SpvOpTypeAccelerationStructureNV,
477 SpvOpTypeAccelerationStructureKHR,
478 SpvOpTypeRayQueryKHR,
479 SpvOpTypeArray,
480 SpvOpTypeRuntimeArray,
481 SpvOpTypeStruct,
482 SpvOpTypeOpaque,
483 SpvOpTypePointer,
484 SpvOpTypeFunction,
485 SpvOpTypeEvent,
486 SpvOpTypeDeviceEvent,
487 SpvOpTypeReserveId,
488 SpvOpTypeQueue,
489 SpvOpTypePipe,
490 SpvOpTypeForwardPointer,
491 SpvOpVariable,
492 SpvOpImageTexelPointer,
493 SpvOpLoad,
494 SpvOpAccessChain,
495 SpvOpInBoundsAccessChain,
496 SpvOpArrayLength,
497 SpvOpVectorExtractDynamic,
498 SpvOpVectorInsertDynamic,
499 SpvOpVectorShuffle,
500 SpvOpCompositeConstruct,
501 SpvOpCompositeExtract,
502 SpvOpCompositeInsert,
503 SpvOpCopyObject,
504 SpvOpTranspose,
505 SpvOpSampledImage,
506 SpvOpImageSampleImplicitLod,
507 SpvOpImageSampleExplicitLod,
508 SpvOpImageSampleDrefImplicitLod,
509 SpvOpImageSampleDrefExplicitLod,
510 SpvOpImageSampleProjImplicitLod,
511 SpvOpImageSampleProjExplicitLod,
512 SpvOpImageSampleProjDrefImplicitLod,
513 SpvOpImageSampleProjDrefExplicitLod,
514 SpvOpImageFetch,
515 SpvOpImageGather,
516 SpvOpImageDrefGather,
517 SpvOpImageRead,
518 SpvOpImage,
519 SpvOpImageQueryFormat,
520 SpvOpImageQueryOrder,
521 SpvOpImageQuerySizeLod,
522 SpvOpImageQuerySize,
523 SpvOpImageQueryLevels,
524 SpvOpImageQuerySamples,
525 SpvOpConvertFToU,
526 SpvOpConvertFToS,
527 SpvOpConvertSToF,
528 SpvOpConvertUToF,
529 SpvOpUConvert,
530 SpvOpSConvert,
531 SpvOpFConvert,
532 SpvOpQuantizeToF16,
533 SpvOpBitcast,
534 SpvOpSNegate,
535 SpvOpFNegate,
536 SpvOpIAdd,
537 SpvOpFAdd,
538 SpvOpISub,
539 SpvOpFSub,
540 SpvOpIMul,
541 SpvOpFMul,
542 SpvOpUDiv,
543 SpvOpSDiv,
544 SpvOpFDiv,
545 SpvOpUMod,
546 SpvOpSRem,
547 SpvOpSMod,
548 SpvOpFRem,
549 SpvOpFMod,
550 SpvOpVectorTimesScalar,
551 SpvOpMatrixTimesScalar,
552 SpvOpVectorTimesMatrix,
553 SpvOpMatrixTimesVector,
554 SpvOpMatrixTimesMatrix,
555 SpvOpOuterProduct,
556 SpvOpDot,
557 SpvOpIAddCarry,
558 SpvOpISubBorrow,
559 SpvOpUMulExtended,
560 SpvOpSMulExtended,
561 SpvOpAny,
562 SpvOpAll,
563 SpvOpIsNan,
564 SpvOpIsInf,
565 SpvOpLogicalEqual,
566 SpvOpLogicalNotEqual,
567 SpvOpLogicalOr,
568 SpvOpLogicalAnd,
569 SpvOpLogicalNot,
570 SpvOpSelect,
571 SpvOpIEqual,
572 SpvOpINotEqual,
573 SpvOpUGreaterThan,
574 SpvOpSGreaterThan,
575 SpvOpUGreaterThanEqual,
576 SpvOpSGreaterThanEqual,
577 SpvOpULessThan,
578 SpvOpSLessThan,
579 SpvOpULessThanEqual,
580 SpvOpSLessThanEqual,
581 SpvOpFOrdEqual,
582 SpvOpFUnordEqual,
583 SpvOpFOrdNotEqual,
584 SpvOpFUnordNotEqual,
585 SpvOpFOrdLessThan,
586 SpvOpFUnordLessThan,
587 SpvOpFOrdGreaterThan,
588 SpvOpFUnordGreaterThan,
589 SpvOpFOrdLessThanEqual,
590 SpvOpFUnordLessThanEqual,
591 SpvOpFOrdGreaterThanEqual,
592 SpvOpFUnordGreaterThanEqual,
593 SpvOpShiftRightLogical,
594 SpvOpShiftRightArithmetic,
595 SpvOpShiftLeftLogical,
596 SpvOpBitwiseOr,
597 SpvOpBitwiseXor,
598 SpvOpBitwiseAnd,
599 SpvOpNot,
600 SpvOpBitFieldInsert,
601 SpvOpBitFieldSExtract,
602 SpvOpBitFieldUExtract,
603 SpvOpBitReverse,
604 SpvOpBitCount,
605 SpvOpPhi,
606 SpvOpImageSparseSampleImplicitLod,
607 SpvOpImageSparseSampleExplicitLod,
608 SpvOpImageSparseSampleDrefImplicitLod,
609 SpvOpImageSparseSampleDrefExplicitLod,
610 SpvOpImageSparseSampleProjImplicitLod,
611 SpvOpImageSparseSampleProjExplicitLod,
612 SpvOpImageSparseSampleProjDrefImplicitLod,
613 SpvOpImageSparseSampleProjDrefExplicitLod,
614 SpvOpImageSparseFetch,
615 SpvOpImageSparseGather,
616 SpvOpImageSparseDrefGather,
617 SpvOpImageSparseTexelsResident,
618 SpvOpImageSparseRead,
619 SpvOpSizeOf});
620 }
621 }
622
AddCombinatorsForExtension(Instruction * extension)623 void IRContext::AddCombinatorsForExtension(Instruction* extension) {
624 assert(extension->opcode() == SpvOpExtInstImport &&
625 "Expecting an import of an extension's instruction set.");
626 const char* extension_name =
627 reinterpret_cast<const char*>(&extension->GetInOperand(0).words[0]);
628 if (!strcmp(extension_name, "GLSL.std.450")) {
629 combinator_ops_[extension->result_id()] = {GLSLstd450Round,
630 GLSLstd450RoundEven,
631 GLSLstd450Trunc,
632 GLSLstd450FAbs,
633 GLSLstd450SAbs,
634 GLSLstd450FSign,
635 GLSLstd450SSign,
636 GLSLstd450Floor,
637 GLSLstd450Ceil,
638 GLSLstd450Fract,
639 GLSLstd450Radians,
640 GLSLstd450Degrees,
641 GLSLstd450Sin,
642 GLSLstd450Cos,
643 GLSLstd450Tan,
644 GLSLstd450Asin,
645 GLSLstd450Acos,
646 GLSLstd450Atan,
647 GLSLstd450Sinh,
648 GLSLstd450Cosh,
649 GLSLstd450Tanh,
650 GLSLstd450Asinh,
651 GLSLstd450Acosh,
652 GLSLstd450Atanh,
653 GLSLstd450Atan2,
654 GLSLstd450Pow,
655 GLSLstd450Exp,
656 GLSLstd450Log,
657 GLSLstd450Exp2,
658 GLSLstd450Log2,
659 GLSLstd450Sqrt,
660 GLSLstd450InverseSqrt,
661 GLSLstd450Determinant,
662 GLSLstd450MatrixInverse,
663 GLSLstd450ModfStruct,
664 GLSLstd450FMin,
665 GLSLstd450UMin,
666 GLSLstd450SMin,
667 GLSLstd450FMax,
668 GLSLstd450UMax,
669 GLSLstd450SMax,
670 GLSLstd450FClamp,
671 GLSLstd450UClamp,
672 GLSLstd450SClamp,
673 GLSLstd450FMix,
674 GLSLstd450IMix,
675 GLSLstd450Step,
676 GLSLstd450SmoothStep,
677 GLSLstd450Fma,
678 GLSLstd450FrexpStruct,
679 GLSLstd450Ldexp,
680 GLSLstd450PackSnorm4x8,
681 GLSLstd450PackUnorm4x8,
682 GLSLstd450PackSnorm2x16,
683 GLSLstd450PackUnorm2x16,
684 GLSLstd450PackHalf2x16,
685 GLSLstd450PackDouble2x32,
686 GLSLstd450UnpackSnorm2x16,
687 GLSLstd450UnpackUnorm2x16,
688 GLSLstd450UnpackHalf2x16,
689 GLSLstd450UnpackSnorm4x8,
690 GLSLstd450UnpackUnorm4x8,
691 GLSLstd450UnpackDouble2x32,
692 GLSLstd450Length,
693 GLSLstd450Distance,
694 GLSLstd450Cross,
695 GLSLstd450Normalize,
696 GLSLstd450FaceForward,
697 GLSLstd450Reflect,
698 GLSLstd450Refract,
699 GLSLstd450FindILsb,
700 GLSLstd450FindSMsb,
701 GLSLstd450FindUMsb,
702 GLSLstd450InterpolateAtCentroid,
703 GLSLstd450InterpolateAtSample,
704 GLSLstd450InterpolateAtOffset,
705 GLSLstd450NMin,
706 GLSLstd450NMax,
707 GLSLstd450NClamp};
708 } else {
709 // Map the result id to the empty set.
710 combinator_ops_[extension->result_id()];
711 }
712 }
713
InitializeCombinators()714 void IRContext::InitializeCombinators() {
715 get_feature_mgr()->GetCapabilities()->ForEach(
716 [this](SpvCapability cap) { AddCombinatorsForCapability(cap); });
717
718 for (auto& extension : module()->ext_inst_imports()) {
719 AddCombinatorsForExtension(&extension);
720 }
721
722 valid_analyses_ |= kAnalysisCombinators;
723 }
724
RemoveFromIdToName(const Instruction * inst)725 void IRContext::RemoveFromIdToName(const Instruction* inst) {
726 if (id_to_name_ &&
727 (inst->opcode() == SpvOpName || inst->opcode() == SpvOpMemberName)) {
728 auto range = id_to_name_->equal_range(inst->GetSingleWordInOperand(0));
729 for (auto it = range.first; it != range.second; ++it) {
730 if (it->second == inst) {
731 id_to_name_->erase(it);
732 break;
733 }
734 }
735 }
736 }
737
GetLoopDescriptor(const Function * f)738 LoopDescriptor* IRContext::GetLoopDescriptor(const Function* f) {
739 if (!AreAnalysesValid(kAnalysisLoopAnalysis)) {
740 ResetLoopAnalysis();
741 }
742
743 std::unordered_map<const Function*, LoopDescriptor>::iterator it =
744 loop_descriptors_.find(f);
745 if (it == loop_descriptors_.end()) {
746 return &loop_descriptors_
747 .emplace(std::make_pair(f, LoopDescriptor(this, f)))
748 .first->second;
749 }
750
751 return &it->second;
752 }
753
FindBuiltinInputVar(uint32_t builtin)754 uint32_t IRContext::FindBuiltinInputVar(uint32_t builtin) {
755 for (auto& a : module_->annotations()) {
756 if (a.opcode() != SpvOpDecorate) continue;
757 if (a.GetSingleWordInOperand(kSpvDecorateDecorationInIdx) !=
758 SpvDecorationBuiltIn)
759 continue;
760 if (a.GetSingleWordInOperand(kSpvDecorateBuiltinInIdx) != builtin) continue;
761 uint32_t target_id = a.GetSingleWordInOperand(kSpvDecorateTargetIdInIdx);
762 Instruction* b_var = get_def_use_mgr()->GetDef(target_id);
763 if (b_var->opcode() != SpvOpVariable) continue;
764 if (b_var->GetSingleWordInOperand(0) != SpvStorageClassInput) continue;
765 return target_id;
766 }
767 return 0;
768 }
769
AddVarToEntryPoints(uint32_t var_id)770 void IRContext::AddVarToEntryPoints(uint32_t var_id) {
771 uint32_t ocnt = 0;
772 for (auto& e : module()->entry_points()) {
773 bool found = false;
774 e.ForEachInOperand([&ocnt, &found, &var_id](const uint32_t* idp) {
775 if (ocnt >= kEntryPointInterfaceInIdx) {
776 if (*idp == var_id) found = true;
777 }
778 ++ocnt;
779 });
780 if (!found) {
781 e.AddOperand({SPV_OPERAND_TYPE_ID, {var_id}});
782 get_def_use_mgr()->AnalyzeInstDefUse(&e);
783 }
784 }
785 }
786
GetBuiltinInputVarId(uint32_t builtin)787 uint32_t IRContext::GetBuiltinInputVarId(uint32_t builtin) {
788 if (!AreAnalysesValid(kAnalysisBuiltinVarId)) ResetBuiltinAnalysis();
789 // If cached, return it.
790 std::unordered_map<uint32_t, uint32_t>::iterator it =
791 builtin_var_id_map_.find(builtin);
792 if (it != builtin_var_id_map_.end()) return it->second;
793 // Look for one in shader
794 uint32_t var_id = FindBuiltinInputVar(builtin);
795 if (var_id == 0) {
796 // If not found, create it
797 // TODO(greg-lunarg): Add support for all builtins
798 analysis::TypeManager* type_mgr = get_type_mgr();
799 analysis::Type* reg_type;
800 switch (builtin) {
801 case SpvBuiltInFragCoord: {
802 analysis::Float float_ty(32);
803 analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty);
804 analysis::Vector v4float_ty(reg_float_ty, 4);
805 reg_type = type_mgr->GetRegisteredType(&v4float_ty);
806 break;
807 }
808 case SpvBuiltInVertexIndex:
809 case SpvBuiltInInstanceIndex:
810 case SpvBuiltInPrimitiveId:
811 case SpvBuiltInInvocationId:
812 case SpvBuiltInSubgroupLocalInvocationId: {
813 analysis::Integer uint_ty(32, false);
814 reg_type = type_mgr->GetRegisteredType(&uint_ty);
815 break;
816 }
817 case SpvBuiltInGlobalInvocationId:
818 case SpvBuiltInLaunchIdNV: {
819 analysis::Integer uint_ty(32, false);
820 analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
821 analysis::Vector v3uint_ty(reg_uint_ty, 3);
822 reg_type = type_mgr->GetRegisteredType(&v3uint_ty);
823 break;
824 }
825 case SpvBuiltInTessCoord: {
826 analysis::Float float_ty(32);
827 analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty);
828 analysis::Vector v3float_ty(reg_float_ty, 3);
829 reg_type = type_mgr->GetRegisteredType(&v3float_ty);
830 break;
831 }
832 case SpvBuiltInSubgroupLtMask: {
833 analysis::Integer uint_ty(32, false);
834 analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
835 analysis::Vector v4uint_ty(reg_uint_ty, 4);
836 reg_type = type_mgr->GetRegisteredType(&v4uint_ty);
837 break;
838 }
839 default: {
840 assert(false && "unhandled builtin");
841 return 0;
842 }
843 }
844 uint32_t type_id = type_mgr->GetTypeInstruction(reg_type);
845 uint32_t varTyPtrId =
846 type_mgr->FindPointerToType(type_id, SpvStorageClassInput);
847 // TODO(1841): Handle id overflow.
848 var_id = TakeNextId();
849 std::unique_ptr<Instruction> newVarOp(
850 new Instruction(this, SpvOpVariable, varTyPtrId, var_id,
851 {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
852 {SpvStorageClassInput}}}));
853 get_def_use_mgr()->AnalyzeInstDefUse(&*newVarOp);
854 module()->AddGlobalValue(std::move(newVarOp));
855 get_decoration_mgr()->AddDecorationVal(var_id, SpvDecorationBuiltIn,
856 builtin);
857 AddVarToEntryPoints(var_id);
858 }
859 builtin_var_id_map_[builtin] = var_id;
860 return var_id;
861 }
862
AddCalls(const Function * func,std::queue<uint32_t> * todo)863 void IRContext::AddCalls(const Function* func, std::queue<uint32_t>* todo) {
864 for (auto bi = func->begin(); bi != func->end(); ++bi)
865 for (auto ii = bi->begin(); ii != bi->end(); ++ii)
866 if (ii->opcode() == SpvOpFunctionCall)
867 todo->push(ii->GetSingleWordInOperand(0));
868 }
869
ProcessEntryPointCallTree(ProcessFunction & pfn)870 bool IRContext::ProcessEntryPointCallTree(ProcessFunction& pfn) {
871 // Collect all of the entry points as the roots.
872 std::queue<uint32_t> roots;
873 for (auto& e : module()->entry_points()) {
874 roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx));
875 }
876 return ProcessCallTreeFromRoots(pfn, &roots);
877 }
878
ProcessReachableCallTree(ProcessFunction & pfn)879 bool IRContext::ProcessReachableCallTree(ProcessFunction& pfn) {
880 std::queue<uint32_t> roots;
881
882 // Add all entry points since they can be reached from outside the module.
883 for (auto& e : module()->entry_points())
884 roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx));
885
886 // Add all exported functions since they can be reached from outside the
887 // module.
888 for (auto& a : annotations()) {
889 // TODO: Handle group decorations as well. Currently not generate by any
890 // front-end, but could be coming.
891 if (a.opcode() == SpvOp::SpvOpDecorate) {
892 if (a.GetSingleWordOperand(1) ==
893 SpvDecoration::SpvDecorationLinkageAttributes) {
894 uint32_t lastOperand = a.NumOperands() - 1;
895 if (a.GetSingleWordOperand(lastOperand) ==
896 SpvLinkageType::SpvLinkageTypeExport) {
897 uint32_t id = a.GetSingleWordOperand(0);
898 if (GetFunction(id)) {
899 roots.push(id);
900 }
901 }
902 }
903 }
904 }
905
906 return ProcessCallTreeFromRoots(pfn, &roots);
907 }
908
ProcessCallTreeFromRoots(ProcessFunction & pfn,std::queue<uint32_t> * roots)909 bool IRContext::ProcessCallTreeFromRoots(ProcessFunction& pfn,
910 std::queue<uint32_t>* roots) {
911 // Process call tree
912 bool modified = false;
913 std::unordered_set<uint32_t> done;
914
915 while (!roots->empty()) {
916 const uint32_t fi = roots->front();
917 roots->pop();
918 if (done.insert(fi).second) {
919 Function* fn = GetFunction(fi);
920 assert(fn && "Trying to process a function that does not exist.");
921 modified = pfn(fn) || modified;
922 AddCalls(fn, roots);
923 }
924 }
925 return modified;
926 }
927
EmitErrorMessage(std::string message,Instruction * inst)928 void IRContext::EmitErrorMessage(std::string message, Instruction* inst) {
929 if (!consumer()) {
930 return;
931 }
932
933 Instruction* line_inst = inst;
934 while (line_inst != nullptr) { // Stop at the beginning of the basic block.
935 if (!line_inst->dbg_line_insts().empty()) {
936 line_inst = &line_inst->dbg_line_insts().back();
937 if (line_inst->IsNoLine()) {
938 line_inst = nullptr;
939 }
940 break;
941 }
942 line_inst = line_inst->PreviousNode();
943 }
944
945 uint32_t line_number = 0;
946 uint32_t col_number = 0;
947 char* source = nullptr;
948 if (line_inst != nullptr) {
949 Instruction* file_name =
950 get_def_use_mgr()->GetDef(line_inst->GetSingleWordInOperand(0));
951 source = reinterpret_cast<char*>(&file_name->GetInOperand(0).words[0]);
952
953 // Get the line number and column number.
954 line_number = line_inst->GetSingleWordInOperand(1);
955 col_number = line_inst->GetSingleWordInOperand(2);
956 }
957
958 message +=
959 "\n " + inst->PrettyPrint(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
960 consumer()(SPV_MSG_ERROR, source, {line_number, col_number, 0},
961 message.c_str());
962 }
963
964 // Gets the dominator analysis for function |f|.
GetDominatorAnalysis(const Function * f)965 DominatorAnalysis* IRContext::GetDominatorAnalysis(const Function* f) {
966 if (!AreAnalysesValid(kAnalysisDominatorAnalysis)) {
967 ResetDominatorAnalysis();
968 }
969
970 if (dominator_trees_.find(f) == dominator_trees_.end()) {
971 dominator_trees_[f].InitializeTree(*cfg(), f);
972 }
973
974 return &dominator_trees_[f];
975 }
976
977 // Gets the postdominator analysis for function |f|.
GetPostDominatorAnalysis(const Function * f)978 PostDominatorAnalysis* IRContext::GetPostDominatorAnalysis(const Function* f) {
979 if (!AreAnalysesValid(kAnalysisDominatorAnalysis)) {
980 ResetDominatorAnalysis();
981 }
982
983 if (post_dominator_trees_.find(f) == post_dominator_trees_.end()) {
984 post_dominator_trees_[f].InitializeTree(*cfg(), f);
985 }
986
987 return &post_dominator_trees_[f];
988 }
989
CheckCFG()990 bool IRContext::CheckCFG() {
991 std::unordered_map<uint32_t, std::vector<uint32_t>> real_preds;
992 if (!AreAnalysesValid(kAnalysisCFG)) {
993 return true;
994 }
995
996 for (Function& function : *module()) {
997 for (const auto& bb : function) {
998 bb.ForEachSuccessorLabel([&bb, &real_preds](const uint32_t lab_id) {
999 real_preds[lab_id].push_back(bb.id());
1000 });
1001 }
1002
1003 for (auto& bb : function) {
1004 std::vector<uint32_t> preds = cfg()->preds(bb.id());
1005 std::vector<uint32_t> real = real_preds[bb.id()];
1006 std::sort(preds.begin(), preds.end());
1007 std::sort(real.begin(), real.end());
1008
1009 bool same = true;
1010 if (preds.size() != real.size()) {
1011 same = false;
1012 }
1013
1014 for (size_t i = 0; i < real.size() && same; i++) {
1015 if (preds[i] != real[i]) {
1016 same = false;
1017 }
1018 }
1019
1020 if (!same) {
1021 std::cerr << "Predecessors for " << bb.id() << " are different:\n";
1022
1023 std::cerr << "Real:";
1024 for (uint32_t i : real) {
1025 std::cerr << ' ' << i;
1026 }
1027 std::cerr << std::endl;
1028
1029 std::cerr << "Recorded:";
1030 for (uint32_t i : preds) {
1031 std::cerr << ' ' << i;
1032 }
1033 std::cerr << std::endl;
1034 }
1035 if (!same) return false;
1036 }
1037 }
1038
1039 return true;
1040 }
1041
IsReachable(const opt::BasicBlock & bb)1042 bool IRContext::IsReachable(const opt::BasicBlock& bb) {
1043 auto enclosing_function = bb.GetParent();
1044 return GetDominatorAnalysis(enclosing_function)
1045 ->Dominates(enclosing_function->entry().get(), &bb);
1046 }
1047 } // namespace opt
1048 } // namespace spvtools
1049