mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-06 11:41:34 +00:00
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
1075 lines
30 KiB
C
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;
|
|
}
|