Carl Love 79c80505d3 Add ISA 2.07 vbit test support
The ISA 2.07 support adds new Iops as well as support for some existing
Iops.  None of these Iops have been enabled in the vbit tester.  This commit
adds the needed support to the files in memcheck/tests/vbit-test.   
These changes add support for additional immediate operands and additional
undefined bit checking functions.

There are additional changes to files VEX/priv/ir_inject.c and VEX/pub/libvex.h
that are in VEX commit 3202

Bugzilla 354797 was created for this issue.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15720
2015-11-03 17:48:04 +00:00

1075 lines
30 KiB
C

/* -*- mode: C; c-basic-offset: 3; -*- */
/*
This file is part of MemCheck, a heavyweight Valgrind tool for
detecting memory errors.
Copyright (C) 2012-2015 Florian Krohm
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307, USA.
The GNU General Public License is contained in the file COPYING.
*/
#include <stdio.h> // fprintf
#include <assert.h> // assert
#if defined(__APPLE__)
#include <machine/endian.h>
#define __BYTE_ORDER BYTE_ORDER
#define __LITTLE_ENDIAN LITTLE_ENDIAN
#elif defined(__sun)
#define __LITTLE_ENDIAN 1234
#define __BIG_ENDIAN 4321
# if defined(_LITTLE_ENDIAN)
# define __BYTE_ORDER __LITTLE_ENDIAN
# else
# define __BYTE_ORDER __BIG_ENDIAN
# endif
#else
#include <endian.h>
#endif
#include <inttypes.h>
#include "vbits.h"
#include "vtest.h"
/* Return the bits of V if they fit into 64-bit. If V has fewer than
64 bits, the bit pattern is zero-extended to the left. */
static uint64_t
get_bits64(vbits_t v)
{
switch (v.num_bits) {
case 1: return v.bits.u32;
case 8: return v.bits.u8;
case 16: return v.bits.u16;
case 32: return v.bits.u32;
case 64: return v.bits.u64;
case 128:
case 256:
/* fall through */
default:
panic(__func__);
}
}
void
print_vbits(FILE *fp, vbits_t v)
{
switch (v.num_bits) {
case 1: fprintf(fp, "%08x", v.bits.u32); break;
case 8: fprintf(fp, "%02x", v.bits.u8); break;
case 16: fprintf(fp, "%04x", v.bits.u16); break;
case 32: fprintf(fp, "%08x", v.bits.u32); break;
case 64: fprintf(fp, "%016"PRIx64, v.bits.u64); break;
case 128:
if (__BYTE_ORDER == __LITTLE_ENDIAN) {
fprintf(fp, "%016"PRIx64, v.bits.u128[1]);
fprintf(fp, "%016"PRIx64, v.bits.u128[0]);
} else {
fprintf(fp, "%016"PRIx64, v.bits.u128[0]);
fprintf(fp, "%016"PRIx64, v.bits.u128[1]);
}
break;
case 256:
if (__BYTE_ORDER == __LITTLE_ENDIAN) {
fprintf(fp, "%016"PRIx64, v.bits.u256[3]);
fprintf(fp, "%016"PRIx64, v.bits.u256[2]);
fprintf(fp, "%016"PRIx64, v.bits.u256[1]);
fprintf(fp, "%016"PRIx64, v.bits.u256[0]);
} else {
fprintf(fp, "%016"PRIx64, v.bits.u256[0]);
fprintf(fp, "%016"PRIx64, v.bits.u256[1]);
fprintf(fp, "%016"PRIx64, v.bits.u256[2]);
fprintf(fp, "%016"PRIx64, v.bits.u256[3]);
}
break;
default:
panic(__func__);
}
}
/* Return a value where all bits are set to undefined. */
vbits_t
undefined_vbits(unsigned num_bits)
{
vbits_t new = { .num_bits = num_bits };
switch (num_bits) {
case 1: new.bits.u32 = 0x01; break;
case 8: new.bits.u8 = 0xff; break;
case 16: new.bits.u16 = 0xffff; break;
case 32: new.bits.u32 = ~0; break;
case 64: new.bits.u64 = ~0ull; break;
case 128: new.bits.u128[0] = ~0ull;
new.bits.u128[1] = ~0ull;
break;
case 256: new.bits.u256[0] = ~0ull;
new.bits.u256[1] = ~0ull;
new.bits.u256[2] = ~0ull;
new.bits.u256[3] = ~0ull;
break;
default:
panic(__func__);
}
return new;
}
/* The following routines named undefined_vbits_BxE() return a 128-bit
* vector with E elements each of size bits. If any of the bits in an
* element is undefined, then return a value where all bits in that
* element are undefined.
*/
vbits_t
undefined_vbits_BxE(unsigned int bits, unsigned int elements, vbits_t v)
{
vbits_t new = { .num_bits = v.num_bits };
uint64_t mask = ~0ull >> (64 - bits);
int i, j;
assert ((elements % 2) == 0);
assert (bits <= 64);
for (i = 0; i<2; i++) {
new.bits.u128[i] = 0ull;
for (j = 0; j<elements/2; j++) {
if ((v.bits.u128[i] & (mask << (j*bits))) != 0)
new.bits.u128[i] |= (mask << (j*bits));
}
}
return new;
}
/* The following routines named undefined_vbits_BxE_rotate() return a 128-bit
* vector with E elements each of size bits. The bits in v are rotated
* left by the amounts in the corresponding element of val. Specified rotate
* amount field is assumed to be at most 8-bits wide.
*/
vbits_t
undefined_vbits_BxE_rotate(unsigned int bits, unsigned int elements,
vbits_t v, value_t val)
{
vbits_t new = { .num_bits = v.num_bits };
uint64_t mask = ~0ull >> (64 - bits);
uint64_t const shift_mask = 0xFF;
uint64_t element;
int i, j;
signed char shift;
assert ((elements % 2) == 0);
assert (bits <= 64);
for (i = 0; i<2; i++) {
new.bits.u128[i] = 0ull;
for (j = 0; j<elements/2; j++) {
element = (v.bits.u128[i] >> (j*bits)) & mask;
shift = (int)((val.u128[i] >> (j*bits)) & shift_mask);
if (shift < 0) {
/* right shift */
new.bits.u128[i] = element >> -shift;
/* OR in the bits shifted out into the top of the element */
new.bits.u128[i] |= element << (bits + shift);
} else {
/* left shift */
/* upper bits from shift */
new.bits.u128[i] = element << shift;
/* OR in the bits shifted out into the bottom of the element */
new.bits.u128[i] |= element >> (bits - shift);
}
}
}
return new;
}
/* Only the even elements of the input are used by the Iop*/
vbits_t
undefined_vbits_128_even_element(unsigned int bits, unsigned int elements,
vbits_t v)
{
int i;
uint64_t mask;
unsigned int const element_width = 128/elements;
vbits_t new = { .num_bits = v.num_bits };
assert ((elements % 2) == 0);
assert (bits <= 64);
/* Create a 128-bit mask with the bits in the even numbered
* elements are all ones.
*/
mask = ~0ull >> (64 - bits);
for (i = 2; i < elements/2; i=i+2) {
mask |= mask << (i * element_width);
}
new.bits.u128[0] = mask & v.bits.u128[0];
new.bits.u128[1] = mask & v.bits.u128[1];
return new;
}
/* Concatenate bit i from each byte j. Place concatenated 8 bit value into
* byte i of the result. Do for all i from 0 to 7 and j from 0 to 7 of each
* 64-bit element.
*/
vbits_t
undefined_vbits_64x2_transpose(vbits_t v)
{
vbits_t new = { .num_bits = v.num_bits };
unsigned int bit, byte, element;
uint64_t value, new_value, select_bit;
for (element = 0; element < 2; element++) {
value = v.bits.u128[element];
new_value = 0;
for (byte = 0; byte < 8; byte++) {
for (bit = 0; bit < 8; bit++) {
select_bit = 1ULL & (value >> (bit + 8*byte));
new_value |= select_bit << (bit*8 + byte);
}
}
new.bits.u128[element] = new_value;
}
return new;
}
/* The routine takes a 256-bit vector value stored across the two 128-bit
* source operands src1 and src2. The size of each element in the input is
* src_num_bits. The elements are narrowed to result_num_bits and packed
* into the result. If saturate is True, then the all the result bits are
* set to 1 if the source element can not be represented in result_num_bits.
*/
vbits_t
undefined_vbits_Narrow256_AtoB(unsigned int src_num_bits,
unsigned int result_num_bits,
vbits_t src1_v, value_t src1_value,
vbits_t src2_v, value_t src2_value,
bool saturate)
{
vbits_t new = { .num_bits = src1_v.num_bits };
unsigned int i;
uint64_t vbits, new_value;
uint64_t const src_mask = ~0x0ULL >> (64 - src_num_bits);
uint64_t const result_mask = ~0x0ULL >> (64 - result_num_bits);
unsigned int num_elements_per_64_bits = src_num_bits/64;
unsigned int shift;
/*
* NOTE: POWER PPC
* the saturated value is 0xFFFF for the vbit is in one of the lower
* 32-bits of the source. The saturated result is 0xFFFF0000 if the
* vbit is in the upper 32-bits of the source. Not sure what
* the saturated result is in general for a B-bit result.
*
* ONLY TESTED FOR 64 bit input, 32 bit result
*/
uint64_t const saturated_result = 0xFFFFULL;
/* Source elements are split between the two source operands */
assert(src_num_bits <= 64);
assert(result_num_bits < 64);
assert(result_num_bits < src_num_bits);
/* Narrow the elements from src1 to the upper 64-bits of result.
* Do each of the 64 bit values that make up a u128
*/
new_value = 0;
for (i = 0; i < num_elements_per_64_bits; i++) {
vbits = src1_v.bits.u128[0] >> (i * src_num_bits);
vbits &= src_mask;
shift = result_num_bits * i;
if (vbits) {
if (saturate) {
/* Value will not fit in B-bits, saturate the result as needed. */
if (vbits >> (src_num_bits/2))
/* vbit is upper half of the source */
new_value |= saturated_result << ( shift + result_num_bits/2);
else
new_value |= saturated_result << shift;
} else {
new_value |= (vbits & result_mask) << shift;
}
}
}
for (i = 0; i < num_elements_per_64_bits; i++) {
vbits = src1_v.bits.u128[1] >> (i * src_num_bits);
vbits &= src_mask;
shift = result_num_bits * i + (num_elements_per_64_bits
* result_num_bits);
if (vbits) {
if (saturate) {
/* Value will not fit in result_num_bits, saturate the result
* as needed.
*/
if (vbits >> (src_num_bits/2))
/* vbit is upper half of the source */
new_value |= saturated_result << (shift + result_num_bits/2);
else
new_value |= saturated_result << shift;
} else {
new_value |= (vbits & result_mask) << shift;
}
}
}
if (__BYTE_ORDER == __LITTLE_ENDIAN)
new.bits.u128[1] = new_value;
else
/* Big endian, swap the upper and lower 32-bits of new_value */
new.bits.u128[0] = (new_value << 32) | (new_value >> 32);
new_value = 0;
/* Narrow the elements from src2 to the lower 64-bits of result.
* Do each of the 64 bit values that make up a u128
*/
for (i = 0; i < num_elements_per_64_bits; i++) {
vbits = src2_v.bits.u128[0] >> (i * src_num_bits);
vbits &= src_mask;
shift = result_num_bits * i;
if (vbits) {
if (saturate) {
/* Value will not fit in result, saturate the result as needed. */
if (vbits >> (src_num_bits/2))
/* vbit is upper half of the source */
new_value |= saturated_result << (shift + result_num_bits/2);
else
new_value |= saturated_result << shift;
} else {
new_value |= (vbits & result_mask) << shift;
}
}
}
for (i = 0; i < num_elements_per_64_bits; i++) {
vbits = src2_v.bits.u128[1] >> (i * src_num_bits);
vbits &= src_mask;
if (vbits) {
if (saturate) {
/* Value will not fit in result_num_bits, saturate the result
* as needed.
*/
if (vbits >> (src_num_bits/2))
/* vbit is upper half of the source */
new_value |= saturated_result << (result_num_bits * i
+ result_num_bits/2
+ (num_elements_per_64_bits
* result_num_bits));
else
new_value |= saturated_result << (result_num_bits * i
+ (num_elements_per_64_bits
* result_num_bits));
} else {
new_value |= (vbits & result_mask) << (result_num_bits * i
+ (num_elements_per_64_bits
* result_num_bits));
}
}
}
if (__BYTE_ORDER == __LITTLE_ENDIAN)
new.bits.u128[0] = new_value;
else
/* Big endian, swap the upper and lower 32-bits of new_value */
new.bits.u128[1] = (new_value << 32) | (new_value >> 32);
return new;
}
/* Return a value where all bits are set to defined. */
vbits_t
defined_vbits(unsigned num_bits)
{
vbits_t new = { .num_bits = num_bits };
switch (num_bits) {
case 1: new.bits.u32 = 0x0; break;
case 8: new.bits.u8 = 0x0; break;
case 16: new.bits.u16 = 0x0; break;
case 32: new.bits.u32 = 0x0; break;
case 64: new.bits.u64 = 0x0; break;
case 128: new.bits.u128[0] = 0x0;
new.bits.u128[1] = 0x0;
break;
case 256: new.bits.u256[0] = 0x0;
new.bits.u256[1] = 0x0;
new.bits.u256[2] = 0x0;
new.bits.u256[3] = 0x0;
break;
default:
panic(__func__);
}
return new;
}
/* Return 1, if equal. */
int
equal_vbits(vbits_t v1, vbits_t v2)
{
assert(v1.num_bits == v2.num_bits);
switch (v1.num_bits) {
case 1: return v1.bits.u32 == v2.bits.u32;
case 8: return v1.bits.u8 == v2.bits.u8;
case 16: return v1.bits.u16 == v2.bits.u16;
case 32: return v1.bits.u32 == v2.bits.u32;
case 64: return v1.bits.u64 == v2.bits.u64;
case 128: return v1.bits.u128[0] == v2.bits.u128[0] &&
v1.bits.u128[1] == v2.bits.u128[1];
case 256: return v1.bits.u256[0] == v2.bits.u256[0] &&
v1.bits.u256[1] == v2.bits.u256[1] &&
v1.bits.u256[2] == v2.bits.u256[2] &&
v1.bits.u256[3] == v2.bits.u256[3];
default:
panic(__func__);
}
}
/* Truncate the bit pattern in V1 to NUM_BITS bits */
vbits_t
truncate_vbits(vbits_t v, unsigned num_bits)
{
assert(num_bits <= v.num_bits);
if (num_bits == v.num_bits) return v;
vbits_t new = { .num_bits = num_bits };
if (num_bits <= 64) {
uint64_t bits;
if (v.num_bits <= 64)
bits = get_bits64(v);
else if (v.num_bits == 128)
if (__BYTE_ORDER == __LITTLE_ENDIAN)
bits = v.bits.u128[0];
else
bits = v.bits.u128[1];
else if (v.num_bits == 256)
if (__BYTE_ORDER == __LITTLE_ENDIAN)
bits = v.bits.u256[0];
else
bits = v.bits.u256[3];
else
panic(__func__);
switch (num_bits) {
case 1: new.bits.u32 = bits & 0x01; break;
case 8: new.bits.u8 = bits & 0xff; break;
case 16: new.bits.u16 = bits & 0xffff; break;
case 32: new.bits.u32 = bits & ~0u; break;
case 64: new.bits.u64 = bits & ~0ll; break;
default:
panic(__func__);
}
return new;
}
if (num_bits == 128) {
assert(v.num_bits == 256);
/* From 256 bits to 128 */
if (__BYTE_ORDER == __LITTLE_ENDIAN) {
new.bits.u128[0] = v.bits.u256[0];
new.bits.u128[1] = v.bits.u256[1];
} else {
new.bits.u128[0] = v.bits.u256[2];
new.bits.u128[1] = v.bits.u256[3];
}
return new;
}
/* Cannot truncate to 256 bits from something larger */
panic(__func__);
}
/* Helper function to compute left_vbits */
static uint64_t
left64(uint64_t x)
{
// left(x) = x | -x
return x | (~x + 1);
}
vbits_t
left_vbits(vbits_t v, unsigned num_bits)
{
assert(num_bits >= v.num_bits);
vbits_t new = { .num_bits = num_bits };
if (v.num_bits <= 64) {
uint64_t bits = left64(get_bits64(v));
switch (num_bits) {
case 8: new.bits.u8 = bits & 0xff; break;
case 16: new.bits.u16 = bits & 0xffff; break;
case 32: new.bits.u32 = bits & ~0u; break;
case 64: new.bits.u64 = bits & ~0ll; break;
case 128:
if (__BYTE_ORDER == __LITTLE_ENDIAN) {
new.bits.u128[0] = bits;
if (bits & (1ull << 63)) { // MSB is set
new.bits.u128[1] = ~0ull;
} else {
new.bits.u128[1] = 0;
}
} else {
new.bits.u128[1] = bits;
if (bits & (1ull << 63)) { // MSB is set
new.bits.u128[0] = ~0ull;
} else {
new.bits.u128[0] = 0;
}
}
break;
case 256:
if (__BYTE_ORDER == __LITTLE_ENDIAN) {
new.bits.u256[0] = bits;
if (bits & (1ull << 63)) { // MSB is set
new.bits.u256[1] = ~0ull;
new.bits.u256[2] = ~0ull;
new.bits.u256[3] = ~0ull;
} else {
new.bits.u256[1] = 0;
new.bits.u256[2] = 0;
new.bits.u256[3] = 0;
}
} else {
new.bits.u256[3] = bits;
if (bits & (1ull << 63)) { // MSB is set
new.bits.u256[0] = ~0ull;
new.bits.u256[1] = ~0ull;
new.bits.u256[2] = ~0ull;
} else {
new.bits.u256[0] = 0;
new.bits.u256[1] = 0;
new.bits.u256[2] = 0;
}
}
break;
default:
panic(__func__);
}
return new;
}
if (v.num_bits == 128) {
if (__BYTE_ORDER == __LITTLE_ENDIAN) {
if (v.bits.u128[1] != 0) {
new.bits.u128[0] = v.bits.u128[0];
new.bits.u128[1] = left64(v.bits.u128[1]);
} else {
new.bits.u128[0] = left64(v.bits.u128[0]);
if (new.bits.u128[0] & (1ull << 63)) { // MSB is set
new.bits.u128[1] = ~0ull;
} else {
new.bits.u128[1] = 0;
}
}
} else {
if (v.bits.u128[0] != 0) {
new.bits.u128[0] = left64(v.bits.u128[0]);
new.bits.u128[1] = v.bits.u128[1];
} else {
new.bits.u128[1] = left64(v.bits.u128[1]);
if (new.bits.u128[1] & (1ull << 63)) { // MSB is set
new.bits.u128[0] = ~0ull;
} else {
new.bits.u128[0] = 0;
}
}
}
if (num_bits == 128) return new;
assert(num_bits == 256);
if (__BYTE_ORDER == __LITTLE_ENDIAN) {
uint64_t b1 = new.bits.u128[1];
uint64_t b0 = new.bits.u128[0];
new.bits.u256[0] = b0;
new.bits.u256[1] = b1;
if (new.bits.u256[1] & (1ull << 63)) { // MSB is set
new.bits.u256[2] = ~0ull;
new.bits.u256[3] = ~0ull;
} else {
new.bits.u256[2] = 0;
new.bits.u256[3] = 0;
}
} else {
uint64_t b1 = new.bits.u128[0];
uint64_t b0 = new.bits.u128[1];
new.bits.u256[2] = b0;
new.bits.u256[3] = b1;
if (new.bits.u256[2] & (1ull << 63)) { // MSB is set
new.bits.u256[0] = ~0ull;
new.bits.u256[1] = ~0ull;
} else {
new.bits.u256[0] = 0;
new.bits.u256[1] = 0;
}
}
return new;
}
panic(__func__);
}
vbits_t
or_vbits(vbits_t v1, vbits_t v2)
{
assert(v1.num_bits == v2.num_bits);
vbits_t new = { .num_bits = v1.num_bits };
switch (v1.num_bits) {
case 8: new.bits.u8 = v1.bits.u8 | v2.bits.u8; break;
case 16: new.bits.u16 = v1.bits.u16 | v2.bits.u16; break;
case 32: new.bits.u32 = v1.bits.u32 | v2.bits.u32; break;
case 64: new.bits.u64 = v1.bits.u64 | v2.bits.u64; break;
case 128: new.bits.u128[0] = v1.bits.u128[0] | v2.bits.u128[0];
new.bits.u128[1] = v1.bits.u128[1] | v2.bits.u128[1];
break;
case 256: new.bits.u256[0] = v1.bits.u256[0] | v2.bits.u256[0];
new.bits.u256[1] = v1.bits.u256[1] | v2.bits.u256[1];
new.bits.u256[2] = v1.bits.u256[2] | v2.bits.u256[2];
new.bits.u256[3] = v1.bits.u256[3] | v2.bits.u256[3];
break;
default:
panic(__func__);
}
return new;
}
vbits_t
and_vbits(vbits_t v1, vbits_t v2)
{
assert(v1.num_bits == v2.num_bits);
vbits_t new = { .num_bits = v1.num_bits };
switch (v1.num_bits) {
case 8: new.bits.u8 = v1.bits.u8 & v2.bits.u8; break;
case 16: new.bits.u16 = v1.bits.u16 & v2.bits.u16; break;
case 32: new.bits.u32 = v1.bits.u32 & v2.bits.u32; break;
case 64: new.bits.u64 = v1.bits.u64 & v2.bits.u64; break;
case 128: new.bits.u128[0] = v1.bits.u128[0] & v2.bits.u128[0];
new.bits.u128[1] = v1.bits.u128[1] & v2.bits.u128[1];
break;
case 256: new.bits.u256[0] = v1.bits.u256[0] & v2.bits.u256[0];
new.bits.u256[1] = v1.bits.u256[1] & v2.bits.u256[1];
new.bits.u256[2] = v1.bits.u256[2] & v2.bits.u256[2];
new.bits.u256[3] = v1.bits.u256[3] & v2.bits.u256[3];
break;
default:
panic(__func__);
}
return new;
}
vbits_t
concat_vbits(vbits_t v1, vbits_t v2)
{
assert(v1.num_bits == v2.num_bits);
vbits_t new = { .num_bits = v1.num_bits * 2 };
switch (v1.num_bits) {
case 8: new.bits.u16 = v1.bits.u8;
new.bits.u16 = (new.bits.u16 << 8) | v2.bits.u8; break;
case 16: new.bits.u32 = v1.bits.u16;
new.bits.u32 = (new.bits.u32 << 16) | v2.bits.u16; break;
case 32: new.bits.u64 = v1.bits.u32;
new.bits.u64 = (new.bits.u64 << 32) | v2.bits.u32; break;
case 64:
if (__BYTE_ORDER == __LITTLE_ENDIAN) {
new.bits.u128[0] = v2.bits.u64;
new.bits.u128[1] = v1.bits.u64;
} else {
new.bits.u128[0] = v1.bits.u64;
new.bits.u128[1] = v2.bits.u64;
}
break;
case 128:
if (__BYTE_ORDER == __LITTLE_ENDIAN) {
new.bits.u256[0] = v2.bits.u128[0];
new.bits.u256[1] = v2.bits.u128[1];
new.bits.u256[2] = v1.bits.u128[0];
new.bits.u256[3] = v1.bits.u128[1];
} else {
new.bits.u256[0] = v1.bits.u128[0];
new.bits.u256[1] = v1.bits.u128[1];
new.bits.u256[2] = v2.bits.u128[0];
new.bits.u256[3] = v2.bits.u128[1];
}
break;
case 256: /* Fall through */
default:
panic(__func__);
}
return new;
}
vbits_t
upper_vbits(vbits_t v)
{
vbits_t new = { .num_bits = v.num_bits / 2 };
switch (v.num_bits) {
case 16: new.bits.u8 = v.bits.u16 >> 8; break;
case 32: new.bits.u16 = v.bits.u32 >> 16; break;
case 64: new.bits.u32 = v.bits.u64 >> 32; break;
case 128:
if (__BYTE_ORDER == __LITTLE_ENDIAN)
new.bits.u64 = v.bits.u128[1];
else
new.bits.u64 = v.bits.u128[0];
break;
case 256:
if (__BYTE_ORDER == __LITTLE_ENDIAN) {
new.bits.u128[0] = v.bits.u256[2];
new.bits.u128[1] = v.bits.u256[3];
} else {
new.bits.u128[0] = v.bits.u256[0];
new.bits.u128[1] = v.bits.u256[1];
}
break;
case 8:
default:
panic(__func__);
}
return new;
}
vbits_t
zextend_vbits(vbits_t v, unsigned num_bits)
{
assert(num_bits >= v.num_bits);
if (num_bits == v.num_bits) return v;
vbits_t new = { .num_bits = num_bits };
if (v.num_bits <= 64) {
uint64_t bits = get_bits64(v);
switch (num_bits) {
case 8: new.bits.u8 = bits; break;
case 16: new.bits.u16 = bits; break;
case 32: new.bits.u32 = bits; break;
case 64: new.bits.u64 = bits; break;
case 128:
if (__BYTE_ORDER == __LITTLE_ENDIAN) {
new.bits.u128[0] = bits;
new.bits.u128[1] = 0;
} else {
new.bits.u128[0] = 0;
new.bits.u128[1] = bits;
}
break;
case 256:
if (__BYTE_ORDER == __LITTLE_ENDIAN) {
new.bits.u256[0] = bits;
new.bits.u256[1] = 0;
new.bits.u256[2] = 0;
new.bits.u256[3] = 0;
} else {
new.bits.u256[0] = 0;
new.bits.u256[1] = 0;
new.bits.u256[2] = 0;
new.bits.u256[3] = bits;
}
break;
default:
panic(__func__);
}
return new;
}
if (v.num_bits == 128) {
assert(num_bits == 256);
if (__BYTE_ORDER == __LITTLE_ENDIAN) {
new.bits.u256[0] = v.bits.u128[0];
new.bits.u256[1] = v.bits.u128[1];
new.bits.u256[2] = 0;
new.bits.u256[3] = 0;
} else {
new.bits.u256[0] = 0;
new.bits.u256[1] = 0;
new.bits.u256[2] = v.bits.u128[1];
new.bits.u256[3] = v.bits.u128[0];
}
return new;
}
/* Cannot zero-extend a 256-bit value to something larger */
panic(__func__);
}
vbits_t
sextend_vbits(vbits_t v, unsigned num_bits)
{
assert(num_bits >= v.num_bits);
int sextend = 0;
switch (v.num_bits) {
case 8: if (v.bits.u8 == 0x80) sextend = 1; break;
case 16: if (v.bits.u16 == 0x8000) sextend = 1; break;
case 32: if (v.bits.u32 == 0x80000000) sextend = 1; break;
case 64: if (v.bits.u64 == (1ull << 63)) sextend = 1; break;
case 128: if (v.bits.u128[1] == (1ull << 63)) sextend = 1; break;
case 256: if (v.bits.u256[3] == (1ull << 63)) sextend = 1; break;
default:
panic(__func__);
}
return sextend ? left_vbits(v, num_bits) : zextend_vbits(v, num_bits);
}
vbits_t
onehot_vbits(unsigned bitno, unsigned num_bits)
{
assert(bitno < num_bits);
vbits_t new = { .num_bits = num_bits };
switch (num_bits) {
case 1: new.bits.u32 = 1 << bitno; break;
case 8: new.bits.u8 = 1 << bitno; break;
case 16: new.bits.u16 = 1 << bitno; break;
case 32: new.bits.u32 = 1u << bitno; break;
case 64: new.bits.u64 = 1ull << bitno; break;
case 128:
if (__BYTE_ORDER == __LITTLE_ENDIAN) {
if (bitno < 64) {
new.bits.u128[0] = 1ull << bitno;
new.bits.u128[1] = 0;
} else {
new.bits.u128[0] = 0;
new.bits.u128[1] = 1ull << (bitno - 64);
}
} else {
if (bitno < 64) {
new.bits.u128[0] = 0;
new.bits.u128[1] = 1ull << bitno;
} else {
new.bits.u128[0] = 1ull << (bitno - 64);
new.bits.u128[1] = 0;
}
}
break;
case 256:
if (__BYTE_ORDER == __LITTLE_ENDIAN) {
if (bitno < 64) {
new.bits.u256[0] = 1ull << bitno;
new.bits.u256[1] = 0;
new.bits.u256[2] = 0;
new.bits.u256[3] = 0;
} else if (bitno < 128) {
new.bits.u256[0] = 0;
new.bits.u256[1] = 1ull << (bitno - 64);
new.bits.u256[2] = 0;
new.bits.u256[3] = 0;
} else if (bitno < 192) {
new.bits.u256[0] = 0;
new.bits.u256[1] = 0;
new.bits.u256[2] = 1ull << (bitno - 128);
new.bits.u256[3] = 0;
} else {
new.bits.u256[0] = 0;
new.bits.u256[1] = 0;
new.bits.u256[2] = 0;
new.bits.u256[3] = 1ull << (bitno - 192);
}
} else {
if (bitno < 64) {
new.bits.u256[0] = 0;
new.bits.u256[1] = 0;
new.bits.u256[2] = 0;
new.bits.u256[3] = 1ull << bitno;
} else if (bitno < 128) {
new.bits.u256[0] = 0;
new.bits.u256[1] = 0;
new.bits.u256[2] = 1ull << (bitno - 64);
new.bits.u256[3] = 0;
} else if (bitno < 192) {
new.bits.u256[0] = 0;
new.bits.u256[1] = 1ull << (bitno - 128);
new.bits.u256[2] = 0;
new.bits.u256[3] = 0;
} else {
new.bits.u256[0] = 1ull << (bitno - 192);
new.bits.u256[1] = 0;
new.bits.u256[2] = 0;
new.bits.u256[3] = 0;
}
}
break;
default:
panic(__func__);
}
return new;
}
int
completely_defined_vbits(vbits_t v)
{
return equal_vbits(v, defined_vbits(v.num_bits));
}
vbits_t
shl_vbits(vbits_t v, unsigned shift_amount)
{
assert(shift_amount < v.num_bits);
vbits_t new = v;
switch (v.num_bits) {
case 8: new.bits.u8 <<= shift_amount; break;
case 16: new.bits.u16 <<= shift_amount; break;
case 32: new.bits.u32 <<= shift_amount; break;
case 64: new.bits.u64 <<= shift_amount; break;
case 128: /* fall through */
case 256: /* fall through */
default:
panic(__func__);
}
return new;
}
vbits_t
shr_vbits(vbits_t v, unsigned shift_amount)
{
assert(shift_amount < v.num_bits);
vbits_t new = v;
switch (v.num_bits) {
case 8: new.bits.u8 >>= shift_amount; break;
case 16: new.bits.u16 >>= shift_amount; break;
case 32: new.bits.u32 >>= shift_amount; break;
case 64: new.bits.u64 >>= shift_amount; break;
case 128: /* fall through */
case 256: /* fall through */
default:
panic(__func__);
}
return new;
}
vbits_t
sar_vbits(vbits_t v, unsigned shift_amount)
{
assert(shift_amount < v.num_bits);
vbits_t new = v;
int msb;
switch (v.num_bits) {
case 8:
new.bits.u8 >>= shift_amount;
msb = (v.bits.u8 & 0x80) != 0;
break;
case 16:
new.bits.u16 >>= shift_amount;
msb = (v.bits.u16 & 0x8000) != 0;
break;
case 32:
new.bits.u32 >>= shift_amount;
msb = (v.bits.u32 & (1u << 31)) != 0;
break;
case 64:
new.bits.u64 >>= shift_amount;
msb = (v.bits.u64 & (1ull << 63)) != 0;
break;
case 128: /* fall through */
case 256: /* fall through */
default:
panic(__func__);
}
if (msb)
new = left_vbits(new, new.num_bits);
return new;
}
/* Return a value for the POWER Iop_CmpORD class iops */
vbits_t
cmpord_vbits(unsigned v1_num_bits, unsigned v2_num_bits)
{
vbits_t new = { .num_bits = v1_num_bits };
/* Size of values being compared must be the same */
assert( v1_num_bits == v2_num_bits);
/* Comparison only produces 32-bit or 64-bit value where
* the lower 3 bits are set to indicate, less than, equal and greater then.
*/
switch (v1_num_bits) {
case 32:
new.bits.u32 = 0xE;
break;
case 64:
new.bits.u64 = 0xE;
break;
default:
panic(__func__);
}
return new;
}