Commit 1afc50aa authored by Daniel Schürmann's avatar Daniel Schürmann
Browse files

aco: write new pass to propagate WQM flags

parent 1ef326fb
Pipeline #261706 waiting for manual action with stages
/*
* Copyright © 2019 Valve Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "aco_ir.h"
/** This pass propagates WQM information:
* If a variable has to be computed in WQM,
* all operands of that instruction also
* have to be computed in WQM
*/
namespace aco {
namespace {
struct wqm_ctx {
Program* program;
/* state for WQM propagation */
std::vector<bool> needs_wqm;
std::vector<bool> worklist;
wqm_ctx(Program* program_) : program(program_),
needs_wqm(program->peekAllocationId()),
worklist(program->blocks.size(), false)
{}
};
void propagate_worklist(wqm_ctx& ctx, unsigned idx)
{
if (ctx.worklist[idx])
return;
ctx.worklist[idx] = true;
for (unsigned pred : ctx.program->blocks[idx].logical_preds)
propagate_worklist(ctx, pred);
}
bool propagate_wqm_instr(std::vector<bool>& needs_wqm, aco_ptr<Instruction>& instr)
{
bool propagate = false;
for (const Operand& op : instr->operands) {
if (!op.isTemp() || needs_wqm[op.tempId()])
continue;
needs_wqm[op.tempId()] = true;
propagate = true;
}
return propagate;
}
void propagate_wqm_block(wqm_ctx& ctx, Block& block)
{
bool propagate_wqm = false;
for (int i = block->instructions.size() - 1; i >= 0; --i) {
aco_ptr<Instruction>& instr = block->instructions[i];
bool propagate = false;
for (const Definition& definition : instr->definitions) {
if (!definition.isTemp())
continue;
const unsigned def = definition.tempId();
ctx.needs_wqm[def] |= definition.needsWQM();
if (ctx.needs_wqm[def]) {
definition.setWQM(needs_exec_mask(instr.get()));
propagate = true;
}
}
if (propagate)
propagate_wqm |= propagate_wqm_instr(ctx.needs_wqm, instr);
}
if (propagate_wqm) {
for (unsigned pred : program->blocks[block.index].logical_preds)
propagate_worklist(ctx, pred);
}
}
bool get_next_block(std::vector<bool> worklist, unsigned* next)
{
std::vector<bool>::reverse_iterator it = std::find_if(worklist.rbegin(),
worklist.rend(), true);
if (it == worklist.rend())
return false;
*next = std::distance(it, std::prev(worklist.rend()));
*it = false;
return true;
}
} /* end namespace */
void propagate_wqm(Program* program)
{
wqm_ctx ctx(program);
propagate_worklist(ctx, program->blocks.size() - 1);
unsigned next = 0;
while (get_next_block(worklist, next)) {
propagate_wqm_block(ctx, program->blocks[next]);
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment