Skip to content

Commit 48f9f4a

Browse files
opt: Update copy prop arrays to handle InterpolateAt* instructions (#5827)
Adds support for `InterpolateAtCentroid`, `InterpolateAtSample`, and `InterpolateAtOffset` to the copy propagate arrays pass, as well as propagating pointers with the `Input` storage class. Also handles situations where variables should be propagated in an order different than the order that they are declared in the source.
1 parent d9c1aee commit 48f9f4a

File tree

3 files changed

+213
-13
lines changed

3 files changed

+213
-13
lines changed

source/opt/copy_prop_arrays.cpp

Lines changed: 80 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ constexpr uint32_t kStoreObjectInOperand = 1;
2828
constexpr uint32_t kCompositeExtractObjectInOperand = 0;
2929
constexpr uint32_t kTypePointerStorageClassInIdx = 0;
3030
constexpr uint32_t kTypePointerPointeeInIdx = 1;
31+
constexpr uint32_t kExtInstSetInIdx = 0;
32+
constexpr uint32_t kExtInstOpInIdx = 1;
33+
constexpr uint32_t kInterpolantInIdx = 2;
3134

3235
bool IsDebugDeclareOrValue(Instruction* di) {
3336
auto dbg_opcode = di->GetCommonDebugOpcode();
@@ -74,28 +77,38 @@ Pass::Status CopyPropagateArrays::Process() {
7477

7578
for (auto var_inst = entry_bb->begin();
7679
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();
8087

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);
8390

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) {
85101
continue;
86102
}
87103

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;
90106

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);
96108
}
97109
}
98110
}
111+
99112
return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange);
100113
}
101114

@@ -204,6 +217,8 @@ bool CopyPropagateArrays::HasNoStores(Instruction* ptr_inst) {
204217
return true;
205218
} else if (use->opcode() == spv::Op::OpEntryPoint) {
206219
return true;
220+
} else if (IsInterpolationInstruction(use)) {
221+
return true;
207222
}
208223
// Some other instruction. Be conservative.
209224
return false;
@@ -225,6 +240,13 @@ bool CopyPropagateArrays::HasValidReferencesOnly(Instruction* ptr_inst,
225240
// time to do the multiple traverses can add up. Consider collecting
226241
// those loads and doing a single traversal.
227242
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);
228250
} else if (use->opcode() == spv::Op::OpAccessChain) {
229251
return HasValidReferencesOnly(use, store_inst);
230252
} else if (use->IsDecoration() || use->opcode() == spv::Op::OpName) {
@@ -489,6 +511,21 @@ bool CopyPropagateArrays::IsPointerToArrayType(uint32_t type_id) {
489511
return false;
490512
}
491513

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+
492529
bool CopyPropagateArrays::CanUpdateUses(Instruction* original_ptr_inst,
493530
uint32_t type_id) {
494531
analysis::TypeManager* type_mgr = context()->get_type_mgr();
@@ -522,6 +559,11 @@ bool CopyPropagateArrays::CanUpdateUses(Instruction* original_ptr_inst,
522559
}
523560
return true;
524561
}
562+
case spv::Op::OpExtInst:
563+
if (IsInterpolationInstruction(use)) {
564+
return true;
565+
}
566+
return false;
525567
case spv::Op::OpAccessChain: {
526568
analysis::Pointer* pointer_type = type->AsPointer();
527569
const analysis::Type* pointee_type = pointer_type->pointee_type();
@@ -670,6 +712,18 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst,
670712
} else {
671713
context()->AnalyzeUses(use);
672714
}
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+
}
673727
} break;
674728
case spv::Op::OpAccessChain: {
675729
// Update the actual use.
@@ -799,6 +853,19 @@ uint32_t CopyPropagateArrays::GetMemberTypeId(
799853
return id;
800854
}
801855

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+
802869
void CopyPropagateArrays::MemoryObject::PushIndirection(
803870
const std::vector<AccessChainEntry>& access_chain) {
804871
access_chain_.insert(access_chain_.end(), access_chain.begin(),

source/opt/copy_prop_arrays.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,10 @@ class CopyPropagateArrays : public MemPass {
222222
// Return true if |type_id| is a pointer type whose pointee type is an array.
223223
bool IsPointerToArrayType(uint32_t type_id);
224224

225+
// Return true if |inst| is one of the InterpolateAt* GLSL.std.450 extended
226+
// instructions.
227+
bool IsInterpolationInstruction(Instruction* inst);
228+
225229
// Returns true if there are not stores using |ptr_inst| or something derived
226230
// from it.
227231
bool HasNoStores(Instruction* ptr_inst);
@@ -254,6 +258,14 @@ class CopyPropagateArrays : public MemPass {
254258
// same way the indexes are used in an |OpCompositeExtract| instruction.
255259
uint32_t GetMemberTypeId(uint32_t id,
256260
const std::vector<uint32_t>& access_chain) const;
261+
262+
// If the result of inst is stored to a variable, add that variable to the
263+
// worklist.
264+
void AddUsesToWorklist(Instruction* inst);
265+
266+
// OpVariable worklist. An instruction is added to this list if we would like
267+
// to run copy propagation on it.
268+
std::queue<Instruction*> worklist_;
257269
};
258270

259271
} // namespace opt

test/opt/copy_prop_array_test.cpp

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1977,6 +1977,127 @@ OpFunctionEnd
19771977

19781978
SinglePassRunAndCheck<CopyPropagateArrays>(text, text, false);
19791979
}
1980+
1981+
TEST_F(CopyPropArrayPassTest, InterpolateFunctions) {
1982+
const std::string before = R"(OpCapability InterpolationFunction
1983+
OpCapability Shader
1984+
%1 = OpExtInstImport "GLSL.std.450"
1985+
OpMemoryModel Logical GLSL450
1986+
OpEntryPoint Fragment %main "main" %in_var_COLOR
1987+
OpExecutionMode %main OriginUpperLeft
1988+
OpSource HLSL 680
1989+
OpName %in_var_COLOR "in.var.COLOR"
1990+
OpName %main "main"
1991+
OpName %offset "offset"
1992+
OpDecorate %in_var_COLOR Location 0
1993+
%int = OpTypeInt 32 1
1994+
%int_0 = OpConstant %int 0
1995+
%float = OpTypeFloat 32
1996+
%float_0 = OpConstant %float 0
1997+
%v2float = OpTypeVector %float 2
1998+
%v4float = OpTypeVector %float 4
1999+
%_ptr_Input_v4float = OpTypePointer Input %v4float
2000+
%void = OpTypeVoid
2001+
%19 = OpTypeFunction %void
2002+
%_ptr_Function_v4float = OpTypePointer Function %v4float
2003+
%in_var_COLOR = OpVariable %_ptr_Input_v4float Input
2004+
%main = OpFunction %void None %19
2005+
%20 = OpLabel
2006+
%45 = OpVariable %_ptr_Function_v4float Function
2007+
%25 = OpLoad %v4float %in_var_COLOR
2008+
OpStore %45 %25
2009+
; CHECK: OpExtInst %v4float %1 InterpolateAtCentroid %in_var_COLOR
2010+
%52 = OpExtInst %v4float %1 InterpolateAtCentroid %45
2011+
; CHECK: OpExtInst %v4float %1 InterpolateAtSample %in_var_COLOR %int_0
2012+
%54 = OpExtInst %v4float %1 InterpolateAtSample %45 %int_0
2013+
%offset = OpCompositeConstruct %v2float %float_0 %float_0
2014+
; CHECK: OpExtInst %v4float %1 InterpolateAtOffset %in_var_COLOR %offset
2015+
%56 = OpExtInst %v4float %1 InterpolateAtOffset %45 %offset
2016+
OpReturn
2017+
OpFunctionEnd
2018+
)";
2019+
2020+
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2021+
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
2022+
SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
2023+
SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
2024+
}
2025+
2026+
TEST_F(CopyPropArrayPassTest, InterpolateMultiPropagation) {
2027+
const std::string before = R"(OpCapability InterpolationFunction
2028+
OpCapability Shader
2029+
%1 = OpExtInstImport "GLSL.std.450"
2030+
OpMemoryModel Logical GLSL450
2031+
OpEntryPoint Fragment %main "main" %in_var_COLOR
2032+
OpExecutionMode %main OriginUpperLeft
2033+
OpSource HLSL 680
2034+
OpName %in_var_COLOR "in.var.COLOR"
2035+
OpName %main "main"
2036+
OpName %param_var_color "param.var.color"
2037+
OpDecorate %in_var_COLOR Location 0
2038+
%float = OpTypeFloat 32
2039+
%v4float = OpTypeVector %float 4
2040+
%_ptr_Input_v4float = OpTypePointer Input %v4float
2041+
%void = OpTypeVoid
2042+
%19 = OpTypeFunction %void
2043+
%_ptr_Function_v4float = OpTypePointer Function %v4float
2044+
%in_var_COLOR = OpVariable %_ptr_Input_v4float Input
2045+
%main = OpFunction %void None %19
2046+
%20 = OpLabel
2047+
%45 = OpVariable %_ptr_Function_v4float Function
2048+
%param_var_color = OpVariable %_ptr_Function_v4float Function
2049+
%25 = OpLoad %v4float %in_var_COLOR
2050+
OpStore %param_var_color %25
2051+
; CHECK: OpExtInst %v4float %1 InterpolateAtCentroid %in_var_COLOR
2052+
%52 = OpExtInst %v4float %1 InterpolateAtCentroid %param_var_color
2053+
%49 = OpLoad %v4float %param_var_color
2054+
OpStore %45 %49
2055+
; CHECK: OpExtInst %v4float %1 InterpolateAtCentroid %in_var_COLOR
2056+
%54 = OpExtInst %v4float %1 InterpolateAtCentroid %45
2057+
OpReturn
2058+
OpFunctionEnd
2059+
)";
2060+
2061+
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2062+
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
2063+
SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
2064+
SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
2065+
}
2066+
2067+
TEST_F(CopyPropArrayPassTest, PropagateScalar) {
2068+
const std::string before = R"(OpCapability InterpolationFunction
2069+
OpCapability Shader
2070+
%1 = OpExtInstImport "GLSL.std.450"
2071+
OpMemoryModel Logical GLSL450
2072+
OpEntryPoint Fragment %main "main" %in_var_SV_InstanceID
2073+
OpExecutionMode %main OriginUpperLeft
2074+
OpSource HLSL 680
2075+
OpName %in_var_SV_InstanceID "in.var.SV_InstanceID"
2076+
OpName %main "main"
2077+
OpDecorate %in_var_SV_InstanceID Location 0
2078+
%float = OpTypeFloat 32
2079+
%v4float = OpTypeVector %float 4
2080+
%_ptr_Input_float = OpTypePointer Input %float
2081+
%void = OpTypeVoid
2082+
%19 = OpTypeFunction %void
2083+
%_ptr_Function_float = OpTypePointer Function %float
2084+
%in_var_SV_InstanceID = OpVariable %_ptr_Input_float Input
2085+
%main = OpFunction %void None %19
2086+
%20 = OpLabel
2087+
%45 = OpVariable %_ptr_Function_float Function
2088+
%25 = OpLoad %v4float %in_var_SV_InstanceID
2089+
OpStore %45 %25
2090+
; CHECK: OpExtInst %v4float %1 InterpolateAtCentroid %in_var_SV_InstanceID
2091+
%52 = OpExtInst %v4float %1 InterpolateAtCentroid %45
2092+
OpReturn
2093+
OpFunctionEnd
2094+
)";
2095+
2096+
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2097+
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
2098+
SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
2099+
SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
2100+
}
19802101
} // namespace
19812102
} // namespace opt
19822103
} // namespace spvtools

0 commit comments

Comments
 (0)