blob: bc4a0a59e655b835a907baf352536cc0b2719e9e [file] [log] [blame]
/* -*- mesa-c++ -*-
*
* Copyright (c) 2018-2019 Collabora LTD
*
* Author: Gert Wollny <gert.wollny@collabora.com>
*
* 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
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS 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 "sfn_value_gpr.h"
#include "sfn_valuepool.h"
#include "sfn_debug.h"
#include "sfn_liverange.h"
namespace r600 {
using std::vector;
using std::array;
GPRValue::GPRValue(uint32_t sel, uint32_t chan, int base_offset):
Value(Value::gpr, chan),
m_sel(sel),
m_base_offset(base_offset),
m_input(false)
{
}
GPRValue::GPRValue(uint32_t sel, uint32_t chan):
Value(Value::gpr, chan),
m_sel(sel),
m_base_offset(0),
m_input(false)
{
}
uint32_t GPRValue::sel() const
{
return m_sel;
}
void GPRValue::do_print(std::ostream& os) const
{
os << 'R';
os << m_sel;
os << '.' << component_names[chan()];
}
bool GPRValue::is_equal_to(const Value& other) const
{
assert(other.type() == Value::Type::gpr);
const auto& rhs = static_cast<const GPRValue&>(other);
return (sel() == rhs.sel() &&
chan() == rhs.chan());
}
void GPRValue::do_print(std::ostream& os, UNUSED const PrintFlags& flags) const
{
os << 'R';
os << m_sel;
os << '.' << component_names[chan()];
}
GPRVector::GPRVector(const GPRVector& orig):
Value(gpr_vector),
m_elms(orig.m_elms),
m_valid(orig.m_valid)
{
}
GPRVector::GPRVector(std::array<PValue,4> elms):
Value(gpr_vector),
m_elms(elms),
m_valid(false)
{
for (unsigned i = 0; i < 4; ++i)
if (!m_elms[i] || (m_elms[i]->type() != Value::gpr)) {
assert(0 && "GPR vector not valid because element missing or nit a GPR");
return;
}
unsigned sel = m_elms[0]->sel();
for (unsigned i = 1; i < 4; ++i)
if (m_elms[i]->sel() != sel) {
assert(0 && "GPR vector not valid because sel is not equal for all elements");
return;
}
m_valid = true;
}
GPRVector::GPRVector(uint32_t sel, std::array<uint32_t,4> swizzle):
Value (gpr_vector),
m_valid(true)
{
for (int i = 0; i < 4; ++i)
m_elms[i] = PValue(new GPRValue(sel, swizzle[i]));
}
GPRVector::GPRVector(const GPRVector& orig, const std::array<uint8_t,4>& swizzle)
{
for (int i = 0; i < 4; ++i)
m_elms[i] = orig.reg_i(swizzle[i]);
m_valid = orig.m_valid;
}
void GPRVector::validate() const
{
assert(m_elms[0]);
uint32_t sel = m_elms[0]->sel();
if (sel >= 124)
return;
for (unsigned i = 1; i < 4; ++i) {
assert(m_elms[i]);
if (sel != m_elms[i]->sel())
return;
}
m_valid = true;
}
uint32_t GPRVector::sel() const
{
validate();
assert(m_valid);
return m_elms[0] ? m_elms[0]->sel() : 999;
}
void GPRVector::set_reg_i(int i, PValue reg)
{
m_elms[i] = reg;
}
void GPRVector::pin_to_channel(int i)
{
auto& v = static_cast<GPRValue&>(*m_elms[i]);
v.set_pin_to_channel();
}
void GPRVector::do_print(std::ostream& os) const
{
os << "R" << sel() << ".";
for (int i = 0; i < 4; ++i)
os << (m_elms[i] ? component_names[m_elms[i]->chan() < 8 ? m_elms[i]->chan() : 8] : '?');
}
void GPRVector::swizzle(const Swizzle& swz)
{
Values v(m_elms);
for (uint32_t i = 0; i < 4; ++i)
if (i != swz[i]) {
assert(swz[i] < 4);
m_elms[i] = v[swz[i]];
}
}
bool GPRVector::is_equal_to(const Value& other) const
{
if (other.type() != gpr_vector) {
std::cerr << "t";
return false;
}
const GPRVector& o = static_cast<const GPRVector&>(other);
for (int i = 0; i < 4; ++i) {
if (*m_elms[i] != *o.m_elms[i]) {
std::cerr << "elm" << i;
return false;
}
}
return true;
}
GPRArrayValue::GPRArrayValue(PValue value, PValue addr, GPRArray *array):
Value(gpr_array_value, value->chan()),
m_value(value),
m_addr(addr),
m_array(array)
{
}
GPRArrayValue::GPRArrayValue(PValue value, GPRArray *array):
Value(gpr_array_value, value->chan()),
m_value(value),
m_array(array)
{
}
static const char *swz_char = "xyzw01_";
void GPRArrayValue::do_print(std::ostream& os) const
{
assert(m_array);
os << "R" << m_value->sel();
if (m_addr) {
os << "[" << *m_addr << "] ";
}
os << swz_char[m_value->chan()];
os << "(" << *m_array << ")";
}
bool GPRArrayValue::is_equal_to(const Value& other) const
{
const GPRArrayValue& v = static_cast<const GPRArrayValue&>(other);
return *m_value == *v.m_value &&
*m_array == *v.m_array;
}
void GPRArrayValue::record_read(LiverangeEvaluator& ev) const
{
if (m_addr) {
ev.record_read(*m_addr);
unsigned chan = m_value->chan();
assert(m_array);
m_array->record_read(ev, chan);
} else
ev.record_read(*m_value);
}
void GPRArrayValue::record_write(LiverangeEvaluator& ev) const
{
if (m_addr) {
ev.record_read(*m_addr);
unsigned chan = m_value->chan();
assert(m_array);
m_array->record_write(ev, chan);
} else
ev.record_write(*m_value);
}
void GPRArrayValue::reset_value(PValue new_value)
{
m_value = new_value;
}
void GPRArrayValue::reset_addr(PValue new_addr)
{
m_addr = new_addr;
}
GPRArray::GPRArray(int base, int size, int mask, int frac):
Value (gpr_vector),
m_base_index(base),
m_component_mask(mask),
m_frac(frac)
{
m_values.resize(size);
for (int i = 0; i < size; ++i) {
for (int j = 0; j < 4; ++j) {
if (mask & (1 << j))
m_values[i].set_reg_i(j, PValue(new GPRValue(base + i, j)));
}
}
}
uint32_t GPRArray::sel() const
{
return m_base_index;
}
static const char *compchar = "xyzw";
void GPRArray::do_print(std::ostream& os) const
{
os << "ARRAY[R" << sel() << "..R" << sel() + m_values.size() - 1 << "].";
for (int j = 0; j < 4; ++j) {
if (m_component_mask & (1 << j))
os << compchar[j];
}
}
bool GPRArray::is_equal_to(const Value& other) const
{
const GPRArray& o = static_cast<const GPRArray&>(other);
return o.sel() == sel() &&
o.m_values.size() == m_values.size() &&
o.m_component_mask == m_component_mask;
}
uint32_t GPRArrayValue::sel() const
{
return m_value->sel();
}
PValue GPRArray::get_indirect(unsigned index, PValue indirect, unsigned component)
{
assert(index < m_values.size());
assert(m_component_mask & (1 << (component + m_frac)));
sfn_log << SfnLog::reg << "Create indirect register from " << *this;
PValue v = m_values[index].reg_i(component + m_frac);
assert(v);
sfn_log << SfnLog::reg << " -> " << *v;
if (indirect) {
sfn_log << SfnLog::reg << "[" << *indirect << "]";
switch (indirect->type()) {
case Value::literal: {
const LiteralValue& lv = static_cast<const LiteralValue&>(*indirect);
v = m_values[lv.value()].reg_i(component + m_frac);
break;
}
case Value::gpr: {
v = PValue(new GPRArrayValue(v, indirect, this));
sfn_log << SfnLog::reg << "(" << *v << ")";
break;
}
default:
assert(0 && !"Indirect addressing must be literal value or GPR");
}
}
sfn_log << SfnLog::reg <<" -> " << *v << "\n";
return v;
}
void GPRArray::record_read(LiverangeEvaluator& ev, int chan) const
{
for (auto& v: m_values)
ev.record_read(*v.reg_i(chan), true);
}
void GPRArray::record_write(LiverangeEvaluator& ev, int chan) const
{
for (auto& v: m_values)
ev.record_write(*v.reg_i(chan), true);
}
void GPRArray::collect_registers(ValueMap& output) const
{
for (auto& v: m_values) {
for (int i = 0; i < 4; ++i) {
auto vv = v.reg_i(i);
if (vv)
output.insert(vv);
}
}
}
}