spirv-reader: Don't hoist builtin vars.
Fixed: tint:1577 Change-Id: I1decc99e4a5a293b49c24aa15d1ac6dd0287462e Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/93680 Commit-Queue: Ben Clayton <bclayton@chromium.org> Auto-Submit: David Neto <dneto@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Ben Clayton <bclayton@chromium.org>
This commit is contained in:
parent
6d200d53ee
commit
93928b0d19
|
@ -725,9 +725,13 @@ BlockInfo::BlockInfo(const spvtools::opt::BasicBlock& bb) : basic_block(&bb), id
|
||||||
BlockInfo::~BlockInfo() = default;
|
BlockInfo::~BlockInfo() = default;
|
||||||
|
|
||||||
DefInfo::DefInfo(const spvtools::opt::Instruction& def_inst,
|
DefInfo::DefInfo(const spvtools::opt::Instruction& def_inst,
|
||||||
|
bool the_locally_defined,
|
||||||
uint32_t the_block_pos,
|
uint32_t the_block_pos,
|
||||||
size_t the_index)
|
size_t the_index)
|
||||||
: inst(def_inst), block_pos(the_block_pos), index(the_index) {}
|
: inst(def_inst),
|
||||||
|
locally_defined(the_locally_defined),
|
||||||
|
block_pos(the_block_pos),
|
||||||
|
index(the_index) {}
|
||||||
|
|
||||||
DefInfo::~DefInfo() = default;
|
DefInfo::~DefInfo() = default;
|
||||||
|
|
||||||
|
@ -4479,9 +4483,10 @@ bool FunctionEmitter::RegisterSpecialBuiltInVariables() {
|
||||||
const auto id = special_var.first;
|
const auto id = special_var.first;
|
||||||
const auto builtin = special_var.second;
|
const auto builtin = special_var.second;
|
||||||
const auto* var = def_use_mgr_->GetDef(id);
|
const auto* var = def_use_mgr_->GetDef(id);
|
||||||
def_info_[id] = std::make_unique<DefInfo>(*var, 0, index);
|
def_info_[id] = std::make_unique<DefInfo>(*var, false, 0, index);
|
||||||
++index;
|
++index;
|
||||||
auto& def = def_info_[id];
|
auto& def = def_info_[id];
|
||||||
|
// Builtins are always defined outside the function.
|
||||||
switch (builtin) {
|
switch (builtin) {
|
||||||
case SpvBuiltInPointSize:
|
case SpvBuiltInPointSize:
|
||||||
def->skip = SkipReason::kPointSizeBuiltinPointer;
|
def->skip = SkipReason::kPointSizeBuiltinPointer;
|
||||||
|
@ -4526,7 +4531,7 @@ bool FunctionEmitter::RegisterLocallyDefinedValues() {
|
||||||
if ((result_id == 0) || inst.opcode() == SpvOpLabel) {
|
if ((result_id == 0) || inst.opcode() == SpvOpLabel) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
def_info_[result_id] = std::make_unique<DefInfo>(inst, block_pos, index);
|
def_info_[result_id] = std::make_unique<DefInfo>(inst, true, block_pos, index);
|
||||||
++index;
|
++index;
|
||||||
auto& info = def_info_[result_id];
|
auto& info = def_info_[result_id];
|
||||||
|
|
||||||
|
@ -4722,6 +4727,13 @@ void FunctionEmitter::FindValuesNeedingNamedOrHoistedDefinition() {
|
||||||
// There is no need to adjust the location of the declaration.
|
// There is no need to adjust the location of the declaration.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!def_info->locally_defined) {
|
||||||
|
// Never hoist a variable declared at module scope.
|
||||||
|
// This occurs for builtin variables, which are mapped to module-scope
|
||||||
|
// private variables.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// The first use must be the at the SSA definition, because block order
|
// The first use must be the at the SSA definition, because block order
|
||||||
// respects dominance.
|
// respects dominance.
|
||||||
const auto first_pos = def_info->block_pos;
|
const auto first_pos = def_info->block_pos;
|
||||||
|
|
|
@ -241,14 +241,22 @@ enum class SkipReason {
|
||||||
struct DefInfo {
|
struct DefInfo {
|
||||||
/// Constructor.
|
/// Constructor.
|
||||||
/// @param def_inst the SPIR-V instruction defining the ID
|
/// @param def_inst the SPIR-V instruction defining the ID
|
||||||
|
/// @param locally_defined the SPIR-V instruction defining the ID
|
||||||
/// @param block_pos the position of the basic block where the ID is defined.
|
/// @param block_pos the position of the basic block where the ID is defined.
|
||||||
/// @param index an ordering index for this local definition
|
/// @param index an ordering index for this local definition
|
||||||
DefInfo(const spvtools::opt::Instruction& def_inst, uint32_t block_pos, size_t index);
|
DefInfo(const spvtools::opt::Instruction& def_inst,
|
||||||
|
bool locally_defined,
|
||||||
|
uint32_t block_pos,
|
||||||
|
size_t index);
|
||||||
/// Destructor.
|
/// Destructor.
|
||||||
~DefInfo();
|
~DefInfo();
|
||||||
|
|
||||||
/// The SPIR-V instruction that defines the ID.
|
/// The SPIR-V instruction that defines the ID.
|
||||||
const spvtools::opt::Instruction& inst;
|
const spvtools::opt::Instruction& inst;
|
||||||
|
|
||||||
|
/// True if the definition of this ID is inside the function.
|
||||||
|
const bool locally_defined = true;
|
||||||
|
|
||||||
/// The position of the first block in which this ID is visible, in function
|
/// The position of the first block in which this ID is visible, in function
|
||||||
/// block order. For IDs defined outside of the function, it is 0.
|
/// block order. For IDs defined outside of the function, it is 0.
|
||||||
/// For IDs defined in the function, it is the position of the block
|
/// For IDs defined in the function, it is the position of the block
|
||||||
|
@ -320,8 +328,11 @@ struct DefInfo {
|
||||||
/// @returns the ostream so calls can be chained
|
/// @returns the ostream so calls can be chained
|
||||||
inline std::ostream& operator<<(std::ostream& o, const DefInfo& di) {
|
inline std::ostream& operator<<(std::ostream& o, const DefInfo& di) {
|
||||||
o << "DefInfo{"
|
o << "DefInfo{"
|
||||||
<< " inst.result_id: " << di.inst.result_id() << " block_pos: " << di.block_pos
|
<< " inst.result_id: " << di.inst.result_id()
|
||||||
<< " num_uses: " << di.num_uses << " last_use_pos: " << di.last_use_pos
|
<< " locally_defined: " << (di.locally_defined ? "true" : "false")
|
||||||
|
<< " block_pos: " << di.block_pos << " num_uses: " << di.num_uses
|
||||||
|
<< " last_use_pos: " << di.last_use_pos
|
||||||
|
<< " used_in_another_construct: " << (di.used_in_another_construct ? "true" : "false")
|
||||||
<< " requires_named_const_def: " << (di.requires_named_const_def ? "true" : "false")
|
<< " requires_named_const_def: " << (di.requires_named_const_def ? "true" : "false")
|
||||||
<< " requires_hoisted_def: " << (di.requires_hoisted_def ? "true" : "false") << " phi_var: '"
|
<< " requires_hoisted_def: " << (di.requires_hoisted_def ? "true" : "false") << " phi_var: '"
|
||||||
<< di.phi_var << "'";
|
<< di.phi_var << "'";
|
||||||
|
@ -840,7 +851,7 @@ class FunctionEmitter {
|
||||||
return info && info->pos != kInvalidBlockPos;
|
return info && info->pos != kInvalidBlockPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the local definition info for a result ID.
|
/// Gets the definition info for a result ID.
|
||||||
/// @param id the SPIR-V ID of local definition.
|
/// @param id the SPIR-V ID of local definition.
|
||||||
/// @returns the definition info for the given ID, if it exists, or nullptr
|
/// @returns the definition info for the given ID, if it exists, or nullptr
|
||||||
DefInfo* GetDefInfo(uint32_t id) const {
|
DefInfo* GetDefInfo(uint32_t id) const {
|
||||||
|
@ -1274,7 +1285,9 @@ class FunctionEmitter {
|
||||||
// Mapping from block ID to its bookkeeping info.
|
// Mapping from block ID to its bookkeeping info.
|
||||||
std::unordered_map<uint32_t, std::unique_ptr<BlockInfo>> block_info_;
|
std::unordered_map<uint32_t, std::unique_ptr<BlockInfo>> block_info_;
|
||||||
|
|
||||||
// Mapping from a locally-defined result ID to its bookkeeping info.
|
// Mapping from a result ID to its bookkeeping info. This may be
|
||||||
|
// either a result ID defined in the function body, or the ID of a
|
||||||
|
// module-scope variable.
|
||||||
std::unordered_map<uint32_t, std::unique_ptr<DefInfo>> def_info_;
|
std::unordered_map<uint32_t, std::unique_ptr<DefInfo>> def_info_;
|
||||||
|
|
||||||
// Structured constructs, where enclosing constructs precede their children.
|
// Structured constructs, where enclosing constructs precede their children.
|
||||||
|
|
|
@ -2537,6 +2537,68 @@ fn main(@builtin(vertex_index) x_1_param : u32) -> main_out {
|
||||||
EXPECT_EQ(module_str, expected) << module_str;
|
EXPECT_EQ(module_str, expected) << module_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(SpvModuleScopeVarParserTest, VertexIndex_UsedTwice_DifferentConstructs) {
|
||||||
|
// Test crbug.com/tint/1577
|
||||||
|
// Builtin variables must not be hoisted. Before the fix, the reader
|
||||||
|
// would see two uses of the variable in different constructs and try
|
||||||
|
// to hoist it. Only function-local definitions should be hoisted.
|
||||||
|
const std::string assembly = VertexIndexPreamble("%uint") + R"(
|
||||||
|
%bool = OpTypeBool
|
||||||
|
%900 = OpConstantTrue %bool
|
||||||
|
%main = OpFunction %void None %voidfn
|
||||||
|
%entry = OpLabel
|
||||||
|
%2 = OpLoad %uint %1 ; used in outer selection
|
||||||
|
OpSelectionMerge %99 None
|
||||||
|
OpBranchConditional %900 %30 %99
|
||||||
|
|
||||||
|
%30 = OpLabel
|
||||||
|
%3 = OpLoad %uint %1 ; used in inner selection
|
||||||
|
OpSelectionMerge %40 None
|
||||||
|
OpBranchConditional %900 %35 %40
|
||||||
|
|
||||||
|
%35 = OpLabel
|
||||||
|
OpBranch %40
|
||||||
|
|
||||||
|
%40 = OpLabel
|
||||||
|
OpBranch %99
|
||||||
|
|
||||||
|
%99 = OpLabel
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
auto p = parser(test::Assemble(assembly));
|
||||||
|
ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
|
||||||
|
EXPECT_TRUE(p->error().empty());
|
||||||
|
const auto module_str = test::ToString(p->program());
|
||||||
|
const std::string expected = R"(var<private> x_1 : u32;
|
||||||
|
|
||||||
|
var<private> x_5 : vec4<f32>;
|
||||||
|
|
||||||
|
fn main_1() {
|
||||||
|
let x_2 : u32 = x_1;
|
||||||
|
if (true) {
|
||||||
|
let x_3 : u32 = x_1;
|
||||||
|
if (true) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct main_out {
|
||||||
|
@builtin(position)
|
||||||
|
x_5_1 : vec4<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
@vertex
|
||||||
|
fn main(@builtin(vertex_index) x_1_param : u32) -> main_out {
|
||||||
|
x_1 = x_1_param;
|
||||||
|
main_1();
|
||||||
|
return main_out(x_5);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
EXPECT_EQ(module_str, expected) << module_str;
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(SpvModuleScopeVarParserTest, VertexIndex_I32_Load_CopyObject) {
|
TEST_F(SpvModuleScopeVarParserTest, VertexIndex_I32_Load_CopyObject) {
|
||||||
const std::string assembly = VertexIndexPreamble("%int") + R"(
|
const std::string assembly = VertexIndexPreamble("%int") + R"(
|
||||||
%main = OpFunction %void None %voidfn
|
%main = OpFunction %void None %voidfn
|
||||||
|
|
Loading…
Reference in New Issue