@@ -28,6 +28,9 @@ constexpr uint32_t kStoreObjectInOperand = 1;
28
28
constexpr uint32_t kCompositeExtractObjectInOperand = 0 ;
29
29
constexpr uint32_t kTypePointerStorageClassInIdx = 0 ;
30
30
constexpr uint32_t kTypePointerPointeeInIdx = 1 ;
31
+ constexpr uint32_t kExtInstSetInIdx = 0 ;
32
+ constexpr uint32_t kExtInstOpInIdx = 1 ;
33
+ constexpr uint32_t kInterpolantInIdx = 2 ;
31
34
32
35
bool IsDebugDeclareOrValue (Instruction* di) {
33
36
auto dbg_opcode = di->GetCommonDebugOpcode ();
@@ -74,28 +77,38 @@ Pass::Status CopyPropagateArrays::Process() {
74
77
75
78
for (auto var_inst = entry_bb->begin ();
76
79
var_inst->opcode () == spv::Op::OpVariable; ++var_inst) {
77
- if (!IsPointerToArrayType (var_inst->type_id ())) {
78
- continue ;
79
- }
80
+ worklist_.push (&*var_inst);
81
+ }
82
+ }
83
+
84
+ while (!worklist_.empty ()) {
85
+ Instruction* var_inst = worklist_.front ();
86
+ worklist_.pop ();
80
87
81
- // Find the only store to the entire memory location, if it exists.
82
- Instruction* store_inst = FindStoreInstruction (&*var_inst);
88
+ // Find the only store to the entire memory location, if it exists.
89
+ Instruction* store_inst = FindStoreInstruction (&*var_inst);
83
90
84
- if (!store_inst) {
91
+ if (!store_inst) {
92
+ continue ;
93
+ }
94
+
95
+ std::unique_ptr<MemoryObject> source_object =
96
+ FindSourceObjectIfPossible (&*var_inst, store_inst);
97
+
98
+ if (source_object != nullptr ) {
99
+ if (!IsPointerToArrayType (var_inst->type_id ()) &&
100
+ source_object->GetStorageClass () != spv::StorageClass::Input) {
85
101
continue ;
86
102
}
87
103
88
- std::unique_ptr<MemoryObject> source_object =
89
- FindSourceObjectIfPossible (&*var_inst, store_inst) ;
104
+ if ( CanUpdateUses (&*var_inst, source_object-> GetPointerTypeId ( this ))) {
105
+ modified = true ;
90
106
91
- if (source_object != nullptr ) {
92
- if (CanUpdateUses (&*var_inst, source_object->GetPointerTypeId (this ))) {
93
- modified = true ;
94
- PropagateObject (&*var_inst, source_object.get (), store_inst);
95
- }
107
+ PropagateObject (&*var_inst, source_object.get (), store_inst);
96
108
}
97
109
}
98
110
}
111
+
99
112
return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange);
100
113
}
101
114
@@ -204,6 +217,8 @@ bool CopyPropagateArrays::HasNoStores(Instruction* ptr_inst) {
204
217
return true ;
205
218
} else if (use->opcode () == spv::Op::OpEntryPoint) {
206
219
return true ;
220
+ } else if (IsInterpolationInstruction (use)) {
221
+ return true ;
207
222
}
208
223
// Some other instruction. Be conservative.
209
224
return false ;
@@ -225,6 +240,13 @@ bool CopyPropagateArrays::HasValidReferencesOnly(Instruction* ptr_inst,
225
240
// time to do the multiple traverses can add up. Consider collecting
226
241
// those loads and doing a single traversal.
227
242
return dominator_analysis->Dominates (store_inst, use);
243
+ } else if (IsInterpolationInstruction (use)) {
244
+ // GLSL InterpolateAt* instructions work similarly to loads
245
+ uint32_t interpolant = use->GetSingleWordInOperand (kInterpolantInIdx );
246
+ if (interpolant !=
247
+ store_inst->GetSingleWordInOperand (kStorePointerInOperand ))
248
+ return false ;
249
+ return dominator_analysis->Dominates (store_inst, use);
228
250
} else if (use->opcode () == spv::Op::OpAccessChain) {
229
251
return HasValidReferencesOnly (use, store_inst);
230
252
} else if (use->IsDecoration () || use->opcode () == spv::Op::OpName) {
@@ -489,6 +511,21 @@ bool CopyPropagateArrays::IsPointerToArrayType(uint32_t type_id) {
489
511
return false ;
490
512
}
491
513
514
+ bool CopyPropagateArrays::IsInterpolationInstruction (Instruction* inst) {
515
+ if (inst->opcode () == spv::Op::OpExtInst &&
516
+ inst->GetSingleWordInOperand (kExtInstSetInIdx ) ==
517
+ context ()->get_feature_mgr ()->GetExtInstImportId_GLSLstd450 ()) {
518
+ uint32_t ext_inst = inst->GetSingleWordInOperand (kExtInstOpInIdx );
519
+ switch (ext_inst) {
520
+ case GLSLstd450InterpolateAtCentroid:
521
+ case GLSLstd450InterpolateAtOffset:
522
+ case GLSLstd450InterpolateAtSample:
523
+ return true ;
524
+ }
525
+ }
526
+ return false ;
527
+ }
528
+
492
529
bool CopyPropagateArrays::CanUpdateUses (Instruction* original_ptr_inst,
493
530
uint32_t type_id) {
494
531
analysis::TypeManager* type_mgr = context ()->get_type_mgr ();
@@ -522,6 +559,11 @@ bool CopyPropagateArrays::CanUpdateUses(Instruction* original_ptr_inst,
522
559
}
523
560
return true ;
524
561
}
562
+ case spv::Op::OpExtInst:
563
+ if (IsInterpolationInstruction (use)) {
564
+ return true ;
565
+ }
566
+ return false ;
525
567
case spv::Op::OpAccessChain: {
526
568
analysis::Pointer* pointer_type = type->AsPointer ();
527
569
const analysis::Type* pointee_type = pointer_type->pointee_type ();
@@ -670,6 +712,18 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst,
670
712
} else {
671
713
context ()->AnalyzeUses (use);
672
714
}
715
+
716
+ AddUsesToWorklist (use);
717
+ } break ;
718
+ case spv::Op::OpExtInst: {
719
+ if (IsInterpolationInstruction (use)) {
720
+ // Replace the actual use.
721
+ context ()->ForgetUses (use);
722
+ use->SetOperand (index, {new_ptr_inst->result_id ()});
723
+ context ()->AnalyzeUses (use);
724
+ } else {
725
+ assert (false && " Don't know how to rewrite instruction" );
726
+ }
673
727
} break ;
674
728
case spv::Op::OpAccessChain: {
675
729
// Update the actual use.
@@ -799,6 +853,19 @@ uint32_t CopyPropagateArrays::GetMemberTypeId(
799
853
return id;
800
854
}
801
855
856
+ void CopyPropagateArrays::AddUsesToWorklist (Instruction* inst) {
857
+ analysis::DefUseManager* def_use_mgr = context ()->get_def_use_mgr ();
858
+
859
+ def_use_mgr->ForEachUse (
860
+ inst, [this , def_use_mgr](Instruction* use, uint32_t ) {
861
+ if (use->opcode () == spv::Op::OpStore) {
862
+ Instruction* target_pointer = def_use_mgr->GetDef (
863
+ use->GetSingleWordInOperand (kStorePointerInOperand ));
864
+ worklist_.push (target_pointer);
865
+ }
866
+ });
867
+ }
868
+
802
869
void CopyPropagateArrays::MemoryObject::PushIndirection (
803
870
const std::vector<AccessChainEntry>& access_chain) {
804
871
access_chain_.insert (access_chain_.end (), access_chain.begin (),
0 commit comments