spirv-reader: phis as a particular case of hoisting to a var

We already compute the "first" and "last" basic block that
uses a value, so we could know when to hoist a value into
a var declaration. You have to do this sometimes to make
sure all uses are in scope of the declaration.

Until now we tracked Phis with an entirely different mechanism.
But there are cases which broke down. That's what happens
in crbug.com/tint/1649.

Additionally, GraphicsFuzz cases generarte similar weirdness.

Also, be more careful about ensuring that the assignments
generated to feed phis behave as if they occur in parallel.
Within a single batch of such assignments, generate and
use intermediate let-declarations for phis that that batch
will overwrite.

Also, unwrap-references when rectifying the signedness of
binary operators.

Skip tests that fail due to crbug.comt/tint/98:
  test/tint/bug/tint/749.spvasm.*

Fixed: tint:1649
Change-Id: I7314c351b74a10bfa9a18011f3d80a520568011c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/101220
Auto-Submit: David Neto <dneto@google.com>
Commit-Queue: David Neto <dneto@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
David Neto 2022-09-16 20:18:39 +00:00 committed by Dawn LUCI CQ
parent ebc5bba671
commit a3f2bf6c60
23 changed files with 889 additions and 11014 deletions

View File

@ -37,6 +37,8 @@
#include "src/tint/sem/depth_texture.h"
#include "src/tint/sem/sampled_texture.h"
#include "src/tint/transform/spirv_atomic.h"
#include "src/tint/utils/hashmap.h"
#include "src/tint/utils/hashset.h"
// Terms:
// CFG: the control flow graph of the function, where basic blocks are the
@ -3356,16 +3358,6 @@ bool FunctionEmitter::EmitStatementsInBasicBlock(const BlockInfo& block_info,
auto* type = ty_.Reference(storage_type, ast::StorageClass::kNone);
identifier_types_.emplace(id, type);
}
// Emit declarations of phi state variables, in index order.
for (auto id : sorted_by_index(block_info.phis_needing_state_vars)) {
const auto* def_inst = def_use_mgr_->GetDef(id);
TINT_ASSERT(Reader, def_inst);
const auto phi_var_name = GetDefInfo(id)->phi_var;
TINT_ASSERT(Reader, !phi_var_name.empty());
auto* var = builder_.Var(phi_var_name,
parser_impl_.ConvertType(def_inst->type_id())->Build(builder_));
AddStatement(create<ast::VariableDeclStatement>(Source{}, var));
}
// Emit regular statements.
const spvtools::opt::BasicBlock& bb = *(block_info.basic_block);
@ -3384,22 +3376,55 @@ bool FunctionEmitter::EmitStatementsInBasicBlock(const BlockInfo& block_info,
// Emit assignments to carry values to phi nodes in potential destinations.
// Do it in index order.
if (!block_info.phi_assignments.IsEmpty()) {
auto sorted = block_info.phi_assignments;
// Keep only the phis that are used.
utils::Vector<BlockInfo::PhiAssignment, 4> worklist;
worklist.Reserve(block_info.phi_assignments.Length());
for (const auto assignment : block_info.phi_assignments) {
if (GetDefInfo(assignment.phi_id)->num_uses > 0) {
worklist.Push(assignment);
}
}
// Sort them.
std::stable_sort(
sorted.begin(), sorted.end(),
worklist.begin(), worklist.end(),
[this](const BlockInfo::PhiAssignment& lhs, const BlockInfo::PhiAssignment& rhs) {
return GetDefInfo(lhs.phi_id)->index < GetDefInfo(rhs.phi_id)->index;
});
for (auto assignment : block_info.phi_assignments) {
const auto var_name = GetDefInfo(assignment.phi_id)->phi_var;
auto expr = MakeExpression(assignment.value);
if (!expr) {
return false;
// Generate assignments to the phi variables being fed by this
// block. It must act as a parallel assignment. So first capture the
// current value of any value that will be overwritten, then generate
// the assignments.
// The set of IDs that are read by the assignments.
utils::Hashset<uint32_t, 8> read_set;
for (const auto assignment : worklist) {
read_set.Add(assignment.value_id);
}
// Generate a let-declaration to capture the current value of each phi
// that will be both read and written.
utils::Hashmap<uint32_t, Symbol, 8> copied_phis;
for (const auto assignment : worklist) {
const auto phi_id = assignment.phi_id;
if (read_set.Find(phi_id)) {
auto copy_name = namer_.MakeDerivedName(namer_.Name(phi_id) + "_c" +
std::to_string(block_info.id));
auto copy_sym = builder_.Symbols().Register(copy_name);
copied_phis.GetOrCreate(phi_id, [copy_sym]() { return copy_sym; });
AddStatement(builder_.WrapInStatement(
builder_.Let(copy_sym, builder_.Expr(namer_.Name(phi_id)))));
}
AddStatement(create<ast::AssignmentStatement>(
Source{},
create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(var_name)),
expr.expr));
}
// Generate assignments to the phi vars.
for (const auto assignment : worklist) {
const auto phi_id = assignment.phi_id;
auto* const lhs_expr = builder_.Expr(namer_.Name(phi_id));
// If RHS value is actually a phi we just cpatured, then use it.
auto* const copy_sym = copied_phis.Find(assignment.value_id);
auto* const rhs_expr =
copy_sym ? builder_.Expr(*copy_sym) : MakeExpression(assignment.value_id).expr;
AddStatement(builder_.Assign(lhs_expr, rhs_expr));
}
}
@ -3692,11 +3717,8 @@ bool FunctionEmitter::EmitStatement(const spvtools::opt::Instruction& inst) {
}
case SpvOpPhi: {
// Emit a read from the associated state variable.
TypedExpression expr{parser_impl_.ConvertType(inst.type_id()),
create<ast::IdentifierExpression>(
Source{}, builder_.Symbols().Register(def_info->phi_var))};
return EmitConstDefOrWriteToHoistedVar(inst, expr);
// The value will be in scope, available for reading from the phi ID.
return true;
}
case SpvOpOuterProduct:
@ -4884,60 +4906,80 @@ void FunctionEmitter::FindValuesNeedingNamedOrHoistedDefinition() {
}
}
// Scan uses of locally defined IDs, in function block order.
// Scan uses of locally defined IDs, finding their first and last uses, in
// block order.
// Updates the span of block positions that this value is used in.
// Ignores values defined outside this function.
auto record_value_use = [this](uint32_t id, const BlockInfo* block_info) {
if (auto* def_info = GetDefInfo(id)) {
// Update usage count.
def_info->num_uses++;
// Update usage span.
def_info->first_use_pos = std::min(def_info->first_use_pos, block_info->pos);
def_info->last_use_pos = std::max(def_info->last_use_pos, block_info->pos);
// Determine whether this ID is defined in a different construct
// from this use.
const auto defining_block = block_order_[def_info->block_pos];
const auto* def_in_construct = GetBlockInfo(defining_block)->construct;
if (def_in_construct != block_info->construct) {
def_info->used_in_another_construct = true;
}
}
};
for (auto block_id : block_order_) {
const auto* block_info = GetBlockInfo(block_id);
const auto block_pos = block_info->pos;
for (const auto& inst : *(block_info->basic_block)) {
// Update bookkeeping for locally-defined IDs used by this instruction.
inst.ForEachInId([this, block_pos, block_info](const uint32_t* id_ptr) {
auto* def_info = GetDefInfo(*id_ptr);
if (def_info) {
// Update usage count.
def_info->num_uses++;
// Update usage span.
def_info->last_use_pos = std::max(def_info->last_use_pos, block_pos);
// Determine whether this ID is defined in a different construct
// from this use.
const auto defining_block = block_order_[def_info->block_pos];
const auto* def_in_construct = GetBlockInfo(defining_block)->construct;
if (def_in_construct != block_info->construct) {
def_info->used_in_another_construct = true;
}
}
});
if (inst.opcode() == SpvOpPhi) {
// Declare a name for the variable used to carry values to a phi.
// For an OpPhi defining value P, an incoming value V from parent block B is
// counted as being "used" at block B, not at the block containing the Phi.
// That's because we will create a variable PHI_P to hold the phi value, and
// in the code generated for block B, create assignment `PHI_P = V`.
// To make the WGSL scopes work, both P and V are counted as being "used"
// in the parent block B.
const auto phi_id = inst.result_id();
auto* phi_def_info = GetDefInfo(phi_id);
phi_def_info->phi_var = namer_.MakeDerivedName(namer_.Name(phi_id) + "_phi");
phi_def_info->is_phi = true;
// Track all the places where we need to mention the variable,
// so we can place its declaration. First, record the location of
// the read from the variable.
uint32_t first_pos = block_pos;
uint32_t last_pos = block_pos;
// Record the assignments that will propagate values from predecessor
// blocks.
for (uint32_t i = 0; i + 1 < inst.NumInOperands(); i += 2) {
const uint32_t value_id = inst.GetSingleWordInOperand(i);
const uint32_t incoming_value_id = inst.GetSingleWordInOperand(i);
const uint32_t pred_block_id = inst.GetSingleWordInOperand(i + 1);
auto* pred_block_info = GetBlockInfo(pred_block_id);
// The predecessor might not be in the block order at all, so we
// need this guard.
if (IsInBlockOrder(pred_block_info)) {
// Track where the incoming value needs to be in scope.
record_value_use(incoming_value_id, block_info);
// Track where P needs to be in scope. It's not an ordinary use, so don't
// count it as one.
const auto pred_pos = pred_block_info->pos;
phi_def_info->first_use_pos =
std::min(phi_def_info->first_use_pos, pred_pos);
phi_def_info->last_use_pos = std::max(phi_def_info->last_use_pos, pred_pos);
// Record the assignment that needs to occur at the end
// of the predecessor block.
pred_block_info->phi_assignments.Push({phi_id, value_id});
first_pos = std::min(first_pos, pred_block_info->pos);
last_pos = std::max(last_pos, pred_block_info->pos);
pred_block_info->phi_assignments.Push({phi_id, incoming_value_id});
}
}
// Schedule the declaration of the state variable.
const auto* enclosing_construct = GetEnclosingScope(first_pos, last_pos);
const auto* enclosing_construct =
GetEnclosingScope(phi_def_info->first_use_pos, phi_def_info->last_use_pos);
GetBlockInfo(enclosing_construct->begin_id)->phis_needing_state_vars.Push(phi_id);
} else {
inst.ForEachInId([block_info, &record_value_use](const uint32_t* id_ptr) {
record_value_use(*id_ptr, block_info);
});
}
}
}
@ -4967,41 +5009,47 @@ void FunctionEmitter::FindValuesNeedingNamedOrHoistedDefinition() {
continue;
}
// The first use must be the at the SSA definition, because block order
// respects dominance.
const auto first_pos = def_info->block_pos;
const auto last_use_pos = def_info->last_use_pos;
const auto* def_in_construct = GetBlockInfo(block_order_[first_pos])->construct;
const auto* def_in_construct = GetBlockInfo(block_order_[def_info->block_pos])->construct;
// A definition in the first block of an kIfSelection or kSwitchSelection
// occurs before the branch, and so that definition should count as
// having been defined at the scope of the parent construct.
if (first_pos == def_in_construct->begin_pos) {
if (def_info->block_pos == def_in_construct->begin_pos) {
if ((def_in_construct->kind == Construct::kIfSelection) ||
(def_in_construct->kind == Construct::kSwitchSelection)) {
def_in_construct = def_in_construct->parent;
}
}
bool should_hoist = false;
if (!def_in_construct->ContainsPos(last_use_pos)) {
// We care about the earliest between the place of definition, and the first
// use of the value.
const auto first_pos = std::min(def_info->block_pos, def_info->first_use_pos);
const auto last_use_pos = def_info->last_use_pos;
bool should_hoist_to_let = false;
bool should_hoist_to_var = false;
if (def_info->is_phi) {
// We need to generate a variable, and assignments to that variable in
// all the phi parent blocks.
should_hoist_to_var = true;
} else if (!def_in_construct->ContainsPos(first_pos) ||
!def_in_construct->ContainsPos(last_use_pos)) {
// To satisfy scoping, we have to hoist the definition out to an enclosing
// construct.
should_hoist = true;
should_hoist_to_var = true;
} else {
// Avoid moving combinatorial values across constructs. This is a
// simple heuristic to avoid changing the cost of an operation
// by moving it into or out of a loop, for example.
if ((def_info->storage_class == ast::StorageClass::kInvalid) &&
def_info->used_in_another_construct) {
should_hoist = true;
should_hoist_to_let = true;
}
}
if (should_hoist) {
if (should_hoist_to_var || should_hoist_to_let) {
const auto* enclosing_construct = GetEnclosingScope(first_pos, last_use_pos);
if (enclosing_construct == def_in_construct) {
// We can use a plain 'const' definition.
if (should_hoist_to_let && (enclosing_construct == def_in_construct)) {
// We can use a plain 'let' declaration.
def_info->requires_named_const_def = true;
} else {
// We need to make a hoisted variable definition.

View File

@ -15,6 +15,7 @@
#ifndef SRC_TINT_READER_SPIRV_FUNCTION_H_
#define SRC_TINT_READER_SPIRV_FUNCTION_H_
#include <limits>
#include <memory>
#include <optional>
#include <string>
@ -166,8 +167,8 @@ struct BlockInfo {
struct PhiAssignment {
/// The ID of an OpPhi receiving a value from this basic block.
uint32_t phi_id;
/// The the value carried to the given OpPhi.
uint32_t value;
/// The ID of the value carried to the given OpPhi.
uint32_t value_id;
};
/// If this basic block branches to a visited basic block containing phis,
/// then this is the list of writes to the variables associated those phis.
@ -258,10 +259,9 @@ struct DefInfo {
/// 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
/// 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
/// containing the definition of the ID.
/// For IDs defined in the function, this is the position of the block
/// containing the definition of the ID, in function block order.
/// For IDs defined outside of the function, it is 0.
/// See method `FunctionEmitter::ComputeBlockOrderAndPositions`
const uint32_t block_pos = 0;
@ -272,8 +272,17 @@ struct DefInfo {
/// The number of uses of this ID.
uint32_t num_uses = 0;
/// The block position of the first use of this ID, or MAX_UINT if it is not
/// used at all. The "first" ordering is determined by the function block
/// order. The first use of an ID might be in an OpPhi that precedes the
/// definition of the ID.
/// The ID defined by an OpPhi is counted as being "used" in each of its
/// parent blocks.
uint32_t first_use_pos = std::numeric_limits<uint32_t>::max();
/// The block position of the last use of this ID, or 0 if it is not used
/// at all. The "last" ordering is determined by the function block order.
/// The ID defined by an OpPhi is counted as being "used" in each of its
/// parent blocks.
uint32_t last_use_pos = 0;
/// Is this value used in a construct other than the one in which it was
@ -288,8 +297,8 @@ struct DefInfo {
/// corresponding position of the ID definition in SPIR-V. This compensates
/// for the difference between dominance and scoping. An SSA definition can
/// dominate all its uses, but the construct where it is defined does not
/// enclose all the uses, and so if it were declared as a WGSL constant
/// definition at the point of its SPIR-V definition, then the WGSL name
/// enclose all the uses, and so if it were declared as a WGSL let-
/// declaration at the point of its SPIR-V definition, then the WGSL name
/// would go out of scope too early. Fix that by creating a variable at the
/// top of the smallest construct that encloses both the definition and all
/// its uses. Then the original SPIR-V definition maps to a WGSL assignment
@ -299,10 +308,8 @@ struct DefInfo {
/// example, pointers. crbug.com/tint/98
bool requires_hoisted_def = false;
/// If the definition is an OpPhi, then `phi_var` is the name of the
/// variable that stores the value carried from parent basic blocks into
/// the basic block containing the OpPhi. Otherwise this is the empty string.
std::string phi_var;
/// Is this ID an OpPhi?
bool is_phi = false;
/// The storage class to use for this value, if it is of pointer type.
/// This is required to carry a storage class override from a storage
@ -332,11 +339,11 @@ inline std::ostream& operator<<(std::ostream& o, const DefInfo& di) {
<< " inst.result_id: " << di.inst.result_id()
<< " locally_defined: " << (di.locally_defined ? "true" : "false")
<< " block_pos: " << di.block_pos << " num_uses: " << di.num_uses
<< " last_use_pos: " << di.last_use_pos
<< " first_use_pos: " << di.first_use_pos << " 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_hoisted_def: " << (di.requires_hoisted_def ? "true" : "false") << " phi_var: '"
<< di.phi_var << "'";
<< " requires_hoisted_def: " << (di.requires_hoisted_def ? "true" : "false")
<< " is_phi: " << (di.is_phi ? "true" : "false") << "";
if (di.storage_class != ast::StorageClass::kNone) {
o << " sc:" << int(di.storage_class);
}
@ -603,7 +610,7 @@ class FunctionEmitter {
/// @returns an possibly updated type
const Type* RemapStorageClass(const Type* type, uint32_t result_id);
/// Marks locally defined values when they should get a 'const'
/// Marks locally defined values when they should get a 'let'
/// definition in WGSL, or a 'var' definition at an outer scope.
/// This occurs in several cases:
/// - When a SPIR-V instruction might use the dynamically computed value

View File

@ -922,6 +922,52 @@ return;
EXPECT_EQ(expect, got);
}
TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_SimultaneousAssignment) {
// Phis must act as if they are simutaneously assigned.
// %101 and %102 should exchange values on each iteration, and never have
// the same value.
auto assembly = Preamble() + R"(
%100 = OpFunction %void None %voidfn
%10 = OpLabel
OpBranch %20
%20 = OpLabel
%101 = OpPhi %bool %true %10 %102 %20
%102 = OpPhi %bool %false %10 %101 %20
OpLoopMerge %99 %20 None
OpBranchConditional %true %99 %20
%99 = OpLabel
OpReturn
OpFunctionEnd
)";
auto p = parser(test::Assemble(assembly));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
auto fe = p->function_emitter(100);
EXPECT_TRUE(fe.EmitBody()) << p->error();
auto ast_body = fe.ast_body();
auto got = test::ToString(p->program(), ast_body);
auto* expect = R"(var x_101 : bool;
var x_102 : bool;
x_101 = true;
x_102 = false;
loop {
let x_101_c20 = x_101;
let x_102_c20 = x_102;
x_101 = x_102_c20;
x_102 = x_101_c20;
if (true) {
break;
}
}
return;
)";
EXPECT_EQ(expect, got);
}
TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_SingleBlockLoopIndex) {
auto assembly = Preamble() + R"(
%pty = OpTypePointer Private %uint
@ -969,20 +1015,19 @@ TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_SingleBlockLoopIndex) {
auto ast_body = fe.ast_body();
auto got = test::ToString(p->program(), ast_body);
auto* expect = R"(loop {
var x_2_phi : u32;
var x_3_phi : u32;
var x_2 : u32;
var x_3 : u32;
let x_101 : bool = x_7;
let x_102 : bool = x_8;
x_2_phi = 0u;
x_3_phi = 1u;
x_2 = 0u;
x_3 = 1u;
if (x_101) {
break;
}
loop {
let x_2 : u32 = x_2_phi;
let x_3 : u32 = x_3_phi;
x_2_phi = (x_2 + 1u);
x_3_phi = x_3;
let x_3_c20 = x_3;
x_2 = (x_2 + 1u);
x_3 = x_3_c20;
if (x_102) {
break;
}
@ -1043,27 +1088,26 @@ TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_MultiBlockLoopIndex) {
auto ast_body = fe.ast_body();
auto got = test::ToString(p->program(), ast_body);
auto* expect = R"(loop {
var x_2_phi : u32;
var x_3_phi : u32;
var x_2 : u32;
var x_3 : u32;
let x_101 : bool = x_7;
let x_102 : bool = x_8;
x_2_phi = 0u;
x_3_phi = 1u;
x_2 = 0u;
x_3 = 1u;
if (x_101) {
break;
}
loop {
var x_4 : u32;
let x_2 : u32 = x_2_phi;
let x_3 : u32 = x_3_phi;
if (x_102) {
break;
}
continuing {
x_4 = (x_2 + 1u);
x_2_phi = x_4;
x_3_phi = x_3;
let x_3_c30 = x_3;
x_2 = x_4;
x_3 = x_3_c30;
}
}
}
@ -1101,6 +1145,7 @@ TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_ValueFromLoopBodyAndContinuin
%30 = OpLabel
%7 = OpIAdd %uint %4 %6 ; use %4 again
%8 = OpCopyObject %uint %5 ; use %5
OpBranch %20
%79 = OpLabel
@ -1123,24 +1168,25 @@ TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_ValueFromLoopBodyAndContinuin
auto got = test::ToString(p->program(), ast_body);
auto* expect = R"(let x_101 : bool = x_17;
loop {
var x_2_phi : u32;
var x_5_phi : u32;
x_2_phi = 0u;
x_5_phi = 1u;
var x_2 : u32;
var x_5 : u32;
x_2 = 0u;
x_5 = 1u;
loop {
var x_4 : u32;
var x_6 : u32;
var x_7 : u32;
let x_2 : u32 = x_2_phi;
let x_5 : u32 = x_5_phi;
let x_4 : u32 = (x_2 + 1u);
let x_6 : u32 = (x_4 + 1u);
x_4 = (x_2 + 1u);
x_6 = (x_4 + 1u);
if (x_101) {
break;
}
continuing {
x_7 = (x_4 + x_6);
x_2_phi = x_4;
x_5_phi = x_7;
let x_8 : u32 = x_5;
x_2 = x_4;
x_5 = x_7;
}
}
}
@ -1203,21 +1249,20 @@ TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_FromElseAndThen) {
auto* expect = R"(let x_101 : bool = x_7;
let x_102 : bool = x_8;
loop {
var x_2_phi : u32;
var x_2 : u32;
if (x_101) {
break;
}
if (x_102) {
x_2_phi = 0u;
x_2 = 0u;
continue;
} else {
x_2_phi = 1u;
x_2 = 1u;
continue;
}
x_2_phi = 0u;
x_2 = 0u;
continuing {
let x_2 : u32 = x_2_phi;
x_1 = x_2;
}
}
@ -1277,13 +1322,13 @@ TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_FromHeaderAndThen) {
auto* expect = R"(let x_101 : bool = x_7;
let x_102 : bool = x_8;
loop {
var x_2_phi : u32;
var x_2 : u32;
if (x_101) {
break;
}
x_2_phi = 0u;
x_2 = 0u;
if (x_102) {
x_2_phi = 1u;
x_2 = 1u;
continue;
} else {
continue;
@ -1291,7 +1336,6 @@ loop {
return;
continuing {
let x_2 : u32 = x_2_phi;
x_1 = x_2;
}
}
@ -1334,7 +1378,8 @@ TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_InMerge_PredecessorsDominatdB
%99 = OpLabel
; predecessors are all dominated by case construct head at %30
%phi = OpPhi %uint %uint_0 %45 %uint_1 %50
%41 = OpPhi %uint %uint_0 %45 %uint_1 %50
%101 = OpCopyObject %uint %41 ; give it a use so it's emitted
OpReturn
OpFunctionEnd
@ -1346,7 +1391,7 @@ TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_InMerge_PredecessorsDominatdB
auto ast_body = fe.ast_body();
auto got = test::ToString(p->program(), ast_body);
auto* expect = R"(var x_41_phi : u32;
auto* expect = R"(var x_41 : u32;
switch(1u) {
default: {
fallthrough;
@ -1357,19 +1402,19 @@ switch(1u) {
case 1u: {
if (true) {
} else {
x_41_phi = 0u;
x_41 = 0u;
break;
}
x_41_phi = 1u;
x_41 = 1u;
}
}
let x_41 : u32 = x_41_phi;
let x_101 : u32 = x_41;
return;
)";
EXPECT_EQ(expect, got) << got << assembly;
}
TEST_F(SpvParserFunctionVarTest, EmitStatement_UseInPhiCountsAsUse) {
TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_UseInPhiCountsAsUse) {
// From crbug.com/215
// If the only use of a combinatorially computed ID is as the value
// in an OpPhi, then we still have to emit it. The algorithm fix
@ -1393,6 +1438,7 @@ TEST_F(SpvParserFunctionVarTest, EmitStatement_UseInPhiCountsAsUse) {
%99 = OpLabel
%101 = OpPhi %bool %11 %10 %12 %20
%102 = OpCopyObject %bool %101 ;; ensure a use of %101
OpReturn
OpFunctionEnd
@ -1405,14 +1451,330 @@ TEST_F(SpvParserFunctionVarTest, EmitStatement_UseInPhiCountsAsUse) {
auto ast_body = fe.ast_body();
auto got = test::ToString(p->program(), ast_body);
auto* expect = R"(var x_101_phi : bool;
auto* expect = R"(var x_101 : bool;
let x_11 : bool = (true & true);
let x_12 : bool = !(x_11);
x_101_phi = x_11;
x_101 = x_11;
if (true) {
x_101_phi = x_12;
x_101 = x_12;
}
let x_101 : bool = x_101_phi;
let x_102 : bool = x_101;
return;
)";
EXPECT_EQ(expect, got);
}
TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_PhiInLoopHeader_FedByHoistedVar_PhiUnused) {
// From investigation into crbug.com/1649
//
// Value %999 is defined deep in control flow, then we arrange for
// it to dominate the backedge of the outer loop. The %999 value is then
// fed back into the phi in the loop header. So %999 needs to be hoisted
// out of the loop. The phi assignment needs to use the hoisted variable.
// The hoisted variable needs to be placed such that its scope encloses
// that phi in the header of the outer loop. The compiler needs
// to "see" that there is an implicit use of %999 in the backedge block
// of that outer loop.
auto assembly = Preamble() + R"(
%100 = OpFunction %void None %voidfn
%10 = OpLabel
OpBranch %20
%20 = OpLabel
%101 = OpPhi %bool %true %10 %999 %80
OpLoopMerge %99 %80 None
OpBranchConditional %true %30 %99
%30 = OpLabel
OpSelectionMerge %50 None
OpBranchConditional %true %40 %50
%40 = OpLabel
%999 = OpCopyObject %bool %true
OpBranch %60
%50 = OpLabel
OpReturn
%60 = OpLabel ; if merge
OpBranch %80
%80 = OpLabel ; continue target
OpBranch %20
%99 = OpLabel
OpReturn
OpFunctionEnd
)";
auto p = parser(test::Assemble(assembly));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
auto fe = p->function_emitter(100);
EXPECT_TRUE(fe.EmitBody()) << p->error();
auto ast_body = fe.ast_body();
auto got = test::ToString(p->program(), ast_body);
auto* expect = R"(loop {
var x_999 : bool;
if (true) {
} else {
break;
}
if (true) {
x_999 = true;
continue;
}
return;
}
return;
)";
EXPECT_EQ(expect, got);
}
TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_PhiInLoopHeader_FedByHoistedVar_PhiUsed) {
// From investigation into crbug.com/1649
//
// Value %999 is defined deep in control flow, then we arrange for
// it to dominate the backedge of the outer loop. The %999 value is then
// fed back into the phi in the loop header. So %999 needs to be hoisted
// out of the loop. The phi assignment needs to use the hoisted variable.
// The hoisted variable needs to be placed such that its scope encloses
// that phi in the header of the outer loop. The compiler needs
// to "see" that there is an implicit use of %999 in the backedge block
// of that outer loop.
auto assembly = Preamble() + R"(
%100 = OpFunction %void None %voidfn
%10 = OpLabel
OpBranch %20
%20 = OpLabel
%101 = OpPhi %bool %true %10 %999 %80
OpLoopMerge %99 %80 None
OpBranchConditional %true %30 %99
%30 = OpLabel
OpSelectionMerge %50 None
OpBranchConditional %true %40 %50
%40 = OpLabel
%999 = OpCopyObject %bool %true
OpBranch %60
%50 = OpLabel
OpReturn
%60 = OpLabel ; if merge
OpBranch %80
%80 = OpLabel ; continue target
OpBranch %20
%99 = OpLabel
%1000 = OpCopyObject %bool %101
OpReturn
OpFunctionEnd
)";
auto p = parser(test::Assemble(assembly));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
auto fe = p->function_emitter(100);
EXPECT_TRUE(fe.EmitBody()) << p->error();
auto ast_body = fe.ast_body();
auto got = test::ToString(p->program(), ast_body);
auto* expect = R"(var x_101 : bool;
x_101 = true;
loop {
var x_999 : bool;
if (true) {
} else {
break;
}
if (true) {
x_999 = true;
continue;
}
return;
continuing {
x_101 = x_999;
}
}
let x_1000 : bool = x_101;
return;
)";
EXPECT_EQ(expect, got);
}
TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_PhiInLoopHeader_FedByPhi_PhiUnused) {
// From investigation into crbug.com/1649
//
// This is a reduction of one of the hard parts of test case
// vk-gl-cts/graphicsfuzz/stable-binarysearch-tree-false-if-discard-loop/1.spvasm
// In particular, see the data flow around %114 in that case.
//
// Here value %999 is is a *phi* defined deep in control flow, then we
// arrange for it to dominate the backedge of the outer loop. The %999
// value is then fed back into the phi in the loop header. The variable
// generated to hold the %999 value needs to be placed such that its scope
// encloses that phi in the header of the outer loop. The compiler needs
// to "see" that there is an implicit use of %999 in the backedge block
// of that outer loop.
auto assembly = Preamble() + R"(
%100 = OpFunction %void None %voidfn
%10 = OpLabel
OpBranch %20
%20 = OpLabel
%101 = OpPhi %bool %true %10 %999 %80
OpLoopMerge %99 %80 None
OpBranchConditional %true %99 %30
%30 = OpLabel
OpLoopMerge %70 %60 None
OpBranch %40
%40 = OpLabel
OpBranchConditional %true %60 %50
%50 = OpLabel
OpBranch %60
%60 = OpLabel ; inner continue
%999 = OpPhi %bool %true %40 %false %50
OpBranchConditional %true %70 %30
%70 = OpLabel ; inner merge
OpBranch %80
%80 = OpLabel ; outer continue target
OpBranch %20
%99 = OpLabel
OpReturn
OpFunctionEnd
)";
auto p = parser(test::Assemble(assembly));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
auto fe = p->function_emitter(100);
EXPECT_TRUE(fe.EmitBody()) << p->error();
auto ast_body = fe.ast_body();
auto got = test::ToString(p->program(), ast_body);
auto* expect = R"(loop {
var x_999 : bool;
if (true) {
break;
}
loop {
x_999 = true;
if (true) {
continue;
}
x_999 = false;
continuing {
if (true) {
break;
}
}
}
}
return;
)";
EXPECT_EQ(expect, got);
}
TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_PhiInLoopHeader_FedByPhi_PhiUsed) {
// From investigation into crbug.com/1649
//
// This is a reduction of one of the hard parts of test case
// vk-gl-cts/graphicsfuzz/stable-binarysearch-tree-false-if-discard-loop/1.spvasm
// In particular, see the data flow around %114 in that case.
//
// Here value %999 is is a *phi* defined deep in control flow, then we
// arrange for it to dominate the backedge of the outer loop. The %999
// value is then fed back into the phi in the loop header. The variable
// generated to hold the %999 value needs to be placed such that its scope
// encloses that phi in the header of the outer loop. The compiler needs
// to "see" that there is an implicit use of %999 in the backedge block
// of that outer loop.
auto assembly = Preamble() + R"(
%100 = OpFunction %void None %voidfn
%10 = OpLabel
OpBranch %20
%20 = OpLabel
%101 = OpPhi %bool %true %10 %999 %80
OpLoopMerge %99 %80 None
OpBranchConditional %true %99 %30
%30 = OpLabel
OpLoopMerge %70 %60 None
OpBranch %40
%40 = OpLabel
OpBranchConditional %true %60 %50
%50 = OpLabel
OpBranch %60
%60 = OpLabel ; inner continue
%999 = OpPhi %bool %true %40 %false %50
OpBranchConditional %true %70 %30
%70 = OpLabel ; inner merge
OpBranch %80
%80 = OpLabel ; outer continue target
OpBranch %20
%99 = OpLabel
%1000 = OpCopyObject %bool %101
OpReturn
OpFunctionEnd
)";
auto p = parser(test::Assemble(assembly));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
auto fe = p->function_emitter(100);
EXPECT_TRUE(fe.EmitBody()) << p->error();
auto ast_body = fe.ast_body();
auto got = test::ToString(p->program(), ast_body);
auto* expect = R"(var x_101 : bool;
x_101 = true;
loop {
var x_999 : bool;
if (true) {
break;
}
loop {
x_999 = true;
if (true) {
continue;
}
x_999 = false;
continuing {
if (true) {
break;
}
}
}
continuing {
x_101 = x_999;
}
}
let x_1000 : bool = x_101;
return;
)";
EXPECT_EQ(expect, got);

View File

@ -2053,7 +2053,8 @@ TypedExpression ParserImpl::RectifyOperandSignedness(const spvtools::opt::Instru
Fail() << "internal error: RectifyOperandSignedness given a null expr\n";
return {};
}
auto* type = expr.type;
// TODO(crbug.com/tint/1669) should this unpack aliases too?
auto* type = expr.type->UnwrapRef();
if (!type) {
Fail() << "internal error: unmapped type for: " << expr.expr->TypeInfo().name << "\n";
return {};
@ -2078,12 +2079,12 @@ TypedExpression ParserImpl::RectifyOperandSignedness(const spvtools::opt::Instru
TypedExpression ParserImpl::RectifySecondOperandSignedness(const spvtools::opt::Instruction& inst,
const Type* first_operand_type,
TypedExpression&& second_operand_expr) {
if ((first_operand_type != second_operand_expr.type) &&
const Type* target_type = first_operand_type->UnwrapRef();
if ((target_type != second_operand_expr.type->UnwrapRef()) &&
AssumesSecondOperandSignednessMatchesFirstOperand(inst.opcode())) {
// Conversion is required.
return {first_operand_type,
create<ast::BitcastExpression>(Source{}, first_operand_type->Build(builder_),
second_operand_expr.expr)};
return {target_type, create<ast::BitcastExpression>(Source{}, target_type->Build(builder_),
second_operand_expr.expr)};
}
// No conversion necessary.
return std::move(second_operand_expr);
@ -2091,6 +2092,7 @@ TypedExpression ParserImpl::RectifySecondOperandSignedness(const spvtools::opt::
const Type* ParserImpl::ForcedResultType(const spvtools::opt::Instruction& inst,
const Type* first_operand_type) {
first_operand_type = first_operand_type->UnwrapRef();
const auto opcode = inst.opcode();
if (AssumesResultSignednessMatchesFirstOperand(opcode)) {
return first_operand_type;

View File

@ -3984,14 +3984,11 @@ TEST_F(SpvParserHandleTest, TexelTypeWhenLoop) {
auto ast_body = fe.ast_body();
const auto got = test::ToString(p->program(), ast_body);
auto* expect = R"(var x_24 : vec2<f32>;
var x_24_phi_1 : vec2<f32>;
var x_26_phi_1 : i32;
x_24_phi_1 = vec2<f32>(0.0f, 0.0f);
x_26_phi_1 = 0i;
var x_26 : i32;
x_24 = vec2<f32>(0.0f, 0.0f);
x_26 = 0i;
loop {
var x_27 : i32;
x_24 = x_24_phi_1;
let x_26 : i32 = x_26_phi_1;
if ((x_26 < 2i)) {
} else {
break;
@ -3999,8 +3996,8 @@ loop {
continuing {
x_27 = (x_26 + 1i);
x_24_phi_1 = vec2<f32>(1.0f, 1.0f);
x_26_phi_1 = x_27;
x_24 = vec2<f32>(1.0f, 1.0f);
x_26 = x_27;
}
}
textureStore(Output2Texture2D, vec2<i32>(vec2<u32>(1u, 1u)), vec4<f32>(x_24, 0.0f, 0.0f));
@ -4060,14 +4057,11 @@ TEST_F(SpvParserHandleTest, SimpleSelectCanSelectFromHoistedConstant) {
auto ast_body = fe.ast_body();
const auto got = test::ToString(p->program(), ast_body);
auto* expect = R"(var x_14 : f32;
var x_14_phi_1 : f32;
var x_15_phi_1 : f32;
x_14_phi_1 = 0.0f;
x_15_phi_1 = 0.0f;
var x_15 : f32;
x_14 = 0.0f;
x_15 = 0.0f;
loop {
var x_17 : f32;
x_14 = x_14_phi_1;
let x_15 : f32 = x_15_phi_1;
if ((x_15 < 1.0f)) {
} else {
break;
@ -4075,8 +4069,9 @@ loop {
continuing {
x_17 = (x_15 + 1.0f);
x_14_phi_1 = x_15;
x_15_phi_1 = x_17;
let x_15_c16_1 = x_15;
x_14 = x_15_c16_1;
x_15 = x_17;
}
}
let x_21 : f32 = select(0.0f, x_14, (x_14 > 1.0f));

View File

@ -14,21 +14,20 @@ bool test_int_S1_c0_b() {
bool ok = false;
int4 val = int4(0, 0, 0, 0);
bool x_40 = false;
bool x_41 = false;
bool x_54 = false;
bool x_55 = false;
bool x_65 = false;
bool x_41_phi = false;
bool x_55_phi = false;
bool x_66_phi = false;
bool x_66 = false;
const float x_26 = asfloat(x_4[1].x);
const int x_27 = int(x_26);
unknown = x_27;
ok = true;
x_41_phi = false;
x_41 = false;
if (true) {
x_40 = all((((0).xxxx / value_or_one_if_zero_int4(int4(x_27, x_27, x_27, x_27))) == (0).xxxx));
x_41_phi = x_40;
x_41 = x_40;
}
const bool x_41 = x_41_phi;
ok = x_41;
const int4 x_44 = int4(x_27, x_27, x_27, x_27);
val = x_44;
@ -40,12 +39,11 @@ bool test_int_S1_c0_b() {
val = x_49;
const int4 x_50 = (x_49 - (1).xxxx);
val = x_50;
x_55_phi = false;
x_55 = false;
if (x_41) {
x_54 = all((x_50 == x_44));
x_55_phi = x_54;
x_55 = x_54;
}
const bool x_55 = x_55_phi;
ok = x_55;
const int4 x_58 = (x_50 * (2).xxxx);
val = x_58;
@ -55,12 +53,11 @@ bool test_int_S1_c0_b() {
val = x_60;
const int4 x_61 = (x_60 / (2).xxxx);
val = x_61;
x_66_phi = false;
x_66 = false;
if (x_55) {
x_65 = all((x_61 == x_44));
x_66_phi = x_65;
x_66 = x_65;
}
const bool x_66 = x_66_phi;
ok = x_66;
return x_66;
}
@ -73,23 +70,22 @@ void main_1() {
float4 x_10_val = float4(0.0f, 0.0f, 0.0f, 0.0f);
float4 x_116 = float4(0.0f, 0.0f, 0.0f, 0.0f);
bool x_86 = false;
bool x_87 = false;
bool x_99 = false;
bool x_100 = false;
bool x_110 = false;
bool x_111 = false;
bool x_114 = false;
bool x_87_phi = false;
bool x_100_phi = false;
bool x_111_phi = false;
bool x_115_phi = false;
bool x_115 = false;
outputColor_S0 = vcolor_S0;
const float x_77 = asfloat(x_4[1].x);
x_8_unknown = x_77;
x_9_ok = true;
x_87_phi = false;
x_87 = false;
if (true) {
x_86 = all((((0.0f).xxxx / float4(x_77, x_77, x_77, x_77)) == (0.0f).xxxx));
x_87_phi = x_86;
x_87 = x_86;
}
const bool x_87 = x_87_phi;
x_9_ok = x_87;
const float4 x_89 = float4(x_77, x_77, x_77, x_77);
x_10_val = x_89;
@ -101,12 +97,11 @@ void main_1() {
x_10_val = x_94;
const float4 x_95 = (x_94 - (1.0f).xxxx);
x_10_val = x_95;
x_100_phi = false;
x_100 = false;
if (x_87) {
x_99 = all((x_95 == x_89));
x_100_phi = x_99;
x_100 = x_99;
}
const bool x_100 = x_100_phi;
x_9_ok = x_100;
const float4 x_103 = (x_95 * (2.0f).xxxx);
x_10_val = x_103;
@ -116,19 +111,18 @@ void main_1() {
x_10_val = x_105;
const float4 x_106 = (x_105 / (2.0f).xxxx);
x_10_val = x_106;
x_111_phi = false;
x_111 = false;
if (x_100) {
x_110 = all((x_106 == x_89));
x_111_phi = x_110;
x_111 = x_110;
}
const bool x_111 = x_111_phi;
x_9_ok = x_111;
x_115_phi = false;
x_115 = false;
if (x_111) {
x_114 = test_int_S1_c0_b();
x_115_phi = x_114;
x_115 = x_114;
}
if (x_115_phi) {
if (x_115) {
const float4 x_122 = asfloat(x_4[3]);
x_116 = x_122;
} else {

View File

@ -14,21 +14,20 @@ bool test_int_S1_c0_b() {
bool ok = false;
int4 val = int4(0, 0, 0, 0);
bool x_40 = false;
bool x_41 = false;
bool x_54 = false;
bool x_55 = false;
bool x_65 = false;
bool x_41_phi = false;
bool x_55_phi = false;
bool x_66_phi = false;
bool x_66 = false;
const float x_26 = asfloat(x_4[1].x);
const int x_27 = int(x_26);
unknown = x_27;
ok = true;
x_41_phi = false;
x_41 = false;
if (true) {
x_40 = all((((0).xxxx / value_or_one_if_zero_int4(int4(x_27, x_27, x_27, x_27))) == (0).xxxx));
x_41_phi = x_40;
x_41 = x_40;
}
const bool x_41 = x_41_phi;
ok = x_41;
const int4 x_44 = int4(x_27, x_27, x_27, x_27);
val = x_44;
@ -40,12 +39,11 @@ bool test_int_S1_c0_b() {
val = x_49;
const int4 x_50 = (x_49 - (1).xxxx);
val = x_50;
x_55_phi = false;
x_55 = false;
if (x_41) {
x_54 = all((x_50 == x_44));
x_55_phi = x_54;
x_55 = x_54;
}
const bool x_55 = x_55_phi;
ok = x_55;
const int4 x_58 = (x_50 * (2).xxxx);
val = x_58;
@ -55,12 +53,11 @@ bool test_int_S1_c0_b() {
val = x_60;
const int4 x_61 = (x_60 / (2).xxxx);
val = x_61;
x_66_phi = false;
x_66 = false;
if (x_55) {
x_65 = all((x_61 == x_44));
x_66_phi = x_65;
x_66 = x_65;
}
const bool x_66 = x_66_phi;
ok = x_66;
return x_66;
}
@ -73,23 +70,22 @@ void main_1() {
float4 x_10_val = float4(0.0f, 0.0f, 0.0f, 0.0f);
float4 x_116 = float4(0.0f, 0.0f, 0.0f, 0.0f);
bool x_86 = false;
bool x_87 = false;
bool x_99 = false;
bool x_100 = false;
bool x_110 = false;
bool x_111 = false;
bool x_114 = false;
bool x_87_phi = false;
bool x_100_phi = false;
bool x_111_phi = false;
bool x_115_phi = false;
bool x_115 = false;
outputColor_S0 = vcolor_S0;
const float x_77 = asfloat(x_4[1].x);
x_8_unknown = x_77;
x_9_ok = true;
x_87_phi = false;
x_87 = false;
if (true) {
x_86 = all((((0.0f).xxxx / float4(x_77, x_77, x_77, x_77)) == (0.0f).xxxx));
x_87_phi = x_86;
x_87 = x_86;
}
const bool x_87 = x_87_phi;
x_9_ok = x_87;
const float4 x_89 = float4(x_77, x_77, x_77, x_77);
x_10_val = x_89;
@ -101,12 +97,11 @@ void main_1() {
x_10_val = x_94;
const float4 x_95 = (x_94 - (1.0f).xxxx);
x_10_val = x_95;
x_100_phi = false;
x_100 = false;
if (x_87) {
x_99 = all((x_95 == x_89));
x_100_phi = x_99;
x_100 = x_99;
}
const bool x_100 = x_100_phi;
x_9_ok = x_100;
const float4 x_103 = (x_95 * (2.0f).xxxx);
x_10_val = x_103;
@ -116,19 +111,18 @@ void main_1() {
x_10_val = x_105;
const float4 x_106 = (x_105 / (2.0f).xxxx);
x_10_val = x_106;
x_111_phi = false;
x_111 = false;
if (x_100) {
x_110 = all((x_106 == x_89));
x_111_phi = x_110;
x_111 = x_110;
}
const bool x_111 = x_111_phi;
x_9_ok = x_111;
x_115_phi = false;
x_115 = false;
if (x_111) {
x_114 = test_int_S1_c0_b();
x_115_phi = x_114;
x_115 = x_114;
}
if (x_115_phi) {
if (x_115) {
const float4 x_122 = asfloat(x_4[3]);
x_116 = x_122;
} else {

View File

@ -25,21 +25,20 @@ bool test_int_S1_c0_b() {
bool ok = false;
ivec4 val = ivec4(0, 0, 0, 0);
bool x_40 = false;
bool x_41 = false;
bool x_54 = false;
bool x_55 = false;
bool x_65 = false;
bool x_41_phi = false;
bool x_55_phi = false;
bool x_66_phi = false;
bool x_66 = false;
float x_26 = x_4.unknownInput_S1_c0;
int x_27 = int(x_26);
unknown = x_27;
ok = true;
x_41_phi = false;
x_41 = false;
if (true) {
x_40 = all(equal((ivec4(0) / ivec4(x_27, x_27, x_27, x_27)), ivec4(0)));
x_41_phi = x_40;
x_41 = x_40;
}
bool x_41 = x_41_phi;
ok = x_41;
ivec4 x_44 = ivec4(x_27, x_27, x_27, x_27);
val = x_44;
@ -51,12 +50,11 @@ bool test_int_S1_c0_b() {
val = x_49;
ivec4 x_50 = (x_49 - ivec4(1));
val = x_50;
x_55_phi = false;
x_55 = false;
if (x_41) {
x_54 = all(equal(x_50, x_44));
x_55_phi = x_54;
x_55 = x_54;
}
bool x_55 = x_55_phi;
ok = x_55;
ivec4 x_58 = (x_50 * ivec4(2));
val = x_58;
@ -66,12 +64,11 @@ bool test_int_S1_c0_b() {
val = x_60;
ivec4 x_61 = (x_60 / ivec4(2));
val = x_61;
x_66_phi = false;
x_66 = false;
if (x_55) {
x_65 = all(equal(x_61, x_44));
x_66_phi = x_65;
x_66 = x_65;
}
bool x_66 = x_66_phi;
ok = x_66;
return x_66;
}
@ -84,23 +81,22 @@ void main_1() {
vec4 x_10_val = vec4(0.0f, 0.0f, 0.0f, 0.0f);
vec4 x_116 = vec4(0.0f, 0.0f, 0.0f, 0.0f);
bool x_86 = false;
bool x_87 = false;
bool x_99 = false;
bool x_100 = false;
bool x_110 = false;
bool x_111 = false;
bool x_114 = false;
bool x_87_phi = false;
bool x_100_phi = false;
bool x_111_phi = false;
bool x_115_phi = false;
bool x_115 = false;
outputColor_S0 = vcolor_S0;
float x_77 = x_4.unknownInput_S1_c0;
x_8_unknown = x_77;
x_9_ok = true;
x_87_phi = false;
x_87 = false;
if (true) {
x_86 = all(equal((vec4(0.0f) / vec4(x_77, x_77, x_77, x_77)), vec4(0.0f)));
x_87_phi = x_86;
x_87 = x_86;
}
bool x_87 = x_87_phi;
x_9_ok = x_87;
vec4 x_89 = vec4(x_77, x_77, x_77, x_77);
x_10_val = x_89;
@ -112,12 +108,11 @@ void main_1() {
x_10_val = x_94;
vec4 x_95 = (x_94 - vec4(1.0f));
x_10_val = x_95;
x_100_phi = false;
x_100 = false;
if (x_87) {
x_99 = all(equal(x_95, x_89));
x_100_phi = x_99;
x_100 = x_99;
}
bool x_100 = x_100_phi;
x_9_ok = x_100;
vec4 x_103 = (x_95 * vec4(2.0f));
x_10_val = x_103;
@ -127,19 +122,18 @@ void main_1() {
x_10_val = x_105;
vec4 x_106 = (x_105 / vec4(2.0f));
x_10_val = x_106;
x_111_phi = false;
x_111 = false;
if (x_100) {
x_110 = all(equal(x_106, x_89));
x_111_phi = x_110;
x_111 = x_110;
}
bool x_111 = x_111_phi;
x_9_ok = x_111;
x_115_phi = false;
x_115 = false;
if (x_111) {
x_114 = test_int_S1_c0_b();
x_115_phi = x_114;
x_115 = x_114;
}
if (x_115_phi) {
if (x_115) {
vec4 x_122 = x_4.ucolorGreen_S1_c0;
x_116 = x_122;
} else {

View File

@ -28,21 +28,20 @@ bool test_int_S1_c0_b(const constant UniformBuffer* const tint_symbol_5) {
bool ok = false;
int4 val = 0;
bool x_40 = false;
bool x_41 = false;
bool x_54 = false;
bool x_55 = false;
bool x_65 = false;
bool x_41_phi = false;
bool x_55_phi = false;
bool x_66_phi = false;
bool x_66 = false;
float const x_26 = (*(tint_symbol_5)).unknownInput_S1_c0;
int const x_27 = int(x_26);
unknown = x_27;
ok = true;
x_41_phi = false;
x_41 = false;
if (true) {
x_40 = all(((int4(0) / int4(x_27, x_27, x_27, x_27)) == int4(0)));
x_41_phi = x_40;
x_41 = x_40;
}
bool const x_41 = x_41_phi;
ok = x_41;
int4 const x_44 = int4(x_27, x_27, x_27, x_27);
val = x_44;
@ -54,12 +53,11 @@ bool test_int_S1_c0_b(const constant UniformBuffer* const tint_symbol_5) {
val = x_49;
int4 const x_50 = as_type<int4>((as_type<uint4>(x_49) - as_type<uint4>(int4(1))));
val = x_50;
x_55_phi = false;
x_55 = false;
if (x_41) {
x_54 = all((x_50 == x_44));
x_55_phi = x_54;
x_55 = x_54;
}
bool const x_55 = x_55_phi;
ok = x_55;
int4 const x_58 = as_type<int4>((as_type<uint4>(x_50) * as_type<uint4>(int4(2))));
val = x_58;
@ -69,12 +67,11 @@ bool test_int_S1_c0_b(const constant UniformBuffer* const tint_symbol_5) {
val = x_60;
int4 const x_61 = (x_60 / int4(2));
val = x_61;
x_66_phi = false;
x_66 = false;
if (x_55) {
x_65 = all((x_61 == x_44));
x_66_phi = x_65;
x_66 = x_65;
}
bool const x_66 = x_66_phi;
ok = x_66;
return x_66;
}
@ -87,24 +84,23 @@ void main_1(thread float4* const tint_symbol_6, const constant UniformBuffer* co
float4 x_10_val = 0.0f;
float4 x_116 = 0.0f;
bool x_86 = false;
bool x_87 = false;
bool x_99 = false;
bool x_100 = false;
bool x_110 = false;
bool x_111 = false;
bool x_114 = false;
bool x_87_phi = false;
bool x_100_phi = false;
bool x_111_phi = false;
bool x_115_phi = false;
bool x_115 = false;
float4 const x_72 = *(tint_symbol_6);
outputColor_S0 = x_72;
float const x_77 = (*(tint_symbol_7)).unknownInput_S1_c0;
x_8_unknown = x_77;
x_9_ok = true;
x_87_phi = false;
x_87 = false;
if (true) {
x_86 = all(((float4(0.0f) / float4(x_77, x_77, x_77, x_77)) == float4(0.0f)));
x_87_phi = x_86;
x_87 = x_86;
}
bool const x_87 = x_87_phi;
x_9_ok = x_87;
float4 const x_89 = float4(x_77, x_77, x_77, x_77);
x_10_val = x_89;
@ -116,12 +112,11 @@ void main_1(thread float4* const tint_symbol_6, const constant UniformBuffer* co
x_10_val = x_94;
float4 const x_95 = (x_94 - float4(1.0f));
x_10_val = x_95;
x_100_phi = false;
x_100 = false;
if (x_87) {
x_99 = all((x_95 == x_89));
x_100_phi = x_99;
x_100 = x_99;
}
bool const x_100 = x_100_phi;
x_9_ok = x_100;
float4 const x_103 = (x_95 * float4(2.0f));
x_10_val = x_103;
@ -131,19 +126,17 @@ void main_1(thread float4* const tint_symbol_6, const constant UniformBuffer* co
x_10_val = x_105;
float4 const x_106 = (x_105 / float4(2.0f));
x_10_val = x_106;
x_111_phi = false;
x_111 = false;
if (x_100) {
x_110 = all((x_106 == x_89));
x_111_phi = x_110;
x_111 = x_110;
}
bool const x_111 = x_111_phi;
x_9_ok = x_111;
x_115_phi = false;
x_115 = false;
if (x_111) {
x_114 = test_int_S1_c0_b(tint_symbol_7);
x_115_phi = x_114;
x_115 = x_114;
}
bool const x_115 = x_115_phi;
if (x_115) {
float4 const x_122 = (*(tint_symbol_7)).ucolorGreen_S1_c0;
x_116 = x_122;

View File

@ -1,7 +1,7 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
; Bound: 170
; Bound: 176
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
@ -24,11 +24,11 @@
OpName %ok "ok"
OpName %val "val"
OpName %x_40 "x_40"
OpName %x_41 "x_41"
OpName %x_54 "x_54"
OpName %x_55 "x_55"
OpName %x_65 "x_65"
OpName %x_41_phi "x_41_phi"
OpName %x_55_phi "x_55_phi"
OpName %x_66_phi "x_66_phi"
OpName %x_66 "x_66"
OpName %main_1 "main_1"
OpName %outputColor_S0 "outputColor_S0"
OpName %output_S1 "output_S1"
@ -37,13 +37,13 @@
OpName %x_10_val "x_10_val"
OpName %x_116 "x_116"
OpName %x_86 "x_86"
OpName %x_87 "x_87"
OpName %x_99 "x_99"
OpName %x_100 "x_100"
OpName %x_110 "x_110"
OpName %x_111 "x_111"
OpName %x_114 "x_114"
OpName %x_87_phi "x_87_phi"
OpName %x_100_phi "x_100_phi"
OpName %x_111_phi "x_111_phi"
OpName %x_115_phi "x_115_phi"
OpName %x_115 "x_115"
OpName %main_out "main_out"
OpMemberName %main_out 0 "sk_FragColor_1"
OpName %main_inner "main_inner"
@ -101,38 +101,38 @@
%int_1 = OpConstant %int 1
%59 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
%int_2 = OpConstant %int 2
%71 = OpConstantComposite %v4int %int_2 %int_2 %int_2 %int_2
%72 = OpConstantComposite %v4int %int_2 %int_2 %int_2 %int_2
%void = OpTypeVoid
%82 = OpTypeFunction %void
%85 = OpTypeFunction %void
%_ptr_Function_v4float = OpTypePointer Function %v4float
%_ptr_Function_float = OpTypePointer Function %float
%91 = OpConstantNull %float
%94 = OpConstantNull %float
%float_1 = OpConstant %float 1
%116 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
%119 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
%float_2 = OpConstant %float 2
%128 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
%132 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
%uint_2 = OpConstant %uint 2
%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
%uint_1 = OpConstant %uint 1
%main_out = OpTypeStruct %v4float
%155 = OpTypeFunction %main_out %bool %v4float
%161 = OpTypeFunction %main_out %bool %v4float
%test_int_S1_c0_b = OpFunction %bool None %22
%24 = OpLabel
%unknown = OpVariable %_ptr_Function_int Function %28
%ok = OpVariable %_ptr_Function_bool Function %20
%val = OpVariable %_ptr_Function_v4int Function %34
%x_40 = OpVariable %_ptr_Function_bool Function %20
%x_41 = OpVariable %_ptr_Function_bool Function %20
%x_54 = OpVariable %_ptr_Function_bool Function %20
%x_55 = OpVariable %_ptr_Function_bool Function %20
%x_65 = OpVariable %_ptr_Function_bool Function %20
%x_41_phi = OpVariable %_ptr_Function_bool Function %20
%x_55_phi = OpVariable %_ptr_Function_bool Function %20
%x_66_phi = OpVariable %_ptr_Function_bool Function %20
%x_66 = OpVariable %_ptr_Function_bool Function %20
%44 = OpAccessChain %_ptr_Uniform_float %x_4 %uint_0
%45 = OpLoad %float %44
%46 = OpConvertFToS %int %45
OpStore %unknown %46
OpStore %ok %true
OpStore %x_41_phi %20
OpStore %x_41 %20
OpSelectionMerge %48 None
OpBranchConditional %true %49 %48
%49 = OpLabel
@ -142,10 +142,10 @@
%50 = OpAll %bool %53
OpStore %x_40 %50
%55 = OpLoad %bool %x_40
OpStore %x_41_phi %55
OpStore %x_41 %55
OpBranch %48
%48 = OpLabel
%56 = OpLoad %bool %x_41_phi
%56 = OpLoad %bool %x_41
OpStore %ok %56
%57 = OpCompositeConstruct %v4int %46 %46 %46 %46
OpStore %val %57
@ -157,169 +157,175 @@
OpStore %val %62
%63 = OpISub %v4int %62 %59
OpStore %val %63
OpStore %x_55_phi %20
OpSelectionMerge %64 None
OpBranchConditional %56 %65 %64
OpStore %x_55 %20
%64 = OpLoad %bool %x_41
OpSelectionMerge %65 None
OpBranchConditional %64 %66 %65
%66 = OpLabel
%68 = OpIEqual %v4bool %63 %57
%67 = OpAll %bool %68
OpStore %x_54 %67
%69 = OpLoad %bool %x_54
OpStore %x_55 %69
OpBranch %65
%65 = OpLabel
%67 = OpIEqual %v4bool %63 %57
%66 = OpAll %bool %67
OpStore %x_54 %66
%68 = OpLoad %bool %x_54
OpStore %x_55_phi %68
OpBranch %64
%64 = OpLabel
%69 = OpLoad %bool %x_55_phi
OpStore %ok %69
%72 = OpIMul %v4int %63 %71
OpStore %val %72
%73 = OpSDiv %v4int %72 %71
%70 = OpLoad %bool %x_55
OpStore %ok %70
%73 = OpIMul %v4int %63 %72
OpStore %val %73
%74 = OpIMul %v4int %73 %71
%74 = OpSDiv %v4int %73 %72
OpStore %val %74
%75 = OpSDiv %v4int %74 %71
%75 = OpIMul %v4int %74 %72
OpStore %val %75
OpStore %x_66_phi %20
OpSelectionMerge %76 None
OpBranchConditional %69 %77 %76
%77 = OpLabel
%79 = OpIEqual %v4bool %75 %57
%78 = OpAll %bool %79
OpStore %x_65 %78
%80 = OpLoad %bool %x_65
OpStore %x_66_phi %80
OpBranch %76
%76 = OpLabel
%81 = OpLoad %bool %x_66_phi
OpStore %ok %81
OpReturnValue %81
%76 = OpSDiv %v4int %75 %72
OpStore %val %76
OpStore %x_66 %20
%77 = OpLoad %bool %x_55
OpSelectionMerge %78 None
OpBranchConditional %77 %79 %78
%79 = OpLabel
%81 = OpIEqual %v4bool %76 %57
%80 = OpAll %bool %81
OpStore %x_65 %80
%82 = OpLoad %bool %x_65
OpStore %x_66 %82
OpBranch %78
%78 = OpLabel
%83 = OpLoad %bool %x_66
OpStore %ok %83
%84 = OpLoad %bool %x_66
OpReturnValue %84
OpFunctionEnd
%main_1 = OpFunction %void None %82
%85 = OpLabel
%main_1 = OpFunction %void None %85
%88 = OpLabel
%outputColor_S0 = OpVariable %_ptr_Function_v4float Function %10
%output_S1 = OpVariable %_ptr_Function_v4float Function %10
%x_8_unknown = OpVariable %_ptr_Function_float Function %91
%x_8_unknown = OpVariable %_ptr_Function_float Function %94
%x_9_ok = OpVariable %_ptr_Function_bool Function %20
%x_10_val = OpVariable %_ptr_Function_v4float Function %10
%x_116 = OpVariable %_ptr_Function_v4float Function %10
%x_86 = OpVariable %_ptr_Function_bool Function %20
%x_87 = OpVariable %_ptr_Function_bool Function %20
%x_99 = OpVariable %_ptr_Function_bool Function %20
%x_100 = OpVariable %_ptr_Function_bool Function %20
%x_110 = OpVariable %_ptr_Function_bool Function %20
%x_111 = OpVariable %_ptr_Function_bool Function %20
%x_114 = OpVariable %_ptr_Function_bool Function %20
%x_87_phi = OpVariable %_ptr_Function_bool Function %20
%x_100_phi = OpVariable %_ptr_Function_bool Function %20
%x_111_phi = OpVariable %_ptr_Function_bool Function %20
%x_115_phi = OpVariable %_ptr_Function_bool Function %20
%103 = OpLoad %v4float %vcolor_S0
OpStore %outputColor_S0 %103
%104 = OpAccessChain %_ptr_Uniform_float %x_4 %uint_0
%105 = OpLoad %float %104
OpStore %x_8_unknown %105
%x_115 = OpVariable %_ptr_Function_bool Function %20
%106 = OpLoad %v4float %vcolor_S0
OpStore %outputColor_S0 %106
%107 = OpAccessChain %_ptr_Uniform_float %x_4 %uint_0
%108 = OpLoad %float %107
OpStore %x_8_unknown %108
OpStore %x_9_ok %true
OpStore %x_87_phi %20
OpSelectionMerge %106 None
OpBranchConditional %true %107 %106
%107 = OpLabel
%109 = OpCompositeConstruct %v4float %105 %105 %105 %105
%110 = OpFDiv %v4float %10 %109
%111 = OpFOrdEqual %v4bool %110 %10
%108 = OpAll %bool %111
OpStore %x_86 %108
%112 = OpLoad %bool %x_86
OpStore %x_87_phi %112
OpBranch %106
%106 = OpLabel
%113 = OpLoad %bool %x_87_phi
OpStore %x_9_ok %113
%114 = OpCompositeConstruct %v4float %105 %105 %105 %105
OpStore %x_10_val %114
%117 = OpFAdd %v4float %114 %116
OpStore %x_87 %20
OpSelectionMerge %109 None
OpBranchConditional %true %110 %109
%110 = OpLabel
%112 = OpCompositeConstruct %v4float %108 %108 %108 %108
%113 = OpFDiv %v4float %10 %112
%114 = OpFOrdEqual %v4bool %113 %10
%111 = OpAll %bool %114
OpStore %x_86 %111
%115 = OpLoad %bool %x_86
OpStore %x_87 %115
OpBranch %109
%109 = OpLabel
%116 = OpLoad %bool %x_87
OpStore %x_9_ok %116
%117 = OpCompositeConstruct %v4float %108 %108 %108 %108
OpStore %x_10_val %117
%118 = OpFSub %v4float %117 %116
OpStore %x_10_val %118
%119 = OpFAdd %v4float %118 %116
OpStore %x_10_val %119
%120 = OpFSub %v4float %119 %116
%120 = OpFAdd %v4float %117 %119
OpStore %x_10_val %120
OpStore %x_100_phi %20
OpSelectionMerge %121 None
OpBranchConditional %113 %122 %121
%122 = OpLabel
%124 = OpFOrdEqual %v4bool %120 %114
%123 = OpAll %bool %124
OpStore %x_99 %123
%125 = OpLoad %bool %x_99
OpStore %x_100_phi %125
OpBranch %121
%121 = OpLabel
%126 = OpLoad %bool %x_100_phi
OpStore %x_9_ok %126
%129 = OpFMul %v4float %120 %128
OpStore %x_10_val %129
%130 = OpFDiv %v4float %129 %128
OpStore %x_10_val %130
%131 = OpFMul %v4float %130 %128
OpStore %x_10_val %131
%132 = OpFDiv %v4float %131 %128
OpStore %x_10_val %132
OpStore %x_111_phi %20
OpSelectionMerge %133 None
OpBranchConditional %126 %134 %133
%134 = OpLabel
%136 = OpFOrdEqual %v4bool %132 %114
%135 = OpAll %bool %136
OpStore %x_110 %135
%137 = OpLoad %bool %x_110
OpStore %x_111_phi %137
OpBranch %133
%133 = OpLabel
%138 = OpLoad %bool %x_111_phi
OpStore %x_9_ok %138
OpStore %x_115_phi %20
OpSelectionMerge %139 None
OpBranchConditional %138 %140 %139
%140 = OpLabel
%141 = OpFunctionCall %bool %test_int_S1_c0_b
OpStore %x_114 %141
%142 = OpLoad %bool %x_114
OpStore %x_115_phi %142
OpBranch %139
%121 = OpFSub %v4float %120 %119
OpStore %x_10_val %121
%122 = OpFAdd %v4float %121 %119
OpStore %x_10_val %122
%123 = OpFSub %v4float %122 %119
OpStore %x_10_val %123
OpStore %x_100 %20
%124 = OpLoad %bool %x_87
OpSelectionMerge %125 None
OpBranchConditional %124 %126 %125
%126 = OpLabel
%128 = OpFOrdEqual %v4bool %123 %117
%127 = OpAll %bool %128
OpStore %x_99 %127
%129 = OpLoad %bool %x_99
OpStore %x_100 %129
OpBranch %125
%125 = OpLabel
%130 = OpLoad %bool %x_100
OpStore %x_9_ok %130
%133 = OpFMul %v4float %123 %132
OpStore %x_10_val %133
%134 = OpFDiv %v4float %133 %132
OpStore %x_10_val %134
%135 = OpFMul %v4float %134 %132
OpStore %x_10_val %135
%136 = OpFDiv %v4float %135 %132
OpStore %x_10_val %136
OpStore %x_111 %20
%137 = OpLoad %bool %x_100
OpSelectionMerge %138 None
OpBranchConditional %137 %139 %138
%139 = OpLabel
%143 = OpLoad %bool %x_115_phi
OpSelectionMerge %144 None
OpBranchConditional %143 %145 %146
%145 = OpLabel
%149 = OpAccessChain %_ptr_Uniform_v4float %x_4 %uint_2
%150 = OpLoad %v4float %149
OpStore %x_116 %150
OpBranch %144
%141 = OpFOrdEqual %v4bool %136 %117
%140 = OpAll %bool %141
OpStore %x_110 %140
%142 = OpLoad %bool %x_110
OpStore %x_111 %142
OpBranch %138
%138 = OpLabel
%143 = OpLoad %bool %x_111
OpStore %x_9_ok %143
OpStore %x_115 %20
%144 = OpLoad %bool %x_111
OpSelectionMerge %145 None
OpBranchConditional %144 %146 %145
%146 = OpLabel
%152 = OpAccessChain %_ptr_Uniform_v4float %x_4 %uint_1
%153 = OpLoad %v4float %152
OpStore %x_116 %153
OpBranch %144
%144 = OpLabel
%154 = OpLoad %v4float %x_116
OpStore %output_S1 %154
OpStore %sk_FragColor %154
%147 = OpFunctionCall %bool %test_int_S1_c0_b
OpStore %x_114 %147
%148 = OpLoad %bool %x_114
OpStore %x_115 %148
OpBranch %145
%145 = OpLabel
%149 = OpLoad %bool %x_115
OpSelectionMerge %150 None
OpBranchConditional %149 %151 %152
%151 = OpLabel
%155 = OpAccessChain %_ptr_Uniform_v4float %x_4 %uint_2
%156 = OpLoad %v4float %155
OpStore %x_116 %156
OpBranch %150
%152 = OpLabel
%158 = OpAccessChain %_ptr_Uniform_v4float %x_4 %uint_1
%159 = OpLoad %v4float %158
OpStore %x_116 %159
OpBranch %150
%150 = OpLabel
%160 = OpLoad %v4float %x_116
OpStore %output_S1 %160
OpStore %sk_FragColor %160
OpReturn
OpFunctionEnd
%main_inner = OpFunction %main_out None %155
%main_inner = OpFunction %main_out None %161
%sk_Clockwise_param = OpFunctionParameter %bool
%vcolor_S0_param = OpFunctionParameter %v4float
%160 = OpLabel
%166 = OpLabel
OpStore %sk_Clockwise %sk_Clockwise_param
OpStore %vcolor_S0 %vcolor_S0_param
%161 = OpFunctionCall %void %main_1
%162 = OpLoad %v4float %sk_FragColor
%163 = OpCompositeConstruct %main_out %162
OpReturnValue %163
%167 = OpFunctionCall %void %main_1
%168 = OpLoad %v4float %sk_FragColor
%169 = OpCompositeConstruct %main_out %168
OpReturnValue %169
OpFunctionEnd
%main = OpFunction %void None %82
%165 = OpLabel
%167 = OpLoad %bool %sk_Clockwise_param_1
%168 = OpLoad %v4float %vcolor_S0_param_1
%166 = OpFunctionCall %main_out %main_inner %167 %168
%169 = OpCompositeExtract %v4float %166 0
OpStore %sk_FragColor_1_1 %169
%main = OpFunction %void None %85
%171 = OpLabel
%173 = OpLoad %bool %sk_Clockwise_param_1
%174 = OpLoad %v4float %vcolor_S0_param_1
%172 = OpFunctionCall %main_out %main_inner %173 %174
%175 = OpCompositeExtract %v4float %172 0
OpStore %sk_FragColor_1_1 %175
OpReturn
OpFunctionEnd

View File

@ -22,21 +22,20 @@ fn test_int_S1_c0_b() -> bool {
var ok : bool;
var val : vec4<i32>;
var x_40 : bool;
var x_41 : bool;
var x_54 : bool;
var x_55 : bool;
var x_65 : bool;
var x_41_phi : bool;
var x_55_phi : bool;
var x_66_phi : bool;
var x_66 : bool;
let x_26 : f32 = x_4.unknownInput_S1_c0;
let x_27 : i32 = i32(x_26);
unknown = x_27;
ok = true;
x_41_phi = false;
x_41 = false;
if (true) {
x_40 = all(((vec4<i32>(0i, 0i, 0i, 0i) / vec4<i32>(x_27, x_27, x_27, x_27)) == vec4<i32>(0i, 0i, 0i, 0i)));
x_41_phi = x_40;
x_41 = x_40;
}
let x_41 : bool = x_41_phi;
ok = x_41;
let x_44 : vec4<i32> = vec4<i32>(x_27, x_27, x_27, x_27);
val = x_44;
@ -48,12 +47,11 @@ fn test_int_S1_c0_b() -> bool {
val = x_49;
let x_50 : vec4<i32> = (x_49 - vec4<i32>(1i, 1i, 1i, 1i));
val = x_50;
x_55_phi = false;
x_55 = false;
if (x_41) {
x_54 = all((x_50 == x_44));
x_55_phi = x_54;
x_55 = x_54;
}
let x_55 : bool = x_55_phi;
ok = x_55;
let x_58 : vec4<i32> = (x_50 * vec4<i32>(2i, 2i, 2i, 2i));
val = x_58;
@ -63,12 +61,11 @@ fn test_int_S1_c0_b() -> bool {
val = x_60;
let x_61 : vec4<i32> = (x_60 / vec4<i32>(2i, 2i, 2i, 2i));
val = x_61;
x_66_phi = false;
x_66 = false;
if (x_55) {
x_65 = all((x_61 == x_44));
x_66_phi = x_65;
x_66 = x_65;
}
let x_66 : bool = x_66_phi;
ok = x_66;
return x_66;
}
@ -81,24 +78,23 @@ fn main_1() {
var x_10_val : vec4<f32>;
var x_116 : vec4<f32>;
var x_86 : bool;
var x_87 : bool;
var x_99 : bool;
var x_100 : bool;
var x_110 : bool;
var x_111 : bool;
var x_114 : bool;
var x_87_phi : bool;
var x_100_phi : bool;
var x_111_phi : bool;
var x_115_phi : bool;
var x_115 : bool;
let x_72 : vec4<f32> = vcolor_S0;
outputColor_S0 = x_72;
let x_77 : f32 = x_4.unknownInput_S1_c0;
x_8_unknown = x_77;
x_9_ok = true;
x_87_phi = false;
x_87 = false;
if (true) {
x_86 = all(((vec4<f32>(0.0f, 0.0f, 0.0f, 0.0f) / vec4<f32>(x_77, x_77, x_77, x_77)) == vec4<f32>(0.0f, 0.0f, 0.0f, 0.0f)));
x_87_phi = x_86;
x_87 = x_86;
}
let x_87 : bool = x_87_phi;
x_9_ok = x_87;
let x_89 : vec4<f32> = vec4<f32>(x_77, x_77, x_77, x_77);
x_10_val = x_89;
@ -110,12 +106,11 @@ fn main_1() {
x_10_val = x_94;
let x_95 : vec4<f32> = (x_94 - vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f));
x_10_val = x_95;
x_100_phi = false;
x_100 = false;
if (x_87) {
x_99 = all((x_95 == x_89));
x_100_phi = x_99;
x_100 = x_99;
}
let x_100 : bool = x_100_phi;
x_9_ok = x_100;
let x_103 : vec4<f32> = (x_95 * vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f));
x_10_val = x_103;
@ -125,19 +120,17 @@ fn main_1() {
x_10_val = x_105;
let x_106 : vec4<f32> = (x_105 / vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f));
x_10_val = x_106;
x_111_phi = false;
x_111 = false;
if (x_100) {
x_110 = all((x_106 == x_89));
x_111_phi = x_110;
x_111 = x_110;
}
let x_111 : bool = x_111_phi;
x_9_ok = x_111;
x_115_phi = false;
x_115 = false;
if (x_111) {
x_114 = test_int_S1_c0_b();
x_115_phi = x_114;
x_115 = x_114;
}
let x_115 : bool = x_115_phi;
if (x_115) {
let x_122 : vec4<f32> = x_4.ucolorGreen_S1_c0;
x_116 = x_122;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -18,17 +18,17 @@ ByteAddressBuffer x_185 : register(t2, space0);
bool coordsInBounds_vi2_vi2_(inout int2 coord, inout int2 shape) {
bool x_87 = false;
bool x_88_phi = false;
bool x_88 = false;
const int2 x_76 = coord;
const bool x_81 = all((x_76 >= (0).xx));
x_88_phi = x_81;
x_88 = x_81;
if (x_81) {
const int2 x_84 = coord;
const int2 x_85 = shape;
x_87 = all((x_84 < x_85));
x_88_phi = x_87;
x_88 = x_87;
}
return x_88_phi;
return x_88;
}
float mm_readA_i1_i1_(inout int row, inout int col) {
@ -286,7 +286,7 @@ void mm_matMul_i1_i1_i1_(inout int dimAOuter, inout int dimInner, inout int dimB
innerCol_4 = 0;
[loop] while (true) {
bool x_393 = false;
bool x_394_phi = false;
bool x_394 = false;
if ((innerCol_4 < 1)) {
} else {
break;
@ -295,15 +295,15 @@ void mm_matMul_i1_i1_i1_(inout int dimAOuter, inout int dimInner, inout int dimB
const int x_383 = innerCol_4;
const int x_385 = dimBOuter;
const bool x_386 = ((x_382 + x_383) < x_385);
x_394_phi = x_386;
x_394 = x_386;
if (x_386) {
const int x_389 = globalRow;
const int x_390 = innerRow_4;
const int x_392 = dimAOuter;
x_393 = ((x_389 + x_390) < x_392);
x_394_phi = x_393;
x_394 = x_393;
}
if (x_394_phi) {
if (x_394) {
const int x_400 = globalCol;
const int x_401 = innerCol_4;
const int x_403 = innerRow_4;

View File

@ -18,17 +18,17 @@ ByteAddressBuffer x_185 : register(t2, space0);
bool coordsInBounds_vi2_vi2_(inout int2 coord, inout int2 shape) {
bool x_87 = false;
bool x_88_phi = false;
bool x_88 = false;
const int2 x_76 = coord;
const bool x_81 = all((x_76 >= (0).xx));
x_88_phi = x_81;
x_88 = x_81;
if (x_81) {
const int2 x_84 = coord;
const int2 x_85 = shape;
x_87 = all((x_84 < x_85));
x_88_phi = x_87;
x_88 = x_87;
}
return x_88_phi;
return x_88;
}
float mm_readA_i1_i1_(inout int row, inout int col) {
@ -286,7 +286,7 @@ void mm_matMul_i1_i1_i1_(inout int dimAOuter, inout int dimInner, inout int dimB
innerCol_4 = 0;
[loop] while (true) {
bool x_393 = false;
bool x_394_phi = false;
bool x_394 = false;
if ((innerCol_4 < 1)) {
} else {
break;
@ -295,15 +295,15 @@ void mm_matMul_i1_i1_i1_(inout int dimAOuter, inout int dimInner, inout int dimB
const int x_383 = innerCol_4;
const int x_385 = dimBOuter;
const bool x_386 = ((x_382 + x_383) < x_385);
x_394_phi = x_386;
x_394 = x_386;
if (x_386) {
const int x_389 = globalRow;
const int x_390 = innerRow_4;
const int x_392 = dimAOuter;
x_393 = ((x_389 + x_390) < x_392);
x_394_phi = x_393;
x_394 = x_393;
}
if (x_394_phi) {
if (x_394) {
const int x_400 = globalCol;
const int x_401 = innerCol_4;
const int x_403 = innerRow_4;

View File

@ -41,17 +41,17 @@ layout(binding = 2, std430) buffer ssbB_ssbo {
bool coordsInBounds_vi2_vi2_(inout ivec2 coord, inout ivec2 shape) {
bool x_87 = false;
bool x_88_phi = false;
bool x_88 = false;
ivec2 x_76 = coord;
bool x_81 = all(greaterThanEqual(x_76, ivec2(0)));
x_88_phi = x_81;
x_88 = x_81;
if (x_81) {
ivec2 x_84 = coord;
ivec2 x_85 = shape;
x_87 = all(lessThan(x_84, x_85));
x_88_phi = x_87;
x_88 = x_87;
}
return x_88_phi;
return x_88;
}
float mm_readA_i1_i1_(inout int row, inout int col) {
@ -309,7 +309,7 @@ void mm_matMul_i1_i1_i1_(inout int dimAOuter, inout int dimInner, inout int dimB
innerCol_4 = 0;
while (true) {
bool x_393 = false;
bool x_394_phi = false;
bool x_394 = false;
if ((innerCol_4 < 1)) {
} else {
break;
@ -318,15 +318,15 @@ void mm_matMul_i1_i1_i1_(inout int dimAOuter, inout int dimInner, inout int dimB
int x_383 = innerCol_4;
int x_385 = dimBOuter;
bool x_386 = ((x_382 + x_383) < x_385);
x_394_phi = x_386;
x_394 = x_386;
if (x_386) {
int x_389 = globalRow;
int x_390 = innerRow_4;
int x_392 = dimAOuter;
x_393 = ((x_389 + x_390) < x_392);
x_394_phi = x_393;
x_394 = x_393;
}
if (x_394_phi) {
if (x_394) {
int x_400 = globalCol;
int x_401 = innerCol_4;
int x_403 = innerRow_4;

View File

@ -43,17 +43,16 @@ struct ssbB {
bool coordsInBounds_vi2_vi2_(thread int2* const coord, thread int2* const shape) {
bool x_87 = false;
bool x_88_phi = false;
bool x_88 = false;
int2 const x_76 = *(coord);
bool const x_81 = all((x_76 >= int2(0)));
x_88_phi = x_81;
x_88 = x_81;
if (x_81) {
int2 const x_84 = *(coord);
int2 const x_85 = *(shape);
x_87 = all((x_84 < x_85));
x_88_phi = x_87;
x_88 = x_87;
}
bool const x_88 = x_88_phi;
return x_88;
}
@ -419,7 +418,7 @@ void mm_matMul_i1_i1_i1_(thread int* const dimAOuter, thread int* const dimInner
innerCol_4 = 0;
while (true) {
bool x_393 = false;
bool x_394_phi = false;
bool x_394 = false;
int const x_380 = innerCol_4;
if ((x_380 < 1)) {
} else {
@ -429,15 +428,14 @@ void mm_matMul_i1_i1_i1_(thread int* const dimAOuter, thread int* const dimInner
int const x_383 = innerCol_4;
int const x_385 = *(dimBOuter);
bool const x_386 = (as_type<int>((as_type<uint>(x_382) + as_type<uint>(x_383))) < x_385);
x_394_phi = x_386;
x_394 = x_386;
if (x_386) {
int const x_389 = globalRow;
int const x_390 = innerRow_4;
int const x_392 = *(dimAOuter);
x_393 = (as_type<int>((as_type<uint>(x_389) + as_type<uint>(x_390))) < x_392);
x_394_phi = x_393;
x_394 = x_393;
}
bool const x_394 = x_394_phi;
if (x_394) {
int const x_397 = globalRow;
int const x_398 = innerRow_4;

View File

@ -41,7 +41,7 @@ note: reading from module-scope private variable 'dimInner_1' may result in a no
OpName %coord "coord"
OpName %shape "shape"
OpName %x_87 "x_87"
OpName %x_88_phi "x_88_phi"
OpName %x_88 "x_88"
OpName %mm_readA_i1_i1_ "mm_readA_i1_i1_"
OpName %row "row"
OpName %col "col"
@ -118,7 +118,7 @@ note: reading from module-scope private variable 'dimInner_1' may result in a no
OpName %param_8 "param_8"
OpName %param_9 "param_9"
OpName %x_393 "x_393"
OpName %x_394_phi "x_394_phi"
OpName %x_394 "x_394"
OpName %main_1 "main_1"
OpName %param_18 "param_18"
OpName %param_19 "param_19"
@ -250,11 +250,11 @@ note: reading from module-scope private variable 'dimInner_1' may result in a no
%shape = OpFunctionParameter %_ptr_Function_v2int
%51 = OpLabel
%x_87 = OpVariable %_ptr_Function_bool Function %54
%x_88_phi = OpVariable %_ptr_Function_bool Function %54
%x_88 = OpVariable %_ptr_Function_bool Function %54
%57 = OpLoad %v2int %coord
%60 = OpSGreaterThanEqual %v2bool %57 %59
%58 = OpAll %bool %60
OpStore %x_88_phi %58
OpStore %x_88 %58
OpSelectionMerge %62 None
OpBranchConditional %58 %63 %62
%63 = OpLabel
@ -264,10 +264,10 @@ note: reading from module-scope private variable 'dimInner_1' may result in a no
%68 = OpAll %bool %69
OpStore %x_87 %68
%70 = OpLoad %bool %x_87
OpStore %x_88_phi %70
OpStore %x_88 %70
OpBranch %62
%62 = OpLabel
%71 = OpLoad %bool %x_88_phi
%71 = OpLoad %bool %x_88
OpReturnValue %71
OpFunctionEnd
%mm_readA_i1_i1_ = OpFunction %float None %72
@ -477,7 +477,7 @@ note: reading from module-scope private variable 'dimInner_1' may result in a no
%param_8 = OpVariable %_ptr_Function_int Function %11
%param_9 = OpVariable %_ptr_Function_float Function %83
%x_393 = OpVariable %_ptr_Function_bool Function %54
%x_394_phi = OpVariable %_ptr_Function_bool Function %54
%x_394 = OpVariable %_ptr_Function_bool Function %54
%294 = OpAccessChain %_ptr_Private_uint %gl_LocalInvocationID %uint_1
%295 = OpLoad %uint %294
%296 = OpBitcast %int %295
@ -869,7 +869,7 @@ note: reading from module-scope private variable 'dimInner_1' may result in a no
%539 = OpLoad %int %dimBOuter
%540 = OpIAdd %int %536 %537
%541 = OpSLessThan %bool %540 %539
OpStore %x_394_phi %541
OpStore %x_394 %541
OpSelectionMerge %542 None
OpBranchConditional %541 %543 %542
%543 = OpLabel
@ -880,10 +880,10 @@ note: reading from module-scope private variable 'dimInner_1' may result in a no
%549 = OpSLessThan %bool %548 %547
OpStore %x_393 %549
%550 = OpLoad %bool %x_393
OpStore %x_394_phi %550
OpStore %x_394 %550
OpBranch %542
%542 = OpLabel
%551 = OpLoad %bool %x_394_phi
%551 = OpLoad %bool %x_394
OpSelectionMerge %552 None
OpBranchConditional %551 %553 %552
%553 = OpLabel

View File

@ -61,17 +61,16 @@ var<private> batch : i32;
fn coordsInBounds_vi2_vi2_(coord : ptr<function, vec2<i32>>, shape : ptr<function, vec2<i32>>) -> bool {
var x_87 : bool;
var x_88_phi : bool;
var x_88 : bool;
let x_76 : vec2<i32> = *(coord);
let x_81 : bool = all((x_76 >= vec2<i32>(0i, 0i)));
x_88_phi = x_81;
x_88 = x_81;
if (x_81) {
let x_84 : vec2<i32> = *(coord);
let x_85 : vec2<i32> = *(shape);
x_87 = all((x_84 < x_85));
x_88_phi = x_87;
x_88 = x_87;
}
let x_88 : bool = x_88_phi;
return x_88;
}
@ -448,7 +447,7 @@ fn mm_matMul_i1_i1_i1_(dimAOuter : ptr<function, i32>, dimInner : ptr<function,
innerCol_4 = 0i;
loop {
var x_393 : bool;
var x_394_phi : bool;
var x_394 : bool;
let x_380 : i32 = innerCol_4;
if ((x_380 < 1i)) {
} else {
@ -458,15 +457,14 @@ fn mm_matMul_i1_i1_i1_(dimAOuter : ptr<function, i32>, dimInner : ptr<function,
let x_383 : i32 = innerCol_4;
let x_385 : i32 = *(dimBOuter);
let x_386 : bool = ((x_382 + x_383) < x_385);
x_394_phi = x_386;
x_394 = x_386;
if (x_386) {
let x_389 : i32 = globalRow;
let x_390 : i32 = innerRow_4;
let x_392 : i32 = *(dimAOuter);
x_393 = ((x_389 + x_390) < x_392);
x_394_phi = x_393;
x_394 = x_393;
}
let x_394 : bool = x_394_phi;
if (x_394) {
let x_397 : i32 = globalRow;
let x_398 : i32 = innerRow_4;