blob: aab993ba296ee7bb6f0d1aa20157e9a8ced475e1 [file] [log] [blame]
/*
* Copyright © 2010 Intel Corporation
* SPDX-License-Identifier: MIT
*/
#include <inttypes.h>
#include "brw_reg.h"
#include "util/macros.h"
bool
brw_reg_saturate_immediate(brw_reg *reg)
{
union {
unsigned ud;
int d;
float f;
double df;
} imm, sat_imm = { 0 };
const unsigned size = brw_type_size_bytes(reg->type);
/* We want to either do a 32-bit or 64-bit data copy, the type is otherwise
* irrelevant, so just check the size of the type and copy from/to an
* appropriately sized field.
*/
if (size < 8)
imm.ud = reg->ud;
else
imm.df = reg->df;
switch (reg->type) {
case BRW_TYPE_UD:
case BRW_TYPE_D:
case BRW_TYPE_UW:
case BRW_TYPE_W:
case BRW_TYPE_UQ:
case BRW_TYPE_Q:
/* Nothing to do. */
return false;
case BRW_TYPE_F:
sat_imm.f = SATURATE(imm.f);
break;
case BRW_TYPE_DF:
sat_imm.df = SATURATE(imm.df);
break;
case BRW_TYPE_UB:
case BRW_TYPE_B:
unreachable("no UB/B immediates");
case BRW_TYPE_V:
case BRW_TYPE_UV:
case BRW_TYPE_VF:
unreachable("unimplemented: saturate vector immediate");
case BRW_TYPE_HF:
unreachable("unimplemented: saturate HF immediate");
default:
unreachable("invalid type");
}
if (size < 8) {
if (imm.ud != sat_imm.ud) {
reg->ud = sat_imm.ud;
return true;
}
} else {
if (imm.df != sat_imm.df) {
reg->df = sat_imm.df;
return true;
}
}
return false;
}
bool
brw_reg_negate_immediate(brw_reg *reg)
{
switch (reg->type) {
case BRW_TYPE_D:
case BRW_TYPE_UD:
reg->d = -reg->d;
return true;
case BRW_TYPE_W:
case BRW_TYPE_UW: {
uint16_t value = -(int16_t)reg->ud;
reg->ud = value | (uint32_t)value << 16;
return true;
}
case BRW_TYPE_F:
reg->f = -reg->f;
return true;
case BRW_TYPE_VF:
reg->ud ^= 0x80808080;
return true;
case BRW_TYPE_DF:
reg->df = -reg->df;
return true;
case BRW_TYPE_UQ:
case BRW_TYPE_Q:
reg->d64 = -reg->d64;
return true;
case BRW_TYPE_UB:
case BRW_TYPE_B:
unreachable("no UB/B immediates");
case BRW_TYPE_UV:
case BRW_TYPE_V:
assert(!"unimplemented: negate UV/V immediate");
case BRW_TYPE_HF:
reg->ud ^= 0x80008000;
return true;
default:
unreachable("invalid type");
}
return false;
}
bool
brw_reg_abs_immediate(brw_reg *reg)
{
switch (reg->type) {
case BRW_TYPE_D:
reg->d = abs(reg->d);
return true;
case BRW_TYPE_W: {
uint16_t value = abs((int16_t)reg->ud);
reg->ud = value | (uint32_t)value << 16;
return true;
}
case BRW_TYPE_F:
reg->f = fabsf(reg->f);
return true;
case BRW_TYPE_DF:
reg->df = fabs(reg->df);
return true;
case BRW_TYPE_VF:
reg->ud &= ~0x80808080;
return true;
case BRW_TYPE_Q:
reg->d64 = imaxabs(reg->d64);
return true;
case BRW_TYPE_UB:
case BRW_TYPE_B:
unreachable("no UB/B immediates");
case BRW_TYPE_UQ:
case BRW_TYPE_UD:
case BRW_TYPE_UW:
case BRW_TYPE_UV:
/* Presumably the absolute value modifier on an unsigned source is a
* nop, but it would be nice to confirm.
*/
assert(!"unimplemented: abs unsigned immediate");
case BRW_TYPE_V:
assert(!"unimplemented: abs V immediate");
case BRW_TYPE_HF:
reg->ud &= ~0x80008000;
return true;
default:
unreachable("invalid type");
}
return false;
}
bool
brw_reg::is_zero() const
{
if (file != IMM)
return false;
assert(brw_type_size_bytes(type) > 1);
switch (type) {
case BRW_TYPE_HF:
assert((d & 0xffff) == ((d >> 16) & 0xffff));
return (d & 0xffff) == 0 || (d & 0xffff) == 0x8000;
case BRW_TYPE_F:
return f == 0;
case BRW_TYPE_DF:
return df == 0;
case BRW_TYPE_W:
case BRW_TYPE_UW:
assert((d & 0xffff) == ((d >> 16) & 0xffff));
return (d & 0xffff) == 0;
case BRW_TYPE_D:
case BRW_TYPE_UD:
return d == 0;
case BRW_TYPE_UQ:
case BRW_TYPE_Q:
return u64 == 0;
default:
return false;
}
}
bool
brw_reg::is_one() const
{
if (file != IMM)
return false;
assert(brw_type_size_bytes(type) > 1);
switch (type) {
case BRW_TYPE_HF:
assert((d & 0xffff) == ((d >> 16) & 0xffff));
return (d & 0xffff) == 0x3c00;
case BRW_TYPE_F:
return f == 1.0f;
case BRW_TYPE_DF:
return df == 1.0;
case BRW_TYPE_W:
case BRW_TYPE_UW:
assert((d & 0xffff) == ((d >> 16) & 0xffff));
return (d & 0xffff) == 1;
case BRW_TYPE_D:
case BRW_TYPE_UD:
return d == 1;
case BRW_TYPE_UQ:
case BRW_TYPE_Q:
return u64 == 1;
default:
return false;
}
}
bool
brw_reg::is_negative_one() const
{
if (file != IMM)
return false;
assert(brw_type_size_bytes(type) > 1);
switch (type) {
case BRW_TYPE_HF:
assert((d & 0xffff) == ((d >> 16) & 0xffff));
return (d & 0xffff) == 0xbc00;
case BRW_TYPE_F:
return f == -1.0;
case BRW_TYPE_DF:
return df == -1.0;
case BRW_TYPE_W:
assert((d & 0xffff) == ((d >> 16) & 0xffff));
return (d & 0xffff) == 0xffff;
case BRW_TYPE_D:
return d == -1;
case BRW_TYPE_Q:
return d64 == -1;
default:
return false;
}
}
bool
brw_reg::is_null() const
{
return file == ARF && nr == BRW_ARF_NULL;
}
bool
brw_reg::is_accumulator() const
{
return file == ARF && (nr & 0xF0) == BRW_ARF_ACCUMULATOR;
}
bool
brw_reg::is_address() const
{
return file == ADDRESS;
}
unsigned
brw_reg::address_slot(unsigned byte_offset) const
{
assert(is_address());
return (reg_offset(*this) + byte_offset) / 2;
}
bool
brw_reg::equals(const brw_reg &r) const
{
return brw_regs_equal(this, &r);
}
bool
brw_reg::negative_equals(const brw_reg &r) const
{
return brw_regs_negative_equal(this, &r);
}
bool
brw_reg::is_contiguous() const
{
switch (file) {
case ADDRESS:
case ARF:
case FIXED_GRF:
return hstride == BRW_HORIZONTAL_STRIDE_1 &&
vstride == width + hstride;
case VGRF:
case ATTR:
return stride == 1;
case UNIFORM:
case IMM:
case BAD_FILE:
return true;
}
unreachable("Invalid register file");
}
unsigned
brw_reg::component_size(unsigned width) const
{
if (file == ADDRESS || file == ARF || file == FIXED_GRF) {
const unsigned w = MIN2(width, 1u << this->width);
const unsigned h = width >> this->width;
const unsigned vs = vstride ? 1 << (vstride - 1) : 0;
const unsigned hs = hstride ? 1 << (hstride - 1) : 0;
assert(w > 0);
/* Note this rounds up to next horizontal stride to be consistent with
* the VGRF case below.
*/
return ((MAX2(1, h) - 1) * vs + MAX2(w * hs, 1)) * brw_type_size_bytes(type);
} else {
return MAX2(width * stride, 1) * brw_type_size_bytes(type);
}
}