| /* |
| * 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); |
| } |
| } |