shader: own control flow on IR blocks with direct targets

This commit is contained in:
nmzik committed 2026-10-09 01:59:41 +02:00
1 parent 8abf99c56e
commit 3df456675d
13 files changed
+477 -472

No files matched your search

+190 -141
View File
@@ -58,8 +58,8 @@ struct Fixture {
auto *result = storage.get();
program.block_storage.push_back(std::move(storage));
program.blocks.push_back(result);
program.block_info.push_back(
{.id = static_cast<uint32_t>(program.block_info.size())});
program.blocks.back()->id =
static_cast<uint32_t>(program.blocks.size() - 1u);
return result;
}
@@ -126,8 +126,8 @@ struct Fixture {
}
void PlanAndTrack() {
for (size_t index = 0; index < program.block_info.size(); ++index) {
const auto condition = program.block_info[index].condition;
for (size_t index = 0; index < program.blocks.size(); ++index) {
const auto condition = program.blocks[index]->condition;
if (!condition.IsEmpty())
Emit(ValueOpcode::Reference, {condition}, 0, program.blocks[index]);
}
@@ -475,9 +475,11 @@ void TestWaterfallImageTable() {
{guard, fixture->Emit(ValueOpcode::IEqual32, {image_words[word], local})});
}
}
fixture->program.block_info[0].condition = guard;
fixture->program.block_info[0].terminator = {
.kind = CFG::TerminatorKind::ConditionalBranch, .true_block = 1u, .false_block = 2u};
fixture->program.blocks[0]->condition = guard;
fixture->program.blocks[0]->terminator = {
.kind = CFG::TerminatorKind::ConditionalBranch,
.true_block = fixture->program.blocks[1u],
.false_block = fixture->program.blocks[2u]};
const auto sample = [&](Value image, Block *block) {
const auto sampler = fixture->Sampler({Value(0u), Value(0u), Value(0u), Value(0u)});
MemoryInfo memory;
@@ -589,19 +591,20 @@ void TestGuardedDirectImageTable() {
if (guard != Guard::Plain && guard != Guard::SccNonZero) {
condition = fixture.Emit(ValueOpcode::ConditionRef, {condition}, kind);
}
fixture.program.block_info[0].condition = condition;
fixture.program.block_info[0].terminator = {
fixture.program.blocks[0]->condition = condition;
fixture.program.blocks[0]->terminator = {
.kind = CFG::TerminatorKind::ConditionalBranch,
.true_block = guard == Guard::Zero ? 1u : 4u,
.false_block = guard == Guard::Zero ? 4u : 1u};
.true_block = fixture.program.blocks[guard == Guard::Zero ? 1u : 4u],
.false_block = fixture.program.blocks[guard == Guard::Zero ? 4u : 1u]};
for (uint32_t block = 1; block < 4; ++block) {
fixture.program.block_info[block].terminator = {
.kind = CFG::TerminatorKind::Branch, .true_block = block + 1u};
fixture.program.blocks[block]->terminator = {
.kind = CFG::TerminatorKind::Branch,
.true_block = fixture.program.blocks[block + 1u]};
}
fixture.program.block_info[4].terminator = {
fixture.program.blocks[4]->terminator = {
.kind = guard == Guard::Bypass ? CFG::TerminatorKind::Branch
: CFG::TerminatorKind::Return,
.true_block = 3u};
: CFG::TerminatorKind::Return,
.true_block = fixture.program.blocks[3u]};
const auto srt = fixture.Address(fixture.UserData(0), fixture.UserData(1));
std::array<Value, 2> pointer;
for (uint32_t word = 0; word < pointer.size(); ++word) {
@@ -767,27 +770,40 @@ void TestBoundedComputeImageLoop() {
if (variant == Variant::ExitBypass) exit->AddBranch(body);
if (variant == Variant::IncrementBypass || variant == Variant::PreviousBound)
exit->AddBranch(latch);
fixture.program.block_info[0].terminator = {
.kind = variant == Variant::EntryBypass ? CFG::TerminatorKind::ConditionalBranch
: CFG::TerminatorKind::Branch,
.true_block = 1u, .false_block = 2u};
fixture.program.block_info[1].terminator = {
fixture.program.blocks[0]->terminator = {
.kind = variant == Variant::EntryBypass
? CFG::TerminatorKind::ConditionalBranch
: CFG::TerminatorKind::Branch,
.true_block = fixture.program.blocks[1u],
.false_block = fixture.program.blocks[2u]};
fixture.program.blocks[1]->terminator = {
.kind = CFG::TerminatorKind::ConditionalBranch,
.true_block = variant == Variant::TrueEdge ? 2u : 4u,
.false_block = variant == Variant::TrueEdge ? 4u : 2u};
fixture.program.block_info[2].terminator = {
.kind = CFG::TerminatorKind::Branch, .true_block = 3u};
fixture.program.block_info[3].terminator = {
.kind = variant == Variant::PreviousBound ? CFG::TerminatorKind::ConditionalBranch
: CFG::TerminatorKind::Branch,
.true_block = 1u, .false_block = 5u};
fixture.program.block_info[4].terminator = {
.true_block =
fixture.program.blocks[variant == Variant::TrueEdge ? 2u : 4u],
.false_block =
fixture.program.blocks[variant == Variant::TrueEdge ? 4u : 2u]};
fixture.program.blocks[2]->terminator = {
.kind = CFG::TerminatorKind::Branch,
.true_block = fixture.program.blocks[3u]};
fixture.program.blocks[3]->terminator = {
.kind = variant == Variant::PreviousBound
? CFG::TerminatorKind::ConditionalBranch
: CFG::TerminatorKind::Branch,
.true_block = fixture.program.blocks[1u],
.false_block = final_exit};
fixture.program.blocks[4]->terminator = {
.kind = final_exit != exit || variant == Variant::ExitBypass ||
variant == Variant::IncrementBypass
? CFG::TerminatorKind::Branch : CFG::TerminatorKind::Return,
.true_block = final_exit != exit || variant == Variant::IncrementBypass ? 3u : 2u};
? CFG::TerminatorKind::Branch
: CFG::TerminatorKind::Return,
.true_block =
fixture.program.blocks[final_exit != exit ||
variant == Variant::IncrementBypass
? 3u
: 2u]};
if (final_exit != exit)
fixture.program.block_info[5].terminator.kind = CFG::TerminatorKind::Return;
fixture.program.blocks[5]->terminator.kind =
CFG::TerminatorKind::Return;
}
auto &phi = header->AppendNewInst(ValueOpcode::Phi, {},
@@ -859,14 +875,16 @@ void TestBoundedComputeImageLoop() {
block->AddBranch(fixture.program.blocks[yes]);
block->AddBranch(fixture.program.blocks[no]);
const auto inverse = fixture.Emit(ValueOpcode::LogicalNot, {predicate}, 0, block);
fixture.program.block_info[index].condition =
fixture.program.blocks[index]->condition =
fixture.Emit(ValueOpcode::ConditionRef, {inverse}, kind, block);
fixture.program.block_info[index].terminator = {
fixture.program.blocks[index]->terminator = {
.kind = CFG::TerminatorKind::ConditionalBranch,
.true_block = yes, .false_block = no};
.true_block = fixture.program.blocks[yes],
.false_block = fixture.program.blocks[no]};
};
fixture.program.block_info[0].terminator = {
.kind = CFG::TerminatorKind::Branch, .true_block = 1u};
fixture.program.blocks[0]->terminator = {
.kind = CFG::TerminatorKind::Branch,
.true_block = fixture.program.blocks[1u]};
branch(1u, 4u, 5u, active, CFG::BranchCondition::ExecZero);
branch(5u, variant == Variant::GuardedDiamondBypass ? 7u : 4u, 6u,
diamond ? execute : mask,
@@ -877,13 +895,15 @@ void TestBoundedComputeImageLoop() {
fixture.Emit(ValueOpcode::IEqual32, {local, Value(1u)}, 0, guard)}, 0, guard);
branch(6u, 3u, 2u, image_guard, CFG::BranchCondition::ExecZero);
body->AddBranch(latch);
fixture.program.block_info[2].terminator = {
.kind = CFG::TerminatorKind::Branch, .true_block = 3u};
fixture.program.blocks[2]->terminator = {
.kind = CFG::TerminatorKind::Branch,
.true_block = fixture.program.blocks[3u]};
branch(3u, 4u, 7u, next_active, CFG::BranchCondition::ExecZero);
increment->AddBranch(header);
fixture.program.block_info[7].terminator = {
.kind = CFG::TerminatorKind::Branch, .true_block = 1u};
fixture.program.block_info[4].terminator.kind = CFG::TerminatorKind::Return;
fixture.program.blocks[7]->terminator = {
.kind = CFG::TerminatorKind::Branch,
.true_block = fixture.program.blocks[1u]};
fixture.program.blocks[4]->terminator.kind = CFG::TerminatorKind::Return;
} else {
const auto active = initial_active;
const auto allowed = fixture.Emit(variant == Variant::Disjunction
@@ -899,14 +919,15 @@ void TestBoundedComputeImageLoop() {
: CFG::BranchCondition::ExecZero, header);
if (variant == Variant::Nonzero || variant == Variant::WrongPolarity)
condition = fixture.Emit(ValueOpcode::LogicalNot, {condition}, 0, header);
fixture.program.block_info[1].condition = condition;
fixture.program.blocks[1]->condition = condition;
if (variant == Variant::PreviousBound) {
previous->AddPhiOperand(entry, Value(false));
previous->AddPhiOperand(latch, in_range);
const auto continuing = fixture.Emit(ValueOpcode::LogicalOr,
{in_range, Value(previous)}, 0, latch);
fixture.program.block_info[3].condition = fixture.Emit(ValueOpcode::ConditionRef,
{continuing}, CFG::BranchCondition::SccNonZero, latch);
fixture.program.blocks[3]->condition =
fixture.Emit(ValueOpcode::ConditionRef, {continuing},
CFG::BranchCondition::SccNonZero, latch);
}
}
const auto step = fixture.Emit(ValueOpcode::IAdd32,
@@ -1067,21 +1088,27 @@ void TestUniformizedMaterialImageKeys() {
choose->AddBranch(done);
if (first_lane) {
sample_entry->AddBranch(first_lane_loop ? sample_header : sample);
fixture.program.block_info[sample_entry_id].terminator = {
.kind = CFG::TerminatorKind::Branch, .true_block = first_lane_loop ? 9u : 7u};
fixture.program.blocks[sample_entry_id]->terminator = {
.kind = CFG::TerminatorKind::Branch,
.true_block = fixture.program.blocks[first_lane_loop ? 9u : 7u]};
}
if (first_lane_loop) {
sample_header->AddBranch(sample);
sample->AddBranch(sample_header);
fixture.program.block_info[9].terminator = {
.kind = CFG::TerminatorKind::Branch, .true_block = 7u,
.merge_block = 8u, .continue_block = 7u, .loop_header = true};
fixture.program.blocks[9]->terminator = {
.kind = CFG::TerminatorKind::Branch,
.true_block = fixture.program.blocks[7u],
.merge_block = fixture.program.blocks[8u],
.continue_block = fixture.program.blocks[7u],
.loop_header = true};
}
sample->AddBranch(done);
fixture.program.block_info[0].terminator = {
.kind = CFG::TerminatorKind::Branch, .true_block = 1u};
fixture.program.block_info[1].terminator = {
.kind = CFG::TerminatorKind::Branch, .true_block = 2u};
fixture.program.blocks[0]->terminator = {
.kind = CFG::TerminatorKind::Branch,
.true_block = fixture.program.blocks[1u]};
fixture.program.blocks[1]->terminator = {
.kind = CFG::TerminatorKind::Branch,
.true_block = fixture.program.blocks[2u]};
const auto enabled = fixture.Emit(
ValueOpcode::INotEqual32, {fixture.UserData(5u), Value(0u)}, 0, entry);
const auto local = fixture.Emit(ValueOpcode::GetBuiltin,
@@ -1097,23 +1124,26 @@ void TestUniformizedMaterialImageKeys() {
ValueOpcode::Phi, {}, static_cast<uint64_t>(Type::U32));
const auto mask = Value(&mask_phi);
const auto active = Value(&active_phi);
fixture.program.block_info[2].condition = branch(
fixture.Emit(ValueOpcode::LogicalNot, {active}, 0, inactive),
variant == Variant::WrongExit ? CFG::BranchCondition::ExecNonZero
: CFG::BranchCondition::ExecZero, inactive);
fixture.program.block_info[2].terminator = {
fixture.program.blocks[2]->condition =
branch(fixture.Emit(ValueOpcode::LogicalNot, {active}, 0, inactive),
variant == Variant::WrongExit ? CFG::BranchCondition::ExecNonZero
: CFG::BranchCondition::ExecZero,
inactive);
fixture.program.blocks[2]->terminator = {
.kind = CFG::TerminatorKind::ConditionalBranch,
.true_block = 5u, .false_block = 3u};
.true_block = fixture.program.blocks[5u],
.false_block = fixture.program.blocks[3u]};
const auto nonzero = fixture.Emit(
ValueOpcode::INotEqual32, {Value(0u), mask}, 0, sentinel);
const auto bit_guard = fixture.Emit(
ValueOpcode::LogicalAnd, {active, nonzero}, 0, sentinel);
fixture.program.block_info[3].condition = branch(
fixture.Emit(ValueOpcode::LogicalNot, {bit_guard}, 0, sentinel),
CFG::BranchCondition::ExecZero, sentinel);
fixture.program.block_info[3].terminator = {
fixture.program.blocks[3]->condition =
branch(fixture.Emit(ValueOpcode::LogicalNot, {bit_guard}, 0, sentinel),
CFG::BranchCondition::ExecZero, sentinel);
fixture.program.blocks[3]->terminator = {
.kind = CFG::TerminatorKind::ConditionalBranch,
.true_block = 5u, .false_block = 4u};
.true_block = fixture.program.blocks[5u],
.false_block = fixture.program.blocks[4u]};
const auto first = fixture.Emit(ValueOpcode::FindILsb32, {mask}, 0, bit);
const auto position = fixture.Emit(
ValueOpcode::BitwiseAnd32, {first, Value(31u)}, 0, bit);
@@ -1130,11 +1160,12 @@ void TestUniformizedMaterialImageKeys() {
{mask, removed}, 0, bit);
const auto continuation = fixture.Emit(
ValueOpcode::LogicalAnd, {bit_guard, active_on_entry}, 0, bit);
fixture.program.block_info[4].condition = branch(
continuation, CFG::BranchCondition::ExecNonZero, bit);
fixture.program.block_info[4].terminator = {
fixture.program.blocks[4]->condition =
branch(continuation, CFG::BranchCondition::ExecNonZero, bit);
fixture.program.blocks[4]->terminator = {
.kind = CFG::TerminatorKind::ConditionalBranch,
.true_block = 1u, .false_block = 5u};
.true_block = fixture.program.blocks[1u],
.false_block = fixture.program.blocks[5u]};
active_phi.AddPhiOperand(entry, active_on_entry);
active_phi.AddPhiOperand(bit, continuation);
mask_phi.AddPhiOperand(entry, fixture.UserData(4u));
@@ -1159,8 +1190,9 @@ void TestUniformizedMaterialImageKeys() {
ValueOpcode::SGreaterThan32, {Value(32u), index}, 0, merge);
const auto material_guard = fixture.Emit(
ValueOpcode::LogicalAnd, {active_on_entry, below}, 0, merge);
fixture.program.block_info[5].terminator = {
.kind = CFG::TerminatorKind::Branch, .true_block = 6u};
fixture.program.blocks[5]->terminator = {
.kind = CFG::TerminatorKind::Branch,
.true_block = fixture.program.blocks[6u]};
const auto scaled = fixture.Emit(
ValueOpcode::ShiftLeftLogical32, {index, Value(4u)}, 0, choose);
const auto selected_scale = fixture.Emit(
@@ -1202,12 +1234,13 @@ void TestUniformizedMaterialImageKeys() {
sample_active_phi->AddPhiOperand(sample_entry, initial);
sample_active = Value(sample_active_phi);
}
fixture.program.block_info[6].condition = branch(
variant == Variant::EmptyFirstEntry ? enabled : initial,
CFG::BranchCondition::ExecNonZero, choose);
fixture.program.block_info[6].terminator = {
fixture.program.blocks[6]->condition =
branch(variant == Variant::EmptyFirstEntry ? enabled : initial,
CFG::BranchCondition::ExecNonZero, choose);
fixture.program.blocks[6]->terminator = {
.kind = CFG::TerminatorKind::ConditionalBranch,
.true_block = sample_entry_id, .false_block = 8u};
.true_block = fixture.program.blocks[sample_entry_id],
.false_block = fixture.program.blocks[8u]};
}
auto *key_block = first_lane ? sample : choose;
const auto key = first_lane
@@ -1219,12 +1252,13 @@ void TestUniformizedMaterialImageKeys() {
const auto sample_guard = fixture.Emit(
ValueOpcode::LogicalAnd, {sample_active, compared}, 0, key_block);
if (!first_lane) {
fixture.program.block_info[6].condition = branch(
fixture.program.blocks[6]->condition = branch(
fixture.Emit(ValueOpcode::LogicalNot, {sample_guard}, 0, choose),
CFG::BranchCondition::ExecZero, choose);
fixture.program.block_info[6].terminator = {
fixture.program.blocks[6]->terminator = {
.kind = CFG::TerminatorKind::ConditionalBranch,
.true_block = 8u, .false_block = 7u};
.true_block = fixture.program.blocks[8u],
.false_block = fixture.program.blocks[7u]};
}
const auto table_offset = fixture.Emit(
ValueOpcode::IAdd32,
@@ -1272,17 +1306,19 @@ void TestUniformizedMaterialImageKeys() {
if (variant == Variant::WideningFirstBackedge)
remaining = fixture.Emit(ValueOpcode::LogicalOr, {remaining, enabled}, 0, sample);
sample_active_phi->AddPhiOperand(sample, remaining);
fixture.program.block_info[7].condition = branch(
fixture.program.blocks[7]->condition = branch(
variant == Variant::WrongFirstBackedge ? sample_guard : remaining,
CFG::BranchCondition::ExecNonZero, sample);
fixture.program.block_info[7].terminator = {
fixture.program.blocks[7]->terminator = {
.kind = CFG::TerminatorKind::ConditionalBranch,
.true_block = 9u, .false_block = 8u};
.true_block = fixture.program.blocks[9u],
.false_block = fixture.program.blocks[8u]};
} else {
fixture.program.block_info[7].terminator = {
.kind = CFG::TerminatorKind::Branch, .true_block = 8u};
fixture.program.blocks[7]->terminator = {
.kind = CFG::TerminatorKind::Branch,
.true_block = fixture.program.blocks[8u]};
}
fixture.program.block_info[8].terminator.kind = CFG::TerminatorKind::Return;
fixture.program.blocks[8]->terminator.kind = CFG::TerminatorKind::Return;
const auto output = fixture.Emit(
ValueOpcode::GetBufferResource,
{fixture.UserData(8u), fixture.UserData(9u),
@@ -1556,10 +1592,10 @@ void TestComputeBufferFill() {
};
const auto Run = [](Options options) {
Fixture fixture;
fixture.program.block_info[0].terminator.kind =
fixture.program.blocks[0]->terminator.kind =
Libs::Graphics::ShaderRecompiler::CFG::TerminatorKind::Return;
if (options.branch) {
fixture.program.block_info[0].terminator.kind = Libs::Graphics::
fixture.program.blocks[0]->terminator.kind = Libs::Graphics::
ShaderRecompiler::CFG::TerminatorKind::ConditionalBranch;
}
const auto buffer =
@@ -2369,16 +2405,20 @@ ResourcePlan ConditionalSamplerPlan(bool diamond, bool reverse, bool reverse_phi
alternate->AddBranch(merge);
if (diamond) {
initial->AddBranch(merge);
fixture.program.block_info[1].terminator = {
.kind = CFG::TerminatorKind::Branch, .true_block = merge_id};
fixture.program.blocks[1]->terminator = {
.kind = CFG::TerminatorKind::Branch,
.true_block = fixture.program.blocks[merge_id]};
}
fixture.program.block_info[0].terminator = {
fixture.program.blocks[0]->terminator = {
.kind = CFG::TerminatorKind::ConditionalBranch,
.true_block = reverse ? alternate_id : initial_target,
.false_block = reverse ? initial_target : alternate_id};
fixture.program.block_info[alternate_id].terminator = {
.kind = CFG::TerminatorKind::Branch, .true_block = merge_id};
fixture.program.block_info[merge_id].terminator.kind =
.true_block =
fixture.program.blocks[reverse ? alternate_id : initial_target],
.false_block =
fixture.program.blocks[reverse ? initial_target : alternate_id]};
fixture.program.blocks[alternate_id]->terminator = {
.kind = CFG::TerminatorKind::Branch,
.true_block = fixture.program.blocks[merge_id]};
fixture.program.blocks[merge_id]->terminator.kind =
CFG::TerminatorKind::Return;
const auto control =
fixture.Buffer({Value(0x2000u), Value(0u), Value(200u), Value(0u)});
@@ -2389,7 +2429,7 @@ ResourcePlan ConditionalSamplerPlan(bool diamond, bool reverse, bool reverse_phi
if (nonuniform) {
flag = fixture.Emit(ValueOpcode::LaneId);
}
fixture.program.block_info[0].condition =
fixture.program.blocks[0]->condition =
fixture.Emit(ValueOpcode::SGreaterThanEqual32, {flag, Value(0u)});
if (writable) {
MemoryInfo memory;
@@ -2590,22 +2630,21 @@ void TestFiniteImageBitScanSentinel() {
{Value(uint32_t(StageInputKind::LocalInvocationIndex)), Value(0u)});
const auto condition = fixture.Emit(nonzero ? ValueOpcode::INotEqual32 : ValueOpcode::IEqual32,
{mask, Value(0u)});
auto &guard = fixture.program.block_info[0];
auto &guard = *fixture.program.blocks[0];
guard.condition = condition;
guard.terminator.kind = CFG::TerminatorKind::ConditionalBranch;
guard.terminator.true_block = 1;
guard.terminator.false_block = 4;
guard.terminator.true_block = dispatch;
guard.terminator.false_block = exit;
fixture.block = dispatch;
const auto first = fixture.Emit(ValueOpcode::FindILsb32, {mask});
const auto minimum = fixture.Emit(ValueOpcode::UMin32, {first, Value(32u)});
const auto selector = fixture.Emit(ValueOpcode::ShiftLeftLogical32, {minimum, Value(2u)});
fixture.Emit(ValueOpcode::ReferenceU32, {selector});
auto &table = fixture.program.block_info[1];
auto &table = *fixture.program.blocks[1];
table.indirect_target = selector;
table.terminator.kind = CFG::TerminatorKind::IndirectBranch;
table.terminator.indirect_selector_code = 0;
table.terminator.indirect_selector_values = {0u, 128u};
table.terminator.indirect_selector_targets = {2u, 3u};
table.terminator.indexed = true;
table.terminator.cases = {{0u, load}, {128u, merge}};
std::array<Value, 8> words;
for (uint32_t word = 0; word < words.size(); ++word) {
auto &phi = merge->AppendNewInst(ValueOpcode::Phi, {}, uint64_t(Type::U32));
@@ -2743,21 +2782,25 @@ void TestBoundedRelativeRegisterWrites() {
header->AddBranch(body);
header->AddBranch(exit);
body->AddBranch(header);
fixture.program.block_info[0].terminator = {
.kind = variant == Variant::EntryBypass ? CFG::TerminatorKind::ConditionalBranch
: CFG::TerminatorKind::Branch,
.true_block = 1u, .false_block = 2u};
fixture.program.block_info[1].terminator = {
fixture.program.blocks[0]->terminator = {
.kind = variant == Variant::EntryBypass
? CFG::TerminatorKind::ConditionalBranch
: CFG::TerminatorKind::Branch,
.true_block = fixture.program.blocks[1u],
.false_block = fixture.program.blocks[2u]};
fixture.program.blocks[1]->terminator = {
.kind = CFG::TerminatorKind::ConditionalBranch,
.true_block = 2u, .false_block = 3u};
fixture.program.block_info[2].terminator = {
.kind = CFG::TerminatorKind::Branch, .true_block = 1u};
fixture.program.block_info[3].terminator.kind = CFG::TerminatorKind::Return;
.true_block = fixture.program.blocks[2u],
.false_block = fixture.program.blocks[3u]};
fixture.program.blocks[2]->terminator = {
.kind = CFG::TerminatorKind::Branch,
.true_block = fixture.program.blocks[1u]};
fixture.program.blocks[3]->terminator.kind = CFG::TerminatorKind::Return;
const auto lane = fixture.Emit(ValueOpcode::GetBuiltin,
{Value(static_cast<uint32_t>(StageInputKind::LocalInvocationId)), Value(0u)});
const auto enabled = fixture.Emit(ValueOpcode::ULessThan32, {lane, Value(32u)});
fixture.program.block_info[0].condition = enabled;
fixture.program.blocks[0]->condition = enabled;
const auto chunk = fixture.Emit(ValueOpcode::SelectU32,
{enabled, Value(64u), Value(512u)});
const auto initial_bound = fixture.Emit(ValueOpcode::ShiftRightLogical32,
@@ -2769,8 +2812,9 @@ void TestBoundedRelativeRegisterWrites() {
auto &records = header->AppendNewInst(ValueOpcode::Phi, {}, uint64_t(Type::U32));
const auto in_range = fixture.Emit(ValueOpcode::ULessThan32,
{Value(&counter), Value(&bound)}, 0, header);
fixture.program.block_info[1].condition = fixture.Emit(
ValueOpcode::ConditionRef, {in_range}, CFG::BranchCondition::VccNonZero, header);
fixture.program.blocks[1]->condition =
fixture.Emit(ValueOpcode::ConditionRef, {in_range},
CFG::BranchCondition::VccNonZero, header);
const auto m0 = fixture.Emit(ValueOpcode::BitwiseAnd32,
{fixture.Emit(ValueOpcode::ShiftLeftLogical32,
{Value(&counter), Value(1u)}, 0, body), Value(255u)}, 0, body);
@@ -2953,26 +2997,27 @@ ResourcePlan ConditionalBufferPlan(ConditionalBufferUse use) {
auto *done = fixture.AddBlock();
auto *condition_block = entry;
uint32_t condition_index = 0;
fixture.program.block_info[0].id = 11;
fixture.program.block_info[1].id = 27;
fixture.program.block_info[2].id = 42;
fixture.program.blocks[0]->id = 11;
fixture.program.blocks[1]->id = 27;
fixture.program.blocks[2]->id = 42;
if (use == ConditionalBufferUse::Loop) {
condition_block = fixture.AddBlock();
condition_index = 3;
fixture.program.block_info[3].id = 55;
fixture.program.block_info[0].terminator = {
.kind = CFG::TerminatorKind::Branch, .true_block = 55};
fixture.program.blocks[3]->id = 55;
fixture.program.blocks[0]->terminator = {
.kind = CFG::TerminatorKind::Branch, .true_block = condition_block};
entry->AddBranch(condition_block);
}
condition_block->AddBranch(optional);
condition_block->AddBranch(done);
optional->AddBranch(use == ConditionalBufferUse::Loop ? condition_block : done);
fixture.program.block_info[condition_index].terminator = {
fixture.program.blocks[condition_index]->terminator = {
.kind = CFG::TerminatorKind::ConditionalBranch,
.true_block = 27, .false_block = 42};
fixture.program.block_info[1].terminator = {
.true_block = optional,
.false_block = done};
fixture.program.blocks[1]->terminator = {
.kind = CFG::TerminatorKind::Branch,
.true_block = use == ConditionalBufferUse::Loop ? 55u : 42u};
.true_block = use == ConditionalBufferUse::Loop ? condition_block : done};
const auto control = fixture.Buffer(
{fixture.UserData(0), fixture.UserData(1), fixture.UserData(2),
@@ -2988,8 +3033,8 @@ ResourcePlan ConditionalBufferPlan(ConditionalBufferUse use) {
phi.AddPhiOperand(optional, Value(1u));
flag = Value(&phi);
}
fixture.program.block_info[condition_index].condition =
fixture.Emit(ValueOpcode::INotEqual32, {flag, Value(0u)}, 0, condition_block);
fixture.program.blocks[condition_index]->condition = fixture.Emit(
ValueOpcode::INotEqual32, {flag, Value(0u)}, 0, condition_block);
const auto payload = fixture.Buffer(
{fixture.UserData(4), fixture.UserData(5), fixture.UserData(6),
@@ -3067,11 +3112,14 @@ void TestGuardedScalarDescriptorReads() {
entry->AddBranch(optional);
entry->AddBranch(done);
optional->AddBranch(done);
fixture.program.block_info[0].terminator = {
.kind = CFG::TerminatorKind::ConditionalBranch, .true_block = 1, .false_block = 2};
fixture.program.block_info[1].terminator = {
.kind = CFG::TerminatorKind::Branch, .true_block = 2};
fixture.program.block_info[2].terminator.kind = CFG::TerminatorKind::Return;
fixture.program.blocks[0]->terminator = {
.kind = CFG::TerminatorKind::ConditionalBranch,
.true_block = fixture.program.blocks[1],
.false_block = fixture.program.blocks[2]};
fixture.program.blocks[1]->terminator = {
.kind = CFG::TerminatorKind::Branch,
.true_block = fixture.program.blocks[2]};
fixture.program.blocks[2]->terminator.kind = CFG::TerminatorKind::Return;
const auto control = fixture.Buffer({fixture.UserData(0), fixture.UserData(1),
fixture.UserData(2), fixture.UserData(3)});
MemoryInfo scalar;
@@ -3083,7 +3131,7 @@ void TestGuardedScalarDescriptorReads() {
{Value(static_cast<uint32_t>(StageInputKind::LocalInvocationId)), Value(0u)});
const auto varying = fixture.Emit(ValueOpcode::INotEqual32, {lane, Value(0u)});
const auto enabled = fixture.Emit(ValueOpcode::INotEqual32, {flag, Value(0u)});
fixture.program.block_info[0].condition =
fixture.program.blocks[0]->condition =
fixture.Emit(ValueOpcode::LogicalAnd, {varying, enabled});
const auto root = fixture.Address(fixture.UserData(4), Value(0u));
const auto Load = [&](Block *block) {
@@ -3192,15 +3240,16 @@ void TestConditionalIndirectImageMaterialization() {
body->AddBranch(done);
const auto flag = fixture->Emit(ValueOpcode::GetUserData,
{Value(static_cast<ScalarReg>(8))}, 0, entry);
fixture->program.block_info[1].condition = fixture->Emit(
ValueOpcode::INotEqual32, {flag, Value(0u)}, 0, entry);
fixture->program.block_info[1].terminator = {
fixture->program.blocks[1]->condition =
fixture->Emit(ValueOpcode::INotEqual32, {flag, Value(0u)}, 0, entry);
fixture->program.blocks[1]->terminator = {
.kind = CFG::TerminatorKind::ConditionalBranch,
.true_block = 0, .false_block = 2};
fixture->program.block_info[0].terminator = {
.kind = CFG::TerminatorKind::Branch, .true_block = 2};
.true_block = fixture->program.blocks[0],
.false_block = fixture->program.blocks[2]};
fixture->program.blocks[0]->terminator = {.kind = CFG::TerminatorKind::Branch,
.true_block =
fixture->program.blocks[2]};
std::swap(fixture->program.blocks[0], fixture->program.blocks[1]);
std::swap(fixture->program.block_info[0], fixture->program.block_info[1]);
fixture->PlanAndTrack();
auto plan = ExtractResourcePlan(fixture->program);
std::array<uint32_t, 9> user_data{