mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-14 07:29:51 +00:00
8350896: Integer/Long.compress gets wrong type from CompressBitsNode::Value
Co-authored-by: Emanuel Peter <epeter@openjdk.org> Reviewed-by: thartmann
This commit is contained in:
parent
06f9ff047f
commit
b02c125676
@ -237,58 +237,167 @@ static const Type* bitshuffle_value(const TypeInteger* src_type, const TypeInteg
|
||||
|
||||
jlong hi = bt == T_INT ? max_jint : max_jlong;
|
||||
jlong lo = bt == T_INT ? min_jint : min_jlong;
|
||||
assert(bt == T_INT || bt == T_LONG, "");
|
||||
|
||||
if(mask_type->is_con() && mask_type->get_con_as_long(bt) != -1L) {
|
||||
// Rule 1: Bit compression selects the source bits corresponding to true mask bits,
|
||||
// packs them and places them contiguously at destination bit positions
|
||||
// starting from least significant bit, remaining higher order bits are set
|
||||
// to zero.
|
||||
|
||||
// Rule 2: Bit expansion is a reverse process, which sequentially reads source bits
|
||||
// starting from LSB and places them at bit positions in result value where
|
||||
// corresponding mask bits are 1. Thus, bit expansion for non-negative mask
|
||||
// value will always generate a +ve value, this is because sign bit of result
|
||||
// will never be set to 1 as corresponding mask bit is always 0.
|
||||
|
||||
// Case A) Constant mask
|
||||
if (mask_type->is_con()) {
|
||||
jlong maskcon = mask_type->get_con_as_long(bt);
|
||||
int bitcount = population_count(static_cast<julong>(bt == T_INT ? maskcon & 0xFFFFFFFFL : maskcon));
|
||||
if (opc == Op_CompressBits) {
|
||||
// Bit compression selects the source bits corresponding to true mask bits
|
||||
// and lays them out contiguously at destination bit positions starting from
|
||||
// LSB, remaining higher order bits are set to zero.
|
||||
// Thus, it will always generate a +ve value i.e. sign bit set to 0 if
|
||||
// any bit of constant mask value is zero.
|
||||
lo = 0L;
|
||||
hi = (1UL << bitcount) - 1;
|
||||
// Case A.1 bit compression:-
|
||||
// For an outlier mask value of -1 upper bound of the result equals
|
||||
// maximum integral value, for any other mask value its computed using
|
||||
// following formula
|
||||
// Result.Hi = 1 << popcount(mask_bits) - 1
|
||||
//
|
||||
// For mask values other than -1, lower bound of the result is estimated
|
||||
// as zero, by assuming at least one mask bit is zero and corresponding source
|
||||
// bit will be masked, hence result of bit compression will always be
|
||||
// non-negative value. For outlier mask value of -1, assume all source bits
|
||||
// apart from most significant bit were set to 0, thereby resulting in
|
||||
// a minimum integral value.
|
||||
// e.g.
|
||||
// src = 0xXXXXXXXX (non-constant source)
|
||||
// mask = 0xEFFFFFFF (constant mask)
|
||||
// result.hi = 0x7FFFFFFF
|
||||
// result.lo = 0
|
||||
if (maskcon != -1L) {
|
||||
int bitcount = population_count(static_cast<julong>(bt == T_INT ? maskcon & 0xFFFFFFFFL : maskcon));
|
||||
hi = (1UL << bitcount) - 1;
|
||||
lo = 0L;
|
||||
} else {
|
||||
// preserve originally assigned hi (MAX_INT/LONG) and lo (MIN_INT/LONG) values
|
||||
// for unknown source bits.
|
||||
assert(hi == (bt == T_INT ? max_jint : max_jlong), "");
|
||||
assert(lo == (bt == T_INT ? min_jint : min_jlong), "");
|
||||
}
|
||||
} else {
|
||||
// Case A.2 bit expansion:-
|
||||
assert(opc == Op_ExpandBits, "");
|
||||
// Expansion sequentially reads source bits starting from LSB
|
||||
// and places them over destination at bit positions corresponding
|
||||
// set mask bit. Thus bit expansion for non-negative mask value
|
||||
// will always generate a +ve value.
|
||||
hi = maskcon >= 0L ? maskcon : maskcon ^ lo;
|
||||
lo = maskcon >= 0L ? 0L : lo;
|
||||
if (maskcon >= 0L) {
|
||||
// Case A.2.1 constant mask >= 0
|
||||
// Result.Hi = mask, optimistically assuming all source bits
|
||||
// read starting from least significant bit positions are 1.
|
||||
// Result.Lo = 0, because at least one bit in mask is zero.
|
||||
// e.g.
|
||||
// src = 0xXXXXXXXX (non-constant source)
|
||||
// mask = 0x7FFFFFFF (constant mask >= 0)
|
||||
// result.hi = 0x7FFFFFFF
|
||||
// result.lo = 0
|
||||
hi = maskcon;
|
||||
lo = 0L;
|
||||
} else {
|
||||
// Case A.2.2) mask < 0
|
||||
// For constant mask strictly less than zero, the maximum result value will be
|
||||
// the same as the mask value with its sign bit flipped, assuming all source bits
|
||||
// except the MSB bit are set(one).
|
||||
//
|
||||
// To compute minimum result value we assume all but last read source bit as zero,
|
||||
// this is because sign bit of result will always be set to 1 while other bit
|
||||
// corresponding to set mask bit should be zero.
|
||||
// e.g.
|
||||
// src = 0xXXXXXXXX (non-constant source)
|
||||
// mask = 0xEFFFFFFF (constant mask)
|
||||
// result.hi = 0xEFFFFFFF ^ 0x80000000 = 0x6FFFFFFF
|
||||
// result.lo = 0x80000000
|
||||
//
|
||||
hi = maskcon ^ lo;
|
||||
// lo still retains MIN_INT/LONG.
|
||||
assert(lo == (bt == T_INT ? min_jint : min_jlong), "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Case B) Non-constant mask.
|
||||
if (!mask_type->is_con()) {
|
||||
int mask_max_bw;
|
||||
int max_bw = bt == T_INT ? 32 : 64;
|
||||
// Case 1) Mask value range includes -1.
|
||||
if ((mask_type->lo_as_long() < 0L && mask_type->hi_as_long() >= -1L)) {
|
||||
mask_max_bw = max_bw;
|
||||
// Case 2) Mask value range is less than -1.
|
||||
} else if (mask_type->hi_as_long() < -1L) {
|
||||
mask_max_bw = max_bw - 1;
|
||||
} else {
|
||||
// Case 3) Mask value range only includes +ve values.
|
||||
assert(mask_type->lo_as_long() >= 0, "");
|
||||
jlong clz = count_leading_zeros(mask_type->hi_as_long());
|
||||
clz = bt == T_INT ? clz - 32 : clz;
|
||||
mask_max_bw = max_bw - clz;
|
||||
}
|
||||
if ( opc == Op_CompressBits) {
|
||||
lo = mask_max_bw == max_bw ? lo : 0L;
|
||||
// Compress operation is inherently an unsigned operation and
|
||||
// result value range is primarily dependent on true count
|
||||
// of participating mask value.
|
||||
hi = mask_max_bw < max_bw ? (1L << mask_max_bw) - 1 : src_type->hi_as_long();
|
||||
int result_bit_width;
|
||||
int mask_bit_width = bt == T_INT ? 32 : 64;
|
||||
if ((mask_type->lo_as_long() < 0L && mask_type->hi_as_long() >= -1L)) {
|
||||
// Case B.1 The mask value range includes -1, hence we may use all bits,
|
||||
// the result has the whole value range.
|
||||
result_bit_width = mask_bit_width;
|
||||
} else if (mask_type->hi_as_long() < -1L) {
|
||||
// Case B.2 Mask value range is strictly less than -1, this indicates presence of at least
|
||||
// one unset(zero) bit in mask value, thus as per Rule 1, bit compression will always
|
||||
// result in a non-negative value. This guarantees that MSB bit of result value will
|
||||
// always be set to zero.
|
||||
result_bit_width = mask_bit_width - 1;
|
||||
} else {
|
||||
assert(mask_type->lo_as_long() >= 0, "");
|
||||
// Case B.3 Mask value range only includes non-negative values. Since all integral
|
||||
// types honours an invariant that TypeInteger._lo <= TypeInteger._hi, thus computing
|
||||
// leading zero bits of upper bound of mask value will allow us to ascertain
|
||||
// optimistic upper bound of result i.e. all the bits other than leading zero bits
|
||||
// can be assumed holding 1 value.
|
||||
jlong clz = count_leading_zeros(mask_type->hi_as_long());
|
||||
// Here, result of clz is w.r.t to long argument, hence for integer argument
|
||||
// we explicitly subtract 32 from the result.
|
||||
clz = bt == T_INT ? clz - 32 : clz;
|
||||
result_bit_width = mask_bit_width - clz;
|
||||
}
|
||||
// If the number of bits required to for the mask value range is less than the
|
||||
// full bit width of the integral type, then the MSB bit is guaranteed to be zero,
|
||||
// thus the compression result will never be a -ve value and we can safely set the
|
||||
// lower bound of the bit compression to zero.
|
||||
lo = result_bit_width == mask_bit_width ? lo : 0L;
|
||||
|
||||
assert(hi == (bt == T_INT ? max_jint : max_jlong), "");
|
||||
assert(lo == (bt == T_INT ? min_jint : min_jlong) || lo == 0, "");
|
||||
|
||||
if (src_type->lo_as_long() >= 0) {
|
||||
// Lemma 1: For strictly non-negative src, the result of the compression will never be
|
||||
// greater than src.
|
||||
// Proof: Since src is a non-negative value, its most significant bit is always 0.
|
||||
// Thus even if the corresponding MSB of the mask is one, the result will be a +ve
|
||||
// value. There are three possible cases
|
||||
// a. All the mask bits corresponding to set source bits are unset(zero).
|
||||
// b. All the mask bits corresponding to set source bits are set(one)
|
||||
// c. Some mask bits corresponding to set source bits are set(one) while others are unset(zero)
|
||||
//
|
||||
// Case a. results into an allzero result, while Case b. gives us the upper bound which is equals source
|
||||
// value, while for Case c. the result will lie within [0, src]
|
||||
//
|
||||
hi = src_type->hi_as_long();
|
||||
lo = 0L;
|
||||
}
|
||||
|
||||
if (result_bit_width < mask_bit_width) {
|
||||
// Rule 3:
|
||||
// We can further constrain the upper bound of bit compression if the number of bits
|
||||
// which can be set(one) is less than the maximum number of bits of integral type.
|
||||
hi = MIN2((jlong)((1UL << result_bit_width) - 1L), hi);
|
||||
}
|
||||
} else {
|
||||
assert(opc == Op_ExpandBits, "");
|
||||
jlong max_mask = mask_type->hi_as_long();
|
||||
jlong min_mask = mask_type->lo_as_long();
|
||||
// Since mask here a range and not a constant value, hence being
|
||||
// conservative in determining the value range of result.
|
||||
lo = mask_type->lo_as_long() >= 0L ? 0L : lo;
|
||||
hi = mask_type->lo_as_long() >= 0L ? max_mask : hi;
|
||||
if (min_mask >= 0L) {
|
||||
// Lemma 2: Based on the integral type invariant ie. TypeInteger.lo <= TypeInteger.hi,
|
||||
// if the lower bound of non-constant mask is a non-negative value then result can never
|
||||
// be greater than the mask.
|
||||
// Proof: Since lower bound of the mask is a non-negative value, hence most significant
|
||||
// bit of its entire value must be unset(zero). If all the lower order 'n' source bits
|
||||
// where n corresponds to popcount of mask are set(ones) then upper bound of the result equals
|
||||
// mask. In order to compute the lower bound, we pssimistically assume all the lower order 'n'
|
||||
// source bits are unset(zero) there by resuling into a zero value.
|
||||
hi = max_mask;
|
||||
lo = 0;
|
||||
} else {
|
||||
// preserve the lo and hi bounds estimated till now.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -329,6 +438,11 @@ const Type* CompressBitsNode::Value(PhaseGVN* phase) const {
|
||||
static_cast<const Type*>(TypeLong::make(res));
|
||||
}
|
||||
|
||||
// Result is zero if src is zero irrespective of mask value.
|
||||
if (src_type == TypeInteger::zero(bt)) {
|
||||
return TypeInteger::zero(bt);
|
||||
}
|
||||
|
||||
return bitshuffle_value(src_type, mask_type, Op_CompressBits, bt);
|
||||
}
|
||||
|
||||
@ -365,5 +479,10 @@ const Type* ExpandBitsNode::Value(PhaseGVN* phase) const {
|
||||
static_cast<const Type*>(TypeLong::make(res));
|
||||
}
|
||||
|
||||
// Result is zero if src is zero irrespective of mask value.
|
||||
if (src_type == TypeInteger::zero(bt)) {
|
||||
return TypeInteger::zero(bt);
|
||||
}
|
||||
|
||||
return bitshuffle_value(src_type, mask_type, Op_ExpandBits, bt);
|
||||
}
|
||||
|
||||
@ -0,0 +1,676 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8350896
|
||||
* @library /test/lib /
|
||||
* @summary C2: wrong result: Integer/Long.compress gets wrong type from CompressBitsNode::Value.
|
||||
* @run driver compiler.c2.gvn.TestBitCompressValueTransform
|
||||
*/
|
||||
package compiler.c2.gvn;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
import compiler.lib.ir_framework.*;
|
||||
import compiler.lib.generators.*;
|
||||
|
||||
public class TestBitCompressValueTransform {
|
||||
|
||||
public static final int field_I = 0x400_0000;
|
||||
public static final long field_L = 0x400_0000_0000_0000L;
|
||||
public static final int gold_I = Integer.valueOf(Integer.compress(0x8000_0000, field_I));
|
||||
public static final long gold_L = Long.valueOf(Long.compress(0x8000_0000_0000_0000L, field_L));
|
||||
|
||||
public static RestrictableGenerator<Integer> GEN_I = Generators.G.ints();
|
||||
public static RestrictableGenerator<Long> GEN_L = Generators.G.longs();
|
||||
|
||||
public final int LIMIT_I1 = GEN_I.next();
|
||||
public final int LIMIT_I2 = GEN_I.next();
|
||||
public final int LIMIT_I3 = GEN_I.next();
|
||||
public final int LIMIT_I4 = GEN_I.next();
|
||||
public final int LIMIT_I5 = GEN_I.next();
|
||||
public final int LIMIT_I6 = GEN_I.next();
|
||||
public final int LIMIT_I7 = GEN_I.next();
|
||||
public final int LIMIT_I8 = GEN_I.next();
|
||||
|
||||
public final long LIMIT_L1 = GEN_L.next();
|
||||
public final long LIMIT_L2 = GEN_L.next();
|
||||
public final long LIMIT_L3 = GEN_L.next();
|
||||
public final long LIMIT_L4 = GEN_L.next();
|
||||
public final long LIMIT_L5 = GEN_L.next();
|
||||
public final long LIMIT_L6 = GEN_L.next();
|
||||
public final long LIMIT_L7 = GEN_L.next();
|
||||
public final long LIMIT_L8 = GEN_L.next();
|
||||
|
||||
public final int BOUND_LO_I = GEN_I.next();
|
||||
public final int BOUND_HI_I = GEN_I.next();
|
||||
|
||||
public final long BOUND_LO_L = GEN_L.next();
|
||||
public final long BOUND_HI_L = GEN_L.next();
|
||||
|
||||
@Test
|
||||
@IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "bmi2", "true" })
|
||||
public long test1(long value) {
|
||||
return Long.compress(0x8000_0000_0000_0000L, value);
|
||||
}
|
||||
|
||||
@Run(test = "test1")
|
||||
public void run1(RunInfo info) {
|
||||
long res = 0;
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
res |= test1(field_L);
|
||||
}
|
||||
Asserts.assertEQ(res, gold_L);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "bmi2", "true" })
|
||||
public int test2(int value) {
|
||||
return Integer.compress(0x8000_0000, value);
|
||||
}
|
||||
|
||||
@Run(test = "test2")
|
||||
public void run2(RunInfo info) {
|
||||
int res = 0;
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
res |= test2(field_I);
|
||||
}
|
||||
Asserts.assertEQ(res, gold_I);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR (counts = { IRNode.COMPRESS_BITS, " 0 "} , failOn = { IRNode.UNSTABLE_IF_TRAP }, applyIfCPUFeature = { "bmi2", "true" })
|
||||
public int test3(int value) {
|
||||
int filter_bits = value & 0xF;
|
||||
int compress_bits = Integer.compress(15, filter_bits);
|
||||
if (compress_bits > 15) {
|
||||
value = -1;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Run(test = "test3")
|
||||
public void run3(RunInfo info) {
|
||||
int res = 0;
|
||||
for (int i = 1; i < 10000; i++) {
|
||||
res |= test3(i);
|
||||
}
|
||||
Asserts.assertLTE(0, res);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR (counts = { IRNode.COMPRESS_BITS, " 0 "} , failOn = { IRNode.UNSTABLE_IF_TRAP }, applyIfCPUFeature = { "bmi2", "true" })
|
||||
public long test4(long value) {
|
||||
long filter_bits = value & 0xFL;
|
||||
long compress_bits = Long.compress(15L, filter_bits);
|
||||
if (compress_bits > 15L) {
|
||||
value = -1;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Run(test = "test4")
|
||||
public void run4(RunInfo info) {
|
||||
long res = 0;
|
||||
for (long i = 1; i < 10000; i++) {
|
||||
res |= test4(i);
|
||||
}
|
||||
Asserts.assertLTE(0L, res);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "bmi2", "true" })
|
||||
public long test5(long value) {
|
||||
// Since value range includes -1 hence with mask
|
||||
// and value as -1 all the result bits will be set.
|
||||
long mask = Long.min(10000L, Long.max(-10000L, value));
|
||||
return Long.compress(value, mask);
|
||||
}
|
||||
|
||||
@Run(test = "test5")
|
||||
public void run5(RunInfo info) {
|
||||
long res = 0;
|
||||
for (int i = -10000; i < 10000; i++) {
|
||||
res |= test5((long)i);
|
||||
}
|
||||
Asserts.assertEQ(-1L, res);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "bmi2", "true" })
|
||||
public long test6(long value) {
|
||||
// For mask within a strictly -ve value range less than -1,
|
||||
// result of compression will always be a +ve value.
|
||||
long mask = Long.min(-2L, Long.max(-10000L, value));
|
||||
return Long.compress(value, mask);
|
||||
}
|
||||
|
||||
@Run(test = "test6")
|
||||
public void run6(RunInfo info) {
|
||||
long res = 0;
|
||||
for (int i = -10000; i < 10000; i++) {
|
||||
res |= test6((long)i);
|
||||
}
|
||||
Asserts.assertLTE(0L, res);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "bmi2", "true" })
|
||||
public long test7(long value) {
|
||||
// For mask within a strictly +ve value range,
|
||||
// result of compression will always be a +ve value with
|
||||
// upper bound capped at max mask value.
|
||||
long mask = Long.min(10000L, Long.max(0L, value));
|
||||
return Long.compress(value, mask);
|
||||
}
|
||||
|
||||
@Run(test = "test7")
|
||||
public void run7(RunInfo info) {
|
||||
long res = Long.MIN_VALUE;
|
||||
for (int i = -10000; i < 10000; i++) {
|
||||
res = Long.max(test7((long)i), res);
|
||||
}
|
||||
Asserts.assertGTE(10000L, res);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "bmi2", "true" })
|
||||
public int test8(int value) {
|
||||
// Since value range includes -1 hence with mask
|
||||
// and value as -1 all the result bits will be set.
|
||||
int mask = Integer.min(10000, Integer.max(-10000, value));
|
||||
return Integer.compress(value, mask);
|
||||
}
|
||||
|
||||
@Run(test = "test8")
|
||||
public void run8(RunInfo info) {
|
||||
int res = 0;
|
||||
for (int i = -10000; i < 10000; i++) {
|
||||
res |= test8(i);
|
||||
}
|
||||
Asserts.assertEQ(-1, res);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "bmi2", "true" })
|
||||
public int test9(int value) {
|
||||
// For mask within a strictly -ve value range less than -1,
|
||||
// result of compression will always be a +ve value.
|
||||
int mask = Integer.min(-2, Integer.max(-10000, value));
|
||||
return Integer.compress(value, mask);
|
||||
}
|
||||
|
||||
@Run(test = "test9")
|
||||
public void run9(RunInfo info) {
|
||||
int res = 0;
|
||||
for (int i = -10000; i < 10000; i++) {
|
||||
res |= test9(i);
|
||||
}
|
||||
Asserts.assertLTE(0, res);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = { "bmi2", "true" })
|
||||
public int test10(int value) {
|
||||
// For mask within a strictly +ve value range,
|
||||
// result of compression will always be a +ve value with
|
||||
// upper bound capped at max mask value.
|
||||
int mask = Integer.min(10000, Integer.max(0, value));
|
||||
return Integer.compress(value, mask);
|
||||
}
|
||||
|
||||
@Run(test = "test10")
|
||||
public void run10(RunInfo info) {
|
||||
int res = Integer.MIN_VALUE;
|
||||
for (int i = -10000; i < 10000; i++) {
|
||||
res = Integer.max(test10(i), res);
|
||||
}
|
||||
Asserts.assertGTE(10000, res);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR (counts = { IRNode.COMPRESS_BITS, " 0 " })
|
||||
public int test11(int value) {
|
||||
// For constant zero input, compress is folded to zero
|
||||
int mask = Integer.min(10000, Integer.max(0, value));
|
||||
return Integer.compress(0, mask);
|
||||
}
|
||||
|
||||
@Run(test = "test11")
|
||||
public void run11(RunInfo info) {
|
||||
int res = 0;
|
||||
for (int i = -10000; i < 10000; i++) {
|
||||
res |= test11(i);
|
||||
}
|
||||
Asserts.assertEQ(0, res);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR (counts = { IRNode.COMPRESS_BITS, " 0 " })
|
||||
public long test12(long value) {
|
||||
// For constant zero input, compress is folded to zero
|
||||
long mask = Long.min(10000L, Long.max(0L, value));
|
||||
return Long.compress(0L, mask);
|
||||
}
|
||||
|
||||
@Run(test = "test12")
|
||||
public void run12(RunInfo info) {
|
||||
long res = 0;
|
||||
for (int i = -10000; i < 10000; i++) {
|
||||
res |= test12(i);
|
||||
}
|
||||
Asserts.assertEQ(0L, res);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR (counts = { IRNode.EXPAND_BITS, " 0 " })
|
||||
public int test13(int value) {
|
||||
// For constant zero input, expand is folded to zero
|
||||
int mask = Integer.min(10000, Integer.max(0, value));
|
||||
return Integer.expand(0, mask);
|
||||
}
|
||||
|
||||
@Run(test = "test13")
|
||||
public void run13(RunInfo info) {
|
||||
int res = 0;
|
||||
for (int i = -10000; i < 10000; i++) {
|
||||
res |= test13(i);
|
||||
}
|
||||
Asserts.assertEQ(0, res);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR (counts = { IRNode.EXPAND_BITS, " 0 " })
|
||||
public long test14(long value) {
|
||||
// For constant zero input, compress is folded to zero
|
||||
long mask = Long.min(10000L, Long.max(0L, value));
|
||||
return Long.expand(0L, mask);
|
||||
}
|
||||
|
||||
@Run(test = "test14")
|
||||
public void run14(RunInfo info) {
|
||||
long res = 0;
|
||||
for (int i = -10000; i < 10000; i++) {
|
||||
res |= test14(i);
|
||||
}
|
||||
Asserts.assertEQ(0L, res);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = {"bmi2" , "true"})
|
||||
public int test15(int src, int mask) {
|
||||
// src_type = [min_int + 1, -1]
|
||||
src = Math.max(Integer.MIN_VALUE + 1, Math.min(src, -1));
|
||||
return Integer.compress(src, mask);
|
||||
}
|
||||
|
||||
@Run (test = "test15")
|
||||
public void run15(RunInfo info) {
|
||||
int res = 0;
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
res |= test15(0, 0);
|
||||
}
|
||||
Asserts.assertEQ(0, res);
|
||||
}
|
||||
|
||||
@DontCompile
|
||||
public int test16_interpreted(int src, int mask) {
|
||||
src = Math.max(BOUND_LO_I, Math.min(src, BOUND_HI_I));
|
||||
int res = Integer.compress(src, mask);
|
||||
|
||||
if (res > LIMIT_I1) {
|
||||
res += 1;
|
||||
}
|
||||
if (res > LIMIT_I2) {
|
||||
res += 2;
|
||||
}
|
||||
if (res > LIMIT_I3) {
|
||||
res += 4;
|
||||
}
|
||||
if (res > LIMIT_I4) {
|
||||
res += 8;
|
||||
}
|
||||
if (res > LIMIT_I5) {
|
||||
res += 16;
|
||||
}
|
||||
if (res > LIMIT_I6) {
|
||||
res += 32;
|
||||
}
|
||||
if (res > LIMIT_I7) {
|
||||
res += 64;
|
||||
}
|
||||
if (res > LIMIT_I8) {
|
||||
res += 128;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = {"bmi2" , "true"})
|
||||
public int test16(int src, int mask) {
|
||||
src = Math.max(BOUND_LO_I, Math.min(src, BOUND_HI_I));
|
||||
int res = Integer.compress(src, mask);
|
||||
|
||||
// Check the result with some random value ranges, if any of the
|
||||
// following conditions incorrectly constant folds the result will
|
||||
// not comply with the interpreter.
|
||||
|
||||
if (res > LIMIT_I1) {
|
||||
res += 1;
|
||||
}
|
||||
if (res > LIMIT_I2) {
|
||||
res += 2;
|
||||
}
|
||||
if (res > LIMIT_I3) {
|
||||
res += 4;
|
||||
}
|
||||
if (res > LIMIT_I4) {
|
||||
res += 8;
|
||||
}
|
||||
if (res > LIMIT_I5) {
|
||||
res += 16;
|
||||
}
|
||||
if (res > LIMIT_I6) {
|
||||
res += 32;
|
||||
}
|
||||
if (res > LIMIT_I7) {
|
||||
res += 64;
|
||||
}
|
||||
if (res > LIMIT_I8) {
|
||||
res += 128;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Run (test = "test16")
|
||||
public void run16(RunInfo info) {
|
||||
int actual = 0;
|
||||
int expected = 0;
|
||||
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
int arg1 = GEN_I.next();
|
||||
int arg2 = GEN_I.next();
|
||||
|
||||
actual += test16(arg1, arg2);
|
||||
expected += test16_interpreted(arg1, arg2);
|
||||
}
|
||||
Asserts.assertEQ(actual, expected);
|
||||
}
|
||||
|
||||
@DontCompile
|
||||
public int test17_interpreted(int src, int mask) {
|
||||
src = Math.max(BOUND_LO_I, Math.min(src, BOUND_HI_I));
|
||||
int res = Integer.expand(src, mask);
|
||||
|
||||
if (res > LIMIT_I1) {
|
||||
res += 1;
|
||||
}
|
||||
if (res > LIMIT_I2) {
|
||||
res += 2;
|
||||
}
|
||||
if (res > LIMIT_I3) {
|
||||
res += 4;
|
||||
}
|
||||
if (res > LIMIT_I4) {
|
||||
res += 8;
|
||||
}
|
||||
if (res > LIMIT_I5) {
|
||||
res += 16;
|
||||
}
|
||||
if (res > LIMIT_I6) {
|
||||
res += 32;
|
||||
}
|
||||
if (res > LIMIT_I7) {
|
||||
res += 64;
|
||||
}
|
||||
if (res > LIMIT_I8) {
|
||||
res += 128;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR (counts = { IRNode.EXPAND_BITS, " >0 " }, applyIfCPUFeature = {"bmi2" , "true"})
|
||||
public int test17(int src, int mask) {
|
||||
src = Math.max(BOUND_LO_I, Math.min(src, BOUND_HI_I));
|
||||
int res = Integer.expand(src, mask);
|
||||
|
||||
// Check the result with some random value ranges, if any of the
|
||||
// following conditions incorrectly constant folds the result will
|
||||
// not comply with the interpreter.
|
||||
|
||||
if (res > LIMIT_I1) {
|
||||
res += 1;
|
||||
}
|
||||
if (res > LIMIT_I2) {
|
||||
res += 2;
|
||||
}
|
||||
if (res > LIMIT_I3) {
|
||||
res += 4;
|
||||
}
|
||||
if (res > LIMIT_I4) {
|
||||
res += 8;
|
||||
}
|
||||
if (res > LIMIT_I5) {
|
||||
res += 16;
|
||||
}
|
||||
if (res > LIMIT_I6) {
|
||||
res += 32;
|
||||
}
|
||||
if (res > LIMIT_I7) {
|
||||
res += 64;
|
||||
}
|
||||
if (res > LIMIT_I8) {
|
||||
res += 128;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Run (test = "test17")
|
||||
public void run17(RunInfo info) {
|
||||
int actual = 0;
|
||||
int expected = 0;
|
||||
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
int arg1 = GEN_I.next();
|
||||
int arg2 = GEN_I.next();
|
||||
|
||||
actual += test16(arg1, arg2);
|
||||
expected += test16_interpreted(arg1, arg2);
|
||||
}
|
||||
Asserts.assertEQ(actual, expected);
|
||||
}
|
||||
|
||||
@DontCompile
|
||||
public long test18_interpreted(long src, long mask) {
|
||||
src = Math.max(BOUND_LO_L, Math.min(src, BOUND_HI_L));
|
||||
long res = Long.compress(src, mask);
|
||||
|
||||
if (res > LIMIT_L1) {
|
||||
res += 1;
|
||||
}
|
||||
if (res > LIMIT_L2) {
|
||||
res += 2;
|
||||
}
|
||||
if (res > LIMIT_L3) {
|
||||
res += 4;
|
||||
}
|
||||
if (res > LIMIT_L4) {
|
||||
res += 8;
|
||||
}
|
||||
if (res > LIMIT_L5) {
|
||||
res += 16;
|
||||
}
|
||||
if (res > LIMIT_L6) {
|
||||
res += 32;
|
||||
}
|
||||
if (res > LIMIT_L7) {
|
||||
res += 64;
|
||||
}
|
||||
if (res > LIMIT_L8) {
|
||||
res += 128;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR (counts = { IRNode.COMPRESS_BITS, " >0 " }, applyIfCPUFeature = {"bmi2" , "true"})
|
||||
public long test18(long src, long mask) {
|
||||
src = Math.max(BOUND_LO_L, Math.min(src, BOUND_HI_L));
|
||||
long res = Long.compress(src, mask);
|
||||
|
||||
// Check the result with some random value ranges, if any of the
|
||||
// following conditions incorrectly constant folds the result will
|
||||
// not comply with the interpreter.
|
||||
|
||||
if (res > LIMIT_L1) {
|
||||
res += 1;
|
||||
}
|
||||
if (res > LIMIT_L2) {
|
||||
res += 2;
|
||||
}
|
||||
if (res > LIMIT_L3) {
|
||||
res += 4;
|
||||
}
|
||||
if (res > LIMIT_L4) {
|
||||
res += 8;
|
||||
}
|
||||
if (res > LIMIT_L5) {
|
||||
res += 16;
|
||||
}
|
||||
if (res > LIMIT_L6) {
|
||||
res += 32;
|
||||
}
|
||||
if (res > LIMIT_L7) {
|
||||
res += 64;
|
||||
}
|
||||
if (res > LIMIT_L8) {
|
||||
res += 128;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Run (test = "test18")
|
||||
public void run18(RunInfo info) {
|
||||
long actual = 0;
|
||||
long expected = 0;
|
||||
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
long arg1 = GEN_L.next();
|
||||
long arg2 = GEN_L.next();
|
||||
|
||||
actual += test18(arg1, arg2);
|
||||
expected += test18_interpreted(arg1, arg2);
|
||||
}
|
||||
Asserts.assertEQ(actual, expected);
|
||||
}
|
||||
|
||||
@DontCompile
|
||||
public long test19_interpreted(long src, long mask) {
|
||||
src = Math.max(BOUND_LO_L, Math.min(src, BOUND_HI_L));
|
||||
long res = Long.expand(src, mask);
|
||||
|
||||
if (res > LIMIT_L1) {
|
||||
res += 1;
|
||||
}
|
||||
if (res > LIMIT_L2) {
|
||||
res += 2;
|
||||
}
|
||||
if (res > LIMIT_L3) {
|
||||
res += 4;
|
||||
}
|
||||
if (res > LIMIT_L4) {
|
||||
res += 8;
|
||||
}
|
||||
if (res > LIMIT_L5) {
|
||||
res += 16;
|
||||
}
|
||||
if (res > LIMIT_L6) {
|
||||
res += 32;
|
||||
}
|
||||
if (res > LIMIT_L7) {
|
||||
res += 64;
|
||||
}
|
||||
if (res > LIMIT_L8) {
|
||||
res += 128;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR (counts = { IRNode.EXPAND_BITS, " >0 " }, applyIfCPUFeature = {"bmi2" , "true"})
|
||||
public long test19(long src, long mask) {
|
||||
src = Math.max(BOUND_LO_L, Math.min(src, BOUND_HI_L));
|
||||
long res = Long.expand(src, mask);
|
||||
|
||||
// Check the result with some random value ranges, if any of the
|
||||
// following conditions incorrectly constant folds the result will
|
||||
// not comply with the interpreter.
|
||||
|
||||
if (res > LIMIT_L1) {
|
||||
res += 1;
|
||||
}
|
||||
if (res > LIMIT_L2) {
|
||||
res += 2;
|
||||
}
|
||||
if (res > LIMIT_L3) {
|
||||
res += 4;
|
||||
}
|
||||
if (res > LIMIT_L4) {
|
||||
res += 8;
|
||||
}
|
||||
if (res > LIMIT_L5) {
|
||||
res += 16;
|
||||
}
|
||||
if (res > LIMIT_L6) {
|
||||
res += 32;
|
||||
}
|
||||
if (res > LIMIT_L7) {
|
||||
res += 64;
|
||||
}
|
||||
if (res > LIMIT_L8) {
|
||||
res += 128;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Run (test = "test19")
|
||||
public void run19(RunInfo info) {
|
||||
long actual = 0;
|
||||
long expected = 0;
|
||||
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
long arg1 = GEN_L.next();
|
||||
long arg2 = GEN_L.next();
|
||||
|
||||
actual += test19(arg1, arg2);
|
||||
expected += test19_interpreted(arg1, arg2);
|
||||
}
|
||||
Asserts.assertEQ(actual, expected);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestFramework.run(TestBitCompressValueTransform.class);
|
||||
}
|
||||
}
|
||||
@ -105,6 +105,7 @@ public class IREncodingPrinter {
|
||||
"avx512f",
|
||||
"avx512_fp16",
|
||||
"avx512_vnni",
|
||||
"bmi2",
|
||||
// AArch64
|
||||
"sha3",
|
||||
"asimd",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user