Skip to content

Commit

Permalink
refactor bit extensions.
Browse files Browse the repository at this point in the history
  • Loading branch information
s-perron committed Jun 13, 2024
1 parent bc28ac7 commit 9ad742d
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 57 deletions.
61 changes: 4 additions & 57 deletions source/opt/const_folding_rules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,59 +21,6 @@ namespace opt {
namespace {
constexpr uint32_t kExtractCompositeIdInIdx = 0;

// Returns the value obtained by extracting the |number_of_bits| least
// significant bits from |value|, and sign-extending it to 64-bits.
uint64_t SignExtendValue(uint64_t value, uint32_t number_of_bits) {
if (number_of_bits == 64) return value;

uint64_t mask_for_sign_bit = 1ull << (number_of_bits - 1);
uint64_t mask_for_significant_bits = (mask_for_sign_bit << 1) - 1ull;
if (value & mask_for_sign_bit) {
// Set upper bits to 1
value |= ~mask_for_significant_bits;
} else {
// Clear the upper bits
value &= mask_for_significant_bits;
}
return value;
}

// Returns the value obtained by extracting the |number_of_bits| least
// significant bits from |value|, and zero-extending it to 64-bits.
uint64_t ZeroExtendValue(uint64_t value, uint32_t number_of_bits) {
if (number_of_bits == 64) return value;

uint64_t mask_for_first_bit_to_clear = 1ull << (number_of_bits);
uint64_t mask_for_bits_to_keep = mask_for_first_bit_to_clear - 1;
value &= mask_for_bits_to_keep;
return value;
}

// Returns a constant whose value is `value` and type is `type`. This constant
// will be generated by `const_mgr`. The type must be a scalar integer type.
const analysis::Constant* GenerateIntegerConstant(
const analysis::Integer* integer_type, uint64_t result,
analysis::ConstantManager* const_mgr) {
assert(integer_type != nullptr);

std::vector<uint32_t> words;
if (integer_type->width() == 64) {
// In the 64-bit case, two words are needed to represent the value.
words = {static_cast<uint32_t>(result),
static_cast<uint32_t>(result >> 32)};
} else {
// In all other cases, only a single word is needed.
assert(integer_type->width() <= 32);
if (integer_type->IsSigned()) {
result = SignExtendValue(result, integer_type->width());
} else {
result = ZeroExtendValue(result, integer_type->width());
}
words = {static_cast<uint32_t>(result)};
}
return const_mgr->GetConstant(integer_type, words);
}

// Returns a constants with the value NaN of the given type. Only works for
// 32-bit and 64-bit float point types. Returns |nullptr| if an error occurs.
const analysis::Constant* GetNan(const analysis::Type* type,
Expand Down Expand Up @@ -1730,7 +1677,7 @@ BinaryScalarFoldingRule FoldBinaryIntegerOperation(uint64_t (*op)(uint64_t,
uint64_t result = op(ia, ib);

const analysis::Constant* result_constant =
GenerateIntegerConstant(integer_type, result, const_mgr);
const_mgr->GenerateIntegerConstant(integer_type, result);
return result_constant;
};
}
Expand All @@ -1745,7 +1692,7 @@ const analysis::Constant* FoldScalarSConvert(
const analysis::Integer* integer_type = result_type->AsInteger();
assert(integer_type && "The result type of an SConvert");
int64_t value = a->GetSignExtendedValue();
return GenerateIntegerConstant(integer_type, value, const_mgr);
return const_mgr->GenerateIntegerConstant(integer_type, value);
}

// A scalar folding rule that folds OpUConvert.
Expand All @@ -1762,8 +1709,8 @@ const analysis::Constant* FoldScalarUConvert(
// If the operand was an unsigned value with less than 32-bit, it would have
// been sign extended earlier, and we need to clear those bits.
auto* operand_type = a->type()->AsInteger();
value = ZeroExtendValue(value, operand_type->width());
return GenerateIntegerConstant(integer_type, value, const_mgr);
value = utils::ClearHighBits(value, 64-operand_type->width());
return const_mgr->GenerateIntegerConstant(integer_type, value);
}
} // namespace

Expand Down
48 changes: 48 additions & 0 deletions source/opt/constants.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,32 @@

namespace spvtools {
namespace opt {

namespace {
// Returns the value obtained by extracting the |number_of_bits| least
// significant bits from |value|, and sign-extending it to 64-bits.
uint64_t SignExtendValue(uint64_t value, uint32_t number_of_bits) {
const uint32_t width = sizeof(value) * 8;
if (number_of_bits == width) return value;

bool is_negative = utils::IsBitAtPositionSet(value, number_of_bits-1);
if (is_negative) {
value = utils::SetHighBits(value, width-number_of_bits);
} else {
value = utils::ClearHighBits(value, width-number_of_bits);
}
return value;
}

// Returns the value obtained by extracting the |number_of_bits| least
// significant bits from |value|, and zero-extending it to 64-bits.
uint64_t ZeroExtendValue(uint64_t value, uint32_t number_of_bits) {
const uint32_t width = sizeof(value) * 8;
if (number_of_bits == width) return value;
return utils::ClearHighBits(value, width-number_of_bits);
}
}

namespace analysis {

float Constant::GetFloat() const {
Expand Down Expand Up @@ -525,6 +551,28 @@ uint32_t ConstantManager::GetNullConstId(const Type* type) {
return GetDefiningInstruction(c)->result_id();
}

const Constant* ConstantManager::GenerateIntegerConstant(
const analysis::Integer* integer_type, uint64_t result) {
assert(integer_type != nullptr);

std::vector<uint32_t> words;
if (integer_type->width() == 64) {
// In the 64-bit case, two words are needed to represent the value.
words = {static_cast<uint32_t>(result),
static_cast<uint32_t>(result >> 32)};
} else {
// In all other cases, only a single word is needed.
assert(integer_type->width() <= 32);
if (integer_type->IsSigned()) {
result = SignExtendValue(result, integer_type->width());
} else {
result = ZeroExtendValue(result, integer_type->width());
}
words = {static_cast<uint32_t>(result)};
}
return GetConstant(integer_type, words);
}

std::vector<const analysis::Constant*> Constant::GetVectorComponents(
analysis::ConstantManager* const_mgr) const {
std::vector<const analysis::Constant*> components;
Expand Down
5 changes: 5 additions & 0 deletions source/opt/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,11 @@ class ConstantManager {
// Returns the id of a OpConstantNull with type of |type|.
uint32_t GetNullConstId(const Type* type);

// Returns a constant whose value is `value` and type is `type`. This constant
// will be generated by `const_mgr`. The type must be a scalar integer type.
const Constant* GenerateIntegerConstant(const analysis::Integer* integer_type,
uint64_t result);

private:
// Creates a Constant instance with the given type and a vector of constant
// defining words. Returns a unique pointer to the created Constant instance
Expand Down

0 comments on commit 9ad742d

Please sign in to comment.