[midend-GSR]将魔数求解移动到utils的静态方法中。

This commit is contained in:
rain2133
2025-08-18 20:37:20 +08:00
parent c9a0c700e1
commit 5c34cbc7b8
6 changed files with 279 additions and 440 deletions

View File

@@ -68,7 +68,7 @@ private:
MagicNumber computeMagicNumber(uint32_t divisor);
std::pair<int, int> computeMulhMagicNumbers(int divisor);
Value* createMagicDivision(BinaryInst* divInst, uint32_t divisor, const MagicNumber& magic);
Value* createMagicDivisionLibdivide(BinaryInst* divInst, int divisor, const std::pair<int, int>& magicPair);
Value* createMagicDivisionLibdivide(BinaryInst* divInst, int divisor);
bool isPowerOfTwo(uint32_t n);
int log2OfPowerOfTwo(uint32_t n);

View File

@@ -127,13 +127,6 @@ private:
*/
bool analyzeInductionVariableRange(const InductionVarInfo* ivInfo, Loop* loop) const;
/**
* 计算用于除法优化的魔数和移位量
* @param divisor 除数
* @return {魔数, 移位量}
*/
std::pair<int, int> computeMulhMagicNumbers(int divisor) const;
/**
* 生成除法替换代码
* @param candidate 优化候选项

View File

@@ -107,6 +107,190 @@ public:
// 所以当AllocaInst的basetype是PointerType时一维数组或者是指向ArrayType的PointerType多位数组返回true
return aval && (baseType->isPointer() || baseType->as<PointerType>()->getBaseType()->isArray());
}
//该实现参考了libdivide的算法
static std::pair<int, int> computeMulhMagicNumbers(int divisor) {
if (DEBUG) {
std::cout << "\n[SR] ===== Computing magic numbers for divisor " << divisor << " (libdivide algorithm) =====" << std::endl;
}
if (divisor == 0) {
if (DEBUG) std::cout << "[SR] Error: divisor must be != 0" << std::endl;
return {-1, -1};
}
// libdivide 常数
const uint8_t LIBDIVIDE_ADD_MARKER = 0x40;
const uint8_t LIBDIVIDE_NEGATIVE_DIVISOR = 0x80;
// 辅助函数:计算前导零个数
auto count_leading_zeros32 = [](uint32_t val) -> uint32_t {
if (val == 0) return 32;
return __builtin_clz(val);
};
// 辅助函数64位除法返回32位商和余数
auto div_64_32 = [](uint32_t high, uint32_t low, uint32_t divisor, uint32_t* rem) -> uint32_t {
uint64_t dividend = ((uint64_t)high << 32) | low;
uint32_t quotient = dividend / divisor;
*rem = dividend % divisor;
return quotient;
};
if (DEBUG) {
std::cout << "[SR] Input divisor: " << divisor << std::endl;
}
// libdivide_internal_s32_gen 算法实现
int32_t d = divisor;
uint32_t ud = (uint32_t)d;
uint32_t absD = (d < 0) ? -ud : ud;
if (DEBUG) {
std::cout << "[SR] absD = " << absD << std::endl;
}
uint32_t floor_log_2_d = 31 - count_leading_zeros32(absD);
if (DEBUG) {
std::cout << "[SR] floor_log_2_d = " << floor_log_2_d << std::endl;
}
// 检查 absD 是否为2的幂
if ((absD & (absD - 1)) == 0) {
if (DEBUG) {
std::cout << "[SR] " << absD << " 是2的幂使用移位方法" << std::endl;
}
// 对于2的幂我们只使用移位不需要魔数
int shift = floor_log_2_d;
if (d < 0) shift |= 0x80; // 标记负数
if (DEBUG) {
std::cout << "[SR] Power of 2 result: magic=0, shift=" << shift << std::endl;
std::cout << "[SR] ===== End magic computation =====" << std::endl;
}
// 对于我们的目的我们将在IR生成中以不同方式处理2的幂
// 返回特殊标记
return {0, shift};
}
if (DEBUG) {
std::cout << "[SR] " << absD << " is not a power of 2, computing magic number" << std::endl;
}
// 非2的幂除数的魔数计算
uint8_t more;
uint32_t rem, proposed_m;
// 计算 proposed_m = floor(2^(floor_log_2_d + 31) / absD)
proposed_m = div_64_32((uint32_t)1 << (floor_log_2_d - 1), 0, absD, &rem);
const uint32_t e = absD - rem;
if (DEBUG) {
std::cout << "[SR] proposed_m = " << proposed_m << ", rem = " << rem << ", e = " << e << std::endl;
}
// 确定是否需要"加法"版本
const bool branchfree = false; // 使用分支版本
if (!branchfree && e < ((uint32_t)1 << floor_log_2_d)) {
// 这个幂次有效
more = (uint8_t)(floor_log_2_d - 1);
if (DEBUG) {
std::cout << "[SR] Using basic algorithm, shift = " << (int)more << std::endl;
}
} else {
// 我们需要上升一个等级
proposed_m += proposed_m;
const uint32_t twice_rem = rem + rem;
if (twice_rem >= absD || twice_rem < rem) {
proposed_m += 1;
}
more = (uint8_t)(floor_log_2_d | LIBDIVIDE_ADD_MARKER);
if (DEBUG) {
std::cout << "[SR] Using add algorithm, proposed_m = " << proposed_m << ", more = " << (int)more << std::endl;
}
}
proposed_m += 1;
int32_t magic = (int32_t)proposed_m;
// 处理负除数
if (d < 0) {
more |= LIBDIVIDE_NEGATIVE_DIVISOR;
if (!branchfree) {
magic = -magic;
}
if (DEBUG) {
std::cout << "[SR] Negative divisor, magic = " << magic << ", more = " << (int)more << std::endl;
}
}
// 为我们的IR生成提取移位量和标志
int shift = more & 0x3F; // 移除标志保留移位量位0-5
bool need_add = (more & LIBDIVIDE_ADD_MARKER) != 0;
bool is_negative = (more & LIBDIVIDE_NEGATIVE_DIVISOR) != 0;
if (DEBUG) {
std::cout << "[SR] Final result: magic = " << magic << ", more = " << (int)more
<< " (0x" << std::hex << (int)more << std::dec << ")" << std::endl;
std::cout << "[SR] Shift = " << shift << ", need_add = " << need_add
<< ", is_negative = " << is_negative << std::endl;
// Test the magic number using the correct libdivide algorithm
std::cout << "[SR] Testing magic number (libdivide algorithm):" << std::endl;
int test_values[] = {1, 7, 37, 100, 999, -1, -7, -37, -100};
for (int test_val : test_values) {
int64_t quotient;
// 实现正确的libdivide算法
int64_t product = (int64_t)test_val * magic;
int64_t high_bits = product >> 32;
if (need_add) {
// ADD_MARKER情况移位前加上被除数
// 这是libdivide的关键洞察
high_bits += test_val;
quotient = high_bits >> shift;
} else {
// 正常情况:只是移位
quotient = high_bits >> shift;
}
// 符号修正这是libdivide有符号除法的关键部分
// 如果被除数为负商需要加1来匹配C语言的截断除法语义
if (test_val < 0) {
quotient += 1;
}
int expected = test_val / divisor;
bool correct = (quotient == expected);
std::cout << "[SR] " << test_val << " / " << divisor << " = " << quotient
<< " (expected " << expected << ") " << (correct ? "" : "") << std::endl;
}
std::cout << "[SR] ===== End magic computation =====" << std::endl;
}
// 返回魔数、移位量并在移位中编码ADD_MARKER标志
// 我们将使用移位的第6位表示ADD_MARKER第7位表示负数如果需要
int encoded_shift = shift;
if (need_add) {
encoded_shift |= 0x40; // 设置第6位表示ADD_MARKER
if (DEBUG) {
std::cout << "[SR] Encoding ADD_MARKER in shift: " << encoded_shift << std::endl;
}
}
return {magic, encoded_shift};
}
};
}// namespace sysy