我对第三个参数很好奇,即来自 LLVMllvm/ADT/APInt.h
标头的布尔isSigned
APInt(unsigned numBits, uint64_t val, bool isSigned = false)
。
无论我将其设置为什么,getActiveBits()
或getMinSignedBits()
等函数的结果都不会改变。
此外,如果我想获取有符号/无符号值,我使用getSExtValue()
或getZExtValue()
.
isSigned
的价值对他们来说也不重要。
那么isSigned
什么时候重要呢?
TL;DR:isSigned
只对numBits > 64
很重要。
sizeof(val)
只有 64 位。假设您要将有符号值存储在带有size > 64 bits
的整数中。
-
如果该值为负值,则必须将所有高位设置为
1
,因为负值通常存储为 2 的补码。 -
如果该值为正,则必须将所有高位设置为
0
例
假设您想以 128 位存储-1。
持有-1uint64_t val
的二进制表示为
1111111111111111111111111111111111111111111111111111111111111111
这只是 64个,所以还有 64 位需要填充。如果没有isSigned
值,就不可能知道这些位应该是1,从而导致-1还是零,从而导致18446744073709551615。
详细解释
从源代码中可以看出,isSigned
仅在特定情况下使用:
APInt(unsigned numBits, uint64_t val, bool isSigned = false)
: BitWidth(numBits) {
assert(BitWidth && "bitwidth too small");
if (isSingleWord()) {
U.VAL = val;
clearUnusedBits();
} else {
initSlowCase(val, isSigned);
}
}
根据其函数标头,isSingleWord
如果位数 <= 64,则返回 true,否则返回 false。
因此,该行
if (isSingleWord()) {
检查值的存储占用的内存是否多于val
本身。
如果numBits
大于 64,则调用APInt::initSlowCase
:
void APInt::initSlowCase(uint64_t val, bool isSigned) {
U.pVal = getClearedMemory(getNumWords());
U.pVal[0] = val;
if (isSigned && int64_t(val) < 0)
for (unsigned i = 1; i < getNumWords(); ++i)
U.pVal[i] = WORDTYPE_MAX;
clearUnusedBits();
}
此函数从val
变量中复制值,并将位填充到numBits
。
这是必要的,因为乞求值存储为二进制补码。 如果设置了isSigned
并且val
为负值,则高字的所有位都设置为 1。
根据文档可以告诉val
是有符号还是无符号。
如果 isSigned 为 true,则 val 被视为有符号值(即作为int64_t(,并且将对位宽进行适当的符号扩展。否则,不会发生符号扩展(超出 val 范围的高阶位为零填充(。