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