opt: set upper bits of spec constant according to spec (#4589)

When setting default value for spec constants, for numeric bit types smaller
than 32 bits, follow the SPIR-V rules for narrow literals:
- signed integers are sign-extended
- otherwise, upper bits are zero.

Followup to #4588
This commit is contained in:
David Neto 2021-10-21 09:44:54 -04:00 committed by GitHub
parent f3fbd98ff5
commit 7326b494d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 87 additions and 18 deletions

View File

@ -85,6 +85,10 @@ std::vector<uint32_t> ParseDefaultValueStr(const char* text,
// with 0x1, which represents a 'true'.
// If all words in the bit pattern are zero, returns a bit pattern with 0x0,
// which represents a 'false'.
// For integer and floating point types narrower than 32 bits, the upper bits
// in the input bit pattern are ignored. Instead the upper bits are set
// according to SPIR-V literal requirements: sign extend a signed integer, and
// otherwise set the upper bits to zero.
std::vector<uint32_t> ParseDefaultValueBitPattern(
const std::vector<uint32_t>& input_bit_pattern,
const analysis::Type* type) {
@ -98,16 +102,33 @@ std::vector<uint32_t> ParseDefaultValueBitPattern(
}
return result;
} else if (const auto* IT = type->AsInteger()) {
auto width = IT->width();
if (width == 8 || width == 16) width = 32;
if (width == input_bit_pattern.size() * sizeof(uint32_t) * 8) {
return std::vector<uint32_t>(input_bit_pattern);
const auto width = IT->width();
assert(width > 0);
const auto adjusted_width = std::max(32u, width);
if (adjusted_width == input_bit_pattern.size() * sizeof(uint32_t) * 8) {
result = std::vector<uint32_t>(input_bit_pattern);
if (width < 32) {
const uint32_t high_active_bit = (1u << width) >> 1;
if (IT->IsSigned() && (high_active_bit & result[0])) {
// Sign extend. This overwrites the sign bit again, but that's ok.
result[0] = result[0] | ~(high_active_bit - 1);
} else {
// Upper bits must be zero.
result[0] = result[0] & ((1u << width) - 1);
}
}
return result;
}
} else if (const auto* FT = type->AsFloat()) {
auto width = FT->width();
if (width == 8 || width == 16) width = 32;
if (width == input_bit_pattern.size() * sizeof(uint32_t) * 8) {
return std::vector<uint32_t>(input_bit_pattern);
const auto width = FT->width();
const auto adjusted_width = std::max(32u, width);
if (adjusted_width == input_bit_pattern.size() * sizeof(uint32_t) * 8) {
result = std::vector<uint32_t>(input_bit_pattern);
if (width < 32) {
// Upper bits must be zero.
result[0] = result[0] & ((1u << width) - 1);
}
return result;
}
}
result.clear();

View File

@ -935,7 +935,7 @@ INSTANTIATE_TEST_SUITE_P(
"%2 = OpSpecConstantTrue %bool\n"
"%3 = OpSpecConstantTrue %bool\n",
},
// 19. 16-bit int type.
// 19. 16-bit signed int type.
{
// code
"OpDecorate %1 SpecId 100\n"
@ -947,17 +947,39 @@ INSTANTIATE_TEST_SUITE_P(
"%3 = OpSpecConstant %short 11\n",
// default values
SpecIdToValueBitPatternMap{
{100, {32768}}, {101, {0xffff}}, {102, {0xffffffd6}}},
// expected
{100, {32767}}, {101, {0xffff}}, {102, {0xffffffd6}}},
// expected. These are sign-extended
"OpDecorate %1 SpecId 100\n"
"OpDecorate %2 SpecId 101\n"
"OpDecorate %3 SpecId 102\n"
"%short = OpTypeInt 16 1\n"
"%1 = OpSpecConstant %short 32768\n"
"%2 = OpSpecConstant %short 65535\n"
"%1 = OpSpecConstant %short 32767\n"
"%2 = OpSpecConstant %short -1\n"
"%3 = OpSpecConstant %short -42\n",
},
// 20. 8-bit int type.
// 20. 16-bit unsigned int type.
{
// code
"OpDecorate %1 SpecId 100\n"
"OpDecorate %2 SpecId 101\n"
"OpDecorate %3 SpecId 102\n"
"%ushort = OpTypeInt 16 0\n"
"%1 = OpSpecConstant %ushort 10\n"
"%2 = OpSpecConstant %ushort 11\n"
"%3 = OpSpecConstant %ushort 11\n",
// default values
SpecIdToValueBitPatternMap{
{100, {32767}}, {101, {0xffff}}, {102, {0xffffffd6}}},
// expected. Upper bits are always zero.
"OpDecorate %1 SpecId 100\n"
"OpDecorate %2 SpecId 101\n"
"OpDecorate %3 SpecId 102\n"
"%ushort = OpTypeInt 16 0\n"
"%1 = OpSpecConstant %ushort 32767\n"
"%2 = OpSpecConstant %ushort 65535\n"
"%3 = OpSpecConstant %ushort 65494\n",
},
// 21. 8-bit signed int type.
{
// code
"OpDecorate %1 SpecId 100\n"
@ -969,16 +991,42 @@ INSTANTIATE_TEST_SUITE_P(
"%3 = OpSpecConstant %char 11\n",
// default values
SpecIdToValueBitPatternMap{
{100, {128}}, {101, {129}}, {102, {0xffffffd6}}},
// expected
{100, {127}}, {101, {128}}, {102, {0xd6}}},
// expected. These are sign extended
"OpDecorate %1 SpecId 100\n"
"OpDecorate %2 SpecId 101\n"
"OpDecorate %3 SpecId 102\n"
"%char = OpTypeInt 8 1\n"
"%1 = OpSpecConstant %char 128\n"
"%2 = OpSpecConstant %char 129\n"
"%1 = OpSpecConstant %char 127\n"
"%2 = OpSpecConstant %char -128\n"
"%3 = OpSpecConstant %char -42\n",
},
// 22. 8-bit unsigned int type.
{
// code
"OpDecorate %1 SpecId 100\n"
"OpDecorate %2 SpecId 101\n"
"OpDecorate %3 SpecId 102\n"
"OpDecorate %4 SpecId 103\n"
"%uchar = OpTypeInt 8 0\n"
"%1 = OpSpecConstant %uchar 10\n"
"%2 = OpSpecConstant %uchar 11\n"
"%3 = OpSpecConstant %uchar 11\n"
"%4 = OpSpecConstant %uchar 11\n",
// default values
SpecIdToValueBitPatternMap{
{100, {127}}, {101, {128}}, {102, {256}}, {103, {0xffffffd6}}},
// expected. Upper bits are always zero.
"OpDecorate %1 SpecId 100\n"
"OpDecorate %2 SpecId 101\n"
"OpDecorate %3 SpecId 102\n"
"OpDecorate %4 SpecId 103\n"
"%uchar = OpTypeInt 8 0\n"
"%1 = OpSpecConstant %uchar 127\n"
"%2 = OpSpecConstant %uchar 128\n"
"%3 = OpSpecConstant %uchar 0\n"
"%4 = OpSpecConstant %uchar 214\n",
},
}));
INSTANTIATE_TEST_SUITE_P(